Ejemplo n.º 1
0
    def text(self, text: str, pos: QRectF, color: QColor=None, size: int=20, shaded: int=0,
             bold: bool=False,shrinkToFit=10) -> None:
        if not isinstance(text,str):
            text = "{}".format(text)

        self._font.setPointSize(size)
        if bold:
            self._font.setWeight(QFont.Black)
        else:
            self._font.setWeight(QFont.Bold)
        self._painter.setFont(self._font)

        fm = QFontMetrics(self._font)
        if pos.width() == 0:
            pos.setWidth(fm.width(text))
        if pos.height() == 0:
            pos.setHeight(fm.height())

        if size > shrinkToFit:
            #
            if fm.width(text) > pos.width() or fm.height() > pos.height()+2:
                self.text(text,pos,color,size-1,shaded,bold,shrinkToFit)
                return

        if shaded:
            diff = size//4 if isinstance(shaded,bool) and shaded == True else shaded
            self._painter.setPen(self._fgs)
            pos2 = pos.translated(diff, diff)
            self._painter.drawText(pos2, Qt.AlignCenter, text)
        p = QPen(color if color is not None else self._fg)
        self._painter.setPen(p)
        self._painter.drawText(pos, Qt.AlignCenter, text)
Ejemplo n.º 2
0
    def initUI(self):
        # load main ui window
        self.uic = uic.loadUi('main.ui', self)

        gr_rect = QRectF(0, 0, self.rect().width(), 20)
        self.scene = QGraphicsScene(gr_rect)
        self.scene.setBackgroundBrush(Qt.black)

        self.anim = NS_Animate(self.scene,
                               gr_rect.width(), gr_rect.height(),
                               QtGui.QColor.fromRgb(0, 32, 49))

        self.horizontalLayout_anim.addWidget(self.anim.window)

        # self.anim.start()
        self.anim.window.resize(gr_rect.width(), gr_rect.height())
    def validateRect(self, r: QRectF, resizeDirections):

        left = r.left()
        top = r.top()
        right = left + r.width()
        bottom = top + r.height()

        # The qBound() is used for enforcement of the minimum and maximum sizes.
        # It's derived after solving the following inequalities (example is for
        # left-resizing):

        # minWidth <= newWidth <= maxWidth
        # minWidth <= right-newLeft <= maxWidth
        # minWidth-right <= -newLeft <= maxWidth-right
        # right-minWidth >= newLeft >= right-maxWidth

        # Ditto for the other 3 directions.
        def qBound(minVal, current, maxVal):
            return max(min(current, maxVal), minVal)

        if resizeDirections.horizontal == ResizeDirectionHorizontal.Left:
            left = qBound(right - self.maximumSize.width(), left, right - self.minimumSize.width())
        elif resizeDirections.horizontal == ResizeDirectionHorizontal.Right:
            right = qBound(self.minimumSize.width() + left, right, self.maximumSize.width() + left)

        if resizeDirections.vertical == ResizeDirectionVertical.Top:
            top = qBound(bottom - self.maximumSize.height(), top, bottom - self.minimumSize.height())
        elif resizeDirections.vertical == ResizeDirectionVertical.Bottom:
            bottom = qBound(self.minimumSize.height() + top, bottom, self.maximumSize.height() + top)

        return QRectF(left, top, right - left, bottom - top)
Ejemplo n.º 4
0
    def updateSelection(self, event):
        rect = QRectF(self.mStart, event.scenePos()).normalized()
        # Make sure the rect has some contents, otherwise intersects returns False
        rect.setWidth(max(1.0, rect.width()))
        rect.setHeight(max(1.0, rect.height()))
        oldSelection = self.mapScene().selectedObjectItems()
        if (oldSelection.isEmpty()):
            # Allow selecting some map objects only when there aren't any selected
            selectedItems = QSet()
            for item in self.mapScene().items(rect, Qt.IntersectsItemShape, Qt.DescendingOrder, viewTransform(event)):
                if type(item) == MapObjectItem:
                    selectedItems.insert(item)

            newSelection = QSet()
            if (event.modifiers() & (Qt.ControlModifier | Qt.ShiftModifier)):
                newSelection = oldSelection | selectedItems
            else:
                newSelection = selectedItems

            self.mapScene().setSelectedObjectItems(newSelection)
            self.updateHandles()
        else:
            # Update the selected handles
            selectedHandles = QSet()
            for item in self.mapScene().items(rect, Qt.IntersectsItemShape, Qt.DescendingOrder, viewTransform(event)):
                if type(item) == PointHandle:
                    selectedHandles.insert(item)

            if (event.modifiers() & (Qt.ControlModifier | Qt.ShiftModifier)):
                self.setSelectedHandles(self.mSelectedHandles | selectedHandles)
            else:
                self.setSelectedHandles(selectedHandles)
Ejemplo n.º 5
0
class BoxOutline(QGraphicsItem):
    def __init__(self, bg_color):
        super(BoxOutline, self).__init__()
        self.rect = QRectF()
        self.bg_color = bg_color

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

    def boundingRect(self):
        return self.rect

    def paint(self, painter, option, widget=None):
        p = QPen(Qt.black)
        if self.isSelected():
            p.setWidth(5)
            painter.setPen(p)
        else:
            p.setWidth(1)
            painter.setPen(p)
        painter.setBrush(self.bg_color)
        r = self.rect.height() / 8.0
        painter.drawRoundedRect(self.rect, r, r)
Ejemplo n.º 6
0
 def updateSceneRect(self):
     #Is called when there is a change in the scene
     #Update scene size to fit the current layout of the graph
     if not self.lockScene:
         rect = self.itemsBoundingRect()
         rect = QRectF(rect.x() - 50, rect.y() - 50, rect.width() + 100, rect.height() + 100)
         self.setSceneRect(rect)
     else:
         self.lockScene = False
Ejemplo n.º 7
0
 def setNetBoxDimensions(self, rect: QRectF):
     """ Set net box dimensions
     
         The net box is the rectangle that compose the network
         drawn to show the occupy matrix
     """
     self.netRectHeight = rect.height() / self.netRows
     self.netRectWidth = rect.width() / self.netCols
     self.left = rect.left()
     self.top = rect.top()
Ejemplo n.º 8
0
    def wait(self):
        array_data = self._arrayreq.wait()
        rectf = self.rectf
        if array_data.handedness_switched:  # array_data should be of type slicingtools.ProjectedArray
            rectf = QRectF(rectf.height(), rectf.width())

        from PyQt5.QtWidgets import QPainter

        img = QImage(QSize(self.rectf.width(), self.rectf.height()), QImage.Format_ARGB32_Premultiplied)
        img.fill(0xFFFFFFFF)
        p = QPainter(img)
        p.drawImage(0, 0, img)
        DummyItem(self.rectf).paint(p, None)
        return img
Ejemplo n.º 9
0
    def activate_tracker(self, bounds: QtCore.QRectF):
        """
        The main map tells us how large its view is (in terms of the game map) and where it is currently.

        :param bounds:
        """
        # scale to scene width and height
        w = self.scene.width()
        h = self.scene.height()
        bounds = QtCore.QRectF(bounds.x() * w, bounds.y() * h, bounds.width() * w, bounds.height() * h)

        # set bounds of tracker and show
        self.tracker.setRect(bounds)
        self.tracker.show()
Ejemplo n.º 10
0
    def updateSelection(self, pos, modifiers):
        rect = QRectF(self.mStart, pos).normalized()
        # Make sure the rect has some contents, otherwise intersects returns False
        rect.setWidth(max(1.0, rect.width()))
        rect.setHeight(max(1.0, rect.height()))
        selectedItems = QSet()
        for item in self.mapScene().items(rect):
            if type(item) == MapObjectItem:
                selectedItems.insert(item)

        if (modifiers & (Qt.ControlModifier | Qt.ShiftModifier)):
            selectedItems |= self.mapScene().selectedObjectItems()
        else:
            self.setMode(Mode.Resize)
        self.mapScene().setSelectedObjectItems(selectedItems)
Ejemplo n.º 11
0
    def data2scene(self, data2scene):
        self._data2scene = data2scene
        self.scene2data, isInvertible = data2scene.inverted()
        assert isInvertible

        for patchNr in range(self._patchAccessor.patchCount):
            # the patch accessor uses the data coordinate system.
            # because the patch is drawn on the screen, its holds coordinates
            # corresponding to Qt's QGraphicsScene's system, which need to be
            # converted to scene coordinates

            # the image rectangle includes an overlap margin
            imageRectF = data2scene.mapRect(self._patchAccessor.patchRectF(patchNr, self.overlap))

            # the patch rectangle has per default no overlap
            patchRectF = data2scene.mapRect(self._patchAccessor.patchRectF(patchNr, 0))

            # add a little overlap when the overlap_draw setting is
            # activated
            if self._overlap_draw != 0:
                patchRectF = QRectF(
                    patchRectF.x() - self._overlap_draw,
                    patchRectF.y() - self._overlap_draw,
                    patchRectF.width() + 2 * self._overlap_draw,
                    patchRectF.height() + 2 * self._overlap_draw,
                )

            patchRect = QRect(
                round(patchRectF.x()), round(patchRectF.y()), round(patchRectF.width()), round(patchRectF.height())
            )

            # the image rectangles of neighboring patches can overlap
            # slightly, to account for inaccuracies in sub-pixel
            # rendering of many ImagePatch objects
            imageRect = QRect(
                round(imageRectF.x()), round(imageRectF.y()), round(imageRectF.width()), round(imageRectF.height())
            )

            self.imageRectFs[patchNr] = imageRectF
            self.dataRectFs[patchNr] = imageRectF
            self.tileRectFs[patchNr] = patchRectF
            self.imageRects[patchNr] = imageRect
            self.tileRects[patchNr] = patchRect
Ejemplo n.º 12
0
    def setSelected(self, value):
        """
        Sets *value*-th glyph as the selected glyph, or none if *value* is
        None.

        *value* should be less than the number of glyphRecords present in the
        widget.
        """
        self._selected = value
        if self._selected is not None and self._glyphRecordsRects is not None:
            scrollArea = self._scrollArea
            if scrollArea is not None:
                rect = None
                for r, indexRecord in self._glyphRecordsRects.items():
                    if indexRecord == self._selected:
                        rect = QRectF(*r)
                        break
                if rect is not None:
                    center = rect.center()
                    scrollArea.ensureVisible(
                        center.x(), center.y(), .6 * rect.width(), .6 * rect.height())
        self.update()
Ejemplo n.º 13
0
class DummyRasterRequest(object):
    """
    For stupid tests.
    Uses DummyItem, but rasterizes it to turn it into a QImage.
    """
    def __init__(self, arrayreq, rect):
        self.rectf = QRectF(rect)
        self._arrayreq = arrayreq

    def wait(self):
        array_data = self._arrayreq.wait()
        rectf = self.rectf
        if array_data.handedness_switched:  # array_data should be of type slicingtools.ProjectedArray
            rectf = QRectF(rectf.height(), rectf.width())

        from PyQt5.QtWidgets import QPainter
        img = QImage(QSize(self.rectf.width(), self.rectf.height()),
                     QImage.Format_ARGB32_Premultiplied)
        img.fill(0xffffffff)
        p = QPainter(img)
        p.drawImage(0, 0, img)
        DummyItem(self.rectf).paint(p, None)
        return img
Ejemplo n.º 14
0
    def itemChange(self, change, value):
        """ Check, whether the item is out of the scenes bounds """
        if change == QGraphicsItem.ItemPositionChange:
            # get the new position
            newPos = value
            oldRect = self.sceneBoundingRect()
            newRect = QRectF(newPos.x(), newPos.y(), oldRect.width(),
                             oldRect.height())
            sceneRect = QRectF(self.scene().sceneRect())

            # check if the left or right side of the new rect is outside the scenes bounds -> move it back inside
            if newRect.left() < sceneRect.left():
                newPos.setX(sceneRect.left())
            elif newRect.left() + newRect.width() > sceneRect.right():
                newPos.setX(sceneRect.right() - newRect.width())

            # check if the top or bottom side of the new rect is outside the scenes bounds -> move it back inside
            if newRect.bottom() > sceneRect.bottom():
                newPos.setY(sceneRect.bottom() - newRect.height())
            elif newRect.top() < sceneRect.top():
                newPos.setY(sceneRect.top())
            return newPos
        return super(NodeItem, self).itemChange(change, value)
Ejemplo n.º 15
0
class InCheckGraphicsItem(QGraphicsItem):
    def __init__(self, brush, rect):
        super().__init__()
        self.rect = QRectF(rect)
        self.brush = brush

    def boundingRect(self):
        return self.rect

    def paint(self, QPainter, QStyleOptionGraphicsItem, QWidget_widget=None):
        QPainter.setClipRect(self.rect)
        center = QPointF(self.rect.width() / 2, self.rect.height() / 2)
        focalPoint = center
        grad = QRadialGradient(center, float(self.rect.width() * 0.58929),
                               focalPoint)
        col = QColor(bConfig['checkColor'])
        grad.setColorAt(0, col)
        grad.setColorAt(1, self.brush.color())
        col = QColor(bConfig['checkColor'])
        col.setAlphaF(float(bConfig['effectsAlpha']))
        QPainter.setBrush(QBrush(col))
        QPainter.setPen(QPen(Qt.NoPen))
        QPainter.fillRect(self.rect,  grad)
Ejemplo n.º 16
0
    def setSelected(self, value):
        """
        Sets *value*-th glyph as the selected glyph, or none if *value* is
        None.

        *value* should be less than the number of glyphRecords present in the
        widget.
        """
        self._selected = value
        if self._selected is not None and self._glyphRecordsRects is not None:
            scrollArea = self._scrollArea
            if scrollArea is not None:
                rect = None
                for r, indexRecord in self._glyphRecordsRects.items():
                    if indexRecord == self._selected:
                        rect = QRectF(*r)
                        break
                if rect is not None:
                    center = rect.center()
                    scrollArea.ensureVisible(center.x(), center.y(),
                                             0.6 * rect.width(),
                                             0.6 * rect.height())
        self.update()
Ejemplo n.º 17
0
def createRoundRectPath(rectF: QtCore.QRectF, r1: float, r2: float, r3: float,
                        r4: float) -> QtGui.QPainterPath:
    """
    create a rounded rectangle painter path

    :param r1: top left radius
    :param r2: top right radius
    :param r3: bottom right radius
    :param r4: bottom left radius
    """

    r1 *= 2
    r2 *= 2
    r3 *= 2
    r4 *= 2

    path = QtGui.QPainterPath()

    width = rectF.width()
    height = rectF.height()
    x = rectF.x()
    y = rectF.y()

    path.moveTo(x + width - r2, y)
    path.lineTo(x + r1, y)
    path.arcTo(x, y, r1, r1, 90.0, 90.0)
    path.lineTo(x, y + height - r4)
    path.arcTo(x, y + height - r4, r4, r4, 180.0, 90.0)
    path.lineTo(x + width - r3, y + height)
    path.arcTo(x + width - r3, y + height - r3, r3, r3, 270.0, 90.0)
    path.lineTo(x + width, y + r2)
    path.arcTo(x + width - r2, y, r2, r2, 0.0, 90.0)

    path.closeSubpath()

    return path
Ejemplo n.º 18
0
class DummyRasterRequest(object):
    """
    For stupid tests.
    Uses DummyItem, but rasterizes it to turn it into a QImage.
    """

    def __init__(self, arrayreq, rect):
        self.rectf = QRectF(rect)
        self._arrayreq = arrayreq

    def wait(self):
        array_data = self._arrayreq.wait()
        rectf = self.rectf
        if array_data.handedness_switched:  # array_data should be of type slicingtools.ProjectedArray
            rectf = QRectF(rectf.height(), rectf.width())

        from PyQt5.QtWidgets import QPainter

        img = QImage(QSize(self.rectf.width(), self.rectf.height()), QImage.Format_ARGB32_Premultiplied)
        img.fill(0xFFFFFFFF)
        p = QPainter(img)
        p.drawImage(0, 0, img)
        DummyItem(self.rectf).paint(p, None)
        return img
Ejemplo n.º 19
0
    def paintEvent(self, e: QPaintEvent):

        contRect = self.contentsRect()
        handleRadius = round(0.24 * contRect.height())

        p = QPainter(self)
        p.setRenderHint(QPainter.Antialiasing)

        p.setPen(self._transparent_pen)
        barRect = QRectF(0, 0,
                         contRect.width() - handleRadius,
                         0.40 * contRect.height())
        barRect.moveCenter(contRect.center())
        rounding = barRect.height() / 2

        # the handle will move along this line
        trailLength = contRect.width() - 2 * handleRadius
        xPos = contRect.x(
        ) + handleRadius + trailLength * self._handle_position

        if self.isChecked():
            p.setBrush(self._bar_checked_brush)
            p.drawRoundedRect(barRect, rounding, rounding)
            p.setBrush(self._handle_checked_brush)

        else:
            p.setBrush(self._bar_brush)
            p.drawRoundedRect(barRect, rounding, rounding)
            p.setPen(self._light_grey_pen)
            p.setBrush(self._handle_brush)

        p.drawEllipse(QPointF(xPos,
                              barRect.center().y()), handleRadius,
                      handleRadius)

        p.end()
Ejemplo n.º 20
0
    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)
