def __init__(self, app):
        super(FsApp, self).__init__()
        self.app       = app
        self.selRect   = None
        self.screenPix = None

        # Set up the user interface from Designer.
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        #self.setWindowOpacity(0.5)
        #self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
        self.captureScreen()
        self.showMaximized()
        self.showFullScreen()


        #capture screen and display
        rec = QApplication.desktop().screenGeometry()
        height = rec.height()
        width = rec.width()
        self.ui.labPix.resize(width, height)
        self.ui.labPix.setScaledContents(True)
        self.ui.labPix.setPixmap(self.screenPix)

        #start rubberband
        self.rubberband = QRubberBand(QRubberBand.Rectangle, self)
        bla = QtGui.QPalette()
        bla.setBrush(QtGui.QPalette.Highlight, QtGui.QBrush(QtCore.Qt.red))
        self.rubberband.setPalette(bla)
        self.rubberband.setWindowOpacity(1.0)
Beispiel #2
0
    def mousePressEvent(self, event):
        super(PieView, self).mousePressEvent(event)

        self.origin = event.pos()
        if not self.rubberBand:
            self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.rubberBand.setGeometry(QRect(self.origin, QSize()))
        self.rubberBand.show()
    def __init__(self, parent = None, func=None):

        self.func = func
        QLabel.__init__(self, parent)
        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.origin = QPoint()
        self.slitpos = 250
        self.focus = (333,666,333,666)  #xs,xe,ys,ye
        self.geometry = (0,0,1000,1000) #x,y,w,h
 def mousePressEvent(self, event):
     print("ImageHolder: " + str(event.pos()))
     self.mousePressPoint = event.pos();
     if self.cropMode:
         if hasattr(self, "currentQRubberBand"):
             self.currentQRubberBand.hide()
         self.currentQRubberBand = QRubberBand(QRubberBand.Rectangle, self)
         self.currentQRubberBand.setGeometry(QRect(self.mousePressPoint, QSize()))
         self.currentQRubberBand.show()
Beispiel #5
0
 def __init__(self, parent=None):
     super(SelectWidget, self).__init__(parent)
     self.setWindowOpacity(0.5)
     self.setupUi(self)
     desktop = QtWidgets.QDesktopWidget()
     self.resize(desktop.availableGeometry().width(), desktop.availableGeometry().height())
     self.rubberband = QRubberBand(
         QRubberBand.Rectangle, self)
     self.setMouseTracking(True)
