Ejemplo n.º 1
0
class CartPoleShape:
    def __init__(self):
        self._boundingBox = QRectF(-239 / 2, -216 / 2, 239, 216)

        self._cartBody = QRectF(self._boundingBox.left(),
                                self._boundingBox.top() + 82,
                                self._boundingBox.width(), 106)

        self._cartJointBody = QRectF(
            self._cartBody.center().x() - 53 / 2,
            self._boundingBox.top() + 53 / 2, 53,
            self._cartBody.top() - self._boundingBox.top() - 53 / 2)

        self._cartJointBall = QRectF(
            self._cartJointBody.center().x() - self._cartJointBody.width() / 2,
            self._cartJointBody.top() - self._cartJointBody.width() / 2,
            self._cartJointBody.width(), self._cartJointBody.width())

        self._poleCenter = self._cartJointBall.center()

        self._leftGear = QRectF(self._boundingBox.left() + 43 - 26,
                                self._boundingBox.top() + 188 - 26, 26 * 2,
                                26 * 2)

        self._leftGearJoint = QRectF(self._boundingBox.left() + 43 - 2,
                                     self._boundingBox.top() + 188 - 2, 4, 4)

        self._rightGear = QRectF(self._boundingBox.left() + 194 - 26,
                                 self._boundingBox.top() + 188 - 26, 26 * 2,
                                 26 * 2)

        self._rightGearJoint = QRectF(self._boundingBox.left() + 194 - 2,
                                      self._boundingBox.top() + 188 - 2, 4, 4)

    def draw(self, qp, pen):
        qp.setPen(pen)
        qp.drawRect(self._cartBody)
        qp.drawLines([
            QLineF(self._cartJointBody.topLeft(),
                   self._cartJointBody.bottomLeft()),
            QLineF(self._cartJointBody.topRight(),
                   self._cartJointBody.bottomRight()),
            QLineF(self._cartJointBody.bottomLeft(),
                   self._cartJointBody.bottomRight())
        ])
        qp.drawArc(self._cartJointBall, 0, 180 * 16)
        qp.drawEllipse(self._leftGear)
        qp.drawEllipse(self._leftGearJoint)
        qp.drawEllipse(self._rightGear)
        qp.drawEllipse(self._rightGearJoint)

    # Computes the model matrix that moves the cart in center and has
    # size width
    def modelMatrix(self, center, width):
        return QTransform.fromScale(width / 239,
                                    width / 239) * QTransform.fromTranslate(
                                        -center.x(), -center.y())
Ejemplo n.º 2
0
 def _rect(self, rect, image_index):
     irect = QRectF(rect)
     irect.translate(-self.rect().center())
     irect.setTopLeft(irect.topLeft() * self.zoom[image_index])
     irect.setBottomRight(irect.bottomRight() * self.zoom[image_index])
     irect.translate(self.centers[image_index])
     return irect
Ejemplo n.º 3
0
    def draw_bg(self, qp, rect, text):
        path = QPainterPath()

        # add container
        path.addRoundedRect(rect, 4, 4)
        if self.isEnabled():
            highlight_color, bg_color, text_color = (
                self.settings['highlight'], self.settings['bg'],
                self.settings['text'])
        else:
            highlight_color, bg_color, text_color = (
                self.settings['highlight_disabled'],
                self.settings['bg_disabled'], self.settings['text_disabled'])
        qp.setPen(QPen(highlight_color, 2))
        qp.fillPath(path, bg_color)

        # add close button
        circle_size = rect.height() / 1.8
        pen_size = 2
        qp.setPen(QPen(text_color, pen_size, Qt.SolidLine))
        rect = QRectF(
            rect.right() - circle_size - self.settings['padding-x'] / 2,
            rect.top() + (rect.height() - circle_size) / 2, circle_size,
            circle_size)
        path.addEllipse(rect)
        qp.drawPath(path)
        # draw cross
        inside_rect = QRectF(rect)
        inside_rect.adjust(pen_size, pen_size, -pen_size, -pen_size)
        qp.drawLine(inside_rect.topLeft(), inside_rect.bottomRight())
        qp.drawLine(inside_rect.bottomLeft(), inside_rect.topRight())

        self.close_rectangles[text] = rect
Ejemplo n.º 4
0
    def _hitTest(self, rc: QRectF, mousePos: QPointF) -> Hit:
        maxdist = 4
        if not rc.adjusted(-maxdist, -maxdist, maxdist,
                           maxdist).contains(mousePos):
            return Hit.NoHit

        def dist(p1, p2):
            return (p1 - p2).manhattanLength()

        if dist(rc.topLeft(), mousePos) < maxdist:
            return Hit.TopLeft
        elif dist(rc.topRight(), mousePos) < maxdist:
            return Hit.TopRight
        elif dist(rc.bottomRight(), mousePos) < maxdist:
            return Hit.BottomRight
        elif dist(rc.bottomLeft(), mousePos) < maxdist:
            return Hit.BottomLeft
        elif abs(rc.left() - mousePos.x()) < maxdist:
            return Hit.Left
        elif abs(rc.right() - mousePos.x()) < maxdist:
            return Hit.Right
        elif abs(rc.top() - mousePos.y()) < maxdist:
            return Hit.Top
        elif abs(rc.bottom() - mousePos.y()) < maxdist:
            return Hit.Bottom
        elif rc.contains(mousePos):
            return Hit.Center
        else:
            return Hit.NoHit
Ejemplo n.º 5
0
    def zoom(self, logAmount):
        scale = math.exp(logAmount)
        border = self.getViewportRect()
        mid = border.center()

        border.translate(-mid)
        border = QRectF(border.topLeft() * scale, border.bottomRight() * scale)
        border.translate(mid)
        self.moveViewRect(border.intersected(self.sceneRect()))
Ejemplo n.º 6
0
class MapObjectOutline(QGraphicsItem):
    def __init__(self, object, parent=None):
        super().__init__(parent)

        self.mObject = object
        self.mBoundingRect = QRectF()
        self.setZValue(1)  # makes sure outlines are above labels

    def syncWithMapObject(self, renderer):
        pixelPos = renderer.pixelToScreenCoords_(self.mObject.position())
        bounds = objectBounds(self.mObject, renderer)
        bounds.translate(-pixelPos)
        self.setPos(pixelPos + self.mObject.objectGroup().offset())
        self.setRotation(self.mObject.rotation())
        if (self.mBoundingRect != bounds):
            self.prepareGeometryChange()
            self.mBoundingRect = bounds

    def boundingRect(self):
        return self.mBoundingRect

    def paint(self, painter, arg2, arg3):
        horizontal = [
            QLineF(self.mBoundingRect.topRight(),
                   self.mBoundingRect.topLeft()),
            QLineF(self.mBoundingRect.bottomRight(),
                   self.mBoundingRect.bottomLeft())
        ]

        vertical = [
            QLineF(self.mBoundingRect.bottomLeft(),
                   self.mBoundingRect.topLeft()),
            QLineF(self.mBoundingRect.bottomRight(),
                   self.mBoundingRect.topRight())
        ]

        dashPen = QPen(Qt.DashLine)
        dashPen.setCosmetic(True)
        dashPen.setDashOffset(max(0.0, self.x()))
        painter.setPen(dashPen)
        painter.drawLines(horizontal)
        dashPen.setDashOffset(max(0.0, self.y()))
        painter.setPen(dashPen)
        painter.drawLines(vertical)
Ejemplo n.º 7
0
    def draw(self, p: QtGui.QPainter, rect: QtCore.QRectF) -> None:
        p.setPen(self._pen)

        if self._orient_v == 'bottom':
            lp, rp = rect.topLeft(), rect.topRight()
            # p.drawLine(rect.topLeft(), rect.topRight())
        elif self._orient_v == 'top':
            lp, rp = rect.bottomLeft(), rect.bottomRight()

        p.drawLine(lp.x(), lp.y(), rp.x(), rp.y())
Ejemplo n.º 8
0
def qgraphicsview_map_rect_from_scene(view: QGraphicsView,
                                      rect: QRectF) -> QPolygonF:
    """Like QGraphicsView.mapFromScene(QRectF) but returning a QPolygonF
    (without rounding).
    """
    tr = view.viewportTransform()
    p1 = tr.map(rect.topLeft())
    p2 = tr.map(rect.topRight())
    p3 = tr.map(rect.bottomRight())
    p4 = tr.map(rect.bottomLeft())
    return QPolygonF([p1, p2, p3, p4])
Ejemplo n.º 9
0
def get_sides_of(rect: QRectF):
    """
    This method returns the sides of a rect as a dictionary.
    Parameters
    ----------
    rect : QRectF
        The rect to inspect.
    Returns
    ----------
    dict
        A container of the sides represented as QLineF
        objects and their position as a key.

    """

    return {
        "top": QLineF(rect.topLeft(), rect.topRight()),
        "right": QLineF(rect.topRight(), rect.bottomRight()),
        "bottom": QLineF(rect.bottomLeft(), rect.bottomRight()),
        "left": QLineF(rect.bottomLeft(), rect.topLeft())
    }
Ejemplo n.º 10
0
class MapObjectOutline(QGraphicsItem):

    def __init__(self, object, parent = None):
        super().__init__(parent)
        
        self.mObject = object
        self.mBoundingRect = QRectF()
        self.setZValue(1) # makes sure outlines are above labels
    
    def syncWithMapObject(self, renderer):
        pixelPos = renderer.pixelToScreenCoords_(self.mObject.position())
        bounds = objectBounds(self.mObject, renderer)
        bounds.translate(-pixelPos)
        self.setPos(pixelPos + self.mObject.objectGroup().offset())
        self.setRotation(self.mObject.rotation())
        if (self.mBoundingRect != bounds):
            self.prepareGeometryChange()
            self.mBoundingRect = bounds

    def boundingRect(self):
        return self.mBoundingRect
    
    def paint(self, painter, arg2, arg3):
        horizontal = [
            QLineF(self.mBoundingRect.topRight(), self.mBoundingRect.topLeft()), 
            QLineF(self.mBoundingRect.bottomRight(), self.mBoundingRect.bottomLeft())]
        
        vertical = [
            QLineF(self.mBoundingRect.bottomLeft(), self.mBoundingRect.topLeft()), 
            QLineF(self.mBoundingRect.bottomRight(), self.mBoundingRect.topRight())]
        
        dashPen = QPen(Qt.DashLine)
        dashPen.setCosmetic(True)
        dashPen.setDashOffset(max(0.0, self.x()))
        painter.setPen(dashPen)
        painter.drawLines(horizontal)
        dashPen.setDashOffset(max(0.0, self.y()))
        painter.setPen(dashPen)
        painter.drawLines(vertical)
Ejemplo n.º 11
0
 def paint(self, painter, option, widget):
     # Main rectangle
     rectangle = QRectF(
         self._bounding_box.topLeft().x(),
         self._bounding_box.topLeft().y() +
         self._bounding_box.height() * 0.1,
         self._bounding_box.width() - self._bounding_box.height() * 0.1,
         self._bounding_box.height() - self._bounding_box.height() * 0.1)
     painter.drawRect(rectangle)
     # Top line
     painter.drawLine(
         rectangle.topLeft().x() + self._bounding_box.height() * 0.1,
         self._bounding_box.topLeft().y(),
         self._bounding_box.topRight().x(),
         self._bounding_box.topRight().y())
     # Top left corner
     painter.drawLine(
         rectangle.topLeft().x() + self._bounding_box.height() * 0.1,
         self._bounding_box.topLeft().y(),
         self._bounding_box.topLeft().x() + 1,
         rectangle.topLeft().y())
     # Top right corner
     painter.drawLine(self._bounding_box.topRight().x(),
                      self._bounding_box.topRight().y(),
                      rectangle.topRight().x(),
                      rectangle.topRight().y())
     # Bottom right corner
     painter.drawLine(
         rectangle.bottomRight().x() + 1,
         rectangle.bottomRight().y() - 1,
         self._bounding_box.bottomRight().x(),
         rectangle.bottomRight().y() - self._bounding_box.height() * 0.1)
     # Right line
     painter.drawLine(
         self._bounding_box.topRight().x(),
         self._bounding_box.topRight().y(),
         self._bounding_box.topRight().x(),
         self._bounding_box.bottomRight().y() -
         self._bounding_box.height() * 0.1)
Ejemplo n.º 12
0
class RoundRectItem(QGraphicsObject):
    def __init__(self, bounds, color, parent=None):
        super(RoundRectItem, self).__init__(parent)

        self.fillRect = False
        self.bounds = QRectF(bounds)
        self.pix = QPixmap()

        self.gradient = QLinearGradient()
        self.gradient.setStart(self.bounds.topLeft())
        self.gradient.setFinalStop(self.bounds.bottomRight())
        self.gradient.setColorAt(0, color)
        self.gradient.setColorAt(1, color.darker(200))

        self.setCacheMode(QGraphicsItem.ItemCoordinateCache)

    def setFill(self, fill):
        self.fillRect = fill
        self.update()

    def fill(self):
        return self.fillRect

    fill = pyqtProperty(bool, fill, setFill)

    def paint(self, painter, option, widget):
        painter.setPen(Qt.NoPen)
        painter.setBrush(QColor(0, 0, 0, 64))
        painter.drawRoundedRect(self.bounds.translated(2, 2), 25.0, 25.0)

        if self.fillRect:
            painter.setBrush(QApplication.palette().brush(QPalette.Window))
        else:
            painter.setBrush(self.gradient)

        painter.setPen(QPen(Qt.black, 1))
        painter.drawRoundedRect(self.bounds, 25.0, 25.0)
        if not self.pix.isNull():
            painter.scale(1.95, 1.95)
            painter.drawPixmap(-self.pix.width() / 2, -self.pix.height() / 2,
                               self.pix)

    def boundingRect(self):
        return self.bounds.adjusted(0, 0, 2, 2)

    def pixmap(self):
        return QPixmap(self.pix)

    def setPixmap(self, pixmap):
        self.pix = QPixmap(pixmap)
        self.update()