Ejemplo n.º 21
0
class InstantPrintTool(QgsMapTool, InstantPrintDialog):

    def __init__(self, iface, populateCompositionFz=None):
        QgsMapTool.__init__(self, iface.mapCanvas())

        self.iface = iface

        projectInstance = QgsProject.instance()
        self.projectLayoutManager = projectInstance.layoutManager()
        self.rubberband = None
        self.oldrubberband = None
        self.pressPos = None
        self.printer = QPrinter()
        self.mapitem = None
        self.populateCompositionFz = populateCompositionFz

        self.dialog = InstantPrintDialog(self.iface.mainWindow())
        self.dialogui = Ui_InstantPrintDialog()
        self.dialogui.setupUi(self.dialog)
        self.dialogui.addScale.setIcon(QIcon(":/images/themes/default/mActionAdd.svg"))
        self.dialogui.deleteScale.setIcon(QIcon(":/images/themes/default/symbologyRemove.svg"))
        self.dialog.hidden.connect(self.__onDialogHidden)
        self.exportButton = self.dialogui.buttonBox.addButton(self.tr("Export"), QDialogButtonBox.ActionRole)
        self.printButton = self.dialogui.buttonBox.addButton(self.tr("Print"), QDialogButtonBox.ActionRole)
        self.helpButton = self.dialogui.buttonBox.addButton(self.tr("Help"), QDialogButtonBox.HelpRole)
        self.dialogui.comboBox_fileformat.addItem("PDF", self.tr("PDF Document (*.pdf);;"))
        self.dialogui.comboBox_fileformat.addItem("JPG", self.tr("JPG Image (*.jpg);;"))
        self.dialogui.comboBox_fileformat.addItem("BMP", self.tr("BMP Image (*.bmp);;"))
        self.dialogui.comboBox_fileformat.addItem("PNG", self.tr("PNG Image (*.png);;"))
        self.iface.layoutDesignerOpened.connect(lambda view: self.__reloadLayouts())
        self.iface.layoutDesignerWillBeClosed.connect(self.__reloadLayouts)
        self.dialogui.comboBox_layouts.currentIndexChanged.connect(self.__selectLayout)
        self.dialogui.comboBox_scale.lineEdit().textChanged.connect(self.__changeScale)
        self.dialogui.comboBox_scale.scaleChanged.connect(self.__changeScale)
        self.exportButton.clicked.connect(self.__export)
        self.printButton.clicked.connect(self.__print)
        self.helpButton.clicked.connect(self.__help)
        self.dialogui.buttonBox.button(QDialogButtonBox.Close).clicked.connect(lambda: self.dialog.hide())
        self.dialogui.addScale.clicked.connect(self.add_new_scale)
        self.dialogui.deleteScale.clicked.connect(self.remove_scale)
        self.deactivated.connect(self.__cleanup)
        self.setCursor(Qt.OpenHandCursor)

        settings = QSettings()
        if settings.value("instantprint/geometry") is not None:
            self.dialog.restoreGeometry(settings.value("instantprint/geometry"))
        if settings.value("instantprint/scales") is not None:
            for scale in settings.value("instantprint/scales").split(";"):
                if scale:
                    self.retrieve_scales(scale)
        self.check_scales()

    def __onDialogHidden(self):
        self.setEnabled(False)
        self.iface.mapCanvas().unsetMapTool(self)
        QSettings().setValue("instantprint/geometry", self.dialog.saveGeometry())
        list = []
        for i in range(self.dialogui.comboBox_scale.count()):
            list.append(self.dialogui.comboBox_scale.itemText(i))
        QSettings().setValue("instantprint/scales", ";".join(list))

    def retrieve_scales(self, checkScale):
        if self.dialogui.comboBox_scale.findText(checkScale) == -1:
            self.dialogui.comboBox_scale.addItem(checkScale)

    def add_new_scale(self):
        new_layout = self.dialogui.comboBox_scale.currentText()
        if self.dialogui.comboBox_scale.findText(new_layout) == -1:
            self.dialogui.comboBox_scale.addItem(new_layout)
        self.check_scales()

    def remove_scale(self):
        layout_to_delete = self.dialogui.comboBox_scale.currentIndex()
        self.dialogui.comboBox_scale.removeItem(layout_to_delete)
        self.check_scales()

    def setEnabled(self, enabled):
        if enabled:
            self.dialog.setVisible(True)
            self.__reloadLayouts()
            self.iface.mapCanvas().setMapTool(self)
        else:
            self.dialog.setVisible(False)
            self.iface.mapCanvas().unsetMapTool(self)

    def __changeScale(self):
        if not self.mapitem:
            return
        newscale = self.dialogui.comboBox_scale.scale()
        if abs(newscale) < 1E-6:
            return
        extent = self.mapitem.extent()
        center = extent.center()
        newwidth = extent.width() / self.mapitem.scale() * newscale
        newheight = extent.height() / self.mapitem.scale() * newscale
        x1 = center.x() - 0.5 * newwidth
        y1 = center.y() - 0.5 * newheight
        x2 = center.x() + 0.5 * newwidth
        y2 = center.y() + 0.5 * newheight
        self.mapitem.setExtent(QgsRectangle(x1, y1, x2, y2))
        self.__createRubberBand()
        self.check_scales()

    def __selectLayout(self):
        if not self.dialog.isVisible():
            return
        activeIndex = self.dialogui.comboBox_layouts.currentIndex()
        if activeIndex < 0:
            return

        layoutView = self.dialogui.comboBox_layouts.itemData(activeIndex)
        maps = []
        layout_name = self.dialogui.comboBox_layouts.currentText()
        layout = self.projectLayoutManager.layoutByName(layout_name)
        for item in layoutView.items():
            if isinstance(item, QgsLayoutItemMap):
                maps.append(item)
        if len(maps) != 1:
            QMessageBox.warning(self.iface.mainWindow(), self.tr("Invalid layout"), self.tr("The layout must have exactly one map item."))
            self.exportButton.setEnabled(False)
            self.iface.mapCanvas().scene().removeItem(self.rubberband)
            self.rubberband = None
            self.dialogui.comboBox_scale.setEnabled(False)
            return

        self.dialogui.comboBox_scale.setEnabled(True)
        self.exportButton.setEnabled(True)

        self.layoutView = layoutView
        self.mapitem = layout.referenceMap()
        self.dialogui.comboBox_scale.setScale(self.mapitem.scale())
        self.__createRubberBand()

    def __createRubberBand(self):
        self.__cleanup()
        extent = self.mapitem.extent()
        center = self.iface.mapCanvas().extent().center()
        self.corner = QPointF(center.x() - 0.5 * extent.width(), center.y() - 0.5 * extent.height())
        self.rect = QRectF(self.corner.x(), self.corner.y(), extent.width(), extent.height())
        self.mapitem.setExtent(QgsRectangle(self.rect))
        self.rubberband = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PolygonGeometry)
        self.rubberband.setToCanvasRectangle(self.__canvasRect(self.rect))
        self.rubberband.setColor(QColor(127, 127, 255, 127))

        self.pressPos = None

    def __cleanup(self):
        if self.rubberband:
            self.iface.mapCanvas().scene().removeItem(self.rubberband)
        if self.oldrubberband:
            self.iface.mapCanvas().scene().removeItem(self.oldrubberband)
        self.rubberband = None
        self.oldrubberband = None
        self.pressPos = None

    def canvasPressEvent(self, e):
        if not self.rubberband:
            return
        r = self.__canvasRect(self.rect)
        if e.button() == Qt.LeftButton and self.__canvasRect(self.rect).contains(e.pos()):
            self.oldrect = QRectF(self.rect)
            self.oldrubberband = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PolygonGeometry)
            self.oldrubberband.setToCanvasRectangle(self.__canvasRect(self.oldrect))
            self.oldrubberband.setColor(QColor(127, 127, 255, 31))
            self.pressPos = (e.x(), e.y())
            self.iface.mapCanvas().setCursor(Qt.ClosedHandCursor)

    def canvasMoveEvent(self, e):
        if not self.pressPos:
            return
        mup = self.iface.mapCanvas().mapSettings().mapUnitsPerPixel()
        x = self.corner.x() + (e.x() - self.pressPos[0]) * mup
        y = self.corner.y() + (self.pressPos[1] - e.y()) * mup

        snaptol = 10 * mup
        # Left edge matches with old right
        if abs(x - (self.oldrect.x() + self.oldrect.width())) < snaptol:
            x = self.oldrect.x() + self.oldrect.width()
        # Right edge matches with old left
        elif abs(x + self.rect.width() - self.oldrect.x()) < snaptol:
            x = self.oldrect.x() - self.rect.width()
        # Left edge matches with old left
        elif abs(x - self.oldrect.x()) < snaptol:
            x = self.oldrect.x()
        # Bottom edge matches with old top
        if abs(y - (self.oldrect.y() + self.oldrect.height())) < snaptol:
            y = self.oldrect.y() + self.oldrect.height()
        # Top edge matches with old bottom
        elif abs(y + self.rect.height() - self.oldrect.y()) < snaptol:
            y = self.oldrect.y() - self.rect.height()
        # Bottom edge matches with old bottom
        elif abs(y - self.oldrect.y()) < snaptol:
            y = self.oldrect.y()

        self.rect = QRectF(
            x,
            y,
            self.rect.width(),
            self.rect.height()
        )
        self.rubberband.setToCanvasRectangle(self.__canvasRect(self.rect))

    def canvasReleaseEvent(self, e):
        if e.button() == Qt.LeftButton and self.pressPos:
            self.corner = QPointF(self.rect.x(), self.rect.y())
            self.pressPos = None
            self.iface.mapCanvas().setCursor(Qt.OpenHandCursor)
            self.iface.mapCanvas().scene().removeItem(self.oldrubberband)
            self.oldrect = None
            self.oldrubberband = None
            self.mapitem.setExtent(QgsRectangle(self.rect))

    def __canvasRect(self, rect):
        mtp = self.iface.mapCanvas().mapSettings().mapToPixel()
        p1 = mtp.transform(QgsPoint(rect.left(), rect.top()))
        p2 = mtp.transform(QgsPoint(rect.right(), rect.bottom()))
        return QRect(p1.x(), p1.y(), p2.x() - p1.x(), p2.y() - p1.y())

    def __export(self):
        settings = QSettings()
        format = self.dialogui.comboBox_fileformat.itemData(self.dialogui.comboBox_fileformat.currentIndex())
        filepath = QFileDialog.getSaveFileName(
            self.iface.mainWindow(),
            self.tr("Export Layout"),
            settings.value("/instantprint/lastfile", ""),
            format
        )
        if not all(filepath):
            return

        # Ensure output filename has correct extension
        filename = os.path.splitext(filepath[0])[0] + "." + self.dialogui.comboBox_fileformat.currentText().lower()
        settings.setValue("/instantprint/lastfile", filepath[0])

        if self.populateCompositionFz:
            self.populateCompositionFz(self.layoutView.composition())

        success = False
        layout_name = self.dialogui.comboBox_layouts.currentText()
        layout_item = self.projectLayoutManager.layoutByName(layout_name)
        exporter = QgsLayoutExporter(layout_item)
        if filename[-3:].lower() == u"pdf":
            success = exporter.exportToPdf(filepath[0], QgsLayoutExporter.PdfExportSettings())
        else:
            success = exporter.exportToImage(filepath[0], QgsLayoutExporter.ImageExportSettings())
        if success != 0:
            QMessageBox.warning(self.iface.mainWindow(), self.tr("Export Failed"), self.tr("Failed to export the layout."))

    def __print(self):
        layout_name = self.dialogui.comboBox_layouts.currentText()
        layout_item = self.projectLayoutManager.layoutByName(layout_name)
        actual_printer = QgsLayoutExporter(layout_item)

        printdialog = QPrintDialog(self.printer)
        if printdialog.exec_() != QDialog.Accepted:
            return

        success = actual_printer.print(self.printer, QgsLayoutExporter.PrintExportSettings())

        if success != 0:
            QMessageBox.warning(self.iface.mainWindow(), self.tr("Print Failed"), self.tr("Failed to print the layout."))

    def __reloadLayouts(self, removed=None):
        if not self.dialog.isVisible():
            # Make it less likely to hit the issue outlined in https://github.com/qgis/QGIS/pull/1938
            return

        self.dialogui.comboBox_layouts.blockSignals(True)
        prev = None
        if self.dialogui.comboBox_layouts.currentIndex() >= 0:
            prev = self.dialogui.comboBox_layouts.currentText()
        self.dialogui.comboBox_layouts.clear()
        active = 0
        for layout in self.projectLayoutManager.layouts():
            if layout != removed and layout.name():
                cur = layout.name()
                self.dialogui.comboBox_layouts.addItem(cur, layout)
                if prev == cur:
                    active = self.dialogui.comboBox_layouts.count() - 1
        self.dialogui.comboBox_layouts.setCurrentIndex(-1)  # Ensure setCurrentIndex below actually changes an index
        self.dialogui.comboBox_layouts.blockSignals(False)
        if self.dialogui.comboBox_layouts.count() > 0:
            self.dialogui.comboBox_layouts.setCurrentIndex(active)
            self.dialogui.comboBox_scale.setEnabled(True)
            self.exportButton.setEnabled(True)
        else:
            self.exportButton.setEnabled(False)
            self.dialogui.comboBox_scale.setEnabled(False)

    def __help(self):
        manualPath = os.path.join(os.path.dirname(__file__), "help", "documentation.pdf")
        QDesktopServices.openUrl(QUrl.fromLocalFile(manualPath))

    def scaleFromString(self, scaleText):
        locale = QLocale()
        parts = [locale.toInt(part) for part in scaleText.split(":")]
        try:
            if len(parts) == 2 and parts[0][1] and parts[1][1] and parts[0][0] != 0 and parts[1][0] != 0:
                return float(parts[0][0]) / float(parts[1][0])
            else:
                return None
        except ZeroDivisionError:
            return

    def check_scales(self):
        predefScalesStr = QSettings().value("Map/scales", PROJECT_SCALES).split(",")
        predefScales = [self.scaleFromString(scaleString) for scaleString in predefScalesStr]

        comboScalesStr = [self.dialogui.comboBox_scale.itemText(i) for i in range(self.dialogui.comboBox_scale.count())]
        comboScales = [self.scaleFromString(scaleString) for scaleString in comboScalesStr]

        currentScale = self.scaleFromString(self.dialogui.comboBox_scale.currentText())

        if not currentScale:
            self.dialogui.comboBox_scale.lineEdit().setStyleSheet("background: #FF7777; color: #FFFFFF;")
            self.dialogui.addScale.setVisible(True)
            self.dialogui.addScale.setEnabled(False)
            self.dialogui.deleteScale.setVisible(False)
        else:
            self.dialogui.comboBox_scale.lineEdit().setStyleSheet("")
            if currentScale in comboScales:
                # If entry scale is already in the list, allow removing it unless it is a predefined scale
                self.dialogui.addScale.setVisible(False)
                self.dialogui.deleteScale.setVisible(True)
                self.dialogui.deleteScale.setEnabled(currentScale not in predefScales)
            else:
                # Otherwise, show button to add it
                self.dialogui.addScale.setVisible(True)
                self.dialogui.addScale.setEnabled(True)
                self.dialogui.deleteScale.setVisible(False)
Ejemplo n.º 22
0
class Callout(QGraphicsItem):
    def __init__(self, chart):
        super().__init__(chart)

        self.m_chart = chart
        self.m_text = ""
        self.m_textRect = QRectF()
        self.m_rect = QRectF()
        self.m_anchor = QPointF()
        self.m_font = QFont()

    def boundingRect(self):
        anchor = self.mapFromParent(self.m_chart.mapToPosition(self.m_anchor))
        rect = QRectF()
        rect.setLeft(min(self.m_rect.left(), anchor.x()))
        rect.setRight(max(self.m_rect.right(), anchor.x()))
        rect.setTop(min(self.m_rect.top(), anchor.y()))
        rect.setBottom(max(self.m_rect.bottom(), anchor.y()))
        return rect

    def paint(self, painter, option, widget=None):
        path = QPainterPath()
        path.addRoundedRect(self.m_rect, 5, 5)

        anchor = self.mapFromParent(self.m_chart.mapToPosition(self.m_anchor))
        if not self.m_rect.contains(anchor):
            point1 = QPointF()
            point2 = QPointF()

            # establish the position of the anchor point in relation to m_rect
            above = anchor.y() <= self.m_rect.top()
            aboveCenter = (anchor.y() > self.m_rect.top()
                           and anchor.y() <= self.m_rect.center().y())
            belowCenter = (anchor.y() > self.m_rect.center().y()
                           and anchor.y() <= self.m_rect.bottom())
            below = anchor.y() > self.m_rect.bottom()

            onLeft = anchor.x() <= self.m_rect.left()
            leftOfCenter = (anchor.x() > self.m_rect.left()
                            and anchor.x() <= self.m_rect.center().x())
            rightOfCenter = (anchor.x() > self.m_rect.center().x()
                             and anchor.x() <= self.m_rect.right())
            onRight = anchor.x() > self.m_rect.right()

            # get the nearest m_rect corner.
            x = (onRight + rightOfCenter) * self.m_rect.width()
            y = (below + belowCenter) * self.m_rect.height()
            cornerCase = ((above and onLeft) or (above and onRight)
                          or (below and onLeft) or (below and onRight))
            vertical = abs(anchor.x() - x) > abs(anchor.y() - y)

            x1 = (x + leftOfCenter * 10 - rightOfCenter * 20 +
                  cornerCase * int(not vertical) *
                  (onLeft * 10 - onRight * 20))
            y1 = (y + aboveCenter * 10 - belowCenter * 20 +
                  cornerCase * int(vertical) * (above * 10 - below * 20))
            point1.setX(x1)
            point1.setY(y1)

            x2 = (x + leftOfCenter * 20 - rightOfCenter * 10 +
                  cornerCase * int(not vertical) *
                  (onLeft * 20 - onRight * 10))
            y2 = (y + aboveCenter * 20 - belowCenter * 10 +
                  cornerCase * int(vertical) * (above * 20 - below * 10))
            point2.setX(x2)
            point2.setY(y2)

            path.moveTo(point1)
            path.lineTo(anchor)
            path.lineTo(point2)
            path = path.simplified()

        painter.setBrush(QColor(255, 255, 255))
        painter.drawPath(path)
        painter.drawText(self.m_textRect, self.m_text)

    def mousePressEvent(self, event):
        event.setAccepted(True)

    def mouseMoveEvent(self, event):
        if event.buttons() & Qt.LeftButton:
            self.setPos(
                self.mapToParent(event.pos() -
                                 event.buttonDownPos(Qt.LeftButton)))
            event.setAccepted(True)
        else:
            event.setAccepted(False)

    def setText(self, text):
        self.m_text = text
        metrics = QFontMetrics(self.m_font)
        self.m_textRect = QRectF(
            metrics.boundingRect(QRect(0, 0, 150, 150), Qt.AlignLeft,
                                 self.m_text))
        self.m_textRect.translate(5, 5)
        self.prepareGeometryChange()
        self.m_rect = self.m_textRect.adjusted(-5, -5, 5, 5)

    def setAnchor(self, point):
        self.m_anchor = point

    def updateGeometry(self):
        self.prepareGeometryChange()
        self.setPos(
            self.m_chart.mapToPosition(self.m_anchor) + QPoint(10, -50))
Ejemplo n.º 23
0
    def interactiveResize(self, mousePos):
        """
        Handle the interactive resize of the shape.
        :type mousePos: QPointF
        """
        scene = self.scene()
        snap = scene.mainwindow.snapToGrid
        size = scene.GridSize
        offset = self.handleSize + self.handleMove
        moved = self.label.moved

        R = QRectF(self.boundingRect())
        D = QPointF(0, 0)

        minBoundW = self.minwidth + offset * 2
        minBoundH = self.minheight + offset * 2

        self.prepareGeometryChange()

        if self.mousePressHandle == self.handleTL:

            fromX = self.mousePressBound.left()
            fromY = self.mousePressBound.top()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toX = snapF(toX, size, -offset, snap)
            toY = snapF(toY, size, -offset, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() - minBoundW + R.width())
                R.setLeft(R.left() - minBoundW + R.width())
            if R.height() < minBoundH:
                D.setY(D.y() - minBoundH + R.height())
                R.setTop(R.top() - minBoundH + R.height())

            self.background.setLeft(R.left())
            self.background.setTop(R.top())
            self.selection.setLeft(R.left())
            self.selection.setTop(R.top())
            self.polygon.setLeft(R.left() + offset)
            self.polygon.setTop(R.top() + offset)

        elif self.mousePressHandle == self.handleTM:

            fromY = self.mousePressBound.top()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toY = snapF(toY, size, -offset, snap)
            D.setY(toY - fromY)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.height() < minBoundH:
                D.setY(D.y() - minBoundH + R.height())
                R.setTop(R.top() - minBoundH + R.height())

            self.background.setTop(R.top())
            self.selection.setTop(R.top())
            self.polygon.setTop(R.top() + offset)

        elif self.mousePressHandle == self.handleTR:

            fromX = self.mousePressBound.right()
            fromY = self.mousePressBound.top()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toX = snapF(toX, size, +offset, snap)
            toY = snapF(toY, size, -offset, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setTop(toY)

             ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() + minBoundW - R.width())
                R.setRight(R.right() + minBoundW - R.width())
            if R.height() < minBoundH:
                D.setY(D.y() - minBoundH + R.height())
                R.setTop(R.top() - minBoundH + R.height())

            self.background.setRight(R.right())
            self.background.setTop(R.top())
            self.selection.setRight(R.right())
            self.selection.setTop(R.top())
            self.polygon.setRight(R.right() - offset)
            self.polygon.setTop(R.top() + offset)

        elif self.mousePressHandle == self.handleML:

            fromX = self.mousePressBound.left()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toX = snapF(toX, size, -offset, snap)
            D.setX(toX - fromX)
            R.setLeft(toX)

             ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() - minBoundW + R.width())
                R.setLeft(R.left() - minBoundW + R.width())

            self.background.setLeft(R.left())
            self.selection.setLeft(R.left())
            self.polygon.setLeft(R.left() + offset)

        elif self.mousePressHandle == self.handleMR:

            fromX = self.mousePressBound.right()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toX = snapF(toX, size, +offset, snap)
            D.setX(toX - fromX)
            R.setRight(toX)

            ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() + minBoundW - R.width())
                R.setRight(R.right() + minBoundW - R.width())

            self.background.setRight(R.right())
            self.selection.setRight(R.right())
            self.polygon.setRight(R.right() - offset)

        elif self.mousePressHandle == self.handleBL:

            fromX = self.mousePressBound.left()
            fromY = self.mousePressBound.bottom()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toX = snapF(toX, size, -offset, snap)
            toY = snapF(toY, size, +offset, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() - minBoundW + R.width())
                R.setLeft(R.left() - minBoundW + R.width())
            if R.height() < minBoundH:
                D.setY(D.y() + minBoundH - R.height())
                R.setBottom(R.bottom() + minBoundH - R.height())

            self.background.setLeft(R.left())
            self.background.setBottom(R.bottom())
            self.selection.setLeft(R.left())
            self.selection.setBottom(R.bottom())
            self.polygon.setLeft(R.left() + offset)
            self.polygon.setBottom(R.bottom() - offset)

        elif self.mousePressHandle == self.handleBM:

            fromY = self.mousePressBound.bottom()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toY = snapF(toY, size, +offset, snap)
            D.setY(toY - fromY)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.height() < minBoundH:
                D.setY(D.y() + minBoundH - R.height())
                R.setBottom(R.bottom() + minBoundH - R.height())

            self.background.setBottom(R.bottom())
            self.selection.setBottom(R.bottom())
            self.polygon.setBottom(R.bottom() - offset)

        elif self.mousePressHandle == self.handleBR:

            fromX = self.mousePressBound.right()
            fromY = self.mousePressBound.bottom()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toX = snapF(toX, size, +offset, snap)
            toY = snapF(toY, size, +offset, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() + minBoundW - R.width())
                R.setRight(R.right() + minBoundW - R.width())
            if R.height() < minBoundH:
                D.setY(D.y() + minBoundH - R.height())
                R.setBottom(R.bottom() + minBoundH - R.height())

            self.background.setRight(R.right())
            self.background.setBottom(R.bottom())
            self.selection.setRight(R.right())
            self.selection.setBottom(R.bottom())
            self.polygon.setRight(R.right() - offset)
            self.polygon.setBottom(R.bottom() - offset)

        self.updateHandles()
        self.updateTextPos(moved=moved)
        self.updateAnchors(self.mousePressData, D)
class cheeseWidget(QWidget):
    
    def __init__(self,winParent, pose3d):    
        super(cheeseWidget, self).__init__()
        self.winParent=winParent
        self.rectangle = QRectF(0.0, 0.0, 300.0, 300.0)
        self.pose3d = pose3d       

    def drawRedZones(self, painter):
        self.setStyle(painter, QColor(255,70,70),QColor(255,70,70),1)
        startAngle = 0 * 16
        spanAngle = 45 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)
        startAngle = 135 * 16
        spanAngle = 45 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)
        startAngle = 180 * 16
        spanAngle = 180 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)
        
    def drawOrangeZones(self, painter):
        self.setStyle(painter, QColor(255,220,23),QColor(255,220,23),1)
        startAngle = 45 * 16
        spanAngle = 30 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)
        startAngle = 105 * 16
        spanAngle = 30 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)

    def drawGreenZones(self, painter):
        self.setStyle(painter, QColor(117,240,154),QColor(117,240,154),1)
        startAngle = 75 * 16
        spanAngle = 15 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)
        startAngle = 90 * 16
        spanAngle = 15 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)

    def drawArrow(self, painter, angle=90):
        radius = 130
        yawRad = self.pose3d.getYaw()
        angle = -(yawRad + pi/2) # PI/2 para centrar la aguja
        origx = self.rectangle.width() / 2
        origy = self.rectangle.height() / 2
        finx = radius * math.cos(angle) + origx
        finy = radius * math.sin(angle) + origy   
        self.setStyle(painter, Qt.black,Qt.black,3)
        painter.drawLine(QPoint(origx,origy), QPoint(finx,finy))
        painter.drawEllipse(145,145, 10, 10)

    def resetPen(self, painter):
        pen = QPen(Qt.black, 1)
        brush = QBrush()
        painter.setPen(pen)
        painter.setBrush(brush)

    def setStyle(self, painter, fillColor, penColor, stroke):
        brush = QBrush()
        pen = QPen(penColor, stroke)
        brush.setColor(fillColor)
        brush.setStyle(Qt.SolidPattern)
        painter.setBrush(brush)
        painter.setPen(pen)
        painter.setRenderHint(QPainter.Antialiasing)
      
    def paintEvent(self, event):
        painter = QPainter(self)
        self.drawRedZones(painter)
        self.drawOrangeZones(painter)
        self.drawGreenZones(painter)
        self.drawArrow(painter,120)

    def updateG(self):
        self.update()
Ejemplo n.º 25
0
class timeAnalogWidget(QWidget):

    time = pyqtSignal()
    def __init__(self,winParent):
        super(timeAnalogWidget, self).__init__()
        self.winParent=winParent
        self.rectangle = QRectF(0.0, 0.0, 300.0, 300.0)
        self.angle = -pi/2
        self.angleMinutes = -pi/2
        self.seconds = 900
        self.accountant = 0
        self.minutes = 0

        timer = QTimer(self)
        timer.start(1000)
        timer.timeout.connect(self.accountantTime)

    def drawWhiteZones(self, painter):
        self.setStyle(painter, QColor(255,255,255),QColor(255,255,255),1)
        startAngle = 0 * 16
        spanAngle = 360 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)

    def drawCLockLines(self, painter):
        radius = 130
        angle = -pi/2
        for i in range (0, 60):
            origx = self.rectangle.width() / 2 + (radius-1) * math.cos(angle)
            origy = self.rectangle.height() / 2 + (radius-1) * math.sin(angle)
            finx = 6 * math.cos(angle) + origx
            finy = 6 * math.sin(angle) + origy
            self.setStyle(painter, Qt.black,Qt.black,3)
            painter.drawLine(QPoint(origx,origy), QPoint(finx,finy))
            angle = angle + (6*pi/180)


    def drawArrows(self, painter):
        radius = 130
        origx = self.rectangle.width() / 2
        origy = self.rectangle.height() / 2
        finx = radius * math.cos(self.angle) + origx
        finy = radius * math.sin(self.angle) + origy
        finMinutesx = radius/2 * math.cos(self.angleMinutes) + origx
        finMinutesy = radius/2 * math.sin(self.angleMinutes) + origy
        self.setStyle(painter, Qt.black,Qt.black,3)
        painter.drawLine(QPoint(origx,origy), QPoint(finx,finy))
        painter.drawLine(QPoint(origx,origy), QPoint(finMinutesx,finMinutesy))
        painter.drawEllipse(145,145, 10, 10)

    def accountantTime(self):
        if self.accountant < self.seconds:
            self.accountant += 1
            self.angle = self.angle + (6*pi/180)
        if self.accountant % 60 == 0:
            self.minutes += 1
            self.angleMinutes = self.angleMinutes + (6*pi/180)

    def resetPen(self, painter):
        pen = QPen(Qt.black, 1)
        brush = QBrush()
        painter.setPen(pen)
        painter.setBrush(brush)

    def setStyle(self, painter, fillColor, penColor, stroke):
        brush = QBrush()
        pen = QPen(penColor, stroke)
        brush.setColor(fillColor)
        brush.setStyle(Qt.SolidPattern)
        painter.setBrush(brush)
        painter.setPen(pen)
        painter.setRenderHint(QPainter.Antialiasing)

    def paintEvent(self, event):
        painter = QPainter(self)
        self.drawWhiteZones(painter)
        self.drawArrows(painter)
        self.drawCLockLines(painter)

    def updateG(self):
        self.update()