class MyLabel(QLabel):

    def __init__(self, parent = None, func=None):

        self.func = func
        QLabel.__init__(self, parent)
        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.origin = QPoint()
        self.slitpos = 250
        self.focus = (333,666,333,666)  #xs,xe,ys,ye
        self.geometry = (0,0,1000,1000) #x,y,w,h

    def paintEvent(self, event):
        QLabel.paintEvent(self, event)
        painter = QPainter(self)
        painter.setPen(Qt.red)
        x,y,w,h = self.geometry
        d = 20
        painter.drawLine(x+w//2-self.slitpos*w//1000,y,
                         x+w//2-self.slitpos*w//1000,y+h)
        painter.drawLine(x+w//2-self.slitpos*w//1000-d,y+h/2,
                         x+w//2-self.slitpos*w//1000,  y+h/2-d)
        painter.drawLine(x+w//2-self.slitpos*w//1000-d,y+h/2,
                         x+w//2-self.slitpos*w//1000,  y+h/2+d)
        painter.drawLine(x+w//2+self.slitpos*w//1000,y,
                         x+w//2+self.slitpos*w//1000,y+h)
        painter.drawLine(x+w//2+self.slitpos*w//1000+d,y+h//2,
                         x+w//2+self.slitpos*w//1000,  y+h//2-d)
        painter.drawLine(x+w//2+self.slitpos*w//1000+d,y+h//2,
                         x+w//2+self.slitpos*w//1000,  y+h//2+d)
        painter.setPen(Qt.green)
        painter.drawRect(x+w*self.focus[0]//1000,y+h*self.focus[2]//1000,w*(self.focus[1]-self.focus[0])//1000,h*(self.focus[3]-self.focus[2])//1000)
        
    def mousePressEvent(self, event):
    
        if event.button() == Qt.LeftButton:
        
            self.origin = QPoint(event.pos())
            self.rubberBand.setGeometry(QRect(self.origin, QSize()))
            self.rubberBand.show()
    
    def mouseMoveEvent(self, event):
    
        if not self.origin.isNull():
            self.rubberBand.setGeometry(QRect(self.origin, event.pos()).normalized())
    
    def mouseReleaseEvent(self, event):
    
        if event.button() == Qt.LeftButton:
            self.rubberBand.hide()
            self.region = QRect(self.origin, event.pos()).normalized()
            if self.func is not None:
                self.func(self.region)
    def mousePressEvent(self, event):
        """"""

        if self.capture_widget:

            self.selection_area = QRubberBand(QRubberBand.Rectangle, self)
            self.selection_area.setGeometry(QRect(event.pos(), QSize()))
            self.origin = event.pos()
            self.selection_area.show()

        super().mousePressEvent(event)
Beispiel #8
0
	def __init__(self, mainwin):
		QLabel.__init__(self)

		self.setAcceptDrops(True)

		self.marker = QRubberBand(QRubberBand.Rectangle, self)
		self.markOrigin = self.markEnd = None

		self.setContextMenuPolicy(Qt.ActionsContextMenu)
		self.addAction(mainwin.cropAction)
		self.addAction(mainwin.saveAction)
Beispiel #9
0
class ImageView(QGraphicsView):
    def __init__(self, parent=None):
        QGraphicsView.__init__(self, parent)

        self.go_prev_img = parent.go_prev_img
        self.go_next_img = parent.go_next_img

        pal = self.palette()
        pal.setColor(self.backgroundRole(), Qt.black)
        self.setPalette(pal)
        self.setFrameShape(QFrame.NoFrame)

    def mousePressEvent(self, event):
        """Go to the next / previous image, or be able to drag the image with a hand."""
        if event.button() == Qt.LeftButton:
            x = event.x()
            if x < 100:
                self.go_prev_img()
            elif x > self.width() - 100:
                self.go_next_img()
            else:
                self.setDragMode(QGraphicsView.ScrollHandDrag)
        QGraphicsView.mousePressEvent(self, event)

    def mouseReleaseEvent(self, event):
        self.setDragMode(QGraphicsView.NoDrag)
        QGraphicsView.mouseReleaseEvent(self, event)

    def zoom(self, zoomratio):
        self.scale(zoomratio, zoomratio)

    def wheelEvent(self, event):
        zoomratio = 1.1
        if event.angleDelta().y() < 0:
            zoomratio = 1.0 / zoomratio
        self.scale(zoomratio, zoomratio)

    def setup_crop(self, width, height):
        self.rband = QRubberBand(QRubberBand.Rectangle, self)
        coords = self.mapFromScene(0, 0, width, height)
        self.rband.setGeometry(QRect(coords.boundingRect()))
        self.rband.show()

    def crop_draw(self, x, y, width, height):
        coords = self.mapFromScene(x, y, width, height)
        self.rband.setGeometry(QRect(coords.boundingRect()))

    def get_coords(self):
        rect = self.rband.geometry()
        size = self.mapToScene(rect).boundingRect()
        x = int(size.x())
        y = int(size.y())
        width = int(size.width())
        height = int(size.height())
        return (x, y, width, height)
Beispiel #10
0
 def __init__(self, parent):
     super(FrameLess, self).__init__(parent)
     self._parent = parent
     self._cursorChanged = False
     self._leftButtonPressed = False
     self._mouseMove = Edge.NoEdge
     self._mousePress = Edge.NoEdge
     self._borderWidth = 5
     self._rubberBand = QRubberBand(QRubberBand.Rectangle)
     self._parent.setWindowFlags(Qt.FramelessWindowHint | Qt.CustomizeWindowHint | Qt.Window)
     self._parent.setAttribute(Qt.WA_Hover)
     self._parent.setMouseTracking(True)
     self._parent.installEventFilter(self)
class ImageWidget(QLabel):

    areaSelected = pyqtSignal(float, float, float, float, QPixmap)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.rubberBand  = None
        self.origin         = None

    def mousePressEvent(self, event):
        self.origin = event.pos()
        if self.rubberBand is None:
            self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.rubberBand.setGeometry(QRect(self.origin, QSize()))
        self.rubberBand.show()

    def mouseMoveEvent(self, event):
        self.rubberBand.setGeometry(QRect(self.origin, event.pos()).normalized())


    def mouseReleaseEvent(self, event):
        self.rubberBand.hide()
        zoreRect = QRect(self.origin, event.pos()).normalized()
        pixmapSize = self.pixmap().size()
        pixX1 = zoreRect.x()
        pixX2 = zoreRect.x() + zoreRect.width()
        pixY1 = zoreRect.y()
        pixY2 = zoreRect.y() + zoreRect.height()
        width  = pixmapSize.width()
        height = pixmapSize.height()

        x1 = pixX1/width 
        x1 = x1 if x1 >= 0.0 else 0.0
        x1 = x1 if x1 <= 1.0 else 1.0
        y1 = pixY1/height 
        y1 = y1 if y1 >= 0.0 else 0.0
        y1 = y1 if y1 <= 1.0 else 1.0
        x2 = pixX2/width 
        x2 = x2 if x2 >= 0.0 else 0.0
        x2 = x2 if x2 <= 1.0 else 1.0
        y2 = pixY2/height 
        y2 = y2 if y2 >= 0.0 else 0.0
        y2 = y2 if y2 <= 1.0 else 1.0

        rect = QRect(min(pixX1, pixX2), min(pixY1, pixY2), abs(pixX1- pixX2), abs(pixY1- pixY2))
        selectedImg = self.pixmap().copy(rect)
        
        self.areaSelected.emit(min(x1, x2), min(y1, y2), np.abs(x1-x2), np.abs(y1-y2), selectedImg)
Beispiel #12
0
class BandMixin(object):
	def __init__(self, **kwargs):
		super(BandMixin, self).__init__(**kwargs)
		self.__band = None

	def showBand(self, *geom):
		if not self.__band:
			self.__band = QRubberBand(QRubberBand.Rectangle, parent=self)
		self.__band.setGeometry(*geom)
		self.__band.show()

	def hideBand(self):
		if self.__band:
			self.__band.hide()
			self.__band.setParent(None)
			self.__band = None
Beispiel #13
0
 def __init__(self, path, parent=None):
     super(DragWidget, self).__init__(parent)
     self.setMinimumSize(400, 200)
     self.setAcceptDrops(True)
     self.parent = parent
     # self.parent.menu.connect(self.delete_icon)
     self.modifier = False
     self.rubberband = QRubberBand(QRubberBand.Rectangle, self)
     self.path = path
     self.icons = []
     self.icon_offsetx = 0
     self.icon_offsety = 0
     # self.clipicon = None
     # self.moving_icons = []
     self.read_drawer()
     self.clean_up()
Beispiel #14
0
    def __init__(self, parent=None):
        """
        Initialisation of the View Object. This is called by the gui created
        with the QTDesigner.
        @param parent: Main is passed as a pointer for reference.
        """
        super(MyGraphicsView, self).__init__(parent)
        self.currentItem = None

        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QGraphicsView.AnchorViewCenter)

        # self.setDragMode(QGraphicsView.RubberBandDrag )
        self.setDragMode(QGraphicsView.NoDrag)

        self.parent = parent
        self.mppos = None

        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.prvRectRubberBand = QtCore.QRect()
Beispiel #15
0
 def __init__(self, mainwindow, scene):
     """
     Initialize the main scene.
     :type mainwindow: MainWindow
     :type scene: DiagramScene
     """
     super().__init__(scene)
     self.setContextMenuPolicy(Qt.PreventContextMenu)
     self.setDragMode(QGraphicsView.NoDrag)
     self.setOptimizationFlags(QGraphicsView.DontAdjustForAntialiasing)
     self.setOptimizationFlags(QGraphicsView.DontSavePainterState)
     self.setViewportUpdateMode(QGraphicsView.MinimalViewportUpdate)
     self.mainwindow = mainwindow
     self.mousePressCenterPos = None
     self.mousePressPos = None
     self.moveTimer = None
     self.rubberBandOrigin = None
     self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
     self.rubberBand.hide()
     self.zoom = 1.00
    def __init__(self, parent=None):

        super(ResizableRubberBandWithGrip, self).__init__(parent)
        self.setAttribute(Qt.WA_DeleteOnClose)

        self.setWindowTitle("Defter: Screenshot")

        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)

        self.setAttribute(Qt.WA_TranslucentBackground)
        self.setAttribute(Qt.WA_NoSystemBackground)

        # self.setAttribute(Qt.WA_PaintOnScreen)
        # self.setAttribute(Qt.WA_OpaquePaintEvent, False)
        # self.setStyleSheet("QWidget{background:transparent;}")
        # self.setStyleSheet("QWidget{background-color:none;}")
        # self.setStyleSheet("background-color: rgba(255, 255, 255, 40%);")

        # self.setWindowOpacity(0.7)

        layout = QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)

        grip1 = MySizeGrip(self)
        # grip2 = QSizeGrip(self)
        # grip3 = QSizeGrip(self)
        grip4 = MySizeGrip(self)
        layout.addWidget(grip1, 0, Qt.AlignLeft | Qt.AlignTop)
        # layout.addWidget(grip3, 0, Qt.AlignRight | Qt.AlignTop)
        # layout.addWidget(grip2, 0, Qt.AlignLeft | Qt.AlignBottom)
        layout.addWidget(grip4, 0, Qt.AlignRight | Qt.AlignBottom)
        self.rubberband = QRubberBand(QRubberBand.Rectangle, self)
        self.rubberband.move(0, 0)
        self.rubberband.show()

        self.show()
class FsApp(QMainWindow):

    def __init__(self, app):
        super(FsApp, self).__init__()
        self.app       = app
        self.selRect   = None
        self.screenPix = None

        # Set up the user interface from Designer.
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        #self.setWindowOpacity(0.5)
        #self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
        self.captureScreen()
        self.showMaximized()
        self.showFullScreen()


        #capture screen and display
        rec = QApplication.desktop().screenGeometry()
        height = rec.height()
        width = rec.width()
        self.ui.labPix.resize(width, height)
        self.ui.labPix.setScaledContents(True)
        self.ui.labPix.setPixmap(self.screenPix)

        #start rubberband
        self.rubberband = QRubberBand(QRubberBand.Rectangle, self)
        bla = QtGui.QPalette()
        bla.setBrush(QtGui.QPalette.Highlight, QtGui.QBrush(QtCore.Qt.red))
        self.rubberband.setPalette(bla)
        self.rubberband.setWindowOpacity(1.0)

    def captureScreen(self):
        screens = self.app.screens()
        self.screenPix = screens[0].grabWindow(0)

    def mousePressEvent(self, event):
        self.origin = event.pos()
        self.rubberband.setGeometry(QtCore.QRect(self.origin, QtCore.QSize()))
        self.rubberband.show()
        QWidget.mousePressEvent(self, event)

    def mouseMoveEvent(self, event):
        if self.rubberband.isVisible():
            self.rubberband.setGeometry(QtCore.QRect(self.origin, event.pos()).normalized())
        QWidget.mouseMoveEvent(self, event)

    def mouseReleaseEvent(self, event):
        if self.rubberband.isVisible():
            self.selRect = self.rubberband.geometry()
            self.rubberband.hide()
            codePix = self.screenPix.copy(    self.selRect.x(),
                            self.selRect.y(), 
                            self.selRect.width(),
                            self.selRect.height())
            QApplication.clipboard().setPixmap(codePix)
            self.exit()
        QWidget.mouseReleaseEvent(self, event)

    def exit(self):
        sys.exit(0)
class ResizableRubberBandWithGrip(QWidget):

    # containerResized = Signal(QSize)
    enter_or_return_key_pressed = pyqtSignal(QRect)
    esc_key_pressed = pyqtSignal()

    # ---------------------------------------------------------------------
    def __init__(self, parent=None):

        super(ResizableRubberBandWithGrip, self).__init__(parent)
        self.setAttribute(Qt.WA_DeleteOnClose)

        self.setWindowTitle("Defter: Screenshot")

        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)

        self.setAttribute(Qt.WA_TranslucentBackground)
        self.setAttribute(Qt.WA_NoSystemBackground)

        # self.setAttribute(Qt.WA_PaintOnScreen)
        # self.setAttribute(Qt.WA_OpaquePaintEvent, False)
        # self.setStyleSheet("QWidget{background:transparent;}")
        # self.setStyleSheet("QWidget{background-color:none;}")
        # self.setStyleSheet("background-color: rgba(255, 255, 255, 40%);")

        # self.setWindowOpacity(0.7)

        layout = QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)

        grip1 = MySizeGrip(self)
        # grip2 = QSizeGrip(self)
        # grip3 = QSizeGrip(self)
        grip4 = MySizeGrip(self)
        layout.addWidget(grip1, 0, Qt.AlignLeft | Qt.AlignTop)
        # layout.addWidget(grip3, 0, Qt.AlignRight | Qt.AlignTop)
        # layout.addWidget(grip2, 0, Qt.AlignLeft | Qt.AlignBottom)
        layout.addWidget(grip4, 0, Qt.AlignRight | Qt.AlignBottom)
        self.rubberband = QRubberBand(QRubberBand.Rectangle, self)
        self.rubberband.move(0, 0)
        self.rubberband.show()

        self.show()

    def mousePressEvent(self, event):
        self._mousePressPos = None
        self._mouseMovePos = None
        if event.button() == Qt.LeftButton:
            self._mousePressPos = event.globalPos()
            self._mouseMovePos = event.globalPos()

        super(ResizableRubberBandWithGrip, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if event.buttons() == Qt.LeftButton:
            # adjust offset from clicked point to origin of widget
            currPos = self.mapToGlobal(self.pos())
            globalPos = event.globalPos()
            diff = globalPos - self._mouseMovePos
            newPos = self.mapFromGlobal(currPos + diff)
            self.move(newPos)

            self._mouseMovePos = globalPos

        super(ResizableRubberBandWithGrip, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        if self._mousePressPos:
            moved = event.globalPos() - self._mousePressPos
            if moved.manhattanLength() > 3:
                event.ignore()
                return

        super(ResizableRubberBandWithGrip, self).mouseReleaseEvent(event)

    # ---------------------------------------------------------------------
    def resizeEvent(self, event):

        # self.containerResized.emit((self.size()))
        self.rubberband.resize(self.size())
        super(ResizableRubberBandWithGrip, self).resizeEvent(event)

    # ---------------------------------------------------------------------
    def mouseDoubleClickEvent(self, event):
        self.hide()
        self.enter_or_return_key_pressed.emit(self.geometry())
        # self.close()
        # self.deleteLater()

    # ---------------------------------------------------------------------
    def keyPressEvent(self, event):

        if event.key() == Qt.Key_Escape:
            self.esc_key_pressed.emit()
        elif event.key() == Qt.Key_Enter or Qt.Key_Return:
            self.hide()
            self.enter_or_return_key_pressed.emit(self.geometry())
            # self.close()
            # self.deleteLater()

        # return ResizableRubberBandWithGripForImageResizing.keyPressEvent(self, event)
        super(ResizableRubberBandWithGrip, self).keyPressEvent(event)
Beispiel #19
0
 def __init__(self, parent=None):
     self._parent_class = _parent_class
     QLabel.__init__(self, parent)
     self.selection = QRubberBand(QRubberBand.Rectangle, self)
class PieView(QAbstractItemView):
    def __init__(self, parent=None):
        super(PieView, self).__init__(parent)

        self.horizontalScrollBar().setRange(0, 0)
        self.verticalScrollBar().setRange(0, 0)

        self.margin = 8
        self.totalSize = 300
        self.pieSize = self.totalSize - 2 * self.margin
        self.validItems = 0
        self.totalValue = 0.0
        self.origin = QPoint()
        self.rubberBand = None

    def dataChanged(self, topLeft, bottomRight, roles):
        super(PieView, self).dataChanged(topLeft, bottomRight, roles)

        self.validItems = 0
        self.totalValue = 0.0

        for row in range(self.model().rowCount(self.rootIndex())):

            index = self.model().index(row, 1, self.rootIndex())
            value = self.model().data(index)

            if value is not None and value > 0.0:
                self.totalValue += value
                self.validItems += 1

        self.viewport().update()

    def edit(self, index, trigger, event):
        if index.column() == 0:
            return super(PieView, self).edit(index, trigger, event)
        else:
            return False

    def indexAt(self, point):
        if self.validItems == 0:
            return QModelIndex()

        # Transform the view coordinates into contents widget coordinates.
        wx = point.x() + self.horizontalScrollBar().value()
        wy = point.y() + self.verticalScrollBar().value()

        if wx < self.totalSize:
            cx = wx - self.totalSize / 2
            cy = self.totalSize / 2 - wy
            # positive cy for items above the center

            # Determine the distance from the center point of the pie chart.
            d = (cx**2 + cy**2)**0.5

            if d == 0 or d > self.pieSize / 2:
                return QModelIndex()

            # Determine the angle of the point.
            angle = (180 / math.pi) * math.acos(cx / d)
            if cy < 0:
                angle = 360 - angle

            # Find the relevant slice of the pie.
            startAngle = 0.0

            for row in range(self.model().rowCount(self.rootIndex())):

                index = self.model().index(row, 1, self.rootIndex())
                value = self.model().data(index)

                if value > 0.0:
                    sliceAngle = 360 * value / self.totalValue

                    if angle >= startAngle and angle < (startAngle +
                                                        sliceAngle):
                        return self.model().index(row, 1, self.rootIndex())

                    startAngle += sliceAngle

        else:
            itemHeight = QFontMetrics(self.viewOptions().font).height()
            listItem = int((wy - self.margin) / itemHeight)
            validRow = 0

            for row in range(self.model().rowCount(self.rootIndex())):

                index = self.model().index(row, 1, self.rootIndex())
                if self.model().data(index) > 0.0:

                    if listItem == validRow:
                        return self.model().index(row, 0, self.rootIndex())

                    # Update the list index that corresponds to the next valid
                    # row.
                    validRow += 1

        return QModelIndex()

    def isIndexHidden(self, index):
        return False

    def itemRect(self, index):
        if not index.isValid():
            return QRect()

        # Check whether the index's row is in the list of rows represented
        # by slices.

        if index.column() != 1:
            valueIndex = self.model().index(index.row(), 1, self.rootIndex())
        else:
            valueIndex = index

        value = self.model().data(valueIndex)
        if value is not None and value > 0.0:

            listItem = 0
            for row in range(index.row() - 1, -1, -1):
                if self.model().data(self.model().index(
                        row, 1, self.rootIndex())) > 0.0:
                    listItem += 1

            if index.column() == 0:

                itemHeight = QFontMetrics(self.viewOptions().font).height()
                return QRect(self.totalSize,
                             int(self.margin + listItem * itemHeight),
                             self.totalSize - self.margin, int(itemHeight))
            elif index.column() == 1:
                return self.viewport().rect()

        return QRect()

    def itemRegion(self, index):
        if not index.isValid():
            return QRegion()

        if index.column() != 1:
            return QRegion(self.itemRect(index))

        if self.model().data(index) <= 0.0:
            return QRegion()

        startAngle = 0.0
        for row in range(self.model().rowCount(self.rootIndex())):

            sliceIndex = self.model().index(row, 1, self.rootIndex())
            value = self.model().data(sliceIndex)

            if value > 0.0:
                angle = 360 * value / self.totalValue

                if sliceIndex == index:
                    slicePath = QPainterPath()
                    slicePath.moveTo(self.totalSize / 2, self.totalSize / 2)
                    slicePath.arcTo(self.margin, self.margin,
                                    self.margin + self.pieSize,
                                    self.margin + self.pieSize, startAngle,
                                    angle)
                    slicePath.closeSubpath()

                    return QRegion(slicePath.toFillPolygon().toPolygon())

                startAngle += angle

        return QRegion()

    def horizontalOffset(self):
        return self.horizontalScrollBar().value()

    def mousePressEvent(self, event):
        super(PieView, self).mousePressEvent(event)

        self.origin = event.pos()
        if not self.rubberBand:
            self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.rubberBand.setGeometry(QRect(self.origin, QSize()))
        self.rubberBand.show()

    def mouseMoveEvent(self, event):
        if self.rubberBand:
            self.rubberBand.setGeometry(
                QRect(self.origin, event.pos()).normalized())

        super(PieView, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        super(PieView, self).mouseReleaseEvent(event)

        if self.rubberBand:
            self.rubberBand.hide()

        self.viewport().update()

    def moveCursor(self, cursorAction, modifiers):
        current = self.currentIndex()

        if cursorAction in (QAbstractItemView.MoveLeft,
                            QAbstractItemView.MoveUp):

            if current.row() > 0:
                current = self.model().index(current.row() - 1,
                                             current.column(),
                                             self.rootIndex())
            else:
                current = self.model().index(0, current.column(),
                                             self.rootIndex())

        elif cursorAction in (QAbstractItemView.MoveRight,
                              QAbstractItemView.MoveDown):

            if current.row() < self.rows(current) - 1:
                current = self.model().index(current.row() + 1,
                                             current.column(),
                                             self.rootIndex())
            else:
                current = self.model().index(
                    self.rows(current) - 1, current.column(), self.rootIndex())

        self.viewport().update()
        return current

    def paintEvent(self, event):
        selections = self.selectionModel()
        option = self.viewOptions()
        state = option.state

        background = option.palette.base()
        foreground = QPen(option.palette.color(QPalette.WindowText))
        textPen = QPen(option.palette.color(QPalette.Text))
        highlightedPen = QPen(option.palette.color(QPalette.HighlightedText))

        painter = QPainter(self.viewport())
        painter.setRenderHint(QPainter.Antialiasing)

        painter.fillRect(event.rect(), background)
        painter.setPen(foreground)

        # Viewport rectangles
        pieRect = QRect(self.margin, self.margin, self.pieSize, self.pieSize)
        keyPoint = QPoint(self.totalSize - self.horizontalScrollBar().value(),
                          self.margin - self.verticalScrollBar().value())

        if self.validItems > 0:
            painter.save()
            painter.translate(pieRect.x() - self.horizontalScrollBar().value(),
                              pieRect.y() - self.verticalScrollBar().value())
            painter.drawEllipse(0, 0, self.pieSize, self.pieSize)
            startAngle = 0.0

            for row in range(self.model().rowCount(self.rootIndex())):

                index = self.model().index(row, 1, self.rootIndex())
                value = self.model().data(index)

                if value > 0.0:
                    angle = 360 * value / self.totalValue

                    colorIndex = self.model().index(row, 0, self.rootIndex())
                    color = self.model().data(colorIndex, Qt.DecorationRole)

                    if self.currentIndex() == index:
                        painter.setBrush(QBrush(color, Qt.Dense4Pattern))
                    elif selections.isSelected(index):
                        painter.setBrush(QBrush(color, Qt.Dense3Pattern))
                    else:
                        painter.setBrush(QBrush(color))

                    painter.drawPie(0, 0, self.pieSize, self.pieSize,
                                    int(startAngle * 16), int(angle * 16))

                    startAngle += angle

            painter.restore()

            keyNumber = 0

            for row in range(self.model().rowCount(self.rootIndex())):
                index = self.model().index(row, 1, self.rootIndex())
                value = self.model().data(index)

                if value > 0.0:
                    labelIndex = self.model().index(row, 0, self.rootIndex())

                    option = self.viewOptions()
                    option.rect = self.visualRect(labelIndex)
                    if selections.isSelected(labelIndex):
                        option.state |= QStyle.State_Selected
                    if self.currentIndex() == labelIndex:
                        option.state |= QStyle.State_HasFocus
                    self.itemDelegate().paint(painter, option, labelIndex)

                    keyNumber += 1

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

    def rows(self, index):
        return self.model().rowCount(self.model().parent(index))

    def rowsInserted(self, parent, start, end):
        for row in range(start, end + 1):
            index = self.model().index(row, 1, self.rootIndex())
            value = self.model().data(index)

            if value is not None and value > 0.0:
                self.totalValue += value
                self.validItems += 1

        super(PieView, self).rowsInserted(parent, start, end)

    def rowsAboutToBeRemoved(self, parent, start, end):
        for row in range(start, end + 1):
            index = self.model().index(row, 1, self.rootIndex())
            value = self.model().data(index)

            if value is not None and value > 0.0:
                self.totalValue -= value
                self.validItems -= 1

        super(PieView, self).rowsAboutToBeRemoved(parent, start, end)

    def scrollContentsBy(self, dx, dy):
        self.viewport().scroll(dx, dy)

    def scrollTo(self, index, ScrollHint):
        area = self.viewport().rect()
        rect = self.visualRect(index)

        if rect.left() < area.left():
            self.horizontalScrollBar().setValue(
                self.horizontalScrollBar().value() + rect.left() - area.left())
        elif rect.right() > area.right():
            self.horizontalScrollBar().setValue(
                self.horizontalScrollBar().value() +
                min(rect.right() - area.right(),
                    rect.left() - area.left()))

        if rect.top() < area.top():
            self.verticalScrollBar().setValue(
                self.verticalScrollBar().value() + rect.top() - area.top())
        elif rect.bottom() > area.bottom():
            self.verticalScrollBar().setValue(
                self.verticalScrollBar().value() +
                min(rect.bottom() - area.bottom(),
                    rect.top() - area.top()))

    def setSelection(self, rect, command):
        # Use content widget coordinates because we will use the itemRegion()
        # function to check for intersections.

        contentsRect = rect.translated(
            self.horizontalScrollBar().value(),
            self.verticalScrollBar().value()).normalized()

        rows = self.model().rowCount(self.rootIndex())
        columns = self.model().columnCount(self.rootIndex())
        indexes = []

        for row in range(rows):
            for column in range(columns):
                index = self.model().index(row, column, self.rootIndex())
                region = self.itemRegion(index)
                if region.intersects(QRegion(contentsRect)):
                    indexes.append(index)

        if len(indexes) > 0:
            firstRow = indexes[0].row()
            lastRow = indexes[0].row()
            firstColumn = indexes[0].column()
            lastColumn = indexes[0].column()

            for i in range(1, len(indexes)):
                firstRow = min(firstRow, indexes[i].row())
                lastRow = max(lastRow, indexes[i].row())
                firstColumn = min(firstColumn, indexes[i].column())
                lastColumn = max(lastColumn, indexes[i].column())

            selection = QItemSelection(
                self.model().index(firstRow, firstColumn, self.rootIndex()),
                self.model().index(lastRow, lastColumn, self.rootIndex()))
            self.selectionModel().select(selection, command)
        else:
            noIndex = QModelIndex()
            selection = QItemSelection(noIndex, noIndex)
            self.selectionModel().select(selection, command)

        self.update()

    def updateGeometries(self):
        self.horizontalScrollBar().setPageStep(self.viewport().width())
        self.horizontalScrollBar().setRange(
            0, max(0, 2 * self.totalSize - self.viewport().width()))
        self.verticalScrollBar().setPageStep(self.viewport().height())
        self.verticalScrollBar().setRange(
            0, max(0, self.totalSize - self.viewport().height()))

    def verticalOffset(self):
        return self.verticalScrollBar().value()

    def visualRect(self, index):
        rect = self.itemRect(index)
        if rect.isValid():
            return QRect(rect.left() - self.horizontalScrollBar().value(),
                         rect.top() - self.verticalScrollBar().value(),
                         rect.width(), rect.height())
        else:
            return rect

    def visualRegionForSelection(self, selection):
        region = QRegion()

        for span in selection:
            for row in range(span.top(), span.bottom() + 1):
                for col in range(span.left(), span.right() + 1):
                    index = self.model().index(row, col, self.rootIndex())
                    region += self.visualRect(index)

        return region
Beispiel #21
0
 def __init__(self, parent=None):
     super().__init__(parent=parent)
     self.initialClick = QPoint()
     self.selectionBand = QRubberBand(QRubberBand.Rectangle, self)
     self.selecting = False
Beispiel #22
0
class SelectWidget(QWidget, Ui_Form2):

    select = [0,0,0,0]

    def __init__(self, parent=None):
        super(SelectWidget, self).__init__(parent)
        self.setWindowOpacity(0.5)
        self.setupUi(self)
        desktop = QtWidgets.QDesktopWidget()
        self.resize(desktop.availableGeometry().width(), desktop.availableGeometry().height())
        self.rubberband = QRubberBand(
            QRubberBand.Rectangle, self)
        self.setMouseTracking(True)

    def mousePressEvent(self, event):
        self.select[0] = event.screenPos().x()
        self.select[1] = event.screenPos().y()
        self.origin = event.pos()
        self.rubberband.setGeometry(
            QtCore.QRect(self.origin, QtCore.QSize()))
        self.rubberband.show()
        QWidget.mousePressEvent(self, event)

    def mouseMoveEvent(self, event):
        if self.rubberband.isVisible():
            self.rubberband.setGeometry(
                QtCore.QRect(self.origin, event.pos()).normalized())
        QWidget.mouseMoveEvent(self, event)

    def mouseReleaseEvent(self, event):
        self.select[2] = event.screenPos().x()
        self.select[3] = event.screenPos().y()
        if self.rubberband.isVisible():
            self.rubberband.hide()
            rect = self.rubberband.geometry()

        # ポインタ座標を左上→右下に揃える
        if self.select[0] > self.select[2]:
            tmp = self.select[0]
            self.select[0] = self.select[2]
            self.select[2] = tmp
        if self.select[1] > self.select[3]:
            tmp = self.select[1]
            self.select[1] = self.select[3]
            self.select[3] = tmp
        # 選択した面積がゼロの場合は何もしないで関数を終わる
        if self.select[0]==self.select[2] or self.select[1]==self.select[3]:
            QWidget.mouseReleaseEvent(self, event)
            self.close()
            return
        # ポインタ座標をメインウインドウに設定する
        area = ''
        for point in self.select:
            area = area + str(int(point)) + ','
        main_window.lineEdit.setText(area[0:-1])
        self.close()
        QWidget.mouseReleaseEvent(self, event)
Beispiel #23
0
class QTrappingPattern(pg.ScatterPlotItem):
    """Interface between QJansenScreen GUI and CGH pipeline.
    Implements logic for manipulating traps.
    """

    trapAdded = pyqtSignal(QTrap)
    sigCompute = pyqtSignal(object)

    def __init__(self, parent=None, *args, **kwargs):
        super(QTrappingPattern, self).__init__(*args, **kwargs)
        self.setParent(parent)  # this is not set by ScatterPlotItem
        self.setPxMode(False)  # scale plot symbols with window
        # Rubberband selection
        self.selection = QRubberBand(QRubberBand.Rectangle, self.parent())
        self.origin = QPoint()
        # traps, selected trap and active group
        self.traps = QTrapGroup(self)
        self.trap = None
        self.group = None
        self._prev = None
        self.selected = []
        self._appearanceOutdated = False
        self._hologramOutdated = False

    @property
    def prev(self):
        return self._prev

    @prev.setter
    def prev(self, prev):
        if self._prev is not None:
            try:
                self._prev.state = states.normal
            except:
                logger.debug(
                    'warning: cannot set _prev.state (trapgroup may have been deleted)'
                )
        self._prev = prev
        if self.prev is not None: prev.state = states.special

    @pyqtSlot()
    def toggleAppearance(self):
        logger.debug('toggleAppearance')
        self._appearanceOutdated = True

    @pyqtSlot()
    def toggleHologram(self):
        logger.debug('toggleHologram')
        self._hologramOutdated = True

    @pyqtSlot(object)
    def refresh(self, frame):
        self.refreshAppearance()
        self.refreshHologram()

    @pyqtSlot()
    def refreshAppearance(self):
        """Provide a list of spots to screen for plotting.

        This will be called by children when their properties change.
        Changes can be triggered by mouse events, by interaction with
        property widgets, or by direct programmatic control of traps
        or groups.
        """
        if self._appearanceOutdated:
            traps = self.traps.flatten()
            spots = [trap.spot for trap in traps]
            self.setData(spots=spots)
            self._appearanceOutdated = False
            logger.debug('refreshAppearance')

    @pyqtSlot()
    def refreshHologram(self):
        if self._hologramOutdated:
            traps = self.traps.flatten()
            self.sigCompute.emit(traps)
            self._hologramOutdated = False
            logger.debug('refreshHologram')

    def selectedPoint(self, position):
        '''Index of trap at position of mouse click'''
        points = self.pointsAt(position)
        if len(points) == 0:
            return None
        return self.points().tolist().index(points[0])

    # Selecting traps and groups of traps
    def clickedTrap(self, pos):
        """Return the trap at the specified position
        """
        coords = self.mapFromScene(pos)
        index = self.selectedPoint(coords)
        found = index is not None
        return self.traps.flatten()[index] if found else None

    def groupOf(self, obj):
        """Return the highest-level group containing the specified object.
        """
        if obj is None:
            return None
        while obj.parent() is not self.traps:
            obj = obj.parent()
        return obj

    def clickedGroup(self, pos):
        """Return the highest-level group containing the trap at
        the specified position.
        """
        self.trap = self.clickedTrap(pos)
        return self.groupOf(self.trap)

    def selectedTraps(self, region):
        """Return a list of traps whose groups fall
        entirely within the selection region.
        """
        self.selected = []
        rect = self.mapFromScene(QRectF(region)).boundingRect()
        for child in self.traps.children():
            if child.isWithin(rect):
                self.selected.append(child)
                child.state = states.grouping
            else:
                child.state = states.normal
        self.refreshAppearance()

    # Creating and deleting traps
    def addTrap(self, trap):
        trap.setParent(self)
        self.traps.add(trap)
        trap.appearanceChanged.connect(self.toggleAppearance)
        trap.hologramChanged.connect(self.toggleHologram)
        trap.destroyed.connect(self.toggleAppearance)
        trap.destroyed.connect(self.toggleHologram)
        trap.cgh = self.parent().cgh.device
        self.trapAdded.emit(trap)

    def createTrap(self, r, state=None):
        trap = QTrap(r=r, state=state)
        self.addTrap(trap)
        return trap

    def createTraps(self, coordinates, state=None):
        coords = list(coordinates)
        if not coords:
            return
        group = QTrapGroup()
        self.traps.add(group)
        for r in coords:
            trap = self.createTrap(r, state=state)
            group.add(trap)
        return group

    def clearTrap(self, trap):
        """Remove specified trap from trapping pattern"""
        self.traps.remove(trap, delete=True)

    def clearTraps(self, traps=None):
        """Remove all traps from trapping pattern.
        """
        traps = traps or self.traps.flatten()
        for trap in traps:
            self.clearTrap(trap)

    # Creating, breaking and moving groups of traps
    def createGroup(self):
        """Combine selected objects into new group"""
        group = QTrapGroup()
        for trap in self.selected:
            if trap.parent() is not self:
                trap.parent().remove(trap)
            group.add(trap)
        self.traps.add(group)
        self.selected = []
        return group

    def breakGroup(self):
        """Break group into children and
        place children in the top level.
        """
        if isinstance(self.group, QTrapGroup):
            for child in self.group.children():
                child.state = states.grouping
                self.group.remove(child)
                self.traps.add(child)
            self.group = None

    def moveGroup(self, pos):
        """Move the selected group so that the selected
        trap is at the specified position.
        """
        coords = self.mapFromScene(pos)
        dr = QVector3D(coords - self.trap.coords())
        self.group.moveBy(dr)

    # Dispatch low-level events to actions
    def leftPress(self, pos, modifiers):
        """Selection and grouping.
        """
        self.group = self.clickedGroup(pos)
        # update selection rectangle
        if self.group is None:
            self.origin = QPoint(pos)
            rect = QRect(self.origin, QSize())
            self.selection.setGeometry(rect)
            self.selection.show()
        # break selected group
        elif modifiers == Qt.ControlModifier:
            self.breakGroup()
        # select group
        else:
            self.group.state = states.selected
        self.refreshAppearance()

    def rightPress(self, pos, modifiers):
        """Creation and destruction.
        """
        # Shift-Right Click: Add trap
        if modifiers == Qt.ShiftModifier:
            r = self.mapFromScene(pos)
            self.createTrap(r, state=states.selected)
        # Ctrl-Right Click: Delete trap
        elif modifiers == Qt.ControlModifier:
            self.traps.remove(self.clickedGroup(pos), delete=True)

    # Handlers for signals emitted by QJansenScreen
    @pyqtSlot(QMouseEvent)
    def mousePress(self, event):
        """Event handler for mousePress events.
        """
        button = event.button()
        pos = event.pos()
        modifiers = event.modifiers()
        self.prev = None
        if button == Qt.LeftButton:
            self.leftPress(pos, modifiers)
        elif button == Qt.RightButton:
            self.rightPress(pos, modifiers)

    @pyqtSlot(QMouseEvent)
    def mouseMove(self, event):
        """Event handler for mouseMove events.
        """
        pos = event.pos()
        # Move traps
        if self.group is not None:
            self.moveGroup(pos)
        # Update selection box
        elif self.selection.isVisible():
            region = QRect(self.origin, QPoint(pos)).normalized()
            self.selection.setGeometry(region)
            self.selectedTraps(region)

    @pyqtSlot(QMouseEvent)
    def mouseRelease(self, event):
        """Event handler for mouseRelease events.
        """
        if self.selected:
            self.createGroup()
        for child in self.traps.children():
            child.state = states.normal
        self.prev = self.group
        self.group = None
        self.selection.hide()
        self.refreshAppearance()

    @pyqtSlot(QWheelEvent)
    def mouseWheel(self, event):
        """Event handler for mouse wheel events.
        """
        pos = event.pos()
        group = self.clickedGroup(pos)
        if group is not None:
            group.state = states.selected
            dz = event.angleDelta().y() / 120.
            group.moveBy(QVector3D(0, 0, dz))
            # group.state = states.normal
        self.group = None
Beispiel #24
0
 def mousePressEvent(self, eventQMouseEvent):
     self.originQPoint = eventQMouseEvent.pos()
     self.currentQRubberBand = QRubberBand(QRubberBand.Rectangle, self)
     self.currentQRubberBand.setGeometry(
         QtCore.QRect(self.originQPoint, QtCore.QSize()))
     self.currentQRubberBand.show()
Beispiel #25
0
class IMUChartView(QChartView, BaseGraph):
    def __init__(self, parent=None):
        super().__init__(parent=parent)

        self.cursor = QGraphicsLineItem()
        self.scene().addItem(self.cursor)

        self.xvalues = {}

        self.chart = QChart()
        self.setChart(self.chart)
        self.chart.legend().setVisible(True)
        self.chart.legend().setAlignment(Qt.AlignTop)
        self.ncurves = 0
        self.setRenderHint(QPainter.Antialiasing)

        # Selection features
        # self.setRubberBand(QChartView.HorizontalRubberBand)
        self.selectionBand = QRubberBand(QRubberBand.Rectangle, self)
        self.selecting = False
        self.initialClick = QPoint()

        # Track mouse
        self.setMouseTracking(True)

        self.labelValue = QLabel(self)
        self.labelValue.setStyleSheet(
            "background-color: rgba(255,255,255,75%); color: black;")
        self.labelValue.setAlignment(Qt.AlignCenter)
        self.labelValue.setMargin(5)
        self.labelValue.setVisible(False)

        self.build_style()

    def build_style(self):
        self.setStyleSheet("QLabel{color:blue;}")
        self.chart.setTheme(QChart.ChartThemeBlueCerulean)
        self.setBackgroundBrush(QBrush(Qt.darkGray))
        self.chart.setPlotAreaBackgroundBrush(QBrush(Qt.black))
        self.chart.setPlotAreaBackgroundVisible(True)

    def save_as_png(self, file_path):
        pixmap = self.grab()

        child = self.findChild(QOpenGLWidget)

        painter = QPainter(pixmap)
        if child is not None:
            d = child.mapToGlobal(QPoint()) - self.mapToGlobal(QPoint())
            painter.setCompositionMode(QPainter.CompositionMode_SourceAtop)
            painter.drawImage(d, child.grabFramebuffer())

        painter.end()
        pixmap.save(file_path, 'PNG')

    #  def closeEvent(self, event):
    #     self.aboutToClose.emit(self)

    @staticmethod
    def decimate(xdata, ydata):
        # assert(len(xdata) == len(ydata))

        # Decimate only if we have too much data
        decimate_factor = len(xdata) / 100000.0
        # decimate_factor = 1.0

        if decimate_factor > 1.0:
            decimate_factor = int(np.floor(decimate_factor))
            # print('decimate factor', decimate_factor)

            x = np.ndarray(int(len(xdata) / decimate_factor), dtype=np.float64)
            y = np.ndarray(int(len(ydata) / decimate_factor), dtype=np.float64)
            # for i in range(len(x)):
            for i, _ in enumerate(x):
                index = i * decimate_factor
                # assert(index < len(xdata))
                x[i] = xdata[index]
                y[i] = ydata[index]
                if x[i] < x[0]:
                    print('timestamp error', x[i], x[0])
            return x, y
        else:
            return xdata, ydata

    @pyqtSlot(float, float)
    def axis_range_changed(self, min_value, max_value):
        # print('axis_range_changed', min, max)
        for axis in self.chart.axes():
            axis.applyNiceNumbers()

    def update_axes(self):

        # Get and remove all axes
        for axis in self.chart.axes():
            self.chart.removeAxis(axis)

        # Create new axes
        # Create axis X
        axisx = QDateTimeAxis()
        axisx.setTickCount(5)
        axisx.setFormat("dd MMM yyyy hh:mm:ss")
        axisx.setTitleText("Date")
        self.chart.addAxis(axisx, Qt.AlignBottom)

        # Create axis Y
        axisY = QValueAxis()
        axisY.setTickCount(5)
        axisY.setLabelFormat("%.3f")
        axisY.setTitleText("Values")
        self.chart.addAxis(axisY, Qt.AlignLeft)
        # axisY.rangeChanged.connect(self.axis_range_changed)

        ymin = None
        ymax = None

        # Attach axes to series, find min-max
        for series in self.chart.series():
            series.attachAxis(axisx)
            series.attachAxis(axisY)
            vect = series.pointsVector()
            # for i in range(len(vect)):
            for i, _ in enumerate(vect):
                if ymin is None:
                    ymin = vect[i].y()
                    ymax = vect[i].y()
                else:
                    ymin = min(ymin, vect[i].y())
                    ymax = max(ymax, vect[i].y())

        # Update range
        # print('min max', ymin, ymax)
        if ymin is not None:
            axisY.setRange(ymin, ymax)

        # Make the X,Y axis more readable
        # axisx.applyNiceNumbers()
        # axisY.applyNiceNumbers()

    def add_data(self, xdata, ydata, color=None, legend_text=None):
        curve = QLineSeries()
        pen = curve.pen()
        if color is not None:
            pen.setColor(color)
        pen.setWidthF(1.5)
        curve.setPen(pen)
        # curve.setPointsVisible(True)
        # curve.setUseOpenGL(True)
        self.total_samples = max(self.total_samples, len(xdata))

        # Decimate
        xdecimated, ydecimated = self.decimate(xdata, ydata)

        # Data must be in ms since epoch
        # curve.append(self.series_to_polyline(xdecimated * 1000.0, ydecimated))
        # self.reftime = datetime.datetime.fromtimestamp(xdecimated[0])

        # if len(xdecimated) > 0:
        #    xdecimated = xdecimated - xdecimated[0]

        xdecimated *= 1000  # No decimal expected
        points = []
        for i, _ in enumerate(xdecimated):
            # TODO hack
            # curve.append(QPointF(xdecimated[i], ydecimated[i]))
            points.append(QPointF(xdecimated[i], ydecimated[i]))

        curve.replace(points)
        points.clear()

        if legend_text is not None:
            curve.setName(legend_text)

        # Needed for mouse events on series
        self.chart.setAcceptHoverEvents(True)
        self.xvalues[self.ncurves] = np.array(xdecimated)

        # connect signals / slots
        # curve.clicked.connect(self.lineseries_clicked)
        # curve.hovered.connect(self.lineseries_hovered)

        # Add series
        self.chart.addSeries(curve)
        self.ncurves += 1
        self.update_axes()

    def update_data(self, xdata, ydata, series_id):
        if series_id < len(self.chart.series()):
            # Find start time to replace data
            current_series = self.chart.series()[series_id]
            current_points = current_series.pointsVector()

            # Find start and end indexes
            start_index = -1
            try:
                start_index = current_points.index(
                    QPointF(xdata[0] * 1000, ydata[0]))  # Right on the value!
                # print("update_data: start_index found exact match.")
            except ValueError:
                # print("update_data: start_index no exact match - scanning deeper...")
                for i, value in enumerate(current_points):
                    # print(str(current_points[i].x()) + " == " + str(xdata[0]*1000))
                    if current_points[i].x() == xdata[0] * 1000 or (
                            i > 0 and current_points[i - 1].x() <
                            xdata[0] * 1000 < current_points[i].x()):
                        start_index = i
                        # print("update_data: start_index found approximative match.")
                        break

            end_index = -1
            try:
                end_index = current_points.index(
                    QPointF(xdata[len(xdata) - 1] * 1000,
                            ydata[len(ydata) - 1]))  # Right on!
                # print("update_data: start_index found exact match.")
            except ValueError:
                # print("update_data: start_index no exact match - scanning deeper...")
                for i, value in enumerate(current_points):
                    # print(str(current_points[i].x()) + " == " + str(xdata[0]*1000))
                    if current_points[i].x(
                    ) == xdata[len(xdata) - 1] * 1000 or (
                            i > 0 and
                            current_points[i - 1].x() < xdata[len(xdata) - 1] *
                            1000 < current_points[i].x()):
                        end_index = i
                        # print("update_data: start_index found approximative match.")
                        break

            if start_index < 0 or end_index < 0:
                return

            # Decimate, if needed
            xdata, ydata = self.decimate(xdata, ydata)

            # Check if we have the same number of points for that range. If not, remove and replace!
            target_points = current_points[start_index:end_index]
            if len(target_points) != len(xdata):
                points = []
                for i, value in enumerate(xdata):
                    # TODO improve
                    points.append(QPointF(value * 1000, ydata[i]))

                new_points = current_points[0:start_index] + points[0:len(points)-1] + \
                             current_points[end_index:len(current_points)-1]

                current_series.replace(new_points)
                new_points.clear()

                # self.xvalues[series_id] = np.array(xdata)

        return

    @classmethod
    def set_title(cls, title):
        # print('Setting title: ', title)
        # self.chart.setTitle(title)
        return

    @staticmethod
    def series_to_polyline(xdata, ydata):
        """Convert series data to QPolygon(F) polyline

        This code is derived from PythonQwt's function named
        `qwt.plot_curve.series_to_polyline`"""

        # print('series_to_polyline types:', type(xdata[0]), type(ydata[0]))
        size = len(xdata)
        polyline = QPolygonF(size)

        # for i in range(0, len(xdata)):
        #   polyline[i] = QPointF(xdata[i] - xdata[0], ydata[i])
        for i, data in enumerate(xdata):
            polyline[i] = QPointF(data - xdata[0], ydata[i])

        # pointer = polyline.data()
        # dtype, tinfo = np.float, np.finfo  # integers: = np.int, np.iinfo
        # pointer.setsize(2*polyline.size()*tinfo(dtype).dtype.itemsize)
        # memory = np.frombuffer(pointer, dtype)
        # memory[:(size-1)*2+1:2] = xdata
        # memory[1:(size-1)*2+2:2] = ydata
        return polyline

    def add_test_data(self):

        # 100Hz, one day accelerometer values
        npoints = 1000 * 60 * 24

        xdata = np.linspace(0., 10., npoints)
        self.add_data(xdata, np.sin(xdata), color=Qt.red, legend_text='Acc. X')
        # self.add_data(xdata, np.cos(xdata), color=Qt.green, legend_text='Acc. Y')
        # self.add_data(xdata, np.cos(2 * xdata), color=Qt.blue, legend_text='Acc. Z')
        self.set_title(
            "Simple example with %d curves of %d points (OpenGL Accelerated Series)"
            % (self.ncurves, npoints))

    def mouseMoveEvent(self, e: QMouseEvent):
        if self.selecting:
            current_pos = e.pos()
            if self.interaction_mode == GraphInteractionMode.SELECT:
                if current_pos.x() < self.initialClick.x():
                    start_x = current_pos.x()
                    width = self.initialClick.x() - start_x
                else:
                    start_x = self.initialClick.x()
                    width = current_pos.x() - self.initialClick.x()
                self.selectionBand.setGeometry(
                    QRect(start_x,
                          self.chart.plotArea().y(), width,
                          self.chart.plotArea().height()))
            if self.interaction_mode == GraphInteractionMode.MOVE:
                new_pos = current_pos - self.initialClick
                self.chart.scroll(-new_pos.x(), new_pos.y())
                self.initialClick = current_pos

    def mousePressEvent(self, e: QMouseEvent):
        # Handling rubberbands
        # super().mousePressEvent(e)
        self.selecting = True
        self.initialClick = e.pos()
        if self.interaction_mode == GraphInteractionMode.SELECT:
            self.selectionBand.setGeometry(
                QRect(self.initialClick.x(),
                      self.chart.plotArea().y(), 1,
                      self.chart.plotArea().height()))
            self.selectionBand.show()

        if self.interaction_mode == GraphInteractionMode.MOVE:
            QGuiApplication.setOverrideCursor(Qt.ClosedHandCursor)
            self.labelValue.setVisible(False)

    def mouseReleaseEvent(self, e: QMouseEvent):
        # Handling rubberbands
        clicked_x = self.mapToScene(e.pos()).x()

        if self.interaction_mode == GraphInteractionMode.SELECT:
            self.selectionBand.hide()
            if clicked_x == self.mapToScene(self.initialClick).x():
                self.setCursorPosition(clicked_x, True)
            else:
                mapped_x = self.mapToScene(self.initialClick).x()
                if self.initialClick.x() < clicked_x:
                    self.setSelectionArea(mapped_x, clicked_x, True)
                else:
                    self.setSelectionArea(clicked_x, mapped_x, True)

        if self.interaction_mode == GraphInteractionMode.MOVE:
            QGuiApplication.restoreOverrideCursor()

        self.selecting = False

    def clearSelectionArea(self, emit_signal=False):
        self.scene().removeItem(self.selection_rec)
        self.selection_rec = None

        if emit_signal:
            self.clearedSelectionArea.emit()

    def setSelectionArea(self, start_pos, end_pos, emit_signal=False):
        selection_brush = QBrush(QColor(153, 204, 255, 128))
        selection_pen = QPen(Qt.transparent)
        self.scene().removeItem(self.selection_rec)
        self.selection_rec = self.scene().addRect(
            start_pos,
            self.chart.plotArea().y(), end_pos - start_pos,
            self.chart.plotArea().height(), selection_pen, selection_brush)
        if emit_signal:
            self.selectedAreaChanged.emit(
                self.chart.mapToValue(QPointF(start_pos, 0)).x(),
                self.chart.mapToValue(QPointF(end_pos, 0)).x())

    def setSelectionAreaFromTime(self,
                                 start_time,
                                 end_time,
                                 emit_signal=False):
        # Convert times to x values
        if isinstance(start_time, datetime.datetime):
            start_time = start_time.timestamp() * 1000
        if isinstance(end_time, datetime.datetime):
            end_time = end_time.timestamp() * 1000

        start_pos = self.chart.mapToPosition(QPointF(start_time, 0)).x()
        end_pos = self.chart.mapToPosition(QPointF(end_time, 0)).x()

        self.setSelectionArea(start_pos, end_pos)

    def setCursorPosition(self, pos, emit_signal=False):
        # print (pos)
        pen = self.cursor.pen()
        pen.setColor(Qt.cyan)
        pen.setWidthF(1.0)
        self.cursor.setPen(pen)
        # On Top
        self.cursor.setZValue(100.0)

        area = self.chart.plotArea()
        x = pos
        y1 = area.y()
        y2 = area.y() + area.height()

        # self.cursor.set
        self.cursor.setLine(x, y1, x, y2)
        self.cursor.show()

        xmap_initial = self.chart.mapToValue(QPointF(pos, 0)).x()
        display = ''
        # '<i>' + (datetime.datetime.fromtimestamp(xmap + self.reftime.timestamp())).strftime('%d-%m-%Y %H:%M:%S') +
        # '</i><br />'
        ypos = 10
        last_val = None
        for i in range(self.ncurves):
            # Find nearest point
            idx = (np.abs(self.xvalues[i] - xmap_initial)).argmin()
            ymap = self.chart.series()[i].at(idx).y()
            xmap = self.chart.series()[i].at(idx).x()
            if i == 0:
                display += "<i>" + (datetime.datetime.fromtimestamp(xmap_initial/1000)).strftime('%d-%m-%Y %H:%M:%S:%f') + \
                           "</i>"

            # Compute where to display label
            if last_val is None or ymap > last_val:
                last_val = ymap
                ypos = self.chart.mapToPosition(QPointF(xmap, ymap)).y()
            if display != '':
                display += '<br />'

            display += self.chart.series()[i].name(
            ) + ': <b>' + '%.3f' % ymap + '</b>'

        self.labelValue.setText(display)
        self.labelValue.setGeometry(pos, ypos, 100, 100)
        self.labelValue.adjustSize()
        self.labelValue.setVisible(True)

        if emit_signal:
            self.cursorMoved.emit(xmap_initial)

        self.update()

    def setCursorPositionFromTime(self, timestamp, emit_signal=False):
        # Find nearest point
        if isinstance(timestamp, datetime.datetime):
            timestamp = timestamp.timestamp()
        pos = self.get_pos_from_time(timestamp)
        self.setCursorPosition(pos, emit_signal)

    def get_pos_from_time(self, timestamp):
        px = timestamp
        idx1 = (np.abs(self.xvalues[0] - px)).argmin()
        x1 = self.chart.series()[0].at(idx1).x()
        pos1 = self.chart.mapToPosition(QPointF(x1, 0)).x()
        idx2 = idx1 + 1
        if idx2 < len(self.chart.series()[0]):
            x2 = self.chart.series()[0].at(idx2).x()
            if x2 != x1:
                pos2 = self.chart.mapToPosition(QPointF(x2, 0)).x()
                x2 /= 1000
                x1 /= 1000
                pos = (((px - x1) / (x2 - x1)) * (pos2 - pos1)) + pos1
            else:
                pos = pos1
        else:
            pos = pos1
        return pos

    def resizeEvent(self, e: QResizeEvent):
        super().resizeEvent(e)

        # Update cursor height
        area = self.chart.plotArea()
        line = self.cursor.line()
        self.cursor.setLine(line.x1(), area.y(), line.x2(),
                            area.y() + area.height())

    def zoom_in(self):
        self.chart.zoomIn()
        self.update_axes()

    def zoom_out(self):
        self.chart.zoomOut()
        self.update_axes()

    def zoom_area(self):
        if self.selection_rec:
            zoom_rec = self.selection_rec.rect()
            zoom_rec.setY(0)
            zoom_rec.setHeight(self.chart.plotArea().height())
            self.chart.zoomIn(zoom_rec)
            self.clearSelectionArea(True)
            self.update_axes()

    def zoom_reset(self):
        self.chart.zoomReset()
        self.update_axes()

    def get_displayed_start_time(self):
        min_x = self.chart.mapToScene(self.chart.plotArea()).boundingRect().x()
        xmap = self.chart.mapToValue(QPointF(min_x, 0)).x()
        return datetime.datetime.fromtimestamp(xmap / 1000)

    def get_displayed_end_time(self):
        max_x = self.chart.mapToScene(self.chart.plotArea()).boundingRect().x()
        max_x += self.chart.mapToScene(
            self.chart.plotArea()).boundingRect().width()
        xmap = self.chart.mapToValue(QPointF(max_x, 0)).x()
        return datetime.datetime.fromtimestamp(xmap / 1000)

    @property
    def is_zoomed(self):
        return self.chart.isZoomed()
class QToolWindowManager ( QWidget ):
	toolWindowVisibilityChanged = pyqtSignal ( QWidget, bool )
	layoutChanged = pyqtSignal ()
	updateTrackingTooltip = pyqtSignal ( str, QPoint )

	def __init__ ( self, parent, config, factory = None ):
		super ( QToolWindowManager, self ).__init__ ( parent )
		self.factory = factory if factory != None else QToolWindowManagerClassFactory ()
		self.dragHandler = None
		self.config = config
		self.closingWindow = 0

		self.areas = []
		self.wrappers = []
		self.toolWindows = []
		self.toolWindowsTypes = {}
		self.draggedToolWindows = []
		self.layoutChangeNotifyLocks = 0

		if self.factory.parent () == None:
			self.factory.setParent ( self )

		self.mainWrapper = QToolWindowWrapper ( self )
		self.mainWrapper.getWidget ().setObjectName ( 'mainWrapper' )
		self.setLayout ( QVBoxLayout ( self ) )
		self.layout ().setContentsMargins ( 2, 2, 2, 2 )
		self.layout ().setSpacing ( 0 )
		self.layout ().addWidget ( self.mainWrapper.getWidget () )
		self.lastArea = self.createArea ()
		self.draggedWrapper = None
		self.resizedWrapper = None
		self.mainWrapper.setContents ( self.lastArea.getWidget () )

		self.dragHandler = self.createDragHandler ()

		self.preview = QRubberBand ( QRubberBand.Rectangle )
		self.preview.hide ()

		self.raiseTimer = QTimer ( self )
		self.raiseTimer.timeout.connect ( self.raiseCurrentArea )
		self.setSizePolicy ( QSizePolicy.Expanding, QSizePolicy.Expanding )

		qApp.installEventFilter ( self )

	def __del__ ( self ):
		self.suspendLayoutNotifications ()
		while len ( self.areas ) != 0:
			a = self.areas[ 0 ]
			a.setParent ( None )
			self.areas.remove ( a )

		while len ( self.wrappers ) != 0:
			w = self.wrappers[ 0 ]
			w.setParent ( None )
			self.areas.remove ( w )

		del self.dragHandler
		del self.mainWrapper

	def empty ( self ) -> bool:
		return len ( self.areas ) == 0

	def removeArea ( self, area ):
		"""Summary line.

		Args:
			area (QToolWindowArea): Description of param1

	    Returns:
	        QToolWindowArea: Description of return value
	    """
		# print ( "[QToolWindowManager] removeArea %s" % area )
		if area in self.areas:
			self.areas.remove ( area )
		if self.lastArea == area:
			self.lastArea = None

	def removeWrapper ( self, wrapper ):
		"""Summary line.

		Args:
			wrapper (QToolWindowWrapper): Description of param1
	    """
		if self.ownsWrapper ( wrapper ):
			self.wrappers.remove ( wrapper )

	def ownsArea ( self, area ) -> bool:
		"""Summary line.

		Args:
			area (QToolWindowArea): Description of param1

	    Returns:
	        bool: Description of return value
	    """
		return area in self.areas

	def ownsWrapper ( self, wrapper ) -> bool:
		"""Summary line.

		Args:
			wrapper (QToolWindowWrapper): Description of param1

	    Returns:
	        bool: Description of return value
	    """
		return wrapper in self.wrappers

	def ownsToolWindow ( self, toolWindow ) -> bool:
		"""Summary line.

		Args:
			wrapper (QToolWindowWrapper): Description of param1

	    Returns:
	        bool: Description of return value
	    """
		return toolWindow in self.toolWindows

	def startDrag ( self, toolWindows, area ):
		if len ( toolWindows ) == 0:
			return
		# print ( "[QToolWindowManager] startDrag", toolWindows )
		self.dragHandler.startDrag ()
		self.draggedToolWindows = toolWindows

		floatingGeometry = QRect ( QCursor.pos (), area.size () )
		self.moveToolWindows ( toolWindows, area, QToolWindowAreaReference.Drag, -1, floatingGeometry )

	def startDragWrapper ( self, wrapper ):
		self.dragHandler.startDrag ()
		self.draggedWrapper = wrapper
		self.lastArea = None
		self.updateDragPosition ()

	def startResize ( self, wrapper ):
		self.resizedWrapper = wrapper

	def addToolWindowTarget ( self, toolWindow, target, toolType = QTWMToolType.ttStandard ):
		self.insertToToolTypes ( toolWindow, toolType )
		self.addToolWindow ( toolWindow, target.area, target.reference, target.index, target.geometry )

	def addToolWindow ( self, toolWindow, area = None, reference = QToolWindowAreaReference.Combine, index = -1,
	                    geometry = QRect () ):
		self.addToolWindows ( [ toolWindow ], area, reference, index, geometry )

	def addToolWindowsTarget ( self, toolWindows, target, toolType ):
		for toolWindow in toolWindows:
			self.insertToToolTypes ( toolWindow, toolType )
		self.addToolWindows ( toolWindows, target.area, target.reference, target.index, target.geometry )

	def addToolWindows ( self, toolWindows, area = None, reference = QToolWindowAreaReference.Combine, index = -1,
	                     geometry = QRect () ):
		for toolWindow in toolWindows:
			if not self.ownsToolWindow ( toolWindow ):
				toolWindow.hide ()
				toolWindow.setParent ( None )
				toolWindow.installEventFilter ( self )
				self.insertToToolTypes ( toolWindow, QTWMToolType.ttStandard )
				self.toolWindows.append ( toolWindow )

				# from qt.controls.QToolWindowManager.QToolTabManager import QTabPane
				#
				# if isinstance ( toolWindow, QTabPane ):
				# 	print ( "[QToolWindowManager] addToolWindow: QTabPane %s" % toolWindow.pane )
				# else:
				# 	print ( "[QToolWindowManager] addToolWindow: %s" % toolWindow )
		self.moveToolWindows ( toolWindows, area, reference, index, geometry )

	def moveToolWindowTarget ( self, toolWindow, target, toolType = QTWMToolType.ttStandard ):
		self.insertToToolTypes ( toolWindow, toolType )
		self.addToolWindow ( toolWindow, target.area, target.reference, target.index, target.geometry )

	def moveToolWindow ( self, toolWindow, area = None, reference = QToolWindowAreaReference.Combine, index = -1,
	                     geometry = QRect () ):
		self.moveToolWindows ( [ toolWindow ], area, reference, index, geometry )

	def moveToolWindowsTarget ( self, toolWindows, target, toolType = QTWMToolType.ttStandard ):
		for toolWindow in toolWindows:
			self.insertToToolTypes ( toolWindow, toolType )
		self.addToolWindows ( toolWindows, target.area, target.reference, target.index, target.geometry )

	def moveToolWindows ( self, toolWindows, area = None, reference = QToolWindowAreaReference.Combine, index = -1,
	                      geometry = None ):

		# qWarning ( "moveToolWindows %s" % toolWindows )

		# If no area find one
		if area == None:
			if self.lastArea != None:
				area = self.lastArea
			elif len ( self.areas ) != 0:
				area = self.areas[ 0 ]
			else:
				qWarning ( "lastArea is None, and areas is 0, self.createArea ()" )
				area = self.createArea ()
				self.lastArea = area
				self.mainWrapper.setContents ( self.lastArea.getWidget () )

		dragOffset = QPoint ()
		# Get the current mouse position and offset from the area before we remove the tool windows from it
		if area != None and reference == QToolWindowAreaReference.Drag:
			widgetPos = area.mapToGlobal ( area.rect ().topLeft () )
			dragOffset = widgetPos - QCursor.pos ()

		wrapper = None
		currentAreaIsSimple = True

		for toolWindow in toolWindows:
			# when iterating over the tool windows, we will figure out if the current one is actually roll-ups and not tabs
			currentArea = findClosestParent ( toolWindow, [ QToolWindowArea, QToolWindowRollupBarArea ] )
			if currentAreaIsSimple and currentArea != None and currentArea.areaType () == QTWMWrapperAreaType.watTabs:
				currentAreaIsSimple = False
			self.releaseToolWindow ( toolWindow, False )

		if reference == QToolWindowAreaReference.Top or \
				reference == QToolWindowAreaReference.Bottom or \
				reference == QToolWindowAreaReference.Left or \
				reference == QToolWindowAreaReference.Right:
			area = cast ( self.splitArea ( self.getFurthestParentArea ( area.getWidget () ).getWidget (), reference ), [ QToolWindowArea, QToolWindowRollupBarArea ] )
		elif reference == QToolWindowAreaReference.HSplitTop or \
				reference == QToolWindowAreaReference.HSplitBottom or \
				reference == QToolWindowAreaReference.VSplitLeft or \
				reference == QToolWindowAreaReference.VSplitRight:
			area = cast ( self.splitArea ( area.getWidget (), reference ), [ QToolWindowArea, QToolWindowRollupBarArea ] )
		elif reference == QToolWindowAreaReference.Floating or \
				reference == QToolWindowAreaReference.Drag:
			# when dragging we will try to determine target are type, from window types.
			areaType = QTWMWrapperAreaType.watTabs
			if len ( toolWindows ) > 1:
				if currentAreaIsSimple:
					areaType = QTWMWrapperAreaType.watRollups
			elif self.toolWindowsTypes[ toolWindows[ 0 ] ] == QTWMToolType.ttSimple:
				areaType = QTWMWrapperAreaType.watRollups

			# create new window
			area = self.createArea ( areaType )
			wrapper = self.createWrapper ()
			wrapper.setContents ( area.getWidget () )
			# wrapper.move ( QCursor.pos () )
			wrapper.getWidget ().show ()
			# wrapper.getWidget ().grabMouse ()

			# qWarning ( "[QToolWindowManager] moveToolWindows create new window reference: %s area's wrapper: %s" % (
			# self.getAreaReferenceString ( reference ), area.wrapper ()) )\\\

			if geometry != None: # we have geometry, apply the mouse offset
				# If we have a title bar we want to move the mouse to half the height of it
				titleBar = wrapper.getWidget ().findChild ( QCustomTitleBar )
				if titleBar:
					dragOffset.setY ( -titleBar.height () / 2 )
				# apply the mouse offset to the current rect
				geometry.moveTopLeft ( geometry.topLeft () + dragOffset )
				wrapper.getWidget ().setGeometry ( geometry )
				wrapper.getWidget ().move ( QCursor.pos () )
				if titleBar:
					currentTitle = titleBar.caption.text ()
					if len ( toolWindows ) > 0:
						titleBar.caption.setText ( toolWindows[ 0 ].windowTitle () )
					wrapper.getWidget ().move (
						- ( titleBar.caption.mapToGlobal ( titleBar.caption.rect ().topLeft () ) - wrapper.mapToGlobal ( wrapper.rect ().topLeft () ) )
						+ QPoint ( -titleBar.caption.fontMetrics ().boundingRect ( titleBar.caption.text () ).width () / 2, -titleBar.caption.height () / 2 )
						+ wrapper.pos ()
					)
					titleBar.caption.setText ( currentTitle )
			else: # with no present geometry we just create a new one
				wrapper.getWidget ().setGeometry ( QRect ( QPoint ( 0, 0 ), toolWindows[ 0 ].sizeHint () ) )
				wrapper.getWidget ().move ( QCursor.pos () )

			# when create new wrapper, we should transfer mouse-event to wrapper's titleBar for we can continue move.
			if reference == QToolWindowAreaReference.Drag:
				titleBar = wrapper.getWidget ().findChild ( QCustomTitleBar )
				if titleBar:
					# set flag for titleBar releaseMouse
					titleBar.createFromDraging = True
					startDragEvent = QMouseEvent ( QEvent.MouseButtonPress, QCursor.pos (), QtCore.Qt.LeftButton,
					                               QtCore.Qt.LeftButton, QtCore.Qt.NoModifier )
					qApp.sendEvent ( titleBar, startDragEvent )
					titleBar.grabMouse ()

		if reference != QToolWindowAreaReference.Hidden:
			area.addToolWindows ( toolWindows, index )
			self.lastArea = area

		# This will remove the previous area the tool windows where attached to
		self.simplifyLayout ()
		for toolWindow in toolWindows:
			self.toolWindowVisibilityChanged.emit ( toolWindow, toolWindow.parent () != None )
		self.notifyLayoutChange ()

		if reference == QToolWindowAreaReference.Drag and wrapper != None:
			self.draggedWrapper = wrapper
			# start the drag on the new wrapper, will end up calling QToolWindowManager::startDrag(IToolWindowWrapper* wrapper)
			wrapper.startDrag ()

	def getAreaReferenceString ( self, reference ):
		# Top = 0
		# Bottom = 1
		# Left = 2
		# Right = 3
		# HSplitTop = 4
		# HSplitBottom = 5
		# VSplitLeft = 6
		# VSplitRight = 7
		# Combine = 8
		# Floating = 9
		# Drag = 10
		# Hidden = 11
		if reference == QToolWindowAreaReference.Top:
			return "Top"
		elif reference == QToolWindowAreaReference.Bottom:
			return "Bottom"
		elif reference == QToolWindowAreaReference.Left:
			return "Left"
		elif reference == QToolWindowAreaReference.Right:
			return "Right"
		elif reference == QToolWindowAreaReference.HSplitTop:
			return "HSplitTop"
		elif reference == QToolWindowAreaReference.HSplitBottom:
			return "HSplitBottom"
		elif reference == QToolWindowAreaReference.VSplitLeft:
			return "VSplitLeft"
		elif reference == QToolWindowAreaReference.VSplitRight:
			return "VSplitRight"
		elif reference == QToolWindowAreaReference.Combine:
			return "Combine"
		elif reference == QToolWindowAreaReference.Floating:
			return "Floating"
		elif reference == QToolWindowAreaReference.Drag:
			return "Drag"
		elif reference == QToolWindowAreaReference.Hidden:
			return "Hidden"

	def releaseToolWindow ( self, toolWindow, allowClose = False ) -> bool:
		# No parent, so can't possibly be inside an IToolWindowArea
		if toolWindow.parentWidget () == None:
			# qWarning ( "[QToolWindowManager] releaseToolWindow %s, but toolWindow.parentWidget () == None" % toolWindow )
			return False

		if not self.ownsToolWindow ( toolWindow ):
			qWarning ( "Unknown tool window %s" % toolWindow )
			return False

		previousTabWidget = findClosestParent ( toolWindow, [ QToolWindowArea, QToolWindowRollupBarArea ] )
		if previousTabWidget is None:
			qWarning ( "[QToolWindowManager] cannot find area for tool window %s" % toolWindow )
			return False

		if allowClose:
			releasePolicy = self.config.setdefault ( QTWM_RELEASE_POLICY, QTWMReleaseCachingPolicy.rcpWidget )
			if releasePolicy == QTWMReleaseCachingPolicy.rcpKeep:
				self.moveToolWindow ( toolWindow, None, QToolWindowAreaReference.Hidden )
				if self.config.setdefault ( QTWM_ALWAYS_CLOSE_WIDGETS, True ) and not self.tryCloseToolWindow ( toolWindow ):
					return False
			elif releasePolicy == QTWMReleaseCachingPolicy.rcpWidget:
				if not toolWindow.testAttribute ( QtCore.Qt.WA_DeleteOnClose ):
					if self.config.setdefault ( QTWM_ALWAYS_CLOSE_WIDGETS, True ) and not self.tryCloseToolWindow (
							toolWindow ):
						return False
					self.moveToolWindow ( toolWindow, None, QToolWindowAreaReference.Hidden )
			elif releasePolicy == QTWMReleaseCachingPolicy.rcpForget or releasePolicy == QTWMReleaseCachingPolicy.rcpDelete:
				if not self.tryCloseToolWindow ( toolWindow ):
					return False
				self.moveToolWindow ( toolWindow, None, QToolWindowAreaReference.Hidden )
				self.toolWindows.remove ( toolWindow )

				if releasePolicy == QTWMReleaseCachingPolicy.rcpDelete:
					toolWindow.deleteLater ()
				return True

		previousTabWidget.removeToolWindow ( toolWindow )

		if allowClose:
			self.simplifyLayout ()
		else:
			previousTabWidget.adjustDragVisuals ()

		toolWindow.hide ()
		toolWindow.setParent ( None )
		return True

	def releaseToolWindows ( self, toolWindows, allowClose = False ) -> bool:
		# print ( "[QToolWindowManager] releaseToolWindows", toolWindows )
		result = True
		for i in range ( len ( toolWindows ) - 1, -1, -1 ):
		# for toolWindow in toolWindows:
			# if i >= 0 and i < len ( toolWindows ):
			result &= self.releaseToolWindow ( toolWindows[ i ], allowClose )
		# while len ( toolWindows ) != 0:
		# 	result &= self.releaseToolWindow ( toolWindows[ 0 ], allowClose )
		return result

	def areaOf ( self, toolWindow ) -> QToolWindowArea:
		area = findClosestParent ( toolWindow, [ QToolWindowArea, QToolWindowRollupBarArea ] )
		# print ( "[QToolWindowManager] areaOf %s is %s" % ( toolWindow, area ) )
		return area

	def swapAreaType ( self, oldArea, areaType = QTWMWrapperAreaType.watTabs ):
		from QToolWindowManager.QToolWindowWrapper import QToolWindowWrapper
		from QToolWindowManager.QToolWindowCustomWrapper import QToolWindowCustomWrapper
		targetWrapper = findClosestParent ( oldArea.getWidget (), [ QToolWindowWrapper, QToolWindowCustomWrapper ] )
		parentSplitter = cast ( oldArea.parentWidget (), QSplitter )
		newArea = self.createArea ( areaType )

		if parentSplitter is None and targetWrapper is None:
			qWarning ( "[QToolWindowManager] Could not determine area parent" )
			return

		newArea.addToolWindow ( oldArea.toolWindows () )
		if parentSplitter != None:
			targetIndex = parentSplitter.indexOf ( oldArea.getWidget () )
			parentSplitter.insertWidget ( targetIndex, newArea.getWidget () )
		else:
			targetWrapper.setContents ( newArea.getWidget () )

		if self.lastArea == oldArea:
			self.lastArea = newArea

		oldAreaIndex = self.areas.index ( oldArea )
		self.areas.remove ( oldArea )
		self.areas.insert ( oldAreaIndex, newArea )
		oldArea.getWidget ().setParent ( None )
		newArea.adjustDragVisuals ()

	def isWrapper ( self, w ) -> bool:
		if w is None:
			return False
		from QToolWindowManager.QToolWindowWrapper import QToolWindowWrapper
		from QToolWindowManager.QToolWindowCustomWrapper import QToolWindowCustomWrapper
		return cast ( w, [ QToolWindowWrapper, QToolWindowCustomWrapper ] ) or (
				not cast ( w, QSplitter ) and cast ( w.parentWidget (), [ QToolWindowWrapper, QToolWindowCustomWrapper ] ) )

	def isMainWrapper ( self, w ) -> bool:
		from QToolWindowManager.QToolWindowWrapper import QToolWindowWrapper
		from QToolWindowManager.QToolWindowCustomWrapper import QToolWindowCustomWrapper
		return self.isWrapper ( w ) and ( cast ( w, [ QToolWindowWrapper, QToolWindowCustomWrapper ] ) == self.mainWrapper or cast ( w.parentWidget (), [ QToolWindowWrapper, QToolWindowCustomWrapper ] ) == self.mainWrapper )

	def isFloatingWrapper ( self, w ) -> bool:
		if not self.isWrapper ( w ):
			return False
		from QToolWindowManager.QToolWindowWrapper import QToolWindowWrapper
		from QToolWindowManager.QToolWindowCustomWrapper import QToolWindowCustomWrapper
		if cast ( w, [ QToolWindowWrapper, QToolWindowCustomWrapper ] ) and cast ( w, [ QToolWindowWrapper, QToolWindowCustomWrapper ] ) != self.mainWrapper:
			return True
		return not cast ( w, QSplitter ) and cast ( w.parentWidget (),
		                                                        [ QToolWindowWrapper, QToolWindowCustomWrapper ] ) and cast ( w.parentWidget (), [ QToolWindowWrapper, QToolWindowCustomWrapper ] ) != self.mainWrapper

	def saveState ( self ):
		result = { }
		result[ "toolWindowManagerStateFormat" ] = 2
		if self.mainWrapper.getContents () and self.mainWrapper.getContents ().metaObject ():
			result[ "mainWrapper" ] = self.saveWrapperState ( self.mainWrapper )

		floatingWindowsData = [ ]
		for wrapper in self.wrappers:
			if wrapper.getWidget ().isWindow () and wrapper.getContents () and wrapper.getContents ().metaObject ():
				m = self.saveWrapperState ( wrapper )
				if len ( m ) != 0:
					floatingWindowsData.append ( m )

		result[ "floatingWindows" ] = floatingWindowsData
		return result

	def restoreState ( self, data ):
		if data is None:
			return
		stateFormat = data[ "toolWindowManagerStateFormat" ]
		if stateFormat != 1 and stateFormat != 2:
			qWarning ( "state format is not recognized" )
			return

		self.suspendLayoutNotifications ()
		self.mainWrapper.getWidget ().hide ()
		for wrapper in self.wrappers:
			wrapper.getWidget ().hide ()
		self.moveToolWindow ( self.toolWindows, None, QToolWindowAreaReference.Hidden )
		self.simplifyLayout ( True )
		self.mainWrapper.setContents ( None )
		self.restoreWrapperState ( data[ "mainWrapper" ], stateFormat, self.mainWrapper )
		for windowData in data[ "floatingWindows" ]:
			self.restoreWrapperState ( windowData, stateFormat )
		self.simplifyLayout ()
		for toolWindow in self.toolWindows:
			self.toolWindowVisibilityChanged.emit ( toolWindow, toolWindow.parentWidget () != None )
		self.resumeLayoutNotifications ()
		self.notifyLayoutChange ()

	def isAnyWindowActive ( self ) -> bool:
		for tool in self.toolWindows:
			if tool.isAnyWindowActive ():
				return True
		return False

	def updateDragPosition ( self ):
		if self.draggedWrapper == None:
			return

		# print ( "[QToolWindowManager] updateDragPosition" )

		self.draggedWrapper.getWidget ().raise_ ()

		hoveredWindow = windowBelow ( self.draggedWrapper.getWidget () )
		if hoveredWindow != None and hoveredWindow != self.draggedWrapper.window ():
			handlerWidget = hoveredWindow.childAt ( hoveredWindow.mapFromGlobal ( QCursor.pos () ) )
			if handlerWidget != None and not self.dragHandler.isHandlerWidget ( handlerWidget ):
				area = self.getClosestParentArea ( handlerWidget )
				if area != None and self.lastArea != area:
					self.dragHandler.switchedArea ( self.lastArea, area )
					self.lastArea = area
					delayTime = self.config.setdefault ( QTWM_RAISE_DELAY, 500 )
					self.raiseTimer.stop ()
					if delayTime > 0:
						self.raiseTimer.start ( delayTime )

		target = self.dragHandler.getTargetFromPosition ( self.lastArea )
		if self.lastArea != None and target.reference != QToolWindowAreaReference.Floating:
			if QToolWindowAreaReference.isOuter ( target.reference ):
				from QToolWindowManager.QToolWindowCustomWrapper import QToolWindowCustomWrapper
				previewArea = findClosestParent ( self.lastArea.getWidget (), [ QToolWindowWrapper, QToolWindowCustomWrapper ] )
				previewAreaContents = previewArea.getContents ()
				self.preview.setParent ( previewArea.getWidget () )
				self.preview.setGeometry (
					self.dragHandler.getRectFromCursorPos ( previewAreaContents, self.lastArea ).translated (
						previewAreaContents.pos () ) )
			else:
				previewArea = self.lastArea.getWidget ()
				self.preview.setParent ( previewArea )
				self.preview.setGeometry ( self.dragHandler.getRectFromCursorPos ( previewArea, self.lastArea ) )

			self.preview.show ()
		else:
			self.preview.hide ()

		self.updateTrackingTooltip.emit ( self.textForPosition ( target.reference ),
		                                  QCursor.pos () + self.config.setdefault ( QTWM_TOOLTIP_OFFSET, QPoint ( 1, 20 ) ) )

	def finishWrapperDrag ( self ):
		target = self.dragHandler.finishDrag ( self.draggedToolWindows, None, self.lastArea )
		self.lastArea = None

		wrapper = self.draggedWrapper
		self.draggedWrapper = None
		self.raiseTimer.stop ()
		self.preview.setParent ( None )
		self.preview.hide ()

		if wrapper is None:
			qWarning ( "[QToolWindowManager] finishWrapperDrag wrapper == None." )
			return

		# print ( "[QToolWindowManager] finishWrapperDrag %s %s" % ( self.draggedWrapper, self.draggedToolWindows ) )

		contents = wrapper.getContents ()
		toolWindows = []
		contentsWidgets = contents.findChildren ( QWidget )
		contentsWidgets.append ( contents )

		for w in contentsWidgets:
			area = cast ( w, [ QToolWindowArea, QToolWindowRollupBarArea ] )
			if area != None and self.ownsArea ( area ):
				toolWindows += area.toolWindows ()

		if target.reference != QToolWindowAreaReference.Floating:
			contents = wrapper.getContents ()
			wrapper.setContents ( None )

			if target.reference == QToolWindowAreaReference.Top or \
					target.reference == QToolWindowAreaReference.Bottom or \
					target.reference == QToolWindowAreaReference.Left or \
					target.reference == QToolWindowAreaReference.Right:
				self.splitArea ( self.getFurthestParentArea ( target.area.getWidget () ).getWidget (), target.reference,
				                 contents )
			elif target.reference == QToolWindowAreaReference.HSplitTop or \
					target.reference == QToolWindowAreaReference.HSplitBottom or \
					target.reference == QToolWindowAreaReference.VSplitLeft or \
					target.reference == QToolWindowAreaReference.VSplitRight:
				self.splitArea ( target.area.getWidget (), target.reference, contents )
			elif target.reference == QToolWindowAreaReference.Combine:
				self.moveToolWindowsTarget ( toolWindows, target )

			wrapper.getWidget ().close ()
			self.simplifyLayout ()

		if target.reference != QToolWindowAreaReference.Combine:
			for w in toolWindows:
				self.toolWindowVisibilityChanged.emit ( w, True )

		if target.reference != QToolWindowAreaReference.Floating:
			self.notifyLayoutChange ()

		self.updateTrackingTooltip.emit ( "", QPoint () )

	def finishWrapperResize ( self ):
		toolWindows = []
		contents = self.resizedWrapper.getContents ()
		contentsWidgets = contents.findChildren ( QWidget )
		contentsWidgets.append ( contents )

		for w in contentsWidgets:
			area = cast ( w, [ QToolWindowArea, QToolWindowRollupBarArea ] )
			if area and self.ownsArea ( area ):
				toolWindows.append ( area.toolWindows () )

		for w in toolWindows:
			self.toolWindowVisibilityChanged.emit ( w, True )

		self.resizedWrapper = None

	def saveWrapperState ( self, wrapper ):
		if wrapper.getContents () == None:
			qWarning ( "[QToolWindowManager] saveWrapperState Empty top level wrapper." )
			return { }

		result = { }
		result[ "geometry" ] = wrapper.getWidget ().saveGeometry ().toBase64 ()
		result[ "name" ] = wrapper.getWidget ().objectName ()

		obj = wrapper.getContents ()
		if cast ( obj, QSplitter ):
			result[ "splitter" ] = self.saveSplitterState ( obj )
			return result

		if isinstance ( obj, QToolWindowArea ):
			result[ "area" ] = obj.saveState ()
			return result

		qWarning ( "[QToolWindowManager] saveWrapperState Couldn't find valid child widget" )
		return { }

	def restoreWrapperState ( self, data, stateFormat, wrapper = None ):
		newContents = None

		if wrapper and data[ "name" ]:
			wrapper.getWidget ().setObjectName ( data[ "name" ] )

		if data[ "splitter" ]:
			newContents = self.restoreSplitterState ( data[ "splitter" ], stateFormat )
		elif data[ "area" ]:
			areaType = QTWMWrapperAreaType.watTabs
			if data[ "area" ][ "type" ] and data[ "area" ][ "type" ] == "rollup":
				areaType = QTWMWrapperAreaType.watRollups

			area = self.createArea ( areaType )
			area.restoreState ( data[ "area" ], stateFormat )
			if area.count () > 0:
				newContents = area.getWidget ()
			else:
				area.deleteLater ()

		if not wrapper:
			if newContents:
				wrapper = self.createWrapper ()
				if data[ "name" ]:
					wrapper.getWidget ().setObjectName ( data[ "name" ] )
			else:
				return None

		wrapper.setContents ( newContents )

		if stateFormat == 1:
			if data[ "geometry" ]:
				if not wrapper.getWidget ().restoreGeometry ( data[ "geometry" ] ):
					print ( "Failed to restore wrapper geometry" )
		elif stateFormat == 2:
			if data[ "geometry" ]:
				if not wrapper.getWidget ().restoreGeometry ( QByteArray.fromBase64 ( data[ "geometry" ] ) ):
					print ( "Failed to restore wrapper geometry" )
		else:
			print ( "Unknown state format" )

		if data[ "geometry" ]:
			wrapper.getWidget ().show ()

		return wrapper

	def saveSplitterState ( self, splitter ):
		result = { }
		result[ "state" ] = splitter.saveState ().toBase64 ()
		result[ "type" ] = "splitter"
		items = [ ]
		for i in range ( splitter.count () ):
			item = splitter.widget ( i )
			itemValue = { }
			area = item
			if area != None:
				itemValue = area.saveState ()
			else:
				childSplitter = item
				if childSplitter:
					itemValue = self.saveSplitterState ( childSplitter )
				else:
					qWarning ( "[QToolWindowManager] saveSplitterState Unknown splitter item" )
			items.append ( itemValue )
		result[ "items" ] = items
		return result

	def restoreSplitterState ( self, data, stateFormat ):
		if len ( data[ "items" ] ) < 2:
			print ( "Invalid splitter encountered" )
			if len ( data[ "items" ] ) == 0:
				return None

		splitter = self.createSplitter ()

		for itemData in data[ "items" ]:
			itemValue = itemData
			itemType = itemValue[ "type" ]
			if itemType == "splitter":
				w = self.restoreSplitterState ( itemValue, stateFormat )
				if w:
					splitter.addWidget ( w )
			elif itemType == "area":
				area = self.createArea ()
				area.restoreState ( itemValue, stateFormat )
				splitter.addWidget ( area.getWidget () )
			elif itemType == "rollup":
				area = self.createArea ()
				area.restoreState ( itemValue, stateFormat )
				splitter.addWidget ( area.getWidget () )
			else:
				print ( "Unknown item type" )

		if stateFormat == 1:
			if data[ "state" ]:
				if not splitter.restoreState ( data[ "state" ] ):
					print ( "Failed to restore splitter state" )
		elif stateFormat == 2:
			if data[ "state" ]:
				if not splitter.restoreState ( QByteArray.fromBase64 ( data[ "state" ] ) ):
					print ( "Failed to restore splitter state" )

		else:
			print ( "Unknown state format" )

		return splitter

	def resizeSplitter ( self, widget, sizes ):
		s = cast ( widget, QSplitter )
		if s == None:
			s = findClosestParent ( widget, QSplitter )
		if s == None:
			qWarning ( "Could not find a matching splitter!" )
			return

		scaleFactor = s.width () if s.orientation () == QtCore.Qt.Horizontal else s.height ()

		for i in range ( 0, len ( sizes ) ):
			sizes[ i ] *= scaleFactor

		s.setSizes ( sizes )

	def createArea ( self, areaType = QTWMWrapperAreaType.watTabs ):
		# qWarning ( "[QToolWindowManager] createArea %s" % areaType )
		a = self.factory.createArea ( self, None, areaType )
		self.lastArea = a
		self.areas.append ( a )
		return a

	def createWrapper ( self ):
		w = self.factory.createWrapper ( self )
		name = None
		while True:
			i = QtCore.qrand ()
			name = "wrapper#%s" % i
			for w2 in self.wrappers:
				if name == w2.getWidget ().objectName ():
					continue
			break
		w.getWidget ().setObjectName ( name )
		self.wrappers.append ( w )
		return w

	def getNotifyLock ( self, allowNotify = True ):
		return QTWMNotifyLock ( self, allowNotify )

	def hide ( self ):
		self.mainWrapper.getWidget ().hide ()

	def show ( self ):
		self.mainWrapper.getWidget ().show ()

	def clear ( self ):
		self.releaseToolWindows ( self.toolWindows, True )
		if len ( self.areas ) != 0:
			self.lastArea = self.areas[ 0 ]
		else:
			self.lastArea = None

	def bringAllToFront ( self ):
		# TODO: Win64 / OSX
		from QToolWindowManager.QToolWindowCustomWrapper import QToolWindowCustomWrapper
		list = qApp.topLevelWidgets ()
		for w in list:
			if w != None and not w.windowState ().testFlag ( QtCore.Qt.WindowMinimized ) and ( isinstance ( w, QToolWindowWrapper ) or isinstance ( w, QToolWindowCustomWrapper ) or isinstance ( w, QCustomWindowFrame ) ):
				w.show ()
				w.raise_ ()

	def bringToFront ( self, toolWindow ):
		area = self.areaOf ( toolWindow )
		if not area:
			return
		while area.indexOf ( toolWindow ) == -1:
			toolWindow = toolWindow.parentWidget ()
		area.setCurrentWidget ( toolWindow )

		window = area.getWidget ().window ()
		window.setWindowState ( window.windowState () & ~QtCore.Qt.WindowMinimized )
		window.show ()
		window.raise_ ()
		window.activateWindow ()

		toolWindow.setFocus ()

	def getToolPath ( self, toolWindow ):
		w = toolWindow
		result = ''
		pw = w.parentWidget ()
		while pw:
			if isinstance ( pw, QSplitter ):
				orientation = None
				if pw.orientation () == QtCore.Qt.Horizontal:
					orientation = 'h'
				else:
					orientation = 'v'
				result += "/%c/%d" % (orientation, pw.indexOf ( w ))
			elif isinstance ( pw, QToolWindowWrapper ):
				result += toolWindow.window ().objectName ()
				break
			w = pw
			pw = w.parentWidget ()
		return result

	def targetFromPath ( self, toolPath ) -> QToolWindowAreaTarget:
		for w in self.areas:
			if w.count () < 0 and self.getToolPath ( w.widget ( 0 ) ) == toolPath:
				return QToolWindowAreaTarget.createByArea ( w, QToolWindowAreaReference.Combine )
		return QToolWindowAreaTarget ( QToolWindowAreaReference.Floating )

	def eventFilter ( self, o, e ):
		"""Summary line.

		Args:
			o (QObject): Description of param1
			e (QEvent): Description of param2
	    """
		if o == qApp:
			if e.type () == QEvent.ApplicationActivate and (
					self.config.setdefault ( QTWM_WRAPPERS_ARE_CHILDREN, False )) and (
					self.config.setdefault ( QTWM_BRING_ALL_TO_FRONT, True )):
				self.bringAllToFront ()
			return False

		if e.type () == 16: # event Destroy
			w = cast ( o, QWidget )
			if not self.closingWindow and self.ownsToolWindow ( w ) and w.isVisible ():
				self.releaseToolWindow ( w, True )
				return False

		# if self.draggedWrapper and o == self.draggedWrapper:
		# 	if e.type () == QEvent.MouseMove:
		# 		qWarning ( "Manager eventFilter: send MouseMove" )
		# 		qApp.sendEvent ( self.draggedWrapper, e )

		# print ( "QToolWindowManager::eventFilter", type ( o ), EventTypes ().as_string ( e.type () ) )

		# if self.draggedWrapper and o == self.draggedWrapper:
		# 	if e.type () == QEvent.MouseButtonRelease:
		# 		qWarning ( f"Manager eventFilter: send MouseButtonRelease {self.draggedWrapper}" )

		# if e.type () == Qt.QEvent.Destroy:
		# 	if not self.closingWindow and self.ownsToolWindow ( w ) and w.isVisible ():
		# 		self.releaseToolWindow ( w, True )
		# 		return False

		return super ().eventFilter ( o, e )

	def event ( self, e ):
		if e.type () == QEvent.StyleChange:
			if self.parentWidget () and self.parentWidget ().styleSheet () != self.styleSheet ():
				self.setStyleSheet ( self.parentWidget ().styleSheet () )

		return super ().event ( e )

	def tryCloseToolWindow ( self, toolWindow ):
		self.closingWindow += 1
		result = True

		if not toolWindow.close ():
			qWarning ( "Widget could not be closed" )
			result = False

		self.closingWindow -= 1
		return result

	def createSplitter ( self ) -> QSplitter:
		return self.factory.createSplitter ( self )

	def splitArea ( self, area, reference, insertWidget = None ):
		from QToolWindowManager.QToolWindowWrapper import QToolWindowWrapper
		from QToolWindowManager.QToolWindowCustomWrapper import QToolWindowCustomWrapper

		residingWidget = insertWidget
		if residingWidget == None:
			residingWidget = self.createArea ().getWidget ()

		if not QToolWindowAreaReference.requiresSplit ( reference ):
			qWarning ( "Invalid reference for area split" )
			return None

		forceOuter = QToolWindowAreaReference.isOuter ( reference )
		reference = reference & 0x3
		parentSplitter = None
		targetWrapper = findClosestParent ( area, [ QToolWindowWrapper, QToolWindowCustomWrapper ] )
		if not forceOuter:
			parentSplitter = cast ( area.parentWidget (), QSplitter )
		if parentSplitter == None and targetWrapper == None:
			qWarning ( "Could not determine area parent" )
			return None
		useParentSplitter = False
		targetIndex = 0
		parentSizes = [ QSize () ]
		if parentSplitter != None:
			parentSizes = parentSplitter.sizes ()
			targetIndex += parentSplitter.indexOf ( area )
			useParentSplitter = parentSplitter.orientation () == QToolWindowAreaReference.splitOrientation ( reference )

		if useParentSplitter:
			origIndex = targetIndex
			targetIndex += reference & 0x1
			newSizes = self.dragHandler.getSplitSizes ( parentSizes[ origIndex ] )
			parentSizes[ origIndex ] = newSizes.oldSize
			parentSizes.insert ( targetIndex, newSizes.newSize )
			parentSplitter.insertWidget ( targetIndex, residingWidget )
			parentSplitter.setSizes ( parentSizes )
			return residingWidget

		splitter = self.createSplitter ()
		splitter.setOrientation ( QToolWindowAreaReference.splitOrientation ( reference ) )

		if forceOuter or area == targetWrapper.getContents ():
			firstChild = targetWrapper.getContents ()
			targetWrapper.setContents ( None )
			splitter.addWidget ( firstChild )
		else:
			area.hide ()
			area.setParent ( None )
			splitter.addWidget ( area )
			area.show ()

		splitter.insertWidget ( reference & 0x1, residingWidget )
		if parentSplitter != None:
			parentSplitter.insertWidget ( targetIndex, splitter )
			parentSplitter.setSizes ( parentSizes )
		else:
			targetWrapper.setContents ( splitter )

		sizes = [ ]
		baseSize = splitter.height () if splitter.orientation () == QtCore.Qt.Vertical else splitter.width ()
		newSizes = self.dragHandler.getSplitSizes ( baseSize )
		sizes.append ( newSizes.oldSize )
		sizes.insert ( reference & 0x1, newSizes.newSize )
		splitter.setSizes ( sizes )

		contentsWidgets = residingWidget.findChildren ( QWidget )
		for w in contentsWidgets:
			qApp.sendEvent ( w, QEvent ( QEvent.ParentChange ) )

		return residingWidget

	def getClosestParentArea ( self, widget ):
		area = findClosestParent ( widget, [ QToolWindowArea, QToolWindowRollupBarArea ] )
		while area != None and not self.ownsArea ( area ):
			area = findClosestParent ( area.getWidget ().parentWidget (), [ QToolWindowArea, QToolWindowRollupBarArea ] )

		# qWarning ( "[QToolWindowManager] getClosestParentArea %s is %s" % ( widget, area ) )

		return area

	def getFurthestParentArea ( self, widget ):
		area = findClosestParent ( widget, [ QToolWindowArea, QToolWindowRollupBarArea ] )
		previousArea = area
		while area != None and not self.ownsArea ( area ):
			area = findClosestParent ( area.getWidget ().parentWidget (), [ QToolWindowArea, QToolWindowRollupBarArea ] )

			if area == None:
				return previousArea
			else:
				previousArea = area

		# qWarning ( "getFurthestParentArea %s is %s" % ( widget, area ) )

		return area

	def textForPosition ( self, reference ):
		texts = [
			"Place at top of window",
			"Place at bottom of window",
			"Place on left side of window",
			"Place on right side of window",
			"Split horizontally, place above",
			"Split horizontally, place below",
			"Split vertically, place left",
			"Split vertically, place right",
			"Add to tab list",
			""
		]
		return texts[ reference ]

	def simplifyLayout ( self, clearMain = False ):
		from QToolWindowManager.QToolWindowWrapper import QToolWindowWrapper
		from QToolWindowManager.QToolWindowCustomWrapper import QToolWindowCustomWrapper

		self.suspendLayoutNotifications ()
		madeChanges = True # Some layout changes may require multiple iterations to fully simplify.

		while madeChanges:
			madeChanges = False
			areasToRemove = [ ]
			for area in self.areas:
				# remove empty areas (if this is only area in main wrapper, only remove it when we explicitly ask for that)
				if area.count () == 0 and ( clearMain or cast ( area.parent (), [ QToolWindowWrapper, QToolWindowCustomWrapper ] ) != self.mainWrapper ):
					areasToRemove.append ( area )
					madeChanges = True

				s = cast ( area.parentWidget (), QSplitter )
				while s != None and s.parentWidget () != None:
					sp_s = cast ( s.parentWidget (), QSplitter )
					sp_w = cast ( s.parentWidget (), [ QToolWindowWrapper, QToolWindowCustomWrapper ] )
					sw = findClosestParent ( s, [ QToolWindowWrapper, QToolWindowCustomWrapper ] )

					# If splitter only contains one object, replace the splitter with the contained object
					if s.count () == 1:
						if sp_s != None:
							index = sp_s.indexOf ( s )
							sizes = sp_s.sizes ()
							sp_s.insertWidget ( index, s.widget ( 0 ) )
							s.hide ()
							s.setParent ( None )
							s.deleteLater ()
							sp_s.setSizes ( sizes )
							madeChanges = True
						elif sp_w != None:
							sp_w.setContents ( s.widget ( 0 ) )
							s.setParent ( None )
							s.deleteLater ()
							madeChanges = True
						else:
							qWarning ( "Unexpected splitter parent" )

					# If splitter's parent is also a splitter, and both have same orientation, replace splitter with contents
					elif sp_s != None and s.orientation () == sp_s.orientation ():
						index = sp_s.indexOf ( s )
						newSizes = sp_s.sizes ()
						oldSizes = s.sizes ()
						newSum = newSizes[ index ]
						oldSum = 0
						for i in oldSizes:
							oldSum += i
						for i in range ( len ( oldSizes ) - 1, -1, -1 ):
							sp_s.insertWidget ( index, s.widget ( i ) )
							newSizes.insert ( index, oldSizes[ i ] / oldSum * newSum )
						s.hide ()
						s.setParent ( None )
						s.deleteLater ()
						sp_s.setSizes ( newSizes )
						madeChanges = True

					s = sp_s

			for area in areasToRemove:
				area.hide ()
				aw = cast ( area.parentWidget (), [ QToolWindowWrapper, QToolWindowCustomWrapper ] )
				if aw != None:
					aw.setContents ( None )

				area.setParent ( None )
				self.areas.remove ( area )
				area.deleteLater ()

		wrappersToRemove = [ ]
		for wrapper in self.wrappers:
			if wrapper.getWidget ().isWindow () and wrapper.getContents () == None:
				wrappersToRemove.append ( wrapper )

		for wrapper in wrappersToRemove:
			self.wrappers.remove ( wrapper )
			wrapper.hide ()
			wrapper.deferDeletion ()

		for area in self.areas:
			area.adjustDragVisuals ()

		self.resumeLayoutNotifications ()
		self.notifyLayoutChange ()

	def createDragHandler ( self ):
		if self.dragHandler:
			del self.dragHandler
		return self.factory.createDragHandler ( self )

	def suspendLayoutNotifications ( self ):
		self.layoutChangeNotifyLocks += 1

	def resumeLayoutNotifications ( self ):
		if self.layoutChangeNotifyLocks > 0:
			self.layoutChangeNotifyLocks -= 1

	def notifyLayoutChange ( self ):
		if self.layoutChangeNotifyLocks == 0:
			QtCore.QMetaObject.invokeMethod ( self, 'layoutChanged', QtCore.Qt.QueuedConnection )

	def insertToToolTypes ( self, tool, toolType ):
		if tool not in self.toolWindowsTypes:
			self.toolWindowsTypes[ tool ] = toolType

	def raiseCurrentArea ( self ):
		if self.lastArea:
			w = self.lastArea.getWidget ()
			while w.parentWidget () and not w.isWindow ():
				w = w.parentWidget ()
			w.raise_ ()
			self.updateDragPosition ()
		self.raiseTimer.stop ()
Beispiel #27
0
class QExampleLabel(QLabel):
    def __init__(self, parentQWidget=None):
        super(QExampleLabel, self).__init__(parentQWidget)
        self.initUI()

    def initUI(self):
        self.setPixmap(QtGui.QPixmap('input.png'))

    def mousePressEvent(self, eventQMouseEvent):
        self.originQPoint = eventQMouseEvent.pos()
        self.currentQRubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.currentQRubberBand.setGeometry(
            QtCore.QRect(self.originQPoint, QtCore.QSize()))
        self.currentQRubberBand.show()

    def mouseMoveEvent(self, eventQMouseEvent):
        self.currentQRubberBand.setGeometry(
            QtCore.QRect(self.originQPoint,
                         eventQMouseEvent.pos()).normalized())

    def mouseReleaseEvent(self, eventQMouseEvent):
        self.currentQRubberBand.hide()
        currentQRect = self.currentQRubberBand.geometry()
        self.currentQRubberBand.deleteLater()
        cropQPixmap = self.pixmap().copy(currentQRect)
        cropQPixmap.save('output.png')
Beispiel #28
0
class PictureBox(QLabel):
    changedNumberRegions = pyqtSignal(int)

    def __init__(self, image, regions, parent=None):

        QLabel.__init__(self, parent)
        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.origin = QPoint()
        self.regions = None
        self.image = image

        def region_to_rect(region):
            y1, x1, y2, x2 = region.bbox
            return QRect(x1, y1, x2 - x1, y2 - y1)

        self.regions = list(map(region_to_rect, regions))
        self._update_picture()

    def mousePressEvent(self, event):
        pal = QPalette()
        if event.button() == Qt.LeftButton:
            pal.setBrush(QPalette.Highlight, QBrush(Qt.blue))
        elif event.button() == Qt.RightButton:
            pal.setBrush(QPalette.Highlight, QBrush(Qt.green))
        self.rubberBand.setPalette(pal)
        self.origin = QPoint(event.pos())
        self.rubberBand.setGeometry(QRect(self.origin, QSize()))
        self.rubberBand.show()

    def mouseMoveEvent(self, event):
        if not self.origin.isNull():
            self.rubberBand.setGeometry(
                QRect(self.origin, event.pos()).normalized())

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            drawnRect = QRect(self.origin, event.pos()).normalized()
            for region in self.getIntersectedRegions(drawnRect):
                self.regions.remove(region)
        elif event.button() == Qt.RightButton:
            drawnRect = QRect(self.origin, event.pos()).normalized()
            meanArea = np.mean([r.width() * r.height() for r in self.regions])
            meanHeight = np.mean([r.height() for r in self.regions])
            meanWidth = np.mean([r.width() for r in self.regions])
            if drawnRect.width() * drawnRect.height() * 2 < meanArea:
                rect = QRect(self.origin.x() - meanWidth / 2,
                             self.origin.y() - meanHeight / 2, meanWidth,
                             meanHeight)
                self.regions.append(rect)
            else:
                self.regions.append(drawnRect)
        self.rubberBand.hide()
        self._update_picture()

    def getIntersectedRegions(self, drawnRect):
        result = []
        for region in self.regions:
            if region.intersects(drawnRect):
                result.append(region)
        return result

    def _update_regions(self):
        pixmap = self._get_pixmap()
        paint = QPainter(pixmap)
        paint.setPen(QColor("green"))
        for region in self.regions:
            paint.drawRect(region)
            # rect = mpatches.Rectangle((minc, minr), maxc - minc, maxr - minr,
            #                          fill=False, edgecolor='green', linewidth=2)
        del paint
        return pixmap

    def savePicture(self, fname):
        pixmap = self._update_regions()
        return pixmap.save(fname)

    def _update_picture(self):
        pixmap = self._update_regions()
        self.setAlignment(Qt.AlignLeft | Qt.AlignTop)
        self.setPixmap(pixmap)
        self.changedNumberRegions.emit(len(self.regions))

    def _get_pixmap(self):
        # Convert image to QImage
        qimg = qimage2ndarray.array2qimage(self.image, True)
        return QPixmap(qimg)
Beispiel #29
0
 def __init__(self, parent=None, main=None):
     QLabel.__init__(self, parent)
     self.selection = QRubberBand(QRubberBand.Rectangle, self)
     self.main = main
Beispiel #30
0
class VideoArea(QLabel):
    def __init__(self, parent=None, main=None):
        QLabel.__init__(self, parent)
        self.selection = QRubberBand(QRubberBand.Rectangle, self)
        self.main = main

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:

            position = QPoint(event.pos())
            if self.selection.isVisible():
                if (self.upper_left - position).manhattanLength() < 20:
                    self.mode = "UL"
                elif (self.lower_right - position).manhattanLength() < 20:
                    self.mode = "LR"
                else:
                    self.selection.hide()
            else:
                self.upper_left = position
                self.lower_right = position
                self.mode = "LR"
                self.selection.show()

    def mouseMoveEvent(self, event):
        if self.selection.isVisible():
            if self.mode == "LR":
                self.lower_right = QPoint(event.pos())
            elif self.mode == "UL":
                self.upper_left = QPoint(event.pos())
            self.selection.setGeometry(
                QRect(self.upper_left, self.lower_right).normalized())

    def mouseReleaseEvent(self, event):
        self.main.controller.set_coordinates(
            *self.selection.geometry().getCoords())
        self.selection.hide()
Beispiel #31
0
class ImageCropperDropper(QLabel):
	'''A QLabel that displays a rectangle when drawing a rectangle with the mouse'''

	cropped = Signal(QPixmap)
	fileDropped = Signal(QUrl)

	def __init__(self, mainwin):
		QLabel.__init__(self)

		self.setAcceptDrops(True)

		self.marker = QRubberBand(QRubberBand.Rectangle, self)
		self.markOrigin = self.markEnd = None

		self.setContextMenuPolicy(Qt.ActionsContextMenu)
		self.addAction(mainwin.cropAction)
		self.addAction(mainwin.saveAction)

	def setPixmap(self, pix):
		QLabel.setPixmap(self, pix)
		self.resize(pix.size())

		self.marker.hide()
		self.markOrigin = self.markEnd = None

	@Slot()
	def doCrop(self):
		'''Crop the pixmap using the user-drawn rectangle, emits cropped(QPixmap) signal'''
		if not self.markEnd:
			QMessageBox.warning(self, 'Error', 'Select a region to crop first')
			return
		cropzone = self._makeRect(self.markOrigin, self.markEnd)
		croppedpix = self.pixmap().copy(cropzone)

		self.setPixmap(croppedpix)
		self.cropped.emit(croppedpix)

	def _makeRect(self, p1, p2):
		'''Make a QRect based on QPoints p1 and p2.
		The 2 points must be 2 corners but don't need to be upper-left&lower-right'''
		x1, x2 = min(p1.x(), p2.x()), max(p1.x(), p2.x())
		y1, y2 = min(p1.y(), p2.y()), max(p1.y(), p2.y())
		return QRect().adjusted(x1, y1, x2, y2)

	def mouseMoveEvent(self, ev):
		if ev.buttons() != Qt.LeftButton:
			return QLabel.mouseMoveEvent(self, ev)
		self.markEnd = ev.pos()
		diffpoint = self.markEnd - self.markOrigin
		#~ self.marker.resize(diffpoint.x(), diffpoint.y())
		self.marker.setGeometry(self._makeRect(self.markOrigin, self.markEnd))
		#~ ev.accept()

	def mousePressEvent(self, ev):
		if ev.button() != Qt.LeftButton:
			return QLabel.mousePressEvent(self, ev)
		self.markOrigin = ev.pos()
		self.marker.move(ev.pos())
		self.marker.resize(QSize())
		self.marker.show()
		#~ ev.accept()

	def dragEnterEvent(self, ev):
		if ev.mimeData().hasUrls():
			ev.setDropAction(Qt.CopyAction)
			ev.accept()

	def dropEvent(self, ev):
		if ev.mimeData().hasUrls():
			ev.setDropAction(Qt.CopyAction)
			ev.accept()
			self.fileDropped.emit(ev.mimeData().urls()[0])
Beispiel #32
0
class ViewerWidget(QAbstractScrollArea):
    """
    The main ViewerWidget class. Should be embeddable in
    other applications. See the open() function for loading
    images.
    """
    # signals
    geolinkMove = pyqtSignal(GeolinkInfo, name='geolinkMove')
    geolinkQueryPoint = pyqtSignal(GeolinkInfo, name='geolinkQueryPoint')
    # can't use ViewerWidget - use base class instead
    layerAdded = pyqtSignal(QAbstractScrollArea, name='layerAdded')
    showStatusMessage = pyqtSignal('QString', name='showStatusMessage')
    activeToolChanged = pyqtSignal(ActiveToolChangedInfo,
                                   name='activeToolChanged')
    polygonCollected = pyqtSignal(PolygonToolInfo, name='polygonCollected')
    polylineCollected = pyqtSignal(PolylineToolInfo, name='polylineCollected')
    vectorLocationSelected = pyqtSignal(list,
                                        viewerlayers.ViewerVectorLayer,
                                        name='vectorLocationSelected')
    locationSelected = pyqtSignal(QueryInfo, name='locationSelected')

    def __init__(self, parent):
        QAbstractScrollArea.__init__(self, parent)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)

        # tracking works awfully badly under X
        # turn off until we work out a workaround
        self.verticalScrollBar().setTracking(False)
        self.horizontalScrollBar().setTracking(False)

        self.layers = viewerlayers.LayerManager()

        self.paintPoint = QPoint()  # normally 0,0 unless we are panning

        # when moving the scroll bars
        # events get fired that we wish to ignore
        self.suppressscrollevent = False

        # set the background color to black so window
        # is black when nothing loaded and when panning
        # new areas are initially black.
        self.setBackgroundColor(Qt.black)

        # to do with tools
        self.rubberBand = None
        self.panCursor = None
        self.panGrabCursor = None
        self.zoomInCursor = None
        self.zoomOutCursor = None
        self.queryCursor = None
        self.vectorQueryCursor = None
        self.polygonCursor = None
        self.activeTool = VIEWER_TOOL_NONE
        self.panOrigin = None
        self.toolPoints = None  # for line and polygon tools - list of points
        self.toolPointsFinished = True  # True if we finished collecting
        # with line and poly tools
        self.toolPen = QPen()  # for drawing the toolPoints
        self.toolPen.setWidth(1)
        self.toolPen.setColor(Qt.yellow)
        self.toolPen.setDashPattern([5, 5, 5, 5])

        # Define the scroll wheel behaviour
        self.mouseWheelZoom = True
        # do we follow extent when geolinking?
        self.geolinkFollowExtent = True
        # to we query all layers or only displayed?
        self.queryOnlyDisplayed = False

    def updateScrollBars(self):
        """
        Update the scroll bars to accurately show where
        we are relative to the full extent
        """
        fullextent = self.layers.getFullExtent()
        setbars = False
        self.suppressscrollevent = True
        if fullextent is not None:
            (fullleft, fulltop, fullright, fullbottom) = fullextent
            layer = self.layers.getTopLayer()
            if layer is not None:
                (left, top, right, bottom) = layer.coordmgr.getWorldExtent()
                (wldX, wldY) = layer.coordmgr.getWorldCenter()
                verticalBar = self.verticalScrollBar()
                horizontalBar = self.horizontalScrollBar()
                # always set range to 0 - 1000 and calculate
                # everything as fraction of that
                verticalBar.setRange(0, 1000)
                horizontalBar.setRange(0, 1000)

                # to pagestep which is also the slider size
                fullxsize = float(fullright - fullleft)
                if fullxsize == 0:
                    fullxsize = 100
                hpagestep = (float(right - left) / fullxsize) * 1000
                horizontalBar.setPageStep(int(hpagestep))
                fullysize = float(fulltop - fullbottom)
                if fullysize == 0:
                    fullysize = 100
                vpagestep = (float(top - bottom) / fullysize) * 1000
                verticalBar.setPageStep(int(vpagestep))

                # position of the slider relative to the center of the image
                hpos = (float(wldX - fullleft) / fullxsize) * 1000
                horizontalBar.setSliderPosition(int(hpos))
                vpos = (float(fulltop - wldY) / fullysize) * 1000
                verticalBar.setSliderPosition(int(vpos))
                setbars = True
        if not setbars:
            # something went wrong - disable
            self.horizontalScrollBar().setRange(0, 0)
            self.verticalScrollBar().setRange(0, 0)
        self.suppressscrollevent = False

    def addRasterLayer(self,
                       gdalDataset,
                       stretch,
                       lut=None,
                       ignoreProjectionMismatch=False,
                       quiet=False):
        """
        Add the given dataset to the stack of images being displayed
        as a raster layer
        """
        size = self.viewport().size()
        self.layers.addRasterLayer(gdalDataset, size.width(), size.height(),
                                   stretch, lut, ignoreProjectionMismatch,
                                   quiet)
        # get rid off tool points
        self.toolPoints = None
        self.toolPointsFinished = True

        self.viewport().update()
        self.updateScrollBars()

        self.layerAdded.emit(self)

    def addVectorLayer(self,
                       ogrDataSource,
                       ogrLayer,
                       color=None,
                       resultSet=False,
                       origSQL=None,
                       quiet=False):
        """
        Add the vector given by the ogrDataSource and its dependent 
        ogrLayer to the stack of images.
        """
        size = self.viewport().size()
        if color is None:
            color = viewerlayers.DEFAULT_VECTOR_COLOR

        self.layers.addVectorLayer(ogrDataSource, ogrLayer, size.width(),
                                   size.height(), color, resultSet, origSQL,
                                   quiet)
        self.viewport().update()
        self.updateScrollBars()

        self.layerAdded.emit(self)

    def addVectorFeatureLayer(self,
                              ogrDataSource,
                              ogrLayer,
                              ogrFeature,
                              color=None,
                              quiet=None):
        """
        Just a single feature vector
        """
        size = self.viewport().size()
        if color is None:
            color = viewerlayers.DEFAULT_VECTOR_COLOR

        self.layers.addVectorFeatureLayer(ogrDataSource, ogrLayer, ogrFeature,
                                          size.width(), size.height(), color,
                                          quiet)
        self.viewport().update()
        self.updateScrollBars()

        self.layerAdded.emit(self)

    def addLayersFromJSONFile(self, fileobj, nlayers):
        """
        Get the layer manager to read all the layer descriptions from fileobj
        and load these layers into this widget.
        """
        size = self.viewport().size()
        self.layers.fromFile(fileobj, nlayers, size.width(), size.height())

        self.viewport().update()
        self.updateScrollBars()

        self.layerAdded.emit(self)

    def removeLayer(self):
        """
        Removes the top later
        """
        self.layers.removeTopLayer()
        # get rid off tool points
        self.toolPoints = None
        self.toolPointsFinished = True
        self.viewport().update()
        self.updateScrollBars()

    # query point functions
    def setQueryPoint(self,
                      senderid,
                      easting,
                      northing,
                      color,
                      size=None,
                      cursor=None):
        """
        Sets/Updates query point keyed on the id() of the sender
        """
        self.layers.queryPointLayer.setQueryPoint(senderid, easting, northing,
                                                  color, size, cursor)
        self.layers.queryPointLayer.getImage()
        self.viewport().update()

    def removeQueryPoint(self, senderid):
        """
        Removes a query point. keyed on the id() of the sender
        """
        self.layers.queryPointLayer.removeQueryPoint(senderid)
        self.layers.queryPointLayer.getImage()
        self.viewport().update()

    def highlightValues(self, color, selectionArray=None):
        """
        Applies a QColor to the LUT where selectionArray == True
        to the top layer and redraws. Pass None to reset
        """
        layer = self.layers.getTopRasterLayer()
        if layer is not None:
            if len(layer.stretch.bands) != 1:
                msg = 'can only highlight values on single band images'
                raise viewererrors.InvalidDataset(msg)
            layer.highlightRows(color, selectionArray)

            # force repaint
            self.viewport().update()

    def setColorTableLookup(self,
                            lookupArray=None,
                            colName=None,
                            surrogateLUT=None,
                            surrogateName=None):
        """
        Uses the supplied lookupArray to look up image
        data before indexing into color table in the top
        layer and redraws. Pass None to reset.
        """
        layer = self.layers.getTopRasterLayer()
        if layer is not None:
            if len(layer.stretch.bands) != 1:
                msg = 'can only highlight values on single band images'
                raise viewererrors.InvalidDataset(msg)
            layer.setColorTableLookup(lookupArray, colName, surrogateLUT,
                                      surrogateName)

            # force repaint
            self.viewport().update()

    def zoomNativeResolution(self):
        """
        Sets the zoom to native resolution wherever
        the current viewport is centered
        """
        self.layers.zoomNativeResolution()
        # force repaint
        self.viewport().update()
        self.updateScrollBars()
        # geolink
        self.emitGeolinkMoved()

    def zoomFullExtent(self):
        """
        Resets the zoom to full extent - should be
        the same as when file was opened.
        """
        self.layers.zoomFullExtent()
        # force repaint
        self.viewport().update()
        self.updateScrollBars()
        # geolink
        self.emitGeolinkMoved()

    def setActiveTool(self, tool, senderid):
        """
        Set active tool (one of VIEWER_TOOL_*).
        pass VIEWER_TOOL_NONE to disable
        pass the id() of the calling object. This is passed around
        in the activeToolChanged signal so GUI elements can recognise
        who asked for the change
        """
        # if the tool was line or polygon
        # now is the time to remove the outline from the widget
        if (self.activeTool == VIEWER_TOOL_POLYGON
                or self.activeTool == VIEWER_TOOL_POLYLINE):
            self.toolPoints = None
            self.toolPointsFinished = True
            # force repaint
            self.viewport().update()

        self.activeTool = tool
        if tool == VIEWER_TOOL_ZOOMIN:
            if self.zoomInCursor is None:
                # create if needed.
                self.zoomInCursor = QCursor(
                    QPixmap([
                        "16 16 3 1", ". c None", "a c #000000", "# c #ffffff",
                        ".....#####......", "...##aaaaa##....",
                        "..#.a.....a.#...", ".#.a...a...a.#..",
                        ".#a....a....a#..", "#a.....a.....a#.",
                        "#a.....a.....a#.", "#a.aaaa#aaaa.a#.",
                        "#a.....a.....a#.", "#a.....a.....a#.",
                        ".#a....a....a#..", ".#.a...a...aaa#.",
                        "..#.a.....a#aaa#", "...##aaaaa###aa#",
                        ".....#####...###", "..............#."
                    ]))
            self.viewport().setCursor(self.zoomInCursor)

        elif tool == VIEWER_TOOL_ZOOMOUT:
            if self.zoomOutCursor is None:
                # create if needed
                self.zoomOutCursor = QCursor(
                    QPixmap([
                        "16 16 4 1", "b c None", ". c None", "a c #000000",
                        "# c #ffffff", ".....#####......", "...##aaaaa##....",
                        "..#.a.....a.#...", ".#.a.......a.#..",
                        ".#a.........a#..", "#a...........a#.",
                        "#a...........a#.", "#a.aaaa#aaaa.a#.",
                        "#a...........a#.", "#a...........a#.",
                        ".#a.........a#..", ".#.a.......aaa#.",
                        "..#.a.....a#aaa#", "...##aaaaa###aa#",
                        ".....#####...###", "..............#."
                    ]))
            self.viewport().setCursor(self.zoomOutCursor)

        elif tool == VIEWER_TOOL_PAN:
            if self.panCursor is None:
                # both these used for pan operations
                self.panCursor = QCursor(Qt.OpenHandCursor)
                self.panGrabCursor = QCursor(Qt.ClosedHandCursor)
            self.viewport().setCursor(self.panCursor)

        elif tool == VIEWER_TOOL_QUERY:
            if self.queryCursor is None:
                self.queryCursor = QCursor(Qt.CrossCursor)
            self.viewport().setCursor(self.queryCursor)

        elif tool == VIEWER_TOOL_VECTORQUERY:
            if self.vectorQueryCursor is None:
                self.vectorQueryCursor = QCursor(
                    QPixmap([
                        "16 16 3 1", "# c None", "a c #000000", ". c #ffffff",
                        "######aaaa######", "######a..a######",
                        "######a..a######", "######a..a######",
                        "######a..a######", "######aaaa######",
                        "aaaaa######aaaaa", "a...a######a...a",
                        "a...a######a...a", "aaaaa######aaaaa",
                        "######aaaa######", "######a..a###a.a",
                        "######a..a###aaa", "######a..a###a.a",
                        "######a..a###a.a", "######aaaa###aaa"
                    ]))
            self.viewport().setCursor(self.vectorQueryCursor)

        elif tool == VIEWER_TOOL_POLYGON or tool == VIEWER_TOOL_POLYLINE:
            if self.polygonCursor is None:
                self.polygonCursor = QCursor(
                    QPixmap([
                        "16 16 3 1", "      c None", ".     c #000000",
                        "+     c #FFFFFF", "                ",
                        "       +.+      ", "      ++.++     ",
                        "     +.....+    ", "    +.     .+   ",
                        "   +.   .   .+  ", "  +.    .    .+ ",
                        " ++.    .    .++", " ... ...+... ...",
                        " ++.    .    .++", "  +.    .    .+ ",
                        "   +.   .   .+  ", "   ++.     .+   ",
                        "    ++.....+    ", "      ++.++     ",
                        "       +.+      "
                    ]))
            self.viewport().setCursor(self.polygonCursor)
            msg = ('Left click adds a point, middle to remove last,' +
                   ' right click to end')
            self.showStatusMessage.emit(msg)

        elif tool == VIEWER_TOOL_NONE:
            # change back
            self.viewport().setCursor(Qt.ArrowCursor)

        obj = ActiveToolChangedInfo(self.activeTool, senderid)
        self.activeToolChanged.emit(obj)

    def setNewStretch(self, newstretch, layer, local=False):
        """
        Change the stretch being applied to the current data
        """
        layer.setNewStretch(newstretch, local)
        self.viewport().update()

    def timeseriesBackward(self):
        """
        Assume images are a stacked timeseries oldest
        to newest. Turn on the previous one to the current
        topmost displayed
        """
        self.layers.timeseriesBackward()
        self.viewport().update()

    def timeseriesForward(self):
        """
        Assume images are a stacked timeseries oldest
        to newest. Turn off the current topmost displayed
        """
        self.layers.timeseriesForward()
        self.viewport().update()

    def setMouseScrollWheelAction(self, scrollZoom):
        "Set the action for a mouse wheen event (scroll/zoom)"
        self.mouseWheelZoom = scrollZoom

    def setBackgroundColor(self, color):
        "Sets the background color for the widget"
        widget = self.viewport()
        palette = widget.palette()
        palette.setColor(widget.backgroundRole(), color)
        widget.setPalette(palette)

    def setGeolinkFollowExtentAction(self, followExtent):
        "Set whether we are following geolink extent of just center"
        self.geolinkFollowExtent = followExtent

    def setQueryOnlyDisplayed(self, queryOnlyDisplayed):
        """
        set whether we are only querying displayed layers (True)
        or all (False)
        """
        self.queryOnlyDisplayed = queryOnlyDisplayed

    def flicker(self):
        """
        Call to change the flicker state (ie draw the top raster image
        or not). 
        """
        state = False
        layer = self.layers.getTopLayer()
        if layer is not None:
            state = not layer.displayed
            self.layers.setDisplayedState(layer, state)
            self.viewport().update()
        return state

    def scrollContentsBy(self, dx, dy):
        """
        Handle the user moving the scroll bars
        """
        if not self.suppressscrollevent:
            layer = self.layers.getTopLayer()
            if layer is not None:
                (left, top, right, bottom) = layer.coordmgr.getWorldExtent()
                hpagestep = float(self.horizontalScrollBar().pageStep())
                xamount = -(float(dx) / hpagestep) * (right - left)
                vpagestep = float(self.verticalScrollBar().pageStep())
                yamount = (float(dy) / vpagestep) * (top - bottom)
                wldX, wldY = layer.coordmgr.getWorldCenter()
                layer.coordmgr.setWorldCenter(wldX + xamount, wldY + yamount)
                # not sure why we need this but get black strips
                # around otherwise
                layer.coordmgr.recalcBottomRight()
                self.layers.makeLayersConsistent(layer)
                self.layers.updateImages()
                self.viewport().update()
                self.updateScrollBars()

                # geolink
                self.emitGeolinkMoved()

    def wheelEvent(self, event):
        """
        User has used mouse wheel to zoom in/out or pan depending on defined preference
        """
        layer = self.layers.getTopRasterLayer()
        if layer is not None:
            delta = event.angleDelta().y()

            # Shift scrolling will move you forward and backwards through the time series
            if QApplication.keyboardModifiers() == Qt.ShiftModifier:
                if delta > 0:
                    self.timeseriesBackward()
                elif delta < 0:
                    self.timeseriesForward()

            elif self.mouseWheelZoom:
                (wldX, wldY) = layer.coordmgr.getWorldCenter()

                impixperwinpix = layer.coordmgr.imgPixPerWinPix
                if delta > 0:
                    impixperwinpix *= 1.0 - VIEWER_ZOOM_WHEEL_FRACTION
                elif delta < 0:
                    impixperwinpix *= 1.0 + VIEWER_ZOOM_WHEEL_FRACTION
                layer.coordmgr.setZoomFactor(impixperwinpix)
                layer.coordmgr.setWorldCenter(wldX, wldY)
                # not sure why we need this but get black strips
                # around otherwise
                layer.coordmgr.recalcBottomRight()
                self.layers.makeLayersConsistent(layer)
                self.layers.updateImages()
                self.updateScrollBars()
                self.viewport().update()
            else:
                dx = event.angleDelta().x()
                dy = delta
                self.scrollContentsBy(dx, dy)

            # geolink
            self.emitGeolinkMoved()

    def resizeEvent(self, event):
        """
        Window has been resized - get new data
        """
        size = event.size()
        self.layers.setDisplaySize(size.width(), size.height())
        self.updateScrollBars()

    def paintEvent(self, event):
        """
        Viewport needs to be redrawn. Assume that
        each layer's image is current (as created by getImage())
        we can just draw it with QPainter
        """
        paint = QPainter(self.viewport())

        for layer in self.layers.layers:
            if layer.displayed:
                paint.drawImage(self.paintPoint, layer.image)

        # draw any query points on top of image
        paint.drawImage(self.paintPoint, self.layers.queryPointLayer.image)

        # now any tool points
        if self.toolPoints is not None:
            path = QPainterPath()
            firstpt = self.toolPoints[0]
            path.moveTo(firstpt.x(), firstpt.y())
            for pt in self.toolPoints[1:]:
                path.lineTo(pt.x(), pt.y())
            paint.setPen(self.toolPen)
            paint.drawPath(path)

        paint.end()

    def mousePressEvent(self, event):
        """
        Mouse has been clicked down if we are in zoom/pan
        mode we need to start doing stuff here
        """
        QAbstractScrollArea.mousePressEvent(self, event)
        pos = event.pos()

        if (self.activeTool == VIEWER_TOOL_ZOOMIN
                or self.activeTool == VIEWER_TOOL_ZOOMOUT):
            if self.rubberBand is None:
                self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
            self.rubberBand.setGeometry(QRect(pos, QSize()))
            self.rubberBand.show()
            self.rubberBand.origin = pos

        elif self.activeTool == VIEWER_TOOL_PAN:
            # remember pos
            self.panOrigin = pos
            # change cursor
            self.viewport().setCursor(self.panGrabCursor)

        elif self.activeTool == VIEWER_TOOL_QUERY:

            modifiers = event.modifiers()
            (dspX, dspY) = (pos.x(), pos.y())
            self.newQueryPoint(dspX=dspX, dspY=dspY, modifiers=modifiers)

        elif self.activeTool == VIEWER_TOOL_VECTORQUERY:

            modifiers = event.modifiers()
            (dspX, dspY) = (pos.x(), pos.y())
            self.newVectorQueryPoint(dspX, dspY, modifiers=modifiers)

        elif self.activeTool == VIEWER_TOOL_POLYGON:
            button = event.button()
            if button == Qt.LeftButton:
                # adding points
                if self.toolPoints is None or self.toolPointsFinished:
                    # first point - starts and ends at same pos
                    self.toolPoints = [pos, pos]
                    self.toolPointsFinished = False
                else:
                    # last point same as first - insert before last
                    self.toolPoints.insert(-1, pos)

            elif button == Qt.MiddleButton and self.toolPoints is not None:
                # delete last point
                if len(self.toolPoints) > 2:
                    del self.toolPoints[-2]

            elif button == Qt.RightButton and self.toolPoints is not None:
                # finished
                # create object for signal
                layer = self.layers.getTopRasterLayer()
                modifiers = event.modifiers()
                obj = PolygonToolInfo(self.toolPoints, layer, modifiers)
                self.polygonCollected.emit(obj)

                self.toolPointsFinished = True  # done, but still display

            # redraw so paint() gets called
            self.viewport().update()

        elif self.activeTool == VIEWER_TOOL_POLYLINE:
            button = event.button()
            if button == Qt.LeftButton:
                # adding points
                if self.toolPoints is None or self.toolPointsFinished:
                    # first point
                    self.toolPoints = [pos]
                    self.toolPointsFinished = False
                else:
                    # add to list
                    self.toolPoints.append(pos)

            elif button == Qt.MiddleButton and self.toolPoints is not None:
                # delete last point
                if len(self.toolPoints) > 1:
                    self.toolPoints.pop()

            elif button == Qt.RightButton and self.toolPoints is not None:
                # finished
                # create object for signal
                if self.queryOnlyDisplayed:
                    layer = self.layers.getTopDisplayedRasterLayer()
                else:
                    layer = self.layers.getTopRasterLayer()
                modifiers = event.modifiers()
                obj = PolylineToolInfo(self.toolPoints, layer, modifiers)
                self.polylineCollected.emit(obj)

                self.toolPointsFinished = True  # done, but still display

            # redraw so paint() gets called
            self.viewport().update()

    def mouseReleaseEvent(self, event):
        """
        Mouse has been released, if we are in zoom/pan
        mode we do stuff here.
        """
        QAbstractScrollArea.mouseReleaseEvent(self, event)
        if self.rubberBand is not None and self.rubberBand.isVisible():
            # get the information about the rect they have drawn
            # note this is on self, rather than viewport()
            selection = self.rubberBand.geometry()
            geom = self.viewport().geometry()

            selectionsize = float(selection.width() * selection.height())

            geomsize = float(geom.width() * geom.height())

            self.rubberBand.hide()

            layer = self.layers.getTopRasterLayer()
            if layer is not None:
                if selectionsize < MIN_SELECTION_SIZE_PX:
                    # this is practically a '0' size selection on a 4K screen and
                    # an improbably small selection on an HD screen so assume user
                    # has just clicked the image and set fraction to 0.5
                    fraction = 0.5
                else:
                    fraction = numpy.sqrt(selectionsize / geomsize)

                if self.activeTool == VIEWER_TOOL_ZOOMIN:
                    if selectionsize < MIN_SELECTION_SIZE_PX:
                        # user 'just clicked' (see if statement above).
                        # NOTE: this fixes issues with 0 or negative dimensions
                        #  inside else: below that used ot hard-crash tuiview

                        wldX, wldY = layer.coordmgr.display2world(
                            selection.left(), selection.top())
                        layer.coordmgr.setZoomFactor(
                            layer.coordmgr.imgPixPerWinPix * fraction)
                        layer.coordmgr.setWorldCenter(wldX, wldY)
                        # not sure why we need this but get black strips
                        # around otherwise
                        layer.coordmgr.recalcBottomRight()
                    else:
                        # I don't think anything needs to be added here
                        dspTop = selection.top()
                        dspLeft = selection.left()
                        dspBottom = selection.bottom()
                        dspRight = selection.right()
                        (rastLeft, rastTop) = layer.coordmgr.display2pixel(
                            dspLeft, dspTop)
                        (rastRight, rastBottom) = layer.coordmgr.display2pixel(
                            dspRight, dspBottom)
                        #print layer.coordmgr
                        layer.coordmgr.setTopLeftPixel(rastLeft, rastTop)
                        layer.coordmgr.calcZoomFactor(rastRight, rastBottom)
                        # not sure why we need this but get black strips
                        # around otherwise
                        layer.coordmgr.recalcBottomRight()
                        #print layer.coordmgr

                elif self.activeTool == VIEWER_TOOL_ZOOMOUT:
                    # the smaller the area the larger the zoom
                    center = selection.center()
                    wldX, wldY = layer.coordmgr.display2world(
                        center.x(), center.y())
                    layer.coordmgr.setZoomFactor(
                        layer.coordmgr.imgPixPerWinPix / fraction)
                    layer.coordmgr.setWorldCenter(wldX, wldY)
                    # not sure why we need this but get black strips
                    # around otherwise
                    layer.coordmgr.recalcBottomRight()

                # redraw
                self.layers.makeLayersConsistent(layer)
                self.layers.updateImages()
                self.viewport().update()
                self.updateScrollBars()

                # geolink
                self.emitGeolinkMoved()

        elif self.activeTool == VIEWER_TOOL_PAN:
            # change cursor back
            self.viewport().setCursor(self.panCursor)
            layer = self.layers.getTopRasterLayer()
            if layer is not None:
                # stop panning and move viewport
                dspXmove = -self.paintPoint.x()
                dspYmove = -self.paintPoint.y()
                (pixNewX,
                 pixNewY) = layer.coordmgr.display2pixel(dspXmove, dspYmove)
                #print 'panning'
                #print layer.coordmgr
                layer.coordmgr.setTopLeftPixel(pixNewX, pixNewY)
                layer.coordmgr.recalcBottomRight()
                #print layer.coordmgr
                # reset
                self.paintPoint.setX(0)
                self.paintPoint.setY(0)
                # redraw
                self.layers.makeLayersConsistent(layer)
                self.layers.updateImages()
                self.viewport().update()
                self.updateScrollBars()
                # geolink
                self.emitGeolinkMoved()

    def mouseMoveEvent(self, event):
        """
        Mouse has been moved while dragging. If in zoom/pan
        mode we need to do something here.
        """
        QAbstractScrollArea.mouseMoveEvent(self, event)
        if self.rubberBand is not None and self.rubberBand.isVisible():
            # must be doing zoom in/out. extend rect
            rect = QRect(self.rubberBand.origin, event.pos()).normalized()
            self.rubberBand.setGeometry(rect)

        elif self.activeTool == VIEWER_TOOL_PAN:
            # panning. Work out the offset from where we
            # starting panning and draw the current image
            # at an offset
            pos = event.pos()
            xamount = pos.x() - self.panOrigin.x()
            yamount = pos.y() - self.panOrigin.y()
            self.paintPoint.setX(xamount)
            self.paintPoint.setY(yamount)
            # force repaint - self.paintPoint used by paintEvent()
            self.viewport().update()
            self.updateScrollBars()

    # query point routines
    def newQueryPoint(self,
                      easting=None,
                      northing=None,
                      dspY=None,
                      dspX=None,
                      column=None,
                      row=None,
                      modifiers=None):
        """
        This viewer has recorded a new query point. Or
        user has entered new coords in querywindow.

        Calls updateQueryPoint and emits the geolinkQueryPoint signal

        pass either [easting and northing] or [dspX,dspY] or [column, row]
        """
        if self.queryOnlyDisplayed:
            layer = self.layers.getTopDisplayedRasterLayer()
        else:
            layer = self.layers.getTopRasterLayer()
        if layer is None:
            return

        if ((easting is None or northing is None)
                and (dspX is None or dspY is None)
                and (column is None or row is None)):
            msg = ("must provide one of [easting,northing] or [dspX,dspY] " +
                   "or [column, row]")
            raise ValueError(msg)

        if dspX is not None and dspY is not None:
            (column, row) = layer.coordmgr.display2pixel(dspX, dspY)
            (easting, northing) = layer.coordmgr.pixel2world(column, row)
        elif easting is not None and northing is not None:
            (column, row) = layer.coordmgr.world2pixel(easting, northing)
        elif column is not None and row is not None:
            (easting, northing) = layer.coordmgr.pixel2world(column, row)

        # update the point
        self.updateQueryPoint(easting, northing, column, row, modifiers)

        # emit the geolinked query point signal
        obj = GeolinkInfo(id(self), easting, northing)
        self.geolinkQueryPoint.emit(obj)

    def newVectorQueryPoint(self, dspX, dspY, modifiers=None):
        """
        New vector query point. Does the spatial query
        and emits the vectorLocationSelected signal with
        the results
        """
        if self.queryOnlyDisplayed:
            layer = self.layers.getTopDisplayedVectorLayer()
        else:
            layer = self.layers.getTopVectorLayer()
        if layer is None:
            return

        (easting, northing) = layer.coordmgr.display2world(dspX, dspY)
        tolerance = layer.coordmgr.metersperpix * 3  # maybe should be a pref?

        # show hourglass while query running
        oldCursor = self.cursor()
        self.setCursor(Qt.WaitCursor)

        results = layer.getAttributesAtPoint(easting, northing, tolerance)

        self.setCursor(oldCursor)

        self.vectorLocationSelected.emit(results, layer)

    def updateQueryPoint(self, easting, northing, column, row, modifiers):
        """
        Map has been clicked, get the value and emit
        a locationSelected signal.
        Called by newQueryPoint or when a geolinkQueryPoint signal
        has been received.
        """
        # read the data out of the dataset
        if self.queryOnlyDisplayed:
            layer = self.layers.getTopDisplayedRasterLayer()
        else:
            layer = self.layers.getTopRasterLayer()
        if (layer is not None and column >= 0
                and column < layer.gdalDataset.RasterXSize and row >= 0
                and row < layer.gdalDataset.RasterYSize):
            data = layer.gdalDataset.ReadAsArray(int(column), int(row), 1, 1)
            if data is not None:
                # we just want the single 'drill down' of data as a 1d array
                data = data[..., 0, 0]
                # if single band GDAL gives us a single value -
                # convert back to array
                # to make life easier
                if data.size == 1:
                    data = numpy.array([data])

                qi = QueryInfo(easting, northing, column, row, data, layer,
                               modifiers)
                # emit the signal - handled by the QueryDockWidget
                self.locationSelected.emit(qi)

    def doGeolinkQueryPoint(self, easting, northing):
        """
        Call this when the widget query point has been moved
        in another viewer and should be updated in this
        one if the query tool is active.
        """
        if self.activeTool == VIEWER_TOOL_QUERY:
            if self.queryOnlyDisplayed:
                layer = self.layers.getTopDisplayedRasterLayer()
            else:
                layer = self.layers.getTopRasterLayer()
            if layer is not None:
                (col, row) = layer.coordmgr.world2pixel(easting, northing)
                self.updateQueryPoint(easting, northing, col, row, None)

    # geolinking routines
    def doGeolinkMove(self, easting, northing, metresperwinpix):
        """
        Call this when widget needs to be moved because
        of geolinking event.
        """
        layer = self.layers.getTopRasterLayer()
        if layer is not None:
            if self.geolinkFollowExtent and metresperwinpix != 0:
                imgpixperwinpix = metresperwinpix / layer.coordmgr.geotransform[
                    1]
                layer.coordmgr.setZoomFactor(imgpixperwinpix)

            layer.coordmgr.setWorldCenter(easting, northing)
            self.layers.makeLayersConsistent(layer)
            self.layers.updateImages()
            self.updateScrollBars()
            self.viewport().update()

    def getGeolinkInfo(self):
        """
        Called by emitGeolinkMoved and anything else that needs the
        current GeolinkInfo
        """
        info = None
        # get the coords of the current centre
        layer = self.layers.getTopRasterLayer()
        if layer is not None:
            easting, northing = layer.coordmgr.getWorldCenter()
            metresperwinpix = (layer.coordmgr.imgPixPerWinPix *
                               layer.coordmgr.geotransform[1])
            info = GeolinkInfo(id(self), easting, northing, metresperwinpix)
        return info

    def emitGeolinkMoved(self):
        """
        Call this on each zoom/pan to emit the appropriate signal.
        """
        info = self.getGeolinkInfo()
        if info is not None:
            # emit the signal
            self.geolinkMove.emit(info)
Beispiel #33
0
 def mousePressEvent(self, event):
     self.origin = event.pos()
     if not self.rubberBand:
         self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
     self.rubberBand.setGeometry(QRect(self.origin, QSize()))
     self.rubberBand.show()
Beispiel #34
0
    def mousePressEvent(self, event):
        """
        Mouse has been clicked down if we are in zoom/pan
        mode we need to start doing stuff here
        """
        QAbstractScrollArea.mousePressEvent(self, event)
        pos = event.pos()

        if (self.activeTool == VIEWER_TOOL_ZOOMIN
                or self.activeTool == VIEWER_TOOL_ZOOMOUT):
            if self.rubberBand is None:
                self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
            self.rubberBand.setGeometry(QRect(pos, QSize()))
            self.rubberBand.show()
            self.rubberBand.origin = pos

        elif self.activeTool == VIEWER_TOOL_PAN:
            # remember pos
            self.panOrigin = pos
            # change cursor
            self.viewport().setCursor(self.panGrabCursor)

        elif self.activeTool == VIEWER_TOOL_QUERY:

            modifiers = event.modifiers()
            (dspX, dspY) = (pos.x(), pos.y())
            self.newQueryPoint(dspX=dspX, dspY=dspY, modifiers=modifiers)

        elif self.activeTool == VIEWER_TOOL_VECTORQUERY:

            modifiers = event.modifiers()
            (dspX, dspY) = (pos.x(), pos.y())
            self.newVectorQueryPoint(dspX, dspY, modifiers=modifiers)

        elif self.activeTool == VIEWER_TOOL_POLYGON:
            button = event.button()
            if button == Qt.LeftButton:
                # adding points
                if self.toolPoints is None or self.toolPointsFinished:
                    # first point - starts and ends at same pos
                    self.toolPoints = [pos, pos]
                    self.toolPointsFinished = False
                else:
                    # last point same as first - insert before last
                    self.toolPoints.insert(-1, pos)

            elif button == Qt.MiddleButton and self.toolPoints is not None:
                # delete last point
                if len(self.toolPoints) > 2:
                    del self.toolPoints[-2]

            elif button == Qt.RightButton and self.toolPoints is not None:
                # finished
                # create object for signal
                layer = self.layers.getTopRasterLayer()
                modifiers = event.modifiers()
                obj = PolygonToolInfo(self.toolPoints, layer, modifiers)
                self.polygonCollected.emit(obj)

                self.toolPointsFinished = True  # done, but still display

            # redraw so paint() gets called
            self.viewport().update()

        elif self.activeTool == VIEWER_TOOL_POLYLINE:
            button = event.button()
            if button == Qt.LeftButton:
                # adding points
                if self.toolPoints is None or self.toolPointsFinished:
                    # first point
                    self.toolPoints = [pos]
                    self.toolPointsFinished = False
                else:
                    # add to list
                    self.toolPoints.append(pos)

            elif button == Qt.MiddleButton and self.toolPoints is not None:
                # delete last point
                if len(self.toolPoints) > 1:
                    self.toolPoints.pop()

            elif button == Qt.RightButton and self.toolPoints is not None:
                # finished
                # create object for signal
                if self.queryOnlyDisplayed:
                    layer = self.layers.getTopDisplayedRasterLayer()
                else:
                    layer = self.layers.getTopRasterLayer()
                modifiers = event.modifiers()
                obj = PolylineToolInfo(self.toolPoints, layer, modifiers)
                self.polylineCollected.emit(obj)

                self.toolPointsFinished = True  # done, but still display

            # redraw so paint() gets called
            self.viewport().update()
Beispiel #35
0
class DragWidget(QWidget):
    spacerX = 16
    spacerY = 16
    clipicon = None
    new_window_signal = pyqtSignal(str)
    query = pyqtSignal()
    src_dragwidget = None
    src_selected = []

    def __init__(self, path, parent=None):
        super(DragWidget, self).__init__(parent)
        self.setMinimumSize(400, 200)
        self.setAcceptDrops(True)
        self.parent = parent
        # self.parent.menu.connect(self.delete_icon)
        self.modifier = False
        self.rubberband = QRubberBand(QRubberBand.Rectangle, self)
        self.path = path
        self.icons = []
        self.icon_offsetx = 0
        self.icon_offsety = 0
        # self.clipicon = None
        # self.moving_icons = []
        self.read_drawer()
        self.clean_up()
        # print(type(IconWidget.icon))
        # print(self.findChildren(ClickableIcon))

    def read_drawer(self):
        # self.icons.clear()
        for item in os.scandir(self.path):
            if item.is_dir():
                icon_widget = IconWidget(parent=self, name=item.name, path=self.path, dir=True)
            else:
                icon_widget = IconWidget(parent=self, name=item.name, path=self.path, dir=False)
            icon_widget.new_window.connect(self.new_window_signal.emit)
            icon_widget.clipboard.connect(self.on_clipboard)
            self.icons.append(icon_widget)
            self.icons[-1].setAttribute(Qt.WA_DeleteOnClose)
        # self.update()

    def updateScrollArea(self):
        """ set the dimension of the widget """
        iconx = []
        icony = []
        if len(self.icons) > 0:
            for item in self.icons:
                iconx.append(item.x())
                icony.append(item.y())
            self.setMinimumWidth(max(iconx)+75)
            self.setMinimumHeight(max(icony)+75)
        
    def dragEnterEvent(self, event):
        event.accept()

    def dragMoveEvent(self, event):
        event.accept()

    def get_dnd_list(self, event):
        icon_list = []
        icon_offsetx = None
        icon_offsety = None
        if len(DragWidget.src_selected) > 0:
            for item in DragWidget.src_selected:
                icon_list.append(item)
        else:
            icon_list.append(event.source())
        return icon_list

    def create_icon(self, name, drawer):
        if drawer:
            icon_widget = IconWidget(self, name=name, path=self.path, dir=True)
        else: 
            icon_widget = IconWidget(self, name=name, path=self.path, dir=False)
        icon_widget.new_window.connect(self.new_window_signal.emit)
        self.icons.append(icon_widget)

    def place_icon(self, x, y):
        self.icons[-1].move(x, y)
        self.icons[-1].show()

    def dropEvent(self, event):
        event.accept()
        icon_list = self.get_dnd_list(event)
        icon_offsetx = event.pos().x()
        icon_offsety = event.pos().y()
        for item in icon_list:
            name = item.name
            drawer = item.drawer
            src_path = item.path + "/" + name
            dst_path = self.path + "/"
            if event.mimeData().hasFormat("application/x-icon"):
                self.create_icon(name, drawer)
                self.move_data(src_path, dst_path)
                self.place_icon(icon_offsetx, icon_offsety)
                icon_offsetx += 100 
                if icon_offsetx > self.window().width():
                    icon_offsetx = event.pos().x()
                    icon_offsety += 75

        icon_offsetx = None
        icon_offsety = None
        self.updateScrollArea()

    def clear_dnd(self):
        DragWidget.src_dragwidget = None
        DragWidget.src_selected.clear()

    def get_modifier(self):
        return self.parent.modifier

    def mousePressEvent(self, event):
        if event.buttons() == Qt.LeftButton:
            for item in self.icons:
                item.icon.deselect_icon()
            self.clear_dnd() 

            self.origin = event.pos()
            self.rubberband.setGeometry(QRect(self.origin, QSize()))
            self.rubberband.show()

    def mouseMoveEvent(self, event):
        if self.rubberband.isVisible():
            self.rubberband.setGeometry(
                QRect(self.origin, event.pos()).normalized())
        # QWidget.mouseMoveEvent(self, event)

    def mouseReleaseEvent(self, event):
        self.clear_dnd()
        if self.rubberband.isVisible():
            self.rubberband.hide()
            rect = self.rubberband.geometry()
            for child in self.findChildren(IconWidget):
                if rect.intersects(child.geometry()):
                    child.icon.select_icon()
                    DragWidget.src_selected.append(child)
                    if DragWidget.src_dragwidget is not self:
                        DragWidget.src_dragwidget = self

    def mouseDoubleClickEvent(self, event):
        print(BLU, "Double Click", END) 
        self.query.emit()

    def create_file(self):
        new_file = self.path + "/" + "newfile.txt"
        open(new_file, 'w').close()
        icon_widget = IconWidget(self, name="newfile.txt", path=self.path, dir=False)
        icon_widget.new_window.connect(self.new_window_signal.emit)
        icon_widget.show()
        self.icons.append(icon_widget)

    def create_drawer(self):
        print("creating new drawer")
        new_drawer = self.path + "/" + "NewDrawer"
        os.makedirs(new_drawer)
        icon_widget = IconWidget(self, name="NewDrawer", path=self.path, dir=True)
        icon_widget.new_window.connect(self.new_window_signal.emit)
        icon_widget.show()
        self.icons.append(icon_widget)

    def rename_file(self):
        print("renaming file")

    def clean_up(self):
        for item in self.icons:
            item.move(DragWidget.spacerX, DragWidget.spacerY)
            # initial icon placement
            DragWidget.spacerX += 100
            if DragWidget.spacerX + 100 > self.window().width():
                DragWidget.spacerY += 75
                DragWidget.spacerX = 16
        # reset placement values
        DragWidget.spacerX = 16
        DragWidget.spacerY = 16
        self.updateScrollArea()

    def move_data(self, source, dest):
        srce_path = source.rsplit('/', 1)[0]
        dest_path = dest.rsplit('/', 1)[0]
        if srce_path != dest_path:
            try:
                shutil.move(source, dest)
            except Exception as err:
                print(err)

    def copy_icon(self, source, dest):
        pass

    def delete_icon(self):
        dest = os.path.expanduser("~") + "/.Trash/"
        error_string = ""
        for item in self.icons:
            if item.icon.selected:
                source = item.path + "/" + item.name
                if source is not "":
                    try:
                        shutil.move(source, dest)
                    except Exception as err:
                        error_string += str(err) + "\n" + "\n"
                    else:
                        self.icons.remove(item)
                        item.deleteLater()
        if error_string is not "":
            QMessageBox.information(self, 'Info', error_string, QMessageBox.Ok)

    def paste_icon(self):
        print("---")
        print("srce=", self.clipicon.path + "/" + self.clipicon.name)
        # print("res=", self.clipicon.path + "/" + self.clipicon.name)
        print("dest=", self.path + "/")

        # if os.path.isdir(os.path.join(self.clipicon.path, self.clipicon.name)):
        SRCE = self.clipicon.path + "/" + self.clipicon.name
        DEST = self.path+"/" + self.clipicon.name
        shutil.copytree(SRCE, DEST)

    def on_clipboard(self, icon):
        print("realpath", self.path)
        print("clip_icon_name=", icon.name)
        DragWidget.clipicon = icon
 def __init__(self,*args,**kwargs):
     QRubberBand.__init__(self,*args,**kwargs)
class CaptureImage(QLabel):

    sequence = []
    bag = None
    imageLabel = ImageLabel()

    def __init__(self, timeline, topic, msg, stamp):
        super(CaptureImage, self).__init__()
        self._timeline = timeline
        self._topic = topic
        #INISIALIZING MESSAGE AND COMMON ATTRIBUTES
        self._msg = msg
        self.imageLabel.header = self._msg.header
        self.imageLabel.imageTopic = self._topic
        #ORIGINAL TIME FROM THE ORIGINAL BAG SO THAT WE SAVE THAT SAME TIME IN THE NEW BAG
        self.stamp = stamp
        #WE HAVE TO DO BECAUSE RECT ARE RELATED WITH THE WIDGET WHICH CREATED THEM
        #SO IN ORDER TO SEE AND DELETE THEM FROM THE NEW WIDGET WE HAVE TO RELATE THEM WITH IT
        #***NOTE***: OBJECTS STORED IN SEQUENCE ARE OF TYPE QRUBBERBAND WHEREAS IN IMAGELABEL ARE
        #OF TYPE RECT
        if len(self.sequence) > 0:
            aux_sequence = []
            for rectangle in self.sequence:
                self.currentQRubberBand = QRubberBand(QRubberBand.Rectangle,
                                                      self)
                self.currentQRubberBand.setGeometry(rectangle.x(),
                                                    rectangle.y(),
                                                    rectangle.width(),
                                                    rectangle.height())
                aux_sequence.append(self.currentQRubberBand)
                self.currentQRubberBand.show()
            del self.sequence[:]
            for rectangle in aux_sequence:
                self.sequence.append(rectangle)

    def mousePressEvent(self, eventQMouseEvent):

        if eventQMouseEvent.buttons() == Qt.LeftButton:
            self.originQPoint = eventQMouseEvent.pos()
            self.currentQRubberBand = QRubberBand(QRubberBand.Rectangle, self)
            self.sequence.append(self.currentQRubberBand)

            r = randint(0, 255)
            g = randint(0, 255)
            b = randint(0, 255)
            palette = QPalette()
            palette.setColor(self.currentQRubberBand.foregroundRole(),
                             QColor(r, g, b))
            self.currentQRubberBand.setPalette(palette)

            self.currentQRubberBand.setGeometry(
                QRect(self.originQPoint, QSize()))
            self.currentQRubberBand.show()

        elif eventQMouseEvent.buttons() == Qt.RightButton:
            found = False
            for rect in self.sequence:
                if (rect.geometry().contains(eventQMouseEvent.pos())):
                    self.menu = MenuRectangle(self._timeline, eventQMouseEvent,
                                              rect, self.imageLabel,
                                              self.sequence)
                    found = True
            if not found:
                self.menuglobalimage = MenuGlobalImage(
                    self._timeline, eventQMouseEvent, self._topic,
                    self.sequence, self.imageLabel, self.stamp)

    def mouseMoveEvent(self, eventQMouseEvent):
        self.currentQRubberBand.setGeometry(
            QRect(self.originQPoint, eventQMouseEvent.pos()).normalized())
Beispiel #38
0
class MainView(QGraphicsView):
    """
    This class implements the main view displayed in the MDI area.
    """
    MoveRate = 40
    MoveBound = 10

    sgnScaled = pyqtSignal(float)

    def __init__(self, mainwindow, scene):
        """
        Initialize the main scene.
        :type mainwindow: MainWindow
        :type scene: DiagramScene
        """
        super().__init__(scene)
        self.setContextMenuPolicy(Qt.PreventContextMenu)
        self.setDragMode(QGraphicsView.NoDrag)
        self.setOptimizationFlags(QGraphicsView.DontAdjustForAntialiasing)
        self.setOptimizationFlags(QGraphicsView.DontSavePainterState)
        self.setViewportUpdateMode(QGraphicsView.MinimalViewportUpdate)
        self.mainwindow = mainwindow
        self.mousePressCenterPos = None
        self.mousePressPos = None
        self.moveTimer = None
        self.rubberBandOrigin = None
        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.rubberBand.hide()
        self.zoom = 1.00

    ####################################################################################################################
    #                                                                                                                  #
    #   SLOTS                                                                                                          #
    #                                                                                                                  #
    ####################################################################################################################

    @pyqtSlot()
    def updateView(self):
        """
        Update the Overview.
        """
        viewport = self.viewport()
        viewport.update()

    @pyqtSlot(float)
    def zoomChanged(self, zoom):
        """
        Executed when the zoom factor changes (triggered by the Zoom widget).
        :type zoom: float
        """
        self.scaleView(zoom)

    ####################################################################################################################
    #                                                                                                                  #
    #   DRAWING                                                                                                        #
    #                                                                                                                  #
    ####################################################################################################################

    def drawBackground(self, painter, rect):
        """
        Draw the scene background.
        :type painter: QPainter
        :type rect: QRectF
        """
        if self.mainwindow.snapToGrid:
            s = DiagramScene.GridSize
            x = int(rect.left()) - (int(rect.left()) % s)
            y = int(rect.top()) - (int(rect.top()) % s)
            painter.setPen(DiagramScene.GridPen)
            painter.drawPoints(*(QPointF(i, j) for i in rangeF(x, rect.right(), s) for j in rangeF(y, rect.bottom(), s)))

    ####################################################################################################################
    #                                                                                                                  #
    #   EVENTS                                                                                                         #
    #                                                                                                                  #
    ####################################################################################################################

    def keyPressEvent(self, keyEvent):
        """
        Executed when a combination of key is pressed.
        :type keyEvent: QKeyEvent
        """
        scene = self.scene()
        key = keyEvent.key()
        modifiers = keyEvent.modifiers()

        if scene.mode is DiagramMode.Idle and \
            modifiers & Qt.ControlModifier and \
                key in {Qt.Key_Minus, Qt.Key_Plus, Qt.Key_0}:

            if key == Qt.Key_Minus:
                zoom = self.zoom - Zoom.Step
            elif key == Qt.Key_Plus:
                zoom = self.zoom + Zoom.Step
            else:
                zoom = Zoom.Default

            zoom = clamp(zoom, Zoom.Min, Zoom.Max)

            if zoom != self.zoom:
                self.setTransformationAnchor(QGraphicsView.NoAnchor)
                self.setResizeAnchor(QGraphicsView.NoAnchor)
                self.scaleView(zoom)
                self.sgnScaled.emit(zoom)

        else:
            super().keyPressEvent(keyEvent)

    def mousePressEvent(self, mouseEvent):
        """
        Executed when a mouse button is clicked on the view.
        :type mouseEvent: QGraphicsSceneMouseEvent
        """
        scene = self.scene()
        mouseButtons = mouseEvent.buttons()
        mousePos = mouseEvent.pos()

        if mouseButtons & Qt.RightButton:

            ############################################################################################################
            #                                                                                                          #
            #                                              SCENE DRAG                                                  #
            #                                                                                                          #
            ############################################################################################################

            visibleRect = self.visibleRect()
            self.mousePressCenterPos = visibleRect.center()
            self.mousePressPos = mousePos

        else:

            if mouseButtons & Qt.LeftButton:

                ########################################################################################################
                #                                                                                                      #
                #                                      RUBBERBAND SELECTION                                            #
                #                                                                                                      #
                ########################################################################################################

                if scene.mode is DiagramMode.Idle and not self.itemAt(mousePos):
                    self.rubberBandOrigin = self.mapToScene(mousePos)
                    self.rubberBand.setGeometry(QRectF(mousePos, mousePos).toRect())
                    self.rubberBand.show()
                    scene.setMode(DiagramMode.RubberBandDrag)

            super().mousePressEvent(mouseEvent)

    # noinspection PyArgumentList
    def mouseMoveEvent(self, mouseEvent):
        """
        Executed when then mouse is moved on the view.
        :type mouseEvent: QGraphicsSceneMouseEvent
        """
        scene = self.scene()
        mousePos = mouseEvent.pos()
        mouseButtons = mouseEvent.buttons()
        viewport = self.viewport()

        if mouseButtons & Qt.RightButton:

            if (mouseEvent.pos() - self.mousePressPos).manhattanLength() >= QApplication.startDragDistance():

                ########################################################################################################
                #                                                                                                      #
                #                                            SCENE DRAG                                                #
                #                                                                                                      #
                ########################################################################################################

                if scene.mode is not DiagramMode.SceneDrag:
                    scene.setMode(DiagramMode.SceneDrag)
                    viewport.setCursor(Qt.ClosedHandCursor)

                mousePos /= self.zoom
                mousePressPos = self.mousePressPos / self.zoom
                self.centerOn(self.mousePressCenterPos - mousePos + mousePressPos)

        else:

            super().mouseMoveEvent(mouseEvent)

            if mouseButtons & Qt.LeftButton:
                
                self.stopMove()

                if scene.mode is DiagramMode.RubberBandDrag:

                    ####################################################################################################
                    #                                                                                                  #
                    #                                       RUBBERBAND DRAG                                            #
                    #                                                                                                  #
                    ####################################################################################################

                    area = QRectF(self.mapFromScene(self.rubberBandOrigin), mousePos).normalized()
                    path = QPainterPath()
                    path.addRect(area)
                    scene.setSelectionArea(self.mapToScene(path))
                    self.rubberBand.setGeometry(area.toRect())

                if scene.mode in { DiagramMode.BreakPointMove,
                                   DiagramMode.InsertEdge,
                                   DiagramMode.MoveNode,
                                   DiagramMode.ResizeNode,
                                   DiagramMode.RubberBandDrag }:

                    ####################################################################################################
                    #                                                                                                  #
                    #                                      VIEW SCROLLING                                              #
                    #                                                                                                  #
                    ####################################################################################################

                    R = viewport.rect()
                    if not R.contains(mousePos):

                        move = QPointF(0, 0)

                        if mousePos.x() < R.left():
                            move.setX(mousePos.x() - R.left())
                        elif mousePos.x() > R.right():
                            move.setX(mousePos.x() - R.right())

                        if mousePos.y() < R.top():
                            move.setY(mousePos.y() - R.top())
                        elif mousePos.y() > R.bottom():
                            move.setY(mousePos.y() - R.bottom())

                        if move:
                            move.setX(clamp(move.x(), -MainView.MoveBound, +MainView.MoveBound))
                            move.setY(clamp(move.y(), -MainView.MoveBound, +MainView.MoveBound))
                            self.startMove(move, MainView.MoveRate)

    def mouseReleaseEvent(self, mouseEvent):
        """
        Executed when the mouse is released from the view.
        :type mouseEvent: QGraphicsSceneMouseEvent
        """
        self.mousePressCenterPos = None
        self.mousePressPos = None
        self.rubberBandOrigin = None
        self.rubberBand.hide()

        self.stopMove()

        scene = self.scene()
        viewport = self.viewport()
        viewport.setCursor(Qt.ArrowCursor)
        viewport.update()

        super().mouseReleaseEvent(mouseEvent)

        if scene.mode in {DiagramMode.RubberBandDrag, DiagramMode.SceneDrag}:
            scene.setMode(DiagramMode.Idle)

    def wheelEvent(self, wheelEvent):
        """
        Executed when the mouse wheel is moved on the scene.
        :type wheelEvent: QWheelEvent
        """
        if wheelEvent.modifiers() & Qt.ControlModifier:

            wheelPos = wheelEvent.pos()
            wheelAngle = wheelEvent.angleDelta()

            zoom = self.zoom
            zoom += +Zoom.Step if wheelAngle.y() > 0 else -Zoom.Step
            zoom = clamp(zoom, Zoom.Min, Zoom.Max)

            if zoom != self.zoom:
                self.setTransformationAnchor(QGraphicsView.NoAnchor)
                self.setResizeAnchor(QGraphicsView.NoAnchor)
                p1 = self.mapToScene(wheelPos)
                self.scaleView(zoom)
                self.sgnScaled.emit(zoom)
                p2 = self.mapToScene(wheelPos)
                move = p2 - p1
                self.translate(move.x(), move.y())

        else:
            super().wheelEvent(wheelEvent)

    ####################################################################################################################
    #                                                                                                                  #
    #   INTERFACE                                                                                                      #
    #                                                                                                                  #
    ####################################################################################################################

    def moveBy(self, *__args):
        """
        Move the view by the given delta.
        """
        if len(__args) == 1:
            delta = __args[0]
        elif len(__args) == 2:
            delta = QPointF(__args[0], __args[1])
        else:
            raise TypeError('too many arguments; expected {}, got {}'.format(2, len(__args)))
        self.centerOn(self.visibleRect().center() + delta)

    def scaleView(self, zoom):
        """
        Scale the view according to the given zoom.
        :type zoom: float
        """
        transform = self.transform()
        self.resetTransform()
        self.translate(transform.dx(), transform.dy())
        self.scale(zoom, zoom)
        self.zoom = zoom

    def startMove(self, delta, rate):
        """
        Start the view movement.
        :type delta: QPointF
        :type rate: float
        """
        if self.moveTimer:
            self.stopMove()

        # move the view: this is needed before the timer so that if we keep
        # moving the mouse fast outside the viewport rectangle we still are able
        # to move the view; if we don't do this the timer may not have kicked in
        # and thus we remain with a non-moving view with a unfocused graphicsitem
        self.moveBy(delta)

        # setup a timer for future move, so the view keeps moving
        # also if we are not moving the mouse anymore but we are
        # holding the position outside the viewport rect
        self.moveTimer = QTimer()
        connect(self.moveTimer.timeout, self.moveBy, delta)
        self.moveTimer.start(rate)

    def stopMove(self):
        """
        Stop the view movement by destroying the timer object causing it.
        """
        if self.moveTimer:
            self.moveTimer.stop()
            disconnect(self.moveTimer.timeout)
            self.moveTimer = None

    def visibleRect(self):
        """
        Returns the visible area in scene coordinates.
        :rtype: QRectF
        """
        return self.mapToScene(self.viewport().rect()).boundingRect()
 def __init__(self, *args, **kwargs):
     QRubberBand.__init__(self, *args, **kwargs)
Beispiel #40
0
    def setupUi(self, MainWindow):
        MainWindow.showMaximized()
        
        # Default font
        font = QFont()
        font.setFamily("Bahnschrift Light")
        font.setPointSize(10)
        font.setBold(False)
        font.setWeight(50)

        self.centralwidget = QWidget(MainWindow)
        self.verticalLayoutWidget = QWidget(self.centralwidget)
        self.verticalLayoutWidget.setFont(font)
        self.verticalLayoutWidget.setGeometry(QRect(20, 60, 1100, 891))
        
        self.verticalLayout = QVBoxLayout(self.verticalLayoutWidget)
        self.verticalLayout.setSizeConstraint(QLayout.SetMaximumSize)
        self.verticalLayout.setSpacing(8)

        # for spacing UI
        spacerItem = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        self.verticalLayout.addItem(spacerItem)
        self.outputLabel = QLabel(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.outputLabel)

        self.printer = QPrinter()
        self.scaleFactor = 0.0

        # To select area
        subclasses = self._subclass_container(self.verticalLayoutWidget)
        self.imageLabel = subclasses["rubberband"]

        # Select From Language
        self.fromLabel = QLabel(self.verticalLayoutWidget)
        self.fromLabel.setText("From:")
        self.fromLabel.setFont(font)
        self.fromLabel.setMaximumSize(QSize(16777215, 30))
        self.verticalLayout.addWidget(self.fromLabel)

        self.comboBox = QComboBox(self.verticalLayoutWidget)
        self.comboBox.addItem("English")
        self.comboBox.addItem("Korean")
        self.comboBox.setFont(font)
        self.comboBox.currentIndexChanged.connect(self.selectionchange)
        self.verticalLayout.addWidget(self.comboBox)

        # Select To Language
        self.toLabel = QLabel(self.verticalLayoutWidget)
        self.toLabel.setText("To:")
        self.toLabel.setFont(font)
        self.toLabel.setMaximumSize(QSize(16777215, 30))
        self.verticalLayout.addWidget(self.toLabel)

        self.comboBox_2 = QComboBox(self.verticalLayoutWidget)
        self.comboBox_2.addItem("English")
        self.comboBox_2.addItem("Korean")
        self.comboBox_2.setFont(font)
        self.comboBox_2.currentIndexChanged.connect(self.selectionchange2)
        self.verticalLayout.addWidget(self.comboBox_2)

        # Translate Button
        self.translateButton = QPushButton(self.verticalLayoutWidget)
        self.translateButton.setText("Translate")
        self.translateButton.setFont(font)
        self.translateButton.clicked.connect(self.changeImage)
        self.verticalLayout.addWidget(self.translateButton)

        spacerItem1 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Minimum)
        self.verticalLayout.addItem(spacerItem1)

        # Instruction text label
        self.instructutionLabel = QLabel(self.centralwidget)
        self.instructutionLabel.setGeometry(QRect(60, 20, 651, 16))
        self.instructutionLabel.setFont(font)
        self.instructutionLabel.setText("*Warning: Please select individual scene only, not the speech bubble!*")


        MainWindow.setCentralWidget(self.centralwidget)

        
        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self.imageLabel)
        self.imageLabel.setMouseTracking(True)
        self.origin = QPoint()

        self.verticalLayoutWidget_2 = QWidget(self.centralwidget)
        self.verticalLayoutWidget_2.setGeometry(QRect(1200, 60, 591, 900))

        self.verticalLayout_2 = QVBoxLayout(self.verticalLayoutWidget_2)

        # Original image text label
        self.originalLabel = QLabel(self.verticalLayoutWidget_2)
        self.originalLabel.setMaximumSize(QSize(16777215, 30))
        self.originalLabel.setFont(font)
        self.originalLabel.setText("Original:")
        self.verticalLayout_2.addWidget(self.originalLabel)

        # Original image label
        self.originalImageLabel = QLabel(self.verticalLayoutWidget_2)
        self.originalImageLabel.setObjectName("originalImageLabel")
        self.originalImageLabel.setMinimumSize(QSize(0, 300))
        self.verticalLayout_2.addWidget(self.originalImageLabel)

        # Translated image text label
        self.translatedLabel = QLabel(self.verticalLayoutWidget_2)
        self.translatedLabel.setMaximumSize(QSize(16777215, 30))
        self.translatedLabel.setText("Translated:")
        self.translatedLabel.setFont(font)
        self.verticalLayout_2.addWidget(self.translatedLabel)

        # Translated image label
        self.translatedImageLabel = QLabel(self.verticalLayoutWidget_2)
        self.translatedImageLabel.setMinimumSize(QSize(0, 300))
        self.verticalLayout_2.addWidget(self.translatedImageLabel)

        #Menu
        self.createActions()
        self.createMenus()

        MainWindow.setWindowTitle("Cartoon Translator")
        QMetaObject.connectSlotsByName(MainWindow)
class TcamScreen(QtWidgets.QGraphicsView):

    new_pixmap = pyqtSignal(QtGui.QPixmap)
    new_pixel_under_mouse = pyqtSignal(bool, int, int, QtGui.QColor)
    destroy_widget = pyqtSignal()
    fit_in_view = pyqtSignal()

    def __init__(self, parent=None):
        super(TcamScreen, self).__init__(parent)
        self.setMouseTracking(True)
        self.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
                           QtWidgets.QSizePolicy.Expanding)
        self.setDragMode(QGraphicsView.ScrollHandDrag)
        self.setFrameStyle(0)
        self.scene = QGraphicsScene(self)
        self.setScene(self.scene)

        self.new_pixmap.connect(self.on_new_pixmap)
        self.fit_in_view.connect(self.fit_view)
        self.pix = ViewItem()
        self.scene.addItem(self.pix)
        self.scene.setSceneRect(self.pix.boundingRect())

        self.is_fullscreen = False

        # Flag to differentiate between actual images
        # and 'fake images' i.e. color background + text while
        # waiting for first trigger image
        self.display_real_image = True
        self.text_item = None

        self.fit_in_view_called = False

        self.mouse_position_x = -1
        self.mouse_position_y = -1

        self.zoom_factor = 1.0
        self.first_image = True
        self.image_counter = 0

        self.capture_roi = False
        self.roi_obj = None
        self.roi_origin = None
        self.roi_widgets = []

        self.selection_area = None
        self.capture_widget = None
        self.origin = None

    def fit_view(self):
        """

        """

        self.reset_zoom()
        self.scene.setSceneRect(self.pix.boundingRect())
        self.scene.update()
        self.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio)

    def reset_zoom(self):

        self.zoom_factor = 1.0
        # this resets the view internal transformation matrix
        self.setTransform(QtGui.QTransform())

    def on_new_pixmap(self, pixmap):
        self.image_counter += 1
        self.pix.setPixmap(pixmap)

        if not self.display_real_image:
            self.text_item.hide()
            self.scene.removeItem(self.text_item)
            self.display_real_image = True

        if self.image_counter == 1:
            self.resize(self.size())
            self.scene.setSceneRect(self.pix.boundingRect())
            self.update()

            self.reset_zoom()
            self.first_image = False

        # wait for the second image
        # resizeEvents, etc appear before the scene has adjusted
        # to the actual image size. By waiting for the 2. image
        # we circumvent this by having the first image making all
        # adjustments for us. The only scenario where this will
        # cause problems is triggering.
        if self.is_fullscreen and self.image_counter == 2:
            self.fit_view()

        self.send_mouse_pixel()
        # don't call repaint here
        # it causes problems once the screen goes blank due to screensavers, etc
        # self.repaint()

    def wait_for_first_image(self):

        if not self.display_real_image:
            return

        self.reset_zoom()
        self.display_real_image = False

        self.text_item = QGraphicsTextItem()
        self.text_item.setDefaultTextColor(QColor("white"))

        self.text_item.setPos(100, 70)
        self.text_item.setPlainText("In Trigger Mode. Waiting for first image...")

        bg = QPixmap(1280, 720)
        bg.fill(QColor("grey"))
        self.pix.setPixmap(bg)
        self.image_counter += 1
        self.scene.addItem(self.text_item)

    def send_mouse_pixel(self):
        # mouse positions start at 0
        # we want the lower right corner to have the correct coordinates
        # e.g. an 1920x1080 image should have the coordinates
        # 1920x1080 for the last pixel

        self.new_pixel_under_mouse.emit(self.pix.legal_coordinates(self.mouse_position_x,
                                                                   self.mouse_position_y),
                                        self.mouse_position_x + 1,
                                        self.mouse_position_y + 1,
                                        self.pix.get_color_at_position(self.mouse_position_x,
                                                                       self.mouse_position_y))

    def mouseMoveEvent(self, event):
        mouse_position = self.mapToScene(event.pos())
        self.mouse_position_x = mouse_position.x()
        self.mouse_position_y = mouse_position.y()

        if self.selection_area:

            # adjust rect since we want to pull in all directions
            # origin can well be bottom left, thus recalc
            def calc_selection_rect():

                x = min(self.origin.x(), event.pos().x())
                y = min(self.origin.y(), event.pos().y())
                x2 = max(self.origin.x(), event.pos().x())
                y2 = max(self.origin.y(), event.pos().y())

                return QPoint(x, y), QPoint(x2, y2)

            p1, p2 = calc_selection_rect()
            self.selection_area.setGeometry(QRect(p1, p2))

        super().mouseMoveEvent(event)

    def mousePressEvent(self, event):
        """"""

        if self.capture_widget:

            self.selection_area = QRubberBand(QRubberBand.Rectangle, self)
            self.selection_area.setGeometry(QRect(event.pos(), QSize()))
            self.origin = event.pos()
            self.selection_area.show()

        super().mousePressEvent(event)

    def mouseReleaseEvent(self, event):

        if self.capture_widget:
            selectionBBox = self.selection_area.rect()
            rect = QRect(self.selection_area.pos(), selectionBBox.size())
            selectionBBox = self.mapToScene(rect).boundingRect().toRect()
            self.capture_widget.emit(selectionBBox)

            self.selection_area.hide()
            self.selection_area = None
            QApplication.restoreOverrideCursor()

        self.capture_widget = None
        self.selection_area = None

        super().mouseReleaseEvent(event)

    def is_scene_larger_than_image(self):
        """
        checks if the entire ViewItem is visible in the scene
        """
        port_rect = self.viewport().rect()
        scene_rect = self.mapToScene(port_rect).boundingRect()
        item_rect = self.pix.mapRectFromScene(scene_rect)

        isec = item_rect.intersected(self.pix.boundingRect())

        res = self.pix.get_resolution()
        if (isec.size().width() >= QSizeF(res).width() and
                isec.size().height() >= QSizeF(res).height()):
            return True
        return False

    def wheelEvent(self, event):

        if not self.display_real_image:
            return
        # Zoom Factor
        zoomInFactor = 1.25
        zoomOutFactor = 1 / zoomInFactor

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

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

        # Zoom
        if event.angleDelta().y() > 0:
            zoomFactor = zoomInFactor
        else:
            zoomFactor = zoomOutFactor

        if (self.is_scene_larger_than_image() and
                zoomFactor < 1.0):
            return

        self.zoom_factor *= zoomFactor

        # we scale the view itself to get infinite zoom
        # so that we can inspect a single pixel
        self.scale(zoomFactor, zoomFactor)

        # Get the new position
        newPos = self.mapToScene(event.pos())

        # Move scene to old position
        delta = newPos - oldPos
        self.translate(delta.x(), delta.y())

        self.scene.setSceneRect(self.pix.boundingRect())

    def set_scale_position(self, scale_factor, x, y):
        self.scale(scale_factor, scale_factor)
        self.translate(x, y)

    def keyPressEvent(self, event):
        if self.isFullScreen():
            if (event.key() == Qt.Key_F11 or
                    event.key() == Qt.Key_Escape or
                    event.key() == Qt.Key_F):
                self.destroy_widget.emit()
        elif self.capture_widget and event.key() == Qt.Key_Escape:
            self.abort_roi_capture()
        else:
            # Ignore event so that parent widgets can use it.
            # This is only called when we are not fullscreen.
            # Fullscreen causes us to have no parents.
            event.ignore()

    def start_roi_capture(self, finished_signal):
        """
        Capture a region of interest
        """

        self.capture_widget = finished_signal
        QApplication.setOverrideCursor(Qt.CrossCursor)

    def abort_roi_capture(self):
        """
        Abort the capture of a regoin of interest
        """
        self.capture_widget = None
        self.origin = None

        if self.selection_area:
            self.selection_area.hide()
            self.selection_area = None

        QApplication.restoreOverrideCursor()

    def add_roi(self, roi_widget):
        """
        Add roi_widget to the QGraphicsScene for display
        """
        if not roi_widget:
            return

        self.roi_widgets.append(roi_widget)
        self.scene.addItem(roi_widget)
        roi_widget.show()

    def remove_roi(self, roi_widget):
        """
        Remove given roi widget from the scene
        """
        if not roi_widget:
            return

        roi_widget.hide()
        try:
            self.roi_widgets.remove(roi_widget)
        except ValueError as e:
            # This means the widget is not in the list
            pass