Ejemplo n.º 13
0
class RoundRectItem(QGraphicsObject):
    def __init__(self, bounds, color, parent=None):
        super(RoundRectItem, self).__init__(parent)

        self.fillRect = False
        self.bounds = QRectF(bounds)
        self.pix = QPixmap()

        self.gradient = QLinearGradient()
        self.gradient.setStart(self.bounds.topLeft())
        self.gradient.setFinalStop(self.bounds.bottomRight())
        self.gradient.setColorAt(0, color)
        self.gradient.setColorAt(1, color.darker(200))

        self.setCacheMode(QGraphicsItem.ItemCoordinateCache)

    def setFill(self, fill):
        self.fillRect = fill
        self.update()

    def fill(self):
        return self.fillRect

    fill = pyqtProperty(bool, fill, setFill)

    def paint(self, painter, option, widget):
        painter.setPen(Qt.NoPen)
        painter.setBrush(QColor(0, 0, 0, 64))
        painter.drawRoundedRect(self.bounds.translated(2, 2), 25.0, 25.0)

        if self.fillRect:
            painter.setBrush(QApplication.palette().brush(QPalette.Window))
        else:
            painter.setBrush(self.gradient)

        painter.setPen(QPen(Qt.black, 1))
        painter.drawRoundedRect(self.bounds, 25.0, 25.0)
        if not self.pix.isNull():
            painter.scale(1.95, 1.95)
            painter.drawPixmap(-self.pix.width() / 2, -self.pix.height() / 2, self.pix)

    def boundingRect(self):
        return self.bounds.adjusted(0, 0, 2, 2)

    def pixmap(self):
        return QPixmap(self.pix)

    def setPixmap(self, pixmap):
        self.pix = QPixmap(pixmap)
        self.update()
Ejemplo n.º 14
0
    def paintEvent(self, event: QPaintEvent):
        bar = self._bar
        if bar.isVisible():
            painter = QPainter(self)

            rect = bar.rect().adjusted(0, 0, 1, 0)
            rect = self.style().visualRect(self.layoutDirection(),
                                           self.geometry(), rect)
            boderRect = QRectF(rect).adjusted(0.5, 0.5, -0.5, -0.5)

            if not FLAT_STYLE:
                verticalGradient(painter, rect, rect)

            painter.setPen(BORDER_COLOR)
            painter.drawLine(boderRect.topRight(), boderRect.bottomRight())
    def draw_boat(self, x, y):
        # width and height of the boat
        boat_w = Settings.WIDTH * 0.75
        boat_h = Settings.HEIGHT * 0.75

        # create boat
        boat = QRectF(x * Settings.WIDTH, y * Settings.HEIGHT, boat_w, boat_h)

        # set gradient
        gradient = QLinearGradient(boat.topLeft(), boat.bottomRight())
        gradient.setColorAt(1, QColor(50, 175, 255, 150))
        gradient.setColorAt(0, QColor(0, 50, 200, 100))

        # add boat
        self.addEllipse(boat, Qt.black, gradient)
Ejemplo n.º 16
0
    def testIntersects(self):
        """

        """

        rect = QRectF(QPointF(-50, -10), QPointF(50, 10))
        # line completely outside of the rectangle
        self.assertFalse(PathFinding.intersects(rect, QLineF(QPointF(-100, -50), QPointF(-100, 50))))
        # the line is a top side of the rectangle
        self.assertFalse(PathFinding.intersects(rect, QLineF(rect.topLeft(), rect.topRight())))
        # the line starts at the left corner of the rectangle and is not perpendicular to any of the rectangle sides;
        # the line ends outside of the rectangle, not going through it
        self.assertFalse(PathFinding.intersects(rect, QLineF(rect.topLeft(), QPointF(-100, -100))))
        # the line starts at the left corner of the rectangle and is perpendicular to the top side of the rectangle;
        # the line ends outside of the rectangle, not going through it
        self.assertFalse(PathFinding.intersects(rect, QLineF(rect.topLeft(), QPointF(rect.left(), rect.top() - 100))))
        # the line is horizontal and goes straight through the center of the rectangle
        self.assertTrue(PathFinding.intersects(rect, QLineF(QPointF(-100, 0), QPointF(100, 0))))
        # the line is vertical and goes straight through the center of the rectangle
        self.assertTrue(PathFinding.intersects(rect, QLineF(QPointF(0, -100), QPointF(0, 100))))
        # the line is vertical and goes up from the bottom right corner of the rectangle
        self.assertFalse(PathFinding.intersects(rect, QLineF(rect.bottomRight(), QPointF(rect.right(), rect.top()-100))))
        # the line is diagonal of the rectangle
        self.assertTrue(PathFinding.intersects(rect, QLineF(rect.topLeft(), rect.bottomRight())))
Ejemplo n.º 17
0
    def getLinePoint(self, end):
        #rect = QRectF(self.pos(), QPoint(self.pos().x()+120, self.pos().y()+60))
        rect = QRectF(self.pos(), QSizeF(120, 60))
        #calculate center points
        left = QPointF(rect.topLeft().x(), rect.center().y())
        right = QPointF(rect.bottomRight().x(), rect.center().y())
        top = QPointF(rect.center().x(), rect.topLeft().y())
        bottom = QPointF(rect.center().x(), rect.bottomRight().y())

        if rect.topLeft().x() < end.x():
            #point is not left from rect
            if rect.bottomRight().x() < end.x():
                y1 = GeoHelper.getY(-1,
                                    rect.bottomRight().x(),
                                    rect.topLeft().y(), end.x())
                if end.y() < y1:
                    return "top", top
                y1 = GeoHelper.getY(1,
                                    rect.bottomRight().x(),
                                    rect.bottomRight().y(), end.x())
                if end.y() < y1:
                    return "right", right
                return "bottom", bottom
            elif rect.center().y() < end.y():
                return "bottom", bottom
            else:
                return "top", top
        else:
            #point is left from rect
            y1 = GeoHelper.getY(1,
                                rect.topLeft().x(),
                                rect.topLeft().y(), end.x())
            if end.y() < y1:
                return "top", top
            y1 = GeoHelper.getY(-1,
                                rect.topLeft().x(),
                                rect.bottomRight().y(), end.x())
            if end.y() < y1:
                return "left", left
            return "bottom", bottom