Ejemplo n.º 26
0
class BboxEditor(QObject):
    changed = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self.bbox01 = QRectF()
        self.bboxDrawing = QRect()
        self.color = QColor()
        self.isActive = False
        self.posPress = QPoint()
        self.bbox01Press = QRect()
        self.isDragging = False
        self.prevWheelEventTimestamp = datetime.datetime.now()
        self.scalingMultiplier = 1
        self.targetRatio = 1
        self.stayInside = True

    def setTargetRatio(self, ratio):
        self.targetRatio = ratio
        self.setBbox01(self.bbox01)

    def setStayInside(self, stay):
        self.stayInside = stay
        self.setBbox01(self.bbox01)

    def bbox01KeepInsideDrawingArea(self):
        # r = w0*w / h0*h
        # h0*h = w0*w / r
        # h0 = w0*w / r / h
        w = self.bbox01.width() * self.bboxDrawing.width()
        h = self.bbox01.height() * self.bboxDrawing.height()
        print('bbox01KeepInsideDrawingArea() bboxDrawing:', self.bboxDrawing,
              'w:', w, 'h:', h)
        if h == 0:
            return
        if w / h != self.targetRatio:
            print('bbox01KeepInsideDrawingArea() bbox01 a:', self.bbox01,
                  'targetRatio:', self.targetRatio)
            self.bbox01.setHeight(w / self.targetRatio /
                                  self.bboxDrawing.height())
            print('bbox01KeepInsideDrawingArea() bbox01 b:', self.bbox01)
        if self.stayInside:
            if self.bbox01.width() > 1:
                self.bbox01.setWidth(1)
            if self.bbox01.height() > 1:
                self.bbox01.setHeight(1)
            if self.bbox01.x() < 0:
                self.bbox01.translate(-self.bbox01.x(), 0)
            if self.bbox01.y() < 0:
                self.bbox01.translate(0, -self.bbox01.y())
            if self.bbox01.x() + self.bbox01.width() > 1:
                self.bbox01.translate(
                    1 - (self.bbox01.x() + self.bbox01.width()), 0)
            if self.bbox01.y() + self.bbox01.height() > 1:
                self.bbox01.translate(
                    0, 1 - (self.bbox01.y() + self.bbox01.height()))
        print('bbox01KeepInsideDrawingArea() bbox01 c:', self.bbox01,
              'toPixels:', self.bbox01ToPixels())

    def bbox01ToPixels(self):
        r = QRect(
            self.bboxDrawing.x() + self.bbox01.x() * self.bboxDrawing.width(),
            self.bboxDrawing.y() + self.bbox01.y() * self.bboxDrawing.height(),
            self.bbox01.width() * self.bboxDrawing.width(),
            self.bbox01.width() * self.bboxDrawing.width() / self.targetRatio)
        #self.bbox01.height()*self.bboxDrawing.height())
        print('bbox01ToPixels() r:', r.width(), r.height(), 'bboxDrawing:',
              self.bboxDrawing, 'bbox01:', self.bbox01)
        return r

    def paint(self, qpainter):
        r = self.bbox01ToPixels()
        print('paint() bboxDrawing:', self.bboxDrawing, ' bbox01:',
              self.bbox01, 'r:', r)

        c = self.color
        w = 3 if self.isActive else 1
        #c.setAlpha(255 if self.isActive else 127)

        # Outer white rect
        pen = QPen(QColor(255, 255, 255))
        pen.setWidth(w + 2)
        qpainter.setPen(pen)
        qpainter.drawRect(r)

        # Main colored rect
        pen = QPen(c)
        pen.setWidth(w)
        qpainter.setPen(pen)
        qpainter.drawRect(r)

    def setColor(self, color):
        self.color = color
        self.changed.emit()

    def setDrawingArea(self, qrect):
        self.bboxDrawing = qrect
        self.changed.emit()

    def setBbox01(self, qrect):
        self.bbox01 = qrect
        self.bbox01KeepInsideDrawingArea()
        self.changed.emit()

    def getBbox01(self):
        return self.bbox01

    def setActive(self, active):
        self.isActive = active
        self.changed.emit()

    def mouseMoveEvent(self, e):
        if not self.isActive:
            return
        if self.isDragging:
            diff = e.pos() - self.posPress
            diff01 = QPointF(diff.x() / self.bboxDrawing.width(),
                             diff.y() / self.bboxDrawing.height())
            print('mouseMoveEvent() bbox01:', self.bbox01, 'diff:', diff,
                  'diff01:', diff01)
            self.setBbox01(self.bbox01Press.translated(diff01))

    def mousePressEvent(self, e):
        if not self.isActive:
            return
        bb = self.bbox01ToPixels()
        if (e.pos().x() >= bb.topLeft().x()) and \
         (e.pos().y() >= bb.topLeft().y()) and \
         e.pos().x() <= bb.bottomRight().x() and \
         e.pos().y() <= bb.bottomRight().y() \
         :
            self.isDragging = True
            self.posPress = e.pos()
            self.bbox01Press = self.bbox01

    def mouseReleaseEvent(self, e):
        if not self.isActive:
            return
        self.isDragging = False

    def wheelEvent(self, e):
        if not self.isActive:
            return
        t_diff = (datetime.datetime.now() -
                  self.prevWheelEventTimestamp).total_seconds()
        if t_diff < 0.1:
            self.scalingMultiplier *= 1.5
        else:
            self.scalingMultiplier = 1
        print('wheelEvent() t:', self.prevWheelEventTimestamp, '->',
              datetime.datetime.now(), 't_diff:', t_diff, 'angleDelta:',
              e.angleDelta(), 'scalingMultiplier:', self.scalingMultiplier)
        #sign = -1 if e.angleDelta().y() < 0 else 1
        #scale = 1 + 0.1*sign
        scale = 0.01
        scale *= self.scalingMultiplier
        scale += 1
        if e.angleDelta().y() > 0:
            scale = 1 / scale
        diff_x = (self.bbox01.width() * (1 - scale)) / 2
        diff_y = (self.bbox01.height() * (1 - scale)) / 2
        print('wheelEvent() scale:', scale, 'diff:', diff_x, diff_y)
        self.setBbox01(self.bbox01.adjusted(diff_x, diff_y, -diff_x, -diff_y))
        self.prevWheelEventTimestamp = datetime.datetime.now()

    def getBbox01(self):
        return self.bbox01
Ejemplo n.º 27
0
    def paint(self, painter, xxx, xxx2):
        pos = self.toCanvasCoordinates(self.map_pos)
        self.setPos(pos)

        if self.marker_mode:
            mode = self.config.csettings["canvas_marker_mode"]

            if mode == 'auto':
                self.set_size(20)
                transform = self.canvas.getCoordinateTransform()
                start_point = transform.toMapCoordinates(pos.x(), pos.y())
                map_end_point_width = endpoint(start_point, self.width, 90 + math.degrees(self.heading))
                map_end_point_length = endpoint(start_point, self.length, math.degrees(self.heading))

                # to canvas coordinates
                canvas_end_point_width = self.toCanvasCoordinates(map_end_point_width)
                canvas_end_point_length = self.toCanvasCoordinates(map_end_point_length)

                width = magnitude(self.toCanvasCoordinates(start_point), QgsPointXY(canvas_end_point_width))
                height = magnitude(self.toCanvasCoordinates(start_point), QgsPointXY(canvas_end_point_length))

                if width < self.size and height < self.size:
                    self.changing_scale = self.canvas.scale()
                else:
                    self.changing_scale = self.canvas.scale() * 2

            elif mode == 'manual':
                self.changing_scale = self.config.csettings["canvas_marker_scale"]
        else:
            self.changing_scale = 400

        if self.svg is None or self.canvas.scale() >= self.changing_scale:
            self.set_size(20)
            half_size = self.size / 2.0
            rect = QRectF(0 - half_size, 0 - half_size, self.size, self.size)
            painter.setRenderHint(QPainter.Antialiasing)

            self.pointpen.setColor(Qt.black)
            self.pointpen.setWidth(2)
            self.pointbrush.setColor(self.color)

            painter.setBrush(self.pointbrush)
            painter.setPen(self.pointpen)
            y = 0 - half_size
            x = rect.width() / 2 - half_size
            line = QLine(x, y, x, rect.height() - half_size)
            y = rect.height() / 2 - half_size
            x = 0 - half_size
            line2 = QLine(x, y, rect.width() - half_size, y)

            # Arrow
            p = QPolygonF()
            p.append(QPoint(0 - half_size, 0))
            p.append(QPoint(0, -self.size))
            x = rect.width() - half_size
            p.append(QPoint(x, 0))
            p.append(QPoint(0, 0))

            offsetp = QPolygonF()
            offsetp.append(QPoint(0 - half_size, 0))
            offsetp.append(QPoint(0, -self.size))
            x = rect.width() - half_size
            offsetp.append(QPoint(x, 0))
            offsetp.append(QPoint(0, 0))

            painter.save()
            painter.rotate(math.degrees(self.heading) + self.canvas.rotation())
            if self.orientation:
                path = QPainterPath()
                path.addPolygon(p)
                painter.drawPath(path)
            painter.restore()
            painter.drawEllipse(rect)
            painter.drawLine(line)
            painter.drawLine(line2)

        # svg valid
        elif self.svg is not None and self.svg.isValid():

            # get rotation
            rotation = self.canvas.rotation()

            painter.save()

            transform = self.canvas.getCoordinateTransform()
            start_point = transform.toMapCoordinates(pos.x(), pos.y())
            map_end_point_width = endpoint(start_point, self.width, 90 + math.degrees(self.heading))
            map_end_point_length = endpoint(start_point, self.length, math.degrees(self.heading))

            # to canvas coordinates
            canvas_end_point_width = self.toCanvasCoordinates(map_end_point_width)
            canvas_end_point_length = self.toCanvasCoordinates(map_end_point_length)

            width = magnitude(self.toCanvasCoordinates(start_point), QgsPointXY(canvas_end_point_width))
            height = magnitude(self.toCanvasCoordinates(start_point), QgsPointXY(canvas_end_point_length))

            if width > height:
                self.set_size(width)
            else:
                self.set_size(height)

            if width != 0 and height != 0:
                center_x = width / 2.0
                center_y = height / 2.0
                # work out how to shift the image so that it rotates
                #           properly about its center
                # ( x cos a + y sin a - x, -x sin a + y cos a - y)
                myradians = math.radians(rotation + math.degrees(self.heading))
                xshift = int(((center_x * math.cos(myradians)) +
                              (center_y * math.sin(myradians)))
                             - center_x)
                yshift = int(((-center_x * math.sin(myradians)) +
                              (center_y * math.cos(myradians)))
                             - center_y)

                painter.translate(-width / 2, -height / 2)
                painter.rotate(math.degrees(self.heading) + self.canvas.rotation())
                self.svg.render(painter, QRectF(xshift, yshift, width, height))
            painter.restore()
Ejemplo n.º 28
0
class DomainView(QGraphicsItem):
    """
    The basic and only interactive unit of the view.
    Paints a domain.
    
    We have an `is_selected` variable.
    This is independent and used in lieu of either Qt's selection or the selection on the groot form.   
    """
    def __init__(self, domain: gr.UserDomain, gene_view: "GeneView",
                 positional_index: int,
                 precursor: Optional["DomainView"]) -> None:
        """
        CONSTRUCTOR
        
        :param domain:             Domain to view 
        :param gene_view:              Owning view 
        :param positional_index:        Index of domain within gene 
        :param precursor:               Previous domain, or None 
        """
        assert isinstance(domain, gr.UserDomain)

        #
        # SUPER
        #
        super().__init__()
        self.setZValue(DRAWING.Z_GENE)

        #
        # FIELDS
        #
        self.gene_view = gene_view
        self.model_view = gene_view.model_view
        self.sibling_next: DomainView = None
        self.sibling_previous: DomainView = precursor
        self.domain: gr.UserDomain = domain
        self.mousedown_original_pos: QPointF = None
        self.mousemove_label: str = None
        self.mousemove_snapline: Tuple[int, int] = None
        self.mousedown_move_all = False
        self.index = positional_index
        self.is_selected = False
        self.colour = DRAWING.DEFAULT_COLOUR

        #
        # POSITION
        #
        table = gene_view.model_view.lookup_table
        self.rect = QRectF(0, 0, domain.length * table.letter_size,
                           table.gene_height)

        self.load_state()

        #
        # PRECURSOR
        #
        if precursor:
            precursor.sibling_next = self

        #
        # COMPONENTS
        #
        self.components: List[
            gr.
            Component] = self.model_view.model.components.find_components_for_minor_domain(
                self.domain)

    def get_x_for_site(self, site):
        offset = site - self.domain.start
        offset *= self.model_view.lookup_table.letter_size
        return self.x() + offset

    @property
    def options(self) -> groot.data.config.GlobalOptions:
        return groot.data.config.options()

    @property
    def model(self) -> gr.Model:
        return self.model_view.model

    def load_state(self):
        """
        Loads the state (position and colour) of this domain view from the options.
        If there is no saved state, the default is applied.
        """
        ac = (self.domain.gene.index, self.domain.start)
        position = self.model.lego_domain_positions.get(ac)

        if not isinstance(position, dict):
            self.reset_state()
            return

        x = position.get("x", 0)
        y = position.get("y", 0)
        c = position.get("c", DRAWING.DEFAULT_COLOUR.colour.name())

        self.setPos(x, y)
        self.colour = ColourBlock(QColor(c))

    def save_state(self):
        """
        Saves the state (position) of this domain view to the options.
        """
        ac = (self.domain.gene.index, self.domain.start)
        self.model.lego_domain_positions[ac] = {
            "x": self.pos().x(),
            "y": self.pos().y(),
            "c": self.colour.colour.name()
        }

    def reset_state(self):
        """
        Resets the state (position and colour) of this domain view to the default.
        The reset state is automatically saved to the options.
        """
        table = self.gene_view.model_view.lookup_table
        precursor = self.sibling_previous
        domain = self.domain

        if precursor:
            x = precursor.window_rect().right()
            y = precursor.window_rect().top()
        else:
            x = domain.start * table.letter_size
            y = domain.gene.index * (table.gene_ysep + table.gene_height)

        self.setPos(x, y)
        self.colour = DRAWING.DEFAULT_COLOUR
        self.save_state()

    @override
    def boundingRect(self) -> QRectF:
        return self.rect

    @override
    def paint(self, painter: QPainter, *args, **kwargs):
        """
        Paint the domains
        """
        r = self.rect
        painter.setBrush(self.colour.brush)
        painter.setPen(self.colour.pen)
        painter.drawRect(r)

        is_selected = self.is_selected

        # Movement is allowed if we have enabled it
        move_enabled = misc_helper.coalesce(
            self.options.lego_move_enabled,
            self.gene_view.model_view.user_move_enabled)

        # Draw the piano roll unless we're moving
        if self.options.lego_view_piano_roll is False or move_enabled:
            draw_piano_roll = False
        elif self.options.lego_view_piano_roll is None:
            draw_piano_roll = is_selected
        else:
            draw_piano_roll = not is_selected

        # Draw the selection bars, unless the piano roll is indicative of this already
        draw_sel_bars = is_selected and not draw_piano_roll

        # Selection bars
        # (A blue box inside the gene box)
        if draw_sel_bars:
            self.__paint_selection_rect(painter)

        # Movement bars
        # (The same as the selection bars but dotted in red and cyan)
        if move_enabled and is_selected:
            self.__paint_movement_rect(painter)

        # Piano roll
        # (A piano roll for genes)
        if draw_piano_roll:
            lookup_table = self.model_view.lookup_table
            letter_size = lookup_table.letter_size
            painter.setPen(Qt.NoPen)
            painter.setBrush(
                DRAWING.PIANO_ROLL_SELECTED_BACKGROUND
                if is_selected else DRAWING.PIANO_ROLL_UNSELECTED_BACKGROUND)
            OFFSET_X = letter_size
            rect_width = self.rect.width()
            rect_height = lookup_table.count * letter_size
            painter.drawRect(0, OFFSET_X, rect_width, rect_height)

            array = self.domain.site_array

            if not array:
                painter.setPen(Pens.RED)
                painter.drawLine(0, 0, rect_width, rect_height)
                painter.drawLine(0, rect_height, rect_width, 0)
            else:
                for i, c in enumerate(array):
                    pos = lookup_table.letter_order_table.get(c)

                    if pos is not None:
                        painter.setPen(
                            lookup_table.letter_colour_table.get(
                                c, DRAWING.GENE_DEFAULT_FG))
                        painter.drawEllipse(i * letter_size,
                                            pos * letter_size + OFFSET_X,
                                            letter_size, letter_size)

        # Snap-lines, when moving
        if self.mousemove_snapline:
            x = self.mousemove_snapline[0] - self.pos().x()
            y = self.mousemove_snapline[1] - self.pos().y()
            painter.setPen(DRAWING.SNAP_LINE_2)
            painter.drawLine(x, self.boundingRect().height() / 2, x, y)
            painter.setPen(DRAWING.SNAP_LINE)
            painter.drawLine(x, self.boundingRect().height() / 2, x, y)
            if not self.mousemove_label.startswith("<"):
                x -= QFontMetrics(painter.font()).width(self.mousemove_label)

            if y < 0:
                y = self.rect.top() - DRAWING.TEXT_MARGIN
            else:
                y = self.rect.bottom() + DRAWING.TEXT_MARGIN + QFontMetrics(
                    painter.font()).xHeight()
            painter.setPen(DRAWING.TEXT_LINE)
            painter.drawText(QPointF(x, y),
                             self.mousemove_label)  # Mouse snapline position
        elif self.mousemove_label:
            painter.setPen(DRAWING.TEXT_LINE)
            painter.drawText(
                QPointF(self.rect.left() + DRAWING.TEXT_MARGIN,
                        self.rect.top() - DRAWING.TEXT_MARGIN),
                self.mousemove_label)  # Mouse position

        if not move_enabled:
            # Positions (when not in move mode)
            if misc_helper.coalesce(self.options.lego_view_positions,
                                    is_selected):
                # Draw position
                if self.sibling_previous is None or self.sibling_next is None or self.sibling_previous.rect.width(
                ) > 32:
                    self.__draw_position(painter)

            # Domains (when not in move mode)
            if misc_helper.coalesce(self.options.lego_view_components,
                                    is_selected):
                self.__draw_component_name(painter)

    def __draw_component_name(self, painter: QPainter):
        text = ", ".join(str(x) for x in self.components)
        x = (self.rect.left() + self.rect.right()) / 2 - QFontMetrics(
            painter.font()).width(text) / 2
        y = self.rect.top() - DRAWING.TEXT_MARGIN

        painter.setPen(DRAWING.COMPONENT_PEN)
        painter.setBrush(0)
        painter.drawText(QPointF(x, y), text)

    def __draw_position(self, painter: QPainter):
        text = str(self.domain.start)
        lx = self.rect.left() - QFontMetrics(painter.font()).width(text) / 2

        painter.setPen(DRAWING.POSITION_TEXT)
        painter.drawText(QPointF(lx,
                                 self.rect.top() - DRAWING.TEXT_MARGIN), text)

    def __paint_movement_rect(self, painter: QPainter):
        r = self.rect
        MARGIN = 4
        painter.setBrush(0)
        painter.setPen(DRAWING.MOVE_LINE)
        painter.drawRect(r.left() + MARGIN,
                         r.top() + MARGIN,
                         r.width() - MARGIN * 2,
                         r.height() - MARGIN * 2)
        painter.setPen(DRAWING.MOVE_LINE_SEL)
        painter.drawRect(r.left() + MARGIN,
                         r.top() + MARGIN,
                         r.width() - MARGIN * 2,
                         r.height() - MARGIN * 2)
        # Black start/end when in movement mode if domain isn't adjacent to its siblings
        if self.sibling_next and self.sibling_next.window_rect().left(
        ) != self.window_rect().right():
            MARGIN = 8
            painter.setPen(DRAWING.DISJOINT_LINE)
            painter.drawLine(r.right(),
                             r.top() - MARGIN, r.right(),
                             r.bottom() + MARGIN)
        if self.sibling_previous and self.sibling_previous.window_rect().right(
        ) != self.window_rect().left():
            MARGIN = 8
            painter.setPen(DRAWING.DISJOINT_LINE)
            painter.drawLine(r.left(),
                             r.top() - MARGIN, r.left(),
                             r.bottom() + MARGIN)

    def __paint_selection_rect(self, painter: QPainter):
        r = self.rect
        MARGIN = 4
        painter.setBrush(0)
        painter.setPen(DRAWING.SELECTION_LINE)
        painter.drawRect(r.left() + MARGIN,
                         r.top() + MARGIN,
                         r.width() - MARGIN * 2,
                         r.height() - MARGIN * 2)

    def __is_draw_position(self, is_selected):
        return misc_helper.coalesce(self.options.lego_view_positions,
                                    is_selected)

    def __draw_next_sibling_position(self, is_selected):
        ns = self.sibling_next

        if ns is None:
            return False

        if not ns.__is_draw_position(is_selected):
            return False

        return ns.pos().x() == self.window_rect().right()

    def window_rect(self) -> QRectF:
        result = self.boundingRect().translated(self.scenePos())
        assert result.left() == self.pos().x(), "{} {}".format(
            self.window_rect().left(),
            self.pos().x())  # todo: remove
        assert result.top() == self.pos().y()
        return result

    def mousePressEvent(self, m: QGraphicsSceneMouseEvent):
        """
        OVERRIDE
        Mouse press on domain view
        i.e. Use clicks a domain
        """
        if m.buttons() & Qt.LeftButton:
            # Remember the initial position items in case we drag stuff
            # - do this for all items because it's still possible for the selection to change post-mouse-down
            for item in self.gene_view.domain_views.values():
                item.mousedown_original_pos = item.pos()

            # If ctrl or meta is down, add to the selection
            if (m.modifiers() & Qt.ControlModifier) or (m.modifiers()
                                                        & Qt.MetaModifier):
                toggle = True
            else:
                toggle = False

            if self.is_selected:
                # If we are selected stop, this confuses with dragging from a design perspective
                return

            self.model_view.handle_domain_clicked(self.domain, toggle)

    def mouseDoubleClickEvent(self, m: QGraphicsSceneMouseEvent):
        """
        OVERRIDE
        Double click
        Just toggles "move enabled" 
        """
        self.model_view.user_move_enabled = not self.model_view.user_move_enabled
        self.model_view.scene.setBackgroundBrush(QBrush(QColor(255, 255, 0)))
        self.model_view.scene.update()

    def focusInEvent(self, QFocusEvent):
        self.setZValue(DRAWING.Z_FOCUS)

    def focusOutEvent(self, QFocusEvent):
        self.setZValue(DRAWING.Z_GENE)

    def snaps(self):
        for gene_view in self.gene_view.model_view.gene_views.values():
            for domain_view in gene_view.domain_views.values():
                if domain_view is not self:
                    left_snap = domain_view.scenePos().x()
                    right_snap = domain_view.scenePos().x(
                    ) + domain_view.boundingRect().width()
                    yield left_snap, "Start of {}[{}]".format(
                        domain_view.domain.gene,
                        domain_view.domain.start), domain_view.scenePos().y()
                    yield right_snap, "End of {}[{}]".format(
                        domain_view.domain.gene,
                        domain_view.domain.end), domain_view.scenePos().y()

    def mouseMoveEvent(self, m: QGraphicsSceneMouseEvent) -> None:
        if m.buttons() & Qt.LeftButton:
            if not misc_helper.coalesce(
                    self.options.lego_move_enabled, self.model_view.
                    user_move_enabled) or self.mousedown_original_pos is None:
                return

            new_pos: QPointF = self.mousedown_original_pos + (
                m.scenePos() - m.buttonDownScenePos(Qt.LeftButton))
            new_x = new_pos.x()
            new_y = new_pos.y()
            new_x2 = new_x + self.boundingRect().width()

            self.mousemove_label = "({0} {1})".format(new_pos.x(), new_pos.y())
            self.mousemove_snapline = None

            x_snap_enabled = misc_helper.coalesce(
                self.options.lego_x_snap,
                not bool(m.modifiers() & Qt.ControlModifier))
            y_snap_enabled = misc_helper.coalesce(
                self.options.lego_y_snap,
                not bool(m.modifiers() & Qt.AltModifier))

            if x_snap_enabled:
                for snap_x, snap_label, snap_y in self.snaps():
                    if (snap_x - 8) <= new_x <= (snap_x + 8):
                        new_x = snap_x
                        self.mousemove_label = "<-- " + snap_label
                        self.mousemove_snapline = snap_x, snap_y
                        break
                    elif (snap_x - 8) <= new_x2 <= (snap_x + 8):
                        new_x = snap_x - self.boundingRect().width()
                        self.mousemove_label = snap_label + " -->"
                        self.mousemove_snapline = snap_x, snap_y
                        break

            if y_snap_enabled:
                ysep = self.rect.height()
                yy = (self.rect.height() + ysep)
                new_y += yy / 2
                new_y = new_y - new_y % yy

            new_pos.setX(new_x)
            new_pos.setY(new_y)

            self.setPos(new_pos)
            self.save_state()

            delta_x = new_x - self.mousedown_original_pos.x()
            delta_y = new_y - self.mousedown_original_pos.y()

            selected_items = self.model_view.get_selected_userdomain_views()

            for selected_item in selected_items:
                if selected_item is not self and selected_item.mousedown_original_pos is not None:
                    selected_item.setPos(
                        selected_item.mousedown_original_pos.x() + delta_x,
                        selected_item.mousedown_original_pos.y() + delta_y)
                    selected_item.save_state()

            self.model_view.overlay_view.update()

    def mouseReleaseEvent(self, m: QGraphicsSceneMouseEvent):
        self.mousemove_label = None
        self.mousemove_snapline = None
        self.update()
        pass  # suppress default mouse handling implementation

    def __repr__(self):
        return "<<View of '{}' at ({},{})>>".format(self.domain,
                                                    self.window_rect().left(),
                                                    self.window_rect().top())