Beispiel #42
0
class MyGraphicsView(CanvasBase):
    """
    This is the used Canvas to print the graphical interface of dxf2gcode.
    All GUI things should be performed in the View and plotting functions in
    the scene
    """

    def __init__(self, parent=None):
        """
        Initialisation of the View Object. This is called by the gui created
        with the QTDesigner.
        @param parent: Main is passed as a pointer for reference.
        """
        super(MyGraphicsView, self).__init__(parent)
        self.currentItem = None

        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QGraphicsView.AnchorViewCenter)

        # self.setDragMode(QGraphicsView.RubberBandDrag )
        self.setDragMode(QGraphicsView.NoDrag)

        self.parent = parent
        self.mppos = None

        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.prvRectRubberBand = QtCore.QRect()

    def tr(self, string_to_translate):
        """
        Translate a string using the QCoreApplication translation framework
        @param string_to_translate: a unicode string
        @return: the translated unicode string if it was possible to translate
        """
        return text_type(QtCore.QCoreApplication.translate('MyGraphicsView',
                                                           string_to_translate))

    def contextMenuEvent(self, event):
        """
        Create the contextmenu.
        @purpose: Links the new Class of ContextMenu to Graphicsview.
        """
        position = self.mapToGlobal(event.pos())
        GVPos = self.mapToScene(event.pos())
        real_pos = Point(GVPos.x(), -GVPos.y())

        menu = MyDropDownMenu(self.scene(), position, real_pos)

    def wheelEvent(self, event):
        """
        With Mouse Wheel the object is scaled
        @purpose: Scale by mouse wheel
        @param event: Event Parameters passed to function
        """
        if c.PYQT5notPYQT4:
            delta = event.angleDelta().y()
        else:
            delta = event.delta()
        scale = (1000 + delta) / 1000.0
        self.scale(scale, scale)

    def mousePressEvent(self, event):
        """
        Right Mouse click shall have no function, Therefore pass only left
        click event
        @purpose: Change inherited mousePressEvent
        @param event: Event Parameters passed to function
        """

        if self.dragMode() == 1:
            super(MyGraphicsView, self).mousePressEvent(event)
        elif event.button() == QtCore.Qt.LeftButton:
            self.mppos = event.pos()
        else:
            pass

    def mouseReleaseEvent(self, event):
        """
        Right Mouse click shall have no function, Therefore pass only left
        click event
        @purpose: Change inherited mousePressEvent
        @param event: Event Parameters passed to function
        """
        delta = 2

        if self.dragMode() == 1:
            # if (event.key() == QtCore.Qt.Key_Shift):
            # self.setDragMode(QGraphicsView.NoDrag)
            super(MyGraphicsView, self).mouseReleaseEvent(event)

        # Selection only enabled for left Button
        elif event.button() == QtCore.Qt.LeftButton:
            self.currentItems = []
            scene = self.scene()
            if not self.isMultiSelect:
                for item in scene.selectedItems():
                    item.setSelected(False, False)
            # If the mouse button is pressed without movement of rubberband
            if self.rubberBand.isHidden():
                rect = QtCore.QRect(event.pos().x()-delta,
                                    event.pos().y() - delta,
                                    2 * delta, 2*delta)
                # logger.debug(rect)

                point = self.mapToScene(event.pos())
                min_distance = float(0x7fffffff)
                for item in self.items(rect):
                    itemDistance = item.contains_point(point)
                    if itemDistance < min_distance:
                        min_distance = itemDistance
                        self.currentItems = item
                if self.currentItems:
                    if self.currentItems.isSelected():
                        self.currentItems.setSelected(False, False)
                    else:
                        self.currentItems.setSelected(True, False)
            else:
                rect = self.rubberBand.geometry()
                self.currentItems = self.items(rect)
                self.rubberBand.hide()
                # logger.debug("Rubberband Selection")

                # All items in the selection
                # self.currentItems = self.items(rect)
                # print self.currentItems
                # logger.debug(rect)

                for item in self.currentItems:
                    if item.isSelected():
                        item.setSelected(False, False)
                    else:
                        # print (item.flags())
                        item.setSelected(True, False)

        else:
            pass

        self.mppos = None
        # super(MyGraphicsView, self).mouseReleaseEvent(event)

    def mouseMoveEvent(self, event):
        """
        MouseMoveEvent of the Graphiscview. May also be used for the Statusbar.
        @purpose: Get the MouseMoveEvent and use it for the Rubberband Selection
        @param event: Event Parameters passed to function
        """
        if self.mppos is not None:
            Point = event.pos() - self.mppos
            if Point.manhattanLength() > 3:
                # print 'the mouse has moved more than 3 pixels since the oldPosition'
                # print "Mouse Pointer is currently hovering at: ", event.pos()
                rect = QtCore.QRect(self.mppos, event.pos())
                '''
                The following is needed because of PyQt5 doesn't like to switch from sign
                 it will keep displaying last rectangle, i.e. you can end up will multiple rectangles
                '''
                if self.prvRectRubberBand.width() > 0 and not rect.width() > 0 or rect.width() == 0 or\
                   self.prvRectRubberBand.height() > 0 and not rect.height() > 0 or rect.height() == 0:
                    self.rubberBand.hide()
                self.rubberBand.setGeometry(rect.normalized())
                self.rubberBand.show()
                self.prvRectRubberBand = rect

        scpoint = self.mapToScene(event.pos())

        # self.setStatusTip('X: %3.1f; Y: %3.1f' % (scpoint.x(), -scpoint.y()))
        # works not as supposed to
        self.setToolTip('X: %3.1f; Y: %3.1f' %(scpoint.x(), -scpoint.y()))

        super(MyGraphicsView, self).mouseMoveEvent(event)

    def autoscale(self):
        """
        Automatically zooms to the full extend of the current GraphicsScene
        """
        scene = self.scene()
        width = scene.bottomRight.x - scene.topLeft.x
        height = scene.topLeft.y - scene.bottomRight.y
        scext = QtCore.QRectF(scene.topLeft.x, -scene.topLeft.y, width * 1.05, height * 1.05)
        self.fitInView(scext, QtCore.Qt.KeepAspectRatio)
        logger.debug(self.tr("Autoscaling to extend: %s") % scext)

    def setShowPathDirections(self, flag):
        """
        This function is called by the Main Window from the Menubar.
        @param flag: This flag is true if all Path Direction shall be shown
        """
        scene = self.scene()
        for shape in scene.shapes:
            shape.starrow.setallwaysshow(flag)
            shape.enarrow.setallwaysshow(flag)
            shape.stmove.setallwaysshow(flag)

    def resetAll(self):
        """
        Deletes the existing GraphicsScene.
        """
        scene = self.scene()
        del scene
