Exemplo n.º 1
0
    def __init__(self):
        QMainWindow.__init__(self)

        view = MapGraphicsView(tileSource=MapTileSourceHere())

        self.setCentralWidget(view)
        view.scene().setCenter(31.789339, 41.450508)
        view.setOptimizationFlag(QGraphicsView.DontSavePainterState, True)
        view.setRenderHint(QPainter.Antialiasing, True)
        view.setRenderHint(QPainter.SmoothPixmapTransform, True)
        pointItem = view.scene().addCircle(31.789339, 44.860767, 3.0)
        pointItem.setBrush(Qt.black)
        pointItem.setToolTip('31.789339, 41.450508')
        pointItem.setFlag(QGraphicsItem.ItemIsSelectable, True)
        pointItem = view.scene().addCircle(31.789339, 44.860767, 5.0)
        pointItem.setBrush(Qt.green)
        pointItem.setPen(QPen(Qt.NoPen))
        pointItem.setToolTip('%f, %f' % (31.789339, 44.860767))
        pointItem.setFlag(QGraphicsItem.ItemIsSelectable, True)
        lineItem = view.scene().addLine(32.859741, 39.933365, 31.789339,
                                        41.450508)
        lineItem.setPen(QPen(QBrush(Qt.blue), 3.0))

        polylineItem = view.scene().addPolyline('41.450508', '31.789339')
        polylineItem.setPen(QPen(QBrush(Qt.red), 3.0))
        pix = QPixmap(24, 24)
        pix.fill(Qt.red)
        pixmapItem = view.scene().addPixmap(31.789339, 44.860767, pix)
        pixmapItem.setOffset(-12, -12)
Exemplo n.º 2
0
 def set_color(self, color):
     if color != self._color:
         self._color = color
         self.colorChanged.emit(self._color)
         pixmap = QPixmap(self.iconSize())
         pixmap.fill(color)
         self.setIcon(QIcon(pixmap))
Exemplo n.º 3
0
 def set_color(self, color):
     if color != self._color:
         self._color = color
         self.colorChanged.emit(self._color)
         pixmap = QPixmap(self.iconSize())
         pixmap.fill(color)
         self.setIcon(QIcon(pixmap))
Exemplo n.º 4
0
def makeForegroundIcon(name, foregroundColour, ext="svg", returnType="icon"):
    """ Open {name}.{ext} icon and change the colour to `foregroundColour`.
    
        Parameters
        ----------
        name : str
            Name of icon file (without extension)
        foregroundColour : str or QColor
            Colour to make the icon
        ext : str
            Icon file extension. Default is "svg"
        returnType : {"icon", "pixmap"}
            Whether to return a QIcon or a QPixmap. Default is "icon"
    """
    if returnType not in ['icon', 'pixmap']:
        raise ValueError(f"Invalid icon return type {returnType}")
    if isinstance(foregroundColour, str):
        foregroundColour = QColor(foregroundColour)
    file = getIconPath(name, ext=ext)
    px0 = QPixmap(file)
    px1 = QPixmap(px0.size())
    px1.fill(foregroundColour)
    px1.setMask(px0.createMaskFromColor(Qt.transparent))
    if returnType == 'icon':
        return QIcon(px1)
    else:
        return px1
Exemplo n.º 5
0
    def findAscent(self, font):
        dummy = "E"
        white = QColor(Qt.white)

        fm = self.fontmetrics(font)
        pm = QPixmap(fm.width(dummy), fm.height())
        pm.fill(white)

        p = QPainter(pm)
        p.setFont(font)
        p.drawText(0, 0, pm.width(), pm.height(), 0, dummy)
        p.end()

        img = pm.toImage()

        w = pm.width()
        linebytes = w * 4
        for row in range(img.height()):
            if PYSIDE2:
                line = bytes(img.scanLine(row))
            else:
                line = img.scanLine(row).asstring(linebytes)
            for col in range(w):
                color = struct.unpack("I", line[col * 4:(col + 1) * 4])[0]
                if color != white.rgb():
                    return fm.ascent() - row + 1
        return fm.ascent()
Exemplo n.º 6
0
    def filename(self, new_file):
        """
        The filename of the image to be displayed.

        This file can be either relative to the ``.ui`` file or absolute. If
        the path does not exist, a shape of ``.null_color`` will be displayed
        instead.

        Parameters
        -------
        new_file : str
            The filename to be used
        """
        # Expand user (~ or ~user) and environment variables.
        pixmap = None
        self._file = new_file
        abs_path = os.path.expanduser(os.path.expandvars(self._file))
        # Find the absolute path relative to UI
        if not os.path.isabs(abs_path):
            try:
                # Based on the QApplication
                if is_pydm_app():
                    abs_path = QApplication.instance().get_path(abs_path)
                # Based on the QtDesigner
                elif is_qt_designer():  # pragma: no cover
                    p = self.get_designer_window()
                    if p is not None:
                        ui_dir = p.absoluteDir().absolutePath()
                        abs_path = os.path.join(ui_dir, abs_path)
            except Exception:
                logger.exception("Unable to find full filepath for %s",
                                 self._file)
        # Check that the path exists
        if os.path.isfile(abs_path):
            if self._movie is not None:
                self._movie.stop()
                self._movie.deleteLater()
                self._movie = None
            if not abs_path.endswith(".gif"):
                pixmap = QPixmap(abs_path)
            else:
                self._movie = QMovie(abs_path, parent=self)
                self._movie.setCacheMode(QMovie.CacheAll)
                self._movie.frameChanged.connect(self.movie_frame_changed)
                if self._movie.frameCount() > 1:
                    self._movie.finished.connect(self.movie_finished)
                self._movie.start()

        # Return a blank image if we don't have a valid path
        else:
            # Warn the user loudly if their file does not exist, but avoid
            # doing this in Designer as this spams the user as they are typing
            if not is_qt_designer():  # pragma: no cover
                logger.error("Image file  %r does not exist", abs_path)
            pixmap = QPixmap(self.sizeHint())
            pixmap.fill(self.null_color)
        # Update the display
        if pixmap is not None:
            self._pixmap = pixmap
            self.update()
Exemplo n.º 7
0
 def update(self, value):
     """Reimplement LineEditWidget method"""
     LineEditWidget.update(self, value)
     color = text_to_qcolor(value)
     if color.isValid():
         bitmap = QPixmap(16, 16)
         bitmap.fill(color)
         icon = QIcon(bitmap)
     else:
         icon = get_icon("not_found")
     self.button.setIcon(icon)
Exemplo n.º 8
0
def square_pixmap(size):
    """Create a white/black hollow square pixmap. For use as labels cursor."""
    pixmap = QPixmap(QSize(size, size))
    pixmap.fill(Qt.transparent)
    painter = QPainter(pixmap)
    painter.setPen(Qt.white)
    painter.drawRect(0, 0, size - 1, size - 1)
    painter.setPen(Qt.black)
    painter.drawRect(1, 1, size - 3, size - 3)
    painter.end()
    return pixmap
Exemplo n.º 9
0
    def _to_qimage(self):

        t = self._to_qgraphicstextitem()
        rect = t.boundingRect()
        height = rect.height()
        width = rect.width()
        pixmap = QPixmap(width, height)
        pixmap.fill(Qt.transparent)
        painter = QPainter(pixmap)
        t.paint(painter, QStyleOptionGraphicsItem(), None)
        painter.end()
        return pixmap.toImage()
Exemplo n.º 10
0
def circle_pixmap(size: int):
    """Create a white/black hollow circle pixmap. For use as labels cursor."""
    size = max(int(size), 1)
    pixmap = QPixmap(QSize(size, size))
    pixmap.fill(Qt.transparent)
    painter = QPainter(pixmap)
    painter.setPen(Qt.white)
    painter.drawEllipse(0, 0, size - 1, size - 1)
    painter.setPen(Qt.black)
    painter.drawEllipse(1, 1, size - 3, size - 3)
    painter.end()
    return pixmap
Exemplo n.º 11
0
    def update_layer_item(self, plot=None, *args, **kwargs):
        if plot is None:
            return

        layer = plot._layer
        pixmap = QPixmap(10, 10)
        pixmap.fill(plot.pen.color())
        icon = QIcon(pixmap)

        layer_item = self.get_layer_item(layer)

        if layer_item is not None:
            layer_item.setIcon(0, icon)
            layer_item.setCheckState(0, Qt.Checked if plot.checked else Qt.Unchecked)