Ejemplo n.º 29
0
    def draw(self, painter, draw=True):
        if draw:
            painter.save()
        painter.setOpacity(self.opacity)
        if draw and self.renderer is not None:
            # if self.img is not None:
            #     qsource = QRectF(0,0,self.img.get_width(), self.img.get_height())
            #     painter.drawImage(self, self.qimage , qsource) # , flags=QtCore.Qt.AutoColor
            # else:
            #     painter.drawRect(self)

            # print('size of drawing', self)

            # print('view box',self.renderer.viewBoxF())

            # viewbox = self.renderer.viewBoxF()

            # --> vraiment presque ça
            # does not really work
            neo = QRectF(self)
            # neo.setX(self.x()-10)
            # neo.setY(self.y()-10)
            # neo.setHeight(self.height()+30)
            # neo.setWidth(self.width()+30)

            # nb this will create a shear if one dim is not cropped as the other --> really not great in fact maybe deactivate for now ???? or compute AR and adapt it
            # TODO just warn that it's buggy and should not be used for SVG files only, ok for other stuff though

            # can I preserve AR ???

            if self.__crop_left is not None:
                neo.setX(neo.x() - self.__crop_left)
                neo.setWidth(neo.width() + self.__crop_left)
            if self.__crop_top is not None:
                neo.setY(neo.y() - self.__crop_top)
                neo.setHeight(neo.height() + self.__crop_top)
            if self.__crop_bottom is not None:
                neo.setHeight(neo.height() + self.__crop_bottom)
            if self.__crop_right is not None:
                neo.setWidth(neo.width() + self.__crop_right)

            # maintenant ça a l'air bon...

            # --> ça c'est ok --> c'est le clip rect qui merde du coup

            # print('view box neo', neo)
            # self.renderer.setViewBox(neo)
            # le clipping marche mais faut le combiner avec autre chose
            # painter.setClipRect(self.x()+10, self.y()+10, self.width()-30,self.height()-30)#, Qt::ClipOperation operation = Qt::ReplaceClip

            # TODO KEEP UNFORTUNATELY  unfortunately cropping does not work when saved as svg but works when saved as raster... see https://bugreports.qt.io/browse/QTBUG-28636
            # maybe do masque d'ecretage in illustrator or inkscape https://linuxgraphic.org/forums/viewtopic.php?f=6&t=6437
            # TODO KEEP IT PROBABLY ALSO CREATES A ZOOM THAT WILL MESS WITH THE FONTS AND LINE SIZE...
            painter.setClipRect(self)  # , Qt::ClipOperation operation = Qt::ReplaceClip , operation=Qt.ReplaceClip

            self.renderer.render(painter, neo)  # the stuff is a qrectf so that should work

            painter.restore()
            # self.renderer.setViewBox(viewbox)

        # then need to draw the letter
        if self.letter is not None:
            self.letter.set_P1(self.get_P1())
            self.letter.draw(painter)

        if self.annotation is not None and self.annotation:
            for annot in self.annotation:
                annot.draw(draw=draw)
Ejemplo n.º 30
0
class MainWindow(QQuickWindow):
    def __init__(self, parent = None):
        super(MainWindow, self).__init__(parent)

        self._background_color = QColor(204, 204, 204, 255)

        self.setClearBeforeRendering(False)
        self.beforeRendering.connect(self._render, type = Qt.DirectConnection)

        self._mouse_device = QtMouseDevice(self)
        self._mouse_device.setPluginId("qt_mouse")
        self._key_device = QtKeyDevice()
        self._key_device.setPluginId("qt_key")
        self._previous_focus = None  # type: Optional["QQuickItem"]

        self._app = QCoreApplication.instance()

        # Remove previously added input devices (if any). This can happen if the window was re-loaded.
        self._app.getController().removeInputDevice("qt_mouse")
        self._app.getController().removeInputDevice("qt_key")

        self._app.getController().addInputDevice(self._mouse_device)
        self._app.getController().addInputDevice(self._key_device)
        self._app.getController().getScene().sceneChanged.connect(self._onSceneChanged)
        self._preferences = Application.getInstance().getPreferences()

        self._preferences.addPreference("general/window_width", 1280)
        self._preferences.addPreference("general/window_height", 720)
        self._preferences.addPreference("general/window_left", 50)
        self._preferences.addPreference("general/window_top", 50)
        self._preferences.addPreference("general/window_state", Qt.WindowNoState)

        # Restore window geometry
        self.setWidth(int(self._preferences.getValue("general/window_width")))
        self.setHeight(int(self._preferences.getValue("general/window_height")))
        self.setPosition(int(self._preferences.getValue("general/window_left")), int(self._preferences.getValue("general/window_top")))

        # Make sure restored geometry is not outside the currently available screens
        screen_found = False
        for s in range(0, self._app.desktop().screenCount()):
            if self.geometry().intersects(self._app.desktop().availableGeometry(s)):
                screen_found = True
                break
        if not screen_found:
            self.setPosition(50, 50)

        self.setWindowState(int(self._preferences.getValue("general/window_state")))
        self._mouse_x = 0
        self._mouse_y = 0

        self._mouse_pressed = False

        self._viewport_rect = QRectF(0, 0, 1.0, 1.0)

        self.closing.connect(self.preClosing)

        Application.getInstance().setMainWindow(self)
        self._fullscreen = False

        self._allow_resize = True

    # This event is triggered before hideEvent(self, event) event and might prevent window closing if
    # does not pass the check, for example if USB printer is printing
    # The implementation is in Cura.qml
    preClosing = pyqtSignal("QQuickCloseEvent*", arguments = ["close"])

    def setAllowResize(self, allow_resize: bool):
        if self._allow_resize != allow_resize:
            if not allow_resize:
                self.setMaximumHeight(self.height())
                self.setMinimumHeight(self.height())
                self.setMaximumWidth(self.width())
                self.setMinimumWidth(self.width())
            else:
                self.setMaximumHeight(16777215)
                self.setMinimumHeight(0)
                self.setMaximumWidth(16777215)
                self.setMinimumWidth(0)
            self._allow_resize = allow_resize

    @pyqtSlot()
    def toggleFullscreen(self):
        if self._fullscreen:
            self.setVisibility(QQuickWindow.Windowed)  # Switch back to windowed
        else:
            self.setVisibility(QQuickWindow.FullScreen)  # Go to fullscreen
        self._fullscreen = not self._fullscreen

    def getBackgroundColor(self):
        return self._background_color

    def setBackgroundColor(self, color):
        self._background_color = color
        self._app.getRenderer().setBackgroundColor(color)

    backgroundColor = pyqtProperty(QColor, fget=getBackgroundColor, fset=setBackgroundColor)

    mousePositionChanged = pyqtSignal()

    @pyqtProperty(int, notify = mousePositionChanged)
    def mouseX(self):
        return self._mouse_x

    @pyqtProperty(int, notify = mousePositionChanged)
    def mouseY(self):
        return self._mouse_y

    def setViewportRect(self, rect):
        if rect != self._viewport_rect:
            self._viewport_rect = rect
            self._updateViewportGeometry(self.width() * self.devicePixelRatio(), self.height() * self.devicePixelRatio())
            self.viewportRectChanged.emit()

    viewportRectChanged = pyqtSignal()

    @pyqtProperty(QRectF, fset = setViewportRect, notify = viewportRectChanged)
    def viewportRect(self):
        return self._viewport_rect

#   Warning! Never reimplemented this as a QExposeEvent can cause a deadlock with QSGThreadedRender due to both trying
#   to claim the Python GIL.
#   def event(self, event):

    def mousePressEvent(self, event):
        super().mousePressEvent(event)
        if event.isAccepted():
            return

        if self.activeFocusItem() is not None and self.activeFocusItem() != self._previous_focus:
            self.activeFocusItem().setFocus(False)

        self._previous_focus = self.activeFocusItem()
        self._mouse_device.handleEvent(event)
        self._mouse_pressed = True

    def mouseMoveEvent(self, event):
        self._mouse_x = event.x()
        self._mouse_y = event.y()

        if self._mouse_pressed:
            self.mousePositionChanged.emit()

        super().mouseMoveEvent(event)
        if event.isAccepted():
            return

        self._mouse_device.handleEvent(event)

    def mouseReleaseEvent(self, event):
        super().mouseReleaseEvent(event)
        if event.isAccepted():
            return
        self._mouse_device.handleEvent(event)
        self._mouse_pressed = False

    def keyPressEvent(self, event):
        super().keyPressEvent(event)
        if event.isAccepted():
            return

        self._key_device.handleEvent(event)

    def keyReleaseEvent(self, event):
        super().keyReleaseEvent(event)
        if event.isAccepted():
            return

        self._key_device.handleEvent(event)

    def wheelEvent(self, event):
        super().wheelEvent(event)
        if event.isAccepted():
            return

        self._mouse_device.handleEvent(event)

    def moveEvent(self, event):
        QMetaObject.invokeMethod(self, "_onWindowGeometryChanged", Qt.QueuedConnection)

    def resizeEvent(self, event):
        super().resizeEvent(event)

        win_w = event.size().width() * self.devicePixelRatio()
        win_h = event.size().height() * self.devicePixelRatio()

        self._updateViewportGeometry(win_w, win_h)

        QMetaObject.invokeMethod(self, "_onWindowGeometryChanged", Qt.QueuedConnection)

    def hideEvent(self, event):
        if Application.getInstance().getMainWindow() == self:
            Application.getInstance().windowClosed()

    renderCompleted = Signal(type = Signal.Queued)

    def _render(self):
        renderer = self._app.getRenderer()
        view = self._app.getController().getActiveView()

        renderer.beginRendering()
        view.beginRendering()
        renderer.render()
        view.endRendering()
        renderer.endRendering()
        self.renderCompleted.emit()

    def _onSceneChanged(self, object):
        self.update()

    @pyqtSlot()
    def _onWindowGeometryChanged(self):
        self._preferences.setValue("general/window_width", self.width())
        self._preferences.setValue("general/window_height", self.height())
        self._preferences.setValue("general/window_left", self.x())
        self._preferences.setValue("general/window_top", self.y())
        # This is a workaround for QTBUG-30085
        if self.windowState() in (Qt.WindowNoState, Qt.WindowMaximized):
            self._preferences.setValue("general/window_state", self.windowState())

    def _updateViewportGeometry(self, width: int, height: int):
        view_width = width * self._viewport_rect.width()
        view_height = height * self._viewport_rect.height()

        for camera in self._app.getController().getScene().getAllCameras():
            camera.setWindowSize(width, height)

            if camera.getAutoAdjustViewPort():
                camera.setViewportSize(view_width, view_height)
                projection_matrix = Matrix()
                if camera.isPerspective():
                    if view_width is not 0:
                        projection_matrix.setPerspective(30, view_width / view_height, 1, 500)
                else:
                    projection_matrix.setOrtho(-view_width / 2, view_width / 2, -view_height / 2, view_height / 2, -500, 500)
                camera.setProjectionMatrix(projection_matrix)

        self._app.getRenderer().setViewportSize(view_width, view_height)
        self._app.getRenderer().setWindowSize(width, height)
Ejemplo n.º 31
0
class DesignItem(QGraphicsItem):
    positionChanged = pyqtSignal(int, int)

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

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

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

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

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

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

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

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

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

    def boundingRect(self):
        return self.rect

    def isSceneRect(self):
        return self.is_scene_rect

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

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

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

    def scaleObjects(self):
        pass

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        # trick to repaint item
        self.setSelected(False)
        self.setSelected(True)
Ejemplo n.º 32
0
class MainWindow(QQuickWindow):
    def __init__(self, parent = None):
        super(MainWindow, self).__init__(parent)

        self._background_color = QColor(204, 204, 204, 255)

        self.setClearBeforeRendering(False)
        self.beforeRendering.connect(self._render, type=Qt.DirectConnection)

        self._mouse_device = QtMouseDevice(self)
        self._mouse_device.setPluginId("qt_mouse")
        self._key_device = QtKeyDevice()
        self._key_device.setPluginId("qt_key")
        self._previous_focus = None

        self._app = QCoreApplication.instance()
        self._app.getController().addInputDevice(self._mouse_device)
        self._app.getController().addInputDevice(self._key_device)
        self._app.getController().getScene().sceneChanged.connect(self._onSceneChanged)
        self._preferences = Preferences.getInstance()

        self._preferences.addPreference("general/window_width", 1280)
        self._preferences.addPreference("general/window_height", 720)
        self._preferences.addPreference("general/window_left", 50)
        self._preferences.addPreference("general/window_top", 50)
        self._preferences.addPreference("general/window_state", Qt.WindowNoState)

        # Restore window geometry
        self.setWidth(int(self._preferences.getValue("general/window_width")))
        self.setHeight(int(self._preferences.getValue("general/window_height")))
        self.setPosition(int(self._preferences.getValue("general/window_left")), int(self._preferences.getValue("general/window_top")))
        # Make sure restored geometry is not outside the currently available screens
        if not self.geometry().intersects(self.screen().availableGeometry()):
            self.setPosition(50,50)

        self.setWindowState(int(self._preferences.getValue("general/window_state")))
        self._mouse_x = 0
        self._mouse_y = 0

        self._viewport_rect = QRectF(0, 0, 1.0, 1.0)

        Application.getInstance().setMainWindow(self)
        self._fullscreen = False

    @pyqtSlot()
    def toggleFullscreen(self):
        if self._fullscreen:
            self.setVisibility(QQuickWindow.Windowed) # Switch back to windowed
        else:
            self.setVisibility(QQuickWindow.FullScreen) # Go to fullscreen
        self._fullscreen = not self._fullscreen

    def getBackgroundColor(self):
        return self._background_color

    def setBackgroundColor(self, color):
        self._background_color = color
        self._app.getRenderer().setBackgroundColor(color)

    backgroundColor = pyqtProperty(QColor, fget=getBackgroundColor, fset=setBackgroundColor)

    mousePositionChanged = pyqtSignal()

    @pyqtProperty(int, notify = mousePositionChanged)
    def mouseX(self):
        return self._mouse_x

    @pyqtProperty(int, notify = mousePositionChanged)
    def mouseY(self):
        return self._mouse_y

    def setViewportRect(self, rect):
        if rect != self._viewport_rect:
            self._viewport_rect = rect
            self._updateViewportGeometry(self.width() * self.devicePixelRatio(), self.height() * self.devicePixelRatio())
            self.viewportRectChanged.emit()

    viewportRectChanged = pyqtSignal()

    @pyqtProperty(QRectF, fset = setViewportRect, notify = viewportRectChanged)
    def viewportRect(self):
        return self._viewport_rect

#   Warning! Never reimplemented this as a QExposeEvent can cause a deadlock with QSGThreadedRender due to both trying
#   to claim the Python GIL.
#   def event(self, event):

    def mousePressEvent(self, event):
        super().mousePressEvent(event)
        if event.isAccepted():
            return

        if self.activeFocusItem() != None and self.activeFocusItem() != self._previous_focus:
            self.activeFocusItem().setFocus(False)

        self._previous_focus = self.activeFocusItem()
        self._mouse_device.handleEvent(event)

    def mouseMoveEvent(self, event):
        self._mouse_x = event.x()
        self._mouse_y = event.y()
        self.mousePositionChanged.emit()

        super().mouseMoveEvent(event)
        if event.isAccepted():
            return

        self._mouse_device.handleEvent(event)

    def mouseReleaseEvent(self, event):
        super().mouseReleaseEvent(event)
        if event.isAccepted():
            return
        self._mouse_device.handleEvent(event)

    def keyPressEvent(self, event):
        super().keyPressEvent(event)
        if event.isAccepted():
            return

        self._key_device.handleEvent(event)

    def keyReleaseEvent(self, event):
        super().keyReleaseEvent(event)
        if event.isAccepted():
            return

        self._key_device.handleEvent(event)

    def wheelEvent(self, event):
        super().wheelEvent(event)
        if event.isAccepted():
            return

        self._mouse_device.handleEvent(event)

    def moveEvent(self, event):
        QMetaObject.invokeMethod(self, "_onWindowGeometryChanged", Qt.QueuedConnection);

    def resizeEvent(self, event):
        super().resizeEvent(event)

        win_w = event.size().width() * self.devicePixelRatio()
        win_h = event.size().height() * self.devicePixelRatio()

        self._updateViewportGeometry(win_w, win_h)

        QMetaObject.invokeMethod(self, "_onWindowGeometryChanged", Qt.QueuedConnection);

    def hideEvent(self, event):
        Application.getInstance().windowClosed()

    def _render(self):
        renderer = self._app.getRenderer()
        view = self._app.getController().getActiveView()

        renderer.beginRendering()
        view.beginRendering()
        renderer.render()
        view.endRendering()
        renderer.endRendering()

    def _onSceneChanged(self, object):
        self.update()

    @pyqtSlot()
    def _onWindowGeometryChanged(self):
        if self.windowState() == Qt.WindowNoState:
            self._preferences.setValue("general/window_width", self.width())
            self._preferences.setValue("general/window_height", self.height())
            self._preferences.setValue("general/window_left", self.x())
            self._preferences.setValue("general/window_top", self.y())
            self._preferences.setValue("general/window_state", Qt.WindowNoState)
        elif self.windowState() == Qt.WindowMaximized:
            self._preferences.setValue("general/window_state", Qt.WindowMaximized)

    def _updateViewportGeometry(self, width, height):
        view_w = width * self._viewport_rect.width()
        view_h = height * self._viewport_rect.height()

        for camera in self._app.getController().getScene().getAllCameras():
            camera.setViewportSize(view_w, view_h)
            camera.setWindowSize(width, height)
            proj = Matrix()
            if camera.isPerspective():
                proj.setPerspective(30, view_w / view_h, 1, 500)
            else:
                proj.setOrtho(-view_w / 2, view_w / 2, -view_h / 2, view_h / 2, -500, 500)
            camera.setProjectionMatrix(proj)

        self._app.getRenderer().setViewportSize(view_w, view_h)
        self._app.getRenderer().setWindowSize(width, height)
Ejemplo n.º 33
0
    def paintEvent(self, event):
        painter = QPainter(self.viewport())
        painter.fillRect(0, 0, self.viewport().width(), self.viewport().height(), QColor('#181818'))

        self.pos = self.verticalScrollBar().value()
        data_start = 0
        data_end = 0

        if len(self.data) > self.visible_lines():
            data_start = self.pos
            data_end = self.pos + self.visible_lines()
        else:
            data_end = len(self.data)

        drawing_pos_y = 10
        trace_depth = 0

        fontMetrics = QFontMetrics(QFont(self.font))
        text_options = QTextOption()
        text_options.setAlignment(Qt.AlignLeft)
        text_options.setWrapMode(QTextOption.WrapAtWordBoundaryOrAnywhere)

        for i, line in enumerate(self.data):
            if i == self.pos:
                break
            if line['event'] == 'leave':
                trace_depth -= 1
            elif line['event'] == 'enter':
                trace_depth += 1

        for i, line in enumerate(self.data[data_start:data_end]):
            if i > self.visible_lines():
                break

            is_obj = False
            if isinstance(line['data'], str) and line['data'].startswith('{'):
                is_obj = True
                line['data'] = json.loads(line['data'])

            drawing_pos_x = 10
            painter.setPen(QColor('#fff'))

            if line['event'] == 'leave':
                if trace_depth:
                    trace_depth -= 1
                drawing_pos_x += (trace_depth * 20)
                painter.setPen(QColor('crimson'))
                painter.setBrush(QColor('#222'))
                polygon = QPolygon()
                polygon.append(QPoint(drawing_pos_x - 6, drawing_pos_y + (self._char_height * 0.5)))
                polygon.append(QPoint(drawing_pos_x + 10, drawing_pos_y - (self._char_height * 0.5)))
                polygon.append(QPoint(self.viewport().width() - 21, drawing_pos_y - (self._char_height * 0.5)))
                polygon.append(QPoint(self.viewport().width() - 21, drawing_pos_y + self._char_height + (self._char_height * 0.5)))
                polygon.append(QPoint(drawing_pos_x + 10, drawing_pos_y + self._char_height + (self._char_height * 0.5)))
                polygon.append(QPoint(drawing_pos_x - 6, drawing_pos_y + (self._char_height * 0.5)))
                painter.drawPolygon(polygon)
            elif line['event'] == 'enter':
                trace_depth += 1
                drawing_pos_x += (trace_depth * 20)
                painter.setPen(QColor('yellowgreen'))
                painter.setBrush(QColor('#222'))
                polygon = QPolygon()
                polygon.append(QPoint(drawing_pos_x + 6, drawing_pos_y - (self._char_height * 0.5)))
                polygon.append(QPoint(int(floor(self.viewport().width())) - 21, drawing_pos_y - (self._char_height * 0.5)))
                polygon.append(QPoint(int(floor(self.viewport().width())) - 5, drawing_pos_y + (self._char_height * 0.5)))
                polygon.append(QPoint(int(floor(self.viewport().width())) - 21, drawing_pos_y + self._char_height + (self._char_height * 0.5)))
                polygon.append(QPoint(drawing_pos_x + 6, drawing_pos_y + self._char_height + (self._char_height * 0.5)))
                #polygon.append(QPoint(drawing_pos_x + 21, drawing_pos_y + (self._char_height * 0.5)))
                polygon.append(QPoint(drawing_pos_x + 6, drawing_pos_y - (self._char_height * 0.5)))
                painter.drawPolygon(polygon)

            drawing_pos_x += 20
            rect = QRectF(drawing_pos_x, drawing_pos_y, self.viewport().width() - 25 - drawing_pos_x, self._char_height + 10)

            if line['event'] == 'enter':
                arg_str = '('
                for a in range(len(line['data'])):
                    arg_str += 'arg_{0}, '.format(a)

                if len(line['data']):
                    arg_str = arg_str[:-2]
                arg_str += ')'
                painter.drawText(rect, line['class'] + arg_str, option=text_options)
            else:
                painter.drawText(rect, line['class'], option=text_options)

            drawing_pos_y += self._char_height + 15

            if isinstance(line['data'], str):
                if line['data']:
                    rect = fontMetrics.boundingRect(drawing_pos_x, drawing_pos_y, self.viewport().width() - drawing_pos_x - 25, 0, Qt.AlignLeft | Qt.TextWordWrap | Qt.TextWrapAnywhere, line['data'])
                    rect = QRectF(drawing_pos_x, drawing_pos_y, rect.width(), rect.height())
                    painter.setPen(QColor('#888'))
                    painter.drawText(rect, line['data'], option=text_options)
                    drawing_pos_y += rect.height() + 5
            else:
                width = int(floor(self.viewport().width() - drawing_pos_x - (5 * self._char_width) - 35))
                max_chars = int(floor(width / self._char_width))
                hold_x = drawing_pos_x + 5
                width -= 20
                painter.setPen(QColor('#888'))
                for data in line['data']:
                    drawing_pos_x = hold_x
                    if isinstance(line['data'][data], int):
                        text = '{0:d}'.format(line['data'][data])
                    elif isinstance(line['data'][data], str):
                        text = line['data'][data]
                    elif isinstance(line['data'][data], list):
                        text = str(line['data'][data])
                    else:
                        text = str(line['data'][data])

                    if line['event'] == 'enter':
                        arg = 'arg_{0}: '.format(data)
                        painter.drawText(drawing_pos_x, drawing_pos_y + self._base_line, arg)
                        drawing_pos_x += len(arg) * self._char_width
                    elif line['event'] == 'leave':
                        retval = data + ': '
                        painter.drawText(drawing_pos_x, drawing_pos_y + self._base_line, retval)
                        drawing_pos_x += len(retval) * self._char_width

                    if len(text) * self._char_width < width:
                        painter.drawText(drawing_pos_x, drawing_pos_y + self._base_line, text)
                        drawing_pos_y += self._char_height + 5
                    else:
                        rect = fontMetrics.boundingRect(drawing_pos_x, drawing_pos_y, width, 0, Qt.AlignLeft | Qt.TextWordWrap | Qt.TextWrapAnywhere, text)
                        rect = QRectF(rect)
                        painter.drawText(rect, text, option=text_options)
                        drawing_pos_y += rect.height() + 5

            drawing_pos_y += self._char_height + 5
