Esempio n. 1
0
    def __init__(self, port_mode, port_type, parent):
        QGraphicsPathItem.__init__(self)
        self.setParentItem(parent)

        self.m_port_mode = port_mode
        self.m_port_type = port_type

        # Port position doesn't change while moving around line
        self.p_itemX = self.scenePos().x()
        self.p_itemY = self.scenePos().y()
        self.p_width = parent.getPortWidth()

        if port_type == PORT_TYPE_AUDIO_JACK:
            pen = QPen(canvas.theme.line_audio_jack, 2)
        elif port_type == PORT_TYPE_MIDI_JACK:
            pen = QPen(canvas.theme.line_midi_jack, 2)
        elif port_type == PORT_TYPE_MIDI_ALSA:
            pen = QPen(canvas.theme.line_midi_alsa, 2)
        elif port_type == PORT_TYPE_PARAMETER:
            pen = QPen(canvas.theme.line_parameter, 2)
        else:
            qWarning(
                "PatchCanvas::CanvasBezierLineMov({}, {}, {}) - invalid port type"
                .format(port_mode2str(port_mode), port_type2str(port_type),
                        parent))
            pen = QPen(Qt.black)

        pen.setCapStyle(Qt.FlatCap)
        pen.setWidthF(pen.widthF() + 0.00001)
        self.setPen(pen)
Esempio n. 2
0
 def shape(self):
     if self.__shape is None:
         path = self.path()
         pen = QPen(self.pen())
         pen.setWidthF(max(pen.widthF(), 7.0))
         pen.setStyle(Qt.SolidLine)
         self.__shape = stroke_path(path, pen)
     return self.__shape
Esempio n. 3
0
class PenWidthSettable(object):
    def __init__(self):
        self._pen = QPen()

    @property
    def penWidth(self) -> float:
        return self._pen.widthF()

    @penWidth.setter
    def penWidth(self, newWidth: number) -> None:
        self._pen.setWidthF(newWidth)
Esempio n. 4
0
    def paint(self, painter, option, widget):
        painter.save()
        painter.setRenderHint(QPainter.Antialiasing,
                              bool(options.antialiasing == ANTIALIASING_FULL))

        selected = self.isSelected()
        theme = canvas.theme
        if self.m_port_type == PORT_TYPE_AUDIO_JACK:
            poly_color = theme.port_audio_jack_bg_sel if selected else theme.port_audio_jack_bg
            poly_pen = theme.port_audio_jack_pen_sel if selected else theme.port_audio_jack_pen
            text_pen = theme.port_audio_jack_text_sel if selected else theme.port_audio_jack_text
            conn_pen = QPen(theme.port_audio_jack_pen_sel)
        elif self.m_port_type == PORT_TYPE_MIDI_JACK:
            poly_color = theme.port_midi_jack_bg_sel if selected else theme.port_midi_jack_bg
            poly_pen = theme.port_midi_jack_pen_sel if selected else theme.port_midi_jack_pen
            text_pen = theme.port_midi_jack_text_sel if selected else theme.port_midi_jack_text
            conn_pen = QPen(theme.port_midi_jack_pen_sel)
        elif self.m_port_type == PORT_TYPE_MIDI_ALSA:
            poly_color = theme.port_midi_alsa_bg_sel if selected else theme.port_midi_alsa_bg
            poly_pen = theme.port_midi_alsa_pen_sel if selected else theme.port_midi_alsa_pen
            text_pen = theme.port_midi_alsa_text_sel if selected else theme.port_midi_alsa_text
            conn_pen = QPen(theme.port_midi_alsa_pen_sel)
        elif self.m_port_type == PORT_TYPE_PARAMETER:
            poly_color = theme.port_parameter_bg_sel if selected else theme.port_parameter_bg
            poly_pen = theme.port_parameter_pen_sel if selected else theme.port_parameter_pen
            text_pen = theme.port_parameter_text_sel if selected else theme.port_parameter_text
            conn_pen = QPen(theme.port_parameter_pen_sel)
        else:
            qCritical(
                "PatchCanvas::CanvasPort.paint() - invalid port type '%s'" %
                port_type2str(self.m_port_type))
            return

        # To prevent quality worsening
        poly_pen = QPen(poly_pen)
        poly_pen.setWidthF(poly_pen.widthF() + 0.00001)

        if self.m_is_alternate:
            poly_color = poly_color.darker(180)
            #poly_pen.setColor(poly_pen.color().darker(110))
            #text_pen.setColor(text_pen.color()) #.darker(150))
            #conn_pen.setColor(conn_pen.color()) #.darker(150))

        lineHinting = poly_pen.widthF() / 2

        poly_locx = [0, 0, 0, 0, 0]
        poly_corner_xhinting = (float(canvas.theme.port_height) / 2) % floor(
            float(canvas.theme.port_height) / 2)
        if poly_corner_xhinting == 0:
            poly_corner_xhinting = 0.5 * (
                1 - 7 / (float(canvas.theme.port_height) / 2))

        if self.m_port_mode == PORT_MODE_INPUT:
            text_pos = QPointF(3, canvas.theme.port_text_ypos)

            if canvas.theme.port_mode == Theme.THEME_PORT_POLYGON:
                poly_locx[0] = lineHinting
                poly_locx[1] = self.m_port_width + 5 - lineHinting
                poly_locx[2] = self.m_port_width + 12 - poly_corner_xhinting
                poly_locx[3] = self.m_port_width + 5 - lineHinting
                poly_locx[4] = lineHinting
            elif canvas.theme.port_mode == Theme.THEME_PORT_SQUARE:
                poly_locx[0] = lineHinting
                poly_locx[1] = self.m_port_width + 5 - lineHinting
                poly_locx[2] = self.m_port_width + 5 - lineHinting
                poly_locx[3] = self.m_port_width + 5 - lineHinting
                poly_locx[4] = lineHinting
            else:
                qCritical(
                    "PatchCanvas::CanvasPort.paint() - invalid theme port mode '%s'"
                    % canvas.theme.port_mode)
                return

        elif self.m_port_mode == PORT_MODE_OUTPUT:
            text_pos = QPointF(9, canvas.theme.port_text_ypos)

            if canvas.theme.port_mode == Theme.THEME_PORT_POLYGON:
                poly_locx[0] = self.m_port_width + 12 - lineHinting
                poly_locx[1] = 7 + lineHinting
                poly_locx[2] = 0 + poly_corner_xhinting
                poly_locx[3] = 7 + lineHinting
                poly_locx[4] = self.m_port_width + 12 - lineHinting
            elif canvas.theme.port_mode == Theme.THEME_PORT_SQUARE:
                poly_locx[0] = self.m_port_width + 12 - lineHinting
                poly_locx[1] = 5 + lineHinting
                poly_locx[2] = 5 + lineHinting
                poly_locx[3] = 5 + lineHinting
                poly_locx[4] = self.m_port_width + 12 - lineHinting
            else:
                qCritical(
                    "PatchCanvas::CanvasPort.paint() - invalid theme port mode '%s'"
                    % canvas.theme.port_mode)
                return

        else:
            qCritical(
                "PatchCanvas::CanvasPort.paint() - invalid port mode '%s'" %
                port_mode2str(self.m_port_mode))
            return

        polygon = QPolygonF()
        polygon += QPointF(poly_locx[0], lineHinting)
        polygon += QPointF(poly_locx[1], lineHinting)
        polygon += QPointF(poly_locx[2], float(canvas.theme.port_height) / 2)
        polygon += QPointF(poly_locx[3],
                           canvas.theme.port_height - lineHinting)
        polygon += QPointF(poly_locx[4],
                           canvas.theme.port_height - lineHinting)
        polygon += QPointF(poly_locx[0], lineHinting)

        if canvas.theme.port_bg_pixmap:
            portRect = polygon.boundingRect().adjusted(-lineHinting + 1,
                                                       -lineHinting + 1,
                                                       lineHinting - 1,
                                                       lineHinting - 1)
            portPos = portRect.topLeft()
            painter.drawTiledPixmap(portRect, canvas.theme.port_bg_pixmap,
                                    portPos)
        else:
            painter.setBrush(poly_color)  #.lighter(200))

        painter.setPen(poly_pen)
        painter.drawPolygon(polygon)

        painter.setPen(text_pen)
        painter.setFont(self.m_port_font)
        painter.drawText(text_pos, self.m_port_name)

        if canvas.theme.idx == Theme.THEME_OOSTUDIO and canvas.theme.port_bg_pixmap:
            conn_pen.setCosmetic(True)
            conn_pen.setWidthF(0.4)
            painter.setPen(conn_pen)

            if self.m_port_mode == PORT_MODE_INPUT:
                connLineX = portRect.left() + 1
            else:
                connLineX = portRect.right() - 1
            conn_path = QPainterPath()
            conn_path.addRect(
                QRectF(connLineX - 1, portRect.top(), 2, portRect.height()))
            painter.fillPath(conn_path, conn_pen.brush())
            painter.drawLine(
                QLineF(connLineX, portRect.top(), connLineX,
                       portRect.bottom()))

        painter.restore()
Esempio n. 5
0
class Connection(QGraphicsItem):
    _startSocket = None
    _endSocket = None

    def __init__(self,
                 start_socket,
                 end_socket=None,
                 id_=None,
                 style="solid",
                 curve=True):
        QGraphicsItem.__init__(self, None)

        if id_ is None:
            id_ = id(self)

        self.id = id_

        self._rect = QRectF(0, 0, 0, 0)

        self._isTempConnection = False

        self._path = QPainterPath()

        self._activeStyle = style
        self._curve = curve
        self._isActive = False

        self._color = start_socket.colorRef()
        self._pen = QPen(self._color)

        self._penWidthInactive = 2
        self._penWidthActive = 4
        self._penWidthBlink = 8

        self._penWidth = self._penWidthInactive

        self.setStartSocket(start_socket)

        self._keyPoints = []

        self._centerWidget = None

        if end_socket is None:
            # creating a dummy endHook for temporary connection dragging,
            #  the "input" and shape/style parameters have no effect
            end_mode = "output" if start_socket.isInput() else "input"
            end_socket = QtSocket(start_socket.parentSocketRow(),
                                  end_mode,
                                  start_socket._shape,
                                  parent_item=self)
            end_socket.boundingRect().setSize(QSizeF(2.0, 2.0))
            self._isTempConnection = True

        self.setEndConnection(end_socket)

        self.updateStartPos()

        self.setZValue(-1.0)
        self.setActiveState(False)

        self._blink_depth = 0

    def startSocket(self):
        if self._startSocket is None:
            return None

        return self._startSocket()

    def endSocket(self):
        if self._endSocket is None:
            return None

        return self._endSocket()

    @property
    def index(self):
        index, total = self.startSocket().getIndexInfo(self)
        return index

    @property
    def is_active(self):
        return self._isActive

    def boundingRect(self):
        return self._rect

    def setKeyPoints(self, interpoints):
        s = self.scenePos()
        sx, sy = s.x(), s.y()
        self._keyPoints = [QPointF(x - sx, -y - sy) for x, y in interpoints]

    def insertKeyPoint(self, index, coordinate):
        if index is None:
            self._keyPoints.append(coordinate)
        else:
            self._keyPoints.insert(index, coordinate)

    def removeKeyPoint(self, index):
        self._keyPoints.pop(self._keyPoints)

    def findNearestKeyPoints(self, coordinate):
        points = []

        start_socket = self._startSocket()
        start_pos = start_socket.scenePos() + start_socket.boundingRect(
        ).center()
        points.append(start_pos)

        points += self._keyPoints
        distances = [(i, sub(point, coordinate))
                     for i, point in enumerate(points)]

        if self.endSocket():
            end_socket = self.endSocket()
            end_position = end_socket.scenePos() + end_socket.boundingRect(
            ).center()
            distances.append((-1, self._difDistance(end_position, coordinate)))

        if len(distances) == 1:
            return distances[0][0], None

        distances.sort(key=lambda item: item[1])
        return distances[0][0], distances[1][0]

    def intersectsCircle(self, position, rect, size):
        size_sqr = size**2
        scene_translation = self.startSocket().sceneTransform()
        connection_rect = scene_translation.mapRect(self._rect)

        # Line circle intersection test http://i.stack.imgur.com/P556i.png
        if connection_rect.contains(rect) or (
                connection_rect.width() <= size
                or connection_rect.height() <= size):
            connection_path = scene_translation.map(self._path)
            simplified_path = connection_path.simplified()

            element_count = simplified_path.elementCount() - 1

            # In case path is linear
            if element_count == -1:
                simplified_path = connection_path
                element_count = simplified_path.elementCount()

            previous_point = None
            for i in range(element_count):
                element = simplified_path.elementAt(i)
                point = QPointF(element.x, element.y)

                previous_point, _previous_point = point, previous_point

                if _previous_point is None:
                    continue

                to_position = QVector2D(position - _previous_point)
                to_end = QVector2D(point - _previous_point)

                to_end_length = to_end.length()
                if not to_end_length:
                    continue

                projection = QVector2D.dotProduct(to_position,
                                                  to_end) / to_end_length

                # Projected point lies within this segment
                if 0 <= projection <= to_end_length:
                    dist_path_sqr = to_position.lengthSquared() - projection**2

                    if dist_path_sqr < size_sqr:
                        return self

    def intersectsLine(self, line, path_rect):
        scene_translation = self.startSocket().sceneTransform()
        connection_rect = scene_translation.mapRect(self._rect)

        if connection_rect.contains(path_rect) or path_rect.contains(connection_rect) \
                or path_rect.intersects(connection_rect):

            connection_path = scene_translation.map(self._path)
            simplified_path = connection_path.simplified()

            element_count = simplified_path.elementCount() - 1

            # In case path is linear
            if element_count == -1:
                simplified_path = connection_path
                element_count = simplified_path.elementCount()

            previous_point = None
            for i in range(element_count):
                element = simplified_path.elementAt(i)

                point = QPointF(element.x, element.y)
                if previous_point is not None:
                    segment = QLineF(previous_point, point)

                    intersect_point = QPointF()
                    intersect_type = segment.intersect(line, intersect_point)

                    if intersect_type == QLineF.BoundedIntersection:
                        return True

                previous_point = point

    def blink(self, time):
        self._pen.setWidth(self._penWidthBlink)
        self.update()

        timer = QTimer()

        def on_finished():
            self._blink_depth -= 1

            # Allow multiple blinks without flashing
            if not self._blink_depth:
                self._pen.setWidth(self._penWidth)
                self.update()

        self._blink_depth += 1
        timer.singleShot(1000 * time, on_finished)

    def setActiveState(self, active):
        assert active in (True, False), active

        if active:
            self._penWidth = self._penWidthActive

        else:
            self._penWidth = self._penWidthInactive

        self._pen.setWidth(self._penWidth)

        value = self._activeStyle

        if value == "dashed":
            self._pen.setStyle(Qt.DashLine)

        elif value == "solid":
            self._pen.setStyle(Qt.SolidLine)

        elif value == "dot":
            self._pen.setStyle(Qt.DotLine)

        else:
            raise ValueError("Unknown pen style '%s'" % value)

        self._isActive = active
        self.update()

    def onDeleted(self):
        self.setEndConnection(None)
        self.setStartSocket(None)

    def updateStartPos(self):
        start_socket = self.startSocket()
        self.setPos(start_socket.scenePos() +
                    start_socket.boundingRect().center())

        self.updatePath()

    def updateEndPos(self):
        self.updatePath()

    def updateVisibility(self):
        visible = self.startSocket().isVisible() and self.endSocket(
        ).isVisible()
        self.setVisible(visible)

    def setColor(self, color):
        if isinstance(color, tuple):
            color = QColor(*color)

        else:
            color = QColor(color)

        self._color = color

    def setStartSocket(self, socket):
        if self.startSocket():
            self.startSocket().removeConnection(self)

        self._startSocket = None

        if socket is not None:
            self._startSocket = weakref.ref(socket)
            socket.addConnection(self)

    def setEndConnection(self, socket):
        if self.endSocket():
            self.endSocket().removeConnection(self)

        self._endSocket = None

        if socket is not None:
            self._endSocket = weakref.ref(socket)
            socket.addConnection(self)

    def setCenterWidget(self, widget):
        self._centerWidget = widget

    def centerWidget(self):
        return self._centerWidget

    def findClosestSocket(self):
        closest_socket = None

        colliding_items = self.endSocket().collidingItems(
            Qt.IntersectsItemBoundingRect)

        for colliding_item in colliding_items:
            if isinstance(colliding_item, QtSocket):
                if colliding_item.isInput() and colliding_item.isVisible():
                    closest_socket = colliding_item

                break

        return closest_socket

    def updatePath(self):
        end_hook = self.endSocket()

        if end_hook is None:
            return

        self.prepareGeometryChange()
        end_pos = self.mapFromItem(end_hook, 0.0,
                                   0.0) + end_hook.boundingRect().center()

        if self._curve:
            if not self._keyPoints:
                tangent_length = (abs(end_pos.x()) / 2.0) + (abs(end_pos.y()) /
                                                             4.0)
                tangent_length2 = tangent_length

            else:
                first_pos = self._keyPoints[0]
                tangent_length = (abs(first_pos.x()) /
                                  2.0) + (abs(first_pos.y()) / 4.0)
                last_pos = self._keyPoints[-1]
                last_segment = end_pos - last_pos
                tangent_length2 = (abs(last_segment.x()) /
                                   2.0) + (abs(last_segment.y()) / 4.0)

            spread = 60.0 / 180.0 * pi

            # Find connection index
            index, number_connections = self.startSocket().getIndexInfo(self)

            dev = (index - number_connections / 2.0 + 0.5) * min(
                spread, pi / (number_connections + 2))
            tx = tangent_length * cos(dev)
            ty = tangent_length * sin(dev)

            start_tangent = QPointF(tx, ty)
            end_tangent = QPointF(end_pos.x() - tangent_length2, end_pos.y())

            path = QPainterPath()
            path.cubicTo(start_tangent, end_tangent, end_pos)

        # Dot styles are used for relationships
        else:
            path = QPainterPath()
            path.lineTo(end_pos)

        stroke_width = self._pen.widthF()
        rect = path.boundingRect().adjusted(-stroke_width, -stroke_width,
                                            stroke_width, stroke_width)

        # draw widget
        center_widget = self._centerWidget

        if center_widget is not None:
            center = path.pointAtPercent(0.5)
            center_widget.onUpdated(center, text=str(self.index))

        self._path = path
        self._rect = rect

    def onSocketHoverEnter(self):
        center_widget = self._centerWidget

        if center_widget is not None:
            center_widget.setVisible(True)

    def onSocketHoverExit(self):
        center_widget = self._centerWidget
        if center_widget is not None:
            center_widget.setVisible(False)

    def paint(self, painter, option, widget):
        self._pen.setColor(self._color)
        painter.setPen(self._pen)
        painter.drawPath(self._path)