Beispiel #43
0
 def __init__(self, parent):
     super().__init__()
     self.rubberband = QRubberBand(QRubberBand.Rectangle, self)
     self.setMouseTracking(True)
     self.parent = parent
Beispiel #44
0
        class RubberbandEnhancedLabel(QLabel):

            def __init__(self, parent=None):
                self._parent_class = _parent_class
                QLabel.__init__(self, parent)
                self.selection = QRubberBand(QRubberBand.Rectangle, self)

            def mousePressEvent(self, event):
                '''
                    Mouse is pressed. If selection is visible either set dragging mode (if close to border) or hide selection.
                    If selection is not visible make it visible and start at this point.
                '''
                #
                if event.button() == Qt.LeftButton:

                    position = QPoint(event.pos())
                    if self.selection.isVisible():
                        # visible selection
                        if (self.upper_left - position).manhattanLength() < 20:
                            # close to upper left corner, drag it
                            self.mode = "drag_upper_left"
                        elif (self.lower_right - position).manhattanLength() < 20:
                            # close to lower right corner, drag it
                            self.mode = "drag_lower_right"
                        else:
                            # clicked somewhere else, hide selection
                            self.selection.hide()
                    else:
                        # no visible selection, start new selection
                        self.upper_left = position
                        self.lower_right = position
                        self.mode = "drag_lower_right"
                        self.selection.show()


            def mouseMoveEvent(self, event):
                '''
                    Mouse moved. If selection is visible, drag it according to drag mode.
                '''
                if self.selection.isVisible():
                    # visible selection
                    if self.mode == "drag_lower_right":
                        self.lower_right = QPoint(event.pos())
                    elif self.mode == "drag_upper_left":
                        self.upper_left = QPoint(event.pos())
                    # update geometry
                    self.selection.setGeometry(QRect(self.upper_left, self.lower_right).normalized())

            def mouseReleaseEvent(self, event):

                if self.selection.isVisible():
                    currentQRect = self.selection.geometry()
                    cropQPixmap = self.pixmap().copy(currentQRect)
                    cropQPixmap.save('output.png')

                    image = QImage("output.png")
                    if image.isNull():
                        QMessageBox.information(self.centralwidget, "Image Viewer", "Cannot load %s." % self.fileName)
                        return

                    pm = QPixmap.fromImage(image)
                    h = pm.height()
                    w = pm.width()

                    if (h > w):
                        self._parent_class.originalImageLabel.setPixmap(pm.scaledToHeight(400))

                    else:
                        self._parent_class.originalImageLabel.setPixmap(pm.scaledToWidth(400))



                    self.selection.hide()