Ejemplo n.º 34
0
    def paintEvent(self, event):
        # based on
        # http://qt.gitorious.org/qt/qt/blobs/master/src/gui/widgets/qslider.cpp

        painter = QPainter(self)
        style = self.style()
        opt = QStyleOptionSlider()
        self.initStyleOption(opt)

        groove_rect = style.subControlRect(style.CC_Slider, opt,
                                           QStyle.SC_SliderGroove, self)
        handle_rect = style.subControlRect(style.CC_Slider, opt,
                                           QStyle.SC_SliderHandle, self)

        slider_space = style.pixelMetric(style.PM_SliderSpaceAvailable, opt)
        range_x = style.sliderPositionFromValue(self.minimum(), self.maximum(),
                                                self.value(), slider_space)
        range_height = 4

        groove_rect = QRectF(groove_rect.x(),
                             handle_rect.center().y() - (range_height / 2),
                             groove_rect.width(), range_height)

        range_rect = QRectF(groove_rect.x(),
                            handle_rect.center().y() - (range_height / 2),
                            range_x, range_height)

        if style.metaObject().className() != 'QMacStyle':
            # Paint groove for Fusion and Windows styles
            cur_brush = painter.brush()
            cur_pen = painter.pen()
            painter.setBrush(QBrush(QColor(169, 169, 169)))
            painter.setPen(Qt.NoPen)
            # painter.drawRect(groove_rect)
            painter.drawRoundedRect(groove_rect,
                                    groove_rect.height() / 2,
                                    groove_rect.height() / 2)
            painter.setBrush(cur_brush)
            painter.setPen(cur_pen)

        cur_brush = painter.brush()
        cur_pen = painter.pen()
        painter.setBrush(QBrush(QColor(18, 141, 148)))
        painter.setPen(Qt.NoPen)
        painter.drawRect(range_rect)
        painter.setBrush(cur_brush)
        painter.setPen(cur_pen)

        opt = QStyleOptionSlider()
        self.initStyleOption(opt)

        opt.subControls = QStyle.SC_SliderHandle

        if self.tickPosition() != self.NoTicks:
            opt.subControls |= QStyle.SC_SliderTickmarks

        if self.isSliderDown():
            opt.state |= QStyle.State_Sunken
        else:
            opt.state |= QStyle.State_Active

        opt.activeSubControls = QStyle.SC_None

        opt.sliderPosition = self.value()
        opt.sliderValue = self.value()
        style.drawComplexControl(QStyle.CC_Slider, opt, painter, self)
Ejemplo n.º 35
0
    def paint(self, painter, option, widget):
        lod = option.levelOfDetailFromTransform(painter.worldTransform())

        if lod > 0.15:
            if lod > 1 or self.rowLength < 3:
                valueSize = len(str(self.value))
                painter.setPen(QColor(0, 0, 0))
                painter.setBrush(self.tokenColor)
                
                rectValue = self.getTokenRect()
                if self.hover:
                	#Make token larger when the mouse hovers over it
                    rectValue = self.getTokenRectHover()

                painter.drawEllipse(rectValue)
                
                #Determine font size based on size of token content
                if self.hover:
                	#Larger text when hovering
                    if valueSize == 1:
                        rectValue = QRectF(rectValue.x(), rectValue.x() + 1, rectValue.width(), rectValue.height())
                        painter.setFont(QFont("Lucida Console", 13))
                    elif valueSize == 2:
                        painter.setFont(QFont("Lucida Console", 11))
                    elif valueSize == 3:
                        painter.setFont(QFont("Lucida Console", 8))
                    elif valueSize > 3:
                        painter.setFont(QFont("Lucida Console", 6))
                else:
                	#Normal size text when not hovering
                    if valueSize == 1:
                        rectValue = QRectF(rectValue.x(), rectValue.x() + 1, rectValue.width(), rectValue.height())
                        painter.setFont(QFont("Lucida Console", 9))
                    elif valueSize == 2:
                        painter.setFont(QFont("Lucida Console", 7))
                    elif valueSize == 3:
                        painter.setFont(QFont("Lucida Console", 5))
                    elif valueSize > 3:
                        painter.setFont(QFont("Lucida Console", 4))
                
                if lod > 0.4:
                    painter.drawText(rectValue, Qt.AlignCenter, str(self.value))
                    
                    #Add dots to indicate that not the entire contents of the token is displayed
                    if valueSize > 5:
                        rect = rectValue                    
                        rect.setY(rect.y() + 5)
                        painter.drawText(rect, Qt.AlignCenter, '..')
Ejemplo n.º 36
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.º 37
0
class RegionSelector:
    '''Class to handle coordinating multiple selector windows for a multimonitor setup. '''
    def __init__(self, x, y, w, h, pixmap):
        self.moving = self.drawing = self.resizing = False

        self.bounds = QRectF(x, y, w, h)
        self.selectors = []
        self.selection = None
        for screen in QApplication.screens():
            # make a new selector for this screen
            # TODO: Support limited subset of screens?
            geo = screen.geometry()
            sel = Selector(geo.x(), geo.y(), geo.width(), geo.height(), pixmap,
                           self)
            self.selectors.append(sel)
        #endfor

    #enddef

    def exec_(self):
        cPos = QCursor.pos()
        QCursor.setPos(
            0, 0
        )  # XFCE workaround. In XCFE, window position is relative to the cursor position
        for sel in self.selectors:
            sel.show()
        QCursor.setPos(cPos)
        self.selectors[-1].exec_()

    #enddef

    def updateSelection(self):
        for s in self.selectors:
            s.updateSelection()

    #enddef

    def mousePressEvent(self, e):
        pos = e.globalPos()
        self.moving = self.drawing = self.resizing = False

        if self.selection is None or not self.selection.contains(pos):
            self.drawing = True
            self.selection = None
            self.selectionStart = pos
        #elif in corner
        #elif on line
        else:  # in
            self.moving = True
            self.selBeforeMove = self.selection
            self.moveOrigin = pos
        #endif
        self.updateSelection()

    #enddef

    def mouseMoveEvent(self, e):
        pos = e.globalPos()
        if self.drawing:
            if pos.x() != self.selectionStart.x() and pos.y(
            ) != self.selectionStart.y():
                self.selection = QRectF(QPointF(self.selectionStart),
                                        QPointF(pos)).normalized()
                self.selection = self.selection.intersected(self.bounds)
                self.updateSelection()
            #endif
        elif self.moving:
            delta = pos - self.moveOrigin
            moved = self.selBeforeMove.translated(delta)

            # TODO: this cause the bounds to be "sticky", since trying to move back after pushing it 50px off the edge
            # means we must re-traverse the other 49 "off screen" pixels before we get some visible movement
            minX, maxX = self.bounds.x(
            ), self.bounds.x() + self.bounds.width() - moved.width()
            minY, maxY = self.bounds.y(
            ), self.bounds.y() + self.bounds.height() - moved.height()

            moved.moveTo(min(max(minX, moved.x()), maxX),
                         min(max(minY, moved.y()), maxY))

            self.selection = moved.intersected(self.bounds)
            self.updateSelection()
        #endif

    #enddef

    def mouseReleaseEvent(self, e):
        self.moving = self.drawing = self.resizing = False

        self.updateSelection()

    #enddef

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.selection = None
            self.close()
        elif event.key() in (Qt.Key_Enter, Qt.Key_Return):
            if self.selection:
                self.close()
            #endif
        #endif

    #enddef

    def close(self):
        for s in self.selectors:
            s.close()
Ejemplo n.º 38
0
class Viewer(QGraphicsView):
    def __init__(self, gridsize_label, position_label, help_label):
        QGraphicsView.__init__(self)

        self.gridsize_label = gridsize_label
        self.position_label = position_label
        self.help_label = help_label

        # Create a QGraphicsScene which this view looks at
        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(QRectF())
        self.setScene(self.scene)

        # Customize QGraphicsView
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setInteractive(False)
        self.scale(1, -1)  # Flips around the Y axis
        # Use OpenGL http://ralsina.me/stories/BBS53.html
        #        self.setViewport(QtOpenGL.QGLWidget())
        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.pen = QPen(QtCore.Qt.black, 0)
        self.portpen = QPen(PORT_COLOR, 3)
        self.portpen.setCosmetic(True)  # Makes constant width
        self.portfont = QtGui.QFont('Arial', pointSize=14)
        self.portfontcolor = PORT_COLOR
        self.subportpen = QPen(SUBPORT_COLOR, 3)
        self.subportpen.setCosmetic(True)  # Makes constant width
        self.subportfont = QtGui.QFont('Arial', pointSize=14)
        self.subportfontcolor = SUBPORT_COLOR

        # Tracking ports

        # Various status variables
        self._mousePressed = None
        self._rb_origin = QPoint()
        self.zoom_factor_total = 1

        # Grid variables
        self.gridpen = QPen(QtCore.Qt.black, 0)
        self.gridpen.setStyle(QtCore.Qt.DotLine)
        self.gridpen.setDashPattern([1, 4])
        self.gridpen.setColor(QtGui.QColor(0, 0, 0, 125))
        #        self.gridpen = QPen(QtCore.Qt.black, 1)
        #        self.gridpen.setCosmetic(True) # Makes constant width
        self.scene_polys = []

        self.initialize()

    def add_polygons(self, polygons, color='#A8F22A', alpha=1):
        qcolor = QColor()
        qcolor.setNamedColor(color)
        qcolor.setAlphaF(alpha)
        for points in polygons:
            qpoly = QPolygonF([QPointF(p[0], p[1]) for p in points])
            scene_poly = self.scene.addPolygon(qpoly)
            scene_poly.setBrush(qcolor)
            scene_poly.setPen(self.pen)
            self.scene_polys.append(scene_poly)
            # Update custom bounding box
            sr = scene_poly.sceneBoundingRect()
            if len(self.scene_polys) == 1:
                self.scene_xmin = sr.left()
                self.scene_xmax = sr.right()
                self.scene_ymin = sr.top()
                self.scene_ymax = sr.bottom()
            else:
                self.scene_xmin = min(self.scene_xmin, sr.left())
                self.scene_xmax = max(self.scene_xmax, sr.right())
                self.scene_ymin = min(self.scene_ymin, sr.top())
                self.scene_ymax = max(self.scene_ymax, sr.bottom())

    def reset_view(self):
        # The SceneRect controls how far you can pan, make it larger than
        # just the bounding box so middle-click panning works
        panning_rect = QRectF(self.scene_bounding_rect)
        panning_rect_center = panning_rect.center()
        panning_rect_size = max(panning_rect.width(),
                                panning_rect.height()) * 3
        panning_rect.setSize(QSizeF(panning_rect_size, panning_rect_size))
        panning_rect.moveCenter(panning_rect_center)
        self.setSceneRect(panning_rect)
        self.fitInView(self.scene_bounding_rect, Qt.KeepAspectRatio)
        self.zoom_view(0.8)

        self.update_grid()

    def add_port(self, port, is_subport=False):
        if (port.width is None) or (port.width == 0):
            x, y = port.midpoint
            cs = 1  # cross size
            pn = QPointF(x, y + cs)
            ps = QPointF(x, y - cs)
            pe = QPointF(x + cs, y)
            pw = QPointF(x - cs, y)
            qline1 = self.scene.addLine(QLineF(pn, ps))
            qline2 = self.scene.addLine(QLineF(pw, pe))
            port_shapes = [qline1, qline2]
        else:
            point1, point2 = port.endpoints
            point1 = QPointF(point1[0], point1[1])
            point2 = QPointF(point2[0], point2[1])
            qline = self.scene.addLine(QLineF(point1, point2))
            arrow_points = np.array([[0, 0], [10, 0], [6, 4], [6, 2], [0, 2]
                                     ]) / (40) * port.width
            arrow_qpoly = QPolygonF(
                [QPointF(p[0], p[1]) for p in arrow_points])
            port_scene_poly = self.scene.addPolygon(arrow_qpoly)
            port_scene_poly.setRotation(port.orientation)
            port_scene_poly.moveBy(port.midpoint[0], port.midpoint[1])
            port_shapes = [qline, port_scene_poly]
        qtext = self.scene.addText(str(port.name), self.portfont)
        port_items = port_shapes + [qtext]
        rad = port.orientation * np.pi / 180
        x, y = port.endpoints[0] * 1 / 4 + port.endpoints[
            1] * 3 / 4 + np.array([np.cos(rad), np.sin(rad)]) * port.width / 8
        #        x,y = port.midpoint[0], port.midpoint[1]
        #        x,y  = x - qtext.boundingRect().width()/2, y - qtext.boundingRect().height()/2
        qtext.setPos(QPointF(x, y))
        qtext.setFlag(QGraphicsItem.ItemIgnoresTransformations)

        if not is_subport:
            [shape.setPen(self.portpen) for shape in port_shapes]
            qtext.setDefaultTextColor(self.portfontcolor)
            self.portitems += port_items
        else:
            [shape.setPen(self.subportpen) for shape in port_shapes]
            qtext.setDefaultTextColor(self.subportfontcolor)
            self.subportitems += port_items
#        self.portlabels.append(qtext)

    def add_aliases(self, aliases):
        for name, ref in aliases.items():
            qtext = self.scene.addText(str(name), self.portfont)
            x, y = ref.center
            qtext.setPos(QPointF(x, y))
            qtext.setFlag(QGraphicsItem.ItemIgnoresTransformations)
            self.aliasitems += [qtext]

    def set_port_visibility(self, visible=True):
        for item in self.portitems:
            item.setVisible(visible)
        self.ports_visible = visible

    def set_subport_visibility(self, visible=True):
        for item in self.subportitems:
            item.setVisible(visible)
        self.subports_visible = visible

    def set_alias_visibility(self, visible=True):
        for item in self.aliasitems:
            item.setVisible(visible)
        self.aliases_visible = visible

    def initialize(self):
        self.scene.clear()
        self.polygons = {}
        self.portitems = []
        self.subportitems = []
        self.aliasitems = []
        self.aliases_visible = True
        self.ports_visible = True
        self.subports_visible = True
        self.mouse_position = [0, 0]
        self.grid_size_snapped = 0
        self.setMouseTracking(True)
        self.scene_bounding_rect = None
        self.scene_polys = []
        self.scene_xmin = 0
        self.scene_xmax = 1
        self.scene_ymin = 0
        self.scene_ymax = 1

    def finalize(self):
        self.scene_bounding_rect = QRectF(
            QPointF(self.scene_xmin, self.scene_ymin),
            QPointF(self.scene_xmax, self.scene_ymax))
        # self.scene_center = [self.scene_bounding_rect.center().x(), self.scene_bounding_rect.center().y()]
        self.scene_size = [
            self.scene_bounding_rect.width(),
            self.scene_bounding_rect.height()
        ]
        self.create_grid()
        self.update_grid()

#==============================================================================
#   Grid creation
#==============================================================================

    def update_grid(self):
        grid_pixels = 50
        grid_snaps = [1, 2, 4]

        # Number of pixels in the viewer
        view_width, view_height = self.rect().width(), self.rect().height()
        # Rectangle of viewport in terms of scene coordinates
        r = self.mapToScene(self.rect()).boundingRect()
        width, height = r.width(), r.height()
        xmin, ymin, xmax, ymax = r.x(), r.y(), r.x() + width, r.y() + height

        grid_size = grid_pixels * (width / view_width)
        exponent = np.floor(np.log10(grid_size))
        digits = round(grid_size / 10**(exponent), 2)
        digits_snapped = min(grid_snaps, key=lambda x: abs(x - digits))
        grid_size_snapped = digits_snapped * 10**(exponent)

        # Starting coordinates for gridlines
        x = round((xmin - 2 * width) / grid_size_snapped) * grid_size_snapped
        y = round((ymin - 2 * height) / grid_size_snapped) * grid_size_snapped

        for gl in self.gridlinesx:
            gl.setLine(x, -1e10, x, 1e10)
            x += grid_size_snapped
        for gl in self.gridlinesy:
            gl.setLine(-1e10, y, 1e10, y)
            y += grid_size_snapped
        self.grid_size_snapped = grid_size_snapped
        self.update_gridsize_label()

    def update_gridsize_label(self):
        self.gridsize_label.setText('grid size = ' +
                                    str(self.grid_size_snapped))
        self.gridsize_label.move(QPoint(5, self.height() - 25))

    def update_mouse_position_label(self):
        self.position_label.setText(
            'X = %0.4f / Y = %0.4f' %
            (self.mouse_position[0], self.mouse_position[1]))
        self.position_label.move(QPoint(self.width() - 250,
                                        self.height() - 25))

    def update_help_label(self):
        self.help_label.setText('Press "?" key for help')
        self.help_label.move(QPoint(self.width() - 175, 0))

    def create_grid(self):
        self.gridlinesx = [
            self.scene.addLine(-10, -10, 10, 10, self.gridpen)
            for n in range(300)
        ]
        self.gridlinesy = [
            self.scene.addLine(-10, -10, 10, 10, self.gridpen)
            for n in range(300)
        ]
        self.update_grid()

#==============================================================================
#  Mousewheel zoom, taken from http://stackoverflow.com/a/29026916
#==============================================================================

    def wheelEvent(self, event):
        # Zoom Factor
        zoom_percentage = 1.4

        # Set Anchors
        self.setTransformationAnchor(QGraphicsView.NoAnchor)
        self.setResizeAnchor(QGraphicsView.NoAnchor)

        # Save the scene pos
        oldPos = self.mapToScene(event.pos())

        # Zoom
        mousewheel_rotation = event.angleDelta().y(
        )  # Typically = 120 on most mousewheels
        zoom_factor = zoom_percentage**(mousewheel_rotation / 120)
        zoom_factor = np.clip(zoom_factor, 0.5, 2.0)

        # Check to make sure we're not overzoomed
        min_width = 0.01
        min_height = 0.01

        window_width = self.rect().width()
        window_height = self.rect().height()
        scene_upper_left_corner = self.mapToScene(QPoint(0, 0))
        scene_bottom_right_corner = self.mapToScene(
            QPoint(window_width, window_height))
        scene_width = (scene_bottom_right_corner - scene_upper_left_corner).x()
        scene_height = (scene_upper_left_corner -
                        scene_bottom_right_corner).y()

        max_width = self.scene_bounding_rect.width() * 3
        max_height = self.scene_bounding_rect.height() * 3

        if ((scene_width > max_width) and
            (scene_height > max_height)) and (zoom_factor < 1):
            pass
        elif ((scene_width < min_width) and
              (scene_height < min_height)) and (zoom_factor > 1):
            pass
        else:
            self.zoom_view(zoom_factor)

        # Get the new position and move scene to old position
        newPos = self.mapToScene(event.pos())
        delta = newPos - oldPos
        self.translate(delta.x(), delta.y())

        self.update_grid()

    def zoom_view(self, zoom_factor):
        old_center = self.mapToScene(self.rect().center())
        self.scale(zoom_factor, zoom_factor)
        self.centerOn(old_center)
        self.zoom_factor_total *= zoom_factor

    def resizeEvent(self, event):
        super(QGraphicsView, self).resizeEvent(event)
        if self.scene_bounding_rect is not None:
            self.reset_view()
        self.update_gridsize_label()
        self.update_mouse_position_label()
        self.update_help_label()

    def mousePressEvent(self, event):
        super(QGraphicsView, self).mousePressEvent(event)
        #==============================================================================
        #  Zoom to rectangle, from
        #  https://wiki.python.org/moin/PyQt/Selecting%20a%20region%20of%20a%20widget
        #==============================================================================
        if event.button() == Qt.RightButton:
            self._mousePressed = Qt.RightButton
            self._rb_origin = QPoint(event.pos())
            self.rubberBand.setGeometry(QRect(self._rb_origin, QSize()))
            self.rubberBand.show()
        #==============================================================================
        # Mouse panning, taken from
        # http://stackoverflow.com/a/15043279
        #==============================================================================
        elif event.button() == Qt.MidButton:
            self._mousePressed = Qt.MidButton
            self._mousePressedPos = event.pos()
            self.setCursor(QtCore.Qt.ClosedHandCursor)
            self._dragPos = event.pos()

    def mouseMoveEvent(self, event):
        super(QGraphicsView, self).mouseMoveEvent(event)

        # # Useful debug
        # try:
        #     self.debug_label.setText(str(itemsBoundingRect_nogrid().width()))
        # except:
        #     print('Debug statement failed')

        # Update the X,Y label indicating where the mouse is on the geometry
        mouse_position = self.mapToScene(event.pos())
        self.mouse_position = [mouse_position.x(), mouse_position.y()]
        self.update_mouse_position_label()

        if not self._rb_origin.isNull(
        ) and self._mousePressed == Qt.RightButton:
            self.rubberBand.setGeometry(
                QRect(self._rb_origin, event.pos()).normalized())

        # Middle-click-to-pan
        if self._mousePressed == Qt.MidButton:
            newPos = event.pos()
            diff = newPos - self._dragPos
            self._dragPos = newPos
            self.horizontalScrollBar().setValue(
                self.horizontalScrollBar().value() - diff.x())
            self.verticalScrollBar().setValue(
                self.verticalScrollBar().value() - diff.y())


#            event.accept()

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.RightButton:
            self.rubberBand.hide()
            rb_rect = QRect(self._rb_origin, event.pos())
            rb_center = rb_rect.center()
            rb_size = rb_rect.size()

            if abs(rb_size.width()) > 3 and abs(rb_size.height()) > 3:
                viewport_size = self.viewport().geometry().size()

                zoom_factor_x = abs(viewport_size.width() / rb_size.width())
                zoom_factor_y = abs(viewport_size.height() / rb_size.height())

                new_center = self.mapToScene(rb_center)

                zoom_factor = min(zoom_factor_x, zoom_factor_y)
                self.zoom_view(zoom_factor)
                self.centerOn(new_center)

            self.update_grid()

        if event.button() == Qt.MidButton:
            self.setCursor(Qt.ArrowCursor)
            self._mousePressed = None
            self.update_grid()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.reset_view()

        if event.key() == Qt.Key_F1:
            self.set_alias_visibility(not self.aliases_visible)

        if event.key() == Qt.Key_F2:
            self.set_port_visibility(not self.ports_visible)

        if event.key() == Qt.Key_F3:
            self.set_subport_visibility(not self.subports_visible)

        if event.key() == Qt.Key_Question:
            help_str = """
            Mouse control:
              Mousewheel: Zoom in and out
              Right-click & drag: Zoom to rectangle
              Middle-click & drag: Pan

            Keyboard shortcuts:
              Esc: Reset view
              F1: Show/hide alias names
              F2: Show/hide ports
              F3: Show/hide subports (ports in underlying references)
            """
            msg = QMessageBox.about(self, 'PHIDL Help', help_str)
            msg.raise_()