Esempio n. 6
0
    def drawMapObject(self, painter, object, color):
        painter.save()
        bounds = object.bounds()
        rect = QRectF(bounds)
        painter.translate(rect.topLeft())
        rect.moveTopLeft(QPointF(0, 0))
        cell = object.cell()
        if (not cell.isEmpty()):
            CellRenderer(painter).render(cell, QPointF(), object.size(), CellRenderer.BottomLeft)
            if (self.testFlag(RenderFlag.ShowTileObjectOutlines)):
                tile = cell.tile
                imgSize = tile.size()
                tileOffset = tile.offset()
                rect = QRectF(QPointF(tileOffset.x(), tileOffset.y() - imgSize.height()), QSizeF(imgSize))
                pen = QPen(Qt.SolidLine)
                pen.setCosmetic(True)
                painter.setPen(pen)
                painter.drawRect(rect)
                pen.setStyle(Qt.DotLine)
                pen.setColor(color)
                painter.setPen(pen)
                painter.drawRect(rect)
        else:
            lineWidth = self.objectLineWidth()
            scale = self.painterScale()
            if lineWidth == 0:
                x = 1
            else:
                x = lineWidth
            shadowDist = x / scale
            shadowOffset = QPointF(shadowDist * 0.5, shadowDist * 0.5)
            linePen = QPen(color, lineWidth, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
            #linePen.setCosmetic(True)
            shadowPen = QPen(linePen)
            shadowPen.setColor(Qt.black)
            brushColor = QColor(color)
            fillBrush = QBrush(brushColor)
            painter.setRenderHint(QPainter.Antialiasing)
            # Trying to draw an ellipse with 0-width is causing a hang in
            # CoreGraphics when drawing the path requested by the
            # QCoreGraphicsPaintEngine. Draw them as rectangle instead.
            shape = object.shape()
            if (shape == MapObject.Ellipse and ((rect.width() == 0.0) ^ (rect.height() == 0.0))):
                shape = MapObject.Rectangle
            x = shape
            if x==MapObject.Rectangle:
                if (rect.isNull()):
                    rect = QRectF(QPointF(-10, -10), QSizeF(20, 20))
                # Draw the shadow
                painter.setPen(shadowPen)
                painter.drawRect(rect.translated(shadowOffset))
                painter.setPen(linePen)
                painter.setBrush(fillBrush)
                painter.drawRect(rect)
            elif x==MapObject.Polyline:
                screenPolygon = self.pixelToScreenCoords_(object.polygon())
                thickShadowPen = QPen(shadowPen)
                thickLinePen = QPen(linePen)
                thickShadowPen.setWidthF(thickShadowPen.widthF() * 4)
                thickLinePen.setWidthF(thickLinePen.widthF() * 4)
            
                painter.setPen(shadowPen)
                painter.drawPolyline(screenPolygon.translated(shadowOffset))
                painter.setPen(thickShadowPen)
                painter.drawPoint(screenPolygon.first() + shadowOffset)
            
                painter.setPen(linePen)
                painter.setBrush(fillBrush)
                painter.drawPolyline(screenPolygon)
                painter.setPen(thickLinePen)
                painter.drawPoint(screenPolygon.first())
            
            elif x==MapObject.Polygon:
                screenPolygon = self.pixelToScreenCoords_(object.polygon())
                thickShadowPen = QPen(shadowPen)
                thickLinePen = QPen(linePen)
                thickShadowPen.setWidthF(thickShadowPen.widthF() * 4)
                thickLinePen.setWidthF(thickLinePen.widthF() * 4)
                
                painter.setPen(shadowPen)
                painter.drawPolygon(screenPolygon.translated(shadowOffset))
                painter.setPen(thickShadowPen)
                painter.drawPoint(screenPolygon.first() + shadowOffset)
                
                painter.setPen(linePen)
                painter.setBrush(fillBrush)
                painter.drawPolygon(screenPolygon)
                
                painter.setPen(thickLinePen)
                painter.drawPoint(screenPolygon.first())
                
            elif x==MapObject.Ellipse:
                if (rect.isNull()):
                    rect = QRectF(QPointF(-10, -10), QSizeF(20, 20))
                # Draw the shadow
                painter.setPen(shadowPen)
                painter.drawEllipse(rect.translated(shadowOffset))
                painter.setPen(linePen)
                painter.setBrush(fillBrush)
                painter.drawEllipse(rect)

        painter.restore()
Esempio n. 7
0
def _map_physical_pen_to_scene(pen, scale_factor):
    scaled_pen = QPen(pen)
    scaled_pen.setWidthF(scale_factor * scaled_pen.widthF())
    return scaled_pen
Esempio n. 8
0
class PrimaryFlightDisplay(QWidget):
    ROLL_SCALE_RANGE = 60
    ROLL_SCALE_TICKMARKLENGTH = 0.04
    ROLL_SCALE_RADIUS = 0.42
    ROLL_SCALE_MARKERWIDTH = 0.06
    ROLL_SCALE_MARKERHEIGHT = 0.04
    LINEWIDTH = 0.0036
    SMALL_TEXT_SIZE = 0.03
    MEDIUM_TEXT_SIZE = SMALL_TEXT_SIZE * 1.2
    LARGE_TEXT_SIZE = MEDIUM_TEXT_SIZE * 1.2
    PITCH_SCALE_RESOLUTION = 5
    PITCH_SCALE_HALFRANGE = 15
    PITCH_SCALE_MAJORWIDTH = 0.1
    PITCH_SCALE_MINORWIDTH = 0.066
    PITCH_SCALE_WIDTHREDUCTION_FROM = 30
    PITCH_SCALE_WIDTHREDUCTION = 0.3
    SHOW_ZERO_ON_SCALES = True
    CROSSTRACK_MAX = 1000
    CROSSTRACK_RADIUS = 0.6
    COMPASS_DISK_MAJORTICK = 10
    COMPASS_DISK_ARROWTICK = 45
    COMPASS_DISK_MAJORLINEWIDTH = 0.006
    COMPASS_DISK_MINORLINEWIDTH = 0.004
    COMPASS_DISK_RESOLUTION = 10
    COMPASS_SEPARATE_DISK_RESOLUTION = 5
    COMPASS_DISK_MARKERWIDTH = 0.2
    COMPASS_DISK_MARKERHEIGHT = 0.133
    UNKNOWN_BATTERY = -1
    UNKNOWN_ATTITUDE = 0
    UNKNOWN_ALTITUDE = -1000
    UNKNOWN_SPEED = -1
    UNKNOWN_COUNT = -1
    UNKNOWN_GPSFIXTYPE = -1

    TAPE_GAUGES_TICKWIDTH_MAJOR = 0.25
    TAPE_GAUGES_TICKWIDTH_MINOR = 0.15

    # The altitude difference between top and bottom of scale
    ALTIMETER_LINEAR_SPAN = 50
    # every 5 meters there is a tick mark
    ALTIMETER_LINEAR_RESOLUTION = 5
    # every 10 meters there is a number
    ALTIMETER_LINEAR_MAJOR_RESOLUTION = 10

    ALTIMETER_VVI_SPAN = 5
    ALTIMETER_VVI_WIDTH = 0.2
    AIRSPEED_LINEAR_SPAN = 15
    AIRSPEED_LINEAR_RESOLUTION = 1
    AIRSPEED_LINEAR_MAJOR_RESOLUTION = 5

    tickValues = [10, 20, 30, 45, 60]
    compassWindNames = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW']
    visibilityChanged = pyqtSignal(bool)

    def __init__(self, parent):
        super().__init__(parent)
        self.instrumentOpagueBackground = QBrush(
            QColor.fromHsvF(0, 0, 0.3, 1.0))
        self.instrumentBackground = QBrush(QColor.fromHsvF(0, 0, 0.3, 0.3))
        self.instrumentEdgePen = QPen(QColor.fromHsvF(0, 0, 0.65, 0.5))
        self.font = QFont()
        self.lineWidth = 2
        self.fineLineWidth = 1

        self.navigationTargetBearing = PrimaryFlightDisplay.UNKNOWN_ATTITUDE
        self.navigationCrosstrackError = 0
        self.primaryAltitude = PrimaryFlightDisplay.UNKNOWN_ALTITUDE
        self.GPSAltitude = PrimaryFlightDisplay.UNKNOWN_ALTITUDE
        self.verticalVelocity = PrimaryFlightDisplay.UNKNOWN_ALTITUDE
        self.primarySpeed = PrimaryFlightDisplay.UNKNOWN_SPEED
        self.groundspeed = PrimaryFlightDisplay.UNKNOWN_SPEED
        self.roll = 0.0
        self.pitch = 0.0
        self.yaw = 0.0
        self.rollspeed = 0.0
        self.pitchspeed = 0.0
        self.yawspeed = 0.0
        self.latitude = 0.0
        self.longitude = 0.0
        self.additionalParameters = {}

        self.param = UserData.getInstance().getUserDataEntry(UD_PFD_KEY, {})
        self.isGPSSpeedPrimary = UserData.getParameterValue(
            self.param, UD_PFD_PRIMARY_SPEED_SOURCE_KEY) == 'GPS'
        self.isGPSAltitudePrimary = UserData.getParameterValue(
            self.param, UD_PFD_PRIMARY_ALTITUDE_SOURCE_KEY) == 'GPS'
        self.setMinimumSize(480, 320)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.smallTestSize = self.SMALL_TEXT_SIZE
        self.mediumTextSize = self.MEDIUM_TEXT_SIZE
        self.largeTextSize = self.LARGE_TEXT_SIZE
        self.uiTimer = QTimer(self)
        self.uiTimer.setInterval(40)
        self.uiTimer.timeout.connect(self.update)
        self.uas = None

    def setActiveUAS(self, uas):
        uas.updateAttitudeSignal.connect(self.updateAttitude)
        uas.updateBatterySignal.connect(self.updateBatteryStatus)
        uas.updateGlobalPositionSignal.connect(self.updateGlobalPosition)
        uas.updateAirSpeedSignal.connect(self.updatePrimarySpeed)
        uas.updateGroundSpeedSignal.connect(self.updateGPSSpeed)
        uas.updateGPSStatusSignal.connect(self.updateGPSReception)
        uas.updateRCStatusSignal.connect(self.updateRCStatus)
        self.uas = uas

    def updateRCStatus(self, sourceUAS, rcType, rssi, noise, errors):
        unused(sourceUAS, rcType)
        self.additionalParameters['rc_rssi'] = rssi
        self.additionalParameters['rc_noise'] = noise
        self.additionalParameters['rc_errors'] = errors

    def updateAttitude(self, sourceUAS, timestamp, roll, pitch, yaw):
        scale = 180 / math.pi
        self.pitch = self.pitch if math.isnan(pitch) else pitch * scale
        self.roll = self.roll if math.isnan(roll) else roll * scale
        self.yaw = self.yaw if math.isnan(yaw) else yaw * scale
        unused(sourceUAS, timestamp)

    def updateAttitudeSpeed(self, sourceUAS, timestamp, rollspeed, pitchspeed,
                            yawspeed):
        scale = 180 / math.pi
        self.rollspeed = self.rollspeed if math.isnan(
            rollspeed) else rollspeed * scale
        self.pitchspeed = self.pitchspeed if math.isnan(
            pitchspeed) else pitchspeed * scale
        self.yawspeed = self.yawspeed if math.isnan(
            yawspeed) else yawspeed * scale
        unused(sourceUAS, timestamp)

    def updateGlobalPosition(self, sourceUAS, timestamp, latitude, longitude,
                             altitude):
        self.latitude = self.latitude if math.isnan(latitude) else latitude
        self.longitude = self.longitude if math.isnan(longitude) else longitude
        self.GPSAltitude = self.GPSAltitude if math.isnan(
            altitude) else altitude
        unused(sourceUAS, timestamp)

    def updatePrimaryAltitude(self, sourceUAS, timestamp, altitude):
        self.primaryAltitude = self.primaryAltitude if math.isnan(
            altitude) else altitude
        unused(sourceUAS, timestamp)

    def updateGPSAltitude(self, sourceUAS, timestamp, altitude):
        self.GPSAltitude = self.GPSAltitude if math.isnan(
            altitude) else altitude
        unused(sourceUAS, timestamp)

    def updatePrimarySpeed(self, sourceUAS, timestamp, speed):
        self.primarySpeed = self.primarySpeed if math.isnan(speed) else speed
        unused(sourceUAS, timestamp)

    def updateBatteryStatus(self, sourceUAS, timestamp, voltage, current,
                            remaining):
        self.additionalParameters['voltage'] = voltage
        self.additionalParameters['current'] = current
        self.additionalParameters['remaining'] = remaining
        unused(sourceUAS, timestamp)

    def updateGPSReception(self, sourceUAS, timestamp, fixType, hdop, vdop,
                           satelliteCount, hacc, vacc, velacc, hdgacc):
        self.additionalParameters['gps_fix'] = fixType
        self.additionalParameters['gps_satellite'] = satelliteCount
        unused(sourceUAS, timestamp, hdop, vdop, hacc, vacc, velacc, hdgacc)

    def updateGPSSpeed(self, sourceUAS, timestamp, speed):
        self.groundspeed = self.groundspeed if math.isnan(speed) else speed
        unused(sourceUAS, timestamp)

    def paintEvent(self, event):
        unused(event)
        compassAIIntrusion = 0
        compassHalfSpan = 180
        painter = QPainter()
        painter.begin(self)
        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.setRenderHint(QPainter.HighQualityAntialiasing, True)

        tapeGaugeWidth = self.tapesGaugeWidthFor(self.width(), self.width())
        aiheight = self.height()
        aiwidth = self.width() - tapeGaugeWidth * 2
        if (aiheight > aiwidth):
            aiheight = aiwidth
        AIMainArea = QRectF(tapeGaugeWidth, 0, aiwidth, aiheight)
        AIPaintArea = QRectF(0, 0, self.width(), self.height())

        velocityMeterArea = QRectF(0, 0, tapeGaugeWidth, aiheight)
        altimeterArea = QRectF(AIMainArea.right(), 0, tapeGaugeWidth, aiheight)

        # calc starts
        compassRelativeWidth = 0.75
        compassBottomMargin = 0.78
        compassSize = compassRelativeWidth * AIMainArea.width(
        )  # Diameter is this times the width.
        compassCenterY = AIMainArea.bottom() + compassSize / 4

        if self.height(
        ) - compassCenterY > AIMainArea.width() / 2 * compassBottomMargin:
            compassCenterY = self.height(
            ) - AIMainArea.width() / 2 * compassBottomMargin
        compassCenterY = (compassCenterY * 2 + AIMainArea.bottom() +
                          compassSize / 4) / 3

        compassArea = QRectF(
            AIMainArea.x() +
            (1 - compassRelativeWidth) / 2 * AIMainArea.width(),
            compassCenterY - compassSize / 2, compassSize, compassSize)

        if self.height() - compassCenterY < compassSize / 2:
            compassHalfSpan = math.acos(
                (compassCenterY - self.height()) * 2 /
                compassSize) * 180 / math.pi + self.COMPASS_DISK_RESOLUTION
            if compassHalfSpan > 180:
                compassHalfSpan = 180

        compassAIIntrusion = compassSize / 2 + AIMainArea.bottom(
        ) - compassCenterY
        if compassAIIntrusion < 0:
            compassAIIntrusion = 0
        #calc ends

        hadClip = painter.hasClipping()

        painter.setClipping(True)
        painter.setClipRect(AIPaintArea)

        self.drawAIGlobalFeatures(painter, AIMainArea, AIPaintArea)
        self.drawAIAttitudeScales(painter, AIMainArea, compassAIIntrusion)
        self.drawAIAirframeFixedFeatures(painter, AIMainArea)
        self.drawAICompassDisk(painter, compassArea, compassHalfSpan)

        painter.setClipping(hadClip)
        if self.isGPSAltitudePrimary:
            self.drawAltimeter(painter, altimeterArea, self.GPSAltitude,
                               self.primaryAltitude, self.verticalVelocity)
        else:
            self.drawAltimeter(painter, altimeterArea, self.primaryAltitude,
                               self.GPSAltitude, self.verticalVelocity)
        if self.isGPSSpeedPrimary:
            self.drawVelocityMeter(painter, velocityMeterArea,
                                   self.groundspeed, self.primarySpeed)
        else:
            self.drawVelocityMeter(painter, velocityMeterArea,
                                   self.primarySpeed, self.groundspeed)
        painter.end()

    def showEvent(self, event):
        super().showEvent(event)
        self.uiTimer.start()
        self.visibilityChanged.emit(True)

    def hideEvent(self, event):
        self.uiTimer.stop()
        super().hideEvent(event)
        self.visibilityChanged.emit(False)

    def resizeEvent(self, e):
        super().resizeEvent(e)
        size = e.size().width()
        self.lineWidth = self.constrain(size * self.LINEWIDTH, 1, 6)
        self.fineLineWidth = self.constrain(size * self.LINEWIDTH * 2 / 3, 1,
                                            2)
        self.instrumentEdgePen.setWidthF(self.fineLineWidth)
        self.smallTestSize = size * self.SMALL_TEXT_SIZE
        self.mediumTextSize = size * self.MEDIUM_TEXT_SIZE
        self.largeTextSize = size * self.LARGE_TEXT_SIZE

    def drawTextCenter(self, painter, text, pixelSize, x, y):
        self.font.setPixelSize(pixelSize)
        painter.setFont(self.font)
        metrics = QFontMetrics(self.font)
        bounds = metrics.boundingRect(text)
        painter.drawText(x - bounds.width() / 2, y - bounds.height() / 2,
                         bounds.width(), bounds.height(),
                         Qt.AlignCenter | Qt.TextDontClip, text)

    def drawTextLeftCenter(self, painter, text, pixelSize, x, y):
        self.font.setPixelSize(pixelSize)
        painter.setFont(self.font)
        metrics = QFontMetrics(self.font)
        bounds = metrics.boundingRect(text)
        painter.drawText(x, y - bounds.height() / 2, bounds.width(),
                         bounds.height(), Qt.AlignLeft | Qt.TextDontClip, text)

    def drawTextRightCenter(self, painter, text, pixelSize, x, y):
        self.font.setPixelSize(pixelSize)
        painter.setFont(self.font)
        metrics = QFontMetrics(self.font)
        bounds = metrics.boundingRect(text)
        painter.drawText(x - bounds.width(), y - bounds.height() / 2,
                         bounds.width(), bounds.height(),
                         Qt.AlignRight | Qt.TextDontClip, text)

    def drawTextCenterTop(self, painter, text, pixelSize, x, y):
        self.font.setPixelSize(pixelSize)
        painter.setFont(self.font)
        metrics = QFontMetrics(self.font)
        bounds = metrics.boundingRect(text)
        painter.drawText(x - bounds.width() / 2, y + bounds.height(),
                         bounds.width(), bounds.height(),
                         Qt.AlignCenter | Qt.TextDontClip, text)

    def drawTextCenterBottom(self, painter, text, pixelSize, x, y):
        self.font.setPixelSize(pixelSize)
        painter.setFont(self.font)
        metrics = QFontMetrics(self.font)
        bounds = metrics.boundingRect(text)
        painter.drawText(x - bounds.width() / 2, y, bounds.width(),
                         bounds.height(), Qt.AlignCenter, text)

    def drawInstrumentBackground(self, painter, edge):
        painter.setPen(self.instrumentEdgePen)
        painter.drawRect(edge)

    def fillInstrumentBackground(self, painter, edge):
        painter.setPen(self.instrumentEdgePen)
        painter.setBrush(self.instrumentBackground)
        painter.drawRect(edge)
        painter.setBrush(Qt.NoBrush)

    def fillInstrumentOpagueBackground(self, painter, edge):
        painter.setPen(self.instrumentEdgePen)
        painter.setBrush(self.instrumentOpagueBackground)
        painter.drawRect(edge)
        painter.setBrush(Qt.NoBrush)

    def constrain(self, value, mn, mx):
        if value < mn:
            value = mn
        elif value > mx:
            value = mx
        return value

    def pitchAngleToTranslation(self, viewHeight, pitch):
        return pitch * viewHeight / 65.0  #PITCHTRANSLATION

    def tapesGaugeWidthFor(self, containerWidth, preferredAIWidth):
        result = (containerWidth - preferredAIWidth) / 2.0
        minimum = containerWidth / 5.5
        if result < minimum:
            result = minimum
        return result

    def min4(self, a, b, c, d):
        if b < a:
            a = b
        if c < a:
            a = c
        if d < a:
            a = d
        return a

    def max4(self, a, b, c, d):
        if b > a:
            a = b
        if c > a:
            a = c
        if d > a:
            a = d
        return a

    def drawAIAttitudeScales(self, painter, area, intrusion):
        # To save computations, we do these transformations once for both scales:
        painter.resetTransform()
        painter.translate(area.center())
        painter.rotate(-self.roll)
        saved = painter.transform()

        self.drawRollScale(painter, area, True, True)
        painter.setTransform(saved)
        self.drawPitchScale(painter, area, intrusion, True, True)

    def drawPitchScale(self, painter, area, intrusion, drawNumbersLeft,
                       drawNumbersRight):
        unused(intrusion)
        # The area should be quadratic but if not width is the major size.
        w = area.width()
        if w < area.height():
            w = area.height()

        pen = QPen()
        pen.setWidthF(self.lineWidth)
        pen.setColor(Qt.white)
        painter.setPen(pen)

        savedTransform = painter.transform()

        # find the mark nearest center
        snap = qRound(
            self.pitch /
            self.PITCH_SCALE_RESOLUTION) * self.PITCH_SCALE_RESOLUTION
        _min = snap - self.PITCH_SCALE_HALFRANGE
        _max = snap + self.PITCH_SCALE_HALFRANGE
        degrees = _min
        while degrees <= _max:
            isMajor = degrees % (self.PITCH_SCALE_RESOLUTION * 2) == 0
            linewidth = self.PITCH_SCALE_MINORWIDTH
            if isMajor:
                linewidth = self.PITCH_SCALE_MAJORWIDTH
            if abs(degrees) > self.PITCH_SCALE_WIDTHREDUCTION_FROM:
                # we want: 1 at PITCH_SCALE_WIDTHREDUCTION_FROM and PITCH_SCALE_WIDTHREDUCTION at 90.
                # That is PITCH_SCALE_WIDTHREDUCTION + (1-PITCH_SCALE_WIDTHREDUCTION) * f(pitch)
                # where f(90)=0 and f(PITCH_SCALE_WIDTHREDUCTION_FROM)=1
                # f(p) = (90-p) * 1/(90-PITCH_SCALE_WIDTHREDUCTION_FROM)
                # or PITCH_SCALE_WIDTHREDUCTION + f(pitch) - f(pitch) * PITCH_SCALE_WIDTHREDUCTION
                # or PITCH_SCALE_WIDTHREDUCTION (1-f(pitch)) + f(pitch)
                fromVertical = -90 - self.pitch
                if self.pitch >= 0:
                    fromVertical = 90 - self.pitch
                if fromVertical < 0:
                    fromVertical = -fromVertical
                temp = fromVertical * 1 / (
                    90.0 - self.PITCH_SCALE_WIDTHREDUCTION_FROM)
                linewidth *= (self.PITCH_SCALE_WIDTHREDUCTION * (1 - temp) +
                              temp)
            shift = self.pitchAngleToTranslation(w, self.pitch - degrees)

            # TODO: Intrusion detection and evasion. That is, don't draw
            # where the compass has intruded.
            painter.translate(0, shift)
            start = QPointF(-linewidth * w, 0)
            end = QPointF(linewidth * w, 0)
            painter.drawLine(start, end)

            if isMajor and (drawNumbersLeft or drawNumbersRight):
                displayDegrees = degrees
                if displayDegrees > 90:
                    displayDegrees = 180 - displayDegrees
                elif displayDegrees < -90:
                    displayDegrees = -180 - displayDegrees
                if self.SHOW_ZERO_ON_SCALES or degrees:
                    if drawNumbersLeft:
                        self.drawTextRightCenter(
                            painter, '{0}'.format(displayDegrees),
                            self.mediumTextSize,
                            -self.PITCH_SCALE_MAJORWIDTH * w - 10, 0)
                    if drawNumbersRight:
                        self.drawTextLeftCenter(
                            painter, '{0}'.format(displayDegrees),
                            self.mediumTextSize,
                            self.PITCH_SCALE_MAJORWIDTH * w + 10, 0)

            painter.setTransform(savedTransform)
            degrees += self.PITCH_SCALE_RESOLUTION

    def drawRollScale(self, painter, area, drawTicks, drawNumbers):
        w = area.width()
        if w < area.height():
            w = area.height()

        pen = QPen()
        pen.setWidthF(self.lineWidth)
        pen.setColor(Qt.white)
        painter.setPen(pen)

        # We should really do these transforms but they are assumed done by caller.
        # painter.resetTransform()
        # painter.translate(area.center())
        # painter.rotate(roll)

        _size = w * self.ROLL_SCALE_RADIUS * 2
        arcArea = QRectF(-_size / 2, -_size / 2, _size, _size)
        painter.drawArc(arcArea, (90 - self.ROLL_SCALE_RANGE) * 16,
                        self.ROLL_SCALE_RANGE * 2 * 16)
        # painter.drawEllipse(QPoint(0,0),200,200)
        if drawTicks:
            length = len(self.tickValues)
            previousRotation = 0
            i = 0
            while i < length * 2 + 1:
                degrees = 0
                if i > length:
                    degrees = -self.tickValues[i - length - 1]
                elif i < length:
                    degrees = self.tickValues[i]
                #degrees = 180 - degrees
                painter.rotate(degrees - previousRotation)
                previousRotation = degrees

                start = QPointF(0, -_size / 2)
                end = QPointF(
                    0, -(1.0 + self.ROLL_SCALE_TICKMARKLENGTH) * _size / 2)

                painter.drawLine(start, end)

                #QString s_number # = QString("%d").arg(degrees);
                #if (SHOW_ZERO_ON_SCALES || degrees)
                #    s_number.sprintf("%d", abs(degrees));

                if drawNumbers:
                    self.drawTextCenterBottom(
                        painter, '{0}'.format(abs(degrees)),
                        self.mediumTextSize, 0,
                        -(self.ROLL_SCALE_RADIUS +
                          self.ROLL_SCALE_TICKMARKLENGTH * 1.7) * w)
                i = i + 1

    def drawAIAirframeFixedFeatures(self, painter, area):
        '''
        red line from -7/10 to -5/10 half-width
        red line from 7/10 to 5/10 half-width
        red slanted line from -2/10 half-width to 0
        red slanted line from 2/10 half-width to 0
        red arrow thing under roll scale
        prepareTransform(painter, width, height);
        '''
        painter.resetTransform()
        painter.translate(area.center())

        w = area.width()
        h = area.height()

        pen = QPen()
        pen.setWidthF(self.lineWidth * 1.5)
        pen.setColor(QColor(255, 0, 0))
        painter.setPen(pen)

        length = 0.15
        side = 0.5
        # The 2 lines at sides.
        painter.drawLine(QPointF(-side * w, 0),
                         QPointF(-(side - length) * w, 0))
        painter.drawLine(QPointF(side * w, 0), QPointF((side - length) * w, 0))

        pen.setColor(QColor(255, 255, 255))
        painter.setPen(pen)
        v = abs(self.__getAdditionalParameter('voltage'))
        a = abs(self.__getAdditionalParameter('current'))
        # Power usage
        self.drawTextLeftCenter(painter, '{:.1f}V'.format(v),
                                self.smallTestSize, -side * w * 0.9,
                                side * w / 4)
        self.drawTextLeftCenter(painter, '{:.1f}A'.format(a),
                                self.smallTestSize, -side * w * 0.9,
                                side * w / 4 + self.mediumTextSize * 1.1)
        # GPS groundspeed / IAS
        spd = ''
        if self.isGPSSpeedPrimary:
            # TODO add option to hide air speed when there is no air speed sensor
            spd = 'IAS ---' if self.primarySpeed == self.UNKNOWN_SPEED else 'IAS {:.1f}'.format(
                self.primarySpeed)
        else:
            spd = 'GS ---' if self.groundspeed == self.UNKNOWN_SPEED else 'GS {:.1f}'.format(
                self.groundspeed)
        self.drawTextLeftCenter(painter, spd, self.smallTestSize,
                                -side * w * 0.9,
                                side * w / 4 + self.mediumTextSize * 3.3)
        # Number of GPS satellites
        s = self.__getAdditionalParameter('gps_satellite')
        s = 0 if s == 255 else s
        self.drawTextRightCenter(painter, '{} {}'.format(chr(0x1F6F0), s),
                                 self.smallTestSize, side * w * 0.9,
                                 side * w / 4)
        # RC receiver RSSI
        s = self.__getAdditionalParameter('rc_rssi')
        s = 0 if s == 255 else s
        s /= 254.0
        self.drawTextRightCenter(painter,
                                 '{} {}'.format(chr(0x1F4F6), int(s * 100.0)),
                                 self.smallTestSize, side * w * 0.9,
                                 side * w / 4 + self.smallTestSize * 1.5)

        pen.setColor(QColor(255, 0, 0))
        painter.setPen(pen)
        rel = length / math.sqrt(2)
        # The gull
        painter.drawLine(QPointF(rel * w, rel * w / 2), QPoint(0, 0))
        painter.drawLine(QPointF(-rel * w, rel * w / 2), QPoint(0, 0))

        # The roll scale marker.
        markerPath = QPainterPath(QPointF(0, -w * self.ROLL_SCALE_RADIUS + 1))
        markerPath.lineTo(
            -h * self.ROLL_SCALE_MARKERWIDTH / 2,
            -w * (self.ROLL_SCALE_RADIUS - self.ROLL_SCALE_MARKERHEIGHT) + 1)
        markerPath.lineTo(
            h * self.ROLL_SCALE_MARKERWIDTH / 2,
            -w * (self.ROLL_SCALE_RADIUS - self.ROLL_SCALE_MARKERHEIGHT) + 1)
        markerPath.closeSubpath()
        painter.drawPath(markerPath)

    def drawAIGlobalFeatures(self, painter, mainArea, paintArea):
        painter.resetTransform()
        painter.translate(mainArea.center())

        pitchPixels = self.pitchAngleToTranslation(mainArea.height(),
                                                   self.pitch)
        gradientEnd = self.pitchAngleToTranslation(mainArea.height(), 60)

        if math.isnan(self.roll) == False:  # check for NaN
            painter.rotate(-self.roll)
        painter.translate(0, pitchPixels)

        # Calculate the radius of area we need to paint to cover all.
        rtx = painter.transform().inverted()[0]

        topLeft = rtx.map(paintArea.topLeft())
        topRight = rtx.map(paintArea.topRight())
        bottomLeft = rtx.map(paintArea.bottomLeft())
        bottomRight = rtx.map(paintArea.bottomRight())
        # Just KISS... make a rectangluar basis.
        minx = self.min4(topLeft.x(), topRight.x(), bottomLeft.x(),
                         bottomRight.x())
        maxx = self.max4(topLeft.x(), topRight.x(), bottomLeft.x(),
                         bottomRight.x())
        miny = self.min4(topLeft.y(), topRight.y(), bottomLeft.y(),
                         bottomRight.y())
        maxy = self.max4(topLeft.y(), topRight.y(), bottomLeft.y(),
                         bottomRight.y())

        hzonLeft = QPoint(minx, 0)
        hzonRight = QPoint(maxx, 0)

        skyPath = QPainterPath(hzonLeft)
        skyPath.lineTo(QPointF(minx, miny))
        skyPath.lineTo(QPointF(maxx, miny))
        skyPath.lineTo(hzonRight)
        skyPath.closeSubpath()

        # TODO: The gradient is wrong now.
        skyGradient = QLinearGradient(0, -gradientEnd, 0, 0)
        skyGradient.setColorAt(0, QColor.fromHsvF(0.6, 1.0, 0.7))
        skyGradient.setColorAt(1, QColor.fromHsvF(0.6, 0.25, 0.9))
        skyBrush = QBrush(skyGradient)
        painter.fillPath(skyPath, skyBrush)

        groundPath = QPainterPath(hzonRight)
        groundPath.lineTo(maxx, maxy)
        groundPath.lineTo(minx, maxy)
        groundPath.lineTo(hzonLeft)
        groundPath.closeSubpath()

        groundGradient = QLinearGradient(0, gradientEnd, 0, 0)
        groundGradient.setColorAt(0, QColor.fromHsvF(0.25, 1, 0.5))
        groundGradient.setColorAt(1, QColor.fromHsvF(0.25, 0.25, 0.5))
        groundBrush = QBrush(groundGradient)
        painter.fillPath(groundPath, groundBrush)

        pen = QPen()
        pen.setWidthF(self.lineWidth)
        pen.setColor(QColor(0, 255, 0))
        painter.setPen(pen)

        start = QPointF(-mainArea.width(), 0)
        end = QPoint(mainArea.width(), 0)
        painter.drawLine(start, end)

    def drawAICompassDisk(self, painter, area, halfspan):
        start = self.yaw - halfspan
        end = self.yaw + halfspan

        firstTick = math.ceil(
            start /
            self.COMPASS_DISK_RESOLUTION) * self.COMPASS_DISK_RESOLUTION
        lastTick = math.floor(
            end / self.COMPASS_DISK_RESOLUTION) * self.COMPASS_DISK_RESOLUTION

        radius = area.width() / 2
        innerRadius = radius * 0.96
        painter.resetTransform()
        painter.setBrush(self.instrumentBackground)
        painter.setPen(self.instrumentEdgePen)
        painter.drawEllipse(area)
        painter.setBrush(Qt.NoBrush)

        scalePen = QPen(Qt.black)
        scalePen.setWidthF(self.fineLineWidth)

        tickYaw = firstTick
        while tickYaw <= lastTick:
            displayTick = tickYaw
            if displayTick < 0:
                displayTick += 360
            elif displayTick >= 360:
                displayTick -= 360

            # yaw is in center.
            off = tickYaw - self.yaw
            # wrap that to ]-180..180]
            if off <= -180:
                off += 360
            elif off > 180:
                off -= 360

            painter.translate(area.center())
            painter.rotate(off)
            drewArrow = False
            isMajor = displayTick % self.COMPASS_DISK_MAJORTICK == 0

            if displayTick == 30 or displayTick == 60 or \
               displayTick ==120 or displayTick ==150 or \
               displayTick ==210 or displayTick ==240 or \
               displayTick ==300 or displayTick ==330:
                # draw a number
                painter.setPen(scalePen)
                self.drawTextCenter(painter,
                                    '{0}'.format(int(displayTick / 10)),
                                    self.smallTestSize, 0, -innerRadius * 0.75)
            else:
                if displayTick % self.COMPASS_DISK_ARROWTICK == 0:
                    if displayTick != 0:
                        markerPath = QPainterPath(
                            QPointF(
                                0, -innerRadius *
                                (1 - self.COMPASS_DISK_MARKERHEIGHT / 2)))
                        markerPath.lineTo(
                            innerRadius * self.COMPASS_DISK_MARKERWIDTH / 4,
                            -innerRadius)
                        markerPath.lineTo(
                            -innerRadius * self.COMPASS_DISK_MARKERWIDTH / 4,
                            -innerRadius)
                        markerPath.closeSubpath()
                        painter.setPen(scalePen)
                        painter.setBrush(Qt.SolidPattern)
                        painter.drawPath(markerPath)
                        painter.setBrush(Qt.NoBrush)
                        drewArrow = True
                    if displayTick % 90 == 0:
                        # Also draw a label
                        name = self.compassWindNames[qRound(displayTick / 45)]
                        painter.setPen(scalePen)
                        self.drawTextCenter(painter, name, self.mediumTextSize,
                                            0, -innerRadius * 0.75)

            # draw the scale lines. If an arrow was drawn, stay off from it.
            if drewArrow:
                p_start = QPoint(0, -innerRadius * 0.94)
            else:
                p_start = QPoint(0, -innerRadius)
            if isMajor:
                p_end = QPoint(0, -innerRadius * 0.86)
            else:
                p_end = QPoint(0, -innerRadius * 0.90)

            painter.setPen(scalePen)
            painter.drawLine(p_start, p_end)
            painter.resetTransform()
            tickYaw += self.COMPASS_DISK_RESOLUTION

        painter.setPen(scalePen)
        painter.translate(area.center())
        markerPath = QPainterPath(QPointF(0, -radius - 2))
        markerPath.lineTo(
            radius * self.COMPASS_DISK_MARKERWIDTH / 2,
            -radius - radius * self.COMPASS_DISK_MARKERHEIGHT - 2)
        markerPath.lineTo(
            -radius * self.COMPASS_DISK_MARKERWIDTH / 2,
            -radius - radius * self.COMPASS_DISK_MARKERHEIGHT - 2)
        markerPath.closeSubpath()
        painter.drawPath(markerPath)

        digitalCompassYCenter = -radius * 0.52
        digitalCompassHeight = radius * 0.28

        digitalCompassBottom = QPointF(
            0, digitalCompassYCenter + digitalCompassHeight)
        digitalCompassAbsoluteBottom = painter.transform().map(
            digitalCompassBottom)

        digitalCompassUpshift = 0
        if digitalCompassAbsoluteBottom.y() > self.height():
            digitalCompassUpshift = digitalCompassAbsoluteBottom.y(
            ) - self.height()

        digitalCompassRect = QRectF(-radius / 3,
                                    -radius * 0.52 - digitalCompassUpshift,
                                    radius * 2 / 3, radius * 0.28)
        painter.setPen(self.instrumentEdgePen)
        painter.drawRoundedRect(digitalCompassRect,
                                self.instrumentEdgePen.widthF() * 2 / 3,
                                self.instrumentEdgePen.widthF() * 2 / 3)

        # final safeguard for really stupid systems
        digitalCompassValue = qRound(self.yaw) % 360

        pen = QPen()
        pen.setWidthF(self.lineWidth)
        pen.setColor(Qt.white)
        painter.setPen(pen)

        self.drawTextCenter(painter, '%03d' % digitalCompassValue,
                            self.largeTextSize, 0,
                            -radius * 0.38 - digitalCompassUpshift)

        # The CDI
        if self.shouldDisplayNavigationData(
        ) and self.navigationTargetBearing != self.UNKNOWN_ATTITUDE and not math.isinf(
                self.navigationCrosstrackError):
            painter.resetTransform()
            painter.translate(area.center())
            # TODO : Sign might be wrong?
            # TODO : The case where error exceeds max. Truncate to max. and make that visible somehow.
            # bool errorBeyondRadius = false
            if abs(self.navigationCrosstrackError) > self.CROSSTRACK_MAX:
                #errorBeyondRadius = true
                if self.navigationCrosstrackError > 0:
                    self.navigationCrosstrackError = self.CROSSTRACK_MAX
                else:
                    self.navigationCrosstrackError = -self.CROSSTRACK_MAX

            r = radius * self.CROSSTRACK_RADIUS
            x = self.navigationCrosstrackError / self.CROSSTRACK_MAX * r
            y = math.sqrt(r * r -
                          x * x)  # the positive y, there is also a negative.

            sillyHeading = 0
            angle = sillyHeading - self.navigationTargetBearing  # TODO: sign.
            painter.rotate(-angle)

            pen = QPen()
            pen.setWidthF(self.lineWidth)
            pen.setColor(Qt.black)
            painter.setPen(pen)
            painter.drawLine(QPointF(x, y), QPointF(x, -y))

    def drawAltimeter(self, painter, area, primaryAltitude, secondaryAltitude,
                      vv):
        unused(secondaryAltitude)
        painter.resetTransform()
        self.fillInstrumentBackground(painter, area)

        pen = QPen()
        pen.setWidthF(self.lineWidth)
        pen.setColor(Qt.white)
        painter.setPen(pen)

        h = area.height()
        w = area.width()
        #float secondaryAltitudeBoxHeight = mediumTextSize * 2;
        # The height where we being with new tickmarks.
        effectiveHalfHeight = h * 0.45

        # not yet implemented: Display of secondary altitude.
        # if (isAirplane())
        #    effectiveHalfHeight-= secondaryAltitudeBoxHeight;

        markerHalfHeight = self.mediumTextSize * 0.8
        leftEdge = self.instrumentEdgePen.widthF() * 2
        rightEdge = w - leftEdge
        tickmarkLeft = leftEdge
        tickmarkRightMajor = tickmarkLeft + self.TAPE_GAUGES_TICKWIDTH_MAJOR * w
        tickmarkRightMinor = tickmarkLeft + self.TAPE_GAUGES_TICKWIDTH_MINOR * w
        numbersLeft = 0.42 * w
        markerTip = (tickmarkLeft * 2 + tickmarkRightMajor) / 3
        scaleCenterAltitude = 0 if primaryAltitude == self.UNKNOWN_ALTITUDE else primaryAltitude

        # altitude scale
        start = scaleCenterAltitude - self.ALTIMETER_LINEAR_SPAN / 2
        end = scaleCenterAltitude + self.ALTIMETER_LINEAR_SPAN / 2
        firstTick = math.ceil(start / self.ALTIMETER_LINEAR_RESOLUTION
                              ) * self.ALTIMETER_LINEAR_RESOLUTION
        lastTick = math.floor(end / self.ALTIMETER_LINEAR_RESOLUTION
                              ) * self.ALTIMETER_LINEAR_RESOLUTION
        tickAlt = firstTick
        while tickAlt <= lastTick:
            y = (tickAlt - scaleCenterAltitude) * effectiveHalfHeight / (
                self.ALTIMETER_LINEAR_SPAN / 2)
            isMajor = tickAlt % self.ALTIMETER_LINEAR_MAJOR_RESOLUTION == 0
            painter.resetTransform()
            painter.translate(area.left(), area.center().y() - y)
            pen.setColor(Qt.red if tickAlt < 0 else Qt.white)
            painter.setPen(pen)
            if isMajor:
                painter.drawLine(tickmarkLeft, 0, tickmarkRightMajor, 0)
                self.drawTextLeftCenter(painter, '{0}'.format(abs(tickAlt)),
                                        self.mediumTextSize, numbersLeft, 0)
            else:
                painter.drawLine(tickmarkLeft, 0, tickmarkRightMinor, 0)
            tickAlt += self.ALTIMETER_LINEAR_RESOLUTION

        markerPath = QPainterPath(QPoint(markerTip, 0))
        markerPath.lineTo(markerTip + markerHalfHeight, markerHalfHeight)
        markerPath.lineTo(rightEdge, markerHalfHeight)
        markerPath.lineTo(rightEdge, -markerHalfHeight)
        markerPath.lineTo(markerTip + markerHalfHeight, -markerHalfHeight)
        markerPath.closeSubpath()

        painter.resetTransform()
        painter.translate(area.left(), area.center().y())

        pen.setWidthF(self.lineWidth)
        pen.setColor(Qt.white)
        painter.setPen(pen)

        painter.setBrush(Qt.SolidPattern)
        painter.drawPath(markerPath)
        painter.setBrush(Qt.NoBrush)

        pen.setColor(Qt.white)
        painter.setPen(pen)

        xCenter = (markerTip + rightEdge) / 2
        alttxt = '---' if primaryAltitude == self.UNKNOWN_ALTITUDE else '%3.0f' % primaryAltitude
        self.drawTextCenter(painter, alttxt, self.mediumTextSize, xCenter, 0)

        if vv == self.UNKNOWN_ALTITUDE:
            return
        vvPixHeight = -vv / self.ALTIMETER_VVI_SPAN * effectiveHalfHeight
        if abs(vvPixHeight) < markerHalfHeight:
            return  # hidden behind marker.

        vvSign = -1
        if vvPixHeight > 0:
            vvSign = 1

        # QRectF vvRect(rightEdge - w*ALTIMETER_VVI_WIDTH, markerHalfHeight*vvSign, w*ALTIMETER_VVI_WIDTH, abs(vvPixHeight)*vvSign);
        vvArrowBegin = QPointF(rightEdge - w * self.ALTIMETER_VVI_WIDTH / 2,
                               markerHalfHeight * vvSign)
        vvArrowEnd = QPointF(rightEdge - w * self.ALTIMETER_VVI_WIDTH / 2,
                             vvPixHeight)
        painter.drawLine(vvArrowBegin, vvArrowEnd)

        # Yeah this is a repitition of above code but we are goigd to trash it all anyway, so no fix.
        vvArowHeadSize = abs(vvPixHeight - markerHalfHeight * vvSign)
        if vvArowHeadSize > w * self.ALTIMETER_VVI_WIDTH / 3:
            vvArowHeadSize = w * self.ALTIMETER_VVI_WIDTH / 3

        xcenter = rightEdge - w * self.ALTIMETER_VVI_WIDTH / 2

        vvArrowHead = QPointF(xcenter + vvArowHeadSize,
                              vvPixHeight - vvSign * vvArowHeadSize)
        painter.drawLine(vvArrowHead, vvArrowEnd)

        vvArrowHead = QPointF(xcenter - vvArowHeadSize,
                              vvPixHeight - vvSign * vvArowHeadSize)
        painter.drawLine(vvArrowHead, vvArrowEnd)

    def drawVelocityMeter(self, painter, area, speed, secondarySpeed):
        unused(secondarySpeed)
        painter.resetTransform()
        self.fillInstrumentBackground(painter, area)

        pen = QPen()
        pen.setWidthF(self.lineWidth)

        h = area.height()
        w = area.width()
        effectiveHalfHeight = h * 0.45
        markerHalfHeight = self.mediumTextSize
        leftEdge = self.instrumentEdgePen.widthF() * 2
        tickmarkRight = w - leftEdge
        tickmarkLeftMajor = tickmarkRight - w * self.TAPE_GAUGES_TICKWIDTH_MAJOR
        tickmarkLeftMinor = tickmarkRight - w * self.TAPE_GAUGES_TICKWIDTH_MINOR
        numbersRight = 0.42 * w
        markerTip = (tickmarkLeftMajor + tickmarkRight * 2) / 3

        # Select between air and ground speed:
        centerScaleSpeed = 0 if speed == self.UNKNOWN_SPEED else speed
        start = centerScaleSpeed - self.AIRSPEED_LINEAR_SPAN / 2
        end = centerScaleSpeed + self.AIRSPEED_LINEAR_SPAN / 2

        firstTick = math.ceil(
            start /
            self.AIRSPEED_LINEAR_RESOLUTION) * self.AIRSPEED_LINEAR_RESOLUTION
        lastTick = math.floor(
            end /
            self.AIRSPEED_LINEAR_RESOLUTION) * self.AIRSPEED_LINEAR_RESOLUTION
        tickSpeed = firstTick
        while tickSpeed <= lastTick:
            if tickSpeed < 0:
                pen.setColor(Qt.red)
            else:
                pen.setColor(Qt.white)
            painter.setPen(pen)

            y = (tickSpeed - centerScaleSpeed) * effectiveHalfHeight / (
                self.AIRSPEED_LINEAR_SPAN / 2)
            hasText = tickSpeed % self.AIRSPEED_LINEAR_MAJOR_RESOLUTION == 0
            painter.resetTransform()
            painter.translate(area.left(), area.center().y() - y)

            if hasText:
                painter.drawLine(tickmarkLeftMajor, 0, tickmarkRight, 0)
                self.drawTextRightCenter(painter, '{0}'.format(abs(tickSpeed)),
                                         self.mediumTextSize, numbersRight, 0)
            else:
                painter.drawLine(tickmarkLeftMinor, 0, tickmarkRight, 0)
            tickSpeed += self.AIRSPEED_LINEAR_RESOLUTION

        markerPath = QPainterPath(QPoint(markerTip, 0))
        markerPath.lineTo(markerTip - markerHalfHeight, markerHalfHeight)
        markerPath.lineTo(leftEdge, markerHalfHeight)
        markerPath.lineTo(leftEdge, -markerHalfHeight)
        markerPath.lineTo(markerTip - markerHalfHeight, -markerHalfHeight)
        markerPath.closeSubpath()

        painter.resetTransform()
        painter.translate(area.left(), area.center().y())

        pen.setWidthF(self.lineWidth)
        pen.setColor(Qt.white)
        painter.setPen(pen)
        painter.setBrush(Qt.SolidPattern)
        painter.drawPath(markerPath)
        painter.setBrush(Qt.NoBrush)

        pen.setColor(Qt.white)
        painter.setPen(pen)
        xCenter = (markerTip + leftEdge) / 2
        spdtxt = '---' if speed == self.UNKNOWN_SPEED else '%3.1f' % speed
        self.drawTextCenter(painter, spdtxt, self.mediumTextSize, xCenter, 0)

    def shouldDisplayNavigationData(self):
        return True

    def __getAdditionalParameter(self, param, defaultValue=0):
        if param in self.additionalParameters:
            return self.additionalParameters[param]
        return defaultValue
class DrawingBox(QWidget):
    """
    Allows to draw an image of a letter. After drawing, sends signal containing
    image rescaled to the input size of the neural network.
    """
    # signal emitted when user releases mouse after drawing
    newImage = pyqtSignal(QImage)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.imageSize = GUI_IMAGE_SIZE
        self.setFixedSize(self.imageSize)
        self.inverted = False
        self.pen = QPen(Qt.white if self.inverted else Qt.black,
            int(np.mean(PEN_WIDTH_RANGE)), Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
        self.image = QImage(self.imageSize, QImage.Format_Grayscale8)
        self.clearImage()
        self.last_pos = None
        self.drawing = False

    @pyqtSlot(int)
    def setPenWidth(self, pen_width):
        self.pen.setWidth(pen_width)

    @pyqtSlot()
    def invert(self):
        self.inverted = not self.inverted
        self.pen.setColor(Qt.white if self.inverted else Qt.black)
        self.image.invertPixels()
        self.update()
        self.pushImage()

    def pushImage(self):
        image = self.image.scaled(NET_IMAGE_SIZE, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
        self.newImage.emit(image)

    @pyqtSlot()
    def clearImage(self):
        self.image.fill(0 if self.inverted else 255)
        self.update()

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.last_pos = event.pos()
            self.drawing = True

    def mouseMoveEvent(self, event):
        dist = (event.pos() - self.last_pos).manhattanLength()
        if (event.buttons() & Qt.LeftButton) and self.drawing and dist > 3:
            self.drawLineTo(event.pos())

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton and self.drawing:
            self.drawLineTo(event.pos())
            self.drawing = False
            self.pushImage()

    def paintEvent(self, event):
        "Paints changes in the image on the widget."
        painter = QPainter(self)
        dirty_rect = event.rect()
        painter.drawImage(dirty_rect, self.image, dirty_rect)

    def drawLineTo(self, end_pos):
        "Draws line on the image and signals which part is dirty."
        painter = QPainter(self.image)
        painter.setPen(self.pen)
        painter.drawLine(self.last_pos, end_pos)
        radius = int((self.pen.widthF() / 2) + 2)
        self.update(QRect(self.last_pos, end_pos).normalized().adjusted(
            -radius, -radius, radius, radius))
        self.last_pos = end_pos
Esempio n. 10
0
class DesignItem(QGraphicsItem):
    positionChanged = pyqtSignal(int, int)

    def __init__(self, scene, is_scene_rect=False):
        QGraphicsItem.__init__(self)
        self.scene = scene
        self.is_scene_rect = is_scene_rect
        self.id = ""
        self.xscale = 1
        self.yscale = 1
        self.scaleX = 1.0
        self.scaleY = 1.0
        self.pen = QPen()
        self.brush = QBrush()
        self.hasHandles = False
        self.handles = [None, None, None, None, None, None, None, None]
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)

    def setId(self, id):
        self.id = id

    def setBrush(self, brush):
        self.brush = brush

    def setPen(self, pen):
        self.pen = pen

    def setRect(self, x, y, w, h):
        self.rect = QRectF(x, y, w, h)

    def setWidth(self, value):
        self.rect.setWidth(value)

    def setHeight(self, value):
        self.rect.setHeight(value)

    def width(self):
        return self.rect.width()

    def height(self):
        return self.rect.height()

    def boundingRect(self):
        return self.rect

    def isSceneRect(self):
        return self.is_scene_rect

    def drawHighlightSelected(self, painter, option):
        itemPenWidth = self.pen.widthF()
        pad = itemPenWidth / 2
        penWidth = 0
        fgcolor = option.palette.windowText().color()
        if fgcolor.red() > 127:
            r = 0
        else:
            r = 255
        if fgcolor.green() > 127:
            g = 0
        else:
            g = 255
        if fgcolor.blue() > 127:
            b = 0
        else:
            b = 255
        bgcolor = QColor(r, g, b)

        painter.setOpacity(1.0)
        painter.setPen(QPen(bgcolor, penWidth, Qt.SolidLine))
        painter.setBrush(Qt.NoBrush)
        painter.drawRect(self.boundingRect().adjusted(pad, pad, -pad, -pad))

        painter.setPen(QPen(option.palette.windowText(), 0, Qt.DashLine))
        painter.setBrush(Qt.NoBrush)
        painter.drawRect(self.boundingRect().adjusted(pad, pad, -pad, -pad))

    def scaleObjects(self):
        pass

    def setHandlePositions(self):
        if not self.hasHandles:
            return

        halfwidth = self.handles[0].width / 2.0
        self.handles[0].setPos(-halfwidth, -halfwidth)
        self.handles[1].setPos(self.rect.width() - halfwidth, -halfwidth)
        self.handles[2].setPos(self.rect.width() - halfwidth,
                               self.rect.height() - halfwidth)
        self.handles[3].setPos(-halfwidth, self.rect.height() - halfwidth)
        self.handles[4].setPos(self.rect.width() / 2 - halfwidth, -halfwidth)
        self.handles[5].setPos(self.rect.width() - halfwidth,
                               self.rect.height() / 2 - halfwidth)
        self.handles[6].setPos(self.rect.width() / 2 - halfwidth,
                               self.rect.height() - halfwidth)
        self.handles[7].setPos(-halfwidth, self.rect.height() / 2 - halfwidth)

        self.scene.update(self.x() - halfwidth - 5,
                          self.y() - halfwidth - 5,
                          self.x() + self.rect.width() + halfwidth * 2 + 5,
                          self.y() + self.rect.height() + halfwidth * 2 + 5)

    def sceneEventFilter(self, watched, event):
        if isinstance(watched, ItemHandle):
            handle = watched
        else:
            return False

        if isinstance(event, QGraphicsSceneMouseEvent):
            mevent = event
        else:
            return False

        if mevent.type() == QEvent.GraphicsSceneMousePress:
            self.oldx = self.pos().x()
            self.oldy = self.pos().y()
            self.oldwidth = self.rect.width()
            self.oldheight = self.rect.height()

            handle.setMouseState(ItemHandle.MOUSE_DOWN)
            handle.mouseDownX = mevent.pos().x()
            handle.mouseDownY = mevent.pos().y()
        elif mevent.type() == QEvent.GraphicsSceneMouseRelease:
            if self.oldx != self.pos().x() and self.oldy != self.pos().y(
            ) and self.oldwidth != self.rect.width(
            ) and self.oldheight != self.rect.height():
                undostack = self.scene.undostack
                cmd = ScaleItemCommand(self.pos().x(),
                                       self.pos().y(), self.rect.width(),
                                       self.rect.height(), self.oldx,
                                       self.oldy, self.oldwidth,
                                       self.oldheight, self.scene, self)
                undoStack.push(cmd)

            handle.setMouseState(ItemHandle.MOUSE_RELEASED)
        elif mevent.type() == QEvent.GraphicsSceneMouseMove:
            handle.setMouseState(ItemHandle.MOUSE_MOVING)
        else:
            return False

        if handle.getMouseState() == ItemHandle.MOUSE_MOVING:
            x = mevent.pos().x()
            y = mevent.pos().y()

            XaxisSign = 0
            YaxisSign = 0
            if handle.getCorner() == 0:
                XaxisSign = +1
                YaxisSign = +1
            elif handle.getCorner() == 1:
                XaxisSign = -1
                YaxisSign = +1
            elif handle.getCorner() == 2:
                XaxisSign = -1
                YaxisSign = -1
            elif handle.getCorner() == 3:
                XaxisSign = +1
                YaxisSign = -1
            elif handle.getCorner() == 4:
                YaxisSign = +1
            elif handle.getCorner() == 5:
                XaxisSign = -1
            elif handle.getCorner() == 6:
                YaxisSign = -1
            elif handle.getCorner() == 7:
                XaxisSign = +1

            xMoved = handle.mouseDownX - x
            yMoved = handle.mouseDownY - y

            newWidth = self.rect.width() + (XaxisSign * xMoved)
            if newWidth < 20:
                newWidth = 20

            newHeight = self.rect.height() + (YaxisSign * yMoved)
            if newHeight < 20:
                newHeight = 20

            deltaWidth = newWidth - self.rect.width()
            deltaHeight = newHeight - self.rect.height()

            shiftPressed = False
            controlPressed = False
            modifiers = QGuiApplication.keyboardModifiers()
            if modifiers == Qt.ShiftModifier:
                shiftPressed = True
            elif modifiers == Qt.ControlModifier:
                controlPressed = True
            elif modifiers == (Qt.ControlModifier | Qt.ShiftModifier):
                shiftPressed = True
                controlPressed = True

            if controlPressed:
                # keep ratio
                ratio = self.rect.width() / self.rect.height()
                if handle.getCorner() < 4:  # corners
                    if newWidth > newHeight:
                        deltaWidth = int(deltaHeight * ratio)
                    else:
                        deltaHeight = int(deltaWidth / ratio)
                else:
                    if handle.getCorner() == 4 or handle.getCorner(
                    ) == 6:  # top | bottom
                        deltaWidth = deltaHeight * ratio
                    else:  # left | right
                        deltaHeight = deltaWidth / ratio

            self.setRect(0, 0,
                         self.rect.width() + deltaWidth,
                         self.rect.height() + deltaHeight)
            self.scaleObjects()

            deltaWidth *= (-1)
            deltaHeight *= (-1)

            newXpos = self.pos().x()
            newYpos = self.pos().y()

            if handle.getCorner() == 0:  # top left
                if shiftPressed:
                    newXpos = self.pos().x() + deltaWidth / 2
                    newYpos = self.pos().y() + deltaHeight / 2
                else:
                    newXpos = self.pos().x() + deltaWidth
                    newYpos = self.pos().y() + deltaHeight
            elif handle.getCorner() == 1:  # top right
                if shiftPressed:
                    newXpos = self.pos().x() + deltaWidth / 2
                    newYpos = self.pos().y() + deltaHeight / 2
                else:
                    newYpos = self.pos().y() + deltaHeight
            elif handle.getCorner() == 2:  # bottom right
                if shiftPressed:
                    newXpos = self.pos().x() + deltaWidth / 2
                    newYpos = self.pos().y() + deltaHeight / 2
            elif handle.getCorner() == 3:  # bottom left
                if shiftPressed:
                    newXpos = self.pos().x() + deltaWidth / 2
                    newYpos = self.pos().y() + deltaHeight / 2
                else:
                    newXpos = self.pos().x() + deltaWidth
            elif handle.getCorner() == 4:  # top
                if shiftPressed:
                    newXpos = self.pos().x() + deltaWidth / 2
                    newYpos = self.pos().y() + deltaHeight / 2
                elif controlPressed:
                    newYpos = self.pos().y() + deltaHeight
                    newXpos = self.pos().x() + deltaWidth / 2
                else:
                    newYpos = self.pos().y() + deltaHeight
            elif handle.getCorner() == 5:  # right
                if shiftPressed:
                    newXpos = self.pos().x() + deltaWidth / 2
                    newYpos = self.pos().y() + deltaHeight / 2
                elif controlPressed:
                    newYpos = self.pos().y() + deltaHeight / 2
            elif handle.getCorner() == 6:  # bottom
                if shiftPressed:
                    newXpos = self.pos().x() + deltaWidth / 2
                    newYpos = self.pos().y() + deltaHeight / 2
                elif controlPressed:
                    newXpos = self.pos().x() + deltaWidth / 2
            elif handle.getCorner() == 7:  # left
                if shiftPressed:
                    newXpos = self.pos().x() + deltaWidth / 2
                    newYpos = self.pos().y() + deltaHeight / 2
                elif controlPressed:
                    newXpos = self.pos().x() + deltaWidth
                    newYpos = self.pos().y() + deltaHeight / 2
                else:
                    newXpos = self.pos().x() + deltaWidth

            if newXpos != self.pos().x() or newYpos != self.pos().y():
                self.setPos(newXpos, newYpos)
                self.posChanged(newXpos, newYpos)

            self.setHandlePositions()
            self.update()
        return True

    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemSelectedChange:
            if value:
                if not self.hasHandles:
                    for i in range(8):
                        self.handles[i] = ItemHandle(self, i,
                                                     self.scene.scaling)
                        self.handles[i].installSceneEventFilter(self)

                    self.hasHandles = True
                    self.setHandlePositions()
            else:
                for i in range(8):
                    self.scene.removeItem(self.handles[i])
                    self.handles[i] = None
                self.hasHandles = False
        elif change == QGraphicsItem.ItemPositionHasChanged:
            if self.isSelected():
                newPos = value
                self.posChanged(newPos.x(), newPos.y())
                self.setHandlePositions()
        return super().itemChange(change, value)

    def posChanged(self, x, y):
        pass
        #self.positionChanged.emit(x, y)

    def contextMenuEvent(self, event):
        if not self.is_scene_rect:
            self.scene.clearSelection()
            self.setSelected(True)
            #self.contextMenu.exec(event.screenPos())

            delAct = QAction("Delete")
            delAct.setShortcut("Delete")
            delAct.triggered.connect(self.deleteItemAction)

            bringToFrontAct = QAction("Bring to front")
            bringToFrontAct.triggered.connect(self.bringToFrontAction)

            sendToBackAct = QAction("Send to back")
            sendToBackAct.triggered.connect(self.sendToBackAction)

            raiseAct = QAction("Raise")
            raiseAct.triggered.connect(self.raiseAction)

            lowerAct = QAction("Lower")
            lowerAct.triggered.connect(self.lowerAction)

            contextMenu = QMenu()
            contextMenu.addAction(delAct)
            contextMenu.addSeparator()
            contextMenu.addAction(bringToFrontAct)
            contextMenu.addAction(raiseAct)
            contextMenu.addAction(lowerAct)
            contextMenu.addAction(sendToBackAct)
            contextMenu.exec(event.screenPos())

    def deleteItemAction(self):
        self.scene.deleteItem(self)

    def lowerAction(self):
        cmd = LowerItemCommand(self)
        self.scene.undostack.push(cmd)

    def raiseAction(self):
        cmd = RaiseItemCommand(self)
        self.scene.undostack.push(cmd)

    def sendToBackAction(self):
        cmd = SendItemToBackCommand(self)
        self.scene.undostack.push(cmd)

    def bringToFrontAction(self):
        cmd = BringItemToFrontCommand(self)
        self.scene.undostack.push(cmd)

    def lowerItem(self):
        pos = self.scene.items().index(self)
        for i in range(pos + 1, len(self.scene.items())):
            item = self.scene.items()[i]
            if isinstance(item, DesignItem) and not item.is_scene_rect:
                self.stackBefore(item)
                break

        # trick to repaint item
        self.setSelected(False)
        self.setSelected(True)

    def raiseItem(self):
        pos = self.scene.items().index(self)
        for i in range(pos - 1, -1, -1):
            item = self.scene.items()[i]
            if isinstance(item, DesignItem):
                item.stackBefore(self)
                break

        # trick to repaint item
        self.setSelected(False)
        self.setSelected(True)

    def bringToFront(self):
        pos = self.scene.items().index(self)
        for i in range(pos - 1, -1, -1):
            item = self.scene.items()[i]
            if isinstance(item, DesignItem):
                item.stackBefore(self)

        # trick to repaint item
        self.setSelected(False)
        self.setSelected(True)

    def sendToBack(self):
        pos = self.scene.items().index(self)
        for i in range(pos + 1, len(self.scene.items())):
            item = self.scene.items()[i]
            if isinstance(item, DesignItem) and not item.is_scene_rect:
                self.stackBefore(item)

        # trick to repaint item
        self.setSelected(False)
        self.setSelected(True)
Esempio n. 11
0
class GraphicsPathObject(QGraphicsObject):
    """A QGraphicsObject subclass implementing an interface similar to
    QGraphicsPathItem, and also adding a positionChanged() signal

    """

    positionChanged = Signal([], ["QPointF"])

    def __init__(self, parent=None, **kwargs):
        QGraphicsObject.__init__(self, parent, **kwargs)
        self.setFlag(QGraphicsObject.ItemSendsGeometryChanges)

        self.__path = QPainterPath()
        self.__brush = QBrush(Qt.NoBrush)
        self.__pen = QPen()
        self.__boundingRect = None

    def setPath(self, path):
        """Set the items `path` (:class:`QPainterPath`).
        """
        if not isinstance(path, QPainterPath):
            raise TypeError("%r, 'QPainterPath' expected" % type(path))

        if self.__path != path:
            self.prepareGeometryChange()
            # Need to store a copy of object so the shape can't be mutated
            # without properly updating the geometry.
            self.__path = QPainterPath(path)
            self.__boundingRect = None
            self.update()

    def path(self):
        """Return the items path.
        """
        return QPainterPath(self.__path)

    def setBrush(self, brush):
        """Set the items `brush` (:class:`QBrush`)
        """
        if not isinstance(brush, QBrush):
            brush = QBrush(brush)

        if self.__brush != brush:
            self.__brush = QBrush(brush)
            self.update()

    def brush(self):
        """Return the items brush.
        """
        return QBrush(self.__brush)

    def setPen(self, pen):
        """Set the items outline `pen` (:class:`QPen`).
        """
        if not isinstance(pen, QPen):
            pen = QPen(pen)

        if self.__pen != pen:
            self.prepareGeometryChange()
            self.__pen = QPen(pen)
            self.__boundingRect = None
            self.update()

    def pen(self):
        """Return the items pen.
        """
        return QPen(self.__pen)

    def paint(self, painter, option, widget=None):
        if self.__path.isEmpty():
            return

        painter.save()
        painter.setPen(self.__pen)
        painter.setBrush(self.__brush)
        painter.drawPath(self.__path)
        painter.restore()

    def boundingRect(self):
        if self.__boundingRect is None:
            br = self.__path.controlPointRect()
            pen_w = self.__pen.widthF()
            self.__boundingRect = br.adjusted(-pen_w, -pen_w, pen_w, pen_w)

        return self.__boundingRect

    def shape(self):
        return shapeFromPath(self.__path, self.__pen)

    def itemChange(self, change, value):
        if change == QGraphicsObject.ItemPositionHasChanged:
            pos = qunwrap(value)
            self.positionChanged.emit()
            self.positionChanged[QPointF].emit(pos)

        return QGraphicsObject.itemChange(self, change, value)
Esempio n. 12
0
    def paint(self, painter, option, widget):
        if canvas.scene.loading_items:
            return

        painter.save()
        painter.setRenderHint(QPainter.Antialiasing,
                              bool(options.antialiasing == ANTIALIASING_FULL))

        selected = self.isSelected()
        theme = canvas.theme
        if self.m_port_type == PORT_TYPE_AUDIO_JACK:
            if self.m_is_alternate:
                poly_color = theme.port_cv_jack_bg_sel if selected else theme.port_cv_jack_bg
                poly_pen = theme.port_cv_jack_pen_sel if selected else theme.port_cv_jack_pen
            else:
                poly_color = theme.port_audio_jack_bg_sel if selected else theme.port_audio_jack_bg
                poly_pen = theme.port_audio_jack_pen_sel if selected else theme.port_audio_jack_pen
            text_pen = theme.port_audio_jack_text_sel if selected else theme.port_audio_jack_text
            conn_pen = QPen(theme.port_audio_jack_pen_sel)
        elif self.m_port_type == PORT_TYPE_MIDI_JACK:
            poly_color = theme.port_midi_jack_bg_sel if selected else theme.port_midi_jack_bg
            poly_pen = theme.port_midi_jack_pen_sel if selected else theme.port_midi_jack_pen
            text_pen = theme.port_midi_jack_text_sel if selected else theme.port_midi_jack_text
            conn_pen = QPen(theme.port_midi_jack_pen_sel)
        elif self.m_port_type == PORT_TYPE_MIDI_ALSA:
            poly_color = theme.port_midi_alsa_bg_sel if selected else theme.port_midi_alsa_bg
            poly_pen = theme.port_midi_alsa_pen_sel if selected else theme.port_midi_alsa_pen
            text_pen = theme.port_midi_alsa_text_sel if selected else theme.port_midi_alsa_text
            conn_pen = QPen(theme.port_midi_alsa_pen_sel)
        elif self.m_port_type == PORT_TYPE_PARAMETER:
            poly_color = theme.port_parameter_bg_sel if selected else theme.port_parameter_bg
            poly_pen = theme.port_parameter_pen_sel if selected else theme.port_parameter_pen
            text_pen = theme.port_parameter_text_sel if selected else theme.port_parameter_text
            conn_pen = QPen(theme.port_parameter_pen_sel)
        else:
            qCritical(
                "PatchCanvas::CanvasPort.paint() - invalid port type '%s'" %
                port_type2str(self.m_port_type))
            return

        # To prevent quality worsening
        poly_pen = QPen(poly_pen)
        poly_pen.setWidthF(poly_pen.widthF() + 0.00001)

        lineHinting = poly_pen.widthF() / 2

        poly_locx = [0, 0, 0, 0, 0, 0]
        poly_corner_xhinting = ((float(canvas.theme.port_height) / 2) %
                                floor(float(canvas.theme.port_height) / 2))
        if poly_corner_xhinting == 0:
            poly_corner_xhinting = 0.5 * (
                1 - 7 / (float(canvas.theme.port_height) / 2))

        is_cv_port = bool(self.m_port_type == PORT_TYPE_AUDIO_JACK
                          and self.m_is_alternate)

        if self.m_port_mode == PORT_MODE_INPUT:
            text_pos = QPointF(3, canvas.theme.port_text_ypos)

            if canvas.theme.port_mode == Theme.THEME_PORT_POLYGON and not is_cv_port:
                poly_locx[0] = lineHinting
                poly_locx[1] = self.m_port_width + 5 - lineHinting
                poly_locx[2] = self.m_port_width + 12 - poly_corner_xhinting
                poly_locx[3] = self.m_port_width + 5 - lineHinting
                poly_locx[4] = lineHinting
                poly_locx[5] = self.m_port_width
            elif canvas.theme.port_mode == Theme.THEME_PORT_SQUARE or is_cv_port:
                poly_locx[0] = lineHinting
                poly_locx[1] = self.m_port_width + 5 - lineHinting
                poly_locx[2] = self.m_port_width + 5 - lineHinting
                poly_locx[3] = self.m_port_width + 5 - lineHinting
                poly_locx[4] = lineHinting
                poly_locx[5] = self.m_port_width
            else:
                qCritical(
                    "PatchCanvas::CanvasPort.paint() - invalid theme port mode '%s'"
                    % canvas.theme.port_mode)
                return

        elif self.m_port_mode == PORT_MODE_OUTPUT:
            text_pos = QPointF(9, canvas.theme.port_text_ypos)

            if canvas.theme.port_mode == Theme.THEME_PORT_POLYGON and not is_cv_port:
                poly_locx[0] = self.m_port_width + 12 - lineHinting
                poly_locx[1] = 7 + lineHinting
                poly_locx[2] = 0 + poly_corner_xhinting
                poly_locx[3] = 7 + lineHinting
                poly_locx[4] = self.m_port_width + 12 - lineHinting
                poly_locx[5] = 12 - lineHinting
            elif canvas.theme.port_mode == Theme.THEME_PORT_SQUARE or is_cv_port:
                poly_locx[0] = self.m_port_width + 12 - lineHinting
                poly_locx[1] = 5 + lineHinting
                poly_locx[2] = 5 + lineHinting
                poly_locx[3] = 5 + lineHinting
                poly_locx[4] = self.m_port_width + 12 - lineHinting
                poly_locx[5] = 12 - lineHinting
            else:
                qCritical(
                    "PatchCanvas::CanvasPort.paint() - invalid theme port mode '%s'"
                    % canvas.theme.port_mode)
                return

        else:
            qCritical(
                "PatchCanvas::CanvasPort.paint() - invalid port mode '%s'" %
                port_mode2str(self.m_port_mode))
            return

        polygon = QPolygonF()

        if self.m_portgrp_id:
            first_of_portgrp = False
            last_of_portgrp = False

            # look in portgroup if port is the first,
            # the last, or not.
            for portgrp in canvas.portgrp_list:
                if portgrp.portgrp_id == self.m_portgrp_id:
                    if self.m_port_id == portgrp.port_id_list[0]:
                        first_of_portgrp = True
                    if self.m_port_id == portgrp.port_id_list[-1]:
                        last_of_portgrp = True
                    break

            if first_of_portgrp:
                polygon += QPointF(poly_locx[0], lineHinting)
                polygon += QPointF(poly_locx[5], lineHinting)
            else:
                polygon += QPointF(poly_locx[0], 0)
                polygon += QPointF(poly_locx[5], 0)

            if last_of_portgrp:
                polygon += QPointF(poly_locx[5],
                                   canvas.theme.port_height - lineHinting)
                polygon += QPointF(poly_locx[0],
                                   canvas.theme.port_height - lineHinting)
            else:
                polygon += QPointF(poly_locx[5], canvas.theme.port_height)
                polygon += QPointF(poly_locx[0], canvas.theme.port_height)
        else:
            polygon += QPointF(poly_locx[0], lineHinting)
            polygon += QPointF(poly_locx[1], lineHinting)
            polygon += QPointF(poly_locx[2],
                               float(canvas.theme.port_height) / 2)
            polygon += QPointF(poly_locx[3],
                               canvas.theme.port_height - lineHinting)
            polygon += QPointF(poly_locx[4],
                               canvas.theme.port_height - lineHinting)
            polygon += QPointF(poly_locx[0], lineHinting)

        if canvas.theme.port_bg_pixmap:
            portRect = polygon.boundingRect().adjusted(-lineHinting + 1,
                                                       -lineHinting + 1,
                                                       lineHinting - 1,
                                                       lineHinting - 1)
            portPos = portRect.topLeft()
            painter.drawTiledPixmap(portRect, canvas.theme.port_bg_pixmap,
                                    portPos)
        else:
            port_gradient = QLinearGradient(0, 0, 0, self.m_port_height)

            dark_color = poly_color.darker(112)
            light_color = poly_color.lighter(111)

            if poly_color.lightness() > 127:
                port_gradient.setColorAt(0, dark_color)
                port_gradient.setColorAt(0.5, light_color)
                port_gradient.setColorAt(1, dark_color)
            else:
                port_gradient.setColorAt(0, light_color)
                port_gradient.setColorAt(0.5, dark_color)
                port_gradient.setColorAt(1, light_color)
            painter.setBrush(port_gradient)

        painter.setPen(poly_pen)
        painter.drawPolygon(polygon)

        if self.m_is_alternate and not self.m_portgrp_id:
            if is_cv_port:
                poly_pen.setWidthF(2.000001)
                painter.setPen(poly_pen)

                y_line = canvas.theme.port_height / 2.0
                if self.m_port_mode == PORT_MODE_OUTPUT:
                    painter.drawLine(QPointF(0.0, y_line),
                                     QPointF(float(poly_locx[1]), y_line))
                elif self.m_port_mode == PORT_MODE_INPUT:
                    painter.drawLine(QPointF(self.m_port_width + 5.0, y_line),
                                     QPointF(self.m_port_width + 12.0, y_line))
            else:
                # draw the little circle for a2j (or MidiBridge) port
                poly_pen.setWidthF(1.000001)
                painter.setBrush(canvas.theme.box_bg_1)

                ellipse_x = poly_locx[1]
                if self.m_port_mode == PORT_MODE_OUTPUT:
                    ellipse_x -= 2
                elif self.m_port_mode == PORT_MODE_INPUT:
                    ellipse_x += 2

                painter.drawEllipse(
                    QPointF(ellipse_x, canvas.theme.port_height / 2.0), 2, 2)

        painter.setPen(text_pen)
        painter.setFont(self.m_port_font)

        sizer = QFontMetrics(self.m_port_font)
        sep_width = sizer.width(self.m_trunck_sep)

        if self.m_portgrp_id:
            print_name_size = self.get_text_width()

            if self.m_port_mode == PORT_MODE_OUTPUT:
                text_pos = QPointF(self.m_port_width + 9 - print_name_size,
                                   canvas.theme.port_text_ypos)

            if print_name_size > (self.m_port_width - 4):
                painter.setPen(QPen(port_gradient, 3))
                painter.drawLine(
                    QPointF(float(poly_locx[5]), 3.0),
                    QPointF(float(poly_locx[5]),
                            canvas.theme.port_height - 3.0))
                painter.setPen(text_pen)
                painter.setFont(self.m_port_font)

        painter.drawText(text_pos, self.m_print_name)

        if self.m_name_truncked:
            sep_x = text_pos.x() + sizer.width(self.m_print_name)

            painter.drawText(QPointF(sep_x + sep_width, text_pos.y()),
                             self.m_print_name_right)
            painter.setPen(poly_pen)
            painter.drawText(QPointF(sep_x,
                                     text_pos.y() + 1), self.m_trunck_sep)

        if canvas.theme.idx == Theme.THEME_OOSTUDIO and canvas.theme.port_bg_pixmap:
            painter.setPen(Qt.NoPen)
            painter.setBrush(conn_pen.brush())

            if self.m_port_mode == PORT_MODE_INPUT:
                connRect = QRectF(portRect.topLeft(),
                                  QSizeF(2, portRect.height()))
            else:
                connRect = QRectF(
                    QPointF(portRect.right() - 2, portRect.top()),
                    QSizeF(2, portRect.height()))

            painter.drawRect(connRect)

        painter.restore()
Esempio n. 13
0
class CanvasPreviewFrame(QFrame):
    miniCanvasMoved = pyqtSignal(float, float)

    # x = 2
    # y = 2
    # w = width - 4
    # h = height - 3
    # bounds -1 px

    _kRectX = 0
    _kRectY = 1
    _kRectWidth = 2
    _kRectHeight = 3

    _kCursorName = 0
    _kCursorZoom = 1
    _kCursorZoomIn = 2
    _kCursorZoomOut = 3
    _kCursorZoomCount = 4

    _MOUSE_MODE_NONE = 0
    _MOUSE_MODE_MOVE = 1
    _MOUSE_MODE_SCALE = 2

    _RUBBERBAND_BLENDING_DEFAULT = 0
    _RUBBERBAND_BLENDING_PLUS = 1
    _RUBBERBAND_BLENDING_DIFF = 2

    # -----------------------------------------------------------------------------------------------------------------

    def __init__(self, parent):
        QFrame.__init__(self, parent)

        #self.setMinimumWidth(210)
        #self.setMinimumHeight(162)
        #self.setMaximumHeight(162)

        self.fRealParent = None
        self.fInternalWidth = 210 - 6  # -4 for width + -1px*2 bounds
        self.fInternalHeight = 162 - 5  # -3 for height + -1px*2 bounds
        self.fInternalRatio = self.fInternalWidth / self.fInternalHeight

        self.fScene = None
        self.fRenderSource = QRectF(0.0, 0.0, 0.0, 0.0)
        self.fRenderTarget = QRectF(0.0, 0.0, 0.0, 0.0)
        self.fUseCustomPaint = False
        self.fFrameWidth = 0.0

        self.fInitialX = 0.0
        self.fInitialY = 0.0
        self.fScale = 1.0

        self.fViewBg = QColor(0, 0, 0)
        self.fViewBrush = QBrush(QColor(75, 75, 255, 30))
        self.fViewPen = QPen(Qt.blue, 1)
        self.fViewRect = [3.0, 3.0, 10.0, 10.0]

        self.fMouseMode = self._MOUSE_MODE_NONE
        self.fMouseLeftDown = False
        self.fMouseRightDown = False
        self.fMouseInitialZoomPos = None

        self.fRubberBandBlending = self._RUBBERBAND_BLENDING_DEFAULT

        self.fZoomCursors = [None for _ in range(self._kCursorZoomCount)]
        self.fZoomCursors[self._kCursorName] = "black"
        self.fZoomCursors[self._kCursorZoom] = QCursor(
            QPixmap(":/cursors/zoom_black.png"), 8, 7)
        self.fZoomCursors[self._kCursorZoomIn] = QCursor(
            QPixmap(":/cursors/zoom-in_black.png"), 8, 7)
        self.fZoomCursors[self._kCursorZoomOut] = QCursor(
            QPixmap(":/cursors/zoom-out_black.png"), 8, 7)

    def init(self,
             scene: QGraphicsScene,
             realWidth: float,
             realHeight: float,
             useCustomPaint: bool = False):
        self.fScene = scene
        self.fRenderSource = QRectF(0.0, 0.0, realWidth, realHeight)
        self.fInternalRatio = realWidth / realHeight
        self._updateStyle()

        if self.fUseCustomPaint != useCustomPaint:
            self.fUseCustomPaint = useCustomPaint
            self.repaint()

    def setRealParent(self, parent):
        self.fRealParent = parent

    # -----------------------------------------------------------------------------------------------------------------

    def setViewPosX(self, xp: float):
        self.fViewRect[self._kRectX] = xp * (
            self.fInternalWidth -
            self.fViewRect[self._kRectWidth] / self.fScale)
        self.update()

    def setViewPosY(self, yp: float):
        self.fViewRect[self._kRectY] = yp * (
            self.fInternalHeight -
            self.fViewRect[self._kRectHeight] / self.fScale)
        self.update()

    def setViewScale(self, scale: float):
        self.fScale = scale

        if self.fRealParent is not None:
            QTimer.singleShot(0, self.fRealParent.slot_miniCanvasCheckAll)

    def setViewSize(self, width: float, height: float):
        self.fViewRect[self._kRectWidth] = width * self.fInternalWidth
        self.fViewRect[self._kRectHeight] = height * self.fInternalHeight
        self.update()

    def setViewTheme(self, bgColor, brushColor, penColor):
        bg_black = bgColor.blackF()
        brush_black = brushColor.blackF()
        r0, g0, b0, _ = bgColor.getRgb()
        r1, g1, b1, _ = brushColor.getRgb()

        if brush_black < bg_black:
            self.fRubberBandBlending = self._RUBBERBAND_BLENDING_PLUS
            brushColor = QColor(r1 - r0, g1 - g0, b1 - b0, 40)
        elif bg_black < brush_black:
            self.fRubberBandBlending = self._RUBBERBAND_BLENDING_DIFF
            brushColor = QColor(r0 - r1, g0 - g1, b0 - b1, 40)
        else:
            bgColor.setAlpha(40)
            self.fRubberBandBlending = self._RUBBERBAND_BLENDING_DEFAULT

        penColor.setAlpha(100)
        self.fViewBg = bgColor
        self.fViewBrush = QBrush(brushColor)
        self.fViewPen = QPen(penColor, 1)

        cursorName = "black" if bg_black < 0.5 else "white"
        if self.fZoomCursors[self._kCursorName] != cursorName:
            prefix = ":/cursors/zoom"
            self.fZoomCursors[self._kCursorName] = cursorName
            self.fZoomCursors[self._kCursorZoom] = QCursor(
                QPixmap("{}_{}.png".format(prefix, cursorName)), 8, 7)
            self.fZoomCursors[self._kCursorZoomIn] = QCursor(
                QPixmap("{}-in_{}.png".format(prefix, cursorName)), 8, 7)
            self.fZoomCursors[self._kCursorZoomOut] = QCursor(
                QPixmap("{}-out_{}.png".format(prefix, cursorName)), 8, 7)

    # -----------------------------------------------------------------------------------------------------------------

    def changeEvent(self, event):
        if event.type() in (QEvent.StyleChange, QEvent.PaletteChange):
            self._updateStyle()
        QFrame.changeEvent(self, event)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            event.accept()
            self.fMouseLeftDown = True
            self._updateMouseMode(event)
            return
        if event.button() == Qt.RightButton:
            event.accept()
            self.fMouseRightDown = True
            self._updateMouseMode(event)
            return
        if event.button() == Qt.MidButton:
            event.accept()
            self.fMouseLeftDown = True
            self.fMouseRightDown = True
            self._updateMouseMode(event)
            return
        QFrame.mouseMoveEvent(self, event)

    def mouseMoveEvent(self, event):
        if self.fMouseMode == self._MOUSE_MODE_MOVE:
            event.accept()
            self._moveViewRect(event.x(), event.y())
            return
        if self.fMouseMode == self._MOUSE_MODE_SCALE:
            event.accept()
            self._scaleViewRect(event.globalY())
            return
        QFrame.mouseMoveEvent(self, event)

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            event.accept()
            self.fMouseLeftDown = False
            self._updateMouseMode()
            return
        if event.button() == Qt.RightButton:
            event.accept()
            self.fMouseRightDown = False
            self._updateMouseMode(event)
            return
        if event.button() == Qt.MidButton:
            event.accept()
            self.fMouseLeftDown = event.buttons() & Qt.LeftButton
            self.fMouseRightDown = event.buttons() & Qt.RightButton
            self._updateMouseMode(event)
            return
        QFrame.mouseReleaseEvent(self, event)

    def wheelEvent(self, event):
        if self.fScene is None:
            QFrame.wheelEvent(self, event)
            return

        event.accept()
        self.fScene.zoom_wheel(event.angleDelta().y())

    def paintEvent(self, event):
        if self.fScene is None:
            QFrame.paintEvent(self, event)
            return

        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing,
                              bool(options.antialiasing == ANTIALIASING_FULL))

        # Brightness-aware out-of-canvas shading
        bg_color = self.fViewBg
        bg_black = bg_color.black()
        bg_shade = -12 if bg_black < 127 else 12
        r, g, b, _ = bg_color.getRgb()
        bg_color = QColor(r + bg_shade, g + bg_shade, b + bg_shade)

        frameWidth = self.fFrameWidth
        if self.fUseCustomPaint:
            # Inner shadow
            color = QColor.fromHsv(40, 0,
                                   255 - max(210, bg_color.black(), bg_black))
            painter.setBrush(Qt.transparent)
            painter.setPen(color)
            painter.drawRect(
                QRectF(0.5, 0.5,
                       self.width() - 1,
                       self.height() - 1))

            # Background
            painter.setBrush(bg_color)
            painter.setPen(bg_color)
            painter.drawRect(
                QRectF(1.5, 1.5,
                       self.width() - 3,
                       self.height() - 3))
        else:
            use_rounding = int(frameWidth > 1)

            rounding = 0.5 * use_rounding
            painter.setBrush(bg_color)
            painter.setPen(bg_color)
            painter.drawRoundedRect(
                QRectF(0.5 + frameWidth, 0.5 + frameWidth,
                       self.width() - 1 - frameWidth * 2,
                       self.height() - 1 - frameWidth * 2), rounding, rounding)

            clipPath = QPainterPath()
            rounding = 1.0 * use_rounding
            clipPath.addRoundedRect(
                QRectF(frameWidth, frameWidth,
                       self.width() - frameWidth * 2,
                       self.height() - frameWidth * 2), rounding, rounding)
            painter.setClipPath(clipPath)

        self.fScene.render(painter, self.fRenderTarget, self.fRenderSource,
                           Qt.KeepAspectRatio)

        # Allow cursor frame to look joined with minicanvas frame
        painter.setClipping(False)

        width = self.fViewRect[self._kRectWidth] / self.fScale
        height = self.fViewRect[self._kRectHeight] / self.fScale

        # cursor
        lineHinting = self.fViewPen.widthF() / 2
        x = self.fViewRect[self._kRectX] + self.fInitialX
        y = self.fViewRect[self._kRectY] + self.fInitialY
        scr_x = floor(x)
        scr_y = floor(y)
        rect = QRectF(scr_x + lineHinting, scr_y + lineHinting,
                      ceil(width + x - scr_x) - lineHinting * 2,
                      ceil(height + y - scr_y) - lineHinting * 2)

        if self.fRubberBandBlending == self._RUBBERBAND_BLENDING_PLUS:
            painter.setCompositionMode(QPainter.CompositionMode_Plus)
        elif self.fRubberBandBlending == self._RUBBERBAND_BLENDING_DIFF:
            painter.setCompositionMode(QPainter.CompositionMode_Difference)

        painter.setBrush(self.fViewBrush)
        painter.setPen(Qt.NoPen)
        painter.drawRect(rect)

        painter.setCompositionMode(QPainter.CompositionMode_SourceOver)
        painter.setBrush(Qt.NoBrush)
        painter.setPen(self.fViewPen)
        painter.drawRect(rect)

        if self.fUseCustomPaint:
            event.accept()
        else:
            QFrame.paintEvent(self, event)

    def resizeEvent(self, event):
        size = event.size()
        width = size.width()
        height = size.height()
        extRatio = (width - self.fFrameWidth * 2) / (height -
                                                     self.fFrameWidth * 2)
        if extRatio >= self.fInternalRatio:
            self.fInternalHeight = floor(height - self.fFrameWidth * 2)
            self.fInternalWidth = floor(self.fInternalHeight *
                                        self.fInternalRatio)
            self.fInitialX = floor(float(width - self.fInternalWidth) / 2.0)
            self.fInitialY = self.fFrameWidth
        else:
            self.fInternalWidth = floor(width - self.fFrameWidth * 2)
            self.fInternalHeight = floor(self.fInternalWidth /
                                         self.fInternalRatio)
            self.fInitialX = self.fFrameWidth
            self.fInitialY = floor(float(height - self.fInternalHeight) / 2.0)

        self.fRenderTarget = QRectF(self.fInitialX, self.fInitialY,
                                    float(self.fInternalWidth),
                                    float(self.fInternalHeight))

        if self.fRealParent is not None:
            QTimer.singleShot(0, self.fRealParent.slot_miniCanvasCheckAll)

        QFrame.resizeEvent(self, event)

    # -----------------------------------------------------------------------------------------------------------------

    def _moveViewRect(self, x: float, y: float):
        if self.fScene is None:
            return

        x -= self.fInitialX
        y -= self.fInitialY

        fixPos = False
        rCentX = self.fViewRect[self._kRectWidth] / self.fScale / 2
        rCentY = self.fViewRect[self._kRectHeight] / self.fScale / 2
        if x < rCentX:
            x = rCentX
            fixPos = True
        elif x > self.fInternalWidth - rCentX:
            x = self.fInternalWidth - rCentX
            fixPos = True

        if y < rCentY:
            y = rCentY
            fixPos = True
        elif y > self.fInternalHeight - rCentY:
            y = self.fInternalHeight - rCentY
            fixPos = True

        if fixPos:
            globalPos = self.mapToGlobal(
                QPoint(self.fInitialX + x, self.fInitialY + y))
            self.cursor().setPos(globalPos)

        x = self.fRenderSource.width() * x / self.fInternalWidth
        y = self.fRenderSource.height() * y / self.fInternalHeight
        self.fScene.m_view.centerOn(x, y)

    def _scaleViewRect(self, globalY: int):
        if self.fScene is None:
            return

        dy = self.fMouseInitialZoomPos.y() - globalY
        if dy != 0:
            self.setCursor(
                self.fZoomCursors[self._kCursorZoomIn if dy > 0 else self.
                                  _kCursorZoomOut])
            self.fScene.zoom_wheel(dy)

        self.cursor().setPos(self.fMouseInitialZoomPos)

    def _updateMouseMode(self, event=None):
        if self.fMouseLeftDown and self.fMouseRightDown:
            self.fMouseInitialZoomPos = event.globalPos()
            self.setCursor(self.fZoomCursors[self._kCursorZoom])
            self.fMouseMode = self._MOUSE_MODE_SCALE

        elif self.fMouseLeftDown:
            self.setCursor(QCursor(Qt.SizeAllCursor))
            if self.fMouseMode == self._MOUSE_MODE_NONE:
                self._moveViewRect(event.x(), event.y())
            self.fMouseMode = self._MOUSE_MODE_MOVE

        else:
            self.unsetCursor()
            self.fMouseMode = self._MOUSE_MODE_NONE

    def _updateStyle(self):
        self.fFrameWidth = 1 if self.fUseCustomPaint else self.frameWidth()
Esempio n. 14
0
    def drawMapObject(self, painter, object, color):
        painter.save()
        pen = QPen(Qt.black)
        pen.setCosmetic(True)
        cell = object.cell()
        if (not cell.isEmpty()):
            tile = cell.tile
            imgSize = tile.size()
            pos = self.pixelToScreenCoords_(object.position())
            tileOffset = tile.offset()
            CellRenderer(painter).render(cell, pos, object.size(), CellRenderer.BottomCenter)
            if (self.testFlag(RenderFlag.ShowTileObjectOutlines)):
                rect = QRectF(QPointF(pos.x() - imgSize.width() / 2 + tileOffset.x(),
                                    pos.y() - imgSize.height() + tileOffset.y()),
                            QSizeF(imgSize))
                pen.setStyle(Qt.SolidLine)
                painter.setPen(pen)
                painter.drawRect(rect)
                pen.setStyle(Qt.DotLine)
                pen.setColor(color)
                painter.setPen(pen)
                painter.drawRect(rect)
        else:
            lineWidth = self.objectLineWidth()
            scale = self.painterScale()
            x = 1
            if lineWidth != 0:
                x = lineWidth
            shadowOffset = x / scale
            brushColor = QColor(color)
            brushColor.setAlpha(50)
            brush = QBrush(brushColor)
            pen.setJoinStyle(Qt.RoundJoin)
            pen.setCapStyle(Qt.RoundCap)
            pen.setWidth(lineWidth)
            
            colorPen = QPen(pen)
            colorPen.setColor(color)
        
            painter.setPen(pen)
            painter.setRenderHint(QPainter.Antialiasing)
            # TODO: Do something sensible to make null-sized objects usable
            x = object.shape()
            if x==MapObject.Ellipse:
                polygon = self.pixelRectToScreenPolygon(object.bounds())
                tw = self.map().tileWidth()
                th = self.map().tileHeight()
                transformScale = QPointF(1, 1)
                if (tw > th):
                    transformScale = QPointF(1, th/tw)
                else:
                    transformScale = QPointF(tw/th, 1)
                l1 = polygon.at(1) - polygon.at(0)
                l2 = polygon.at(3) - polygon.at(0)
                trans = QTransform()
                trans.scale(transformScale.x(), transformScale.y())
                trans.rotate(45)
                iTrans, ok = trans.inverted()
                l1x = iTrans.map(l1)
                l2x = iTrans.map(l2)
                ellipseSize = QSizeF(l1x.manhattanLength(), l2x.manhattanLength())
                if (ellipseSize.width() > 0 and ellipseSize.height() > 0):
                    painter.save()
                    painter.setPen(pen)
                    painter.translate(polygon.at(0))
                    painter.scale(transformScale.x(), transformScale.y())
                    painter.rotate(45)
                    painter.drawEllipse(QRectF(QPointF(0, 0), ellipseSize))
                    painter.restore()

                painter.setBrush(Qt.NoBrush)
                painter.drawPolygon(polygon)
                
                painter.setPen(colorPen)
                painter.setBrush(Qt.NoBrush)
                painter.translate(QPointF(0, -shadowOffset))
                painter.drawPolygon(polygon)
                painter.setBrush(brush)
                if (ellipseSize.width() > 0 and ellipseSize.height() > 0):
                    painter.save()
                    painter.translate(polygon.at(0))
                    painter.scale(transformScale.x(), transformScale.y())
                    painter.rotate(45)
                    painter.drawEllipse(QRectF(QPointF(0, 0), ellipseSize))
                    painter.restore()
            elif x==MapObject.Rectangle:
                polygon = self.pixelRectToScreenPolygon(object.bounds())
                painter.drawPolygon(polygon)
                painter.setPen(colorPen)
                painter.setBrush(brush)
                polygon.translate(0, -shadowOffset)
                painter.drawPolygon(polygon)
            elif x==MapObject.Polygon:
                pos = object.position()
                polygon = object.polygon().translated(pos)
                screenPolygon = self.pixelToScreenCoords_(polygon)
                thickPen = QPen(pen)
                thickColorPen = QPen(colorPen)
                thickPen.setWidthF(thickPen.widthF() * 4)
                thickColorPen.setWidthF(thickColorPen.widthF() * 4)
            
                painter.drawPolygon(screenPolygon)
                
                painter.setPen(thickPen)
                painter.drawPoint(screenPolygon.first())

                painter.setPen(colorPen)
                painter.setBrush(brush)
                screenPolygon.translate(0, -shadowOffset)
                painter.drawPolygon(screenPolygon)
                painter.setPen(thickColorPen)
                painter.drawPoint(screenPolygon.first())
                
            elif x==MapObject.Polyline:
                pos = object.position()
                polygon = object.polygon().translated(pos)
                screenPolygon = self.pixelToScreenCoords_(polygon)
                thickPen = QPen(pen)
                thickColorPen = QPen(colorPen)
                thickPen.setWidthF(thickPen.widthF() * 4)
                thickColorPen.setWidthF(thickColorPen.widthF() * 4)
                
                painter.drawPolyline(screenPolygon)
                painter.setPen(thickPen)
                painter.drawPoint(screenPolygon.first())
                
                painter.setPen(colorPen)
                screenPolygon.translate(0, -shadowOffset)
                painter.drawPolyline(screenPolygon)
                
                painter.setPen(thickColorPen)
                painter.drawPoint(screenPolygon.first())

        painter.restore()
Esempio n. 15
0
    def drawMapObject(self, painter, object, color):
        painter.save()
        pen = QPen(Qt.black)
        pen.setCosmetic(True)
        cell = object.cell()
        if (not cell.isEmpty()):
            tile = cell.tile
            imgSize = tile.size()
            pos = self.pixelToScreenCoords_(object.position())
            tileOffset = tile.offset()
            CellRenderer(painter).render(cell, pos, object.size(),
                                         CellRenderer.BottomCenter)
            if (self.testFlag(RenderFlag.ShowTileObjectOutlines)):
                rect = QRectF(
                    QPointF(pos.x() - imgSize.width() / 2 + tileOffset.x(),
                            pos.y() - imgSize.height() + tileOffset.y()),
                    QSizeF(imgSize))
                pen.setStyle(Qt.SolidLine)
                painter.setPen(pen)
                painter.drawRect(rect)
                pen.setStyle(Qt.DotLine)
                pen.setColor(color)
                painter.setPen(pen)
                painter.drawRect(rect)
        else:
            lineWidth = self.objectLineWidth()
            scale = self.painterScale()
            x = 1
            if lineWidth != 0:
                x = lineWidth
            shadowOffset = x / scale
            brushColor = QColor(color)
            brushColor.setAlpha(50)
            brush = QBrush(brushColor)
            pen.setJoinStyle(Qt.RoundJoin)
            pen.setCapStyle(Qt.RoundCap)
            pen.setWidth(lineWidth)

            colorPen = QPen(pen)
            colorPen.setColor(color)

            painter.setPen(pen)
            painter.setRenderHint(QPainter.Antialiasing)
            # TODO: Do something sensible to make null-sized objects usable
            x = object.shape()
            if x == MapObject.Ellipse:
                polygon = self.pixelRectToScreenPolygon(object.bounds())
                tw = self.map().tileWidth()
                th = self.map().tileHeight()
                transformScale = QPointF(1, 1)
                if (tw > th):
                    transformScale = QPointF(1, th / tw)
                else:
                    transformScale = QPointF(tw / th, 1)
                l1 = polygon.at(1) - polygon.at(0)
                l2 = polygon.at(3) - polygon.at(0)
                trans = QTransform()
                trans.scale(transformScale.x(), transformScale.y())
                trans.rotate(45)
                iTrans, ok = trans.inverted()
                l1x = iTrans.map(l1)
                l2x = iTrans.map(l2)
                ellipseSize = QSizeF(l1x.manhattanLength(),
                                     l2x.manhattanLength())
                if (ellipseSize.width() > 0 and ellipseSize.height() > 0):
                    painter.save()
                    painter.setPen(pen)
                    painter.translate(polygon.at(0))
                    painter.scale(transformScale.x(), transformScale.y())
                    painter.rotate(45)
                    painter.drawEllipse(QRectF(QPointF(0, 0), ellipseSize))
                    painter.restore()

                painter.setBrush(Qt.NoBrush)
                painter.drawPolygon(polygon)

                painter.setPen(colorPen)
                painter.setBrush(Qt.NoBrush)
                painter.translate(QPointF(0, -shadowOffset))
                painter.drawPolygon(polygon)
                painter.setBrush(brush)
                if (ellipseSize.width() > 0 and ellipseSize.height() > 0):
                    painter.save()
                    painter.translate(polygon.at(0))
                    painter.scale(transformScale.x(), transformScale.y())
                    painter.rotate(45)
                    painter.drawEllipse(QRectF(QPointF(0, 0), ellipseSize))
                    painter.restore()
            elif x == MapObject.Rectangle:
                polygon = self.pixelRectToScreenPolygon(object.bounds())
                painter.drawPolygon(polygon)
                painter.setPen(colorPen)
                painter.setBrush(brush)
                polygon.translate(0, -shadowOffset)
                painter.drawPolygon(polygon)
            elif x == MapObject.Polygon:
                pos = object.position()
                polygon = object.polygon().translated(pos)
                screenPolygon = self.pixelToScreenCoords_(polygon)
                thickPen = QPen(pen)
                thickColorPen = QPen(colorPen)
                thickPen.setWidthF(thickPen.widthF() * 4)
                thickColorPen.setWidthF(thickColorPen.widthF() * 4)

                painter.drawPolygon(screenPolygon)

                painter.setPen(thickPen)
                painter.drawPoint(screenPolygon.first())

                painter.setPen(colorPen)
                painter.setBrush(brush)
                screenPolygon.translate(0, -shadowOffset)
                painter.drawPolygon(screenPolygon)
                painter.setPen(thickColorPen)
                painter.drawPoint(screenPolygon.first())

            elif x == MapObject.Polyline:
                pos = object.position()
                polygon = object.polygon().translated(pos)
                screenPolygon = self.pixelToScreenCoords_(polygon)
                thickPen = QPen(pen)
                thickColorPen = QPen(colorPen)
                thickPen.setWidthF(thickPen.widthF() * 4)
                thickColorPen.setWidthF(thickColorPen.widthF() * 4)

                painter.drawPolyline(screenPolygon)
                painter.setPen(thickPen)
                painter.drawPoint(screenPolygon.first())

                painter.setPen(colorPen)
                screenPolygon.translate(0, -shadowOffset)
                painter.drawPolyline(screenPolygon)

                painter.setPen(thickColorPen)
                painter.drawPoint(screenPolygon.first())

        painter.restore()
Esempio n. 16
0
    def updateLinePos(self, scenePos):
        if self.m_ready_to_disc:
            if self.m_port_type == PORT_TYPE_AUDIO_JACK:
                pen = QPen(canvas.theme.line_audio_jack_sel, 2, Qt.DotLine)
            elif self.m_port_type == PORT_TYPE_MIDI_JACK:
                pen = QPen(canvas.theme.line_midi_jack_sel, 2, Qt.DotLine)
            elif self.m_port_type == PORT_TYPE_MIDI_ALSA:
                pen = QPen(canvas.theme.line_midi_alsa_sel, 2, Qt.DotLine)
            elif self.m_port_type == PORT_TYPE_PARAMETER:
                pen = QPen(canvas.theme.line_parameter_sel, 2, Qt.DotLine)
            else:
                pen = QPen(Qt.black)
        else:
            if self.m_port_type == PORT_TYPE_AUDIO_JACK:
                pen = QPen(canvas.theme.line_audio_jack_sel, 2)
            elif self.m_port_type == PORT_TYPE_MIDI_JACK:
                pen = QPen(canvas.theme.line_midi_jack_sel, 2)
            elif self.m_port_type == PORT_TYPE_MIDI_ALSA:
                pen = QPen(canvas.theme.line_midi_alsa_sel, 2)
            elif self.m_port_type == PORT_TYPE_PARAMETER:
                pen = QPen(canvas.theme.line_parameter_sel, 2)
            else:
                pen = QPen(Qt.black)

        pen.setCapStyle(Qt.FlatCap)
        pen.setWidthF(pen.widthF() + 0.00001)
        self.setPen(pen)

        phi = 0.75 if self.m_portgrp_lenght > 2 else 0.62
        phito = 0.75 if self.m_portgrp_lenght_to > 2 else 0.62

        if self.parentItem().type() == CanvasPortType:
            if self.m_portgrp_lenght > 1:
                first_old_y = canvas.theme.port_height * phi
                last_old_y = canvas.theme.port_height * (
                    self.m_portgrp_lenght - phi)
                delta = (last_old_y - first_old_y) / (self.m_portgrp_lenght -
                                                      1)
                old_y = first_old_y + (self.m_port_posinportgrp * delta) \
                        - canvas.theme.port_height * self.m_port_posinportgrp
            else:
                old_y = canvas.theme.port_height / 2

            if self.m_portgrp_lenght_to == 1:
                new_y = 0
            else:
                first_new_y = canvas.theme.port_height * phito
                last_new_y = canvas.theme.port_height * (
                    self.m_portgrp_lenght_to - phito)
                delta = (last_new_y -
                         first_new_y) / (self.m_portgrp_lenght_to - 1)
                new_y1 = first_new_y + (self.m_port_posinportgrp_to * delta)
                new_y = new_y1 - ( (last_new_y - first_new_y) / 2 ) \
                        - canvas.theme.port_height * phito

        elif self.parentItem().type() == CanvasPortGroupType:
            first_old_y = canvas.theme.port_height * phi
            last_old_y = canvas.theme.port_height * (self.m_portgrp_lenght -
                                                     phi)
            delta = (last_old_y - first_old_y) / (self.m_portgrp_lenght - 1)
            old_y = first_old_y + (self.m_port_posinportgrp * delta)

            if self.m_portgrp_lenght_to == 1:
                new_y = 0
            elif (self.m_port_posinportgrp_to == self.m_port_posinportgrp
                  and self.m_portgrp_lenght == self.m_portgrp_lenght_to):
                new_y = old_y - ( (last_old_y - first_old_y) / 2 ) \
                        - (canvas.theme.port_height * phi)
            else:
                first_new_y = canvas.theme.port_height * phito
                last_new_y = canvas.theme.port_height * (
                    self.m_portgrp_lenght_to - phito)
                delta = (last_new_y -
                         first_new_y) / (self.m_portgrp_lenght_to - 1)
                new_y1 = first_new_y + (self.m_port_posinportgrp_to * delta)
                new_y = new_y1 - ( (last_new_y - first_new_y) / 2 ) \
                        - (canvas.theme.port_height * phito)

        final_x = scenePos.x() - self.p_itemX
        final_y = scenePos.y() - self.p_itemY + new_y

        if self.m_port_mode == PORT_MODE_OUTPUT:
            old_x = self.p_width + 12
            mid_x = abs(final_x - old_x) / 2
            new_x1 = old_x + mid_x
            new_x2 = final_x - mid_x

            diffxy = abs(final_y - old_y) - abs(final_x - old_x)
            if diffxy > 0:
                new_x1 += abs(diffxy)
                new_x2 -= abs(diffxy)

        elif self.m_port_mode == PORT_MODE_INPUT:
            old_x = 0
            mid_x = abs(final_x - old_x) / 2
            new_x1 = old_x - mid_x
            new_x2 = final_x + mid_x

            diffxy = abs(final_y - old_y) - abs(final_x - old_x)
            if diffxy > 0:
                new_x1 -= abs(diffxy)
                new_x2 += abs(diffxy)
        else:
            return

        path = QPainterPath(QPointF(old_x, old_y))
        path.cubicTo(new_x1, old_y, new_x2, final_y, final_x, final_y)
        self.setPath(path)
Esempio n. 17
0
    def paint(self, painter, option, widget):
        painter.save()
        painter.setRenderHint(QPainter.Antialiasing,
                              bool(options.antialiasing == ANTIALIASING_FULL))
        rect = QRectF(0, 0, self.p_width, self.p_height)

        # Draw rectangle
        pen = QPen(canvas.theme.box_pen_sel if self.isSelected() else canvas.
                   theme.box_pen)
        pen.setWidthF(pen.widthF() + 0.00001)
        painter.setPen(pen)
        lineHinting = pen.widthF() / 2

        if canvas.theme.box_bg_type == Theme.THEME_BG_GRADIENT:
            box_gradient = QLinearGradient(0, 0, 0, self.p_height)
            box_gradient.setColorAt(0, canvas.theme.box_bg_1)
            box_gradient.setColorAt(1, canvas.theme.box_bg_2)
            painter.setBrush(box_gradient)
        else:
            painter.setBrush(canvas.theme.box_bg_1)

        rect.adjust(lineHinting, lineHinting, -lineHinting, -lineHinting)
        painter.drawRect(rect)

        # Draw plugin inline display if supported
        self.paintInlineDisplay(painter)

        # Draw pixmap header
        rect.setHeight(canvas.theme.box_header_height)
        if canvas.theme.box_header_pixmap:
            painter.setPen(Qt.NoPen)
            painter.setBrush(canvas.theme.box_bg_2)

            # outline
            rect.adjust(lineHinting, lineHinting, -lineHinting, -lineHinting)
            painter.drawRect(rect)

            rect.adjust(1, 1, -1, 0)
            painter.drawTiledPixmap(rect, canvas.theme.box_header_pixmap,
                                    rect.topLeft())

        # Draw text
        painter.setFont(self.m_font_name)

        if self.isSelected():
            painter.setPen(canvas.theme.box_text_sel)
        else:
            painter.setPen(canvas.theme.box_text)

        if canvas.theme.box_use_icon:
            textPos = QPointF(25, canvas.theme.box_text_ypos)
        else:
            appNameSize = fontHorizontalAdvance(self.m_font_name,
                                                self.m_group_name)
            rem = self.p_width - appNameSize
            textPos = QPointF(rem / 2, canvas.theme.box_text_ypos)

        painter.drawText(textPos, self.m_group_name)

        self.repaintLines()

        painter.restore()
Esempio n. 18
0
    def drawMapObject(self, painter, object, color):
        painter.save()
        bounds = object.bounds()
        rect = QRectF(bounds)
        painter.translate(rect.topLeft())
        rect.moveTopLeft(QPointF(0, 0))
        cell = object.cell()
        if (not cell.isEmpty()):
            CellRenderer(painter).render(cell, QPointF(), object.size(),
                                         CellRenderer.BottomLeft)
            if (self.testFlag(RenderFlag.ShowTileObjectOutlines)):
                tile = cell.tile
                imgSize = tile.size()
                tileOffset = tile.offset()
                rect = QRectF(
                    QPointF(tileOffset.x(),
                            tileOffset.y() - imgSize.height()),
                    QSizeF(imgSize))
                pen = QPen(Qt.SolidLine)
                pen.setCosmetic(True)
                painter.setPen(pen)
                painter.drawRect(rect)
                pen.setStyle(Qt.DotLine)
                pen.setColor(color)
                painter.setPen(pen)
                painter.drawRect(rect)
        else:
            lineWidth = self.objectLineWidth()
            scale = self.painterScale()
            if lineWidth == 0:
                x = 1
            else:
                x = lineWidth
            shadowDist = x / scale
            shadowOffset = QPointF(shadowDist * 0.5, shadowDist * 0.5)
            linePen = QPen(color, lineWidth, Qt.SolidLine, Qt.RoundCap,
                           Qt.RoundJoin)
            #linePen.setCosmetic(True)
            shadowPen = QPen(linePen)
            shadowPen.setColor(Qt.black)
            brushColor = QColor(color)
            fillBrush = QBrush(brushColor)
            painter.setRenderHint(QPainter.Antialiasing)
            # Trying to draw an ellipse with 0-width is causing a hang in
            # CoreGraphics when drawing the path requested by the
            # QCoreGraphicsPaintEngine. Draw them as rectangle instead.
            shape = object.shape()
            if (shape == MapObject.Ellipse
                    and ((rect.width() == 0.0) ^ (rect.height() == 0.0))):
                shape = MapObject.Rectangle
            x = shape
            if x == MapObject.Rectangle:
                if (rect.isNull()):
                    rect = QRectF(QPointF(-10, -10), QSizeF(20, 20))
                # Draw the shadow
                painter.setPen(shadowPen)
                painter.drawRect(rect.translated(shadowOffset))
                painter.setPen(linePen)
                painter.setBrush(fillBrush)
                painter.drawRect(rect)
            elif x == MapObject.Polyline:
                screenPolygon = self.pixelToScreenCoords_(object.polygon())
                thickShadowPen = QPen(shadowPen)
                thickLinePen = QPen(linePen)
                thickShadowPen.setWidthF(thickShadowPen.widthF() * 4)
                thickLinePen.setWidthF(thickLinePen.widthF() * 4)

                painter.setPen(shadowPen)
                painter.drawPolyline(screenPolygon.translated(shadowOffset))
                painter.setPen(thickShadowPen)
                painter.drawPoint(screenPolygon.first() + shadowOffset)

                painter.setPen(linePen)
                painter.setBrush(fillBrush)
                painter.drawPolyline(screenPolygon)
                painter.setPen(thickLinePen)
                painter.drawPoint(screenPolygon.first())

            elif x == MapObject.Polygon:
                screenPolygon = self.pixelToScreenCoords_(object.polygon())
                thickShadowPen = QPen(shadowPen)
                thickLinePen = QPen(linePen)
                thickShadowPen.setWidthF(thickShadowPen.widthF() * 4)
                thickLinePen.setWidthF(thickLinePen.widthF() * 4)

                painter.setPen(shadowPen)
                painter.drawPolygon(screenPolygon.translated(shadowOffset))
                painter.setPen(thickShadowPen)
                painter.drawPoint(screenPolygon.first() + shadowOffset)

                painter.setPen(linePen)
                painter.setBrush(fillBrush)
                painter.drawPolygon(screenPolygon)

                painter.setPen(thickLinePen)
                painter.drawPoint(screenPolygon.first())

            elif x == MapObject.Ellipse:
                if (rect.isNull()):
                    rect = QRectF(QPointF(-10, -10), QSizeF(20, 20))
                # Draw the shadow
                painter.setPen(shadowPen)
                painter.drawEllipse(rect.translated(shadowOffset))
                painter.setPen(linePen)
                painter.setBrush(fillBrush)
                painter.drawEllipse(rect)

        painter.restore()