Beispiel #45
0
class ImageViewer(QLabel):
    def __init__(self):
        super(ImageViewer, self).__init__()
        self.crop = Signal()
        #pixmap = QPixmap(640, 640)
        pixmap = QPixmap()
        self.setPixmap(pixmap)


        self.first_x, self.first_y = None, None
        self.last_x, self.last_y = None, None
        self.pen_color = QColor('#000000')        
        self.scaleFactor = 0.0
        self.setBackgroundRole(QPalette.Base)
        #self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
        #self.setScaledContents(True)

        #self.setGeometry(QRect(110, 550, 640, 640))
        self.setText("Feature")
        #self.setAlignment(Qt.AlignTop | Qt.AlignLeft)
        self.setAlignment(Qt.AlignCenter)
        self.setWordWrap(False)
        #self.setFixedSize(640,640)
        self.createActions()
        self.show()


    def setImage(self, q_img):        
        self.setPixmap(q_img)
        self.scaleFactor = 1.0
        #self.fitToWindowAct.setEnabled(True)
        self.updateActions()

        if not self.fitToWindowAct.isChecked():
            self.adjustSize()

    def open(self):
        fileName, _ = QFileDialog.getOpenFileName(self, "Open File",
                QDir.currentPath())
        if fileName:
            image = QImage(fileName)
            if image.isNull():
                QMessageBox.information(self, "Image Viewer",
                        "Cannot load %s." % fileName)
                return

            self.setPixmap(QPixmap.fromImage(image))
            self.scaleFactor = 1.0

            self.fitToWindowAct.setEnabled(True)
            self.updateActions()

            if not self.fitToWindowAct.isChecked():
                self.adjustSize()


    def zoomIn(self):
        self.scaleImage(1.25)

    def zoomOut(self):
        self.scaleImage(0.8)

    def normalSize(self):
        self.adjustSize()
        self.scaleFactor = 1.0

    def fitToWindow(self):
        fitToWindow = self.fitToWindowAct.isChecked()
        self.scrollArea.setWidgetResizable(fitToWindow)
        if not fitToWindow:
            self.normalSize()

        self.updateActions()


    def createActions(self):
        self.openAct = QAction("&Open...", self, shortcut="Ctrl+O",
                triggered=self.open)

        self.zoomInAct = QAction("Zoom &In (25%)", self, shortcut="Ctrl++",
                enabled=False, triggered=self.zoomIn)

        self.zoomOutAct = QAction("Zoom &Out (25%)", self, shortcut="Ctrl+-",
                enabled=False, triggered=self.zoomOut)

        self.normalSizeAct = QAction("&Normal Size", self, shortcut="Ctrl+S",
                enabled=False, triggered=self.normalSize)

        self.fitToWindowAct = QAction("&Fit to Window", self, enabled=False,
                checkable=True, shortcut="Ctrl+F", triggered=self.fitToWindow)


    def updateActions(self):
        self.zoomInAct.setEnabled(not self.fitToWindowAct.isChecked())
        self.zoomOutAct.setEnabled(not self.fitToWindowAct.isChecked())
        self.normalSizeAct.setEnabled(not self.fitToWindowAct.isChecked())

    def scaleImage(self, factor):
        self.scaleFactor *= factor
        self.resize(self.scaleFactor * self.pixmap().size())
        self.zoomInAct.setEnabled(self.scaleFactor < 3.0)
        self.zoomOutAct.setEnabled(self.scaleFactor > 0.333)


    def mousePressEvent (self, eventQMouseEvent):
        self.originQPoint = self.mapFrom(self, eventQMouseEvent.pos())
        self.first_x = int(eventQMouseEvent.x())
        self.first_y = int(eventQMouseEvent.y())
        self.currentQRubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.currentQRubberBand.setGeometry(QRect(self.originQPoint, QSize()))
        self.currentQRubberBand.show()


    def mouseMoveEvent (self, eventQMouseEvent):
        self.x = int(eventQMouseEvent.x())
        self.y = int(eventQMouseEvent.y())
        text1 = str(self.x)
        text2 = str(self.y)
        p = self.mapToGlobal(eventQMouseEvent.pos())
        #QToolTip.showText(eventQMouseEvent.pos() , "X: "+text1+" "+"Y: "+text2,self)
        QToolTip.showText(p, "X: "+text1+" "+"Y: "+text2,self)
        # print ('mouse QToolTip 1') 전체장에서의 위젯 시작점의 좌표가 오리진 포인트가 되어야 함.
        '''
        if self.currentQRubberBand.isVisible():
            self.currentQRubberBand.setGeometry(QRect(self.originQPoint, eventQMouseEvent.pos()).normalized() & self.pixmap().rect())
        '''
        pos = self.mapFromGlobal(self.mapToGlobal(eventQMouseEvent.pos()))
        #QToolTip.showText(eventQMouseEvent.pos(), "X: {} Y: {}".format(p.x(), p.y()), self)
        if self.currentQRubberBand.isVisible() and self.pixmap() is not None:
            self.currentQRubberBand.setGeometry(QRect(self.originQPoint, pos).normalized() & self.rect())



    def mouseReleaseEvent (self, eventQMouseEvent):
        self.last_x = int(eventQMouseEvent.x())
        self.last_y = int(eventQMouseEvent.y())

        '''
        self.currentQRubberBand.hide()
        currentQRect = self.currentQRubberBand.geometry()
        self.currentQRubberBand.deleteLater()
        if self.pixmap() is not None:
            tr = QTransform()
            if self.fitToWindowAct.isChecked():
                tr.scale(self.pixmap().width() / self.scrollArea.width(),
                         self.pixmap().height() / self.scrollArea.height())
            else:
                tr.scale(1 / self.scaleFactor, 1 / self.scaleFactor)
            r = tr.mapRect(currentQRect)
            cropQPixmap = self.pixmap().copy(r)
            cropQPixmap.save('output.png')
        '''

        self.currentQRubberBand.hide()
        currentQRect = self.currentQRubberBand.geometry()
        self.currentQRubberBand.deleteLater()
        cropQPixmap = self.pixmap().copy(currentQRect)
        #size = cropQPixmap.size() 
        # 직접변환 해서 저장하는 코드... 나중에 
        #s = cropQPixmap.bits().asstring(size.width() * size.height() * image.depth() // 8)  # format 0xffRRGGBB
        #arr = np.fromstring(s, dtype=np.uint8).reshape((size.height(), size.width(), cropQPixmap.depth() // 8))
        #new_image = Image.fromarray(array)
        cropQPixmap.save('output.png')
        img = cv2.imread("output.png", cv2.IMREAD_COLOR)
        h, w = self.cut_imgSize()
        self.crop.cut_signal.emit(img, h, w)

    def cut_imgSize (self) :
        h = abs(self.last_y - self.first_y)
        w = abs(self.last_x - self.first_x)
        return h,w