Ejemplo n.º 39
0
class cheeseWidget(QWidget):
    def __init__(self, winParent, pose3d):
        super(cheeseWidget, self).__init__()
        self.winParent = winParent
        self.rectangle = QRectF(0.0, 0.0, 300.0, 300.0)
        self.pose3d = pose3d

    def drawRedZones(self, painter):
        self.setStyle(painter, QColor(255, 70, 70), QColor(255, 70, 70), 1)
        startAngle = 0 * 16
        spanAngle = 45 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)
        startAngle = 135 * 16
        spanAngle = 45 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)
        startAngle = 180 * 16
        spanAngle = 180 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)

    def drawOrangeZones(self, painter):
        self.setStyle(painter, QColor(255, 220, 23), QColor(255, 220, 23), 1)
        startAngle = 45 * 16
        spanAngle = 30 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)
        startAngle = 105 * 16
        spanAngle = 30 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)

    def drawGreenZones(self, painter):
        self.setStyle(painter, QColor(117, 240, 154), QColor(117, 240, 154), 1)
        startAngle = 75 * 16
        spanAngle = 15 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)
        startAngle = 90 * 16
        spanAngle = 15 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)

    def drawArrow(self, painter, angle=90):
        radius = 130
        yawRad = self.pose3d.getYaw()
        angle = -(yawRad + pi / 2)  # PI/2 para centrar la aguja
        origx = self.rectangle.width() / 2
        origy = self.rectangle.height() / 2
        finx = radius * math.cos(angle) + origx
        finy = radius * math.sin(angle) + origy
        self.setStyle(painter, Qt.black, Qt.black, 3)
        painter.drawLine(QPoint(origx, origy), QPoint(finx, finy))
        painter.drawEllipse(145, 145, 10, 10)

    def resetPen(self, painter):
        pen = QPen(Qt.black, 1)
        brush = QBrush()
        painter.setPen(pen)
        painter.setBrush(brush)

    def setStyle(self, painter, fillColor, penColor, stroke):
        brush = QBrush()
        pen = QPen(penColor, stroke)
        brush.setColor(fillColor)
        brush.setStyle(Qt.SolidPattern)
        painter.setBrush(brush)
        painter.setPen(pen)
        painter.setRenderHint(QPainter.Antialiasing)

    def paintEvent(self, event):
        painter = QPainter(self)
        self.drawRedZones(painter)
        self.drawOrangeZones(painter)
        self.drawGreenZones(painter)
        self.drawArrow(painter, 120)

    def updateG(self):
        self.update()
Ejemplo n.º 40
0
    #     self.setWidth(width)
    #     self.setHeight(height)
    #
    # def dilate(self, nb_dilation=1):
    #     self.erode(nb_erosion=-nb_dilation)


if __name__ == '__main__':
    # ça marche --> voici deux examples de shapes
    test = Rect2D(0, 0, 100, 100)

    rect = QRectF(0, 0, 125, 256)
    print(rect.x())
    print(rect.y())
    print(rect.width())
    print(rect.height())

    rect.translate(10, 20)  # ça marche
    print(rect)

    (test.x(), test.y(), test.width(), test.height())
    print(test.contains(QPointF(50, 50)))
    print(test.contains(QPointF(-1, -1)))
    print(test.contains(QPointF(0, 0)))
    print(test.contains(QPointF(100, 100)))
    print(test.contains(QPointF(100, 100.1)))

    point = QPointF(50, 50)
    point.x()

    # p1 = test.p1()
Ejemplo n.º 41
0
class FloatingGradientItem(QGraphicsItem):
    def __init__(self, rect, finishCallback=None, parent=None):
        super(FloatingGradientItem, self).__init__(parent)
        self.__boundingRect = QRectF(0, 0, rect.width(), rect.height())
        self.setPos(rect.x(), rect.y())

        self.__front = 0.0
        self.__rear = 0.0

        self.__frontSpeed = 1.0
        self.__rearSpeed = 0

        self.__backwards = True

        self.__frontColor = QColor.fromRgb(0, 255, 0, 255)  # defualt green
        self.__rearColor = QColor.fromRgb(0, 0, 0, 0)  # default transparent

        self.__timer = QTimer()
        self.__timer.timeout.connect(self.__moveGradient)
        self.__timer.start(17)

        self.__finishCallback = finishCallback

    def setFrontSpeed(self, value):
        if value < 0 or value > 100:
            raise ValueError(f"value is {value}. Accepted [0, 100]")

        self.__frontSpeed = value

    def setRearSpeed(self, value):
        if value < 0 or value > 100:
            raise ValueError(f"value is {value}. Accepted [0, 100]")

        self.__rearSpeed = value

    def setBackwards(self, value):
        if not isinstance(value, bool):
            raise ValueError(f"value is not a bool")
        self.__backwards = value

    def setWidth(self, width):
        self.__boundingRect.setWidth(width)

    def setHeight(self, height):
        self.__boundingRect.setHeight(height)

    def setSize(self, width, height):
        self.setWidth(width)
        self.setHeight(height)

    def __moveGradient(self):
        self.__front += self.__frontSpeed
        if self.__front > 100:
            self.__front = 100

        self.__rear += self.__rearSpeed
        if self.__rear > 100:
            self.__front = 0
            self.__rear = 0
            self.__rearSpeed = 0

        self.__rearSpeed += 2 * self.__frontSpeed**2 / 100
        self.update(self.__boundingRect)

        if self.__front < 0.00001 and self.__finishCallback:
            self.__finishCallback()

    def boundingRect(self):
        return self.__boundingRect

    def paint(self, painter, style_option, widget):
        frontPos = self.__boundingRect.height() * self.__front / 100
        rearPos = self.__boundingRect.height() * self.__rear / 100

        width = self.__boundingRect.width()
        height = self.__boundingRect.height()

        if self.__backwards:
            frontPos = height - frontPos
            rearPos = height - rearPos

        gradient = QLinearGradient(width / 2, frontPos, width / 2, rearPos)
        gradient.setColorAt(0, self.__frontColor)
        gradient.setColorAt(1, self.__rearColor)

        painter.fillRect(QRectF(0, rearPos, width, frontPos - rearPos),
                         gradient)
Ejemplo n.º 42
0
    def paint(self, painter):
        painter.setRenderHint(QPainter.Antialiasing)

        pixelRatio = self.devicePixelRatioF()
        rect = QRectF(0, 0,
                      self.width() * pixelRatio,
                      self.height() * pixelRatio)
        sz = QSizeF(self.width() * pixelRatio,
                    self.height() * pixelRatio).toSize()

        self.resizePixmap(sz)

        yOffset = rect.toRect().topLeft().y() + (100 - self.value() -
                                                 10) * sz.height() / 100

        # draw water
        waterImage = QImage(sz, QImage.Format_ARGB32_Premultiplied)
        waterPainter = QPainter()
        waterPainter.begin(waterImage)
        waterPainter.setRenderHint(QPainter.Antialiasing)
        waterPainter.setCompositionMode(QPainter.CompositionMode_Source)

        pointStart = QPointF(sz.width() / 2, 0)
        pointEnd = QPointF(sz.width() / 2, sz.height())
        linear = QLinearGradient(pointStart, pointEnd)
        startColor = QColor('#1F08FF')
        startColor.setAlphaF(1)
        endColor = QColor('#50FFF7')
        endColor.setAlphaF(0.28)
        linear.setColorAt(0, startColor)
        linear.setColorAt(1, endColor)
        linear.setSpread(QGradient.PadSpread)
        waterPainter.setPen(Qt.NoPen)
        waterPainter.setBrush(linear)
        waterPainter.drawEllipse(waterImage.rect().center(),
                                 sz.width() / 2 + 1,
                                 sz.height() / 2 + 1)

        waterPainter.setCompositionMode(QPainter.CompositionMode_SourceOver)
        waterPainter.drawImage(int(self.backXOffset), yOffset,
                               self.waterBackImage)
        waterPainter.drawImage(
            int(self.backXOffset) - self.waterBackImage.width(), yOffset,
            self.waterBackImage)
        waterPainter.drawImage(int(self.frontXOffset), yOffset,
                               self.waterFrontImage)
        waterPainter.drawImage(
            int(self.frontXOffset) - self.waterFrontImage.width(), yOffset,
            self.waterFrontImage)

        # draw pop
        if self.value() > 30:
            for pop in self.pops:
                popPath = QPainterPath()
                popPath.addEllipse(pop.xOffset * sz.width() / 100,
                                   (100 - pop.yOffset) * sz.height() / 100,
                                   pop.size * sz.width() / 100,
                                   pop.size * sz.height() / 100)
                waterPainter.fillPath(popPath, QColor(255, 255, 255,
                                                      255 * 0.3))

        if self.isTextVisible():
            font = waterPainter.font()
            rectValue = QRect()
            progressText = self.text().strip('%')

            if progressText == '100':
                font.setPixelSize(sz.height() * 35 / 100)
                waterPainter.setFont(font)

                rectValue.setWidth(sz.width() * 60 / 100)
                rectValue.setHeight(sz.height() * 35 / 100)
                rectValue.moveCenter(rect.center().toPoint())
                waterPainter.setPen(Qt.white)
                waterPainter.drawText(rectValue, Qt.AlignCenter, progressText)
            else:
                font.setPixelSize(sz.height() * 40 / 100)
                waterPainter.setFont(font)

                rectValue.setWidth(sz.width() * 45 / 100)
                rectValue.setHeight(sz.height() * 40 / 100)
                rectValue.moveCenter(rect.center().toPoint())
                rectValue.moveLeft(rect.left() + rect.width() * 0.45 * 0.5)

                waterPainter.setPen(Qt.white)
                waterPainter.drawText(rectValue, Qt.AlignCenter, progressText)
                font.setPixelSize(font.pixelSize() / 2)
                waterPainter.setFont(font)
                rectPerent = QRect(
                    QPoint(rectValue.right(),
                           rectValue.bottom() - rect.height() * 20 / 100),
                    QPoint(rectValue.right() + rect.width() * 20 / 100,
                           rectValue.bottom()))

                waterPainter.drawText(rectPerent, Qt.AlignCenter, '%')

        waterPainter.end()

        maskPixmap = QPixmap(sz)
        maskPixmap.fill(Qt.transparent)
        path = QPainterPath()
        path.addEllipse(QRectF(0, 0, sz.width(), sz.height()))
        maskPainter = QPainter()
        maskPainter.begin(maskPixmap)
        maskPainter.setRenderHint(QPainter.Antialiasing)
        maskPainter.setPen(QPen(Qt.white, 1))
        maskPainter.fillPath(path, QBrush(Qt.white))
        maskPainter.end()

        mode = QPainter.CompositionMode_SourceIn
        contentImage = QImage(sz, QImage.Format_ARGB32_Premultiplied)
        contentPainter = QPainter()
        contentPainter.begin(contentImage)
        contentPainter.setCompositionMode(QPainter.CompositionMode_Source)
        contentPainter.fillRect(contentImage.rect(), Qt.transparent)
        contentPainter.setCompositionMode(QPainter.CompositionMode_SourceOver)
        contentPainter.drawImage(0, 0, maskPixmap.toImage())
        contentPainter.setCompositionMode(mode)
        contentPainter.drawImage(0, 0, waterImage)
        contentPainter.setCompositionMode(
            QPainter.CompositionMode_DestinationOver)
        contentPainter.end()

        contentImage.setDevicePixelRatio(pixelRatio)
        painter.drawImage(self.rect(), contentImage)
Ejemplo n.º 43
0
class DisplaySpriteObject(QGraphicsItem):
    def __init__(self):

        super(DisplaySpriteObject, self).__init__()

        self._sprite = None

        self._displayFrameIndex = -1

        self.prepareGeometryChange()

        self._boundingRect = QRectF()

        self._backgroundPixmap = None

        self._enableOnionSkin = True

    @property
    def sprite(self):
        return self._sprite

    @property
    def active_surface(self):
        return self._sprite.active_surface

    @property
    def active_surface_pixel_data(self):
        return self._sprite.active_surface_pixel_data

    @property
    def display_frame_index(self):
        return self._displayFrameIndex

    @display_frame_index.setter
    def display_frame_index(self, value):
        self._displayFrameIndex = value

    @property
    def background_pixmap(self):
        return self._backgroundPixmap

    @property
    def is_empty(self):
        return self._sprite is None

    @background_pixmap.setter
    def background_pixmap(self, value):
        self._backgroundPixmap = value

    def boundingRect(self):
        return self._boundingRect

    @property
    def bounding_rect_i(self):
        return QRect(self._boundingRect.left(), self._boundingRect.top(),
                     self._boundingRect.width(), self._boundingRect.height())

    @property
    def area_rect(self):
        return QRect(0, 0, self._boundingRect.width(),
                     self._boundingRect.height())

    @property
    def width(self):
        return self.boundingRect().width()

    @property
    def height(self):
        return self.boundingRect().height()

    @property
    def enable_onion_skin(self):
        return self._enableOnionSkin

    @enable_onion_skin.setter
    def enable_onion_skin(self, value):
        self._enableOnionSkin = value

    def set_sprite(self, sprite):

        self._sprite = sprite

        self.update_bounding_rect()

    def update_bounding_rect(self):

        if self._boundingRect.size != self._sprite.size:
            self.prepareGeometryChange()
            self._boundingRect = QRectF(-self._sprite.width / 2,
                                        -self._sprite.height / 2,
                                        self._sprite.width,
                                        self._sprite.height)

    def unload_sprite(self):

        self._sprite = None
        self._displayFrameIndex = -1
        self.prepareGeometryChange()
        self._boundingRect = QRectF()

    def paint(self, painter, option, widget=None):

        painter.setClipRect(option.exposedRect)

        if self._backgroundPixmap is not None:
            painter.drawTiledPixmap(option.rect, self._backgroundPixmap)

        if self._sprite is not None:

            frame_index = self._displayFrameIndex \
                if self._displayFrameIndex != -1 \
                else self._sprite.current_animation.current_frame_index

            if self._enableOnionSkin:

                last_frame_index = frame_index - 1

                if last_frame_index >= 0:

                    last_frame_layers = self._sprite.current_animation. \
                        frame_at(last_frame_index).surfaces

                    painter.setOpacity(0.2)

                    for layer in last_frame_layers:
                        painter.drawImage(option.rect, layer.image)

                    painter.setOpacity(1.0)

            layers = self._sprite.current_animation.frame_at(
                frame_index).surfaces

            for layer in layers:
                painter.drawImage(option.rect, layer.image)
Ejemplo n.º 44
0
class timeAnalogWidget(QWidget):

    time = pyqtSignal()

    def __init__(self, winParent):
        super(timeAnalogWidget, self).__init__()
        self.winParent = winParent
        self.rectangle = QRectF(0.0, 0.0, 300.0, 300.0)
        self.angle = -pi / 2
        self.angleMinutes = -pi / 2
        self.seconds = 900
        self.accountant = 0
        self.minutes = 0

        timer = QTimer(self)
        timer.start(1000)
        timer.timeout.connect(self.accountantTime)

    def drawWhiteZones(self, painter):
        self.setStyle(painter, QColor(255, 255, 255), QColor(255, 255, 255), 1)
        startAngle = 0 * 16
        spanAngle = 360 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)

    def drawCLockLines(self, painter):
        radius = 130
        angle = -pi / 2
        for i in range(0, 60):
            origx = self.rectangle.width() / 2 + (radius - 1) * math.cos(angle)
            origy = self.rectangle.height() / 2 + (radius -
                                                   1) * math.sin(angle)
            finx = 6 * math.cos(angle) + origx
            finy = 6 * math.sin(angle) + origy
            self.setStyle(painter, Qt.black, Qt.black, 3)
            painter.drawLine(QPoint(origx, origy), QPoint(finx, finy))
            angle = angle + (6 * pi / 180)

    def drawArrows(self, painter):
        radius = 130
        origx = self.rectangle.width() / 2
        origy = self.rectangle.height() / 2
        finx = radius * math.cos(self.angle) + origx
        finy = radius * math.sin(self.angle) + origy
        finMinutesx = radius / 2 * math.cos(self.angleMinutes) + origx
        finMinutesy = radius / 2 * math.sin(self.angleMinutes) + origy
        self.setStyle(painter, Qt.black, Qt.black, 3)
        painter.drawLine(QPoint(origx, origy), QPoint(finx, finy))
        painter.drawLine(QPoint(origx, origy), QPoint(finMinutesx,
                                                      finMinutesy))
        painter.drawEllipse(145, 145, 10, 10)

    def accountantTime(self):
        if self.accountant < self.seconds:
            self.accountant += 1
            self.angle = self.angle + (6 * pi / 180)
        if self.accountant % 60 == 0:
            self.minutes += 1
            self.angleMinutes = self.angleMinutes + (6 * pi / 180)

    def resetPen(self, painter):
        pen = QPen(Qt.black, 1)
        brush = QBrush()
        painter.setPen(pen)
        painter.setBrush(brush)

    def setStyle(self, painter, fillColor, penColor, stroke):
        brush = QBrush()
        pen = QPen(penColor, stroke)
        brush.setColor(fillColor)
        brush.setStyle(Qt.SolidPattern)
        painter.setBrush(brush)
        painter.setPen(pen)
        painter.setRenderHint(QPainter.Antialiasing)

    def paintEvent(self, event):
        painter = QPainter(self)
        self.drawWhiteZones(painter)
        self.drawArrows(painter)
        self.drawCLockLines(painter)

    def updateG(self):
        self.update()
Ejemplo n.º 45
0
class Node:
    width = 120

    def __init__(self, icon: str):
        super(Node, self)
        self.windowRect = QRectF(0, 0, Node.width, 20)
        self.item = None
        self.inputs = []
        self.icon = QPixmap(icon)

    def setPos(self, pos: QPointF):
        self.item.setPos(pos)

    def GetTitle(self):
        return ""

    def Inputs(self):
        return []

    def Outputs(self):
        return []

    def GetInputPoint(self, ids: int):
        ic = len(self.Inputs())
        oc = len(self.Outputs())
        m = max(ic, oc) * 10
        io = 25 + m - ic * 10 + ids * 20
        return self.item.pos() + QPointF(-5, io + 5)

    def GetOutputPoint(self, ids: int):
        ic = len(self.Inputs())
        oc = len(self.Outputs())
        m = max(ic, oc) * 10
        io = 25 + m - oc * 10 + ids * 20
        return self.item.pos() + QPointF(self.windowRect.width() + 5, io + 5)

    def GetInputId(self, pos: QPointF):
        pos = pos - self.item.pos()
        ic = len(self.Inputs())
        oc = len(self.Outputs())
        m = max(ic, oc) * 10
        io = 20 + m - ic * 10
        ids = int((pos.y() - io) / 20.0)
        if (ids < 0 or ids >= ic or pos.x() > self.windowRect.width() / 2):
            return -1
        return ids

    def GetOutputId(self, pos: QPointF):
        pos = pos - self.item.pos()
        ic = len(self.Inputs())
        oc = len(self.Outputs())
        m = max(ic, oc) * 10
        io = 20 + m - oc * 10
        ids = int((pos.y() - io) / 20.0)
        if (ids < 0 or ids >= oc or pos.x() < self.windowRect.width() / 2):
            return -1
        return ids

    def ItemsInit(self, scene: QGraphicsScene):
        ic = len(self.Inputs())
        oc = len(self.Outputs())
        m = max(ic, oc) * 10
        self.windowRect.setHeight(m * 2 + 20)
        ins = self.Inputs()
        ino = 20 + m - ic * 10
        ouo = 20 + m - oc * 10

        pix = scene.addPixmap(self.icon)
        pix.setPos(
            (self.windowRect.width() - self.icon.width()) * 0.5,
            20 + (self.windowRect.height() - 20 - self.icon.height()) * 0.5)
        pix.setParentItem(self.item)

        for i in range(0, ic):
            ti = scene.addText(ins[i])
            ti.setPos(0, i * 20 + ino)
            ti.setParentItem(self.item)
            ie = scene.addEllipse(
                QRectF(QPointF(-5, i * 20 + 5 + ino), QSizeF(10, 10)))
            ie.setParentItem(self.item)
            ie.setFlag(QGraphicsItem.ItemNegativeZStacksBehindParent)
            ie.setZValue(-1)

        ins = self.Outputs()
        for i in range(0, oc):
            ti = scene.addText(ins[i])
            ti.setPos(
                QPointF(self.windowRect.width() - ti.boundingRect().width(),
                        i * 20 + ouo))
            ti.setParentItem(self.item)
            ie = scene.addEllipse(
                QRectF(QPointF(self.windowRect.width() - 5, i * 20 + 5 + ouo),
                       QSizeF(10, 10)))
            ie.setParentItem(self.item)
            ie.setFlag(QGraphicsItem.ItemNegativeZStacksBehindParent)
            ie.setZValue(-1)

        self.inputs = []
        for i in range(0, ic):
            self.inputs.append(NodeConnector())
Ejemplo n.º 46
0
    def paint(self, painter, option, index):
        model = index.model()
        tile = model.tileAt(index)
        if (not tile):
            return
        tileImage = tile.image()
        if self.mTilesetView.drawGrid():
            _x = 1
        else:
            _x = 0
        extra = _x
        zoom = self.mTilesetView.scale()
        tileSize = tileImage.size() * zoom
        # Compute rectangle to draw the image in: bottom- and left-aligned
        targetRect = option.rect.adjusted(0, 0, -extra, -extra)
        targetRect.setTop(targetRect.bottom() - tileSize.height() + 1)
        targetRect.setRight(targetRect.left() + tileSize.width() - 1)
        # Draw the tile image
        zoomable = self.mTilesetView.zoomable()
        if zoomable:
            if (zoomable.smoothTransform()):
                painter.setRenderHint(QPainter.SmoothPixmapTransform)
        painter.drawPixmap(targetRect, tileImage)
        # Overlay with film strip when animated
        if (self.mTilesetView.markAnimatedTiles() and tile.isAnimated()):
            painter.save()

            scale = min(tileImage.width() / 32.0, tileImage.height() / 32.0)

            painter.setClipRect(targetRect)
            painter.translate(targetRect.right(), targetRect.bottom())
            painter.scale(scale * zoom, scale * zoom)
            painter.translate(-18, 3)
            painter.rotate(-45)
            painter.setOpacity(0.8)

            strip = QRectF(0, 0, 32, 6)

            painter.fillRect(strip, Qt.black)
            painter.setRenderHint(QPainter.Antialiasing)
            painter.setBrush(Qt.white)
            painter.setPen(Qt.NoPen)

            hole = QRectF(0, 0, strip.height() * 0.6, strip.height() * 0.6)
            step = (strip.height() - hole.height()) + hole.width()

            margin = (strip.height() - hole.height()) / 2
            x = (step - hole.width()) / 2
            while x < strip.right():
                hole.moveTo(x, margin)
                painter.drawRoundedRect(hole, 25, 25, Qt.RelativeSize)
                x += step

            painter.restore()

        # Overlay with highlight color when selected
        if (option.state & QStyle.State_Selected):
            opacity = painter.opacity()
            painter.setOpacity(0.5)
            painter.fillRect(targetRect, option.palette.highlight())
            painter.setOpacity(opacity)

        if (self.mTilesetView.isEditTerrain()):
            terrain = tile.terrain()
            paintTerrainOverlay(painter, terrain,
                                self.mTilesetView.terrainId(), targetRect,
                                option.palette.highlight().color())
            # Overlay with terrain corner indication when hovered
            if (index == self.mTilesetView.hoveredIndex()):
                pos = QPoint()
                x = self.mTilesetView.hoveredCorner()
                if x == 0:
                    pos = targetRect.topLeft()
                elif x == 1:
                    pos = targetRect.topRight()
                elif x == 2:
                    pos = targetRect.bottomLeft()
                elif x == 3:
                    pos = targetRect.bottomRight()

                painter.save()
                painter.setBrush(option.palette.highlight())
                painter.setClipRect(targetRect)
                painter.setRenderHint(QPainter.Antialiasing)
                pen = QPen(option.palette.highlight().color().darker(), 2)
                painter.setPen(pen)
                painter.drawEllipse(pos,
                                    targetRect.width() / 3,
                                    targetRect.height() / 3)
                painter.restore()