Exemplo n.º 12
0
    def drawColorBar(self, painter, colorMap, interval, scaleMap, orientation,
                     rect):
        """
        Draw a color bar into a rectangle

        :param QPainter painter: Painter
        :param qwt.color_map.QwtColorMap colorMap: Color map
        :param qwt.interval.QwtInterval interval: Value range
        :param qwt.scalemap.QwtScaleMap scaleMap: Scale map
        :param Qt.Orientation orientation: Orientation
        :param QRectF rect: Target rectangle
        """
        colorTable = []
        if colorMap.format() == QwtColorMap.Indexed:
            colorTable = colorMap.colorTable(interval)
        c = QColor()
        devRect = rect.toAlignedRect()
        pixmap = QPixmap(devRect.size())
        pixmap.fill(Qt.transparent)
        pmPainter = QPainter(pixmap)
        pmPainter.translate(-devRect.x(), -devRect.y())
        if orientation == Qt.Horizontal:
            sMap = QwtScaleMap(scaleMap)
            sMap.setPaintInterval(rect.left(), rect.right())
            for x in range(devRect.left(), devRect.right() + 1):
                value = sMap.invTransform(x)
                if colorMap.format() == QwtColorMap.RGB:
                    c.setRgba(colorMap.rgb(interval, value))
                else:
                    c = colorTable[colorMap.colorIndex(interval, value)]
                pmPainter.setPen(c)
                pmPainter.drawLine(
                    QLineF(x, devRect.top(), x, devRect.bottom()))
        else:
            sMap = QwtScaleMap(scaleMap)
            sMap.setPaintInterval(rect.bottom(), rect.top())
            for y in range(devRect.top(), devRect.bottom() + 1):
                value = sMap.invTransform(y)
                if colorMap.format() == QwtColorMap.RGB:
                    c.setRgba(colorMap.rgb(interval, value))
                else:
                    c = colorTable[colorMap.colorIndex(interval, value)]
                pmPainter.setPen(c)
                pmPainter.drawLine(
                    QLineF(devRect.left(), y, devRect.right(), y))
        pmPainter.end()
        self.drawPixmap(painter, rect, pixmap)
Exemplo n.º 13
0
    def toPixmap(self, *args):
        """
        Convert the graphic to a `QPixmap`

        All pixels of the pixmap get initialized by `Qt.transparent`
        before the graphic is scaled and rendered on it.

        The size of the pixmap is the default size ( ceiled to integers )
        of the graphic.
        
        :return: The graphic as pixmap in default size

        .. seealso::
        
            :py:meth:`defaultSize()`, :py:meth:`toImage()`, :py:meth:`render()`
        """
        if len(args) == 0:
            if self.isNull():
                return QPixmap()
            sz = self.defaultSize()
            w = np.ceil(sz.width())
            h = np.ceil(sz.height())
            pixmap = QPixmap(w, h)
            pixmap.fill(Qt.transparent)
            r = QRectF(0.0, 0.0, sz.width(), sz.height())
            painter = QPainter(pixmap)
            self.render(painter, r, Qt.KeepAspectRatio)
            painter.end()
            return pixmap
        elif len(args) in (1, 2):
            size = args[0]
            aspectRatioMode = Qt.IgnoreAspectRatio
            if len(args) == 2:
                aspectRatioMode = args[-1]
            pixmap = QPixmap(size)
            pixmap.fill(Qt.transparent)
            r = QRect(0, 0, size.width(), size.height())
            painter = QPainter(pixmap)
            self.render(painter, r, aspectRatioMode)
            painter.end()
            return pixmap
Exemplo n.º 14
0
def drag_with_pixmap(list_widget: QListWidget) -> QDrag:
    """Create a QDrag object with a pixmap of the currently select list item.

    This method is useful when you have a QListWidget that displays custom
    widgets for each QListWidgetItem instance in the list (usually by calling
    ``QListWidget.setItemWidget(item, widget)``).  When used in a
    ``QListWidget.startDrag`` method, this function creates a QDrag object that
    shows an image of the item being dragged (rather than an empty rectangle).

    Parameters
    ----------
    list_widget : QListWidget
        The QListWidget for which to create a QDrag object.

    Returns
    -------
    QDrag
        A QDrag instance with a pixmap of the currently selected item.

    Examples
    --------
    >>> class QListWidget:
    ...     def startDrag(self, supportedActions):
    ...         drag = drag_with_pixmap(self)
    ...         drag.exec_(supportedActions, Qt.MoveAction)

    """
    drag = QDrag(list_widget)
    drag.setMimeData(list_widget.mimeData(list_widget.selectedItems()))
    size = list_widget.viewport().visibleRegion().boundingRect().size()
    pixmap = QPixmap(size)
    pixmap.fill(Qt.transparent)
    painter = QPainter(pixmap)
    for index in list_widget.selectedIndexes():
        rect = list_widget.visualRect(index)
        painter.drawPixmap(rect, list_widget.viewport().grab(rect))
    painter.end()
    drag.setPixmap(pixmap)
    drag.setHotSpot(list_widget.viewport().mapFromGlobal(QCursor.pos()))
    return drag
Exemplo n.º 15
0
def create_transparent_pixmap(source: QPixmap, opacity: float) -> QPixmap:
    '''
    Creates a semi transparent pixmap from the given pixmap Source. The Opacity
    parameter defines the opacity from completely transparent (0.0) to
    completely opaque (1.0)

    Parameters
    ----------
    source : QPixmap
    opacity : qreal

    Returns
    -------
    value : QPixmap
    '''
    transparent_pixmap = QPixmap(source.size())
    transparent_pixmap.fill(Qt.transparent)

    painter = QPainter(transparent_pixmap)
    painter.setOpacity(opacity)
    painter.drawPixmap(0, 0, source)
    return transparent_pixmap
Exemplo n.º 16
0
    def data(self, index, role):
        if role in (Qt.DisplayRole, Qt.EditRole):
            try:
                return self.item_list[index.row()][0]
            except IndexError:
                return None

        elif role == Qt.DecorationRole:
            # preflight
            if not self.display_item_colors: return

            # get display color
            try:
                color = QColor(*self.item_list[index.row()][1])
            except IndexError:
                color = QColor(*iColor["rgba_gray_0"])

            # create pixmap/icon
            pixmap = QPixmap(
                getFontSize(QApplication) * 2,
                getFontSize(QApplication) * 0.5)
            pixmap.fill(color)
            icon = QIcon(pixmap)
            return icon
Exemplo n.º 17
0
 def pixmap(self, size, mode, state):
     pm = QPixmap(size)
     pm.fill(Qt.transparent)
     self.paint(QPainter(pm), QRect(QPoint(0, 0), size), mode, state)
     return pm