Beispiel #46
0
    def initUI(self):               
        '''
            UI initialization
        '''
        #set size and center
        self.setFixedSize(370, 350)
        self.center()
        
        #create all butons for menu and assign them functions
        self.btn1 = QPushButton('Load PDF', self)
        self.btn1.clicked.connect(self.getFilePath)
        self.btn1.setToolTip('Choose pdf file to work with')
        self.btn1.resize(100, 50)
        self.btn1.move(25, 25) 

        self.btn2 = QPushButton('Set Config', self)
        self.btn2.clicked.connect(self.initConfigForm)
        self.btn2.setToolTip('Configure settings')
        self.btn2.resize(100, 50)
        self.btn2.move(25, 80) 
        
        self.btn3 = QPushButton('Create\nBounding Box', self)
        self.btn3.clicked.connect(self.createBoundingBox)
        self.btn3.setToolTip('Create box limiting area of change')
        self.btn3.resize(100, 50)
        self.btn3.move(135, 25) 

        self.btn4 = QPushButton('Generate Average', self)
        self.btn4.clicked.connect(self.getAverageEstimateWrapper)
        self.btn4.setToolTip('Estimate watermark by averaging over pages')
        self.btn4.resize(100, 50)
        self.btn4.move(135, 80) 

        self.btn5 = QPushButton('Flat Elimination', self)
        self.btn5.clicked.connect(self.convertFlatWrapper)
        self.btn5.setToolTip('Replace all RGB values between set values and replace them with color')
        self.btn5.resize(100, 50)
        self.btn5.move(245, 25) 

        self.btn6 = QPushButton('Average\nElimination', self)
        self.btn6.clicked.connect(self.convertAverageWrapper)
        self.btn6.setToolTip('Replace all RGB values that are similar enough to averaged sample')
        self.btn6.resize(100, 50)
        self.btn6.move(245, 80) 

        #hide certain buttons untill a pdf is choosen
        self.btn3.hide()
        self.btn4.hide()
        self.btn5.hide()
        self.btn6.hide()

        #set name, logo, etc. for progress bar
        self.bar = QWidget()
        self.bar.setWindowIcon(QIcon('graphics//logo.png'))
        self.bar.setWindowTitle('Progress bar')
        self.progress = QProgressBar(self.bar)
        self.bar.move(QDesktopWidget().availableGeometry().center() - QPoint(150, 15))
        self.progress.setGeometry(0, 0, 300, 30)

        #slector for bounding box
        self.selector = QWidget()
        self.pic = QLabel(self.selector)
        
        #assign events to the correct window
        self.selector.mousePressEvent = lambda event : self.MPE(event)
        self.selector.mouseMoveEvent  = lambda event : self.MME(event)
        self.selector.mouseReleaseEvent = lambda event : self.MRE(event)
        
        #set title and logo
        self.selector.setWindowTitle('Select Bounding Box')
        self.selector.setWindowIcon(QIcon('graphics//logo.png'))

        #create rubber band for selector
        self.selection = QRubberBand(QRubberBand.Rectangle, self.pic)
        
        #set project logo in the menu
        logo = QLabel(self)
        logo.resize(200, 200)
        logo.setPixmap(QPixmap("graphics//logo.png"))
        logo.move(85, 130)

        #set title and logo for main windows and finish initialization
        self.setWindowIcon(QIcon('graphics//logo.png'))
        self.setWindowTitle('PDF Purifico')    
        self.show()

        return
Beispiel #47
0
 def setup_crop(self, width, height):
     self.rband = QRubberBand(QRubberBand.Rectangle, self)
     coords = self.mapFromScene(0, 0, width, height)
     self.rband.setGeometry(QRect(coords.boundingRect()))
     self.rband.show()