Ejemplo n.º 47
0
    def paint(self, painter, option, index):
        model = index.model()
        tile = model.tileAt(index)
        if (not tile):
            return
        tileImage = tile.image()
        if self.mTilesetView.drawGrid():
            _x = 1
        else:
            _x = 0
        extra = _x
        zoom = self.mTilesetView.scale()
        tileSize = tileImage.size() * zoom
        # Compute rectangle to draw the image in: bottom- and left-aligned
        targetRect = option.rect.adjusted(0, 0, -extra, -extra)
        targetRect.setTop(targetRect.bottom() - tileSize.height() + 1)
        targetRect.setRight(targetRect.left() + tileSize.width() - 1)
        # Draw the tile image
        zoomable = self.mTilesetView.zoomable()
        if zoomable:
            if (zoomable.smoothTransform()):
                painter.setRenderHint(QPainter.SmoothPixmapTransform)
        painter.drawPixmap(targetRect, tileImage)
        # Overlay with film strip when animated
        if (self.mTilesetView.markAnimatedTiles() and tile.isAnimated()):
            painter.save()

            scale = min(tileImage.width() / 32.0, tileImage.height() / 32.0)

            painter.setClipRect(targetRect)
            painter.translate(targetRect.right(), targetRect.bottom())
            painter.scale(scale * zoom, scale * zoom)
            painter.translate(-18, 3)
            painter.rotate(-45)
            painter.setOpacity(0.8)

            strip = QRectF(0, 0, 32, 6)
            
            painter.fillRect(strip, Qt.black)
            painter.setRenderHint(QPainter.Antialiasing)
            painter.setBrush(Qt.white)
            painter.setPen(Qt.NoPen)

            hole = QRectF(0, 0, strip.height() * 0.6, strip.height() * 0.6)
            step = (strip.height() - hole.height()) + hole.width()
            
            margin = (strip.height() - hole.height()) / 2
            x = (step - hole.width()) / 2
            while x < strip.right():
                hole.moveTo(x, margin)
                painter.drawRoundedRect(hole, 25, 25, Qt.RelativeSize)
                x += step
                
            painter.restore()
        
        # Overlay with highlight color when selected
        if (option.state & QStyle.State_Selected):
            opacity = painter.opacity()
            painter.setOpacity(0.5)
            painter.fillRect(targetRect, option.palette.highlight())
            painter.setOpacity(opacity)

        if (self.mTilesetView.isEditTerrain()):
            terrain = tile.terrain()
            paintTerrainOverlay(painter, terrain,
                                self.mTilesetView.terrainId(), targetRect,
                                option.palette.highlight().color())
            # Overlay with terrain corner indication when hovered
            if (index == self.mTilesetView.hoveredIndex()):
                pos = QPoint()
                x = self.mTilesetView.hoveredCorner()
                if x==0:
                    pos = targetRect.topLeft()
                elif x==1:
                    pos = targetRect.topRight()
                elif x==2:
                    pos = targetRect.bottomLeft()
                elif x==3:
                    pos = targetRect.bottomRight()

                painter.save()
                painter.setBrush(option.palette.highlight())
                painter.setClipRect(targetRect)
                painter.setRenderHint(QPainter.Antialiasing)
                pen = QPen(option.palette.highlight().color().darker(), 2)
                painter.setPen(pen)
                painter.drawEllipse(pos, targetRect.width() / 3, targetRect.height() / 3)
                painter.restore()
Ejemplo n.º 48
0
class MainWindow(QQuickWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self._background_color = QColor(204, 204, 204, 255)

        self.setClearBeforeRendering(False)
        self.beforeRendering.connect(self._render, type=Qt.DirectConnection)

        self._mouse_device = QtMouseDevice(self)
        self._mouse_device.setPluginId("qt_mouse")
        self._key_device = QtKeyDevice()
        self._key_device.setPluginId("qt_key")
        self._previous_focus = None  # type: Optional["QQuickItem"]

        self._app = QCoreApplication.instance()

        # Remove previously added input devices (if any). This can happen if the window was re-loaded.
        self._app.getController().removeInputDevice("qt_mouse")
        self._app.getController().removeInputDevice("qt_key")

        self._app.getController().addInputDevice(self._mouse_device)
        self._app.getController().addInputDevice(self._key_device)
        self._app.getController().getScene().sceneChanged.connect(
            self._onSceneChanged)
        self._preferences = Application.getInstance().getPreferences()

        self._preferences.addPreference("general/window_width", 1280)
        self._preferences.addPreference("general/window_height", 720)
        self._preferences.addPreference("general/window_left", 50)
        self._preferences.addPreference("general/window_top", 50)
        self._preferences.addPreference("general/window_state",
                                        Qt.WindowNoState)

        # Restore window geometry
        self.setWidth(int(self._preferences.getValue("general/window_width")))
        self.setHeight(int(
            self._preferences.getValue("general/window_height")))
        self.setPosition(
            int(self._preferences.getValue("general/window_left")),
            int(self._preferences.getValue("general/window_top")))

        # Make sure restored geometry is not outside the currently available screens
        screen_found = False
        for s in range(0, self._app.desktop().screenCount()):
            if self.geometry().intersects(
                    self._app.desktop().availableGeometry(s)):
                screen_found = True
                break
        if not screen_found:
            self.setPosition(50, 50)

        self.setWindowState(
            int(self._preferences.getValue("general/window_state")))
        self._mouse_x = 0
        self._mouse_y = 0

        self._mouse_pressed = False

        self._viewport_rect = QRectF(0, 0, 1.0, 1.0)

        self.closing.connect(self.preClosing)

        Application.getInstance().setMainWindow(self)
        self._fullscreen = False

        self._allow_resize = True

    # This event is triggered before hideEvent(self, event) event and might prevent window closing if
    # does not pass the check, for example if USB printer is printing
    # The implementation is in Cura.qml
    preClosing = pyqtSignal("QQuickCloseEvent*", arguments=["close"])

    def setAllowResize(self, allow_resize: bool):
        if self._allow_resize != allow_resize:
            if not allow_resize:
                self.setMaximumHeight(self.height())
                self.setMinimumHeight(self.height())
                self.setMaximumWidth(self.width())
                self.setMinimumWidth(self.width())
            else:
                self.setMaximumHeight(16777215)
                self.setMinimumHeight(0)
                self.setMaximumWidth(16777215)
                self.setMinimumWidth(0)
            self._allow_resize = allow_resize

    @pyqtSlot()
    def toggleFullscreen(self):
        if self._fullscreen:
            self.setVisibility(
                QQuickWindow.Windowed)  # Switch back to windowed
        else:
            self.setVisibility(QQuickWindow.FullScreen)  # Go to fullscreen
        self._fullscreen = not self._fullscreen

    def getBackgroundColor(self):
        return self._background_color

    def setBackgroundColor(self, color):
        self._background_color = color
        self._app.getRenderer().setBackgroundColor(color)

    backgroundColor = pyqtProperty(QColor,
                                   fget=getBackgroundColor,
                                   fset=setBackgroundColor)

    mousePositionChanged = pyqtSignal()

    @pyqtProperty(int, notify=mousePositionChanged)
    def mouseX(self):
        return self._mouse_x

    @pyqtProperty(int, notify=mousePositionChanged)
    def mouseY(self):
        return self._mouse_y

    def setViewportRect(self, rect):
        if rect != self._viewport_rect:
            self._viewport_rect = rect
            self._updateViewportGeometry(
                self.width() * self.devicePixelRatio(),
                self.height() * self.devicePixelRatio())
            self.viewportRectChanged.emit()

    viewportRectChanged = pyqtSignal()

    @pyqtProperty(QRectF, fset=setViewportRect, notify=viewportRectChanged)
    def viewportRect(self):
        return self._viewport_rect

#   Warning! Never reimplemented this as a QExposeEvent can cause a deadlock with QSGThreadedRender due to both trying
#   to claim the Python GIL.
#   def event(self, event):

    def mousePressEvent(self, event):
        super().mousePressEvent(event)
        if event.isAccepted():
            return

        if self.activeFocusItem(
        ) is not None and self.activeFocusItem() != self._previous_focus:
            self.activeFocusItem().setFocus(False)

        self._previous_focus = self.activeFocusItem()
        self._mouse_device.handleEvent(event)
        self._mouse_pressed = True

    def mouseMoveEvent(self, event):
        self._mouse_x = event.x()
        self._mouse_y = event.y()

        if self._mouse_pressed:
            self.mousePositionChanged.emit()

        super().mouseMoveEvent(event)
        if event.isAccepted():
            return

        self._mouse_device.handleEvent(event)

    def mouseReleaseEvent(self, event):
        super().mouseReleaseEvent(event)
        if event.isAccepted():
            return
        self._mouse_device.handleEvent(event)
        self._mouse_pressed = False

    def keyPressEvent(self, event):
        super().keyPressEvent(event)
        if event.isAccepted():
            return

        self._key_device.handleEvent(event)

    def keyReleaseEvent(self, event):
        super().keyReleaseEvent(event)
        if event.isAccepted():
            return

        self._key_device.handleEvent(event)

    def wheelEvent(self, event):
        super().wheelEvent(event)
        if event.isAccepted():
            return

        self._mouse_device.handleEvent(event)

    def moveEvent(self, event):
        QMetaObject.invokeMethod(self, "_onWindowGeometryChanged",
                                 Qt.QueuedConnection)

    def resizeEvent(self, event):
        super().resizeEvent(event)

        win_w = event.size().width() * self.devicePixelRatio()
        win_h = event.size().height() * self.devicePixelRatio()

        self._updateViewportGeometry(win_w, win_h)

        QMetaObject.invokeMethod(self, "_onWindowGeometryChanged",
                                 Qt.QueuedConnection)

    def hideEvent(self, event):
        if Application.getInstance().getMainWindow() == self:
            Application.getInstance().windowClosed()

    renderCompleted = Signal(type=Signal.Queued)

    def _render(self):
        renderer = self._app.getRenderer()
        view = self._app.getController().getActiveView()

        renderer.beginRendering()
        view.beginRendering()
        renderer.render()
        view.endRendering()
        renderer.endRendering()
        self.renderCompleted.emit()

    def _onSceneChanged(self, object):
        self.update()

    @pyqtSlot()
    def _onWindowGeometryChanged(self):
        if self.windowState() == Qt.WindowNoState:
            self._preferences.setValue("general/window_width", self.width())
            self._preferences.setValue("general/window_height", self.height())
            self._preferences.setValue("general/window_left", self.x())
            self._preferences.setValue("general/window_top", self.y())
            self._preferences.setValue("general/window_state",
                                       Qt.WindowNoState)
        elif self.windowState() == Qt.WindowMaximized:
            self._preferences.setValue("general/window_state",
                                       Qt.WindowMaximized)

    def _updateViewportGeometry(self, width: int, height: int):
        view_width = width * self._viewport_rect.width()
        view_height = height * self._viewport_rect.height()

        for camera in self._app.getController().getScene().getAllCameras():
            camera.setWindowSize(width, height)

            if camera.getAutoAdjustViewPort():
                camera.setViewportSize(view_width, view_height)
                projection_matrix = Matrix()
                if camera.isPerspective():
                    if view_width is not 0:
                        projection_matrix.setPerspective(
                            30, view_width / view_height, 1, 500)
                else:
                    projection_matrix.setOrtho(-view_width / 2, view_width / 2,
                                               -view_height / 2,
                                               view_height / 2, -500, 500)
                camera.setProjectionMatrix(projection_matrix)

        self._app.getRenderer().setViewportSize(view_width, view_height)
        self._app.getRenderer().setWindowSize(width, height)
Ejemplo n.º 49
0
class MainWindow(QQuickWindow):
    def __init__(self, parent = None):
        super(MainWindow, self).__init__(parent)

        self._background_color = QColor(204, 204, 204, 255)

        self.setClearBeforeRendering(False)
        self.beforeRendering.connect(self._render, type=Qt.DirectConnection)

        self._mouse_device = QtMouseDevice(self)
        self._mouse_device.setPluginId("qt_mouse")
        self._key_device = QtKeyDevice()
        self._key_device.setPluginId("qt_key")

        self._app = QCoreApplication.instance()
        self._app.getController().addInputDevice(self._mouse_device)
        self._app.getController().addInputDevice(self._key_device)
        self._app.getController().getScene().sceneChanged.connect(self._onSceneChanged)
        self._preferences = Preferences.getInstance()

        self._preferences.addPreference("general/window_width", 1280)
        self._preferences.addPreference("general/window_height", 720)
        self._preferences.addPreference("general/window_left", 50)
        self._preferences.addPreference("general/window_top", 50)
        self._preferences.addPreference("general/window_state", Qt.WindowNoState)

        # Restore window geometry
        self.setWidth(int(self._preferences.getValue("general/window_width")))
        self.setHeight(int(self._preferences.getValue("general/window_height")))
        self.setPosition(int(self._preferences.getValue("general/window_left")), int(self._preferences.getValue("general/window_top")))
        # Make sure restored geometry is not outside the currently available screens
        if not self.geometry().intersects(self.screen().availableGeometry()):
            self.setPosition(50,50)

        self.setWindowState(int(self._preferences.getValue("general/window_state")))
        self._mouse_x = 0
        self._mouse_y = 0

        self._viewport_rect = QRectF(0, 0, 1.0, 1.0)

        Application.getInstance().setMainWindow(self)
        self._fullscreen = False

    @pyqtSlot()
    def toggleFullscreen(self):
        if self._fullscreen:
            self.setVisibility(QQuickWindow.Windowed) # Switch back to windowed
        else:
            self.setVisibility(QQuickWindow.FullScreen) # Go to fullscreen
        self._fullscreen = not self._fullscreen

    def getBackgroundColor(self):
        return self._background_color

    def setBackgroundColor(self, color):
        self._background_color = color
        self._app.getRenderer().setBackgroundColor(color)

    backgroundColor = pyqtProperty(QColor, fget=getBackgroundColor, fset=setBackgroundColor)

    mousePositionChanged = pyqtSignal()
    @pyqtProperty(int, notify = mousePositionChanged)
    def mouseX(self):
        return self._mouse_x

    @pyqtProperty(int, notify = mousePositionChanged)
    def mouseY(self):
        return self._mouse_y

    def setViewportRect(self, rect):
        if rect != self._viewport_rect:
            self._viewport_rect = rect
            self._updateViewportGeometry(self.width() * self.devicePixelRatio(), self.height() * self.devicePixelRatio())
            self.viewportRectChanged.emit()

    viewportRectChanged = pyqtSignal()
    @pyqtProperty(QRectF, fset = setViewportRect, notify = viewportRectChanged)
    def viewportRect(self):
        return self._viewport_rect

#   Warning! Never reimplemented this as a QExposeEvent can cause a deadlock with QSGThreadedRender due to both trying
#   to claim the Python GIL.
#   def event(self, event):

    def mousePressEvent(self, event):
        super().mousePressEvent(event)
        if event.isAccepted():
            return

        self._mouse_device.handleEvent(event)

    def mouseMoveEvent(self, event):
        self._mouse_x = event.x()
        self._mouse_y = event.y()
        self.mousePositionChanged.emit()

        super().mouseMoveEvent(event)
        if event.isAccepted():
            return

        self._mouse_device.handleEvent(event)

    def mouseReleaseEvent(self, event):
        super().mouseReleaseEvent(event)
        if event.isAccepted():
            return

        self._mouse_device.handleEvent(event)

    def keyPressEvent(self, event):
        super().keyPressEvent(event)
        if event.isAccepted():
            return

        self._key_device.handleEvent(event)

    def keyReleaseEvent(self, event):
        super().keyReleaseEvent(event)
        if event.isAccepted():
            return

        self._key_device.handleEvent(event)

    def wheelEvent(self, event):
        super().wheelEvent(event)
        if event.isAccepted():
            return

        self._mouse_device.handleEvent(event)

    def moveEvent(self, event):
        QMetaObject.invokeMethod(self, "_onWindowGeometryChanged", Qt.QueuedConnection);

    def resizeEvent(self, event):
        super().resizeEvent(event)

        win_w = event.size().width() * self.devicePixelRatio()
        win_h = event.size().height() * self.devicePixelRatio()

        self._updateViewportGeometry(win_w, win_h)

        QMetaObject.invokeMethod(self, "_onWindowGeometryChanged", Qt.QueuedConnection);

    def hideEvent(self, event):
        Application.getInstance().windowClosed()

    def _render(self):
        renderer = self._app.getRenderer()
        view = self._app.getController().getActiveView()

        renderer.beginRendering()
        view.beginRendering()
        renderer.renderQueuedNodes()
        view.endRendering()
        renderer.endRendering()

    def _onSceneChanged(self, object):
        self.update()

    @pyqtSlot()
    def _onWindowGeometryChanged(self):
        if self.windowState() == Qt.WindowNoState:
            self._preferences.setValue("general/window_width", self.width())
            self._preferences.setValue("general/window_height", self.height())
            self._preferences.setValue("general/window_left", self.x())
            self._preferences.setValue("general/window_top", self.y())
            self._preferences.setValue("general/window_state", Qt.WindowNoState)
        elif self.windowState() == Qt.WindowMaximized:
            self._preferences.setValue("general/window_state", Qt.WindowMaximized)

    def _updateViewportGeometry(self, width, height):
        view_w = width * self._viewport_rect.width()
        view_h = height * self._viewport_rect.height()

        for camera in self._app.getController().getScene().getAllCameras():
            camera.setViewportSize(view_w, view_h)
            proj = Matrix()
            if camera.isPerspective():
                proj.setPerspective(30, view_w / view_h, 1, 500)
            else:
                proj.setOrtho(-view_w / 2, view_w / 2, -view_h / 2, view_h / 2, -500, 500)
            camera.setProjectionMatrix(proj)

        self._app.getRenderer().setViewportSize(view_w, view_h)
        self._app.getRenderer().setWindowSize(width, height)
Ejemplo n.º 50
0
    def table(self,
              rect: QRectF,
              lineData: list=None,
              columnCount: int=0,
              rowCount:int=0,
              w: dict=None,
              h: dict=None,
              size:int=18,
              border:bool=True) -> None:
        #lineData: [{x:1,y:2,text:"hallo"}...]
        #    oder  [{x:[1,3],y:[2,4],text."hallo"}..]

        for id in range(len(lineData)):
            if not isinstance(lineData[id], dict):
                lineData[id] = {"text": "{}".format(lineData[id])}

        if w is None:
            w = dict()
        if h is None:
            h = dict()


        #Berechne Reservierte Größen
        reserved = {"w": 0, "h": 0}

        for wr in w.values():
            reserved["w"] += wr
        for hr in h.values():
            reserved["h"] += hr

        #Berechne Zellengrößen
        marginX = 5
        marginY = 5

        remCol = columnCount - len(w)
        remRow = rowCount - len(h)

        regularWidth = (rect.width() - reserved["w"] - (columnCount + 1) * marginX) / remCol
        regularHeight = (rect.height() - reserved["h"] - (rowCount + 1) * marginY) / remRow

        def calcCellUsage() -> list:
            index = 0
            pos = []

            for column in range(columnCount):
                l = list()
                for row in range(rowCount):
                    l.append(None)
                pos.append(l)

            curX = 0
            curY = 0
            for i in lineData:
                if "x" in i.keys():
                    x = i["x"]
                    if isinstance(x, int):
                        x = range(x, x + 1)
                    elif isinstance(x, tuple):
                        x = range(x[0], x[-1] + 1)
                else:
                    x = range(curX, curX + 1)
                    i["x"] = x

                if "y" in i.keys():
                    y = i["y"]
                    if isinstance(y, int):
                        y = range(y, y + 1)
                    elif isinstance(y, tuple):
                        x = range(y[0], y[-1] + 1)
                else:
                    y = range(curY, curY + 1)

                    i["y"] = y

                curX = x[-1] + 1
                curY = y[-1]

                if curX >= columnCount:
                    curX = 0
                    curY += 1

                for xx in x:
                    for yy in y:
                        pos[xx][yy] = index
                index += 1
            return pos

        def calcWidth(col:int) -> float:
            try:
                if col in w.keys():
                    return w[col]
            except IndexError:
                pass
            return regularWidth

        def calcHeight(row:int) -> float:
            try:
                if row in h.keys():
                    return h[row]
            except IndexError:
                pass
            return regularHeight

        def calcCellSize(col:int, row: int) -> tuple:
            if col >= columnCount:
                raise IndexError
            if row >= rowCount:
                raise IndexError
            if pos[col][row] is None:
                raise IndexError

            width = calcWidth(col)
            height = calcHeight(row)

            id = pos[col][row]
            try:
                if pos[col + 1][row] is id:
                    width += calcCellSize(col + 1, row)[0] + marginX
            except IndexError:
                pass

            try:
                if pos[col][row + 1] is id:
                    height += calcCellSize(col, row + 1)[1] + marginY
            except IndexError:
                pass
            return width, height

        def calcCumulativeWidth(col: int) -> float:
            if col is 0:
                return marginX
            x = calcWidth(col - 1) + marginX + calcCumulativeWidth(col - 1)
            return x

        def calcCumulativeHeight(row: int) -> float:
            if row is 0:
                return marginY
            return calcHeight(row - 1) + marginY + calcCumulativeHeight(row - 1)

        def calcCell(index: int) -> tuple:
            x = lineData[index]["x"]
            if not isinstance(x, int):
                x = x[0]
            y = lineData[index]["y"]
            if not isinstance(y, int):
                y = y[0]

            left = rect.left() + calcCumulativeWidth(x)
            top = rect.top() + calcCumulativeHeight(y)

            d = calcCellSize(x, y)

            return left, top, d[0], d[1]

        def getFontOptions(index: int) -> dict:
            data = {
                "size": size,
                "color": self._fg,
                "shaded": False,
                "bold": False
            }

            elem = lineData[index]

            if "size" in elem.keys():
                data["size"] = elem["size"]
            if "color" in elem.keys():
                data["color"] = elem["color"]
            if "shaded" in elem.keys():
                data["shaded"] = elem["shaded"]
            if "bold" in elem.keys():
                data["bold"] = elem["bold"]
            return data

        if border:
            self.rect(rect, False)

        pos = calcCellUsage()

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

        painter.restore()
Ejemplo n.º 52
0
    def interactiveResize(self, mousePos):
        """
        Handle the interactive resize of the shape.
        :type mousePos: QPointF
        """
        scene = self.scene()
        snap = scene.mainwindow.snapToGrid
        size = scene.GridSize
        offset = self.handleSize + self.handleMove
        moved = self.label.moved

        R = QRectF(self.boundingRect())
        D = QPointF(0, 0)

        minBoundW = self.minwidth + offset * 2
        minBoundH = self.minheight + offset * 2

        self.prepareGeometryChange()

        if self.mousePressHandle == self.handleTL:

            fromX = self.mousePressBound.left()
            fromY = self.mousePressBound.top()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toX = snapF(toX, size, -offset, snap)
            toY = snapF(toY, size, -offset, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() - minBoundW + R.width())
                R.setLeft(R.left() - minBoundW + R.width())
            if R.height() < minBoundH:
                D.setY(D.y() - minBoundH + R.height())
                R.setTop(R.top() - minBoundH + R.height())

            self.selection.setLeft(R.left())
            self.selection.setTop(R.top())

            self.background[self.indexT] = QPointF(R.left() + R.width() / 2,
                                                   R.top())
            self.background[self.indexB] = QPointF(
                R.left() + R.width() / 2, self.background[self.indexB].y())
            self.background[self.indexL] = QPointF(R.left(),
                                                   R.top() + R.height() / 2)
            self.background[self.indexE] = QPointF(R.left(),
                                                   R.top() + R.height() / 2)
            self.background[self.indexR] = QPointF(
                self.background[self.indexR].x(),
                R.top() + R.height() / 2)

            self.polygon[self.indexT] = QPointF(R.left() + R.width() / 2,
                                                R.top() + offset)
            self.polygon[self.indexB] = QPointF(R.left() + R.width() / 2,
                                                self.polygon[self.indexB].y())
            self.polygon[self.indexL] = QPointF(R.left() + offset,
                                                R.top() + R.height() / 2)
            self.polygon[self.indexE] = QPointF(R.left() + offset,
                                                R.top() + R.height() / 2)
            self.polygon[self.indexR] = QPointF(self.polygon[self.indexR].x(),
                                                R.top() + R.height() / 2)

        elif self.mousePressHandle == self.handleTM:

            fromY = self.mousePressBound.top()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toY = snapF(toY, size, -offset, snap)
            D.setY(toY - fromY)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.height() < minBoundH:
                D.setY(D.y() - minBoundH + R.height())
                R.setTop(R.top() - minBoundH + R.height())

            self.selection.setTop(R.top())

            self.background[self.indexT] = QPointF(
                self.background[self.indexT].x(), R.top())
            self.background[self.indexL] = QPointF(
                self.background[self.indexL].x(),
                R.top() + R.height() / 2)
            self.background[self.indexE] = QPointF(
                self.background[self.indexE].x(),
                R.top() + R.height() / 2)
            self.background[self.indexR] = QPointF(
                self.background[self.indexR].x(),
                R.top() + R.height() / 2)

            self.polygon[self.indexT] = QPointF(self.polygon[self.indexT].x(),
                                                R.top() + offset)
            self.polygon[self.indexL] = QPointF(self.polygon[self.indexL].x(),
                                                R.top() + R.height() / 2)
            self.polygon[self.indexE] = QPointF(self.polygon[self.indexE].x(),
                                                R.top() + R.height() / 2)
            self.polygon[self.indexR] = QPointF(self.polygon[self.indexR].x(),
                                                R.top() + R.height() / 2)

        elif self.mousePressHandle == self.handleTR:

            fromX = self.mousePressBound.right()
            fromY = self.mousePressBound.top()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toX = snapF(toX, size, +offset, snap)
            toY = snapF(toY, size, -offset, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() + minBoundW - R.width())
                R.setRight(R.right() + minBoundW - R.width())
            if R.height() < minBoundH:
                D.setY(D.y() - minBoundH + R.height())
                R.setTop(R.top() - minBoundH + R.height())

            self.selection.setRight(R.right())
            self.selection.setTop(R.top())

            self.background[self.indexT] = QPointF(R.right() - R.width() / 2,
                                                   R.top())
            self.background[self.indexB] = QPointF(
                R.right() - R.width() / 2, self.background[self.indexB].y())
            self.background[self.indexL] = QPointF(
                self.background[self.indexL].x(),
                R.top() + R.height() / 2)
            self.background[self.indexE] = QPointF(
                self.background[self.indexE].x(),
                R.top() + R.height() / 2)
            self.background[self.indexR] = QPointF(R.right(),
                                                   R.top() + R.height() / 2)

            self.polygon[self.indexT] = QPointF(R.right() - R.width() / 2,
                                                R.top() + offset)
            self.polygon[self.indexB] = QPointF(R.right() - R.width() / 2,
                                                self.polygon[self.indexB].y())
            self.polygon[self.indexL] = QPointF(self.polygon[self.indexL].x(),
                                                R.top() + R.height() / 2)
            self.polygon[self.indexE] = QPointF(self.polygon[self.indexE].x(),
                                                R.top() + R.height() / 2)
            self.polygon[self.indexR] = QPointF(R.right() - offset,
                                                R.top() + R.height() / 2)

        elif self.mousePressHandle == self.handleML:

            fromX = self.mousePressBound.left()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toX = snapF(toX, size, -offset, snap)
            D.setX(toX - fromX)
            R.setLeft(toX)

            ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() - minBoundW + R.width())
                R.setLeft(R.left() - minBoundW + R.width())

            self.selection.setLeft(R.left())

            self.background[self.indexL] = QPointF(
                R.left(),
                self.mousePressBound.top() + self.mousePressBound.height() / 2)
            self.background[self.indexE] = QPointF(
                R.left(),
                self.mousePressBound.top() + self.mousePressBound.height() / 2)
            self.background[self.indexT] = QPointF(
                R.left() + R.width() / 2, self.background[self.indexT].y())
            self.background[self.indexB] = QPointF(
                R.left() + R.width() / 2, self.background[self.indexB].y())

            self.polygon[self.indexL] = QPointF(
                R.left() + offset,
                self.mousePressBound.top() + self.mousePressBound.height() / 2)
            self.polygon[self.indexE] = QPointF(
                R.left() + offset,
                self.mousePressBound.top() + self.mousePressBound.height() / 2)
            self.polygon[self.indexT] = QPointF(R.left() + R.width() / 2,
                                                self.polygon[self.indexT].y())
            self.polygon[self.indexB] = QPointF(R.left() + R.width() / 2,
                                                self.polygon[self.indexB].y())

        elif self.mousePressHandle == self.handleMR:

            fromX = self.mousePressBound.right()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toX = snapF(toX, size, +offset, snap)
            D.setX(toX - fromX)
            R.setRight(toX)

            ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() + minBoundW - R.width())
                R.setRight(R.right() + minBoundW - R.width())

            self.selection.setRight(R.right())

            self.background[self.indexR] = QPointF(
                R.right(),
                self.mousePressBound.top() + self.mousePressBound.height() / 2)
            self.background[self.indexT] = QPointF(
                R.right() - R.width() / 2, self.background[self.indexT].y())
            self.background[self.indexB] = QPointF(
                R.right() - R.width() / 2, self.background[self.indexB].y())

            self.polygon[self.indexR] = QPointF(
                R.right() - offset,
                self.mousePressBound.top() + self.mousePressBound.height() / 2)
            self.polygon[self.indexT] = QPointF(R.right() - R.width() / 2,
                                                self.polygon[self.indexT].y())
            self.polygon[self.indexB] = QPointF(R.right() - R.width() / 2,
                                                self.polygon[self.indexB].y())

        elif self.mousePressHandle == self.handleBL:

            fromX = self.mousePressBound.left()
            fromY = self.mousePressBound.bottom()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toX = snapF(toX, size, -offset, snap)
            toY = snapF(toY, size, +offset, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() - minBoundW + R.width())
                R.setLeft(R.left() - minBoundW + R.width())
            if R.height() < minBoundH:
                D.setY(D.y() + minBoundH - R.height())
                R.setBottom(R.bottom() + minBoundH - R.height())

            self.selection.setLeft(R.left())
            self.selection.setBottom(R.bottom())

            self.background[self.indexT] = QPointF(
                R.left() + R.width() / 2, self.background[self.indexT].y())
            self.background[self.indexB] = QPointF(R.left() + R.width() / 2,
                                                   R.bottom())
            self.background[self.indexL] = QPointF(R.left(),
                                                   R.bottom() - R.height() / 2)
            self.background[self.indexE] = QPointF(R.left(),
                                                   R.bottom() - R.height() / 2)
            self.background[self.indexR] = QPointF(
                self.background[self.indexR].x(),
                R.bottom() - R.height() / 2)

            self.polygon[self.indexT] = QPointF(R.left() + R.width() / 2,
                                                self.polygon[self.indexT].y())
            self.polygon[self.indexB] = QPointF(R.left() + R.width() / 2,
                                                R.bottom() - offset)
            self.polygon[self.indexL] = QPointF(R.left() + offset,
                                                R.bottom() - R.height() / 2)
            self.polygon[self.indexE] = QPointF(R.left() + offset,
                                                R.bottom() - R.height() / 2)
            self.polygon[self.indexR] = QPointF(self.polygon[self.indexR].x(),
                                                R.bottom() - R.height() / 2)

        elif self.mousePressHandle == self.handleBM:

            fromY = self.mousePressBound.bottom()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toY = snapF(toY, size, +offset, snap)
            D.setY(toY - fromY)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.height() < minBoundH:
                D.setY(D.y() + minBoundH - R.height())
                R.setBottom(R.bottom() + minBoundH - R.height())

            self.selection.setBottom(R.bottom())

            self.background[self.indexB] = QPointF(
                self.background[self.indexB].x(), R.bottom())
            self.background[self.indexL] = QPointF(
                self.background[self.indexL].x(),
                R.top() + R.height() / 2)
            self.background[self.indexE] = QPointF(
                self.background[self.indexE].x(),
                R.top() + R.height() / 2)
            self.background[self.indexR] = QPointF(
                self.background[self.indexR].x(),
                R.top() + R.height() / 2)

            self.polygon[self.indexB] = QPointF(self.polygon[self.indexB].x(),
                                                R.bottom() - offset)
            self.polygon[self.indexL] = QPointF(self.polygon[self.indexL].x(),
                                                R.top() + R.height() / 2)
            self.polygon[self.indexE] = QPointF(self.polygon[self.indexE].x(),
                                                R.top() + R.height() / 2)
            self.polygon[self.indexR] = QPointF(self.polygon[self.indexR].x(),
                                                R.top() + R.height() / 2)

        elif self.mousePressHandle == self.handleBR:

            fromX = self.mousePressBound.right()
            fromY = self.mousePressBound.bottom()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toX = snapF(toX, size, +offset, snap)
            toY = snapF(toY, size, +offset, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() + minBoundW - R.width())
                R.setRight(R.right() + minBoundW - R.width())
            if R.height() < minBoundH:
                D.setY(D.y() + minBoundH - R.height())
                R.setBottom(R.bottom() + minBoundH - R.height())

            self.selection.setRight(R.right())
            self.selection.setBottom(R.bottom())

            self.background[self.indexT] = QPointF(
                R.right() - R.width() / 2, self.background[self.indexT].y())
            self.background[self.indexB] = QPointF(R.right() - R.width() / 2,
                                                   R.bottom())
            self.background[self.indexL] = QPointF(
                self.background[self.indexL].x(),
                R.bottom() - R.height() / 2)
            self.background[self.indexE] = QPointF(
                self.background[self.indexE].x(),
                R.bottom() - R.height() / 2)
            self.background[self.indexR] = QPointF(R.right(),
                                                   R.bottom() - R.height() / 2)

            self.polygon[self.indexT] = QPointF(R.right() - R.width() / 2,
                                                self.polygon[self.indexT].y())
            self.polygon[self.indexB] = QPointF(R.right() - R.width() / 2,
                                                R.bottom() - offset)
            self.polygon[self.indexL] = QPointF(self.polygon[self.indexL].x(),
                                                R.bottom() - R.height() / 2)
            self.polygon[self.indexE] = QPointF(self.polygon[self.indexE].x(),
                                                R.bottom() - R.height() / 2)
            self.polygon[self.indexR] = QPointF(R.right() - offset,
                                                R.bottom() - R.height() / 2)

        self.updateHandles()
        self.updateTextPos(moved=moved)
        self.updateAnchors(self.mousePressData, D)