Exemplo n.º 18
0
def crosshair_pixmap():
    """Create a cross cursor with white/black hollow square pixmap in the middle.
    For use as points cursor."""

    size = 25

    pixmap = QPixmap(QSize(size, size))
    pixmap.fill(Qt.transparent)
    painter = QPainter(pixmap)

    # Base measures
    width = 1
    center = 3  # Must be odd!
    rect_size = center + 2 * width
    square = rect_size + width * 4

    pen = QPen(Qt.white, 1)
    pen.setJoinStyle(Qt.PenJoinStyle.MiterJoin)
    painter.setPen(pen)

    # # Horizontal rectangle
    painter.drawRect(0, (size - rect_size) // 2, size - 1, rect_size - 1)

    # Vertical rectangle
    painter.drawRect((size - rect_size) // 2, 0, rect_size - 1, size - 1)

    # Square
    painter.drawRect(
        (size - square) // 2, (size - square) // 2, square - 1, square - 1
    )

    pen = QPen(Qt.black, 2)
    pen.setJoinStyle(Qt.PenJoinStyle.MiterJoin)
    painter.setPen(pen)

    # # Square
    painter.drawRect(
        (size - square) // 2 + 2,
        (size - square) // 2 + 2,
        square - 4,
        square - 4,
    )

    pen = QPen(Qt.black, 3)
    pen.setJoinStyle(Qt.PenJoinStyle.MiterJoin)
    painter.setPen(pen)

    # # # Horizontal lines
    mid_vpoint = QPoint(2, size // 2)
    painter.drawLine(
        mid_vpoint, QPoint(((size - center) // 2) - center + 1, size // 2)
    )
    mid_vpoint = QPoint(size - 3, size // 2)
    painter.drawLine(
        mid_vpoint, QPoint(((size - center) // 2) + center + 1, size // 2)
    )

    # # # Vertical lines
    mid_hpoint = QPoint(size // 2, 2)
    painter.drawLine(
        QPoint(size // 2, ((size - center) // 2) - center + 1), mid_hpoint
    )
    mid_hpoint = QPoint(size // 2, size - 3)
    painter.drawLine(
        QPoint(size // 2, ((size - center) // 2) + center + 1), mid_hpoint
    )

    painter.end()
    return pixmap
Exemplo n.º 19
0
class MapGraphicsScene(QGraphicsScene):
    """Graphics scene for showing a slippy map.
    """

    sigZoomChanged = Signal(int)

    def __init__(self, tileSource, parent=None):
        """Constructor.

        Args:
            tileSource(MapTileSource): Source for loading the tiles.
            parent(QObject): Parent object, default `None`
        """
        QGraphicsScene.__init__(self, parent=parent)

        self._zoom = 15

        self._tileSource = tileSource
        self._tileSource.setParent(self)
        self._tileSource.tileReceived.connect(self.setTilePixmap)
        tdim = self._tileSource.tileSize()

        self._emptyTile = QPixmap(tdim, tdim)
        self._emptyTile.fill(Qt.lightGray)

        self._tilesRect = QRect()
        self._tilePixmaps = {}

        self._tileInDownload = list()

        self.setSceneRect(0.0, 0.0, 400, 300)
        self.sceneRectChanged.connect(self.onSceneRectChanged)

    @Slot()
    def close(self):
        self._tileSource.close()

    def setTileSource(self, newTileSource):
        self._tileSource.tileReceived.disconnect(self.setTilePixmap)
        self._tileSource.close()

        self._tilePixmaps.clear()
        self._tileInDownload = list()

        self._tileSource = newTileSource
        self._tileSource.setParent(self)
        self._tileSource.tileReceived.connect(self.setTilePixmap)

        self.requestTiles()

        self.invalidate()
        self.update()

    @Slot(QRectF)
    def onSceneRectChanged(self, rect):
        """Callback for the changing of the visible rect.

        Evaluate the visible tiles and request to load the new tiles.

        Args:
            rect(QRectF): Current visible area.
        """
        tdim = self._tileSource.tileSize()
        center = rect.center()
        ct = self.tileFromPos(center.x(), center.y())
        tx = ct.x()
        ty = ct.y()

        width = rect.width()
        height = rect.height()
        # top left corner of the center tile
        xp = int(width / 2.0 - (tx - floor(tx)) * tdim)
        yp = int(height / 2.0 - (ty - floor(ty)) * tdim)

        # first tile vertical and horizontal
        xs = tx - (xp + tdim - 1) / tdim
        ys = ty - (yp + tdim - 1) / tdim

        # last tile vertical and horizontal
        xe = (width - xp - 1) / tdim - xs + 1 + tx
        ye = (height - yp - 1) / tdim - ys + 1 + ty

        # define the rect of visible tiles
        self._tilesRect = QRect(xs, ys, xe, ye)

        # Request the loading of new tiles (if needed)
        self.requestTiles()

        self.invalidate()
        self.update()

    def drawBackground(self, painter, rect):
        """Draw the background tiles.

        If a tile is not available, draw a gray rectangle.

        Args:
            painter(QPainter): Painter for drawing.
            rect(QRectF): Current visible area.
        """
        tilesRect = self._tilesRect
        left = tilesRect.left()
        top = tilesRect.top()
        numXtiles = tilesRect.width()
        numYtiles = tilesRect.height()
        tdim = self._tileSource.tileSize()
        pixRect = QRectF(0.0, 0.0, tdim, tdim)
        emptyTilePix = self._emptyTile
        tilePixmaps = self._tilePixmaps

        for x in iterRange(numXtiles + 1):
            for y in iterRange(numYtiles + 1):
                tp = (x + left, y + top)
                box = self.tileRect(tp[0], tp[1])
                # Use default gray image if tile image is missing
                pix = tilePixmaps.get(tp, emptyTilePix)
                painter.drawPixmap(box, pix, pixRect)

    def zoomTo(self, pos, zoomlevel):
        """Zoom to a specific zoom level.

        If the level is out of range, the zoom action is ignored.

        clear the current tile cache, evaluate the new center and
        update the position of all the items.

        Args:
            zoomlevel(int): New zoom level.
        """

        tileSource = self._tileSource
        if zoomlevel > tileSource.maxZoom() or zoomlevel < tileSource.minZoom(
        ):
            return

        # Get the coordinates of the center using the position in pixels of the mouse
        pos_corr = self.views()[0].mapToScene(pos)
        coord = self.lonLatFromPos(pos_corr.x(), pos_corr.y())

        # Set the new zoom level
        self._zoom = zoomlevel

        # Clear cache and abort active requests
        self._tileSource.abortAllRequests()
        self._tilePixmaps.clear()

        # Re-center map so that the point on which it was zoomed is in the same position
        self.setCenter(coord[0], coord[1])
        pos_corr = self.views()[0].mapToScene(pos)
        center = self.sceneRect().center()
        self.translate(center.x() - pos_corr.x(), center.y() - pos_corr.y())

        self.sigZoomChanged.emit(zoomlevel)

    def zoomIn(self, pos=None):
        """Increments the zoom level

        Args:
            pos (QPointF): Center position, Latitude and Longitude. Default None for the
                           current center position.
        """
        if pos is None:
            pos = self.sceneRect().center()
        self.zoomTo(pos, self._zoom + 1)

    def zoomOut(self, pos=None):
        """Decrements the zoom level

        Args:
            pos (QPointF): Center position, Latitude and Longitude. Default None for the
                           current center position.
        """
        if pos is None:
            pos = self.sceneRect().center()
        self.zoomTo(pos, self._zoom - 1)

    def zoom(self):
        return self._zoom

    @Slot(int, int, int, QPixmap)
    def setTilePixmap(self, x, y, zoom, pixmap):
        """Set the image of the tile.

        Args:
            x(int): X coordinate of the tile.
            y(int): Y coordinate of the tile.
            zoom(int): Zoom coordinate of the tile.
            pixmap(QPixmap): Image for the tile.
        """
        if self._zoom == zoom:
            self._tilePixmaps[(x, y)] = pixmap
        self.update()

    def requestTiles(self):
        """Request the loading of tiles.

        Check the loaded tiles and requests only
        the missing tiles.
        """
        tilesRect = self._tilesRect
        tilePixmaps = self._tilePixmaps

        numXtiles = tilesRect.width()
        numYtiles = tilesRect.height()
        left = tilesRect.left()
        top = tilesRect.top()
        tileSource = self._tileSource
        zoom = self._zoom

        # Request load of new tiles
        for x in iterRange(numXtiles):
            for y in iterRange(numYtiles):
                tp = (left + x, top + y)
                # Request tile only if missing
                if tp not in tilePixmaps:
                    pix = tileSource.requestTile(tp[0], tp[1], zoom)
                    if pix is not None:
                        tilePixmaps[tp] = pix

        self.update()

    def tileRect(self, tx, ty):
        """Area for a specific tile.

        Args:
            tx(int): X coordinate of the tile.
            ty(int): Y coordinate of the tile.

        Returns:
            QRectF, the area of the tile.
        """
        tdim = self._tileSource.tileSize()
        return QRectF(tx * tdim, ty * tdim, tdim, tdim)

    def setSize(self, width, height):
        """Set the size of the visible area in pixels.

        Update the scene rect.

        Args:
            width(int): Width of the visible area.
            height(int): Height of the visible area.
        """
        rect = QRectF(self.sceneRect().topLeft(), QSizeF(width, height))
        self.setSceneRect(rect)

    def setCenter(self, lon, lat):
        """Move the center of the visible area to new coordinates.

        Update the scene rect.

        Args:
            lon(float): New longitude of the center.
            lat(float): New latitude of the center.
        """
        rect = QRectF(self.sceneRect())
        pos = self.posFromLonLat(lon, lat)
        rect.moveCenter(QPointF(pos[0], pos[1]))
        self.setSceneRect(rect)

    def center(self):
        centerPos = self.sceneRect().center()
        centerCoord = self.lonLatFromPos(centerPos.x(), centerPos.y())
        return QPointF(centerCoord[0], centerCoord[1])

    def translate(self, dx, dy):
        """Translate the visible area by dx, dy pixels.

        Update the scene rect.

        Args:
            dx(int): Increments for the center x coord in pixels.
            dy(int): Increments for the center y coord in pixels.
        """
        self.setSceneRect(self.sceneRect().translated(dx, dy))

    def posFromLonLat(self, lon, lat):
        """Position in scene coordinate of the WGS84 coordinates.

        Convert from WGS84 reference system to scene reference system.

        Args:
            lon(float or numpy.ndarray): Longitude value or values.
            lat(float or numpy.ndarray): Latitude value or values.

        Returns:
            tuple: (x, y) with the positions of the input coordinates.
        """
        return posFromLonLat(lon, lat, self._zoom, self._tileSource.tileSize())

    def lonLatFromPos(self, x, y):
        """Position in WGS84 coordinate of the scene coordinates.

        Convert from scene reference system to WGS84 reference system.

        Args:
            x(float, int or numpy.ndarray): X value or values.
            y(float, int or numpy.ndarray): Y value or values.

        Returns:
            tuple: (lon, lat) with the coordinates of the input positions.
        """
        return lonLatFromPos(x, y, self._zoom, self._tileSource.tileSize())

    def tileFromPos(self, x, y):
        """Tile in the selected position.

        Args:
            x(float, int): X value for position.
            y(float, int): Y value for position.

        Returns:
            QPointF with the coordinates of the tile.
        """
        tdim = float(self._tileSource.tileSize())
        return QPointF(x / tdim, y / tdim)

    def addCircle(self, longitude, latitude, radius):
        """Add a new circle to the graphics scene.

        Args:
            longitude(float): Longitude of the center of the circle.
            latitude(float): Latitude of the center of the circle.
            radius(float): Longitude of the center of the circle.

        Returns:
            MapGraphicsCircleItem added to the scene.
        """
        item = MapGraphicsCircleItem(longitude, latitude, radius)
        self.addItem(item)
        return item

    def addLine(self, lon0, lat0, lon1, lat1):
        """Add a newline) to the graphics scene.

        Args:
            lon0(float): Longitude of the start point.
            lat0(float): Latitude of the start point.
            lon1(float): Longitude of the end point.
            lat1(float): Latitude of the end point.

        Returns:
            MapGraphicsLineItem added to the scene.
        """
        item = MapGraphicsLineItem(lon0, lat0, lon1, lat1)
        self.addItem(item)
        return item

    def addRect(self, lon0, lat0, lon1, lat1):
        """Add a newline) to the graphics scene.

        Args:
            lon0(float): Longitude of the top left point.
            lat0(float): Latitude of the top left point.
            lon1(float): Longitude of the bottom right point.
            lat1(float): Latitude of the bottom right point.

        Returns:
            MapGraphicsLineItem added to the scene.
        """
        item = MapGraphicsRectItem(lon0, lat0, lon1, lat1)
        self.addItem(item)
        return item

    def addPolyline(self, longitudes, latitudes):
        """Add a new circle (point) to the graphics scene.

        Args:
            longitudes(iterable): Longitudes of all the points of the polyline.
            latitudes(iterable): Latitudes of all the points of the polyline.

        Returns:
            MapGraphicsPolylineItem added to the scene.
        """
        item = MapGraphicsPolylineItem(longitudes, latitudes)
        self.addItem(item)
        return item

    def addPixmap(self, longitude, latitude, pixmap):
        """Add a new circle (point) to the graphics scene.

        Args:
            longitude(float): Longitude of the origin of the pixmap.
            latitude(float): Latitude of the center of the pixmap.
            pixmap(QPixmap): Pixmap.

        Returns:
            MapGraphicsPixmapItem added to the scene.

        Note:
            Use `MapGraphicsPixmapItem.setOffset(off)` to translate by `off` pixels
            the pixmap respect the origin coordinates.
        """
        item = MapGraphicsPixmapItem(longitude, latitude, pixmap)
        self.addItem(item)
        return item

    def addText(self, longitude, latitude, text):
        """Add a test item to the graphics scene.

        Args:
            longitude(float): Longitude of the origin of the text
            latitude(float): Latitude of the origin of the text

        Returns:
            MapGraphicsTextItem added to the scene.
        """
        item = MapGraphicsTextItem(longitude, latitude, text)
        self.addItem(item)
        return item

    def addLegend(self, pos=QPointF(10.0, 10.0)):
        legend = MapLegendItem(pos=pos)
        self.addItem(legend)
        return legend

    def addScale(self, **kwargs):
        """Add a scale bar with text on the right bottom of the map

        Keyword Args:
            textPen: QPen to use for drawing the text. Default 'black'.
            barBrush: QBrush to use for drawing the scale bar. Default (190, 190, 190, 160)
            barPen: QPen to use for drawing the scale bar border. Default (190, 190, 190, 240)
            barBrushHover:  QBrush to use for drawing the scale bar when the mouse is over it.
                Default (110, 110, 110, 255).
            barPenHover: QPen to use for drawing the scale bar borderwhen the mouse is over it.
                Default (90, 90, 90, 255).

        Note:
            Almost all the argumnets accepted by the functions.makeBrush() and functions.makePen()
            are accepted.
        """
        scaleItem = MapScaleItem(**kwargs)
        self.addItem(scaleItem)
        return scaleItem

    def addLinesGroup(self, longitudes, latitudes):
        item = MapGraphicsLinesGroupItem(longitudes, latitudes)
        self.addItem(item)
        return item
Exemplo n.º 20
0
    def __init__(self):
        QMainWindow.__init__(self)

        view = MapGraphicsView(tileSource=MapTileSourceHere())

        self.setCentralWidget(view)

        view.scene().setCenter(10.065990, 44.861041)
        view.setOptimizationFlag(QGraphicsView.DontSavePainterState, True)
        view.setRenderHint(QPainter.Antialiasing, True)
        view.setRenderHint(QPainter.SmoothPixmapTransform, True)

        pointItem = view.scene().addCircle(10.068640, 44.860767, 3.0)
        pointItem.setBrush(Qt.black)
        pointItem.setToolTip('10.068640, 44.860767')
        pointItem.setFlag(QGraphicsItem.ItemIsSelectable, True)

        lats = list()
        lons = list()
        for p in POINTS:
            pointItem = view.scene().addCircle(p[1], p[0], 5.0)
            pointItem.setBrush(Qt.green)
            pointItem.setPen(QPen(Qt.NoPen))
            pointItem.setToolTip('%f, %f' % (p[1], p[0]))
            pointItem.setFlag(QGraphicsItem.ItemIsSelectable, True)
            lons.append(p[1])
            lats.append(p[0])

        lineItem = view.scene().addLine(10.191037, 44.832810, 10.201736, 44.837632)
        lineItem.setPen(QPen(QBrush(Qt.blue), 3.0))

        polylineItem = view.scene().addPolyline(lons, lats)
        polylineItem.setPen(QPen(QBrush(Qt.red), 3.0))

        pix = QPixmap(24, 24)
        pix.fill(Qt.red)
        pixmapItem = view.scene().addPixmap(10.090598, 44.857893, pix)
        pixmapItem.setOffset(-12, -12)
        pointItemPixmapOrigin = view.scene().addCircle(10.090598, 44.857893, 3.0)
        pointItemPixmapOrigin.setBrush(Qt.black)

        pointItemWithChild = view.scene().addCircle(10.083103, 44.858014, 3.0)
        pointItemWithChild.setBrush(Qt.blue)
        pointItemWithChild.setPen(QPen(Qt.NoPen))

        textItem = QGraphicsSimpleTextItem('Annotation\nfor blue point', parent=pointItemWithChild)
        textItem.setBrush(QBrush(QColor(Qt.blue)))
        textItem.setPos(-5, 3)

        lats_2 = list()
        lons_2 = list()
        for p in POINTS_2:
            lons_2.append(p[1])
            lats_2.append(p[0])
        linesGroupItem = view.scene().addLinesGroup(lons_2, lats_2)
        linesGroupItem.setLineStyle(POINTS_2_COLORS, width=POINTS_2_SIZES)

        legendItem = view.scene().addLegend()
        legendItem.addPoint('Point 1', '#FF0000', border=None)
        legendItem.addRect('Rect 2', '#00FF00', border=None)
        legendItem.addPoint('Circle 3', '#0000FF', border=None)
        legendItem.addRect('Sphere 4', '#00FFFF', border=None)
        legendItem.addPoint('Polygon 5', '#FF00FF', border=None)

        scaleItem = view.scene().addScale(anchor=Qt.BottomRightCorner)
Exemplo n.º 21
0
    def create_high_dpi_drop_indicator_pixmap(
            self, size: QSizeF, area: DockWidgetArea,
            mode: OverlayMode) -> QPixmap:
        '''
        Create high dpi drop indicator pixmap

        Parameters
        ----------
        size : QSizeF
        area : DockWidgetArea
        mode : OverlayMode

        Returns
        -------
        value : QPixmap
        '''
        border_color = self.icon_color(IconColor.frame_color)
        background_color = self.icon_color(IconColor.window_background_color)

        window = self.public.window()

        # QT version compatibility (TODO necessary for qtpy?)
        device_pixel_ratio = (window.devicePixelRatioF()
                              if hasattr(window, 'devicePixelRatioF')
                              else window.devicePixelRatio())

        pixmap_size = QSizeF(size * device_pixel_ratio)
        pm = QPixmap(pixmap_size.toSize())
        pm.fill(QColor(0, 0, 0, 0))
        p = QPainter(pm)
        pen = p.pen()
        shadow_rect = QRectF(pm.rect())

        base_rect = QRectF()
        base_rect.setSize(shadow_rect.size() * 0.7)
        base_rect.moveCenter(shadow_rect.center())

        # Fill
        shadow_color = self.icon_color(IconColor.shadow_color)
        if shadow_color.alpha() == 255:
            shadow_color.setAlpha(64)

        p.fillRect(shadow_rect, shadow_color)

        # Drop area rect.
        p.save()
        area_rect = QRectF()
        area_line = QLineF()
        non_area_rect = QRectF()

        if area == DockWidgetArea.top:
            area_rect = QRectF(base_rect.x(), base_rect.y(), base_rect.width(),
                               base_rect.height()*.5)
            non_area_rect = QRectF(base_rect.x(), shadow_rect.height()*.5,
                                   base_rect.width(), base_rect.height()*.5)
            area_line = QLineF(area_rect.bottomLeft(), area_rect.bottomRight())
        elif area == DockWidgetArea.right:
            area_rect = QRectF(shadow_rect.width()*.5, base_rect.y(),
                               base_rect.width()*.5, base_rect.height())
            non_area_rect = QRectF(base_rect.x(), base_rect.y(),
                                   base_rect.width()*.5, base_rect.height())
            area_line = QLineF(area_rect.topLeft(), area_rect.bottomLeft())
        elif area == DockWidgetArea.bottom:
            area_rect = QRectF(base_rect.x(), shadow_rect.height()*.5,
                               base_rect.width(), base_rect.height()*.5)
            non_area_rect = QRectF(base_rect.x(), base_rect.y(),
                                   base_rect.width(), base_rect.height()*.5)
            area_line = QLineF(area_rect.topLeft(), area_rect.topRight())
        elif area == DockWidgetArea.left:
            area_rect = QRectF(base_rect.x(), base_rect.y(),
                               base_rect.width()*.5, base_rect.height())
            non_area_rect = QRectF(shadow_rect.width()*.5, base_rect.y(),
                                   base_rect.width()*.5, base_rect.height())
            area_line = QLineF(area_rect.topRight(), area_rect.bottomRight())

        baseSize = base_rect.size()
        if (OverlayMode.container == mode
                and area != DockWidgetArea.center):
            base_rect = area_rect

        p.fillRect(base_rect, background_color)
        if area_rect.isValid():
            pen = p.pen()
            pen.setColor(border_color)
            Color = self.icon_color(IconColor.overlay_color)
            if Color.alpha() == 255:
                Color.setAlpha(64)

            p.setBrush(Color)
            p.setPen(Qt.NoPen)
            p.drawRect(area_rect)
            pen = p.pen()
            pen.setWidth(1)
            pen.setColor(border_color)
            pen.setStyle(Qt.DashLine)
            p.setPen(pen)
            p.drawLine(area_line)

        p.restore()
        p.save()

        # Draw outer border
        pen = p.pen()
        pen.setColor(border_color)
        pen.setWidth(1)
        p.setBrush(Qt.NoBrush)
        p.setPen(pen)
        p.drawRect(base_rect)

        # draw window title bar
        p.setBrush(border_color)
        frame_rect = QRectF(base_rect.topLeft(),
                            QSizeF(base_rect.width(), baseSize.height()/10))
        p.drawRect(frame_rect)
        p.restore()

        # Draw arrow for outer container drop indicators
        if (OverlayMode.container == mode and
                area != DockWidgetArea.center):
            arrow_rect = QRectF()
            arrow_rect.setSize(baseSize)
            arrow_rect.setWidth(arrow_rect.width()/4.6)
            arrow_rect.setHeight(arrow_rect.height()/2)
            arrow_rect.moveCenter(QPointF(0, 0))

            arrow = QPolygonF()
            arrow.append(arrow_rect.topLeft())
            arrow.append(QPointF(arrow_rect.right(), arrow_rect.center().y()))
            arrow.append(arrow_rect.bottomLeft())

            p.setPen(Qt.NoPen)
            p.setBrush(self.icon_color(IconColor.arrow_color))
            p.setRenderHint(QPainter.Antialiasing, True)
            p.translate(non_area_rect.center().x(), non_area_rect.center().y())
            if area == DockWidgetArea.top:
                p.rotate(-90)
            elif area == DockWidgetArea.right:
                ...
            elif area == DockWidgetArea.bottom:
                p.rotate(90)
            elif area == DockWidgetArea.left:
                p.rotate(180)

            p.drawPolygon(arrow)

        pm.setDevicePixelRatio(device_pixel_ratio)
        return pm
Exemplo n.º 22
0
def color_icon(name: str, size: int = 20) -> QIcon:
    """Get color block as QIcon by name."""
    color_block = QPixmap(QSize(size, size))
    color_block.fill(color_qt(name))
    return QIcon(color_block)
Exemplo n.º 23
0
 def pixmap(self, size, mode, state):
     pm = QPixmap(size)
     pm.fill(Qt.transparent)
     self.paint(QPainter(pm), QRect(QPoint(0, 0), size), mode, state)
     return pm
Exemplo n.º 24
0
class PyDMDrawingImage(PyDMDrawing):
    """
    Renders an image given by the ``filename`` property.
    This class inherits from PyDMDrawing.

    Parameters
    ----------
    parent : QWidget
        The parent widget for the Label
    init_channel : str, optional
        The channel to be used by the widget.

    Attributes
    ----------
    null_color : Qt.Color
        QColor to fill the image if the filename is not found.
    """
    null_color = Qt.gray

    def __init__(self, parent=None, init_channel=None, filename=""):
        super(PyDMDrawingImage, self).__init__(parent, init_channel)
        hint = super(PyDMDrawingImage, self).sizeHint()
        self._pixmap = QPixmap(hint)
        self._pixmap.fill(self.null_color)
        self._aspect_ratio_mode = Qt.KeepAspectRatio
        self._movie = None
        # Make sure we don't set a non-existant file
        if filename:
            self.filename = filename
        # But we always have an internal value to reference
        else:
            self._file = filename
        if is_qt_designer():  # pragma: no cover
            designer_window = self.get_designer_window()
            if designer_window is not None:
                designer_window.fileNameChanged.connect(
                    self.designer_form_saved)

    def get_designer_window(self):  # pragma: no cover
        # Internal function to find the designer window that owns this widget.
        p = self.parent()
        while p is not None:
            if isinstance(p, QDesignerFormWindowInterface):
                return p
            p = p.parent()
        return None

    @Slot(str)
    def designer_form_saved(self, filename):  # pragma: no cover
        self.filename = self._file

    @Property(str)
    def filename(self):
        """
        The filename of the image to be displayed.
        This can be an absolute or relative path to the display file.

        Returns
        -------
        str
            The filename configured.
        """
        return self._file

    @filename.setter
    def filename(self, new_file):
        """
        The filename of the image to be displayed.

        This file can be either relative to the ``.ui`` file or absolute. If
        the path does not exist, a shape of ``.null_color`` will be displayed
        instead.

        Parameters
        -------
        new_file : str
            The filename to be used
        """
        # Expand user (~ or ~user) and environment variables.
        pixmap = None
        self._file = new_file
        abs_path = os.path.expanduser(os.path.expandvars(self._file))
        # Find the absolute path relative to UI
        if not os.path.isabs(abs_path):
            try:
                # Based on the QApplication
                if is_pydm_app():
                    abs_path = QApplication.instance().get_path(abs_path)
                # Based on the QtDesigner
                elif is_qt_designer():  # pragma: no cover
                    p = self.get_designer_window()
                    if p is not None:
                        ui_dir = p.absoluteDir().absolutePath()
                        abs_path = os.path.join(ui_dir, abs_path)
            except Exception:
                logger.exception("Unable to find full filepath for %s",
                                 self._file)
        # Check that the path exists
        if os.path.isfile(abs_path):
            if self._movie is not None:
                self._movie.stop()
                self._movie.deleteLater()
                self._movie = None
            if not abs_path.endswith(".gif"):
                pixmap = QPixmap(abs_path)
            else:
                self._movie = QMovie(abs_path, parent=self)
                self._movie.setCacheMode(QMovie.CacheAll)
                self._movie.frameChanged.connect(self.movie_frame_changed)
                if self._movie.frameCount() > 1:
                    self._movie.finished.connect(self.movie_finished)
                self._movie.start()

        # Return a blank image if we don't have a valid path
        else:
            # Warn the user loudly if their file does not exist, but avoid
            # doing this in Designer as this spams the user as they are typing
            if not is_qt_designer():  # pragma: no cover
                logger.error("Image file  %r does not exist", abs_path)
            pixmap = QPixmap(self.sizeHint())
            pixmap.fill(self.null_color)
        # Update the display
        if pixmap is not None:
            self._pixmap = pixmap
            self.update()

    def sizeHint(self):
        if self._pixmap.size().isEmpty():
            return super(PyDMDrawingImage, self).sizeHint()
        return self._pixmap.size()

    @Property(Qt.AspectRatioMode)
    def aspectRatioMode(self):
        """
        PyQT Property for aspect ratio mode to be used when rendering
        the image

        Returns
        -------
        int
            Index at Qt.AspectRatioMode enum
        """
        return self._aspect_ratio_mode

    @aspectRatioMode.setter
    def aspectRatioMode(self, new_mode):
        """
        PyQT Property for aspect ratio mode to be used when rendering
        the image

        Parameters
        ----------
        new_mode : int
            Index at Qt.AspectRatioMode enum
        """
        if new_mode != self._aspect_ratio_mode:
            self._aspect_ratio_mode = new_mode
            self.update()

    def draw_item(self, painter):
        """
        Draws the image after setting up the canvas with a call to
        ```PyDMDrawing.draw_item```.
        """
        super(PyDMDrawingImage, self).draw_item(painter)
        x, y, w, h = self.get_bounds(maxsize=True, force_no_pen=True)
        if not isinstance(self._pixmap, QMovie):
            _scaled = self._pixmap.scaled(w, h, self._aspect_ratio_mode,
                                          Qt.SmoothTransformation)
            # Make sure the image is centered if smaller than the widget itself
            if w > _scaled.width():
                logger.debug("Centering image horizontally ...")
                x += (w - _scaled.width()) / 2
            if h > _scaled.height():
                logger.debug("Centering image vertically ...")
                y += (h - _scaled.height()) / 2
            painter.drawPixmap(x, y, _scaled)

    def movie_frame_changed(self, frame_no):
        """
        Callback executed when a new frame is available at the QMovie.

        Parameters
        ----------
        frame_no : int
            The new frame index

        Returns
        -------
        None

        """
        if self._movie is None:
            return
        curr_pixmap = self._movie.currentPixmap()
        self._pixmap = curr_pixmap
        self.update()

    def movie_finished(self):
        """
        Callback executed when the movie is finished.

        Returns
        -------
        None
        """
        if self._movie is None:
            return

        self._movie.start()
Exemplo n.º 25
0
def graph2icon(g: Graph,
               width: int,
               node_mode: bool,
               show_label: bool,
               monochrome: bool,
               *,
               except_node: Optional[int] = None,
               engine: str = "",
               pos: Optional[_Pos] = None) -> QIcon:
    """Draw a generalized chain graph."""
    if engine:
        pos = engine_picker(g, engine, node_mode)
    if pos is None:
        raise ValueError("no engine selected")
    if not pos:
        pixmap = QPixmap(width, width)
        pixmap.fill(Qt.transparent)
        return QIcon(pixmap)

    width_bound = -float('inf')
    for x, y in pos.values():
        if abs(x) > width_bound:
            width_bound = x
        if abs(y) > width_bound:
            width_bound = y
    width_bound *= 2.5
    image = QImage(QSize(int(width_bound), int(width_bound)),
                   QImage.Format_ARGB32_Premultiplied)
    image.fill(Qt.transparent)
    painter = QPainter(image)
    painter.translate(image.width() / 2, image.height() / 2)
    pen = QPen()
    r = int(width_bound / 50)
    pen.setWidth(r)
    painter.setPen(pen)
    _font.setPixelSize(r * 6)
    painter.setFont(_font)

    # Draw edges
    if node_mode:
        for l1, l2 in g.edges:
            if except_node in {l1, l2}:
                pen.setColor(Qt.gray)
            else:
                pen.setColor(Qt.black)
            painter.setPen(pen)

            painter.drawLine(QPointF(pos[l1][0], -pos[l1][1]),
                             QPointF(pos[l2][0], -pos[l2][1]))
    else:
        color = color_qt('dark-gray') if monochrome else LINK_COLOR
        color.setAlpha(150)
        painter.setBrush(QBrush(color))
        for link in g.vertices:
            if link == except_node:
                pen.setColor(Qt.gray)
            else:
                pen.setColor(Qt.black)
            painter.setPen(pen)

            painter.drawPolygon(*convex_hull([(pos[n][0], -pos[n][1])
                                              for n, edge in edges_view(g)
                                              if link in edge],
                                             as_qpoint=True))

    # Draw vertices
    for k, (x, y) in pos.items():
        if node_mode:
            color = color_num(len(list(g.neighbors(k))) - 1)
            if k == except_node:
                color.setAlpha(150)
        else:
            if monochrome:
                color = Qt.black
            elif except_node in dict(edges_view(g))[k]:
                color = color_qt('green')
            else:
                color = color_qt('blue')
        pen.setColor(color)
        painter.setPen(pen)
        painter.setBrush(QBrush(color))
        point = QPointF(x, -y)
        painter.drawEllipse(point, r, r)
        if show_label:
            pen.setColor(Qt.darkMagenta)
            painter.setPen(pen)
            painter.drawText(point, str(k))
    painter.end()
    return QIcon(QPixmap.fromImage(image).scaledToWidth(width))
Exemplo n.º 26
0
    def __init__(self,
                 parent,
                 data=None,
                 readonly=False,
                 bg_value=None,
                 bg_gradient='blue-red',
                 minvalue=None,
                 maxvalue=None,
                 digits=None):
        QWidget.__init__(self, parent)
        assert bg_gradient in gradient_map
        if data is not None and np.isscalar(data):
            readonly = True
        self.readonly = readonly

        # prepare internal views and models
        self.model_axes = AxesArrayModel(parent=self, readonly=readonly)
        self.view_axes = AxesView(parent=self, model=self.model_axes)

        self.model_hlabels = LabelsArrayModel(parent=self, readonly=readonly)
        self.view_hlabels = LabelsView(parent=self,
                                       model=self.model_hlabels,
                                       hpos=RIGHT,
                                       vpos=TOP)

        self.model_vlabels = LabelsArrayModel(parent=self, readonly=readonly)
        self.view_vlabels = LabelsView(parent=self,
                                       model=self.model_vlabels,
                                       hpos=LEFT,
                                       vpos=BOTTOM)

        self.model_data = DataArrayModel(parent=self,
                                         readonly=readonly,
                                         minvalue=minvalue,
                                         maxvalue=maxvalue)
        self.view_data = DataView(parent=self, model=self.model_data)

        # in case data is None
        self.data_adapter = None

        # Create vertical and horizontal scrollbars
        self.vscrollbar = ScrollBar(self, self.view_data.verticalScrollBar())
        self.hscrollbar = ScrollBar(self, self.view_data.horizontalScrollBar())

        # Synchronize resizing
        self.view_axes.horizontalHeader().sectionResized.connect(
            self.view_vlabels.updateSectionWidth)
        self.view_axes.verticalHeader().sectionResized.connect(
            self.view_hlabels.updateSectionHeight)
        self.view_hlabels.horizontalHeader().sectionResized.connect(
            self.view_data.updateSectionWidth)
        self.view_vlabels.verticalHeader().sectionResized.connect(
            self.view_data.updateSectionHeight)
        # Synchronize auto-resizing
        self.view_axes.horizontalHeader().sectionHandleDoubleClicked.connect(
            self.resize_axes_column_to_contents)
        self.view_hlabels.horizontalHeader(
        ).sectionHandleDoubleClicked.connect(
            self.resize_hlabels_column_to_contents)
        self.view_axes.verticalHeader().sectionHandleDoubleClicked.connect(
            self.resize_axes_row_to_contents)
        self.view_vlabels.verticalHeader().sectionHandleDoubleClicked.connect(
            self.resize_vlabels_row_to_contents)

        # synchronize specific methods
        self.view_axes.allSelected.connect(self.view_data.selectAll)
        self.view_data.signal_copy.connect(self.copy)
        self.view_data.signal_excel.connect(self.to_excel)
        self.view_data.signal_paste.connect(self.paste)
        self.view_data.signal_plot.connect(self.plot)

        # propagate changes (add new items in the QUndoStack attribute of MappingEditor)
        self.model_data.newChanges.connect(self.data_changed)

        # Synchronize scrolling
        # data <--> hlabels
        self.view_data.horizontalScrollBar().valueChanged.connect(
            self.view_hlabels.horizontalScrollBar().setValue)
        self.view_hlabels.horizontalScrollBar().valueChanged.connect(
            self.view_data.horizontalScrollBar().setValue)
        # data <--> vlabels
        self.view_data.verticalScrollBar().valueChanged.connect(
            self.view_vlabels.verticalScrollBar().setValue)
        self.view_vlabels.verticalScrollBar().valueChanged.connect(
            self.view_data.verticalScrollBar().setValue)

        # Synchronize selecting columns(rows) via hor.(vert.) header of x(y)labels view
        self.view_hlabels.horizontalHeader().sectionPressed.connect(
            self.view_data.selectColumn)
        self.view_hlabels.horizontalHeader().sectionEntered.connect(
            self.view_data.selectNewColumn)
        self.view_vlabels.verticalHeader().sectionPressed.connect(
            self.view_data.selectRow)
        self.view_vlabels.verticalHeader().sectionEntered.connect(
            self.view_data.selectNewRow)

        # following lines are required to keep usual selection color
        # when selecting rows/columns via headers of label views.
        # Otherwise, selected rows/columns appear in grey.
        self.view_data.setStyleSheet("""QTableView {
            selection-background-color: palette(highlight);
            selection-color: white;
        }""")

        # set external borders
        array_frame = QFrame(self)
        array_frame.setFrameStyle(QFrame.StyledPanel)
        # remove borders of internal tables
        self.view_axes.setFrameStyle(QFrame.NoFrame)
        self.view_hlabels.setFrameStyle(QFrame.NoFrame)
        self.view_vlabels.setFrameStyle(QFrame.NoFrame)
        self.view_data.setFrameStyle(QFrame.NoFrame)
        # Set layout of table views:
        # [ axes  ][hlabels]|V|
        # [vlabels][ data  ]|s|
        # |  H. scrollbar  |
        array_layout = QGridLayout()
        array_layout.addWidget(self.view_axes, 0, 0)
        array_layout.addWidget(self.view_hlabels, 0, 1)
        array_layout.addWidget(self.view_vlabels, 1, 0)
        self.view_data.setSizePolicy(QSizePolicy.Expanding,
                                     QSizePolicy.Expanding)
        array_layout.addWidget(self.view_data, 1, 1)
        array_layout.addWidget(self.vscrollbar, 0, 2, 2, 1)
        array_layout.addWidget(self.hscrollbar, 2, 0, 1, 2)
        array_layout.setSpacing(0)
        array_layout.setContentsMargins(0, 0, 0, 0)
        array_frame.setLayout(array_layout)

        # Set filters and buttons layout
        self.filters_layout = QHBoxLayout()
        self.btn_layout = QHBoxLayout()
        self.btn_layout.setAlignment(Qt.AlignLeft)

        label = QLabel("Digits")
        self.btn_layout.addWidget(label)
        spin = QSpinBox(self)
        spin.valueChanged.connect(self.digits_changed)
        self.digits_spinbox = spin
        self.btn_layout.addWidget(spin)
        self.digits = 0

        scientific = QCheckBox(_('Scientific'))
        scientific.stateChanged.connect(self.scientific_changed)
        self.scientific_checkbox = scientific
        self.btn_layout.addWidget(scientific)
        self.use_scientific = False

        gradient_chooser = QComboBox()
        gradient_chooser.setMaximumSize(120, 20)
        gradient_chooser.setIconSize(QSize(100, 20))

        pixmap = QPixmap(100, 15)
        pixmap.fill(Qt.white)
        gradient_chooser.addItem(QIcon(pixmap), " ")

        pixmap.fill(Qt.transparent)
        painter = QPainter(pixmap)
        for name, gradient in available_gradients[1:]:
            qgradient = gradient.as_qgradient()

            # * fill with white because gradient can be transparent and if we do not "start from whilte", it skews the
            #   colors.
            # * 1 and 13 instead of 0 and 15 to have a transparent border around/between the gradients
            painter.fillRect(0, 1, 100, 13, Qt.white)
            painter.fillRect(0, 1, 100, 13, qgradient)
            gradient_chooser.addItem(QIcon(pixmap), name, gradient)

        # without this, we can crash python :)
        del painter, pixmap
        # select default gradient
        # requires Qt5+
        # gradient_chooser.setCurrentText(bg_gradient)
        gradient_chooser.setCurrentIndex(
            gradient_chooser.findText(bg_gradient))
        gradient_chooser.currentIndexChanged.connect(self.gradient_changed)
        self.btn_layout.addWidget(gradient_chooser)
        self.gradient_chooser = gradient_chooser

        # Set widget layout
        layout = QVBoxLayout()
        layout.addLayout(self.filters_layout)
        layout.addWidget(array_frame)
        layout.addLayout(self.btn_layout)
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

        # set gradient
        self.model_data.set_bg_gradient(gradient_map[bg_gradient])

        # set data
        if data is not None:
            self.set_data(data, bg_value=bg_value, digits=digits)

        # See http://doc.qt.io/qt-4.8/qt-draganddrop-fridgemagnets-dragwidget-cpp.html for an example
        self.setAcceptDrops(True)
Exemplo n.º 27
0
class MapGraphicsScene(QGraphicsScene):
    """Graphics scene for showing a slippy map.
    """

    sigZoomChanged = Signal(int)

    def __init__(self, tileSource, parent=None):
        """Constructor.

        Args:
            tileSource(MapTileSource): Source for loading the tiles.
            parent(QObject): Parent object, default `None`
        """
        QGraphicsScene.__init__(self, parent=parent)

        self._zoom = 15

        self._tileSource = tileSource
        self._tileSource.setParent(self)
        self._tileSource.tileReceived.connect(self.setTilePixmap)
        tdim = self._tileSource.tileSize()

        self._emptyTile = QPixmap(tdim, tdim)
        self._emptyTile.fill(Qt.lightGray)

        self._tilesRect = QRect()
        self._tilePixmaps = {}

        self._tileInDownload = list()

        self.setSceneRect(0.0, 0.0, 400, 300)
        self.sceneRectChanged.connect(self.onSceneRectChanged)

    @Slot()
    def close(self):
        self._tileSource.close()

    def setTileSource(self, newTileSource):
        self._tileSource.tileReceived.disconnect(self.setTilePixmap)
        self._tileSource.close()

        self._tilePixmaps.clear()
        self._tileInDownload = list()

        self._tileSource = newTileSource
        self._tileSource.setParent(self)
        self._tileSource.tileReceived.connect(self.setTilePixmap)

        self.requestTiles()

        self.invalidate()
        self.update()

    @Slot(QRectF)
    def onSceneRectChanged(self, rect):
        """Callback for the changing of the visible rect.

        Evaluate the visible tiles and request to load the new tiles.

        Args:
            rect(QRectF): Current visible area.
        """
        tdim = self._tileSource.tileSize()
        center = rect.center()
        ct = self.tileFromPos(center.x(), center.y())
        tx = ct.x()
        ty = ct.y()

        width = rect.width()
        height = rect.height()
        # top left corner of the center tile
        xp = int(width / 2.0 - (tx - floor(tx)) * tdim)
        yp = int(height / 2.0 - (ty - floor(ty)) * tdim)

        # first tile vertical and horizontal
        xs = tx - (xp + tdim - 1) / tdim
        ys = ty - (yp + tdim - 1) / tdim

        # last tile vertical and horizontal
        xe = (width - xp - 1) / tdim - xs + 1 + tx
        ye = (height - yp - 1) / tdim - ys + 1 + ty

        # define the rect of visible tiles
        self._tilesRect = QRect(xs, ys, xe, ye)

        # Request the loading of new tiles (if needed)
        self.requestTiles()

        self.invalidate()
        self.update()

    def drawBackground(self, painter, rect):
        """Draw the background tiles.

        If a tile is not available, draw a gray rectangle.

        Args:
            painter(QPainter): Painter for drawing.
            rect(QRectF): Current visible area.
        """
        tilesRect = self._tilesRect
        left = tilesRect.left()
        top = tilesRect.top()
        numXtiles = tilesRect.width()
        numYtiles = tilesRect.height()
        tdim = self._tileSource.tileSize()
        pixRect = QRectF(0.0, 0.0, tdim, tdim)
        emptyTilePix = self._emptyTile
        tilePixmaps = self._tilePixmaps

        for x in iterRange(numXtiles+1):
            for y in iterRange(numYtiles+1):
                tp = (x + left, y + top)
                box = self.tileRect(tp[0], tp[1])
                # Use default gray image if tile image is missing
                pix = tilePixmaps.get(tp, emptyTilePix)
                painter.drawPixmap(box, pix, pixRect)

    def zoomTo(self, pos, zoomlevel):
        """Zoom to a specific zoom level.

        If the level is out of range, the zoom action is ignored.

        clear the current tile cache, evaluate the new center and
        update the position of all the items.

        Args:
            zoomlevel(int): New zoom level.
        """

        tileSource = self._tileSource
        if zoomlevel > tileSource.maxZoom() or zoomlevel < tileSource.minZoom():
            return

        # Get the coordinates of the center using the position in pixels of the mouse
        pos_corr = self.views()[0].mapToScene(pos)
        coord = self.lonLatFromPos(pos_corr.x(), pos_corr.y())

        # Set the new zoom level
        self._zoom = zoomlevel

        # Clear cache and abort active requests
        self._tileSource.abortAllRequests()
        self._tilePixmaps.clear()

        # Re-center map so that the point on which it was zoomed is in the same position
        self.setCenter(coord[0], coord[1])
        pos_corr = self.views()[0].mapToScene(pos)
        center = self.sceneRect().center()
        self.translate(center.x() - pos_corr.x(), center.y() - pos_corr.y())

        self.sigZoomChanged.emit(zoomlevel)

    def zoomIn(self, pos=None):
        """Increments the zoom level

        Args:
            pos (QPointF): Center position, Latitude and Longitude. Default None for the
                           current center position.
        """
        if pos is None:
            pos = self.sceneRect().center()
        self.zoomTo(pos, self._zoom + 1)

    def zoomOut(self, pos=None):
        """Decrements the zoom level

        Args:
            pos (QPointF): Center position, Latitude and Longitude. Default None for the
                           current center position.
        """
        if pos is None:
            pos = self.sceneRect().center()
        self.zoomTo(pos, self._zoom - 1)

    def zoom(self):
        return self._zoom

    @Slot(int, int, int, QPixmap)
    def setTilePixmap(self, x, y, zoom, pixmap):
        """Set the image of the tile.

        Args:
            x(int): X coordinate of the tile.
            y(int): Y coordinate of the tile.
            zoom(int): Zoom coordinate of the tile.
            pixmap(QPixmap): Image for the tile.
        """
        if self._zoom == zoom:
            self._tilePixmaps[(x, y)] = pixmap
        self.update()

    def requestTiles(self):
        """Request the loading of tiles.

        Check the loaded tiles and requests only
        the missing tiles.
        """
        tilesRect = self._tilesRect
        tilePixmaps = self._tilePixmaps

        numXtiles = tilesRect.width()
        numYtiles = tilesRect.height()
        left = tilesRect.left()
        top = tilesRect.top()
        tileSource = self._tileSource
        zoom = self._zoom

        # Request load of new tiles
        for x in iterRange(numXtiles):
            for y in iterRange(numYtiles):
                tp = (left + x, top + y)
                # Request tile only if missing
                if tp not in tilePixmaps:
                    pix = tileSource.requestTile(tp[0], tp[1], zoom)
                    if pix is not None:
                        tilePixmaps[tp] = pix

        self.update()

    def tileRect(self, tx, ty):
        """Area for a specific tile.

        Args:
            tx(int): X coordinate of the tile.
            ty(int): Y coordinate of the tile.

        Returns:
            QRectF, the area of the tile.
        """
        tdim = self._tileSource.tileSize()
        return QRectF(tx * tdim, ty * tdim, tdim, tdim)

    def setSize(self, width, height):
        """Set the size of the visible area in pixels.

        Update the scene rect.

        Args:
            width(int): Width of the visible area.
            height(int): Height of the visible area.
        """
        rect = QRectF(self.sceneRect().topLeft(), QSizeF(width, height))
        self.setSceneRect(rect)

    def setCenter(self, lon, lat):
        """Move the center of the visible area to new coordinates.

        Update the scene rect.

        Args:
            lon(float): New longitude of the center.
            lat(float): New latitude of the center.
        """
        rect = QRectF(self.sceneRect())
        pos = self.posFromLonLat(lon, lat)
        rect.moveCenter(QPointF(pos[0], pos[1]))
        self.setSceneRect(rect)

    def center(self):
        centerPos = self.sceneRect().center()
        centerCoord = self.lonLatFromPos(centerPos.x(), centerPos.y())
        return QPointF(centerCoord[0], centerCoord[1])

    def translate(self, dx, dy):
        """Translate the visible area by dx, dy pixels.

        Update the scene rect.

        Args:
            dx(int): Increments for the center x coord in pixels.
            dy(int): Increments for the center y coord in pixels.
        """
        self.setSceneRect(self.sceneRect().translated(dx, dy))

    def posFromLonLat(self, lon, lat):
        """Position in scene coordinate of the WGS84 coordinates.

        Convert from WGS84 reference system to scene reference system.

        Args:
            lon(float or numpy.ndarray): Longitude value or values.
            lat(float or numpy.ndarray): Latitude value or values.

        Returns:
            tuple: (x, y) with the positions of the input coordinates.
        """
        return posFromLonLat(lon, lat, self._zoom, self._tileSource.tileSize())

    def lonLatFromPos(self, x, y):
        """Position in WGS84 coordinate of the scene coordinates.

        Convert from scene reference system to WGS84 reference system.

        Args:
            x(float, int or numpy.ndarray): X value or values.
            y(float, int or numpy.ndarray): Y value or values.

        Returns:
            tuple: (lon, lat) with the coordinates of the input positions.
        """
        return lonLatFromPos(x, y, self._zoom, self._tileSource.tileSize())

    def tileFromPos(self, x, y):
        """Tile in the selected position.

        Args:
            x(float, int): X value for position.
            y(float, int): Y value for position.

        Returns:
            QPointF with the coordinates of the tile.
        """
        tdim = float(self._tileSource.tileSize())
        return QPointF(x / tdim, y / tdim)

    def addCircle(self, longitude, latitude, radius):
        """Add a new circle to the graphics scene.

        Args:
            longitude(float): Longitude of the center of the circle.
            latitude(float): Latitude of the center of the circle.
            radius(float): Longitude of the center of the circle.

        Returns:
            MapGraphicsCircleItem added to the scene.
        """
        item = MapGraphicsCircleItem(longitude, latitude, radius)
        self.addItem(item)
        return item

    def addLine(self, lon0, lat0, lon1, lat1):
        """Add a newline) to the graphics scene.

        Args:
            lon0(float): Longitude of the start point.
            lat0(float): Latitude of the start point.
            lon1(float): Longitude of the end point.
            lat1(float): Latitude of the end point.

        Returns:
            MapGraphicsLineItem added to the scene.
        """
        item = MapGraphicsLineItem(lon0, lat0, lon1, lat1)
        self.addItem(item)
        return item

    def addRect(self, lon0, lat0, lon1, lat1):
        """Add a newline) to the graphics scene.

        Args:
            lon0(float): Longitude of the top left point.
            lat0(float): Latitude of the top left point.
            lon1(float): Longitude of the bottom right point.
            lat1(float): Latitude of the bottom right point.

        Returns:
            MapGraphicsLineItem added to the scene.
        """
        item = MapGraphicsRectItem(lon0, lat0, lon1, lat1)
        self.addItem(item)
        return item

    def addPolyline(self, longitudes, latitudes):
        """Add a new circle (point) to the graphics scene.

        Args:
            longitudes(iterable): Longitudes of all the points of the polyline.
            latitudes(iterable): Latitudes of all the points of the polyline.

        Returns:
            MapGraphicsPolylineItem added to the scene.
        """
        item = MapGraphicsPolylineItem(longitudes, latitudes)
        self.addItem(item)
        return item

    def addPixmap(self, longitude, latitude, pixmap):
        """Add a new circle (point) to the graphics scene.

        Args:
            longitude(float): Longitude of the origin of the pixmap.
            latitude(float): Latitude of the center of the pixmap.
            pixmap(QPixmap): Pixmap.

        Returns:
            MapGraphicsPixmapItem added to the scene.

        Note:
            Use `MapGraphicsPixmapItem.setOffset(off)` to translate by `off` pixels
            the pixmap respect the origin coordinates.
        """
        item = MapGraphicsPixmapItem(longitude, latitude, pixmap)
        self.addItem(item)
        return item

    def addText(self, longitude, latitude, text):
        """Add a test item to the graphics scene.

        Args:
            longitude(float): Longitude of the origin of the text
            latitude(float): Latitude of the origin of the text

        Returns:
            MapGraphicsTextItem added to the scene.
        """
        item = MapGraphicsTextItem(longitude, latitude, text)
        self.addItem(item)
        return item

    def addLegend(self, pos=QPointF(10.0, 10.0)):
        legend = MapLegendItem(pos=pos)
        self.addItem(legend)
        return legend

    def addScale(self, **kwargs):
        """Add a scale bar with text on the right bottom of the map

        Keyword Args:
            textPen: QPen to use for drawing the text. Default 'black'.
            barBrush: QBrush to use for drawing the scale bar. Default (190, 190, 190, 160)
            barPen: QPen to use for drawing the scale bar border. Default (190, 190, 190, 240)
            barBrushHover:  QBrush to use for drawing the scale bar when the mouse is over it.
                Default (110, 110, 110, 255).
            barPenHover: QPen to use for drawing the scale bar borderwhen the mouse is over it.
                Default (90, 90, 90, 255).

        Note:
            Almost all the argumnets accepted by the functions.makeBrush() and functions.makePen()
            are accepted.
        """
        scaleItem = MapScaleItem(**kwargs)
        self.addItem(scaleItem)
        return scaleItem

    def addLinesGroup(self, longitudes, latitudes):
        item = MapGraphicsLinesGroupItem(longitudes, latitudes)
        self.addItem(item)
        return item
Exemplo n.º 28
0
    def __init__(self):
        QMainWindow.__init__(self)

        view = MapGraphicsView(tileSource=MapTileSourceHere())

        self.setCentralWidget(view)

        view.scene().setCenter(10.065990, 44.861041, zoom=13)
        view.setOptimizationFlag(QGraphicsView.DontSavePainterState, True)
        view.setRenderHint(QPainter.Antialiasing, True)
        view.setRenderHint(QPainter.SmoothPixmapTransform, True)

        pointItem = view.scene().addCircle(10.068640, 44.860767, 3.0)
        pointItem.setBrush(Qt.black)
        pointItem.setToolTip('10.068640, 44.860767')
        pointItem.setFlag(QGraphicsItem.ItemIsSelectable, True)

        lats = list()
        lons = list()
        for p in POINTS:
            pointItem = view.scene().addCircle(p[1], p[0], 5.0)
            pointItem.setBrush(Qt.green)
            pointItem.setPen(QPen(Qt.NoPen))
            pointItem.setToolTip('%f, %f' % (p[1], p[0]))
            pointItem.setFlag(QGraphicsItem.ItemIsSelectable, True)
            lons.append(p[1])
            lats.append(p[0])

        lineItem = view.scene().addLine(10.191037, 44.832810, 10.201736,
                                        44.837632)
        lineItem.setPen(QPen(QBrush(Qt.blue), 3.0))

        polylineItem = view.scene().addPolyline(lons, lats)
        polylineItem.setPen(QPen(QBrush(Qt.red), 3.0))

        pix = QPixmap(24, 24)
        pix.fill(Qt.red)
        pixmapItem = view.scene().addPixmap(10.090598, 44.857893, pix)
        pixmapItem.setOffset(-12, -12)
        pointItemPixmapOrigin = view.scene().addCircle(10.090598, 44.857893,
                                                       3.0)
        pointItemPixmapOrigin.setBrush(Qt.black)

        # Pixmap with both corners geo-referenced
        geo_pixmap = QPixmap(36, 36)
        geo_pixmap.fill(Qt.blue)
        geo_pixmap_item = view.scene().addGeoPixmap(10.090598, 44.8709, 10.092,
                                                    44.873, geo_pixmap)
        geo_pixmap_item.setLabel("GeoPixmapItem")
        geo_pixmap_item.showLabel()

        # Blue Point with an HTML label
        blue_point = view.scene().addCircle(10.083103, 44.868014, 3.0)
        blue_point.setBrush(Qt.blue)
        blue_point.setPen(QPen(Qt.NoPen))
        blue_point.setLabel("<div style='background-color: #ffff00;'>" +
                            "Label for Blue Point" + "</div>",
                            html=True)
        blue_point.showLabel()

        # Location Pin
        pin_item = view.scene().addPin(10.06, 44.84)
        pin_item.setLabel(
            "<div style='background-color: #00ff00;'><I>Pin Item</I></div>",
            html=True)
        pin_item.showLabel()

        # Pixmap with all four corners geo-referenced
        lon0r = 10.06
        lat0r = 44.83
        lon1r = 10.110000000000001
        lat1r = 44.743397459621555
        lon2r = 9.936794919243113
        lat2r = 44.64339745962155
        lon3r = 9.886794919243112
        lat3r = 44.73

        clr = QColor(0, 255, 0, 100)
        pix = QPixmap(100, 100)
        pix.fill(clr)

        view.scene().addGeoPixmapCorners(lon0r, lat0r, lon1r, lat1r, lon2r,
                                         lat2r, lon3r, lat3r, pix)

        lats_2 = list()
        lons_2 = list()
        for p in POINTS_2:
            lons_2.append(p[1])
            lats_2.append(p[0])
        linesGroupItem = view.scene().addLinesGroup(lons_2, lats_2)
        linesGroupItem.setLineStyle(POINTS_2_COLORS, width=POINTS_2_SIZES)

        legendItem = view.scene().addLegend()
        legendItem.addPoint('Point 1', '#FF0000', border=None)
        legendItem.addRect('Rect 2', '#00FF00', border=None)
        legendItem.addPoint('Circle 3', '#0000FF', border=None)
        legendItem.addRect('Sphere 4', '#00FFFF', border=None)
        legendItem.addPoint('Polygon 5', '#FF00FF', border=None)

        navItem = view.scene().addNavItem(anchor=Qt.TopRightCorner)

        scaleItem = view.scene().addScale(anchor=Qt.BottomRightCorner)