Beispiel #48
0
class GUI(QMainWindow):
    '''
        Main GUI class
    '''
    def __init__(self):

        '''
            Initializes most basic object and sets default values for parameters
        '''
        super().__init__()
        self.initUI()

        #path to pdf
        self.path = None
        #masks for flat elimination algorithm
        self.conditionLower = np.array([255, 255, 255])
        self.conditionUpper = np.array([100, 100, 100])
        #batch size
        self.batchSize = 5
        #pages to work on -> unfinished so set to always work on full file
        self.pages = [0]
        #color to use when replacing pixels
        self.color = np.array([255, 255, 255])
        #default output name
        self.outName = "temporary"
        #not existing bounding box
        self.boundingBox = [0]

        self.DEBUG = True
        
    def initUI(self):               
        '''
            UI initialization
        '''
        #set size and center
        self.setFixedSize(370, 350)
        self.center()
        
        #create all butons for menu and assign them functions
        self.btn1 = QPushButton('Load PDF', self)
        self.btn1.clicked.connect(self.getFilePath)
        self.btn1.setToolTip('Choose pdf file to work with')
        self.btn1.resize(100, 50)
        self.btn1.move(25, 25) 

        self.btn2 = QPushButton('Set Config', self)
        self.btn2.clicked.connect(self.initConfigForm)
        self.btn2.setToolTip('Configure settings')
        self.btn2.resize(100, 50)
        self.btn2.move(25, 80) 
        
        self.btn3 = QPushButton('Create\nBounding Box', self)
        self.btn3.clicked.connect(self.createBoundingBox)
        self.btn3.setToolTip('Create box limiting area of change')
        self.btn3.resize(100, 50)
        self.btn3.move(135, 25) 

        self.btn4 = QPushButton('Generate Average', self)
        self.btn4.clicked.connect(self.getAverageEstimateWrapper)
        self.btn4.setToolTip('Estimate watermark by averaging over pages')
        self.btn4.resize(100, 50)
        self.btn4.move(135, 80) 

        self.btn5 = QPushButton('Flat Elimination', self)
        self.btn5.clicked.connect(self.convertFlatWrapper)
        self.btn5.setToolTip('Replace all RGB values between set values and replace them with color')
        self.btn5.resize(100, 50)
        self.btn5.move(245, 25) 

        self.btn6 = QPushButton('Average\nElimination', self)
        self.btn6.clicked.connect(self.convertAverageWrapper)
        self.btn6.setToolTip('Replace all RGB values that are similar enough to averaged sample')
        self.btn6.resize(100, 50)
        self.btn6.move(245, 80) 

        #hide certain buttons untill a pdf is choosen
        self.btn3.hide()
        self.btn4.hide()
        self.btn5.hide()
        self.btn6.hide()

        #set name, logo, etc. for progress bar
        self.bar = QWidget()
        self.bar.setWindowIcon(QIcon('graphics//logo.png'))
        self.bar.setWindowTitle('Progress bar')
        self.progress = QProgressBar(self.bar)
        self.bar.move(QDesktopWidget().availableGeometry().center() - QPoint(150, 15))
        self.progress.setGeometry(0, 0, 300, 30)

        #slector for bounding box
        self.selector = QWidget()
        self.pic = QLabel(self.selector)
        
        #assign events to the correct window
        self.selector.mousePressEvent = lambda event : self.MPE(event)
        self.selector.mouseMoveEvent  = lambda event : self.MME(event)
        self.selector.mouseReleaseEvent = lambda event : self.MRE(event)
        
        #set title and logo
        self.selector.setWindowTitle('Select Bounding Box')
        self.selector.setWindowIcon(QIcon('graphics//logo.png'))

        #create rubber band for selector
        self.selection = QRubberBand(QRubberBand.Rectangle, self.pic)
        
        #set project logo in the menu
        logo = QLabel(self)
        logo.resize(200, 200)
        logo.setPixmap(QPixmap("graphics//logo.png"))
        logo.move(85, 130)

        #set title and logo for main windows and finish initialization
        self.setWindowIcon(QIcon('graphics//logo.png'))
        self.setWindowTitle('PDF Purifico')    
        self.show()

        return
        

    def pageForm(self):
        '''
            Unfinished form for retrieving arbitrary start and finish pages
        '''
        #setup widget
        self.pageForm = QWidget()
        self.pageForm.resize(600, 100)

        #set label
        label = QLabel(self.pageForm)
        label.setText("Set first and last page")
        label.move(15, 15)

        #set input fields
        self.firstP = QLineEdit(self.pageForm)
        self.firstP.move(180, 15)

        self.lastP = QLineEdit(self.pageForm)
        self.lastP.move(330, 15)

        #create send button
        self.formPageButton = QPushButton('Set pages', self.pageForm)
        self.formPageButton.clicked.connect(self.setPages)
        self.formPageButton.move(480, 15)

        self.pageForm.show()
        return


    def setPages(self):
        '''
            validate input and save it
        '''
        
        firstP = int(self.firstP.text())
        lastP = int(self.lastP.text())

        #validate
        if (firstP > 0) and (lastP > 0) and (lastP >= firstP):
            self.pages = [firstP, lastP]

        self.waitForPages = False

        #hide form once done
        self.pageForm.hide()

        return



    def initConfigForm(self):
        '''
            Create form forconfiguration changes
        '''

        #create base widget
        self.form = QWidget()
        self.form.resize(500, 350)

        #Creates labels and input fields for all the data
        label = QLabel(self.form)
        label.setText("R value from RGB (min - max)")
        label.move(15, 15)

        label = QLabel(self.form)
        label.setText("G value from RGB (min - max)")
        label.move(15, 45)

        label = QLabel(self.form)
        label.setText("B value from RGB (min - max)")
        label.move(15, 75)


        self.minR = QLineEdit(self.form)
        self.minR.move(180, 15)
        self.maxR = QLineEdit(self.form)
        self.maxR.move(330, 15)

        self.minG = QLineEdit(self.form)
        self.minG.move(180, 45)
        self.maxG = QLineEdit(self.form)
        self.maxG.move(330, 45)

        self.minB = QLineEdit(self.form)
        self.minB.move(180, 75)
        self.maxB = QLineEdit(self.form)
        self.maxB.move(330, 75)


        label = QLabel(self.form)
        label.setText("R value from RGB to set")
        label.move(15, 105)

        label = QLabel(self.form)
        label.setText("G value from RGB to set")
        label.move(15, 135)

        label = QLabel(self.form)
        label.setText("B value from RGB to set")
        label.move(15, 165)

        self.colorR = QLineEdit(self.form)
        self.colorR.move(180, 105)

        self.colorG = QLineEdit(self.form)
        self.colorG.move(180, 135)

        self.colorB = QLineEdit(self.form)
        self.colorB.move(180, 165)

        label = QLabel(self.form)
        label.setText("Size of batches to read to RAM")
        label.move(15, 195)

        self.batchS = QLineEdit(self.form)
        self.batchS.move(180, 195)

        label = QLabel(self.form)
        label.setText("Name for new file")
        label.move(15, 225)

        self.name = QLineEdit(self.form)
        self.name.move(180, 225)

        #button to send
        self.formButton = QPushButton('Save Config', self.form)
        self.formButton.clicked.connect(self.setConfig)
        self.formButton.move(330, 135)
        self.formButton.resize(135, 50)

        #set name and logo
        self.form.setWindowTitle("Config")
        self.form.setWindowIcon(QIcon('graphics//logo.png'))
        self.form.show()
        return


    def setConfig(self):
        '''
            validate and set data from config form
        '''
        try:
            #retrieve all the data and cast to correct type
            minR = int(self.minR.text())
            minG = int(self.minG.text())
            minB = int(self.minB.text())

            maxR = int(self.maxR.text())
            maxG = int(self.maxG.text())
            maxB = int(self.maxB.text())

            colorR = int(self.colorR.text())
            colorG = int(self.colorG.text())
            colorB = int(self.colorB.text())

            batchS = int(self.batchS.text())

            self.outName = self.name.text()

            #validate and save
            if (0 <= minR <= 255) and (0 <= minG <= 255) and (0 <= minB <= 255):
                self.conditionUpper = np.array([minR, minG, minB])

            if (0 <= maxR <= 255) and (0 <= maxG <= 255) and (0 <= maxB <= 255):
                self.conditionUpper = np.array([maxR, maxG, maxB])

            if (0 <= colorR <= 255) and (0 <= colorG <= 255) and (0 <= colorB <= 255):
                self.conditionUpper = np.array([colorR, colorG, colorB])

            if (batchS > 0):
                self.batchSize = batchS

            self.form.hide()

        except:
            #in case of error
            QMessageBox.question(self, 'Error', "Something broke", QMessageBox.Yes)
            self.form.hide()


        return

    def onCountChanged(self, value):
        '''
            For updating progress bar
        '''
        self.progress.setValue(value)
        return



    def getFilePath(self):
        '''
            Get path to pdf file
        '''
        w = QWidget()
        filename = QFileDialog.getOpenFileName(w, 'Select PDF file')
        self.path = filename[0]

        #since we got a pdf now we can enable the other buttons
        self.btn3.show()
        self.btn4.show()
        self.btn5.show()
        self.btn6.show()
        return

    def convertFlatWrapper(self):
        '''
            Wrapper for convertFlat function
        '''

        #set pages correctly
        if (len(self.pages) == 2):
            pagesToClean = self.pages[1] - self.pages[0] + 1
            pageOffset = self.pages[0] - 1
        elif (len(self.pages) == 1):
            pagesToClean = self.pages[0]
            pageOffset = 0
        else:
            QMessageBox.about(self,"Error", "Pages set incorrectly")
            return

        #prepare update bar send data to thread and start it
        self.bar.show()
        self.calc = External()
        self.calc.setFunction(convertFlat, (self.path, self.conditionLower, self.conditionUpper, self.batchSize, self.outName, pagesToClean, pageOffset, self.color, self.boundingBox))

        self.calc.countChanged.connect(self.onCountChanged)
        self.calc.start()

        return

    def getAverageEstimateWrapper(self):
        '''
            Wrapper for getAverageEstimate
        '''

        #set pages correctly
        if (len(self.pages) == 2):
            pagesToClean = self.pages[1] - self.pages[0] + 1
            pageOffset = self.pages[0] - 1
        elif (len(self.pages) == 1):
            pagesToClean = self.pages[0]
            pageOffset = 0
        else:
            QMessageBox.about(self,"Error", "Pages set incorrectly")
            return

        #prepare update bar send data to thread and start it
        self.bar.show()
        self.calc = External()
        self.calc.setFunction(getAverageEstimate, (self.path, self.batchSize, self.outName, pagesToClean, pageOffset))

        self.calc.countChanged.connect(self.onCountChanged)

        self.calc.start()

        return

    def convertAverageWrapper(self):
        '''
            Wrapper for converAverage
        '''
        if (len(self.pages) == 2):
            pagesToClean = self.pages[1] - self.pages[0] + 1
            pageOffset = self.pages[0] - 1
        elif (len(self.pages) == 1):
            pagesToClean = self.pages[0]
            pageOffset = 0
        else:
            QMessageBox.about(self,"Error", "Pages set incorrectly")


        #slect averaged file touse as filter for pdf
        w = QWidget()
        filename = QFileDialog.getOpenFileName(w, 'Select averaged file to filter pdf')

        #prepare update bar send data to thread and start it
        self.bar.show()
        self.calc = External()
        self.calc.setFunction(convertAverage, (self.path, filename[0], self.batchSize, self.outName, pagesToClean, pageOffset, self.color, self.boundingBox))
        self.calc.countChanged.connect(self.onCountChanged)

        self.calc.start()

        return

    def center(self):
        '''
            method for centering
        '''
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
        return
        
        
    def closeEvent(self, event):
        '''
            Confirmation when closing software
        '''
        reply = QMessageBox.question(self, 'Message', "Are you sure?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

        return
        
    
        
    def MPE(self, event):
        '''
            Mouse is pressed. If selection is visible either set dragging mode (if close to border) or hide selection.
            If selection is not visible make it visible and start at this point.
        '''

        if event.button() == Qt.LeftButton:

            position = QPoint(event.pos())

            if (self.DEBUG):
                print("Start coords:", position.x(), position.y())

            #set coords for later
            self.start_x = position.x()
            self.start_y = position.y()
            
            if self.selection.isVisible():
                # visible selection
                if (self.upper_left - position).manhattanLength() < 20:
                    # close to upper left corner, drag it
                    self.mode = "drag_upper_left"
                elif (self.lower_right - position).manhattanLength() < 20:
                    # close to lower right corner, drag it
                    self.mode = "drag_lower_right"
                else:
                    # clicked somewhere else, hide selection
                    self.selection.hide()
            else:
                # no visible selection, start new selection
                self.upper_left = position
                self.lower_right = position
                self.mode = "drag_lower_right"
                self.selection.show()

        return

    def MME(self, event):
        '''
            Mouse moved. If selection is visible, drag it according to drag mode.
        '''

        if self.selection.isVisible():
            # visible selection
            if self.mode is "drag_lower_right":
                self.lower_right = QPoint(event.pos())
            elif self.mode is "drag_upper_left":
                self.upper_left = QPoint(event.pos())
            # update geometry
            self.selection.setGeometry(QRect(self.upper_left, self.lower_right).normalized())

        return
        
    def MRE(self, event):
        '''
            Mouse is released. Hide selector, selection and save propertly transformed coords 
        '''
        if event.button() == Qt.LeftButton:

            position = QPoint(event.pos())

            if (self.DEBUG):
                print("Stop coords:", position.x(), position.y())
            
            #save final position
            self.stop_x = position.x()
            self.stop_y = position.y()
            
            if self.selection.isVisible():
                self.selection.hide()
                self.selector.hide()
        
            im = convert_from_path(self.path, fmt='jpeg', first_page=1, last_page=1)[0]
            width, height = im.size

            if (self.DEBUG):
                orig = np.array(im)
                color = np.array([100, 100, 200])
                

            pts = np.zeros((2,2))

            #set coordinates for bounding box
            pts[0][0] = int(self.start_x / self.scaled_im_width * width)
            pts[0][1] = int(self.start_y / self.scaled_im_height * height)
            pts[1][0] = int(self.stop_x / self.scaled_im_width * width)
            pts[1][1] = int(self.stop_y / self.scaled_im_height * height)

            self.boundingBox = pts

            if(self.DEBUG):

                drawLines(orig, pts.astype(int), color, 3)
                im = Image.fromarray(orig)
                im.save('temp\\sample.jpeg')
                im.show()

        return     
        
    def createBoundingBox(self):
        '''
            Creates bounding box to be used in one of the enxt algorithms
        '''
        im = convert_from_path(self.path, fmt='jpeg', first_page=1, last_page=1)[0]

        im.save("temp\\temp.jpg")

        #get original sizes
        width, height = im.size
        
        im.close()
        
        
        geo = QDesktopWidget().availableGeometry()
        
        #transform for convinience
        if (geo.height() < height):
            width *=  (geo.height()/height) * 0.9
            height = geo.height() * 0.9

        #save for reversing later
        self.scaled_im_width = int(width)
        self.scaled_im_height = int(height)
            
        
        self.pic.setGeometry(0 , 0, width, height)
        self.selector.setFixedSize(width, height)

        #load picture
        self.pic.setPixmap(QPixmap("temp\\temp.jpg").scaledToHeight(height))

        qr = self.selector.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.selector.move(qr.topLeft())
        
        self.selector.show()

        return
 def mousePressEvent(self, event):
     self.origin = event.pos()
     if self.rubberBand is None:
         self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
     self.rubberBand.setGeometry(QRect(self.origin, QSize()))
     self.rubberBand.show()
Beispiel #50
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)
            """
            QMessageBox.about(self, 'PHIDL Help', help_str)
Beispiel #51
0
class VideoWidget(QVideoWidget):
    def __init__(self, parent=None):
        super(VideoWidget, self).__init__(parent)
        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        pal = QPalette()
        pal.setBrush(QPalette.Highlight, QBrush(QColor(Qt.green)))
        self.rubberBand.setPalette(pal)
        self.setUpdatesEnabled(True)
        self.setMouseTracking(True)
        self.origin = QPoint()
        self.changeRubberBand = False

        self.parent = parent.parent()
        self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)

        self.setAttribute(Qt.WA_NoSystemBackground, True)
        self.setAttribute(Qt.WA_PaintOnScreen, True)
        palette = self.palette()
        palette.setColor(QPalette.Background, Qt.black)
        self.setPalette(palette)
        self.setSizePolicy(QSizePolicy.MinimumExpanding,
                           QSizePolicy.MinimumExpanding)

        self.surface = VideoWidgetSurface(self)

        self.setAttribute(Qt.WA_OpaquePaintEvent)
        self.gt = None

        self.pressed = False
        self.snapped = False
        self.zoomed = False
        self.zoomedRect = False

        self.offset = QPoint()
        self.pressPos = QPoint()
        self.dragPos = QPoint()
        self.tapTimer = QBasicTimer()
        self.zoomPixmap = QPixmap()
        self.maskPixmap = QPixmap()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape and self.isFullScreen():
            self.setFullScreen(False)
            event.accept()
        elif event.key() == Qt.Key_Enter and event.modifiers() & Qt.Key_Alt:
            self.setFullScreen(not self.isFullScreen())
            event.accept()
        else:
            super(VideoWidget, self).keyPressEvent(event)

    def mouseDoubleClickEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        self.setFullScreen(not self.isFullScreen())
        event.accept()

    def videoSurface(self):
        return self.surface

    def UpdateSurface(self):
        self.surface.widget.update()

    def sizeHint(self):
        return self.surface.surfaceFormat().sizeHint()

    def GetCurrentFrame(self):
        return self.surface.image

    def SetInvertColor(self, value):
        global invertColorFilter
        invertColorFilter = value

    def SetGray(self, value):
        global grayColorFilter
        grayColorFilter = value

    def SetEdgeDetection(self, value):
        global edgeDetectionFilter
        edgeDetectionFilter = value

    def SetAutoContrastFilter(self, value):
        global contrastFilter
        contrastFilter = value

    def SetMonoFilter(self, value):
        global monoFilter
        monoFilter = value

    def RestoreFilters(self):
        global invertColorFilter, grayColorFilter, edgeDetectionFilter, monoFilter, contrastFilter
        invertColorFilter = grayColorFilter = edgeDetectionFilter = monoFilter = contrastFilter = False

    def GetXBlackZone(self):
        x = 0.0
        normalizedWidth = self.surface.widget.height() * (GetImageWidth() /
                                                          GetImageHeight())
        if (self.surface.widget.width() / self.surface.widget.height()) > (
                GetImageWidth() / GetImageHeight()):
            x = (self.surface.widget.width() - (normalizedWidth)) / 2.0
        return x

    def GetYBlackZone(self):
        y = 0.0
        normalizedHeight = self.surface.widget.width() / (GetImageWidth() /
                                                          GetImageHeight())
        if (self.surface.widget.width() / self.surface.widget.height()) < (
                GetImageWidth() / GetImageHeight()):
            y = (self.surface.widget.height() - (normalizedHeight)) / 2.0
        return y

    # determines if a clicked point lands on the image (False if lands on the
    # black borders or outside)
    def IsPointOnScreen(self, x, y):
        res = True
        normalizedWidth = self.surface.widget.height() * (GetImageWidth() /
                                                          GetImageHeight())
        normalizedHeight = self.surface.widget.width() / (GetImageWidth() /
                                                          GetImageHeight())
        if x > (normalizedWidth +
                self.GetXBlackZone()) or x < self.GetXBlackZone():
            res = False
        if y > (normalizedHeight +
                self.GetYBlackZone()) or y < self.GetYBlackZone():
            res = False
        return res

    # ratio between event.x() and real image width on screen.
    def GetXRatio(self):
        return GetImageWidth() / (self.surface.widget.width() -
                                  (2 * self.GetXBlackZone()))

    # ratio between event.y() and real image height on screen.
    def GetYRatio(self):
        return GetImageHeight() / (self.surface.widget.height() -
                                   (2 * self.GetYBlackZone()))

    def paintEvent(self, event):
        self.gt = GetGCPGeoTransform()
        painter = QPainter(self)

        if (self.surface.isActive()):
            videoRect = self.surface.videoRect()
            if not videoRect.contains(event.rect()):
                region = event.region()
                region.subtracted(QRegion(videoRect))
                brush = self.palette().window()
                for rect in region.rects():
                    painter.fillRect(rect, brush)

            try:
                self.surface.paint(painter)
            except Exception:
                None
        else:
            painter.fillRect(event.rect(), self.palette().window())
        try:
            SetImageSize(self.surface.currentFrame.width(),
                         self.surface.currentFrame.height())
        except:
            None

        # Magnifier Glass
        if self.zoomed and magnifier:
            dim = min(self.width(), self.height())
            magnifierSize = min(MAX_MAGNIFIER, dim * 2 / 3)
            radius = magnifierSize / 2
            ring = radius - 15
            box = QSize(magnifierSize, magnifierSize)

            # reupdate our mask
            if self.maskPixmap.size() != box:
                self.maskPixmap = QPixmap(box)
                self.maskPixmap.fill(Qt.transparent)
                g = QRadialGradient()
                g.setCenter(radius, radius)
                g.setFocalPoint(radius, radius)
                g.setRadius(radius)
                g.setColorAt(1.0, QColor(64, 64, 64, 0))
                g.setColorAt(0.5, QColor(0, 0, 0, 255))
                mask = QPainter(self.maskPixmap)
                mask.setRenderHint(QPainter.Antialiasing)
                mask.setCompositionMode(QPainter.CompositionMode_Source)
                mask.setBrush(g)
                mask.setPen(Qt.NoPen)
                mask.drawRect(self.maskPixmap.rect())
                mask.setBrush(QColor(Qt.transparent))
                mask.drawEllipse(g.center(), ring, ring)
                mask.end()

            center = self.dragPos - QPoint(0, radius)
            center += QPoint(0, radius / 2)
            corner = center - QPoint(radius, radius)
            xy = center * 2 - QPoint(radius, radius)
            # only set the dimension to the magnified portion
            if self.zoomPixmap.size() != box:
                self.zoomPixmap = QPixmap(box)
                self.zoomPixmap.fill(Qt.lightGray)

            if True:
                painter = QPainter(self.zoomPixmap)
                painter.translate(-xy)
                self.largePixmap = QPixmap.fromImage(self.surface.image)
                painter.drawPixmap(self.offset, self.largePixmap)
                painter.end()

            clipPath = QPainterPath()
            clipPath.addEllipse(QPointF(center), ring, ring)
            painter = QPainter(self)
            painter.setRenderHint(QPainter.Antialiasing)
            painter.setClipPath(clipPath)
            painter.drawPixmap(corner, self.zoomPixmap)
            painter.drawPixmap(corner, self.maskPixmap)
            painter.setPen(Qt.gray)
            painter.drawPath(clipPath)
        return

    def resizeEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        QWidget.resizeEvent(self, event)
        self.zoomed = False
        if zoomRect and self.surface.zoomedrect is not None:
            self.surface.updatetest()
            return
        self.surface.updateVideoRect()

    def mouseMoveEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        # Cursor Coordinates
        if self.gt is not None:

            # check if the point  is on picture (not in black borders)
            if (not self.IsPointOnScreen(event.x(), event.y())):
                return

            transf = self.gt([
                (event.x() - self.GetXBlackZone()) * self.GetXRatio(),
                (event.y() - self.GetYBlackZone()) * self.GetYRatio()
            ])

            Longitude = transf[1]
            Latitude = transf[0]
            Altitude = 0.0

            self.parent.lb_cursor_coord.setText(
                "<span style='font-size:10pt; font-weight:bold;'>Lon :</span>"
                + "<span style='font-size:9pt; font-weight:normal;'>" +
                ("%.3f" % Longitude) + "</span>" +
                "<span style='font-size:10pt; font-weight:bold;'> Lat :</span>"
                + "<span style='font-size:9pt; font-weight:normal;'>" +
                ("%.3f" % Latitude) + "</span>")
        else:
            self.parent.lb_cursor_coord.setText(
                "<span style='font-size:10pt; font-weight:bold;'>Lon :</span>"
                +
                "<span style='font-size:9pt; font-weight:normal;'>Null</span>"
                +
                "<span style='font-size:10pt; font-weight:bold;'> Lat :</span>"
                +
                "<span style='font-size:9pt; font-weight:normal;'>Null</span>")

        if not event.buttons():
            return

        if self.changeRubberBand:
            self.rubberBand.setGeometry(
                QRect(self.origin, event.pos()).normalized())

        if self.zoomed is True:
            self.rubberBand.hide()
            self.zoomedRect = False

        if not self.zoomed:
            if not self.pressed or not self.snapped:
                delta = event.pos() - self.pressPos
                self.pressPos = event.pos()
                self.pan(delta)
                return
            else:
                threshold = 10
                delta = event.pos() - self.pressPos
                if self.snapped:
                    self.snapped &= delta.x() < threshold
                    self.snapped &= delta.y() < threshold
                    self.snapped &= delta.x() > -threshold
                    self.snapped &= delta.y() > -threshold

                if not self.snapped:
                    self.tapTimer.stop()

        else:
            self.dragPos = event.pos()
            self.surface.updateVideoRect()

#     TODO: MAKE PAINT GEOMETRY ACTION AND CREATE SHAPES

    def pan(self, delta):
        """ Pan Action """
        self.offset += delta
        self.surface.updateVideoRect()

    def timerEvent(self, _):
        """ Time Event """
        if not self.zoomed:
            self.activateMagnifier()
        self.surface.updateVideoRect()

    def mousePressEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if event.button() == Qt.LeftButton:
            self.pressed = self.snapped = True
            self.pressPos = self.dragPos = event.pos()
            self.tapTimer.stop()
            self.tapTimer.start(HOLD_TIME, self)

        if zoomRect and event.button() == Qt.LeftButton:
            self.origin = event.pos()
            self.rubberBand.setGeometry(QRect(self.origin, QSize()))
            self.rubberBand.show()
            self.changeRubberBand = True

    def activateMagnifier(self):
        """ Activate Magnifier Glass """
        self.zoomed = True
        self.tapTimer.stop()
        self.surface.updateVideoRect()

    def SetMagnifier(self, value):
        """ Set Magnifier Glass """
        global magnifier
        magnifier = value

    def SetZoomRect(self, value):
        """ Set Zoom Rectangle """
        global zoomRect
        zoomRect = value

    def mouseReleaseEvent(self, _):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        self.changeRubberBand = False
        if self.zoomed is True:
            return
        self.zoomed = False
        if not zoomRect:
            self.surface.updateVideoRect()
        else:
            self.rubberBand.hide()
            self.zoomedRect = True

            # TODO :  ACTUALIZAR LA IMAGEN
            selRect = self.rubberBand.geometry()

            orig2widgScale = self.surface.widget.contentsRect().width() / \
                self.surface.image.width()

            X1 = selRect.topLeft().x() / orig2widgScale
            Y1 = selRect.topLeft().y() / orig2widgScale
            X2 = selRect.bottomRight().x() / self.surface.widget.contentsRect().bottomRight().x() * \
                self.surface.image.width()
            Y2 = selRect.bottomRight().y() / self.surface.widget.contentsRect().bottomRight().y() * \
                self.surface.image.height()

            self.surface.image.width()
            self.surface.image.height()

            wid2origRect = QRect(X1, Y1, X2, Y2)
            zoom_img = self.surface.image.copy(wid2origRect)
            # zoom_img.save('D:\\test.png')
            #             n_img = self.surface.image.copy(selRect)
            #             n_img.save('D:\\test.png')
            zoom_img.scaled(1920, 1080)
            self.surface.currentFrame = QVideoFrame(zoom_img)
            #             self.surface.targetRect=selRect
            self.surface.currentFrame.unmap()
            self.UpdateSurface()

    def leaveEvent(self, _):
        self.parent.lb_cursor_coord.setText("")
Beispiel #52
0
class VideoWidget(QVideoWidget):
    def __init__(self, parent=None):
        ''' Constructor '''
        super(VideoWidget, self).__init__(parent)
        self.surface = VideoWidgetSurface(self)
        self.Tracking_RubberBand = QRubberBand(QRubberBand.Rectangle, self)

        self.Censure_RubberBand = QRubberBand(QRubberBand.Rectangle, self)

        pal = QPalette()
        pal.setBrush(QPalette.Highlight, QBrush(QColor(Qt.blue)))
        self.Tracking_RubberBand.setPalette(pal)

        pal = QPalette()
        pal.setBrush(QPalette.Highlight, QBrush(QColor(Qt.black)))
        self.Censure_RubberBand.setPalette(pal)

        self.var_currentMouseMoveEvent = None

        self._interaction = InteractionState()
        self._filterSatate = FilterState()

        self.setUpdatesEnabled(True)
        self.snapped = False
        self.zoomed = False
        self._isinit = False
        self.gt = None

        self.drawCesure = []
        self.poly_coordinates, self.drawPtPos, self.drawLines, self.drawRuler, self.drawPolygon = [], [], [], [], []
        self.poly_RubberBand = QgsRubberBand(iface.mapCanvas(),
                                             True)  # Polygon type
        # set rubber band style
        color = QColor(176, 255, 128)
        self.poly_RubberBand.setColor(color)
        color.setAlpha(190)
        self.poly_RubberBand.setStrokeColor(color)
        self.poly_RubberBand.setWidth(3)

        self.parent = parent.parent()

        self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)

        self.setAttribute(Qt.WA_NoSystemBackground)
        self.setAttribute(Qt.WA_PaintOnScreen)
        self.setAttribute(Qt.WA_OpaquePaintEvent)
        self.setAttribute(Qt.WA_DeleteOnClose)
        palette = self.palette()
        palette.setColor(QPalette.Background, Qt.black)
        self.setPalette(palette)
        self.setSizePolicy(QSizePolicy.MinimumExpanding,
                           QSizePolicy.MinimumExpanding)

        self.offset, self.origin, self.pressPos, self.dragPos = QPoint(
        ), QPoint(), QPoint(), QPoint()
        self.tapTimer = QBasicTimer()
        self.zoomPixmap, self.maskPixmap = QPixmap(), QPixmap()

    def removeLastLine(self):
        ''' Remove Last Line Objects '''
        if len(self.drawLines) > 0:
            for pt in range(len(self.drawLines) - 1, -1, -1):
                del self.drawLines[pt]
                try:
                    if self.drawLines[pt - 1][0] is None:
                        break
                except Exception:
                    None
            self.UpdateSurface()
            AddDrawLineOnMap(self.drawLines)
        return

    def removeLastSegmentLine(self):
        ''' Remove Last Segment Line Objects '''
        if len(self.drawLines) > 0:
            del self.drawLines[-1]
            self.UpdateSurface()
            AddDrawLineOnMap(self.drawLines)
        return

    def removeAllLines(self):
        ''' Resets Line List '''
        self.drawLines = []
        self.UpdateSurface()
        # Clear all Layer
        RemoveAllDrawLineOnMap()

    def ResetDrawRuler(self):
        ''' Resets Ruler List '''
        self.drawRuler = []

    def removeAllCensure(self):
        ''' Remove All Censure Objects '''
        self.drawCesure = []

    def removeLastCensured(self):
        ''' Remove Last Censure Objects '''
        if len(self.drawCesure) > 0:
            del self.drawCesure[-1]

    def removeLastPoint(self):
        ''' Remove All Point Drawer Objects '''
        if len(self.drawPtPos) > 0:
            del self.drawPtPos[-1]
            self.UpdateSurface()
            RemoveLastDrawPointOnMap()
        return

    def removeAllPoint(self):
        ''' Remove All Point Drawer Objects '''
        self.drawPtPos = []
        self.UpdateSurface()
        # Clear all Layer
        RemoveAllDrawPointOnMap()
        return

    def removeAllPolygon(self):
        ''' Remove All Polygon Drawer Objects '''
        self.drawPolygon = []
        self.UpdateSurface()
        # Clear all Layer
        RemoveAllDrawPolygonOnMap()

    def removeLastPolygon(self):
        ''' Remove Last Polygon Drawer Objects '''
        if len(self.drawPolygon) > 0:
            for pt in range(len(self.drawPolygon) - 1, -1, -1):
                del self.drawPolygon[pt]
                try:
                    if self.drawPolygon[pt - 1][0] is None:
                        break
                except Exception:
                    None
            self.UpdateSurface()
            # remove last index layer
            RemoveLastDrawPolygonOnMap()

    def currentMouseMoveEvent(self, event):
        self.var_currentMouseMoveEvent = event

    def keyPressEvent(self, event):
        ''' Exit fullscreen '''
        if event.key() == Qt.Key_Escape and self.isFullScreen():
            self.setFullScreen(False)
            event.accept()
        elif event.key() == Qt.Key_Enter and event.modifiers() & Qt.Key_Alt:
            self.setFullScreen(not self.isFullScreen())
            event.accept()
        else:
            super(VideoWidget, self).keyPressEvent(event)

    def mouseDoubleClickEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if GetImageHeight() == 0:
            return

        if (not vut.IsPointOnScreen(event.x(), event.y(), self.surface)):
            return

        if self.gt is not None and self._interaction.lineDrawer:
            self.drawLines.append([None, None, None])
            self.UpdateSurface()
            return
        if self.gt is not None and self._interaction.ruler:
            self.drawRuler.append([None, None, None])
            self.UpdateSurface()
            return
        if self.gt is not None and self._interaction.polygonDrawer:
            self.drawPolygon.append([None, None, None])

            AddDrawPolygonOnMap(self.poly_coordinates)

            # Empty RubberBand
            for _ in range(self.poly_RubberBand.numberOfVertices()):
                self.poly_RubberBand.removeLastPoint()
            # Empty List
            self.poly_coordinates = []
            self.UpdateSurface()
            return

        self.setFullScreen(not self.isFullScreen())
        event.accept()

    def videoSurface(self):
        ''' Return video Surface '''
        return self.surface

    def UpdateSurface(self):
        ''' Update Video Surface '''
        self.surface.widget.update()

    def sizeHint(self):
        ''' This property holds the recommended size for the widget '''
        return self.surface.surfaceFormat().sizeHint()

    def GetCurrentFrame(self):
        ''' Return current frame QImage '''
        return self.surface.image

    def SetInvertColor(self, value):
        ''' Set Invert color filter '''
        self._filterSatate.invertColorFilter = value

    def SetObjectTracking(self, value):
        ''' Set Object Tracking '''
        self._interaction.objectTracking = value

    def SetRuler(self, value):
        ''' Set Ruler '''
        self._interaction.ruler = value

    def SetHandDraw(self, value):
        ''' Set Hand Draw '''
        self._interaction.HandDraw = value

    def SetCensure(self, value):
        ''' Set Censure Video Parts '''
        self._interaction.censure = value

    def SetGray(self, value):
        ''' Set gray scale '''
        self._filterSatate.grayColorFilter = value

    def SetMirrorH(self, value):
        ''' Set Horizontal Mirror '''
        self._filterSatate.MirroredHFilter = value

    def SetEdgeDetection(self, value):
        ''' Set Canny Edge filter '''
        self._filterSatate.edgeDetectionFilter = value

    def SetAutoContrastFilter(self, value):
        ''' Set Automatic Contrast filter '''
        self._filterSatate.contrastFilter = value

    def SetMonoFilter(self, value):
        ''' Set mono filter '''
        self._filterSatate.monoFilter = value

    def RestoreFilters(self):
        ''' Remove and restore all video filters '''
        self._filterSatate.clear()

    def RestoreDrawer(self):
        ''' Remove and restore all Drawer Options '''
        self._interaction.clear()

    def paintEvent(self, event):
        ''' Paint Event '''
        self.gt = GetGCPGeoTransform()

        self.painter = QPainter(self)
        self.painter.setRenderHint(QPainter.HighQualityAntialiasing)

        if (self.surface.isActive()):
            videoRect = self.surface.videoRect()
            if not videoRect.contains(event.rect()):
                region = event.region()
                region.subtracted(QRegion(videoRect))
                brush = self.palette().window()
                for rect in region.rects():
                    self.painter.fillRect(rect, brush)

            try:
                self.painter = self.surface.paint(self.painter)
            except Exception:
                None
        else:
            self.painter.fillRect(event.rect(), self.palette().window())
        try:
            SetImageSize(self.surface.currentFrame.width(),
                         self.surface.currentFrame.height())
        except Exception:
            None

        # Draw On Video
        draw.drawOnVideo(self.drawPtPos, self.drawLines, self.drawPolygon,
                         self.drawRuler, self.drawCesure, self.painter,
                         self.surface, self.gt)

        # Magnifier Glass
        if self.zoomed and self._interaction.magnifier:
            draw.drawMagnifierOnVideo(self.width(), self.height(),
                                      self.maskPixmap, self.dragPos,
                                      self.zoomPixmap, self.surface,
                                      self.painter, self.offset)

        self.painter.end()
        return

    def resizeEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        QWidget.resizeEvent(self, event)
        self.zoomed = False
        self.surface.updateVideoRect()

    def mouseMoveEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if GetImageHeight() == 0:
            return

        # check if the point  is on picture (not in black borders)
        if (not vut.IsPointOnScreen(event.x(), event.y(), self.surface)):
            return

        if self._interaction.pointDrawer or self._interaction.polygonDrawer or self._interaction.lineDrawer or self._interaction.ruler:
            self.setCursor(QCursor(Qt.CrossCursor))

        # Cursor Coordinates
        if self.gt is not None:

            Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                event, self.surface)

            txt = "<span style='font-size:10pt; font-weight:bold;'>Lon :</span>"
            txt += "<span style='font-size:9pt; font-weight:normal;'>" + \
                ("%.3f" % Longitude) + "</span>"
            txt += "<span style='font-size:10pt; font-weight:bold;'> Lat :</span>"
            txt += "<span style='font-size:9pt; font-weight:normal;'>" + \
                ("%.3f" % Latitude) + "</span>"

            if hasElevationModel():
                txt += "<span style='font-size:10pt; font-weight:bold;'> Alt :</span>"
                txt += "<span style='font-size:9pt; font-weight:normal;'>" + \
                    ("%.0f" % Altitude) + "</span>"
            else:
                txt += "<span style='font-size:10pt; font-weight:bold;'> Alt :</span>"
                txt += "<span style='font-size:9pt; font-weight:normal;'>-</span>"

            self.parent.lb_cursor_coord.setText(txt)

        else:
            self.parent.lb_cursor_coord.setText(
                "<span style='font-size:10pt; font-weight:bold;'>Lon :</span>"
                + "<span style='font-size:9pt; font-weight:normal;'>-</span>" +
                "<span style='font-size:10pt; font-weight:bold;'> Lat :</span>"
                + "<span style='font-size:9pt; font-weight:normal;'>-</span>" +
                "<span style='font-size:10pt; font-weight:bold;'> Alt :</span>"
                + "<span style='font-size:9pt; font-weight:normal;'>-</span>")

        if not event.buttons():
            return

        if not self.Tracking_RubberBand.isHidden():
            self.Tracking_RubberBand.setGeometry(
                QRect(self.origin, event.pos()).normalized())

        if not self.Censure_RubberBand.isHidden():
            self.Censure_RubberBand.setGeometry(
                QRect(self.origin, event.pos()).normalized())

        if not self.zoomed:
            delta = event.pos() - self.pressPos
            if not self.snapped:
                self.pressPos = event.pos()
                self.pan(delta)
                self.tapTimer.stop()
                return
            else:
                threshold = 10
                self.snapped &= delta.x() < threshold
                self.snapped &= delta.y() < threshold
                self.snapped &= delta.x() > -threshold
                self.snapped &= delta.y() > -threshold

        else:
            self.dragPos = event.pos()
            self.surface.updateVideoRect()

    def pan(self, delta):
        """ Pan Action (Magnifier method)"""
        self.offset += delta
        self.surface.updateVideoRect()

    def timerEvent(self, _):
        """ Time Event (Magnifier method)"""
        if not self.zoomed:
            self.activateMagnifier()
        self.surface.updateVideoRect()

    def mousePressEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if GetImageHeight() == 0:
            return

        if event.button() == Qt.LeftButton:
            self.snapped = True
            self.pressPos = self.dragPos = event.pos()
            self.tapTimer.stop()
            self.tapTimer.start(100, self)

            if (not vut.IsPointOnScreen(event.x(), event.y(), self.surface)):
                self.UpdateSurface()
                return

            # point drawer
            if self.gt is not None and self._interaction.pointDrawer:
                Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                    event, self.surface)

                pointIndex = len(self.drawPtPos) + 1
                AddDrawPointOnMap(pointIndex, Longitude, Latitude, Altitude)

                self.drawPtPos.append([Longitude, Latitude, Altitude])

            # polygon drawer
            if self.gt is not None and self._interaction.polygonDrawer:
                Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                    event, self.surface)
                self.poly_RubberBand.addPoint(QgsPointXY(Longitude, Latitude))
                self.poly_coordinates.extend(QgsPointXY(Longitude, Latitude))
                self.drawPolygon.append([Longitude, Latitude, Altitude])

            # line drawer
            if self.gt is not None and self._interaction.lineDrawer:
                Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                    event, self.surface)

                self.drawLines.append([Longitude, Latitude, Altitude])

                AddDrawLineOnMap(self.drawLines)

            if self._interaction.objectTracking:
                self.origin = event.pos()
                self.Tracking_RubberBand.setGeometry(
                    QRect(self.origin, QSize()))
                self.Tracking_RubberBand.show()

            if self._interaction.censure:
                self.origin = event.pos()
                self.Censure_RubberBand.setGeometry(QRect(
                    self.origin, QSize()))
                self.Censure_RubberBand.show()

            # Ruler drawer
            if self.gt is not None and self._interaction.ruler:
                Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                    event, self.surface)
                self.drawRuler.append([Longitude, Latitude, Altitude])

        # if not called, the paint event is not triggered.
        self.UpdateSurface()

    def activateMagnifier(self):
        """ Activate Magnifier Glass """
        self.zoomed = True
        self.tapTimer.stop()
        self.surface.updateVideoRect()

    def SetMagnifier(self, value):
        """ Set Magnifier Glass """
        self._interaction.magnifier = value

    def SetPointDrawer(self, value):
        """ Set Point Drawer """
        self._interaction.pointDrawer = value

    def SetLineDrawer(self, value):
        """ Set Line Drawer """
        self._interaction.lineDrawer = value

    def SetPolygonDrawer(self, value):
        """ Set Polygon Drawer """
        self._interaction.polygonDrawer = value

    def mouseReleaseEvent(self, _):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if self._interaction.censure:
            geom = self.Tracking_RubberBand.geometry()
            self.Censure_RubberBand.hide()
            self.drawCesure.append([geom])

        if self._interaction.objectTracking:
            geom = self.Tracking_RubberBand.geometry()
            bbox = (geom.x(), geom.y(), geom.width(), geom.height())
            frame = convertQImageToMat(self.GetCurrentFrame())
            self.Tracking_RubberBand.hide()
            self.tracker = cv2.TrackerBoosting_create()
            self.tracker.clear()
            ok = self.tracker.init(frame, bbox)
            if ok:
                self._isinit = True
            else:
                self._isinit = False

    def leaveEvent(self, _):
        self.parent.lb_cursor_coord.setText("")
        self.setCursor(QCursor(Qt.ArrowCursor))
Beispiel #53
0
class App(QWidget):

    #几个传递值的信号
    ExposuretimeChangedValue = pyqtSignal(int)
    GainChangedValue = pyqtSignal(int)
    plotBlood = pyqtSignal(int, int, int, int)
    #绘图
    laser_computation = pyqtSignal(QImage)
    camera_height = 2748
    camera_width = 3664
    laserimage_height = 2748
    laserimage_width = 3664
    win = pg.GraphicsWindow(title="v distribution")
    win.resize(500, 300)
    win.setWindowTitle('blood perfusion')
    p = win.addPlot(title='blood perfusion')
    p.setLabel(axis='left', text='v')
    p.setLabel(axis='bottom', text='number')
    p.setRange(yRange=[0, 150], padding=0)

    curve = p.plot(pen='y')

    def __init__(self):
        super(App, self).__init__()
        self.ui = Ui_widget()
        self.ui.setupUi(self)
        self.title = 'PyQt5 Video'

        self.initUI()
        self.origin = QPoint()
        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)

        self.originX = 0
        self.originY = 0
        self.endX = 0
        self.endY = 0

        self.plotFlag = 0
        self.plotdata = np.empty(0)

        self.plotdata_v1 = np.empty(0)
        self.plotdata_v1_flag = 0

    def initUI(self):
        #相机线程
        th = camera_thread.Thread(self)
        #计算线程
        computation_th = computation_thread.Thread(self)
        self.laser_computation.connect(
            lambda p: computation_th.receive_image(p))  # 测试用
        computation_th.laser_computation_finish.connect(
            lambda p, x, y: self.setLaserImage(p, x, y))
        th.changePixmap.connect(
            lambda p: self.setPixMap(p))  # 将changePixmap 函数与setPixMap 函数 联系起来
        th.laser_posess.connect(lambda p: self.get_under_posess_image(p))  #
        #显示初始值
        self.ui.lineEdit_gain.setText(str(th.Gain))
        self.ui.lineEdit_exposuretime.setText(str(th.Exposuretime))
        #发送图片
        #截取图片
        self.ui.label_CaptureFrame.clicked.connect(th.capturePicture)
        #滑动条修改曝光时间
        self.ui.horizontalSlider_SetExposure.setTickPosition(
            QSlider.TicksBelow)
        self.ui.horizontalSlider_SetExposure.valueChanged.connect(
            self.on_changed_ExposureTime)
        self.ui.horizontalSlider_SetExposure.valueChanged.connect(
            th.CameraSettingChanged)
        self.ExposuretimeChangedValue.connect(
            lambda value: th.CameraSettingExposuretime(value))
        #滑动条修改帧率
        self.ui.horizontalSlider_Setfps.valueChanged.connect(
            th.CameraSettingChanged)
        #滑动条修改增益
        self.ui.horizontalSlider_SetGain.setTickPosition(QSlider.TicksBelow)
        self.ui.horizontalSlider_SetGain.valueChanged.connect(
            th.CameraSettingChanged)
        self.ui.horizontalSlider_SetGain.valueChanged.connect(
            self.on_changed_Gain)
        self.GainChangedValue.connect(
            lambda value: th.CameraSettingExposuretime(value))
        self.ui.label_OpenCamera.setMouseTracking(True)
        #plot按钮功能
        self.ui.label_PlotBloodFlow.clicked.connect(self.PlotBloodFlow)

        #不同流速血流计算功能
        self.ui.pushButton_v1.setCheckable(True)
        self.ui.pushButton_v1.toggled.connect(self.changeV1Flag)

        #还差保持路径、截取间隔、还有截取时间
        #开启线程
        #画图信号
        self.plotBlood.connect(
            lambda ox, oy, ex, ey: computation_th.getPlotEdge(ox, oy, ex, ey))
        th.start()
        computation_th.start()
        print("init gui finish")

    #修改相机曝光时间
    def on_changed_ExposureTime(self, value):

        Exposuretime = self.ui.horizontalSlider_SetExposure.value()
        self.ui.lineEdit_exposuretime.setText(str(Exposuretime))
        print(Exposuretime)
        # self.plotdata = np.append(self.plotdata, Exposuretime)
        # print(self.plotdata)
        # self.curve.setData(self.plotdata)
        self.ExposuretimeChangedValue.emit(Exposuretime)

    #修改相机增益
    def on_changed_Gain(self, value):
        Gain = self.ui.horizontalSlider_SetGain.value()
        self.ui.lineEdit_gain.setText(str(Gain))
        print(Gain)
        self.GainChangedValue.emit(Gain)

    #显示拍摄图片
    def setPixMap(self, p):
        p = QPixmap.fromImage(p)
        p = p.scaled(640, 480, Qt.KeepAspectRatio)
        self.ui.label_VideoDisplay.setPixmap(p)

    #显示激光散斑图像
    def get_under_posess_image(self, p):
        print("get under posess image")
        under_posess_image = p
        print(type(p))
        self.laser_computation.emit(under_posess_image)
        print("send image to thread to possess")
# 鼠标响应事件,用来画圈求均值

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.origin = QPoint(event.pos())
            self.originX = event.x()
            self.originY = event.y()
            print(self.originX, self.originY)
            self.rubberBand.setGeometry(QRect(self.origin, QSize()))
            self.rubberBand.show()

    def mouseMoveEvent(self, event):
        if not self.origin.isNull():
            self.rubberBand.setGeometry(
                QRect(self.origin, event.pos()).normalized())

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.endX = event.x()
            self.endY = event.y()
            print(self.endX, self.endY)
            # self.rubberBand.hide()
            #画完之后,获取区域,开始画图
            print("change the plotflag")
            labelOrignX = self.originX - self.ui.label_laserdisplay.x()
            print(labelOrignX)
            labelOrignY = self.originY - self.ui.label_laserdisplay.y()
            labelEndX = self.endX - self.ui.label_laserdisplay.x()
            labelEndY = self.endY - self.ui.label_laserdisplay.y()
            print(labelOrignX, labelOrignY, labelEndX, labelEndY)
            self.plotBlood.emit(labelOrignX, labelOrignY, labelEndX, labelEndY)
            self.plotFlag = 1
            print("change the plotflag")

    # def PlotBloodFlow(self):
    #     labelOrignX = self.originX - self.ui.label_laserdisplay.x()
    #     labelOrignY = self.originY - self.ui.label_laserdisplay.y()
    #     labelEndX = self.endX - self.ui.label_laserdisplay.x()
    #     labelEndY = self.endY - self.ui.label_laserdisplay.y()
    def PlotBloodFlow(self):
        self.plotFlag = 0
        self.plotdata = np.empty(0)

    def setLaserImage(self, p, x, y):
        #变回mat格式
        print('start set laser image')
        setLaserImage_start = datetime.datetime.now()

        yVals = y / (640 * 480)
        p = QPixmap.fromImage(p)
        p = p.scaled(640, 480, Qt.KeepAspectRatio)
        # # p = self.cmap2pixmap(laser,'Reds', 50)
        # # # 再转化为opencv里的图片格式,求完激光散斑再转Qimage显示
        plot_start = datetime.datetime.now()
        self.ui.label_laserdisplay.setPixmap(p)

        plot_end = datetime.datetime.now()
        print("plot cost time:", plot_end - plot_start)
        if (self.plotFlag == 1):
            if (self.plotdata_v1_flag):
                self.plotdata_v1 = np.append(self.plotdata_v1, y)
            # self.plotdata = np.append(self.plotdata, y)
            self.curve.setData(y)
        # self.ui.graphicsView.plotItem(y)
        # plotWidget = pg.plot(title="Three plot curves")
        # plotWidget.plot(x, yVals)
        setLaserImage_end = datetime.datetime.now()
        print('laser image display successfully and time = ',
              setLaserImage_end - setLaserImage_start)

    #修改截取时间
    def convertQImageToMat(self, p):
        '''  Converts a QImage into an opencv MAT format  '''
        convert_start = datetime.datetime.now()
        p = p.convertToFormat(3)
        ptr = p.bits()
        ptr.setsize(p.byteCount())
        arr = np.array(ptr).reshape(p.height(), p.width(), 1)
        convert_end = datetime.datetime.now()
        print("convertQImageToMat Finished and time =",
              convert_end - convert_start)
        return arr


##激光散斑处理

    def laser_posess(self, imarray, wsize):
        posess_start = datetime.datetime.now()
        # imarray = cv2.cvtColor(imarray, cv2.COLOR_BGR2GRAY)
        # print(imarray.shape)
        print('start posess')
        imarray1 = imarray
        imarray1 = imarray.reshape(self.laserimage_height,
                                   self.laserimage_width)
        imarray1 = np.array(imarray1).astype(float)
        # print(imarray1.shape)
        # print(imarray1.dtype)  # 图像类型
        #JISUAN
        immean = ndimage.uniform_filter(imarray1, size=wsize)
        im2mean = ndimage.uniform_filter(np.square(imarray1), size=wsize)
        imcontrast = np.sqrt(
            abs(im2mean - np.square(immean)) / np.square(immean))
        temp = 2 * np.square(imcontrast)
        result = np.real((1 + np.sqrt(1 - temp)) / temp)
        T1 = 0.0015
        v = 1000 * ((780 * 1e-9) / (2 * np.pi * T1)) * result
        print('speckle computation finished')
        imcontrast_show = v  #把(0,1)to (0,255)
        # print(np.max(imcontrast_show))
        # print(np.min(imcontrast_show))
        # print(imcontrast_show.shape)
        # print(imcontrast_show.dtype)  # 图像类型
        imcontrast_show = np.array(imcontrast_show).astype(int)
        imcontrast_show = imcontrast_show.reshape(self.laserimage_height,
                                                  self.laserimage_width, 1)
        # imcontrast_show = np.transpose(imcontrast_show, (1, 0, 2)).copy()

        posess_end = datetime.datetime.now()
        print('laser_posess finished and time=', posess_end - posess_start)

        return imcontrast_show

    def changeV1Flag(self, checked):
        if checked:
            self.plotdata_v1_flag = 1
            self.plotdata_v1 = np.arange(5)
        else:
            print(self.plotdata_v1)
            file = open('log.txt', 'a')
            for fp in self.plotdata_v1:
                file.write(str(fp))
                file.write(' ')
            file.write(
                '\n-------------------------------------我是分割线-----------------------------------------\n'
            )
            file.close()
            self.plotdata_v1_flag = 0
            self.plotdata_v1 = np.empty(0)
Beispiel #54
0
class MyGraphicsView(CanvasBase):
    """
    This is the used Canvas to print the graphical interface of dxf2gcode.
    All GUI things should be performed in the View and plotting functions in
    the scene
    """
    def __init__(self, parent=None):
        """
        Initialisation of the View Object. This is called by the gui created
        with the QTDesigner.
        @param parent: Main is passed as a pointer for reference.
        """
        super(MyGraphicsView, self).__init__(parent)
        self.currentItem = None

        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QGraphicsView.AnchorViewCenter)

        # self.setDragMode(QGraphicsView.RubberBandDrag )
        self.setDragMode(QGraphicsView.NoDrag)

        self.parent = parent
        self.mppos = None

        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.prvRectRubberBand = QtCore.QRect()

    def tr(self, string_to_translate):
        """
        Translate a string using the QCoreApplication translation framework
        @param string_to_translate: a unicode string
        @return: the translated unicode string if it was possible to translate
        """
        return text_type(
            QtCore.QCoreApplication.translate('MyGraphicsView',
                                              string_to_translate))

    def contextMenuEvent(self, event):
        """
        Create the contextmenu.
        @purpose: Links the new Class of ContextMenu to Graphicsview.
        """
        position = self.mapToGlobal(event.pos())
        GVPos = self.mapToScene(event.pos())
        real_pos = Point(GVPos.x(), -GVPos.y())

        menu = MyDropDownMenu(self.scene(), position, real_pos)

    def wheelEvent(self, event):
        """
        With Mouse Wheel the object is scaled
        @purpose: Scale by mouse wheel
        @param event: Event Parameters passed to function
        """
        if c.PYQT5notPYQT4:
            delta = event.angleDelta().y()
        else:
            delta = event.delta()
        scale = (1000 + delta) / 1000.0
        self.scale(scale, scale)

    def mousePressEvent(self, event):
        """
        Right Mouse click shall have no function, Therefore pass only left
        click event
        @purpose: Change inherited mousePressEvent
        @param event: Event Parameters passed to function
        """

        if self.dragMode() == 1:
            super(MyGraphicsView, self).mousePressEvent(event)
        elif event.button() == QtCore.Qt.LeftButton:
            self.mppos = event.pos()
        else:
            pass

    def mouseReleaseEvent(self, event):
        """
        Right Mouse click shall have no function, Therefore pass only left
        click event
        @purpose: Change inherited mousePressEvent
        @param event: Event Parameters passed to function
        """
        delta = 2

        if self.dragMode() == 1:
            # if (event.key() == QtCore.Qt.Key_Shift):
            # self.setDragMode(QGraphicsView.NoDrag)
            super(MyGraphicsView, self).mouseReleaseEvent(event)

        # Selection only enabled for left Button
        elif event.button() == QtCore.Qt.LeftButton:
            self.currentItems = []
            scene = self.scene()
            if not self.isMultiSelect:
                for item in scene.selectedItems():
                    item.setSelected(False, False)
            # If the mouse button is pressed without movement of rubberband
            if self.rubberBand.isHidden():
                rect = QtCore.QRect(event.pos().x() - delta,
                                    event.pos().y() - delta, 2 * delta,
                                    2 * delta)
                # logger.debug(rect)

                point = self.mapToScene(event.pos())
                min_distance = float(0x7fffffff)
                for item in self.items(rect):
                    itemDistance = item.contains_point(point)
                    if itemDistance < min_distance:
                        min_distance = itemDistance
                        self.currentItems = item
                if self.currentItems:
                    if self.currentItems.isSelected():
                        self.currentItems.setSelected(False, False)
                    else:
                        self.currentItems.setSelected(True, False)
            else:
                rect = self.rubberBand.geometry()
                self.currentItems = self.items(rect)
                self.rubberBand.hide()
                # logger.debug("Rubberband Selection")

                # All items in the selection
                # self.currentItems = self.items(rect)
                # print self.currentItems
                # logger.debug(rect)

                for item in self.currentItems:
                    if item.isSelected():
                        item.setSelected(False, False)
                    else:
                        # print (item.flags())
                        item.setSelected(True, False)

        else:
            pass

        self.mppos = None
        # super(MyGraphicsView, self).mouseReleaseEvent(event)

    def mouseMoveEvent(self, event):
        """
        MouseMoveEvent of the Graphiscview. May also be used for the Statusbar.
        @purpose: Get the MouseMoveEvent and use it for the Rubberband Selection
        @param event: Event Parameters passed to function
        """
        if self.mppos is not None:
            Point = event.pos() - self.mppos
            if Point.manhattanLength() > 3:
                # print 'the mouse has moved more than 3 pixels since the oldPosition'
                # print "Mouse Pointer is currently hovering at: ", event.pos()
                rect = QtCore.QRect(self.mppos, event.pos())
                '''
                The following is needed because of PyQt5 doesn't like to switch from sign
                 it will keep displaying last rectangle, i.e. you can end up will multiple rectangles
                '''
                if self.prvRectRubberBand.width() > 0 and not rect.width() > 0 or rect.width() == 0 or\
                   self.prvRectRubberBand.height() > 0 and not rect.height() > 0 or rect.height() == 0:
                    self.rubberBand.hide()
                self.rubberBand.setGeometry(rect.normalized())
                self.rubberBand.show()
                self.prvRectRubberBand = rect

        scpoint = self.mapToScene(event.pos())

        # self.setStatusTip('X: %3.1f; Y: %3.1f' % (scpoint.x(), -scpoint.y()))
        # works not as supposed to
        self.setToolTip('X: %3.1f; Y: %3.1f' % (scpoint.x(), -scpoint.y()))

        super(MyGraphicsView, self).mouseMoveEvent(event)

    def autoscale(self):
        """
        Automatically zooms to the full extend of the current GraphicsScene
        """
        scene = self.scene()
        width = scene.bottomRight.x - scene.topLeft.x
        height = scene.topLeft.y - scene.bottomRight.y
        scext = QtCore.QRectF(scene.topLeft.x, -scene.topLeft.y, width * 1.05,
                              height * 1.05)
        self.fitInView(scext, QtCore.Qt.KeepAspectRatio)
        logger.debug(self.tr("Autoscaling to extend: %s") % scext)

    def setShowPathDirections(self, flag):
        """
        This function is called by the Main Window from the Menubar.
        @param flag: This flag is true if all Path Direction shall be shown
        """
        scene = self.scene()
        for shape in scene.shapes:
            shape.starrow.setallwaysshow(flag)
            shape.enarrow.setallwaysshow(flag)
            shape.stmove.setallwaysshow(flag)

    def resetAll(self):
        """
        Deletes the existing GraphicsScene.
        """
        scene = self.scene()
        del scene
Beispiel #55
0
class PieView(QAbstractItemView):
    def __init__(self, parent=None):
        super(PieView, self).__init__(parent)

        self.horizontalScrollBar().setRange(0, 0)
        self.verticalScrollBar().setRange(0, 0)

        self.margin = 8
        self.totalSize = 300
        self.pieSize = self.totalSize - 2*self.margin
        self.validItems = 0
        self.totalValue = 0.0
        self.origin = QPoint()
        self.rubberBand = None

    def dataChanged(self, topLeft, bottomRight, roles):
        super(PieView, self).dataChanged(topLeft, bottomRight, roles)

        self.validItems = 0
        self.totalValue = 0.0

        for row in range(self.model().rowCount(self.rootIndex())):

            index = self.model().index(row, 1, self.rootIndex())
            value = self.model().data(index)

            if value is not None and value > 0.0:
                self.totalValue += value
                self.validItems += 1

        self.viewport().update()

    def edit(self, index, trigger, event):
        if index.column() == 0:
            return super(PieView, self).edit(index, trigger, event)
        else:
            return False

    def indexAt(self, point):
        if self.validItems == 0:
            return QModelIndex()

        # Transform the view coordinates into contents widget coordinates.
        wx = point.x() + self.horizontalScrollBar().value()
        wy = point.y() + self.verticalScrollBar().value()

        if wx < self.totalSize:
            cx = wx - self.totalSize/2
            cy = self.totalSize/2 - wy; # positive cy for items above the center

            # Determine the distance from the center point of the pie chart.
            d = (cx**2 + cy**2)**0.5

            if d == 0 or d > self.pieSize/2:
                return QModelIndex()

            # Determine the angle of the point.
            angle = (180 / math.pi) * math.acos(cx/d)
            if cy < 0:
                angle = 360 - angle

            # Find the relevant slice of the pie.
            startAngle = 0.0

            for row in range(self.model().rowCount(self.rootIndex())):

                index = self.model().index(row, 1, self.rootIndex())
                value = self.model().data(index)

                if value > 0.0:
                    sliceAngle = 360*value/self.totalValue

                    if angle >= startAngle and angle < (startAngle + sliceAngle):
                        return self.model().index(row, 1, self.rootIndex())

                    startAngle += sliceAngle

        else:
            itemHeight = QFontMetrics(self.viewOptions().font).height()
            listItem = int((wy - self.margin) / itemHeight)
            validRow = 0

            for row in range(self.model().rowCount(self.rootIndex())):

                index = self.model().index(row, 1, self.rootIndex())
                if self.model().data(index) > 0.0:

                    if listItem == validRow:
                        return self.model().index(row, 0, self.rootIndex())

                    # Update the list index that corresponds to the next valid
                    # row.
                    validRow += 1

        return QModelIndex()

    def isIndexHidden(self, index):
        return False

    def itemRect(self, index):
        if not index.isValid():
            return QRect()

        # Check whether the index's row is in the list of rows represented
        # by slices.

        if index.column() != 1:
            valueIndex = self.model().index(index.row(), 1, self.rootIndex())
        else:
            valueIndex = index

        if self.model().data(valueIndex) > 0.0:

            listItem = 0
            for row in range(index.row()-1, -1, -1):
                if self.model().data(self.model().index(row, 1, self.rootIndex())) > 0.0:
                    listItem += 1

            if index.column() == 0:

                itemHeight = QFontMetrics(self.viewOptions().font).height()
                return QRect(self.totalSize,
                             int(self.margin + listItem*itemHeight),
                             self.totalSize - self.margin, int(itemHeight))
            elif index.column() == 1:
                return self.viewport().rect()

        return QRect()

    def itemRegion(self, index):
        if not index.isValid():
            return QRegion()

        if index.column() != 1:
            return QRegion(self.itemRect(index))

        if self.model().data(index) <= 0.0:
            return QRegion()

        startAngle = 0.0
        for row in range(self.model().rowCount(self.rootIndex())):

            sliceIndex = self.model().index(row, 1, self.rootIndex())
            value = self.model().data(sliceIndex)

            if value > 0.0:
                angle = 360*value/self.totalValue

                if sliceIndex == index:
                    slicePath = QPainterPath()
                    slicePath.moveTo(self.totalSize/2, self.totalSize/2)
                    slicePath.arcTo(self.margin, self.margin,
                            self.margin+self.pieSize, self.margin+self.pieSize,
                            startAngle, angle)
                    slicePath.closeSubpath()

                    return QRegion(slicePath.toFillPolygon().toPolygon())

                startAngle += angle

        return QRegion()

    def horizontalOffset(self):
        return self.horizontalScrollBar().value()

    def mousePressEvent(self, event):
        super(PieView, self).mousePressEvent(event)

        self.origin = event.pos()
        if not self.rubberBand:
            self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.rubberBand.setGeometry(QRect(self.origin, QSize()))
        self.rubberBand.show()

    def mouseMoveEvent(self, event):
        if self.rubberBand:
            self.rubberBand.setGeometry(QRect(self.origin, event.pos()).normalized())

        super(PieView, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        super(PieView, self).mouseReleaseEvent(event)

        if self.rubberBand:
            self.rubberBand.hide()

        self.viewport().update()

    def moveCursor(self, cursorAction, modifiers):
        current = self.currentIndex()

        if cursorAction in (QAbstractItemView.MoveLeft, QAbstractItemView.MoveUp):

            if current.row() > 0:
                current = self.model().index(current.row() - 1,
                        current.column(), self.rootIndex())
            else:
                current = self.model().index(0, current.column(),
                        self.rootIndex())

        elif cursorAction in (QAbstractItemView.MoveRight, QAbstractItemView.MoveDown):

            if current.row() < self.rows(current) - 1:
                current = self.model().index(current.row() + 1,
                        current.column(), self.rootIndex())
            else:
                current = self.model().index(self.rows(current) - 1,
                        current.column(), self.rootIndex())

        self.viewport().update()
        return current

    def paintEvent(self, event):
        selections = self.selectionModel()
        option = self.viewOptions()
        state = option.state

        background = option.palette.base()
        foreground = QPen(option.palette.color(QPalette.WindowText))
        textPen = QPen(option.palette.color(QPalette.Text))
        highlightedPen = QPen(option.palette.color(QPalette.HighlightedText))

        painter = QPainter(self.viewport())
        painter.setRenderHint(QPainter.Antialiasing)

        painter.fillRect(event.rect(), background)
        painter.setPen(foreground)

        # Viewport rectangles
        pieRect = QRect(self.margin, self.margin, self.pieSize,
                self.pieSize)
        keyPoint = QPoint(self.totalSize - self.horizontalScrollBar().value(),
                self.margin - self.verticalScrollBar().value())

        if self.validItems > 0:
            painter.save()
            painter.translate(pieRect.x() - self.horizontalScrollBar().value(),
                    pieRect.y() - self.verticalScrollBar().value())
            painter.drawEllipse(0, 0, self.pieSize, self.pieSize)
            startAngle = 0.0

            for row in range(self.model().rowCount(self.rootIndex())):

                index = self.model().index(row, 1, self.rootIndex())
                value = self.model().data(index)

                if value > 0.0:
                    angle = 360*value/self.totalValue

                    colorIndex = self.model().index(row, 0, self.rootIndex())
                    color = self.model().data(colorIndex, Qt.DecorationRole)

                    if self.currentIndex() == index:
                        painter.setBrush(QBrush(color, Qt.Dense4Pattern))
                    elif selections.isSelected(index):
                        painter.setBrush(QBrush(color, Qt.Dense3Pattern))
                    else:
                        painter.setBrush(QBrush(color))

                    painter.drawPie(0, 0, self.pieSize, self.pieSize,
                            int(startAngle*16), int(angle*16))

                    startAngle += angle

            painter.restore()

            keyNumber = 0

            for row in range(self.model().rowCount(self.rootIndex())):
                index = self.model().index(row, 1, self.rootIndex())
                value = self.model().data(index)

                if value > 0.0:
                    labelIndex = self.model().index(row, 0, self.rootIndex())

                    option = self.viewOptions()
                    option.rect = self.visualRect(labelIndex)
                    if selections.isSelected(labelIndex):
                        option.state |= QStyle.State_Selected
                    if self.currentIndex() == labelIndex:
                        option.state |= QStyle.State_HasFocus
                    self.itemDelegate().paint(painter, option, labelIndex)

                    keyNumber += 1

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

    def rows(self, index):
        return self.model().rowCount(self.model().parent(index))

    def rowsInserted(self, parent, start, end):
        for row in range(start, end + 1):
            index = self.model().index(row, 1, self.rootIndex())
            value = self.model().data(index)

            if value is not None and value > 0.0:
                self.totalValue += value
                self.validItems += 1

        super(PieView, self).rowsInserted(parent, start, end)

    def rowsAboutToBeRemoved(self, parent, start, end):
        for row in range(start, end + 1):
            index = self.model().index(row, 1, self.rootIndex())
            value = self.model().data(index)

            if value is not None and value > 0.0:
                self.totalValue -= value
                self.validItems -= 1

        super(PieView, self).rowsAboutToBeRemoved(parent, start, end)

    def scrollContentsBy(self, dx, dy):
        self.viewport().scroll(dx, dy)

    def scrollTo(self, index, ScrollHint):
        area = self.viewport().rect()
        rect = self.visualRect(index)

        if rect.left() < area.left():
            self.horizontalScrollBar().setValue(
                self.horizontalScrollBar().value() + rect.left() - area.left())
        elif rect.right() > area.right():
            self.horizontalScrollBar().setValue(
                self.horizontalScrollBar().value() + min(
                    rect.right() - area.right(), rect.left() - area.left()))

        if rect.top() < area.top():
            self.verticalScrollBar().setValue(
                self.verticalScrollBar().value() + rect.top() - area.top())
        elif rect.bottom() > area.bottom():
            self.verticalScrollBar().setValue(
                self.verticalScrollBar().value() + min(
                    rect.bottom() - area.bottom(), rect.top() - area.top()))

    def setSelection(self, rect, command):
        # Use content widget coordinates because we will use the itemRegion()
        # function to check for intersections.

        contentsRect = rect.translated(self.horizontalScrollBar().value(),
                self.verticalScrollBar().value()).normalized()

        rows = self.model().rowCount(self.rootIndex())
        columns = self.model().columnCount(self.rootIndex())
        indexes = []

        for row in range(rows):
            for column in range(columns):
                index = self.model().index(row, column, self.rootIndex())
                region = self.itemRegion(index)
                if not region.intersect(QRegion(contentsRect)).isEmpty():
                    indexes.append(index)

        if len(indexes) > 0:
            firstRow = indexes[0].row()
            lastRow = indexes[0].row()
            firstColumn = indexes[0].column()
            lastColumn = indexes[0].column()

            for i in range(1, len(indexes)):
                firstRow = min(firstRow, indexes[i].row())
                lastRow = max(lastRow, indexes[i].row())
                firstColumn = min(firstColumn, indexes[i].column())
                lastColumn = max(lastColumn, indexes[i].column())

            selection = QItemSelection(
                self.model().index(firstRow, firstColumn, self.rootIndex()),
                self.model().index(lastRow, lastColumn, self.rootIndex()))
            self.selectionModel().select(selection, command)
        else:
            noIndex = QModelIndex()
            selection = QItemSelection(noIndex, noIndex)
            self.selectionModel().select(selection, command)

        self.update()

    def updateGeometries(self):
        self.horizontalScrollBar().setPageStep(self.viewport().width())
        self.horizontalScrollBar().setRange(0, max(0, 2*self.totalSize - self.viewport().width()))
        self.verticalScrollBar().setPageStep(self.viewport().height())
        self.verticalScrollBar().setRange(0, max(0, self.totalSize - self.viewport().height()))

    def verticalOffset(self):
        return self.verticalScrollBar().value()

    def visualRect(self, index):
        rect = self.itemRect(index)
        if rect.isValid():
            return QRect(rect.left() - self.horizontalScrollBar().value(),
                         rect.top() - self.verticalScrollBar().value(),
                         rect.width(), rect.height())
        else:
            return rect

    def visualRegionForSelection(self, selection):
        region = QRegion()

        for span in selection:
            for row in range(span.top(), span.bottom() + 1):
                for col in range(span.left(), span.right() + 1):
                    index = self.model().index(row, col, self.rootIndex())
                    region += self.visualRect(index)

        return region
class QImageEdit(QLabel):
    def __init__(self, parentQWidget=None):
        super(QImageEdit, self).__init__(parentQWidget)
        self.rubberBand = None
        self.move_rubberBand = False
        self.rubberBand_offset = None
        self.originPoint = None

    def setImage(self, image: QPixmap):
        self.setPixmap(image)

    def getImage(self) -> QPixmap:
        if self.rubberBand is not None:
            currentRect = self.rubberBand.geometry()
            return self.pixmap().copy(currentRect)
        else:
            return self.pixmap()

    def clear(self):
        super(QImageEdit, self).clear()
        if self.rubberBand is not None:
            self.rubberBand.deleteLater()
        self.rubberBand = None
        self.move_rubberBand = False
        self.rubberBand_offset = None
        self.originPoint = None

    def mousePressEvent(self, event):
        self.originPoint = event.pos()

        if self.rubberBand is None:
            self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
            self.rubberBand.setGeometry(QRect(self.originPoint, QSize()))
            self.rubberBand.show()
        else:
            if self.rubberBand.geometry().contains(self.originPoint):
                self.rubberBand_offset = \
                    self.originPoint - self.rubberBand.pos()
                self.move_rubberBand = True
            else:
                self.rubberBand.hide()
                self.rubberBand.deleteLater()
                self.rubberBand = None
                self.move_rubberBand = False
                self.rubberBand_offset = None
                self.mousePressEvent(event)

    def mouseMoveEvent(self, event):
        newPoint = event.pos()
        if self.move_rubberBand:
            self.rubberBand.move(newPoint - self.rubberBand_offset)
        else:
            self.rubberBand.setGeometry(
                QRect(self.originPoint, newPoint).normalized())

    def mouseReleaseEvent(self, event):
        self.move_rubberBand = False
Beispiel #57
0
	def showBand(self, *geom):
		if not self.__band:
			self.__band = QRubberBand(QRubberBand.Rectangle, parent=self)
		self.__band.setGeometry(*geom)
		self.__band.show()
Beispiel #58
0
class MiniMapGraphicsView(QGraphicsView):

    def __init__(self, parent):
        super().__init__(parent)
        
        self._drag_start_pos = None
        
        self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.setFixedSize(200, 200)
        self.viewport().setFixedSize(self.contentsRect().size())
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setInteractive(False)
        self.setFocusProxy(parent)
        
        self.band = QRubberBand(QRubberBand.Rectangle, self)
        self.band.hide()
        
    def centerOn(self, pos):
        if self.band.isVisible():
            self.parent().centerOn(self.mapToScene(pos))
            rect = self.band.geometry()
            rect.moveCenter(pos)
            self.band.setGeometry(rect)
        
    def mousePressEvent(self, event):
        if self.band.isVisible() and event.button() == Qt.LeftButton:
            rect = self.band.geometry()
            if event.pos() in rect:
                self._drag_start_pos = event.pos()
            else:
                self.centerOn(event.pos())
    
    def mouseMoveEvent(self, event):
        if self.band.isVisible() and event.buttons() == Qt.MouseButtons(Qt.LeftButton) and self._drag_start_pos is not None:
            self.centerOn(event.pos())
    
    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton and self.band.isVisible():
            self.viewport().unsetCursor()
            self._drag_start_pos = None

    def adjustRubberband(self):
        rect = self.parent().mapToScene(self.parent().rect()).boundingRect()
        if not rect.contains(self.scene().sceneRect()):
            rect = self.mapFromScene(rect).boundingRect()
            self.band.setGeometry(rect)
            self.band.show()
        else:
            self.band.hide()
        
    def zoomToFit(self):
        self.fitInView(self.scene().sceneRect().adjusted(-20, -20, 20, 20), Qt.KeepAspectRatio)
class ImageHolder(QWidget):

    foregroundState = list()
    foreground = None
    mousePressPoint = None
    cropMode = False
    def __init__(self, image):
        super(ImageHolder, self).__init__()
        self.image = image
        self.setMinimumSize(self.image.size())
        self.resize(self.image.size())
        self.foreground = QImage(self.image.size(),QImage.Format_ARGB32_Premultiplied)
        undo = QShortcut(QKeySequence("Ctrl+z"), self)
        undo.activated.connect(self.undo)

        crop = QShortcut(QKeySequence("c"), self)
        crop.activated.connect(self.toggleCropMode)


    def applyState(self):
        print("apply state")
        if self.cropMode:
            rect = self.currentQRubberBand.geometry()
            self.image = self.image.copy(rect)
            self.setMinimumSize(self.image.size())
            self.resize(self.image.size())
            QApplication.restoreOverrideCursor()
            self.toggleCropMode()
            self.currentQRubberBand.hide()
            self.repaint()

    def cancelState(self):
        if cropMode:
            self.currentQRubberBand.hide()

    def toggleCropMode(self):
        self.cropMode = not self.cropMode
        if self.cropMode:
            QApplication.setOverrideCursor(QCursor(Qt.CrossCursor))
        else:
            QApplication.restoreOverrideCursor()

    def mousePressEvent(self, event):
        print("ImageHolder: " + str(event.pos()))
        self.mousePressPoint = event.pos();
        if self.cropMode:
            if hasattr(self, "currentQRubberBand"):
                self.currentQRubberBand.hide()
            self.currentQRubberBand = QRubberBand(QRubberBand.Rectangle, self)
            self.currentQRubberBand.setGeometry(QRect(self.mousePressPoint, QSize()))
            self.currentQRubberBand.show()

    def mouseMoveEvent(self, event):
        print("mouseMove: " + str(event.pos()))
        if self.cropMode:
            self.currentQRubberBand.setGeometry(QRect(self.mousePressPoint, event.pos()).normalized())

    def undo(self):
        if self.cropMode:
            self.currentQRubberBand.hide()
        elif len(self.foregroundState) > 0:
            self.foreground = self.foregroundState.pop()
            self.repaint()

    def mouseReleaseEvent(self, event):
        if not self.cropMode:
            self.foregroundState.append(QImage(self.foreground))
            self.painter.begin(self.foreground)
            self.painter.setPen(QPen(QBrush(QColor(255,241,18,100)), 15, Qt.SolidLine, Qt.RoundCap))
            self.painter.drawLine(QLine(self.mousePressPoint.x(),self.mousePressPoint.y(),
             event.pos().x(), event.pos().y()))
            self.painter.end()
            self.repaint()

    def saveChanges(self):
        newImage = QImage(self.image.size(), QImage.Format_ARGB32_Premultiplied)
        painter = QPainter(newImage)
        painter.drawImage(0,0, self.image)
        painter.drawImage(0,0, self.foreground)
        painter.end()
        return newImage

    def paintEvent(self, event):
        self.painter = QPainter(self)
        self.painter.setPen(QPen(QBrush(QColor(255,241,18,100)), 15, Qt.SolidLine, Qt.RoundCap))
        self.painter.drawImage(0,0, self.image)
        self.painter.drawImage(0,0, self.foreground)
        self.painter.end()
Beispiel #60
0
class Viewer(QGraphicsView):
    def __init__(self):
        QGraphicsView.__init__(self)

        self.setGeometry(QRect(100, 100, 800, 600))
        self.setWindowTitle("PIHDL Graphics Window")

        # 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.gridlinesx = [self.scene.addLine(-10,-10,10,10, self.gridpen) for n in range(100)]
        #        self.gridlinesy = [self.scene.addLine(-10,-10,10,10, self.gridpen) for n in range(100)]

        self.initialize()

    def itemsBoundingRect_nogrid(self):
        self.remove_grid()
        r = self.scene.itemsBoundingRect()
        self.create_grid()
        return r

    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)

        sr = self.itemsBoundingRect_nogrid()
        ymax = sr.top()
        xmin = sr.left()
        width = sr.width()
        height = sr.height()
        self.scene.setSceneRect(
            QRectF(xmin - 2 * width, ymax - 2 * height, width * 5, height * 5))

    def reset_view(self):
        self.fitInView(self.itemsBoundingRect_nogrid(), Qt.KeepAspectRatio)
        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]

#        x,y = port.midpoint[0], port.midpoint[1]
#        x,y  = x - qtext.boundingRect().width()/2, y - qtext.boundingRect().height()/2

    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.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
        #        print('\n xmin = %s, xmax = %s, ymin = %s, ymax = %s' % (xmin, xmax, ymin, ymax))
        #        print('Starting at x = %s' % x)
        #        print('Starting at y = %s' % y)
        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

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

    def remove_grid(self):
        for gl in self.gridlinesx + self.gridlinesy:
            self.scene.removeItem(gl)
        self.gridlinesx == []
        self.gridlinesy == []

#==============================================================================
#  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
        actual_rect = self.mapToScene(self.rect())
        bbox_size = actual_rect[0] - actual_rect[2]
        actual_width = abs(bbox_size.x())
        actual_height = abs(bbox_size.y())
        max_width = abs(self.scene.sceneRect().x() * 3)
        max_height = abs(self.scene.sceneRect().y() * 3)
        min_width = 1
        min_height = 1
        if ((actual_width > max_width) or
            (actual_height > max_height)) and (zoom_factor < 1):
            pass
        elif ((actual_width < min_width) or
              (actual_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):
        self.scale(zoom_factor, zoom_factor)
        self.zoom_factor_total *= zoom_factor

    def mousePressEvent(self, 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):
        if not self._rb_origin.isNull(
        ) and self._mousePressed == Qt.RightButton:
            self.rubberBand.setGeometry(
                QRect(self._rb_origin, event.pos()).normalized())

        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)