Ejemplo n.º 53
0
class NodeItemRenderer:
    """ Class is used to separate the drawing from the logic.
        This class renders a given node to a graphics scene """

    __blobConnectorSizeWithPadding = Constants.nodeItemConnectorPaddding * 2 + Constants.connectorItemOuterSize

    def __init__(self, nodeItem):
        self.__nodeItem = nodeItem

        # create lists to store TextRects for the node item
        self.__headRects = list()
        self.__blobTopNameRects = list()
        self.__blobBottomNameRects = list()

        # create Qt rects for the head and body area
        self.__rectHead = QRectF(0, 0, 1, 1)
        self.__rectBlobArea = QRectF(0, 0, 1, 1)

        # create Qt rect for enclosing rects used as bounding rects
        self.__rectAll = QRectF(0, 0, 1, 1)
        self.__rectAllSelected = QRectF(0, 0, 1, 1)

        self.__hasCurrentPhase = True

        self.update()

    def boundingRect(self):
        # selected layers have a outer 'glow', so selected layers are bigger than not selected layers
        if self.__nodeItem.isSelected():
            return self.__rectAllSelected
        else:
            return self.__rectAll

    def update(self):
        """ Recalculates positions of name, type, blobs, etc. """

        # clear lists
        del self.__headRects[:]
        del self.__blobTopNameRects[:]
        del self.__blobBottomNameRects[:]

        # get size of the name
        nameWidth = Constants.nodeItemFontNameMetrics.width(
            self.__nodeItem.getName()) + Constants.nodeItemHeadPadding
        nameHeight = Constants.nodeItemFontTypeMetrics.height()
        self.__headRects.append(
            TextRect(self.__nodeItem.getName(),
                     QRectF(0, 0, nameWidth, nameHeight),
                     Constants.nodeItemFontName))

        # get size of the type
        typeWidth = Constants.nodeItemFontTypeMetrics.width(
            self.__nodeItem.getTypeString()) + Constants.nodeItemHeadPadding
        typeHeight = Constants.nodeItemFontTypeMetrics.height()
        self.__headRects.append(
            TextRect(self.__nodeItem.getTypeString(),
                     QRectF(0, 0, typeWidth, typeHeight),
                     Constants.nodeItemFontType))

        # get size of the phase (if the node has the paramter include.phase
        if len(self.__nodeItem.getPhase()) > 0:
            phaseString = "Phase: " + self.__nodeItem.getPhase()
            phaseWidth = Constants.nodeItemFontTypeMetrics.width(
                phaseString) + Constants.nodeItemHeadPadding
            phaseHeight = Constants.nodeItemFontTypeMetrics.height()
            self.__headRects.append(
                TextRect(phaseString, QRectF(0, 0, phaseWidth, phaseHeight),
                         Constants.nodeItemFontType))

        # calculate rect width and height for names of blobs
        topBlobsInfo = self.__buildBlobNameRectList(
            self.__nodeItem.getTopConnectors())
        bottomBlobsInfo = self.__buildBlobNameRectList(
            self.__nodeItem.getBottomConnectors())
        self.__blobTopNameRects = topBlobsInfo[0]
        self.__blobBottomNameRects = bottomBlobsInfo[0]

        blobAreaWidth = 2 * self.__blobConnectorSizeWithPadding + Constants.nodeItemConnectorPaddding + \
                        bottomBlobsInfo[1] + topBlobsInfo[1]
        blobAreaHeight = max(topBlobsInfo[2], bottomBlobsInfo[2],
                             Constants.nodeItemMinBlobAreaHeight)

        # calculate the total width of the node
        rectWidth = blobAreaWidth
        for textRect in self.__headRects:
            rectWidth = max(rectWidth, textRect.rect.width())

        # change the width of the head rects to be the full width of the node
        self.__updateHeadRects(rectWidth, self.__headRects)

        # calculate the total node height
        rectHeight = self.__rectHead.bottom() + blobAreaHeight

        # create Qt rects for the body and enclosing width the top left at (0, 0)
        self.__rectBlobArea = QRectF(0, self.__rectHead.bottom(), rectWidth,
                                     blobAreaHeight)
        self.__rectAll = QRectF(0, 0, rectWidth, rectHeight)

        # calculate a larger box to support selection (outer glow)
        selSize = Constants.nodeItemSelectionSize
        self.__rectAllSelected = QRectF(self.__rectAll.left() - selSize,
                                        self.__rectAll.top() - selSize,
                                        self.__rectAll.width() + 2 * selSize,
                                        self.__rectAll.height() + 2 * selSize)

        # after calculating the total width, adjust the name rects to align at the left/right
        self.__adjustBlobNameRectPositions(self.__blobTopNameRects,
                                           self.__rectAll.width(),
                                           self.__rectHead.bottom(), False)
        self.__adjustBlobNameRectPositions(self.__blobBottomNameRects,
                                           self.__rectAll.width(),
                                           self.__rectHead.bottom(), True)

    def __updateHeadRects(self, finalWidth, headRects):
        """ Resizes the size of the head text rect after the total needed width was calculated """

        totalHeadHeight = 0
        for x in range(0, len(headRects)):
            # special case for the first head text -> start at (0, 0) and has space at the top
            if x == 0:
                headRects[x].rect = QRectF(
                    0, 0, finalWidth,
                    headRects[x].rect.height() + Constants.nodeItemTextMargin)
            # special case for the last head text -> has space at the bottom
            elif x == len(headRects) - 1:
                headRects[x].rect = QRectF(
                    0, headRects[x - 1].rect.bottom(), finalWidth,
                    headRects[x].rect.height() + Constants.nodeItemTextMargin)
            else:
                headRects[x].rect = QRectF(0, headRects[x - 1].rect.bottom(),
                                           finalWidth,
                                           headRects[x].rect.height())

            # add the rects height to the total head rect height
            totalHeadHeight += headRects[x].rect.height()

        # create Qt rect for the head part
        self.__rectHead = QRectF(0, 0, finalWidth, totalHeadHeight)

    def __buildBlobNameRectList(self, connectors):
        """ Creates rects for all top/bottom connectors (bounding rect for the text only) """

        # check if the connector or the blob name text is higher
        blobNameHeightRect = max(Constants.nodeItemFontBlobMetrics.height(),
                                 self.__blobConnectorSizeWithPadding)

        blobNameRectList = list()

        maxWidth = 0
        height = 0

        # for each connector calculate the width of the name and create a Qt rect.
        # calculate the max width of all blob names and the total height
        for item in connectors:
            blobName = item.getBlobName()
            blobNameWidth = Constants.nodeItemFontBlobMetrics.width(
                blobName) + Constants.nodeItemTextMargin
            blobRect = QRectF(0, 0, blobNameWidth, blobNameHeightRect)
            blobNameRectList.append(TextRect(blobName, blobRect))
            maxWidth = max(maxWidth, blobNameWidth)
            height += blobNameHeightRect

        return blobNameRectList, maxWidth, height

    def __adjustBlobNameRectPositions(self, blobRectNames, totalWidth,
                                      aboveHeight, atLeftBorder):
        """ Recalculates the blob name rects after the total width of the node was calculated """
        i = 0

        for item in blobRectNames:
            # position at the left side of the node
            x = self.__blobConnectorSizeWithPadding

            # or position at the right side of the node
            if not atLeftBorder:
                x = totalWidth - self.__blobConnectorSizeWithPadding - item.rect.width(
                )

            # calculate starting position (head size + position in body)
            item.rect = QRectF(x, aboveHeight + i * item.rect.height(),
                               item.rect.width(), item.rect.height())

            i += 1

    def updateConnectorPositions(self, connectors, atLeftBorder):
        """ Repositions the connector items after the new size of the node was calculated """

        i = 0
        for item in connectors:
            # position the connector item at the left border of the node,left of the blob name rect
            x = Constants.nodeItemConnectorPaddding + Constants.connectorItemOuterSize / 2

            # or at the right border of the node, right of the blob name rect
            if not atLeftBorder:
                x = self.__rectAll.width() - Constants.nodeItemConnectorPaddding - Constants.connectorItemOuterSize + \
                    Constants.connectorItemOuterSize / 2

            # set the y coordinate of the connector item to be at the center of the blob name rect
            y = self.__rectHead.bottom() + Constants.nodeItemConnectorPaddding + Constants.connectorItemOuterSize / 2 + \
                i * self.__blobConnectorSizeWithPadding

            item.setPos(QPointF(x, y))
            i += 1

    def paint(self, painter):
        # use antialiasing for both text and box
        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.setRenderHint(QPainter.TextAntialiasing, True)

        # get the opacity of the node item, layers with the include.phase parameter have a different opacity
        opacity = Constants.itemOpacityInPhase
        if not self.__nodeItem.getNodeEditor().isCurrentPhase(
                self.__nodeItem.getPhase()):
            opacity = Constants.itemOpacityNotInPhase

        # draw a outer 'glow' around the node item if the node is selected
        if self.__nodeItem.isSelected():
            selectedColor = Constants.selectedColor
            selectedColor.setAlpha(opacity)
            painter.setPen(QPen(selectedColor,
                                Constants.nodeItemSelectionSize))
            painter.drawRect(self.__rectAllSelected)
            painter.fillRect(self.__rectAllSelected, QBrush(selectedColor))

        # get the type color for the header (name and type)
        typeColor = LayerColorDefinitions.getTypeColor(
            self.__nodeItem.getType())
        typeColor.setRgb(typeColor.red(), typeColor.green(), typeColor.blue(),
                         opacity)

        # get background color
        backgroundColor = Constants.itemBackgroundColorLight
        backgroundColor.setAlpha(opacity)

        # set a linear gradient for the header (type color -> background color)
        gradient = QLinearGradient(0, self.__rectHead.top(), 0,
                                   self.__rectHead.bottom())
        gradient.setColorAt(0, typeColor)
        gradient.setColorAt(0.5, backgroundColor)

        # draw background and border for the header
        painter.fillRect(self.__rectHead, QBrush(gradient))

        # draw background for the blob area
        painter.fillRect(self.__rectBlobArea, QBrush(backgroundColor))
        borderColor = Constants.itemBorderColor
        if self.__nodeItem.getIsInPlace():
            borderColor = Constants.itemInPlaceColor
        borderColor.setAlpha(opacity)
        painter.setPen(QPen(borderColor, Constants.nodeItemBorderSize))

        # draw outer border around the node
        painter.drawRect(self.__rectAll)

        # draw a line to separate header and connectors
        borSize = Constants.nodeItemBorderSize
        painter.setPen(QPen(borderColor, borSize))
        painter.drawLine(self.__rectHead.left() + borSize / 2,
                         self.__rectHead.bottom() - borSize / 2,
                         self.__rectHead.right() - borSize / 2,
                         self.__rectHead.bottom() - borSize / 2)

        painter.setPen(QPen(QColor(0, 0, 0, opacity)))

        # draw text of header
        if len(self.__headRects) > 1:
            # align the first head text at the bottom to provide some space at the top
            painter.setFont(self.__headRects[0].font)
            painter.drawText(self.__headRects[0].rect,
                             Qt.AlignHCenter | Qt.AlignBottom,
                             self.__headRects[0].text)

            # align other head texts at the center
            for i in range(1, len(self.__headRects) - 1):
                painter.setFont(self.__headRects[i].font)
                painter.drawText(self.__headRects[i].rect, Qt.AlignCenter,
                                 self.__headRects[i].text)

            # align the last head text at the top to provide some space at the bottom
            painter.setFont(self.__headRects[-1].font)
            painter.drawText(self.__headRects[-1].rect,
                             Qt.AlignHCenter | Qt.AlignTop,
                             self.__headRects[-1].text)

        # there is only one head text, so align it at the center
        elif len(self.__headRects) == 1:
            painter.setFont(self.__headRects[0].font)
            painter.drawText(self.__headRects[0].rect,
                             Qt.AlignHCenter | Qt.AlignCenter,
                             self.__headRects[0].text)

        # draw blob names
        painter.setFont(Constants.nodeItemFontBlob)
        for item in self.__blobBottomNameRects:
            painter.drawText(item.rect, Qt.AlignVCenter | Qt.AlignLeft,
                             item.text)
        for item in self.__blobTopNameRects:
            painter.drawText(item.rect, Qt.AlignVCenter | Qt.AlignRight,
                             item.text)