Ejemplo n.º 18
0
class PathNucleicAcidPartItem(QAbstractPartItem):
    """Summary

    Attributes:
        active_virtual_helix_item (cadnano.views.pathview.virtualhelixitem.VirtualHelixItem): Description
        findChild (TYPE): Description
        grab_corner (TYPE): Description
        prexover_manager (TYPE): Description
    """
    findChild = util.findChild  # for debug
    _BOUNDING_RECT_PADDING = 20
    _GC_SIZE = 10

    def __init__(self, model_part_instance, viewroot, parent):
        """parent should always be pathrootitem

        Args:
            model_part_instance (TYPE): Description
            viewroot (TYPE): Description
            parent (TYPE): Description
        """
        super(PathNucleicAcidPartItem, self).__init__(model_part_instance,
                                                      viewroot, parent)
        self.setAcceptHoverEvents(True)

        self._getActiveTool = viewroot.manager.activeToolGetter
        self.active_virtual_helix_item = None
        m_p = self._model_part
        self._controller = NucleicAcidPartItemController(self, m_p)
        self.prexover_manager = PreXoverManager(self)
        self._virtual_helix_item_list = []
        self._initModifierRect()
        self._proxy_parent = ProxyParentItem(self)
        self._proxy_parent.setFlag(QGraphicsItem.ItemHasNoContents)
        self._scale_2_model = m_p.baseWidth() / _BASE_WIDTH
        self._scale_2_Qt = _BASE_WIDTH / m_p.baseWidth()

        # self._rect = QRectF()
        self._vh_rect = QRectF()
        # self.setPen(getPenObj(styles.ORANGE_STROKE, 0))
        self.setPen(getNoPen())
        # self.setRect(self._rect)

        self.outline = outline = PathRectItem(self)
        outline.setFlag(QGraphicsItem.ItemStacksBehindParent)
        self.setZValue(styles.ZPART)
        self._proxy_parent.setZValue(styles.ZPART)
        outline.setZValue(styles.ZDESELECTOR)
        self.outline.setPen(getPenObj(m_p.getColor(), _DEFAULT_WIDTH))
        o_rect = self._configureOutline(outline)
        model_color = m_p.getColor()

        self.resize_handle_group = ResizeHandleGroup(
            o_rect,
            _HANDLE_SIZE,
            model_color,
            True,
            # HandleType.LEFT |
            HandleType.RIGHT,
            self)

        self.model_bounds_hint = m_b_h = QGraphicsRectItem(self)
        m_b_h.setBrush(getBrushObj(styles.BLUE_FILL, alpha=32))
        m_b_h.setPen(getNoPen())
        m_b_h.hide()

        self.workplane = PathWorkplaneItem(m_p, self)
        self.hide()  # show on adding first vh

    # end def

    def proxy(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self._proxy_parent

    # end def

    def modelColor(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self._model_part.getProperty('color')

    # end def

    def convertToModelZ(self, z):
        """scale Z-axis coordinate to the model

        Args:
            z (TYPE): Description
        """
        return z * self._scale_2_model

    # end def

    def convertToQtZ(self, z):
        """Summary

        Args:
            z (TYPE): Description

        Returns:
            TYPE: Description
        """
        return z * self._scale_2_Qt

    # end def

    def _initModifierRect(self):
        """docstring for _initModifierRect
        """
        self._can_show_mod_rect = False
        self._mod_rect = m_r = QGraphicsRectItem(_DEFAULT_RECT, self)
        m_r.setPen(_MOD_PEN)
        m_r.hide()

    # end def

    def vhItemForIdNum(self, id_num):
        """Returns the pathview VirtualHelixItem corresponding to id_num

        Args:
            id_num (int): VirtualHelix ID number. See `NucleicAcidPart` for description and related methods.
        """
        return self._virtual_helix_item_hash.get(id_num)

    ### SIGNALS ###

    ### SLOTS ###
    def partActiveVirtualHelixChangedSlot(self, part, id_num):
        """Summary

        Args:
            part (TYPE): Description
            id_num (int): VirtualHelix ID number. See `NucleicAcidPart` for description and related methods.

        Returns:
            TYPE: Description
        """
        vhi = self._virtual_helix_item_hash.get(id_num, None)
        self.setActiveVirtualHelixItem(vhi)
        self.setPreXoverItemsVisible(vhi)

    # end def

    def partActiveBaseInfoSlot(self, part, info):
        """Summary

        Args:
            part (TYPE): Description
            info (TYPE): Description

        Returns:
            TYPE: Description
        """
        pxi_m = self.prexover_manager
        pxi_m.deactivateNeighbors()
        if info and info is not None:
            id_num, is_fwd, idx, to_vh_id_num = info
            pxi_m.activateNeighbors(id_num, is_fwd, idx)

    # end def

    def partZDimensionsChangedSlot(self,
                                   model_part,
                                   min_id_num,
                                   max_id_num,
                                   ztf=False):
        """Summary

        Args:
            model_part (Part): The model part
            min_id_num (TYPE): Description
            max_id_num (TYPE): Description
            ztf (bool, optional): Description

        Returns:
            TYPE: Description
        """
        if len(self._virtual_helix_item_list) > 0:
            vhi_hash = self._virtual_helix_item_hash
            vhi_max = vhi_hash[max_id_num]
            vhi_rect_max = vhi_max.boundingRect()
            self._vh_rect.setRight(vhi_rect_max.right() + vhi_max.x())

            vhi_min = vhi_hash[min_id_num]
            vhi_h_rect = vhi_min.handle().boundingRect()
            self._vh_rect.setLeft(
                (vhi_h_rect.left() - styles.VH_XOFFSET + vhi_min.x()))
        if ztf:
            self.scene().views()[0].zoomToFit()

        TLx, TLy, BRx, BRy = self._getVHRectCorners()
        self.reconfigureRect((TLx, TLy), (BRx, BRy))

    # end def

    def partSelectedChangedSlot(self, model_part, is_selected):
        """Summary

        Args:
            model_part (Part): The model part
            is_selected (TYPE): Description

        Returns:
            TYPE: Description
        """
        # print("partSelectedChangedSlot", is_selected)
        if is_selected:
            self.resetPen(styles.SELECTED_COLOR, styles.SELECTED_PEN_WIDTH)
            self.resetBrush(styles.SELECTED_BRUSH_COLOR, styles.SELECTED_ALPHA)
        else:
            self.resetPen(self.modelColor())
            self.resetBrush(styles.DEFAULT_BRUSH_COLOR, styles.DEFAULT_ALPHA)

    def partPropertyChangedSlot(self, model_part, property_key, new_value):
        """Summary

        Args:
            model_part (Part): The model part
            property_key (TYPE): Description
            new_value (TYPE): Description

        Returns:
            TYPE: Description
        """
        if self._model_part == model_part:
            self._model_props[property_key] = new_value
            if property_key == 'color':
                for vhi in self._virtual_helix_item_list:
                    vhi.handle().refreshColor()
                # self.workplane.outline.setPen(getPenObj(new_value, 0))
                TLx, TLy, BRx, BRy = self._getVHRectCorners()
                self.reconfigureRect((TLx, TLy), (BRx, BRy))
            elif property_key == 'is_visible':
                if new_value:
                    self.show()
                else:
                    self.hide()
            elif property_key == 'virtual_helix_order':
                vhi_dict = self._virtual_helix_item_hash
                new_list = [vhi_dict[id_num] for id_num in new_value]
                ztf = False
                self._setVirtualHelixItemList(new_list, zoom_to_fit=ztf)
            elif property_key == 'workplane_idxs':
                if hasattr(self, 'workplane'):
                    self.workplane.setIdxs(new_idxs=new_value)

    # end def

    def partVirtualHelicesTranslatedSlot(self, sender, vh_set, left_overs,
                                         do_deselect):
        """Summary

        Args:
            sender (obj): Model object that emitted the signal.
            vh_set (TYPE): Description
            left_overs (TYPE): Description
            do_deselect (TYPE): Description

        Returns:
            TYPE: Description
        """
        # self.prexover_manager.clearPreXoverItems()
        # if self.active_virtual_helix_item is not None:
        #     self.active_virtual_helix_item.deactivate()
        #     self.active_virtual_helix_item = None

        # if self.active_virtual_helix_item is not None:
        #     self.setPreXoverItemsVisible(self.active_virtual_helix_item)
        pass

    # end def

    def partRemovedSlot(self, sender):
        """docstring for partRemovedSlot

        Args:
            sender (obj): Model object that emitted the signal.
        """
        self.parentItem().removePartItem(self)
        scene = self.scene()
        scene.removeItem(self)
        self._model_part = None
        self._virtual_helix_item_hash = None
        self._virtual_helix_item_list = None
        self._controller.disconnectSignals()
        self._controller = None
        # self.grab_corner = None

    # end def

    def partVirtualHelixAddedSlot(self, model_part, id_num, virtual_helix,
                                  neighbors):
        """
        When a virtual helix is added to the model, this slot handles
        the instantiation of a virtualhelix item.

        Args:
            model_part (Part): The model part
            id_num (int): VirtualHelix ID number. See `NucleicAcidPart` for description and related methods.
        """
        # print("NucleicAcidPartItem.partVirtualHelixAddedSlot")
        vhi = PathVirtualHelixItem(virtual_helix, self, self._viewroot)
        self._virtual_helix_item_hash[id_num] = vhi
        vhi_list = self._virtual_helix_item_list
        vhi_list.append(vhi)
        ztf = not getBatch()
        self._setVirtualHelixItemList(vhi_list, zoom_to_fit=ztf)
        if not self.isVisible():
            self.show()

    # end def

    def partVirtualHelixResizedSlot(self, sender, id_num, virtual_helix):
        """Notifies the virtualhelix at coord to resize.

        Args:
            sender (obj): Model object that emitted the signal.
            id_num (int): VirtualHelix ID number. See `NucleicAcidPart` for description and related methods.
        """
        vhi = self._virtual_helix_item_hash[id_num]
        # print("resize:", id_num, virtual_helix.getSize())
        vhi.resize()

    # end def

    def partVirtualHelixRemovingSlot(self, sender, id_num, virtual_helix,
                                     neighbors):
        """Summary

        Args:
            sender (obj): Model object that emitted the signal.
            id_num (int): VirtualHelix ID number. See `NucleicAcidPart` for description and related methods.

        Returns:
            TYPE: Description
        """
        self.removeVirtualHelixItem(id_num)

    # end def

    def partVirtualHelixRemovedSlot(self, sender, id_num):
        """ Step 2 of removing a VHI
        """
        ztf = not getBatch()
        self._setVirtualHelixItemList(self._virtual_helix_item_list,
                                      zoom_to_fit=ztf)
        if len(self._virtual_helix_item_list) == 0:
            self.hide()
        self.reconfigureRect((), ())

    # end def

    def partVirtualHelixPropertyChangedSlot(self, sender, id_num,
                                            virtual_helix, keys, values):
        """Summary

        Args:
            sender (obj): Model object that emitted the signal.
            id_num (int): VirtualHelix ID number. See `NucleicAcidPart` for description and related methods.
            keys (TYPE): Description
            values (TYPE): Description

        Returns:
            TYPE: Description
        """
        if self._model_part == sender:
            vh_i = self._virtual_helix_item_hash[id_num]
            vh_i.virtualHelixPropertyChangedSlot(keys, values)

    # end def

    def partVirtualHelicesSelectedSlot(self, sender, vh_set, is_adding):
        """is_adding (bool): adding (True) virtual helices to a selection
        or removing (False)

        Args:
            sender (obj): Model object that emitted the signal.
            vh_set (TYPE): Description
            is_adding (TYPE): Description
        """
        vhhi_group = self._viewroot.vhiHandleSelectionGroup()
        vh_hash = self._virtual_helix_item_hash
        doc = self._viewroot.document()
        if is_adding:
            # print("got the adding slot in path")
            for id_num in vh_set:
                vhi = vh_hash[id_num]
                vhhi = vhi.handle()
                vhhi.modelSelect(doc)
            # end for
            vhhi_group.processPendingToAddList()
        else:
            # print("got the removing slot in path")
            for id_num in vh_set:
                vhi = vh_hash[id_num]
                vhhi = vhi.handle()
                vhhi.modelDeselect(doc)
            # end for
            vhhi_group.processPendingToAddList()

    # end def

    ### ACCESSORS ###
    def removeVirtualHelixItem(self, id_num):
        """Summary

        Args:
            id_num (int): VirtualHelix ID number. See `NucleicAcidPart` for description and related methods.

        Returns:
            TYPE: Description
        """
        self.setActiveVirtualHelixItem(None)
        vhi = self._virtual_helix_item_hash[id_num]
        vhi.virtualHelixRemovedSlot()
        self._virtual_helix_item_list.remove(vhi)
        del self._virtual_helix_item_hash[id_num]

    # end def

    def window(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self.parentItem().window()

    # end def

    ### PRIVATE METHODS ###
    def _configureOutline(self, outline):
        """Adjusts `outline` size with default padding.

        Args:
            outline (TYPE): Description

        Returns:
            o_rect (QRect): `outline` rect adjusted by _BOUNDING_RECT_PADDING
        """
        _p = self._BOUNDING_RECT_PADDING
        o_rect = self.rect().adjusted(-_p, -_p, _p, _p)
        outline.setRect(o_rect)
        return o_rect

    # end def

    def _getVHRectCorners(self):
        vhTL = self._vh_rect.topLeft()
        vhBR = self._vh_rect.bottomRight()
        # vhTLx, vhTLy = vhTL.x(), vhTL.y()
        # vhBRx, vhBRy = vhBR.x(), vhBR.y()
        return vhTL.x(), vhTL.y(), vhBR.x(), vhBR.y()

    # end def

    def _setVirtualHelixItemList(self, new_list, zoom_to_fit=True):
        """
        Give me a list of VirtualHelixItems and I'll parent them to myself if
        necessary, position them in a column, adopt their handles, and
        position them as well.

        Args:
            new_list (TYPE): Description
            zoom_to_fit (bool, optional): Description
        """
        y = 0  # How far down from the top the next PH should be
        vhi_rect = None
        vhi_h_rect = None
        vhi_h_selection_group = self._viewroot.vhiHandleSelectionGroup()
        for vhi in new_list:
            _, _, _z = vhi.cnModel().getAxisPoint(0)
            _z *= self._scale_2_Qt
            vhi.setPos(_z, y)
            if vhi_rect is None:
                vhi_rect = vhi.boundingRect()
                step = vhi_rect.height() + styles.PATH_HELIX_PADDING
            # end if

            # get the VirtualHelixHandleItem
            vhi_h = vhi.handle()
            do_reselect = False
            if vhi_h.parentItem() == vhi_h_selection_group:
                do_reselect = True

            vhi_h.tempReparent()  # so positioning works

            if vhi_h_rect is None:
                vhi_h_rect = vhi_h.boundingRect()

            vhi_h_x = _z - _VH_XOFFSET
            vhi_h_y = y + (vhi_rect.height() - vhi_h_rect.height()) / 2
            vhi_h.setPos(vhi_h_x, vhi_h_y)

            y += step
            self.updateXoverItems(vhi)
            if do_reselect:
                vhi_h_selection_group.addToGroup(vhi_h)
        # end for
        # this need only adjust top and bottom edges of the bounding rectangle
        # self._vh_rect.setTop()
        self._vh_rect.setBottom(y)
        self._virtual_helix_item_list = new_list

        # now update Z dimension (X in Qt space in the Path view)
        part = self.part()
        self.partZDimensionsChangedSlot(part,
                                        *part.zBoundsIds(),
                                        ztf=zoom_to_fit)

    # end def

    def resetPen(self, color, width=0):
        """Summary

        Args:
            color (TYPE): Description
            width (int, optional): Description

        Returns:
            TYPE: Description
        """
        pen = getPenObj(color, width)
        self.outline.setPen(pen)
        # self.setPen(pen)

    # end def

    def resetBrush(self, color, alpha):
        """Summary

        Args:
            color (TYPE): Description
            alpha (TYPE): Description

        Returns:
            TYPE: Description
        """
        brush = getBrushObj(color, alpha=alpha)
        self.setBrush(brush)

    # end def

    def reconfigureRect(self,
                        top_left,
                        bottom_right,
                        finish=False,
                        padding=80):
        """
        Updates the bounding rect to the size of the childrenBoundingRect.
        Refreshes the outline and grab_corner locations.

        Called by partZDimensionsChangedSlot and partPropertyChangedSlot.
        """
        outline = self.outline

        hasTL = True if top_left else False
        hasBR = True if bottom_right else False

        if hasTL ^ hasBR:  # called via resizeHandle mouseMove?
            ptTL = QPointF(*top_left) if top_left else outline.rect().topLeft()
            ptBR = QPointF(*bottom_right) if bottom_right else outline.rect(
            ).bottomRight()
            o_rect = QRectF(ptTL, ptBR)
            pad_xoffset = self._BOUNDING_RECT_PADDING * 2
            new_size = int(
                (o_rect.width() - _VH_XOFFSET - pad_xoffset) / _BASE_WIDTH)
            substep = self._model_part.subStepSize()
            snap_size = new_size - new_size % substep
            snap_offset = -(new_size % substep) * _BASE_WIDTH
            self.resize_handle_group.updateText(HandleType.RIGHT, snap_size)
            if finish:
                self._model_part.setAllVirtualHelixSizes(snap_size)
                o_rect = o_rect.adjusted(0, 0, snap_offset, 0)
                # print("finish", vh_size, new_size, substep, snap_size)
            self.outline.setRect(o_rect)
        else:
            # 1. Temporarily remove children that shouldn't affect size
            outline.setParentItem(None)
            self.workplane.setParentItem(None)
            self.model_bounds_hint.setParentItem(None)
            self.resize_handle_group.setParentItemAll(None)
            self.prexover_manager.setParentItem(None)
            # 2. Get the tight bounding rect
            self.setRect(self.childrenBoundingRect())  # vh_items only
            # 3. Restore children like nothing happened
            outline.setParentItem(self)
            self.workplane.setParentItem(self)
            self.model_bounds_hint.setParentItem(self)
            self.resize_handle_group.setParentItemAll(self)
            self.prexover_manager.setParentItem(self)
            self._configureOutline(outline)

        self.resetPen(self.modelColor(), 0)  # cosmetic
        self.resetBrush(styles.DEFAULT_BRUSH_COLOR, styles.DEFAULT_ALPHA)
        self.workplane.reconfigureRect((), ())
        self.resize_handle_group.alignHandles(outline.rect())
        return outline.rect()

    # end def

    ### PUBLIC METHODS ###
    def getModelMinBounds(self, handle_type=None):
        """Bounds in form of Qt scaled from model
        Absolute min should be 2*stepsize.
        Round up from indexOfRightmostNonemptyBase to nearest substep.

        Returns:
            Tuple (xTL, yTL, xBR, yBR)
        """
        _p = self._BOUNDING_RECT_PADDING
        default_idx = self._model_part.stepSize() * 2
        nonempty_idx = self._model_part.indexOfRightmostNonemptyBase()
        right_bound_idx = max(default_idx, nonempty_idx)
        substep = self._model_part.subStepSize()
        snap_idx = (right_bound_idx / substep) * substep
        xTL = 0
        xBR = snap_idx * _BASE_WIDTH + _p
        min_rect = self.rect().adjusted(-_p, -_p, _p, _p)
        yTL = min_rect.top()
        yBR = min_rect.bottom()
        return xTL, yTL, xBR, yBR

    # end def

    def showModelMinBoundsHint(self, handle_type, show=True):
        """Shows QGraphicsRectItem reflecting current model bounds.
        ResizeHandleGroup should toggle this when resizing.

        Args:
            status_str (str): Description to display in status bar.
        """
        m_b_h = self.model_bounds_hint
        if show:
            xTL, yTL, xBR, yBR = self.getModelMinBounds()
            m_b_h.setRect(QRectF(QPointF(xTL, yTL), QPointF(xBR, yBR)))
            m_b_h.show()
        else:
            m_b_h.hide()

    # end def

    def setModifyState(self, bool):
        """Hides the modRect when modify state disabled.

        Args:
            bool (TYPE): Description
        """
        self._can_show_mod_rect = bool
        if bool is False:
            self._mod_rect.hide()

    def getOrderedVirtualHelixList(self):
        """Used for encoding.
        """
        ret = []
        for vhi in self._virtual_helix_item_list:
            ret.append(vhi.coord())
        return ret

    # end def

    def reorderHelices(self, id_nums, index_delta):
        """
        Reorder helices by moving helices _pathHelixList[first:last]
        by a distance delta in the list. Notify each PathHelix and
        PathHelixHandle of its new location.

        Args:
            first (TYPE): Description
            last (TYPE): Description
            index_delta (TYPE): Description
        """
        vhi_list = self._virtual_helix_item_list
        helix_numbers = [vhi.idNum() for vhi in vhi_list]

        first_index = helix_numbers.index(id_nums[0])
        last_index = helix_numbers.index(id_nums[-1]) + 1

        for id_num in id_nums:
            helix_numbers.remove(id_num)

        if index_delta < 0:  # move group earlier in the list
            new_index = max(0, index_delta + first_index) - len(id_nums)
        else:  # move group later in list
            new_index = min(len(vhi_list),
                            index_delta + last_index) - len(id_nums)
        new_list = helix_numbers[:new_index] + id_nums + helix_numbers[
            new_index:]
        # call the method to move the items and store the list
        self._model_part.setImportedVHelixOrder(new_list, check_batch=False)

    # end def

    def setActiveVirtualHelixItem(self, new_active_vhi):
        """Summary

        Args:
            new_active_vhi (TYPE): Description

        Returns:
            TYPE: Description
        """
        current_vhi = self.active_virtual_helix_item
        if new_active_vhi != current_vhi:
            if current_vhi is not None:
                current_vhi.deactivate()
            if new_active_vhi is not None:
                new_active_vhi.activate()
            self.active_virtual_helix_item = new_active_vhi

    # end def

    def unsetActiveVirtualHelixItem(self):
        if self.active_virtual_helix_item is not None:
            self.active_virtual_helix_item.deactivate()
            self.active_virtual_helix_item = None
        self.prexover_manager.reset()

    def setPreXoverItemsVisible(self, virtual_helix_item):
        """
        self._pre_xover_items list references prexovers parented to other
        PathHelices such that only the activeHelix maintains the list of
        visible prexovers

        Args:
            virtual_helix_item (cadnano.views.pathview.virtualhelixitem.VirtualHelixItem): Description
        """
        vhi = virtual_helix_item

        if vhi is None:
            return

        # print("path.setPreXoverItemsVisible", virtual_helix_item.idNum())
        part = self.part()
        info = part.active_base_info
        if info and virtual_helix_item is not None:
            id_num, is_fwd, idx, to_vh_id_num = info
            per_neighbor_hits, pairs = part.potentialCrossoverMap(id_num, idx)
            self.prexover_manager.activateVirtualHelix(virtual_helix_item, idx,
                                                       per_neighbor_hits)
        else:
            self.prexover_manager.reset()

    # end def

    def updateXoverItems(self, virtual_helix_item):
        """Summary

        Args:
            virtual_helix_item (cadnano.views.pathview.virtualhelixitem.VirtualHelixItem): Description

        Returns:
            TYPE: Description
        """
        for item in virtual_helix_item.childItems():
            if isinstance(item, XoverNode3):
                item.refreshXover()

    # end def

    def updateStatusBar(self, status_string):
        """Shows status_string in the MainWindow's status bar.

        Args:
            status_string (str): The text to be displayed.
        """
        self.window().statusBar().showMessage(status_string)

    ### COORDINATE METHODS ###
    def keyPanDeltaX(self):
        """How far a single press of the left or right arrow key should move
        the scene (in scene space)
        """
        vhs = self._virtual_helix_item_list
        return vhs[0].keyPanDeltaX() if vhs else 5

    # end def

    def keyPanDeltaY(self):
        """How far an an arrow key should move the scene (in scene space)
        for a single press
        """
        vhs = self._virtual_helix_item_list
        if not len(vhs) > 1:
            return 5
        dy = vhs[0].pos().y() - vhs[1].pos().y()
        dummyRect = QRectF(0, 0, 1, dy)
        return self.mapToScene(dummyRect).boundingRect().height()

    # end def

    ### TOOL METHODS ###
    def mousePressEvent(self, event):
        """Handler for user mouse press.

        Args:
            event (:obj:`QGraphicsSceneMouseEvent`): Contains item, scene, and screen
            coordinates of the the event, and previous event.
        """
        self._viewroot.clearSelectionsIfActiveTool()
        self.unsetActiveVirtualHelixItem()

        return QGraphicsItem.mousePressEvent(self, event)

    def hoverMoveEvent(self, event):
        """
        Parses a mouseMoveEvent to extract strandSet and base index,
        forwarding them to approproate tool method as necessary.

        Args:
            event (TYPE): Description
        """
        active_tool = self._getActiveTool()
        tool_method_name = active_tool.methodPrefix() + "HoverMove"
        if hasattr(self, tool_method_name):
            getattr(self, tool_method_name)(event.pos())

    # end def

    def createToolHoverMove(self, pt):
        """Create the strand is possible.

        Args:
            pt (QPointF): mouse cursor location of create tool hover.
        """
        active_tool = self._getActiveTool()
        if not active_tool.isFloatingXoverBegin():
            temp_xover = active_tool.floatingXover()
            temp_xover.updateFloatingFromPartItem(self, pt)
Ejemplo n.º 19
0
class RoundRectItem(QGraphicsObject):
    """Base class for most graphic objects in our scene"""
    def __init__(self, bounds, color=None, parent=None):
        """
        Args:
            bounds - QRectF, geometry of object
            color - QColor or None
            parent - widget to contain this graphic item or None
        """
        super(RoundRectItem, self).__init__(parent)

        self._fillRect = False
        self._bounds = QRectF(bounds)
        self._pix = QPixmap()
        self._color = color

        self.setCacheMode(QGraphicsItem.ItemCoordinateCache)

    def setFill(self, fill: bool):
        """
        Changes the property of how the cell is filled.

        Args:
          fill: bool
        """
        self._fillRect = fill
        self.update()

    @property
    def _gradient(self):
        gradient = QLinearGradient()
        gradient.setStart(
            (self._bounds.topLeft() + self._bounds.topRight()) / 2)
        gradient.setFinalStop(
            (self._bounds.bottomLeft() + self._bounds.bottomRight()) / 2)
        gradient.setColorAt(0, self._color)
        gradient.setColorAt(1, self._color.darker(200))
        return gradient

    def paint(self, painter, option, widget):
        """Standard Qt paint event."""
        if self._color:
            painter.setPen(Qt.NoPen)
            painter.setBrush(QColor(0, 0, 0, 64))
            painter.drawRoundedRect(self._bounds.translated(2, 2), 25.0, 25.0)

            if self._fillRect:
                painter.setBrush(QApplication.palette().brush(QPalette.Window))
            else:
                painter.setBrush(self._gradient)

            painter.setPen(QPen(Qt.black, 1))
            painter.drawRoundedRect(self._bounds, 25.0, 25.0)

        if not self._pix.isNull():
            if self._rounded_pixmap:
                painter.setRenderHint(QPainter.Antialiasing, True)
                brush = QBrush(
                    self._pix.scaled(self._bounds.width(),
                                     self._bounds.height()))
                painter.setBrush(brush)
                painter.drawRoundedRect(self._bounds, 25.0, 25.0)
            else:
                painter.scale(self._bounds.width() / self._pix.width(),
                              self._bounds.height() / self._pix.height())
                painter.drawPixmap(-self._pix.width() / 2,
                                   -self._pix.height() / 2, self._pix)

    def boundingRect(self):
        """returns bounding rectangle"""
        return self._bounds.adjusted(0, 0, 2, 2)

    def setPixmap(self, pixmap_path: str, rounded_pixmap=False):
        """
        Sets new pixmap for this graphic object.

        Args:
          pixmap_path: path to image for pixmap
          rounded_pixmap: make the picture rounded (used, e.g., for lava in the cells)
        """
        self._rounded_pixmap = rounded_pixmap
        self._pix = QPixmap(pixmap_path)
        self.update()
Ejemplo n.º 20
0
class JoyPad(QtWidgets.QWidget, IndicatorPosition):
    IndicatorPosition = IndicatorPosition
    Q_ENUM(IndicatorPosition)

    joy_btn_pressed = QtCore.pyqtSignal(str)
    joy_btn_released = QtCore.pyqtSignal(str)
    joy_l_pressed = QtCore.pyqtSignal(bool)
    joy_l_released = QtCore.pyqtSignal(bool)
    joy_r_pressed = QtCore.pyqtSignal(bool)
    joy_r_released = QtCore.pyqtSignal(bool)
    joy_c_pressed = QtCore.pyqtSignal(bool)
    joy_c_released = QtCore.pyqtSignal(bool)
    joy_t_pressed = QtCore.pyqtSignal(bool)
    joy_t_released = QtCore.pyqtSignal(bool)
    joy_b_pressed = QtCore.pyqtSignal(bool)
    joy_b_released = QtCore.pyqtSignal(bool)

    def __init__(self, parent=None):
        super(JoyPad, self).__init__(parent)
        self.rect1 = QRectF()
        self.rect2 = QRectF()
        self.left_image = None
        self.right_image = None
        self.top_image = None
        self.bottom_image = None
        self.center_image = None
        self._dummyPixmap = QtGui.QPixmap()
        self._font = QFont('Lato Heavy', 20)
        self._text_color = QColor('white')
        self._textL = ''
        self._textR = ''
        self._textC = ''
        self._textT = ''
        self._textB = ''
        self.colorState = False
        self._true_color = QColor('lawngreen')
        self._false_color = QColor('gray')
        self.highlight_color = self._false_color
        self._highlightPosition = IndicatorPosition.NONE
        self.highlight_left = False
        self.highlight_right = False
        self.highlight_top = False
        self.highlight_bottom = False
        self.highlight_center = False
        self.last_active_btn = None
        self.setMouseTracking(True)
        self.setToolTipDuration(2000)
        self.installEventFilter(self)
        self.btn_names = {
            'L': 'left',
            'R': 'right',
            'T': 'top',
            'B': 'bottom',
            'C': 'center'
        }
        self.tooltips = {'L': '', 'R': '', 'T': '', 'B': '', 'C': ''}
        self.axis_list = ('X', 'Y', 'Z', 'A')

    def eventFilter(self, obj, event):
        if obj is self and self.isEnabled():
            if event.type() == QEvent.MouseButtonPress:
                if event.button() == Qt.RightButton:
                    event.ignore()
                else:
                    pos = event.localPos()
                    active_btn = self.get_active_btn(pos)
                    self.last_active_btn = active_btn
                    if active_btn is not None:
                        self._pressedOutput(active_btn)
            elif event.type() == QEvent.MouseButtonRelease:
                if event.button() == Qt.RightButton:
                    event.ignore()
                elif self.last_active_btn is not None:
                    self._releasedOutput(self.last_active_btn)
            elif event.type() == QEvent.MouseMove:
                pos = event.pos()
                active_btn = self.get_active_btn(pos)
                if active_btn is not None:
                    self.setToolTip(self.tooltips[active_btn])
        return super(JoyPad, self).eventFilter(obj, event)

    def _pressedOutput(self, btncode):
        self.joy_btn_pressed.emit(btncode)
        self['joy_{}_pressed'.format(btncode.lower())].emit(True)

    def _releasedOutput(self, btncode):
        self.joy_btn_released.emit(btncode)
        self['joy_{}_released'.format(btncode.lower())].emit(False)

    def get_active_btn(self, pos):
        if self.center_path.contains(pos): return 'C'
        elif self.left_path.contains(pos): return 'L'
        elif self.right_path.contains(pos): return 'R'
        elif self.bottom_path.contains(pos): return 'B'
        elif self.top_path.contains(pos): return 'T'
        return None

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(painter.Antialiasing)
        w = min(event.rect().width(), event.rect().height())
        self.rect1.setSize(QSizeF(w * 0.4, w * 0.4))
        self.rect2.setSize(QSizeF(w * 0.9, w * 0.9))
        self.create_paths(painter, event)
        self.draw_painter_paths(painter, event)
        self.draw_icons(painter, event)
        self.draw_highlight(painter, event)
        painter.end()

    def create_paths(self, qp, event):
        self.left_path = QPainterPath()
        self.right_path = QPainterPath()
        self.bottom_path = QPainterPath()
        self.top_path = QPainterPath()
        self.center_path = QPainterPath()
        center = event.rect().center()
        self.rect1.moveCenter(center)
        self.rect2.moveCenter(center)
        left_start = QPointF(self.rect1.topLeft())
        right_start = QPointF(self.rect1.bottomRight())
        bottom_start = QPointF(self.rect1.bottomLeft())
        top_start = QPointF(self.rect1.topRight())
        path = (self.right_path, self.top_path, self.left_path,
                self.bottom_path)
        start = (right_start, top_start, left_start, bottom_start)
        angle = -45
        for i in range(4):
            path[i].moveTo(start[i])
            path[i].arcTo(self.rect1, angle, 90)
            path[i].arcTo(self.rect2, angle + 90, -90)
            path[i].closeSubpath()
            angle += 90
        cap = QRectF()
        cap.setSize(QSizeF(self.rect1.width() * 0.8,
                           self.rect1.height() * 0.8))
        cap.moveCenter(center)
        self.center_path.addEllipse(cap)

    def draw_painter_paths(self, qp, event):
        w = min(event.rect().width(), event.rect().height())
        center = event.rect().center()
        fp = QPoint(int(center.x() - w / 4), int(center.y() - w / 4))
        bg = QRadialGradient(center, w / 2, fp)
        bg.setColorAt(0, QColor(180, 180, 180))
        bg.setColorAt(1, QColor(40, 40, 40))
        qp.setBrush(QBrush(bg))
        qp.setPen(QPen(QColor(Qt.black), 4))
        qp.drawPath(self.left_path)
        qp.drawPath(self.right_path)
        qp.drawPath(self.top_path)
        qp.drawPath(self.bottom_path)
        qp.drawPath(self.center_path)

    def draw_icons(self, qp, event):
        rect = QRect()
        rect.setSize(
            QSize(int(self.rect1.width() * 0.4),
                  int(self.rect1.height() * 0.4)))
        center = event.rect().center()
        qp.setPen(QPen(self._text_color, 2))
        qp.setFont(self._font)
        # left button
        rect.moveCenter(
            QPoint(int(center.x() - self.rect2.width() / 3), center.y()))
        if isinstance(self.left_image, QPixmap):
            pix = self.left_image
            qp.drawPixmap(rect, pix, pix.rect())
        elif isinstance(self.left_image, str):
            qp.drawText(rect, Qt.AlignCenter, self.left_image)
        # right button
        rect.moveCenter(
            QPoint(int(center.x() + self.rect2.width() / 3), center.y()))
        if isinstance(self.right_image, QPixmap):
            pix = self.right_image
            qp.drawPixmap(rect, pix, pix.rect())
        elif isinstance(self.right_image, str):
            qp.drawText(rect, Qt.AlignCenter, self.right_image)
        # bottom button
        rect.moveCenter(
            QPoint(center.x(), int(center.y() + self.rect2.width() / 3)))
        if isinstance(self.bottom_image, QPixmap):
            pix = self.bottom_image
            qp.drawPixmap(rect, pix, pix.rect())
        elif isinstance(self.bottom_image, str):
            qp.drawText(rect, Qt.AlignCenter, self.bottom_image)
        # top button
        rect.moveCenter(
            QPoint(center.x(), int(center.y() - self.rect2.width() / 3)))
        if isinstance(self.top_image, QPixmap):
            pix = self.top_image
            qp.drawPixmap(rect, pix, pix.rect())
        elif isinstance(self.top_image, str):
            qp.drawText(rect, Qt.AlignCenter, self.top_image)
        # center button
        rect.moveCenter(QPoint(center.x(), center.y()))
        if isinstance(self.center_image, QPixmap):
            pix = self.center_image
            qp.drawPixmap(rect, pix, pix.rect())
        elif isinstance(self.center_image, str):
            qp.drawText(rect, Qt.AlignCenter, self.center_image)

    def draw_highlight(self, qp, event):
        rect = QRectF()
        rect.setSize(self.rect1.size() * 0.9)
        center = event.rect().center()
        rect.moveCenter(center)
        pen_width = self.rect1.width() * 0.08
        qp.setPen(QPen(self.highlight_color, pen_width, cap=Qt.FlatCap))
        if self.highlight_center is True:
            qp.drawArc(rect, 0, 5760)
        else:
            if self.highlight_right is True:
                qp.drawArc(rect, -45 * 16, 90 * 16)
            if self.highlight_left is True:
                qp.drawArc(rect, 135 * 16, 90 * 16)
            if self.highlight_top is True:
                qp.drawArc(rect, 45 * 16, 90 * 16)
            if self.highlight_bottom is True:
                qp.drawArc(rect, 225 * 16, 90 * 16)

    def reset_highlight(self):
        self.highlight_left = False
        self.highlight_right = False
        self.highlight_top = False
        self.highlight_bottom = False
        self.highlight_center = False

    def set_highlight(self, btn, state=True):
        if type(btn) == int:
            if btn == IndicatorPosition.LEFT:
                btn = 'L'
            elif btn == IndicatorPosition.RIGHT:
                btn = 'R'
            elif btn == IndicatorPosition.CENTER:
                btn = 'C'
            elif btn == IndicatorPosition.TOP:
                btn = 'T'
            elif btn == IndicatorPosition.BOTTOM:
                btn = 'B'
            elif btn == IndicatorPosition.LEFTRIGHT:
                btn = 'X'
            elif btn == IndicatorPosition.TOPBOTTOM:
                btn = 'Z'
            elif btn == IndicatorPosition.NONE:
                self.reset_highlight()
                return
            else:
                print('undefined position:{}'.format(btn))
                return
        if btn not in self.axis_list and btn not in self.btn_names.keys():
            return
        if btn == 'X' or btn == 'A':
            self.highlight_left = state
            self.highlight_right = state
        elif btn == 'Y' or btn == 'Z':
            self.highlight_top = state
            self.highlight_bottom = state
        else:
            name = self.btn_names[btn]
            self['highlight_' + name] = state
        self.update()

    def set_button_icon(self, btn, path):
        self.set_icon(btn, 'image', path)

    def set_button_text(self, btn, text):
        self.set_icon(btn, 'text', text)

    def set_icon(self, btn, kind, data):
        if btn not in self.btn_names.keys(): return
        name = self.btn_names[btn]
        if kind == 'image':
            if data is None:
                self[name + "_image"] = None
            else:
                self[name + "_image"] = QPixmap(data)
        elif kind == 'text':
            self[name + "_image"] = data
        else:
            return
        self.update()

    def set_tooltip(self, btn, tip):
        if btn in self.btn_names.keys():
            self.tooltips[btn] = tip

    def setLight(self, data):
        if data:
            self.highlight_color = self._true_color
        else:
            self.highlight_color = self._false_color
        self.update()

    def set_HighlightPosition(self, position):
        self._highlightPosition = position
        self.reset_highlight()
        self.set_highlight(position, True)
        self.update()

    def get_HighlightPosition(self):
        return self._highlightPosition

    def reset_HighlightPosition(self):
        self._highlightPosition = IndicatorPosition.NONE
        self.reset_highlight()
        self.update()

    highlightPosition = QtCore.pyqtProperty(IndicatorPosition,
                                            get_HighlightPosition,
                                            set_HighlightPosition,
                                            reset_HighlightPosition)

    @QtCore.pyqtSlot()
    def set_colorStateTrue(self):
        self.setLight(True)

    @QtCore.pyqtSlot()
    def set_colorStateFalse(self):
        self.setLight(False)

    @QtCore.pyqtSlot(bool)
    def set_colorState(self, state):
        self.colorState = bool(state)
        self.setLight(state)

    def get_colorState(self):
        return self.colorState

    def reset_colorState(self):
        self.colorState = False
        self.setLight(False)

    setColorState = QtCore.pyqtProperty(bool, get_colorState, set_colorState,
                                        reset_colorState)

    def setLeftImagePath(self, data):
        if data.isNull():
            data = None
        self.set_icon('L', 'image', data)

    def getLeftImagePath(self):
        if isinstance(self.left_image, QPixmap):
            self.left_image
        else:
            return self._dummyPixmap

    def resetLeftImagePath(self):
        pass

    def setRightImagePath(self, data):
        if data.isNull():
            data = None
        self.set_icon('R', 'image', data)

    def getRightImagePath(self):
        return self._dummyPixmap

    def resetRightImagePath(self):
        pass

    def setCenterImagePath(self, data):
        if data.isNull():
            data = None
        self.set_icon('C', 'image', data)

    def getCenterImagePath(self):
        return self._dummyPixmap

    def resetCenterImagePath(self):
        pass

    def setTopImagePath(self, data):
        if data.isNull():
            data = None
        self.set_icon('T', 'image', data)

    def getTopImagePath(self):
        return self._dummyPixmap

    def resetTopImagePath(self):
        pass

    def setBottomImagePath(self, data):
        if data.isNull():
            data = None
        self.set_icon('B', 'image', data)

    def getBottomImagePath(self):
        return self._dummyPixmap

    def resetBottomImagePath(self):
        pass

    left_image_path = QtCore.pyqtProperty(QPixmap, getLeftImagePath,
                                          setLeftImagePath, resetLeftImagePath)
    right_image_path = QtCore.pyqtProperty(QPixmap, getRightImagePath,
                                           setRightImagePath,
                                           resetRightImagePath)
    center_image_path = QtCore.pyqtProperty(QPixmap, getCenterImagePath,
                                            setCenterImagePath,
                                            resetCenterImagePath)
    top_image_path = QtCore.pyqtProperty(QPixmap, getTopImagePath,
                                         setTopImagePath, resetTopImagePath)
    bottom_image_path = QtCore.pyqtProperty(QPixmap, getBottomImagePath,
                                            setBottomImagePath,
                                            resetBottomImagePath)

    def getFont(self):
        return self._font

    def setFont(self, value):
        self._font = value

    def resetFont(self):
        self._font = QFont('Lato Heavy', 20)

    button_font = QtCore.pyqtProperty(QFont, getFont, setFont, resetFont)

    def setLeftText(self, data):
        self._textL = data
        if not data.strip():
            data = None
        self.set_icon('L', 'text', data)

    def getLeftText(self):
        return self._textL

    def resetLeftText(self):
        self._textL = ''
        self.set_icon('L', 'text', '')

    def setRightText(self, data):
        self._textR = data
        if not data.strip():
            data = None
        self.set_icon('R', 'text', data)

    def getRightText(self):
        return self._textR

    def resetRightText(self):
        self._textR = ''
        self.set_icon('R', 'text', '')

    def setCenterText(self, data):
        self._textC = data
        if not data.strip():
            data = None
        self.set_icon('C', 'text', data)

    def getCenterText(self):
        return self._textC

    def resetCenterText(self):
        self._textC = ''
        self.set_icon('C', 'text', '')

    def setTopText(self, data):
        self._textT = data
        if not data.strip():
            data = None
        self.set_icon('T', 'text', data)

    def getTopText(self):
        return self._textT

    def resetTopText(self):
        self._textT = ''
        self.set_icon('T', 'text', '')

    def setBottomText(self, data):
        self._textB = data
        if not data.strip():
            data = None
        self.set_icon('B', 'text', data)

    def getBottomText(self):
        return self._textB

    def resetBottomText(self):
        self._textB = ''
        self.set_icon('B', 'text', '')

    left_text = QtCore.pyqtProperty(str, getLeftText, setLeftText,
                                    resetLeftText)
    right_text = QtCore.pyqtProperty(str, getRightText, setRightText,
                                     resetRightText)
    center_text = QtCore.pyqtProperty(str, getCenterText, setCenterText,
                                      resetCenterText)
    top_text = QtCore.pyqtProperty(str, getTopText, setTopText, resetTopText)
    bottom_text = QtCore.pyqtProperty(str, getBottomText, setBottomText,
                                      resetBottomText)

    @QtCore.pyqtSlot(QColor)
    def set_true_color(self, color):
        self._true_color = color
        self.setLight(self.colorState)

    @QtCore.pyqtSlot(str)
    def set_true_color(self, color):
        self._true_color = QColor(color)
        self.setLight(self.colorState)

    def get_true_color(self):
        return self._true_color

    def reset_true_color(self):
        self._true_color = QColor('lawngreen')
        self.setLight(self.colorState)

    @QtCore.pyqtSlot(QColor)
    def set_false_color(self, color):
        self._false_color = color
        self.setLight(self.colorState)

    @QtCore.pyqtSlot(str)
    def set_false_color(self, color):
        self._false_color = QColor(color)
        self.setLight(self.colorState)

    def get_false_color(self):
        return self._false_color

    def reset_false_color(self):
        self._false_color = QColor('gray')
        self.setLight(self.colorState)

    def set_text_color(self, color):
        self._text_color = QColor(color)
        self.update()

    def get_text_color(self):
        return self._text_color

    def reset_text_color(self):
        self._text_color = QColor('white')
        self.update()

    true_color = QtCore.pyqtProperty(QColor, get_true_color, set_true_color,
                                     reset_true_color)
    false_color = QtCore.pyqtProperty(QColor, get_false_color, set_false_color,
                                      reset_false_color)
    text_color = QtCore.pyqtProperty(QColor, get_text_color, set_text_color,
                                     reset_text_color)

    @QtCore.pyqtSlot(str)
    def btn_pressed(self, btn):
        print("Button pressed", btn)

    @QtCore.pyqtSlot(str)
    def btn_released(self, btn):
        print("Button released", btn)

    # required code for object indexing
    def __getitem__(self, item):
        return getattr(self, item)

    def __setitem__(self, item, value):
        return setattr(self, item, value)
Ejemplo n.º 21
0
class TestPathFinding(TestCase):

################################################################################

    def setUp(self):
        """

        """

        #       --left     --right
        #       '          '
        #   I   |    II    |  III
        # ------+==========+------   --top
        #  VIII |  IX (in) |  IV
        # ------+==========+------   --bottom
        #  VII  |    VI    |   V

        self._offset = 10
        self._rect = QRectF(QPointF(-20, -10), QPointF(20, 10))
        self._pointI = QPointF(self._rect.left()-self._offset, self._rect.top()-self._offset)
        self._pointII = QPointF(self._rect.center().x(), self._rect.top()-self._offset)
        self._pointIII = QPointF(self._rect.right()+ self._offset, self._rect.top()- self._offset)
        self._pointIV = QPointF(self._rect.right()+self._offset, self._rect.center().y())
        self._pointV = QPointF(self._rect.right()+self._offset, self._rect.bottom()+self._offset)
        self._pointVI = QPointF(self._rect.center().x(), self._rect.bottom()+self._offset)
        self._pointVII = QPointF(self._rect.left()-self._offset, self._rect.bottom()+self._offset)
        self._pointVIII = QPointF(self._rect.left()-self._offset, self._rect.center().y())
        self._pointIX = self._rect.center()

        self._lineI_VII = QLineF(self._pointI, self._pointVII)
        self._lineI_V = QLineF(self._pointI, self._pointV)
        self._lineII = QLineF(self._pointII, QPointF(self._rect.center().x(), self._rect.top()))
        self._lineII_IV = QLineF(QPointF(self._rect.right()-self._offset, self._rect.top()-self._offset),
                                 QPointF(self._rect.right()+self._offset, self._rect.top()+self._offset))

################################################################################

    def testPointRectDist(self):
        """

        """

        lineI = PathFinding.pointRectDist(self._pointI, self._rect)
        self.assertEqual(lineI.p2(), self._rect.topLeft())
        self.assertEqual(lineI.length(), pow(pow(self._offset, 2)+pow(self._offset, 2), 0.5))
        lineII = PathFinding.pointRectDist(self._pointII, self._rect)
        self.assertEqual(lineII.p2(), QPointF(self._rect.center().x(), self._rect.top()))
        self.assertEqual(lineII.length(), self._offset)
        lineIII = PathFinding.pointRectDist(self._pointIII, self._rect)
        self.assertEqual(lineIII.p2(), self._rect.topRight())
        self.assertEqual(lineIII.length(), pow(pow(self._offset, 2)+pow(self._offset, 2), 0.5))
        lineIV = PathFinding.pointRectDist(self._pointIV, self._rect)
        self.assertEqual(lineIV.p2(), QPointF(self._rect.right(), self._rect.center().y()))
        self.assertEqual(lineIV.length(), self._offset)
        lineV = PathFinding.pointRectDist(self._pointV, self._rect)
        self.assertEqual(lineV.p2(), self._rect.bottomRight())
        self.assertEqual(lineV.length(), pow(pow(self._offset, 2)+pow(self._offset, 2), 0.5))
        lineVI = PathFinding.pointRectDist(self._pointVI, self._rect)
        self.assertEqual(lineVI.p2(), QPointF(self._rect.center().x(), self._rect.bottom()))
        self.assertEqual(lineVI.length(), self._offset)
        lineVII = PathFinding.pointRectDist(self._pointVII, self._rect)
        self.assertEqual(lineVII.p2(), self._rect.bottomLeft())
        self.assertEqual(lineVII.length(), pow(pow(self._offset, 2)+pow(self._offset, 2), 0.5))
        lineVIII = PathFinding.pointRectDist(self._pointVIII, self._rect)
        self.assertEqual(lineVIII.p2(), QPointF(self._rect.left(), self._rect.center().y()))
        self.assertEqual(lineVIII.length(), self._offset)
        lineIX = PathFinding.pointRectDist(self._pointIX, self._rect)
        self.assertEqual(lineIX.p2(), self._pointIX)
        self.assertEqual(lineIX.length(), 0)

################################################################################

    def testIntersects(self):
        """

        """

        rect = QRectF(QPointF(-50, -10), QPointF(50, 10))
        # line completely outside of the rectangle
        self.assertFalse(PathFinding.intersects(rect, QLineF(QPointF(-100, -50), QPointF(-100, 50))))
        # the line is a top side of the rectangle
        self.assertFalse(PathFinding.intersects(rect, QLineF(rect.topLeft(), rect.topRight())))
        # the line starts at the left corner of the rectangle and is not perpendicular to any of the rectangle sides;
        # the line ends outside of the rectangle, not going through it
        self.assertFalse(PathFinding.intersects(rect, QLineF(rect.topLeft(), QPointF(-100, -100))))
        # the line starts at the left corner of the rectangle and is perpendicular to the top side of the rectangle;
        # the line ends outside of the rectangle, not going through it
        self.assertFalse(PathFinding.intersects(rect, QLineF(rect.topLeft(), QPointF(rect.left(), rect.top() - 100))))
        # the line is horizontal and goes straight through the center of the rectangle
        self.assertTrue(PathFinding.intersects(rect, QLineF(QPointF(-100, 0), QPointF(100, 0))))
        # the line is vertical and goes straight through the center of the rectangle
        self.assertTrue(PathFinding.intersects(rect, QLineF(QPointF(0, -100), QPointF(0, 100))))
        # the line is vertical and goes up from the bottom right corner of the rectangle
        self.assertFalse(PathFinding.intersects(rect, QLineF(rect.bottomRight(), QPointF(rect.right(), rect.top()-100))))
        # the line is diagonal of the rectangle
        self.assertTrue(PathFinding.intersects(rect, QLineF(rect.topLeft(), rect.bottomRight())))
Ejemplo n.º 22
0
    def drawMagnifier(self):
        # First, calculate the magnifier position due to the mouse position
        watchAreaWidth = 16
        watchAreaHeight = 16
        watchAreaPixmap = QPixmap()

        cursor_pos = self.mousePoint

        watchArea = QRect(
            QPoint(cursor_pos.x() - watchAreaWidth / 2,
                   cursor_pos.y() - watchAreaHeight / 2),
            QPoint(cursor_pos.x() + watchAreaWidth / 2,
                   cursor_pos.y() + watchAreaHeight / 2))
        if watchArea.left() < 0:
            watchArea.moveLeft(0)
            watchArea.moveRight(watchAreaWidth)
        if self.mousePoint.x() + watchAreaWidth / 2 >= self.screenPixel.width(
        ):
            watchArea.moveRight(self.screenPixel.width() - 1)
            watchArea.moveLeft(watchArea.right() - watchAreaWidth)
        if self.mousePoint.y() - watchAreaHeight / 2 < 0:
            watchArea.moveTop(0)
            watchArea.moveBottom(watchAreaHeight)
        if self.mousePoint.y(
        ) + watchAreaHeight / 2 >= self.screenPixel.height():
            watchArea.moveBottom(self.screenPixel.height() - 1)
            watchArea.moveTop(watchArea.bottom() - watchAreaHeight)

        # tricks to solve the hidpi impact on QCursor.pos()
        watchArea.setTopLeft(
            QPoint(watchArea.topLeft().x() * self.scale,
                   watchArea.topLeft().y() * self.scale))
        watchArea.setBottomRight(
            QPoint(watchArea.bottomRight().x() * self.scale,
                   watchArea.bottomRight().y() * self.scale))
        watchAreaPixmap = self.screenPixel.copy(watchArea)

        # second, calculate the magnifier area
        magnifierAreaWidth = watchAreaWidth * 10
        magnifierAreaHeight = watchAreaHeight * 10
        fontAreaHeight = 40

        cursorSize = 24
        magnifierArea = QRectF(
            QPoint(QCursor.pos().x() + cursorSize,
                   QCursor.pos().y() + cursorSize),
            QPoint(QCursor.pos().x() + cursorSize + magnifierAreaWidth,
                   QCursor.pos().y() + cursorSize + magnifierAreaHeight))
        if magnifierArea.right() >= self.screenPixel.width():
            magnifierArea.moveLeft(QCursor.pos().x() - magnifierAreaWidth -
                                   cursorSize / 2)
        if magnifierArea.bottom() + fontAreaHeight >= self.screenPixel.height(
        ):
            magnifierArea.moveTop(QCursor.pos().y() - magnifierAreaHeight -
                                  cursorSize / 2 - fontAreaHeight)

        # third, draw the watch area to magnifier area
        watchAreaScaled = watchAreaPixmap.scaled(
            QSize(magnifierAreaWidth * self.scale,
                  magnifierAreaHeight * self.scale))
        magnifierPixmap = self.graphicsScene.addPixmap(watchAreaScaled)
        magnifierPixmap.setOffset(magnifierArea.topLeft())

        # then draw lines and text
        self.graphicsScene.addRect(QRectF(magnifierArea),
                                   QPen(QColor(255, 255, 255), 2))
        self.graphicsScene.addLine(
            QLineF(QPointF(magnifierArea.center().x(), magnifierArea.top()),
                   QPointF(magnifierArea.center().x(),
                           magnifierArea.bottom())),
            QPen(QColor(0, 255, 255), 2))
        self.graphicsScene.addLine(
            QLineF(QPointF(magnifierArea.left(),
                           magnifierArea.center().y()),
                   QPointF(magnifierArea.right(),
                           magnifierArea.center().y())),
            QPen(QColor(0, 255, 255), 2))

        # get the rgb of mouse point
        pointRgb = QColor(self.screenPixel.toImage().pixel(self.mousePoint))

        # draw information
        self.graphicsScene.addRect(
            QRectF(
                magnifierArea.bottomLeft(),
                magnifierArea.bottomRight() + QPoint(0, fontAreaHeight + 30)),
            Qt.black, QBrush(Qt.black))
        rgbInfo = self.graphicsScene.addSimpleText(
            ' Rgb: ({0}, {1}, {2})'.format(pointRgb.red(), pointRgb.green(),
                                           pointRgb.blue()))
        rgbInfo.setPos(magnifierArea.bottomLeft() + QPoint(0, 5))
        rgbInfo.setPen(QPen(QColor(255, 255, 255), 2))

        rect = self.selectedArea.normalized()
        sizeInfo = self.graphicsScene.addSimpleText(' Size: {0} x {1}'.format(
            rect.width() * self.scale,
            rect.height() * self.scale))
        sizeInfo.setPos(magnifierArea.bottomLeft() + QPoint(0, 15) +
                        QPoint(0, fontAreaHeight / 2))
        sizeInfo.setPen(QPen(QColor(255, 255, 255), 2))
Ejemplo n.º 23
0
    def redraw(self):
        self.graphicsScene.clear()

        # draw screenshot
        self.graphicsScene.addPixmap(self.screenPixel)

        # prepare for drawing selected area
        rect = QRectF(self.selectedArea)
        rect = rect.normalized()

        topLeftPoint = rect.topLeft()
        topRightPoint = rect.topRight()
        bottomLeftPoint = rect.bottomLeft()
        bottomRightPoint = rect.bottomRight()
        topMiddlePoint = (topLeftPoint + topRightPoint) / 2
        leftMiddlePoint = (topLeftPoint + bottomLeftPoint) / 2
        bottomMiddlePoint = (bottomLeftPoint + bottomRightPoint) / 2
        rightMiddlePoint = (topRightPoint + bottomRightPoint) / 2

        # draw the picture mask
        mask = QColor(0, 0, 0, 155)

        if self.selectedArea == QRect():
            self.graphicsScene.addRect(0, 0, self.screenPixel.width(),
                                       self.screenPixel.height(),
                                       QPen(Qt.NoPen), mask)
        else:
            self.graphicsScene.addRect(0, 0, self.screenPixel.width(),
                                       topRightPoint.y(), QPen(Qt.NoPen), mask)
            self.graphicsScene.addRect(0, topLeftPoint.y(), topLeftPoint.x(),
                                       rect.height(), QPen(Qt.NoPen), mask)
            self.graphicsScene.addRect(
                topRightPoint.x(), topRightPoint.y(),
                self.screenPixel.width() - topRightPoint.x(), rect.height(),
                QPen(Qt.NoPen), mask)
            self.graphicsScene.addRect(
                0, bottomLeftPoint.y(), self.screenPixel.width(),
                self.screenPixel.height() - bottomLeftPoint.y(),
                QPen(Qt.NoPen), mask)

        # draw the toolBar
        if self.action != ACTION_SELECT:
            spacing = 5
            # show the toolbar first, then move it to the correct position
            # because the width of it may be wrong if this is the first time it shows
            self.tooBar.show()

            dest = QPointF(rect.bottomRight() -
                           QPointF(self.tooBar.width(), 0) -
                           QPointF(spacing, -spacing))
            if dest.x() < spacing:
                dest.setX(spacing)
            pen_set_bar_height = self.penSetBar.height(
            ) if self.penSetBar is not None else 0
            if dest.y() + self.tooBar.height(
            ) + pen_set_bar_height >= self.height():
                if rect.top() - self.tooBar.height(
                ) - pen_set_bar_height < spacing:
                    dest.setY(rect.top() + spacing)
                else:
                    dest.setY(rect.top() - self.tooBar.height() -
                              pen_set_bar_height - spacing)

            self.tooBar.move(dest.toPoint())

            if self.penSetBar is not None:
                self.penSetBar.show()
                self.penSetBar.move(dest.toPoint() +
                                    QPoint(0,
                                           self.tooBar.height() + spacing))

                if self.action == ACTION_TEXT:
                    self.penSetBar.showFontWidget()
                else:
                    self.penSetBar.showPenWidget()
        else:
            self.tooBar.hide()

            if self.penSetBar is not None:
                self.penSetBar.hide()

        # draw the list
        for step in self.drawListResult:
            self.drawOneStep(step)

        if self.drawListProcess is not None:
            self.drawOneStep(self.drawListProcess)
            if self.action != ACTION_TEXT:
                self.drawListProcess = None

        if self.selectedArea != QRect():
            self.itemsToRemove = []

            # draw the selected rectangle
            pen = QPen(QColor(0, 255, 255), 2)
            self.itemsToRemove.append(self.graphicsScene.addRect(rect, pen))

            # draw the drag point
            radius = QPoint(3, 3)
            brush = QBrush(QColor(0, 255, 255))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(topLeftPoint - radius, topLeftPoint + radius), pen,
                    brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(topMiddlePoint - radius, topMiddlePoint + radius),
                    pen, brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(topRightPoint - radius, topRightPoint + radius),
                    pen, brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(leftMiddlePoint - radius, leftMiddlePoint + radius),
                    pen, brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(rightMiddlePoint - radius,
                           rightMiddlePoint + radius), pen, brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(bottomLeftPoint - radius, bottomLeftPoint + radius),
                    pen, brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(bottomMiddlePoint - radius,
                           bottomMiddlePoint + radius), pen, brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(bottomRightPoint - radius,
                           bottomRightPoint + radius), pen, brush))

        # draw the textedit
        if self.textPosition is not None:
            textSpacing = 50
            position = QPoint()
            if self.textPosition.x() + self.textInput.width(
            ) >= self.screenPixel.width():
                position.setX(self.textPosition.x() - self.textInput.width())
            else:
                position.setX(self.textPosition.x())

            if self.textRect is not None:
                if self.textPosition.y() + self.textInput.height(
                ) + self.textRect.height() >= self.screenPixel.height():
                    position.setY(self.textPosition.y() -
                                  self.textInput.height() -
                                  self.textRect.height())
                else:
                    position.setY(self.textPosition.y() +
                                  self.textRect.height())
            else:
                if self.textPosition.y() + self.textInput.height(
                ) >= self.screenPixel.height():
                    position.setY(self.textPosition.y() -
                                  self.textInput.height())
                else:
                    position.setY(self.textPosition.y())

            self.textInput.move(position)
            self.textInput.show()
            # self.textInput.getFocus()

        # draw the magnifier
        if self.action == ACTION_SELECT:
            self.drawMagnifier()
            if self.mousePressed:
                self.drawSizeInfo()

        if self.action == ACTION_MOVE_SELECTED:
            self.drawSizeInfo()
Ejemplo n.º 24
0
    def drawPrimitive(self, element, opt, painter, widget):
        if not self.__panel_widget(widget):
            return QProxyStyle.drawPrimitive(self, element, opt, painter,
                                             widget)
        if element == QStyle.PE_PanelButtonTool:
            flat = True
            pressed = (opt.state & STATE_SUNKEN or opt.state & STATE_ON)
            hovered = opt.state & STATE_ENABLED and opt.state & STATE_MOUSEOVER
            button_color = _COLORS['ToolButtonColor']
            if not flat and widget.property("gradient"):
                button_color = QLinearGradient(opt.rect.topRight(),
                                               opt.rect.bottomRight())
                button_color.setColorAt(0, QColor("#454545"))
                button_color.setColorAt(1, QColor("#191919"))
            if pressed:
                button_color = _COLORS['ToolButtonSelected']
            elif hovered:
                if not flat and widget.property("gradient"):
                    button_color.setColorAt(0, QColor("#555"))
                    button_color.setColorAt(1, QColor("#191919"))
                else:
                    button_color = _COLORS['ToolButtonHover']
            if widget.property("border_bottom"):
                painter.setPen(_COLORS['Border'])
                painter.drawLine(opt.rect.bottomLeft(), opt.rect.bottomRight())
            painter.fillRect(opt.rect.adjusted(2, 2, -2, -2), button_color)
            # elif not opt.state & STATE_ENABLED:
            #    color = _PALETTE['ButtonDisabled']
            #    painter.fillRect(opt.rect, color)
            # TODO: keyboard focus change state
        # elif element == QStyle.PE_PanelButtonCommand:
        # Draw a flat push button
        #    is_down = opt.state & STATE_SUNKEN or opt.state & STATE_ON
        #    is_enabled = opt.state & STATE_ENABLED
        #    is_hover = is_enabled and opt.state & STATE_MOUSEOVER
        # FIXME: has_focus state
        # FIXME: from theme
        #    color = QColor("#444a58")
        #    if is_down:
        #        color = color.darker(130)
        #    elif is_hover:
        #        color = color.lighter(110)
        #    painter.fillRect(opt.rect, color)

        elif element == QStyle.PE_PanelLineEdit:
            painter.save()
            # Fill background
            rect = opt.rect
            enabled = False
            if opt.state & STATE_ENABLED:
                enabled = True
            if not enabled:
                painter.setOpacity(0.55)
            painter.fillRect(rect, _COLORS['LineEditBackground'])
            has_focus = False
            if opt.state & QStyle.State_HasFocus:
                has_focus = True
            if enabled and (has_focus or opt.state & STATE_MOUSEOVER):
                # FIXME: color from theme
                # hover = QColor("#6a6ea9")
                # if has_focus:
                #    alpha = 200
                # else:
                #    alpha = 55
                # hover.setAlpha(alpha)
                # painter.setPen(QPen(hover, 2, Qt.SolidLine,
                #               Qt.SquareCap, Qt.RoundJoin))
                # painter.drawRect(rect.adjusted(0, 0, 0, 0))
                pass
            painter.restore()
        elif element == QStyle.PE_IndicatorToolBarSeparator:
            rect = opt.rect
            painter.setPen(_COLORS['SeparatorColor'])
            border_rect = QRectF(rect).adjusted(0.5, 0.5, -0.5, -0.5)
            if opt.state & QStyle.State_Horizontal:
                border_rect.setWidth(1)
                painter.drawLine(border_rect.topRight() + QPointF(0, 3),
                                 border_rect.bottomRight() - QPointF(0, 3))
            else:
                border_rect.setHeight(1)
                painter.drawLine(border_rect.topLeft() + QPointF(3, 0),
                                 border_rect.topRight() - QPointF(3, 0))
        elif element == QStyle.PE_IndicatorToolBarHandle:
            # FIXME: draw a fancy handler
            QProxyStyle.drawPrimitive(self, element, opt, painter, widget)
        else:
            QProxyStyle.drawPrimitive(self, element, opt, painter, widget)
Ejemplo n.º 25
0
def _hashMarkGen(path, p1, p2, p3):
    path.moveTo(p1)
    path.lineTo(p2)
    path.lineTo(p3)
# end

# create hash marks QPainterPaths only once
_PP_RECT = QRectF(0, 0, styles.PATH_BASE_WIDTH, styles.PATH_BASE_WIDTH)
_PATH_CENTER = QPointF(styles.PATH_BASE_WIDTH / 2,\
                          styles.PATH_BASE_WIDTH / 2)
_PATH_U_CENTER = QPointF(styles.PATH_BASE_WIDTH / 2, 0)
_PATH_D_CENTER = QPointF(styles.PATH_BASE_WIDTH / 2, styles.PATH_BASE_WIDTH)
_PPATH_LU = QPainterPath()
_hashMarkGen(_PPATH_LU, _PP_RECT.bottomLeft(), _PATH_D_CENTER, _PATH_CENTER)
_PPATH_RU = QPainterPath()
_hashMarkGen(_PPATH_RU, _PP_RECT.bottomRight(), _PATH_D_CENTER, _PATH_CENTER)
_PPATH_RD = QPainterPath()
_hashMarkGen(_PPATH_RD, _PP_RECT.topRight(), _PATH_U_CENTER, _PATH_CENTER)
_PPATH_LD = QPainterPath()
_hashMarkGen(_PPATH_LD, _PP_RECT.topLeft(), _PATH_U_CENTER, _PATH_CENTER)

_SCAF_PEN = QPen(styles.PXI_SCAF_STROKE, styles.PATH_STRAND_STROKE_WIDTH)
_SCAF_PEN.setCapStyle(Qt.FlatCap)  # or Qt.RoundCap
_SCAF_PEN.setJoinStyle(Qt.RoundJoin)
_STAP_PEN = QPen(styles.PXI_STAP_STROKE, styles.PATH_STRAND_STROKE_WIDTH)
_STAP_PEN.setCapStyle(Qt.FlatCap)  # or Qt.RoundCap
_STAP_PEN.setJoinStyle(Qt.RoundJoin)
_DISAB_PEN = QPen(styles.PXI_DISAB_STROKE, styles.PATH_STRAND_STROKE_WIDTH)
_DISAB_PEN.setCapStyle(Qt.FlatCap)
_DISAB_PEN.setJoinStyle(Qt.RoundJoin)
_DISAB_BRUSH = QBrush(styles.PXI_DISAB_STROKE)  # For the helix number label
Ejemplo n.º 26
0
class RectZoomMoveView(QChartView):
    """
    Filter data to be displayed in rectangular body
    """

    rangeSig = pyqtSignal(list)

    def __init__(self, parent=None):
        super(RectZoomMoveView, self).__init__(parent)
        self.setChart(QChart())
        self.chart().setMargins(QMargins(5, 5, 5, 5))
        self.chart().setContentsMargins(-10, -10, -10, -10)
        self.chart().setTitle(" ")
        self.relationState = True

        # Define two rectangles for background and drawing respectively
        self.parentRect = QGraphicsRectItem(self.chart())

        self.parentRect.setFlag(QGraphicsItem.ItemClipsChildrenToShape, True)
        self.parentRect.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
        self.RangeItem = RectRangeItem(parent=self.parentRect)
        self.RangeItem.setZValue(998)
        pen = QPen(Qt.gray)
        pen.setWidth(1)
        self.parentRect.setPen(pen)
        self.parentRect.setZValue(997)

        self.scene().addItem(self.parentRect)
        self.scene().addItem(self.RangeItem)

        self.RangeItem.hide()
        self.m_chartRectF = QRectF()
        self.m_rubberBandOrigin = QPointF(0, 0)
        self.dataLength = 0

        self.RangeItem.selectedChange.connect(self.changeFromRectItem)

        self.BtnsWidget = ViewButtonsWidget(self)
        self.BtnsWidget.refreshBtn.clicked.connect(self.updateView)
        self.BtnsWidget.RelationSig.connect(self.setRelationState)
        self.BtnsWidget.dateRangeEdit.dateRangeSig.connect(self.changDateRect)

    def changDateRect(self, daterange):
        if self.chartTypes == "Bar":
            v = 3
        else:
            v = 2
        l = len(self.RangeItem.rangePoints)
        if l > 2:
            try:
                num = self.mintimeData.date().daysTo(daterange[0])
                left = self.RangeItem.rangePoints[num]
                num = self.mintimeData.date().daysTo(daterange[1])
                right = self.RangeItem.rangePoints[num]
                rect = self.chart().plotArea()
                rect.setLeft(left)
                rect.setRight(right)
            except:
                rect = self.chart().plotArea()
            self.RangeItem.setRect(rect)
            self.RangeItem.updateHandlesPos()
        else:
            try:
                num = self.mintimeData.date().daysTo(daterange[0])
                left = self.RangeItem.rangePoints[num]
                num = self.mintimeData.date().daysTo(daterange[0])
                right = self.RangeItem.rangePoints[num]
                rect = self.chart().plotArea()
                rect.setLeft(left)
                rect.setRight(right)
            except:
                rect = self.chart().plotArea()
            self.RangeItem.setRect(rect)
            self.RangeItem.updateHandlesPos()

    def lineSpace(self, start, end, num):
        res = []
        if self.chartTypes == "Bar":
            step = (end - start) / (num)
            for i in range(num + 2):
                res.append(start + i * step)
        else:
            step = (end - start) / (num - 1)
            for i in range(num + 1):
                res.append(start + i * step)
        return res

    def getRangePoints(self):
        count = self.zoomSeries.count()
        rect = self.chart().plotArea()
        left = rect.left()
        right = rect.right()
        if count == 0:
            self.RangeItem.rangePoints = [left, right]
        else:
            # Get coordinate position for each node
            self.RangeItem.rangePoints = self.lineSpace(left, right, count)

    def setRangeColor(self, color):
        self.RangeItem.setRangeColor(color)

    def setRelationState(self, state):
        self.relationState = state

    def initSeries(self, chartTypes="Bar"):
        self.chartTypes = chartTypes
        axisX = QDateTimeAxis()
        axisX.setFormat("yyyy-MM-dd")
        self.zoomSeries = QLineSeries(self.chart())
        self.chart().addSeries(self.zoomSeries)
        self.chart().setAxisY(QValueAxis(), self.zoomSeries)
        self.chart().setAxisX(axisX, self.zoomSeries)
        self.initView()

    def clearAll(self):
        # Clear all series and axes
        self.chart().removeAllSeries()
        axess = self.chart().axes()
        for axes in axess:
            self.chart().removeAxis(axes)

    def setData(self, timeData, valueData, chartTypes="Bar"):
        axisX = QDateTimeAxis()
        axisX.setFormat("yyyy-MM-dd")

        if self.chartTypes == "Bar":
            # Clear all series
            self.clearAll()
            self.zoomSeries = QLineSeries(self.chart())
            barSeries = QBarSeries(self.chart())
            barset = QBarSet("data")
            barSeries.setBarWidth(0.8)
            barSeries.append(barset)
            for td, vd in zip(timeData, valueData):
                self.zoomSeries.append(td.toMSecsSinceEpoch(), vd)
            barset.append(valueData)
            self.zoomSeries.hide()
            self.chart().addSeries(self.zoomSeries)
            self.chart().addSeries(barSeries)
            self.chart().setAxisY(QValueAxis(), self.zoomSeries)
            axisX.setRange(min(timeData), max(timeData))
            self.chart().setAxisX(axisX, self.zoomSeries)
        elif self.chartTypes == "Scatter":
            # Clear all series
            self.clearAll()
            self.zoomSeries = QLineSeries(self.chart())
            scattSeries = QScatterSeries(self.chart())
            scattSeries.setMarkerSize(8)

            for td, vd in zip(timeData, valueData):
                self.zoomSeries.append(td.toMSecsSinceEpoch(), vd)
                scattSeries.append(td.toMSecsSinceEpoch(), vd)
            self.zoomSeries.hide()
            self.chart().addSeries(self.zoomSeries)
            self.chart().addSeries(scattSeries)
            self.chart().setAxisY(QValueAxis(), self.zoomSeries)
            axisX.setRange(min(timeData), max(timeData))
            self.chart().setAxisX(axisX, self.zoomSeries)
        elif self.chartTypes in ["Line", "PLine"]:
            self.clearAll()
            if self.chartTypes == "Line":
                self.zoomSeries = QLineSeries(self.chart())
            else:
                self.zoomSeries = QSplineSeries(self.chart())
            for td, vd in zip(timeData, valueData):
                self.zoomSeries.append(td.toMSecsSinceEpoch(), vd)
            self.chart().addSeries(self.zoomSeries)

            self.chart().setAxisY(QValueAxis(), self.zoomSeries)
            axisX.setRange(min(timeData), max(timeData))
            self.chart().setAxisX(axisX, self.zoomSeries)
        elif self.chartTypes == "Area":

            self.clearAll()
            self.zoomSeries = QLineSeries()
            self.zoomSeries.setColor(QColor("#666666"))
            for td, vd in zip(timeData, valueData):
                self.zoomSeries.append(td.toMSecsSinceEpoch(), vd)

            areaSeries = QAreaSeries(self.zoomSeries, None)

            self.chart().addSeries(self.zoomSeries)
            self.chart().addSeries(areaSeries)
            self.chart().setAxisY(QValueAxis(), areaSeries)
            axisX.setRange(min(timeData), max(timeData))
            self.chart().setAxisX(axisX, areaSeries)
            self.zoomSeries.hide()
        self.mintimeData = min(timeData)
        self.maxtimeData = max(timeData)
        self.BtnsWidget.dateRangeEdit.setDateRange([
            self.mintimeData.toString("yyyy-MM-dd"),
            self.maxtimeData.toString("yyyy-MM-dd"),
        ])
        self.updateView()

    def resetView(self):

        rect = self.chart().plotArea()
        self.parentRect.setRect(rect)
        topRight = self.chart().plotArea().topRight()
        x = int(topRight.x())
        y = int(topRight.y())
        self.BtnsWidget.setGeometry(QRect(x - 420, 0, 420, 23))
        self.RangeItem.setRect(rect)
        self.RangeItem.show()
        self.save_current_rubber_band()
        self.RangeItem.updateHandlesPos()
        self.apply_nice_numbers()
        self.getRangePoints()
        self.sendRang()

    def initView(self):
        self.RangeItem.hide()
        # Hide y-axis
        if self.chart().axisY():
            self.chart().axisY().setVisible(False)
        if self.chart().axisX():
            self.chart().axisX().setGridLineVisible(False)
        self.m_chartRectF = QRectF()
        self.m_rubberBandOrigin = QPointF(0, 0)
        self.getRangePoints()

    def updateView(self):
        self.RangeItem.hide()
        # Hide y-axis
        if self.chart().axisY():
            self.chart().axisY().setVisible(False)
        if self.chart().axisX():
            self.chart().axisX().setGridLineVisible(False)
        self.m_chartRectF = QRectF()
        self.m_rubberBandOrigin = QPointF(0, 0)
        self.resetView()

    # Map points to chart
    def point_to_chart(self, pnt):
        scene_point = self.mapToScene(pnt)
        chart_point = self.chart().mapToValue(scene_point)
        return chart_point

    # Map chart to points
    def chart_to_view_point(self, char_coord):
        scene_point = self.chart().mapToPosition(char_coord)
        view_point = self.mapFromScene(scene_point)
        return view_point

    # Save positions of rectangles
    def save_current_rubber_band(self):
        rect = self.RangeItem.rect()

        chart_top_left = self.point_to_chart(rect.topLeft().toPoint())
        self.m_chartRectF.setTopLeft(chart_top_left)

        chart_bottom_right = self.point_to_chart(rect.bottomRight().toPoint())
        self.m_chartRectF.setBottomRight(chart_bottom_right)

    # Respond to change in positions of rectangles
    def changeFromRectItem(self, rectIndex):
        self.save_current_rubber_band()
        self.sendRang(rectIndex)

    def sendRang(self, rectIndex=[]):

        if self.RangeItem.rect() != self.parentRect.rect():
            self.BtnsWidget.setPalActive()
        else:
            self.BtnsWidget.setPalDisActive()
        if self.chartTypes == "Bar":
            v = 3
        else:
            v = 2
        if rectIndex == []:
            maxData = QDateTime.fromMSecsSinceEpoch(
                self.zoomSeries.at(len(self.RangeItem.rangePoints) - v).x())
            minData = QDateTime.fromMSecsSinceEpoch(self.zoomSeries.at(0).x())
        else:
            minData = max(rectIndex[0], 0)
            maxData = min(rectIndex[1], len(self.RangeItem.rangePoints) - v)
            minData = QDateTime.fromMSecsSinceEpoch(
                self.zoomSeries.at(minData).x())
            maxData = QDateTime.fromMSecsSinceEpoch(
                self.zoomSeries.at(maxData).x())

        if minData > maxData:
            if self.RangeItem.handleSelected is None:
                self.resetView()
        else:
            self.BtnsWidget.dateRangeEdit.setDate([
                minData.toString("yyyy-MM-dd"),
                maxData.toString("yyyy-MM-dd")
            ])
            if self.relationState:
                self.rangeSig.emit([
                    minData.toString("yyyy-MM-dd HH:mm:ss"),
                    maxData.toString("yyyy-MM-dd HH:mm:ss"),
                ])

    # Change positions of rectangles in scaling
    def resizeEvent(self, event):
        super().resizeEvent(event)
        rect = self.chart().plotArea()
        self.parentRect.setRect(rect)
        self.getRangePoints()
        topRight = self.chart().plotArea().topRight()
        x = int(topRight.x())
        y = int(topRight.y())
        self.BtnsWidget.setGeometry(QRect(x - 420, 0, 420, 23))
        if self.RangeItem.isVisible():
            self.restore_rubber_band()
            self.save_current_rubber_band()
            self.RangeItem.updateHandlesPos()
        else:
            self.RangeItem.setRect(self.parentRect.rect())
            self.RangeItem.show()
            self.RangeItem.setRect(self.parentRect.rect())
            self.save_current_rubber_band()
            self.RangeItem.updateHandlesPos()
        self.apply_nice_numbers()

    # Restore to original positions of rectangles
    def restore_rubber_band(self):
        view_top_left = self.chart_to_view_point(self.m_chartRectF.topLeft())
        view_bottom_right = self.chart_to_view_point(
            self.m_chartRectF.bottomRight())

        self.m_rubberBandOrigin = view_top_left
        height = self.chart().plotArea().height()
        rect = QRectF()
        rect.setTopLeft(view_top_left)
        rect.setBottomRight(view_bottom_right)
        rect.setHeight(height)
        self.RangeItem.setRect(rect)

    # Adjust display coordinates of axes automatically
    def apply_nice_numbers(self):
        axes_list = self.chart().axes()
        for value_axis in axes_list:
            if value_axis:
                pass
Ejemplo n.º 27
0
class TextBoxItem(QGraphicsItem):
    max_rect = QRect(-56, -20, 112, 40)
    init_offset = QPointF(66, -34)
    dummy_contents = 'XX-ABCDE  ####\n##### xxxxx\n10000 = 10000  X####'
    dummy_contents_compact = 'XX-ABCDE\n10000  #### '
    txt_rect_2lines = QRectF()  # STATIC
    txt_rect_3lines = QRectF()  # STATIC

    def setRectanglesFromFont(font):
        TextBoxItem.txt_rect_2lines = QRectF(
            QFontMetrics(font).boundingRect(
                TextBoxItem.max_rect, Qt.AlignLeft,
                TextBoxItem.dummy_contents_compact))
        TextBoxItem.txt_rect_3lines = QRectF(
            QFontMetrics(font).boundingRect(TextBoxItem.max_rect, Qt.AlignLeft,
                                            TextBoxItem.dummy_contents))

    def __init__(self, parent_item):
        QGraphicsItem.__init__(self, parent_item)
        self.radar_contact = parent_item.radar_contact
        self.info_text = ''
        self.rectangle = QRectF()
        self.setCursor(Qt.PointingHandCursor)
        self.setPos(TextBoxItem.init_offset)
        self.mouse_hovering = False
        self.paint_border = True
        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
        self.setAcceptHoverEvents(True)
        self.updateContents()

    def updateContents(self):
        self.prepareGeometryChange()
        expand = self.mouse_hovering or self.radar_contact is selection.acft or env.linkedStrip(
            self.radar_contact) != None
        self.paint_border = expand
        self.info_text = infoTextLines(self.radar_contact, not expand)
        self.rectangle = TextBoxItem.txt_rect_3lines if expand else TextBoxItem.txt_rect_2lines

    def positionQuadrant(self):
        return (1 if self.pos().x() > 0 else -1), (1 if self.pos().y() > 0 else
                                                   -1)

    def calloutConnectingPoint(self):
        q = self.positionQuadrant()
        if q == (-1, -1): return self.rectangle.bottomRight()
        elif q == (-1, 1): return self.rectangle.topRight()
        elif q == (1, -1): return self.rectangle.bottomLeft()
        elif q == (1, 1): return self.rectangle.topLeft()

    def paint(self, painter, option, widget):
        coloured_pen = new_pen(ACFT_pen_colour(self.radar_contact))
        # 1. Write info text
        painter.setPen(coloured_pen)
        painter.drawText(self.rectangle, Qt.AlignLeft | Qt.AlignVCenter,
                         self.info_text)
        # 2. Draw container box?
        if self.paint_border:
            pen = coloured_pen if self.radar_contact is selection.acft else new_pen(
                settings.colour('radar_tag_line'))
            if self.radar_contact.individual_cheat:
                pen.setStyle(Qt.DashLine)
            painter.setPen(pen)
            painter.drawRect(self.rectangle)

    def boundingRect(self):
        return self.rectangle

    # EVENTS

    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemPositionChange:
            self.parentItem().textBoxChanged()
        return QGraphicsItem.itemChange(self, change, value)

    def hoverEnterEvent(self, event):
        self.mouse_hovering = True
        self.updateContents()
        self.parentItem().textBoxChanged()
        QGraphicsItem.hoverEnterEvent(self, event)

    def hoverLeaveEvent(self, event):
        self.mouse_hovering = False
        self.updateContents()
        self.parentItem().textBoxChanged()
        QGraphicsItem.hoverLeaveEvent(self, event)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            selection.selectAircraft(self.radar_contact)
        elif event.button() == Qt.MiddleButton:
            if event.modifiers() & Qt.ShiftModifier:
                selection.unlinkAircraft(self.radar_contact)
            else:
                selection.linkAircraft(self.radar_contact)
            event.accept()
        QGraphicsItem.mousePressEvent(self, event)

    def mouseDoubleClickEvent(self, event):
        if event.button() == Qt.LeftButton:
            if event.modifiers() & Qt.ShiftModifier:  # reset box position
                self.setPos(TextBoxItem.init_offset)
                self.parentItem().textBoxChanged()
            else:
                strip = selection.strip
                if strip != None:
                    signals.stripEditRequest.emit(strip)
            event.accept()
        else:
            QGraphicsItem.mouseDoubleClickEvent(self, event)
Ejemplo n.º 28
0
class PangoBboxGraphic(PangoGraphic):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setFlag(QGraphicsItem.ItemIsSelectable)
        self.fpath = None
        self.rect = QRectF()

    def paint(self, painter, option, widget):
        super().paint(painter, option, widget)
        w = self.dw()
        pen = self.pen()
        pen.setWidth(int(w))
        painter.setPen(pen)

        if not self.force_opaque:
            painter.setOpacity(0.8)
        painter.drawRect(self.rect)

        if self.parentItem() is not None:
            self.paint_text_rect(painter)

        painter.setOpacity(1)
        if option.state & QStyle.State_MouseOver or self.isSelected():
            painter.drawEllipse(self.rect.topLeft(), w, w)
            painter.drawEllipse(self.rect.topRight(), w, w)
            painter.drawEllipse(self.rect.bottomLeft(), w, w)
            painter.drawEllipse(self.rect.bottomRight(), w, w)

    def paint_text_rect(self, painter):
        p = painter.pen()

        font = QFont()
        font.setPointSizeF(self.dw()*3)
        painter.setFont(font)
        painter.setBrush(self.brush())

        fm = QFontMetrics(font)
        w = fm.width(self.parentItem().name)
        h = fm.height()
        br = self.rect.bottomRight()

        text_rect = QRectF(QPointF(br.x()-w, br.y()-h), br)

        if text_rect.width() < self.boundingRect().width()/2 and\
                text_rect.height() < self.boundingRect().height()/2:
            painter.drawRect(text_rect)
            pen = self.pen()
            pen.setColor(QColor("black"))
            painter.setPen(pen)
            painter.drawText(text_rect, Qt.AlignCenter, self.parentItem().name)

        painter.setPen(p)

    def boundingRect(self):
        w = self.dw()
        return self.shape().controlPointRect().adjusted(-w*2, -w*2, w*2, w*2)

    def shape(self):
        path = QPainterPath()
        path.addRect(self.rect)
        return self.shape_from_path(path, self.pen())