Exemplo n.º 1
0
class Window(QLabel):
    def __init__(self, pixmap, parent=None):
        QLabel.__init__(self, parent)
        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.origin = QPoint()
        self.pixmap = pixmap

    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()
            print(self.rubberBand.geometry())

    def resizeEvent(self, event):
        self.updateScreenshotLabel()
        # scaledSize = self.pixmap.size()
        # scaledSize.scale(self.screenshotLabel.size(), Qt.KeepAspectRatio)
        # if not self.screenshotLabel.pixmap() or scaledSize != self.screenshotLabel.pixmap().size():
        #     self.updateScreenshotLabel()

    def updateScreenshotLabel(self):
        self.setPixmap(
            self.pixmap.scaled(self.size(), Qt.KeepAspectRatio,
                               Qt.SmoothTransformation))
Exemplo n.º 2
0
class Label(QLabel):
    selection_changed = pyqtSignal(QRect, name="selectionChanged")

    def __init__(self):
        QLabel.__init__(self)
        self.rb = QRubberBand(QRubberBand.Rectangle, self)
        self.setMouseTracking(True)

    def mousePressEvent(self, event: QMouseEvent):
        self.origin = event.pos()
        self.rb.setGeometry(QRect(self.origin, QSize()))
        self.rb.show()
        QLabel.mousePressEvent(self, event)

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

    def mouseReleaseEvent(self, event):
        if self.rb.isVisible():
            self.rb.hide()
        self.selection_changed.emit(self.rb.geometry())
        QLabel.mouseReleaseEvent(self, event)
Exemplo n.º 3
0
class Label(QtWidgets.QLabel):
    def __init__(self):
        super().__init__()
        self.origin = QPoint()
        self.rubberBand = None


#    def paintEvent(self, event):
#        qp = QtGui.QPainter(self)
#        br = QtGui.QBrush(QtGui.QColor(100, 10, 10, 40))
#        qp.setBrush(br)
#        qp.drawRect(QtCore.QRect(self.begin, self.end))

    def mousePressEvent(self, event):
        super(Label, self).mousePressEvent(event)
        self.origin = event.pos()

        if not self.rubberBand:
            self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
            print("Rubber!")
        self.rubberBand.setGeometry(QRect(self.origin, QSize()))
        self.rubberBand.show()

        #self.update()

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

    def mouseReleaseEvent(self, event):
        if self.rubberBand:
            self.rubberBand.hide()
Exemplo n.º 4
0
class WidgetPicker(QWidget):
    """Widget for letting user point at another widget."""

    selected = Signal()

    def __init__(self):
        super(WidgetPicker, self).__init__()
        self.band = QRubberBand(QRubberBand.Rectangle)
        self.setMouseTracking(True)
        self.el = QEventLoop()

    def mousePressEvent(self, ev):
        self.el.quit()
        self.widget = QApplication.widgetAt(ev.globalPos())
        self.band.hide()

    def mouseMoveEvent(self, ev):
        widget = QApplication.widgetAt(ev.globalPos())
        if widget:
            rect = widget.frameGeometry()
            if widget.parent():
                rect.moveTo(widget.parent().mapToGlobal(rect.topLeft()))
            self.band.setGeometry(rect)
            self.band.show()
        else:
            self.band.hide()

    def run(self):
        self.grabMouse()
        try:
            self.el.exec_()
        finally:
            self.releaseMouse()
        return self.widget
Exemplo n.º 5
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')
Exemplo n.º 6
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):
        scene = self.scene()
        if scene is None:
            return

        rect = self.parent().mapToScene(self.parent().rect()).boundingRect()
        if not rect.contains(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 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
Exemplo n.º 8
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)
Exemplo n.º 9
0
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)
Exemplo n.º 10
0
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)
Exemplo n.º 11
0
class QLabelSelectable(QLabel):
    selectionFinished = pyqtSignal()

    def __init__(self, parent=None):
        QLabel.__init__(self, parent)
        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.origin = QPoint()

        self.startSelection = False
        self.endSelection = False

    def reset(self):
        self.startSelection = False
        self.endSelection = False

    def mousePressEvent(self, event):
        if event.button(
        ) == Qt.LeftButton and self.startSelection and not self.endSelection:
            self.origin = QPoint(event.pos())
        self.rubberBand.setGeometry(QRect(self.origin, QSize()))
        self.rubberBand.show()

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

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton and self.startSelection:
            #print(self.rubberBand.geometry())

            self.drawRectangle()

            self.rubberBand.hide()

            self.endSelection = True

    def drawRectangle(self):
        # create painter instance with pixmap
        self.painterInstance = QPainter(self.pixmap())

        # set rectangle color and thickness
        self.penRectangle = QPen(Qt.red)
        self.penRectangle.setWidth(3)

        # draw rectangle on painter
        self.painterInstance.setPen(self.penRectangle)
        self.painterInstance.drawRect(self.rubberBand.geometry())
        self.selectionFinished.emit()
Exemplo n.º 12
0
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)
Exemplo n.º 13
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
Exemplo n.º 14
0
class Image_Display(RawImageWidget, QWidget):
    def __init__(self, parent=None, **kargs):
        RawImageWidget.__init__(self, parent=parent, scaled=True)
        super(QWidget, self).__init__(parent)
        self.setWindowTitle("image")
        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.mousePressPosition = QPoint(0, 0)
        self.mouseReleasePosition = QPoint(0, 0)
        self.clientCallback = None
        self.mousePressed = False
        self.okToClose = False
        self.setGeometry(QRect(10, 300, 600, 600))

    def closeEvent(self, event):
        if not self.okToClose:
            self.hide()
            return

    def display(self, image, pixelLevels):
        self.setImage(image, levels=pixelLevels)
        self.show()

    def mousePressEvent(self, event):
        self.mousePressPosition = QPoint(event.pos())
        self.rubberBand.setGeometry(QRect(self.mousePressPosition, QSize()))
        self.rubberBand.show()
        self.mousePressed = True

    def mouseMoveEvent(self, event):
        if not self.mousePressed: return
        self.rubberBand.setGeometry(
            QRect(self.mousePressPosition, event.pos()).normalized())

    def mouseReleaseEvent(self, event):
        if not self.mousePressed: return
        self.mouseReleasePosition = QPoint(event.pos())
        if not self.clientCallback == None:
            self.clientCallback(self.mousePressPosition,
                                self.mouseReleasePosition)
        self.rubberBand.hide()
        self.mousePressed = False

    def clientReleaseEvent(self, clientCallback):
        self.clientCallback = clientCallback
Exemplo n.º 15
0
class TimeView(QGraphicsView):

    time_clicked = pyqtSignal(float)
    time_selected = pyqtSignal(float, float)

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.initialClick = QPoint()
        self.selectionBand = QRubberBand(QRubberBand.Rectangle, self)
        self.selecting = False

    def mouseReleaseEvent(self, event):
        clicked_x = self.mapToScene(event.pos()).x()
        self.selectionBand.hide()
        if clicked_x == self.mapToScene(self.initialClick).x():
            self.time_clicked.emit(clicked_x)
        else:
            if self.initialClick.x() < clicked_x:
                self.time_selected.emit(
                    self.mapToScene(self.initialClick).x(), clicked_x)
            else:
                self.time_selected.emit(clicked_x,
                                        self.mapToScene(self.initialClick).x())

        self.selecting = False

    def mousePressEvent(self, event):
        self.selecting = True
        self.initialClick = event.pos()
        self.selectionBand.setGeometry(
            QRect(self.initialClick.x(), 0, 1, self.height()))
        self.selectionBand.show()

    def mouseMoveEvent(self, event):
        if self.selecting:
            current_pos = event.pos()
            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, 0, width, self.height()))
Exemplo n.º 16
0
class PageScrollArea(QScrollArea):
    reachbottom = pyqtSignal()
    reachtop = pyqtSignal()
    areaSelected = pyqtSignal(QRect)

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

    def wheelEvent(self, event):
        super().wheelEvent(event)
        if self.verticalScrollBar().value() == self.verticalScrollBar(
        ).maximum() and event.angleDelta().y() == -120:
            self.reachbottom.emit()

        if self.verticalScrollBar().value() == 0 and event.angleDelta().y(
        ) == 120:
            self.reachtop.emit()

    def mousePressEvent(self, event):
        self.rubberorigin = event.pos()

        self.rubberband = QRubberBand(QRubberBand.Rectangle, self)
        self.rubberband.setGeometry(QRect(self.rubberorigin, QSize()))
        self.rubberband.show()
      

    def mouseReleaseEvent(self, event):
        rect = QRect(self.rubberband.pos(), self.rubberband.size())
        self.areaSelected.emit(rect)
        self.rubberband.hide()

    def mouseMoveEvent(self, event):
        super().mouseMoveEvent(event)
        self.rubberband.setGeometry(
            QRect(self.rubberorigin, event.pos()).normalized())

    def keyPressEvent(self, event):
        super().keyPressEvent(event)
        if self.verticalScrollBar().value() == self.verticalScrollBar(
        ).maximum() and (event.key() == 16777237 or event.key() == 16777239):
            self.reachbottom.emit()
        if self.verticalScrollBar().value() == 0 and (
                event.key() == 16777235 or event.key() == 16777238):
            self.reachtop.emit()
Exemplo n.º 17
0
class Window(QLabel):
    def __int__(self, parent=None):
        QLabel.__init__(self, parent)

        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.origin = QPoint()

    def mousePressEvent(self, event: QMouseEvent):
        if event.button() == Qt.LeftButton:
            self.origin = QPoint(event.pos())
            self.rubberBand.setGeometry(QRect(self.origin, QSize()))
            self.rubberBand.show()

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

    def mouseReleaseEvent(self, event: QMouseEvent):
        if event.button() == Qt.LeftButton:
            self.rubberBand.hide()
Exemplo n.º 18
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()
Exemplo n.º 19
0
class DragListWidget(QListWidget):
    # 可以往外拖的QListWidget

    def __init__(self, *args, **kwargs):
        super(DragListWidget, self).__init__(*args, **kwargs)
        self.resize(400, 400)
        # 隐藏横向滚动条
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        # 不能编辑
        self.setEditTriggers(self.NoEditTriggers)
        # 开启拖功能
        self.setDragEnabled(True)
        # 只能往外拖
        self.setDragDropMode(self.DragOnly)
        # 忽略放
        self.setDefaultDropAction(Qt.IgnoreAction)
        # ****重要的一句(作用是可以单选,多选。Ctrl、Shift多选,可从空白位置框选)****
        # ****不能用ExtendedSelection,因为它可以在选中item后继续框选会和拖拽冲突****
        self.setSelectionMode(self.ContiguousSelection)
        # 设置从左到右、自动换行、依次排列
        self.setFlow(self.LeftToRight)
        self.setWrapping(True)
        self.setResizeMode(self.Adjust)
        # item的间隔
        self.setSpacing(5)
        # 橡皮筋(用于框选效果)
        self._rubberPos = None
        self._rubberBand = QRubberBand(QRubberBand.Rectangle, self)

        self.initItems()

    # 实现拖拽的时候预览效果图
    # 这里演示拼接所有的item截图(也可以自己写算法实现堆叠效果)
    def startDrag(self, supportedActions):
        items = self.selectedItems()
        drag = QDrag(self)
        mimeData = self.mimeData(items)
        # 由于QMimeData只能设置image、urls、str、bytes等等不方便
        # 这里添加一个额外的属性直接把item放进去,后面可以根据item取出数据
        mimeData.setProperty('myItems', items)
        drag.setMimeData(mimeData)
        pixmap = QPixmap(self.viewport().visibleRegion().boundingRect().size())
        pixmap.fill(Qt.transparent)
        painter = QPainter()
        painter.begin(pixmap)
        for item in items:
            rect = self.visualRect(self.indexFromItem(item))
            painter.drawPixmap(rect, self.viewport().grab(rect))
        painter.end()
        drag.setPixmap(pixmap)
        drag.setHotSpot(self.viewport().mapFromGlobal(QCursor.pos()))
        drag.exec_(supportedActions)

    def mousePressEvent(self, event):
        # 列表框点击事件,用于设置框选工具的开始位置
        super(DragListWidget, self).mousePressEvent(event)
        if event.buttons() != Qt.LeftButton or self.itemAt(event.pos()):
            return
        self._rubberPos = event.pos()
        self._rubberBand.setGeometry(QRect(self._rubberPos, QSize()))
        self._rubberBand.show()

    def mouseReleaseEvent(self, event):
        # 列表框点击释放事件,用于隐藏框选工具
        super(DragListWidget, self).mouseReleaseEvent(event)
        self._rubberPos = None
        self._rubberBand.hide()

    def mouseMoveEvent(self, event):
        # 列表框鼠标移动事件,用于设置框选工具的矩形范围
        super(DragListWidget, self).mouseMoveEvent(event)
        if self._rubberPos:
            pos = event.pos()
            lx, ly = self._rubberPos.x(), self._rubberPos.y()
            rx, ry = pos.x(), pos.y()
            size = QSize(abs(rx - lx), abs(ry - ly))
            self._rubberBand.setGeometry(
                QRect(QPoint(min(lx, rx), min(ly, ry)), size))

    def makeItem(self, size, cname):
        item = QListWidgetItem(self)
        item.setData(Qt.UserRole + 1, cname)  # 把颜色放进自定义的data里面
        item.setSizeHint(size)
        label = QLabel(self)  # 自定义控件
        label.setMargin(2)  # 往内缩进2
        label.resize(size)
        pixmap = QPixmap(size.scaled(96, 96, Qt.IgnoreAspectRatio))  # 调整尺寸
        pixmap.fill(QColor(cname))
        label.setPixmap(pixmap)
        self.setItemWidget(item, label)

    def initItems(self):
        size = QSize(100, 100)
        for cname in QColor.colorNames():
            self.makeItem(size, cname)
Exemplo n.º 20
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()
        #self.showMaximized()

    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
Exemplo n.º 21
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])
Exemplo n.º 22
0
class imageLabel(QLabel):
    """Subclass of QLabel for displaying image"""
    def __init__(self, parent, image=None):
        super().__init__(parent)
        self.parent = parent
        self.image = QImage()
        #self.image = "images/parrot.png"

        #self.original_image = self.image.copy
        self.original_image = self.image

        self.rubber_band = QRubberBand(QRubberBand.Rectangle, self)

        # setBackgroundRole() will create a bg for the image
        #self.setBackgroundRole(QPalette.Base)
        self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
        self.setScaledContents(True)

        # Load image
        self.setPixmap(QPixmap().fromImage(self.image))
        self.setAlignment(Qt.AlignCenter)

    def openImage(self):
        """Load a new image into the """
        image_file, _ = QFileDialog.getOpenFileName(
            self, "Open Image", "",
            "PNG Files (*.png);;JPG Files (*.jpeg *.jpg );;Bitmap Files (*.bmp);;\
                GIF Files (*.gif)")

        if image_file:
            # Reset values when opening an image
            self.parent.zoom_factor = 1
            #self.parent.scroll_area.setVisible(True)
            self.parent.print_act.setEnabled(True)
            self.parent.updateActions()

            # Reset all sliders
            self.parent.brightness_slider.setValue(0)

            # Get image format
            image_format = self.image.format()
            self.image = QImage(image_file)
            self.original_image = self.image.copy()

            #pixmap = QPixmap(image_file)
            self.setPixmap(QPixmap().fromImage(self.image))
            #image_size = self.image_label.sizeHint()
            self.resize(self.pixmap().size())

            #self.scroll_area.setMinimumSize(image_size)

            #self.image_label.setPixmap(pixmap.scaled(self.image_label.size(),
            #    Qt.KeepAspectRatio, Qt.SmoothTransformation))
        elif image_file == "":
            # User selected Cancel
            pass
        else:
            QMessageBox.information(self, "Error", "Unable to open image.",
                                    QMessageBox.Ok)

    def saveImage(self):
        """Save the image displayed in the label."""
        #TODO: Add different functionality for the way in which the user can save their image.
        if self.image.isNull() == False:
            image_file, _ = QFileDialog.getSaveFileName(
                self, "Save Image", "",
                "PNG Files (*.png);;JPG Files (*.jpeg *.jpg );;Bitmap Files (*.bmp);;\
                    GIF Files (*.gif)")

            if image_file and self.image.isNull() == False:
                self.image.save(image_file)
            else:
                QMessageBox.information(self, "Error", "Unable to save image.",
                                        QMessageBox.Ok)
        else:
            QMessageBox.information(self, "Empty Image",
                                    "There is no image to save.",
                                    QMessageBox.Ok)

    def clearImage(self):
        """ """
        #TODO: If image is not null ask to save image first.
        pass

    def revertToOriginal(self):
        """Revert the image back to original image."""
        #TODO: Display message dialohg to confirm actions
        self.image = self.original_image
        self.setPixmap(QPixmap().fromImage(self.image))
        self.repaint()

        #self.parent.zoom_factor = 1

    def resizeImage(self):
        """Resize image."""
        #TODO: Resize image by specified size
        if self.image.isNull() == False:
            resize = QTransform().scale(0.5, 0.5)

            pixmap = QPixmap(self.image)

            resized_image = pixmap.transformed(resize,
                                               mode=Qt.SmoothTransformation)
            #rotated = pixmap.trueMatrix(transform90, pixmap.width, pixmap.height)

            #self.image_label.setPixmap(rotated)

            #self.image_label.setPixmap(rotated.scaled(self.image_label.size(),
            #    Qt.KeepAspectRatio, Qt.SmoothTransformation))
            self.image = QImage(resized_image)
            self.setPixmap(resized_image)
            #self.image = QPixmap(rotated)
            self.setScaledContents(True)
            self.repaint()  # repaint the child widget
        else:
            # No image to rotate
            pass

    def cropImage(self):
        """Crop selected portions in the image."""
        if self.image.isNull() == False:
            rect = QRect(10, 20, 400, 200)
            original_image = self.image
            cropped = original_image.copy(rect)

            self.image = QImage(cropped)
            self.setPixmap(QPixmap().fromImage(cropped))

    def rotateImage90(self, direction):
        """Rotate image 90º clockwise or counterclockwise."""
        if self.image.isNull() == False:
            if direction == "cw":
                transform90 = QTransform().rotate(90)
            elif direction == "ccw":
                transform90 = QTransform().rotate(-90)

            pixmap = QPixmap(self.image)

            #TODO: Try flipping the height/width when flipping the image

            rotated = pixmap.transformed(transform90,
                                         mode=Qt.SmoothTransformation)
            self.resize(self.image.height(), self.image.width())
            #rotated = pixmap.trueMatrix(transform90, pixmap.width, pixmap.height)

            #self.image_label.setPixmap(rotated.scaled(self.image_label.size(),
            #    Qt.KeepAspectRatio, Qt.SmoothTransformation))
            self.image = QImage(rotated)
            #self.setPixmap(rotated)
            self.setPixmap(
                rotated.scaled(self.size(), Qt.KeepAspectRatioByExpanding,
                               Qt.SmoothTransformation))
            self.repaint()  # repaint the child widget
        else:
            # No image to rotate
            pass

    def flipImage(self, axis):
        """
        Mirror the image across the horizontal axis.
        """
        if self.image.isNull() == False:
            if axis == "horizontal":
                flip_h = QTransform().scale(-1, 1)
                pixmap = QPixmap(self.image)
                flipped = pixmap.transformed(flip_h)
            elif axis == "vertical":
                flip_v = QTransform().scale(1, -1)
                pixmap = QPixmap(self.image)
                flipped = pixmap.transformed(flip_v)

            #self.image_label.setPixmap(flipped)
            #self.image_label.setPixmap(flipped.scaled(self.image_label.size(),
            #    Qt.KeepAspectRatio, Qt.SmoothTransformation))
            self.image = QImage(flipped)
            self.setPixmap(flipped)
            #self.image = QPixmap(flipped)
            self.repaint()
        else:
            # No image to flip
            pass

    def convertToGray(self):
        """Convert image to grayscale."""
        if self.image.isNull() == False:
            converted_img = self.image.convertToFormat(
                QImage.Format_Grayscale16)
            #self.image = converted_img
            self.image = QImage(converted_img)
            self.setPixmap(QPixmap().fromImage(converted_img))
            self.repaint()

    def convertToRGB(self):
        """Convert image to RGB format."""
        if self.image.isNull() == False:
            converted_img = self.image.convertToFormat(QImage.Format_RGB32)
            #self.image = converted_img
            self.image = QImage(converted_img)
            self.setPixmap(QPixmap().fromImage(converted_img))
            self.repaint()

    def convertToSepia(self):
        """Convert image to sepia filter."""
        #TODO: Sepia #704214 rgb(112, 66, 20)
        #TODO: optimize speed that the image converts, or add to thread
        if self.image.isNull() == False:
            for row_pixel in range(self.image.width()):
                for col_pixel in range(self.image.height()):
                    current_val = QColor(self.image.pixel(
                        row_pixel, col_pixel))

                    # Calculate r, g, b values for current pixel
                    red = current_val.red()
                    green = current_val.green()
                    blue = current_val.blue()

                    new_red = int(0.393 * red + 0.769 * green + 0.189 * blue)
                    new_green = int(0.349 * red + 0.686 * green + 0.168 * blue)
                    new_blue = int(0.272 * red + 0.534 * green + 0.131 * blue)

                    # Set the new RGB values for the current pixel
                    if new_red > 255:
                        red = 255
                    else:
                        red = new_red

                    if new_green > 255:
                        green = 255
                    else:
                        green = new_green

                    if new_blue > 255:
                        blue = 255
                    else:
                        blue = new_blue

                    new_value = qRgb(red, green, blue)
                    self.image.setPixel(row_pixel, col_pixel, new_value)

        self.setPixmap(QPixmap().fromImage(self.image))
        self.repaint()

    def changeBrighteness(self, value):
        #TODO: Reset the value of brightness, remember the original values
        # as going back to 0, i.e. keep track of original image's values
        #TODO: modify values based on original image
        if (value < -255 | value > 255):
            return self.image

        for row_pixel in range(self.image.width()):
            for col_pixel in range(self.image.height()):
                current_val = QColor(self.image.pixel(row_pixel, col_pixel))
                red = current_val.red()
                green = current_val.green()
                blue = current_val.blue()

                new_red = red + value
                new_green = green + value
                new_blue = blue + value

                # Set the new RGB values for the current pixel
                if new_red > 255:
                    red = 255
                elif new_red < 0:
                    red = 0
                else:
                    red = new_red

                if new_green > 255:
                    green = 255
                elif new_green < 0:
                    green = 0
                else:
                    green = new_green

                if new_blue > 255:
                    blue = 255
                elif new_blue < 0:
                    blue = 0
                else:
                    blue = new_blue

                new_value = qRgb(red, green, blue)
                self.image.setPixel(row_pixel, col_pixel, new_value)

        self.setPixmap(QPixmap().fromImage(self.image))

    def changeContrast(self, contrast):
        """Change the contrast of the pixels in the image.
           Contrast is the difference between max and min pixel intensity."""
        for row_pixel in range(self.image.width()):
            for col_pixel in range(self.image.height()):
                # Calculate a contrast correction factor
                factor = float(259 * (contrast + 255) / (255 *
                                                         (259 - contrast)))

                current_val = QColor(self.image.pixel(row_pixel, col_pixel))
                red = current_val.red()
                green = current_val.green()
                blue = current_val.blue()

                new_red = factor * (red - 128) + 128
                new_green = factor * (green - 128) + 128
                new_blue = factor * (blue - 128) + 128

                new_value = qRgb(new_red, new_green, new_blue)
                self.image.setPixel(row_pixel, col_pixel, new_value)

        self.setPixmap(QPixmap().fromImage(self.image))

    def changeHue(self):
        for row_pixel in range(self.image.width()):
            for col_pixel in range(self.image.height()):
                current_val = QColor(self.image.pixel(row_pixel, col_pixel))

                hue = current_val.hue()

                current_val.setHsv(hue, current_val.saturation(),
                                   current_val.value(), current_val.alpha())
                self.image.setPixelColor(row_pixel, col_pixel, current_val)

        self.setPixmap(QPixmap().fromImage(self.image))

    def mousePressEvent(self, event):
        """Handle mouse press event."""
        self.origin = event.pos()
        if not (self.rubber_band):
            self.rubber_band = QRubberBand(QRubberBand.Rectangle, self)
        self.rubber_band.setGeometry(QRect(self.origin, QSize()))
        self.rubber_band.show()

        #print(self.rubber_band.height())
        print(self.rubber_band.x())

    def mouseMoveEvent(self, event):
        """Handle mouse move event."""
        self.rubber_band.setGeometry(
            QRect(self.origin, event.pos()).normalized())

    def mouseReleaseEvent(self, event):
        """Handle when the mouse is released."""
        self.rubber_band.hide()
Exemplo n.º 23
0
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
Exemplo n.º 24
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
Exemplo n.º 25
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
Exemplo n.º 26
0
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)
Exemplo n.º 27
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
Exemplo n.º 28
0
class ImageViewer(QGraphicsView, QObject):
    def __init__(self, parent=None):
        super(ImageViewer, self).__init__(parent)
        self.setRenderHints(QPainter.Antialiasing
                            | QPainter.SmoothPixmapTransform)
        #self.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        self.setDragMode(QGraphicsView.ScrollHandDrag)
        #self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
        #self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
        self._scene = ImageViewerScene(self)
        self.setScene(self._scene)
        self._create_grid()
        self._create_grid_lines()
        self._pixmap = None
        self._selection_mode = SELECTION_MODE.NONE

        # polygon selection
        _polygon_guide_line_pen = QPen(QtGui.QColor(235, 72, 40))
        _polygon_guide_line_pen.setWidth(2)
        _polygon_guide_line_pen.setStyle(QtCore.Qt.DotLine)
        self._polygon_guide_line = QGraphicsLineItem()
        self._polygon_guide_line.setVisible(False)
        self._polygon_guide_line.setPen(_polygon_guide_line_pen)
        self._scene.addItem(self._polygon_guide_line)
        self._current_polygon = None
        # rectangle selection
        self._box_origin = QPoint()
        self._box_picker = QRubberBand(QRubberBand.Rectangle, self)

        # free selection
        self._current_free_path = None
        self._is_drawing = False
        self._last_point_drawn = QPoint()
        self._current_label = None

    @property
    def current_label(self):
        return self._current_label

    @current_label.setter
    def current_label(self, value):
        self._current_label = value

    @property
    def pixmap(self) -> ImagePixmap:
        return self._pixmap

    @pixmap.setter
    def pixmap(self, value: QPixmap):
        self.selection_mode = SELECTION_MODE.NONE
        self.resetTransform()
        if self.pixmap:
            self._scene.removeItem(self._pixmap)
        self.remove_annotations()
        self._pixmap = ImagePixmap()
        self._pixmap.setPixmap(value)
        self._pixmap.setOffset(-value.width() / 2, -value.height() / 2)
        self._pixmap.setTransformationMode(QtCore.Qt.SmoothTransformation)
        self._pixmap.signals.hoverEnterEventSgn.connect(
            self.pixmap_hoverEnterEvent_slot)
        self._pixmap.signals.hoverLeaveEventSgn.connect(
            self.pixmap_hoverLeaveEvent_slot)
        self._pixmap.signals.hoverMoveEventSgn.connect(
            self.pixmap_hoverMoveEvent_slot)
        self._scene.addItem(self._pixmap)
        # rect=self._scene.addRect(QtCore.QRectF(0,0,100,100), QtGui.QPen(QtGui.QColor("red")))
        # rect.setZValue(1.0)
        self.fit_to_window()

    @property
    def selection_mode(self):
        return self._selection_mode

    @selection_mode.setter
    def selection_mode(self, value):
        self._polygon_guide_line.hide()
        self._current_polygon = None
        self._current_free_path = None
        self._is_drawing = value == SELECTION_MODE.FREE
        if value == SELECTION_MODE.NONE:
            self.enable_items(True)
        else:
            self.enable_items(False)
        self._selection_mode = value

    def remove_annotations(self):
        for item in self._scene.items():
            if isinstance(item, EditableBox):
                self._scene.removeItem(item)
            elif isinstance(item, EditablePolygon):
                item.delete_polygon()

    def remove_annotations_by_label(self, label_name):
        for item in self._scene.items():
            if isinstance(item, EditableBox):
                if item.label and item.label.name == label_name:
                    self._scene.removeItem(item)
            elif isinstance(item, EditablePolygon):
                if item.label and item.label.name == label_name:
                    item.delete_polygon()

    def enable_items(self, value):
        for item in self._scene.items():
            if isinstance(item, EditablePolygon) or isinstance(
                    item, EditableBox):
                item.setEnabled(value)

    def _create_grid(self):
        gridSize = 15
        backgroundPixmap = QtGui.QPixmap(gridSize * 2, gridSize * 2)
        #backgroundPixmap.fill(QtGui.QColor("white"))
        backgroundPixmap.fill(QtGui.QColor(20, 20, 20))
        #backgroundPixmap.fill(QtGui.QColor("powderblue"))
        painter = QtGui.QPainter(backgroundPixmap)
        #backgroundColor=QtGui.QColor("palegoldenrod")
        #backgroundColor=QtGui.QColor(237,237,237)
        backgroundColor = QtGui.QColor(0, 0, 0)
        painter.fillRect(0, 0, gridSize, gridSize, backgroundColor)
        painter.fillRect(gridSize, gridSize, gridSize, gridSize,
                         backgroundColor)
        painter.end()
        self._scene.setBackgroundBrush(QtGui.QBrush(backgroundPixmap))

    def _create_grid_lines(self):
        pen_color = QColor(255, 255, 255, 255)
        pen = QPen(pen_color)
        pen.setWidth(2)
        pen.setStyle(QtCore.Qt.DotLine)
        self.vline = QGraphicsLineItem()
        self.vline.setVisible(False)
        self.vline.setPen(pen)
        self.hline = QGraphicsLineItem()
        self.hline.setVisible(False)
        self.hline.setPen(pen)
        self._scene.addItem(self.vline)
        self._scene.addItem(self.hline)

    def wheelEvent(self, event: QWheelEvent):
        adj = (event.angleDelta().y() / 120) * 0.1
        self.scale(1 + adj, 1 + adj)

    def fit_to_window(self):
        """Fit image within view."""
        if not self.pixmap or not self._pixmap.pixmap():
            return
        #self._pixmap.setTransformationMode(QtCore.Qt.SmoothTransformation)
        self.fitInView(self._pixmap, QtCore.Qt.KeepAspectRatio)

    def show_guide_lines(self):
        if self.hline and self.vline:
            self.hline.show()
            self.vline.show()

    def hide_guide_lines(self):
        if self.hline and self.vline:
            self.hline.hide()
            self.vline.hide()

    def pixmap_hoverEnterEvent_slot(self):
        self.show_guide_lines()

    def pixmap_hoverLeaveEvent_slot(self):
        self.hide_guide_lines()

    def pixmap_hoverMoveEvent_slot(self, evt: QGraphicsSceneHoverEvent, x, y):
        bbox: QRect = self._pixmap.boundingRect()
        offset = QPointF(bbox.width() / 2, bbox.height() / 2)
        self.vline.setLine(x, -offset.y(), x, bbox.height() - offset.y())
        self.vline.setZValue(1)
        self.hline.setLine(-offset.x(), y, bbox.width() - offset.x(), y)
        self.hline.setZValue(1)

    def mouseMoveEvent(self, evt: QtGui.QMouseEvent) -> None:
        if self.selection_mode == SELECTION_MODE.BOX:
            if not self._box_origin.isNull():
                self._box_picker.setGeometry(
                    QRect(self._box_origin, evt.pos()).normalized())
        elif self.selection_mode == SELECTION_MODE.POLYGON:
            if self._current_polygon:
                if self._current_polygon.count > 0:
                    last_point: QPointF = self._current_polygon.last_point
                    self._polygon_guide_line.setZValue(1)
                    self._polygon_guide_line.show()
                    mouse_pos = self.mapToScene(evt.pos())
                    self._polygon_guide_line.setLine(last_point.x(),
                                                     last_point.y(),
                                                     mouse_pos.x(),
                                                     mouse_pos.y())
            else:
                self._polygon_guide_line.hide()

        elif self.selection_mode == SELECTION_MODE.FREE and evt.buttons(
        ) and QtCore.Qt.LeftButton:
            if self._current_free_path:
                painter: QPainterPath = self._current_free_path.path()
                self._last_point_drawn = self.mapToScene(evt.pos())
                painter.lineTo(self._last_point_drawn)
                self._current_free_path.setPath(painter)

        super(ImageViewer, self).mouseMoveEvent(evt)

    def mousePressEvent(self, evt: QtGui.QMouseEvent) -> None:

        if evt.buttons() == QtCore.Qt.LeftButton:
            if self.selection_mode == SELECTION_MODE.BOX:
                self.setDragMode(QGraphicsView.NoDrag)
                self._box_origin = evt.pos()
                self._box_picker.setGeometry(QRect(self._box_origin, QSize()))
                self._box_picker.show()

            elif self._selection_mode == SELECTION_MODE.POLYGON:
                pixmap_rect: QRectF = self._pixmap.boundingRect()
                new_point = self.mapToScene(evt.pos())
                # consider only the points intothe image
                if pixmap_rect.contains(new_point):
                    if self._current_polygon is None:
                        self._current_polygon = EditablePolygon()
                        self._current_polygon.signals.deleted.connect(
                            self.delete_polygon_slot)
                        self._scene.addItem(self._current_polygon)
                        self._current_polygon.addPoint(new_point)
                    else:
                        self._current_polygon.addPoint(new_point)

            elif self._selection_mode == SELECTION_MODE.FREE:
                # start drawing
                new_point = self.mapToScene(evt.pos())
                pixmap_rect: QRectF = self._pixmap.boundingRect()
                # consider only the points intothe image
                if pixmap_rect.contains(new_point):
                    self.setDragMode(QGraphicsView.NoDrag)
                    pen = QPen(QtGui.QColor(235, 72, 40))
                    pen.setWidth(10)
                    self._last_point_drawn = new_point
                    self._current_free_path = QGraphicsPathItem()
                    self._current_free_path.setOpacity(0.6)
                    self._current_free_path.setPen(pen)
                    painter = QPainterPath()
                    painter.moveTo(self._last_point_drawn)
                    self._current_free_path.setPath(painter)
                    self._scene.addItem(self._current_free_path)
        else:
            self.setDragMode(QGraphicsView.ScrollHandDrag)

        super(ImageViewer, self).mousePressEvent(evt)

    def mouseReleaseEvent(self, evt: QtGui.QMouseEvent) -> None:
        if evt.button() == QtCore.Qt.LeftButton:
            if self.selection_mode == SELECTION_MODE.BOX:
                roi: QRect = self._box_picker.geometry()
                roi: QRectF = self.mapToScene(roi).boundingRect()
                pixmap_rect = self._pixmap.boundingRect()
                self._box_picker.hide()
                if pixmap_rect == roi.united(pixmap_rect):
                    rect = EditableBox(roi)
                    rect.label = self.current_label
                    self._scene.addItem(rect)
                    self.selection_mode = SELECTION_MODE.NONE
                    self.setDragMode(QGraphicsView.ScrollHandDrag)

            elif self.selection_mode == SELECTION_MODE.FREE and self._current_free_path:
                # create polygon
                self._current_free_path: QGraphicsPathItem
                path_rect = self._current_free_path.boundingRect()
                pixmap_rect = self._pixmap.boundingRect()
                if pixmap_rect == path_rect.united(pixmap_rect):
                    path = self._current_free_path.path()
                    path_polygon = EditablePolygon()
                    path_polygon.label = self.current_label
                    self._scene.addItem(path_polygon)
                    for i in range(0, path.elementCount(), 10):
                        x, y = path.elementAt(i).x, path.elementAt(i).y
                        path_polygon.addPoint(QPointF(x, y))
                self._scene.removeItem(self._current_free_path)
                self.selection_mode = SELECTION_MODE.NONE
                self.setDragMode(QGraphicsView.ScrollHandDrag)

        super(ImageViewer, self).mouseReleaseEvent(evt)

    def keyPressEvent(self, event: QtGui.QKeyEvent) -> None:
        if self._current_polygon and event.key() == QtCore.Qt.Key_Space:
            points = self._current_polygon.points
            self._current_polygon.label = self.current_label
            self._current_polygon = None
            self.selection_mode = SELECTION_MODE.NONE
            self._polygon_guide_line.hide()
            self.setDragMode(QGraphicsView.ScrollHandDrag)
        super(ImageViewer, self).keyPressEvent(event)

    def delete_polygon_slot(self, polygon: EditablePolygon):
        self._current_polygon = None
        self.selection_mode = SELECTION_MODE.NONE
        self._polygon_guide_line.hide()
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()
Exemplo n.º 30
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
Exemplo n.º 31
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
Exemplo n.º 32
0
class DropCanvas(QWidget):
    def __init__(self, parent):
        super().__init__()

        self.dots = parent
        self.scene = QGraphicsScene(self)
        self.view = ControlView(self)

        self.control = ''  ## shared
        self.pathMakerOn = False  ## shared
        self.openPlayFile = ''  ## shared
        self.pathList = []  ## used by animations, updated here

        self.pathMaker = PathMaker(self)
        self.mapper = InitMap(self)
        self.sideCar = SideCar(self)

        self.animation = Animation(self)
        self.sideShow = SideShow(self)
        self.initBkg = InitBkg(self)

        self.scene.setSceneRect(0, 0, common["ViewW"], common["ViewH"])

        self.setFixedSize(common["ViewW"] + 2, common["ViewH"] + 2)

        self.key = ''
        self.pixCount = 0

        self.origin = QPoint(0, 0)
        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)

        self.setMouseTracking(True)
        self.view.viewport().installEventFilter(self)
        self.view.keysSignal[str].connect(self.setKeys)

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

    @pyqtSlot(str)
    def setKeys(self, key):
        self.key = key
        if self.pathMakerOn and self.key == 'C' and \
            len(self.scene.items()) == 0:
            self.clear()
            return
        if not self.pathMakerOn:  ## canvas
            if self.key in CanvasStr or self.key == '':
                if self.key in Loops:  ## canvas hotkeys
                    self.sideShow.keysInPlay(self.key)
                elif self.key == 'C':
                    self.clear()
                else:
                    self.sendPixKeys()
        elif self.key in PathStr:  ## pathMaker
            self.pathMaker.pathKeys(self.key)

        # pub.sendMessage('setKeys', key=key)  ## pypubsub solution
        # if used - requires some work to coordinate with mapper
        # if self.mapper.mapSet: ## already in sendPixKeys
        #     self.mapper.updateMap()  ## redraw mapper

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

    ''' Problem: Starting a new path drawing session, typing 'N' in 
    pathMaker, will immeadiately start drawing without having to register
    a mousePress event if entered after displaying pointItems or 
    if started after either running play or pixtest. The mouse events used 
    by the newPath functions no-longer respond - it won't stop drawing. 
    Annoying but not fatal. I'm pretty sure the problem is with the eventFilter 
    though scene ownership may also be involved. I just moved the event filter to
    pathMaker and it seems to work thought not a fix. 
    The one thing the three funtions, running an animation, pixtext, and displaying
    pointItems have in common is they all add graphicsitems to the scene and delete 
    them from the scene.  Hope that helps.
    Any help would be appreciated. I may want to add additional pathMaker
    like classes later and how to share the canvas would be useful. 
    Thanks in advance ..'''
    def eventFilter(self, source, e):
        if not self.pathMakerOn:
            if e.type() == QEvent.MouseButtonPress:
                self.origin = QPoint(e.pos())
                self.mapper.clearTagGroup()  ## chks if set
                if self.key == 'cmd':  ## only used by eventFilter
                    self.mapper.clearMap()  ## set rubberband if mapset
                    self.unSelect()
                elif self.hasHiddenPix() and self.mapper.selections:
                    if self.control not in PlayKeys:
                        self.mapper.updatePixItemPos()
            elif e.type() == QEvent.MouseMove:
                if self.key == 'cmd' and self.origin != QPoint(0, 0):
                    if self.mapper.mapSet:
                        self.mapper.removeMap()
                    self.rubberBand.show()
                    self.rubberBand.setGeometry(
                        QRect(self.origin, e.pos()).normalized())
                elif self.mapper.mapSet and not self.scene.selectedItems():
                    self.mapper.removeMap()
                elif self.control not in PlayKeys:  ## animations running
                    self.mapper.updatePixItemPos()  ## costly but necessary
            elif e.type() == QEvent.MouseButtonRelease:
                if self.mapper.mapSet == False:
                    self.rubberBand.hide()  ## supposes something is selected
                    self.mapper.addSelectionsFromCanvas()
                if self.mapper.mapSet and self.key == 'cmd':
                    self.setKeys('')
                if self.hasHiddenPix() and self.key != 'cmd' or \
                    self.mapper.mapSet and not self.scene.selectedItems():
                    self.mapper.removeMap()
            elif e.type() == QEvent.MouseButtonDblClick and self.key != 'cmd':
                ## to preseve selections dblclk on an selection otherwise it
                ## will unselect all - possibly a default as it works the
                ## same as single click outside the map area
                if self.mapper.selections or self.hasHiddenPix():
                    if self.mapper.mapSet:
                        self.mapper.removeMap()
                        self.setKeys('noMap')
        return QWidget.eventFilter(self, source, e)

### --------------------------------------------------------
## set in drag/drop for id and in pixitem to clone itself

    def addPixItem(self, imgFile, x, y, clone, mirror):
        self.pixCount += 1
        pix = PixItem(imgFile, self.pixCount, x, y, self, mirror)
        if clone != None:  ## clone it
            self.sideCar.transFormPixItem(
                pix, clone.rotation,
                clone.scale * random.randrange(95, 105) / 100.0)
        else:
            if 'frame' in pix.fileName:  ## pin it on dnd
                pix.setPos(0, 0)
                pix.setFlag(QGraphicsPixmapItem.ItemIsMovable, False)
            self.scene.addItem(pix)

    def sendPixKeys(self):  ## update pixitems thru setPixKeys
        for pix in self.scene.items():
            if pix.type == 'pix':
                pix.setPixKeys(self.key)
            elif pix.zValue() <= common["pathZ"]:
                break
        if self.mapper.mapSet:
            self.mapper.updateMap()

    def exit(self):
        self.clear()
        self.dots.close()

    def clear(self):
        if self.pathMakerOn:
            self.pathMaker.pathMakerOff()
        self.pathMaker.pathChooserOff()
        self.sideShow.stop('clear')
        self.initBkg.disableBkgBtns()
        self.dots.statusBar.clearMessage()
        self.mapper.clearMap()
        self.dots.btnAddBkg.setEnabled(True)
        self.pixCount = 0
        self.sideCar.gridSet = False
        self.openPlayFile = ''
        self.scene.clear()

    def loadSprites(self):
        self.sideShow.enablePlay()
        self.dots.scrollpanel.loadSprites()

    def selectAll(self):
        for pix in self.scene.items():
            if pix.type == 'pix':
                pix.setSelected(True)
                pix.isHidden = False
            elif pix.zValue() <= common["pathZ"]:
                break

    def unSelect(self):
        self.mapper.clearMap()
        for pix in self.scene.items():
            if pix.type == 'pix':
                pix.isHidden = False
                pix.setSelected(False)
            elif pix.zValue() <= common["pathZ"]:
                break

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

    def deleteSelected(self):  # self.pathMakerOn equals false
        self.mapper.clearMap()
        self.mapper.clearTagGroup()
        for pix in self.scene.selectedItems():
            if pix.anime != None and \
                pix.anime.state() == QAbstractAnimation.Running:
                pix.anime.stop()
            pix.deletePix()
        self.anySprites()

    def anySprites(self):
        for pix in self.scene.items():
            if pix.type == 'pix':  ## still some left
                break
            elif pix.zValue() <= common["pathZ"]:
                self.sideShow.enablePlay()

    def flopSelected(self):
        if not self.pathMakerOn:
            for pix in self.scene.items():
                if pix.type == 'pix':
                    if pix.isSelected() or pix.isHidden:
                        if pix.flopped:
                            pix.setMirrored(False)
                        else:
                            pix.setMirrored(True)
                elif pix.zValue() <= common["pathZ"]:
                    break

    def hasHiddenPix(self):
        for pix in self.scene.items():
            if pix.type == 'pix':
                if pix.isHidden:
                    return True  ## found one
            elif pix.zValue() <= common["pathZ"]:
                break
        return False

    ## added dlbclk if hidden to re-select ##
    def hideSelected(self):
        # if self.mapper.mapSet and self.hasHiddenPix():
        self.mapper.removeMap()  ## also updates pix.pos()
        for pix in self.scene.items():
            if pix.type == 'pix':
                if pix.isSelected():
                    pix.setSelected(False)
                    pix.isHidden = True
                elif pix.isHidden:
                    pix.setSelected(True)
                    pix.isHidden = False
            elif pix.zValue() <= common["pathZ"]:
                break

    def ZDump(self):
        for pix in self.scene.items():
            print(pix.zValue())
        print("bkg: " + str(self.initBkg.hasBackGround()))

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

    def contextMenuEvent(self, e):
        if not self.scene.selectedItems():
            return
        menu = QMenu(self)
        menu.setStyleSheet("QMenu {\n"
                           "font-size: 14px;\n"
                           "border: 1px solid rgb(125,125,125);\n"
                           "}")
        alst = sorted(AnimeList)
        ## basing pathlist on what's in the directory
        self.pathList = getPathList(True)  ## names only
        rlst = sorted(self.pathList)
        alst.extend(["Random"])
        for anime in alst:
            action = menu.addAction(anime)
            action.triggered.connect(
                lambda chk, anime=anime: self.setAnimationTag(anime))
        menu.addSeparator()
        for anime in rlst:
            action = menu.addAction(anime)
            action.triggered.connect(
                lambda chk, anime=anime: self.setAnimationTag(anime))
        menu.addSeparator()
        anime = "Clear Tags"
        action = menu.addAction(anime)
        action.triggered.connect(
            lambda chk, anime=anime: self.setAnimationTag(anime))
        menu.exec_(e.globalPos())

    def setAnimationTag(self, tag):
        if self.mapper.tagSet and tag == "Clear Tags":
            self.mapper.clearTagGroup()
        for pix in self.scene.selectedItems():
            if tag == "Clear Tags":
                pix.tag = ''
            else:
                pix.tag = tag
            pix.anime = None  ## set by play
            pix.setSelected(False)  ## when tagged
        if self.mapper.mapSet:
            self.mapper.removeMap()
Exemplo n.º 33
0
class ImageViewer(QGraphicsView, QObject):
    points_selection_sgn = pyqtSignal(list)
    key_press_sgn = pyqtSignal(QtGui.QKeyEvent)

    def __init__(self, parent=None):
        super(ImageViewer, self).__init__(parent)
        self.setDragMode(QGraphicsView.ScrollHandDrag)
        self.setRenderHints(QPainter.Antialiasing
                            | QPainter.SmoothPixmapTransform)
        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)

        self._scene = ImageViewerScene(self)
        self.setScene(self._scene)
        self._image = None
        self._image_original = None
        self._pixmap = None
        self._img_contrast = 1.0
        self._img_brightness = 50.0
        self._img_gamma = 1.0
        self._create_grid()
        self._channels = []
        self._current_tool = SELECTION_TOOL.POINTER
        self._dataset = None

        # create grid lines
        pen_color = QColor(255, 255, 255, 255)
        pen = QPen(pen_color)
        pen.setWidth(2)
        pen.setStyle(QtCore.Qt.DotLine)
        self.vline = QGraphicsLineItem()
        self.vline.setVisible(False)
        self.vline.setPen(pen)
        self.hline = QGraphicsLineItem()
        self.hline.setVisible(False)
        self.hline.setPen(pen)
        self._scene.addItem(self.vline)
        self._scene.addItem(self.hline)
        self._current_label = None

        # rectangle selection tool
        self._rectangle_tool_origin = QPoint()
        self._rectangle_tool_picker = QRubberBand(QRubberBand.Rectangle, self)

        # polygon selection tool
        app = QApplication.instance()
        color = app.palette().color(QPalette.Highlight)
        self._polygon_guide_line_pen = QPen(color)
        self._polygon_guide_line_pen.setWidth(3)
        self._polygon_guide_line_pen.setStyle(QtCore.Qt.DotLine)
        self._polygon_guide_line = QGraphicsLineItem()
        self._polygon_guide_line.setVisible(False)
        self._polygon_guide_line.setPen(self._polygon_guide_line_pen)
        self._scene.addItem(self._polygon_guide_line)
        self._current_polygon = None

        # circle
        self._current_ellipse = None

        # free selection tool
        self._current_free_path = None
        self._is_drawing = False
        self._last_point_drawn = QPoint()
        self._last_click_point = None
        self._free_Path_pen = QPen(color)
        self._free_Path_pen.setWidth(10)

        self._extreme_points = Queue(maxsize=4)

    @property
    def current_label(self):
        return self._current_label

    @current_label.setter
    def current_label(self, value):
        self._current_label = value
        if self._current_label:
            color = QColor(self._current_label.color)
            self._free_Path_pen.setColor(color)
            self._polygon_guide_line_pen.setColor(color)
            self._polygon_guide_line.setPen(self._polygon_guide_line_pen)

    @property
    def dataset(self):
        return self._dataset

    @dataset.setter
    def dataset(self, value):
        self._dataset = value

    @property
    def img_contrast(self):
        return self._img_contrast

    @img_contrast.setter
    def img_contrast(self, value):
        self._img_contrast = value

    @property
    def img_gamma(self):
        return self._img_gamma

    @img_gamma.setter
    def img_gamma(self, value):
        self._img_gamma = value

    @property
    def img_brightness(self):
        return self._img_brightness

    @img_brightness.setter
    def img_brightness(self, value):
        self._img_brightness = value

    @property
    def image(self):
        return self._image

    @image.setter
    def image(self, value):
        self._image = value
        self._image_original = value.copy()
        self.update_viewer()

    @property
    def pixmap(self) -> ImagePixmap:
        return self._pixmap

    @gui_exception
    def update_viewer(self, fit_image=True):
        rgb = cv2.cvtColor(self._image, cv2.COLOR_BGR2RGB)
        rgb = ImageUtilities.adjust_image(rgb, self._img_contrast,
                                          self._img_brightness)
        rgb = ImageUtilities.adjust_gamma(rgb, self._img_gamma)
        pil_image = Image.fromarray(rgb)
        qppixmap_image = pil_image.toqpixmap()
        x, y = -qppixmap_image.width() / 2, -qppixmap_image.height() / 2

        if self._pixmap:
            self._pixmap.resetTransform()
            self._pixmap.setPixmap(qppixmap_image)
            self._pixmap.setOffset(x, y)
        else:
            self._pixmap = ImagePixmap()
            self._pixmap.setPixmap(qppixmap_image)
            self._pixmap.setOffset(x, y)
            self._scene.addItem(self._pixmap)
            self._pixmap.signals.hoverEnterEventSgn.connect(
                self.pixmap_hoverEnterEvent_slot)
            self._pixmap.signals.hoverLeaveEventSgn.connect(
                self.pixmap_hoverLeaveEvent_slot)
            self._pixmap.signals.hoverMoveEventSgn.connect(
                self.pixmap_hoverMoveEvent_slot)
        self._hide_guide_lines()
        if fit_image:
            self.fit_to_window()

    @gui_exception
    def reset_viewer(self):
        self._img_contrast = 1.0
        self._img_brightness = 50.0
        self._img_gamma = 1.0
        self._image = self._image_original.copy()

    @gui_exception
    def equalize_histogram(self):
        self._image = ImageUtilities.histogram_equalization(self._image)

    @gui_exception
    def correct_lightness(self):
        self._image = ImageUtilities.correct_lightness(self._image)

    def clusterize(self, k):
        self._image = ImageUtilities.kmeans(self._image.copy(), k)

    @property
    def current_tool(self):
        return self._current_tool

    @current_tool.setter
    def current_tool(self, value):
        self._polygon_guide_line.hide()
        self._current_polygon = None
        self._current_free_path = None
        self._current_ellipse = None
        self._is_drawing = value == SELECTION_TOOL.FREE
        self._current_tool = value
        self.clear_extreme_points()
        if value == SELECTION_TOOL.POINTER:
            self.enable_items(True)
        else:
            self.enable_items(False)

    def fit_to_window(self):
        if not self._pixmap or not self._pixmap.pixmap():
            return
        self.resetTransform()
        self.setTransform(QtGui.QTransform())
        self.fitInView(self._pixmap, QtCore.Qt.KeepAspectRatio)

    def _create_grid(self, gridSize=15):
        app: QApplication = QApplication.instance()
        curr_theme = "dark"
        if app:
            curr_theme = app.property("theme")
        if curr_theme == "light":
            color1 = QtGui.QColor("white")
            color2 = QtGui.QColor(237, 237, 237)
        else:
            color1 = QtGui.QColor(20, 20, 20)
            color2 = QtGui.QColor(0, 0, 0)
        backgroundPixmap = QtGui.QPixmap(gridSize * 2, gridSize * 2)
        backgroundPixmap.fill(color1)
        painter = QtGui.QPainter(backgroundPixmap)
        painter.fillRect(0, 0, gridSize, gridSize, color2)
        painter.fillRect(gridSize, gridSize, gridSize, gridSize, color2)
        painter.end()
        self._scene.setBackgroundBrush(QtGui.QBrush(backgroundPixmap))

    def wheelEvent(self, event: QWheelEvent):
        adj = (event.angleDelta().y() / 120) * 0.1
        self.scale(1 + adj, 1 + adj)

    @gui_exception
    def keyPressEvent(self, event: QKeyEvent):
        if event.key() == QtCore.Qt.Key_Space:
            image_rect: QRectF = self._pixmap.sceneBoundingRect()
            if self.current_tool == SELECTION_TOOL.POLYGON and self._current_polygon:
                points = self._current_polygon.points
                self._polygon_guide_line.hide()
                self.setDragMode(QGraphicsView.ScrollHandDrag)
                if len(points) <= 2:
                    self._current_polygon.delete_item()
                self.current_tool = SELECTION_TOOL.POINTER
            elif self.current_tool == SELECTION_TOOL.EXTREME_POINTS and \
                    self._extreme_points.full():
                points = []
                image_offset = QPointF(image_rect.width() / 2,
                                       image_rect.height() / 2)
                for pt in self._extreme_points.queue:
                    pt: EditablePolygonPoint
                    center = pt.sceneBoundingRect().center()
                    x = math.floor(center.x() + image_offset.x())
                    y = math.floor(center.y() + image_offset.y())
                    points.append([x, y])
                self.points_selection_sgn.emit(points)
                self.current_tool = SELECTION_TOOL.POINTER
        else:
            event.ignore()

    # guide lines events
    def _show_guide_lines(self):
        if self.hline and self.vline:
            self.hline.show()
            self.vline.show()

    def _hide_guide_lines(self):
        if self.hline and self.vline:
            self.hline.hide()
            self.vline.hide()

    def _update_guide_lines(self, x, y):
        bbox: QRect = self._pixmap.boundingRect()
        offset = QPointF(bbox.width() / 2, bbox.height() / 2)
        self.vline.setLine(x, -offset.y(), x, bbox.height() - offset.y())
        self.vline.setZValue(1)
        self.hline.setLine(-offset.x(), y, bbox.width() - offset.x(), y)
        self.hline.setZValue(1)

    def pixmap_hoverMoveEvent_slot(self, evt: QGraphicsSceneHoverEvent, x, y):
        self._update_guide_lines(x, y)

    def pixmap_hoverEnterEvent_slot(self):
        self._show_guide_lines()

    def pixmap_hoverLeaveEvent_slot(self):
        self._hide_guide_lines()

    def delete_polygon_slot(self, polygon: EditablePolygon):
        self._current_polygon = None
        self.current_tool = SELECTION_TOOL.POINTER
        self._polygon_guide_line.hide()

    @gui_exception
    def mousePressEvent(self, evt: QtGui.QMouseEvent) -> None:
        image_rect: QRectF = self._pixmap.boundingRect()
        mouse_pos = self.mapToScene(evt.pos())
        if evt.buttons() == QtCore.Qt.LeftButton:
            if self.current_tool == SELECTION_TOOL.BOX:
                # create rectangle
                self.setDragMode(QGraphicsView.NoDrag)
                self._rectangle_tool_origin = evt.pos()
                geometry = QRect(self._rectangle_tool_origin, QSize())
                self._rectangle_tool_picker.setGeometry(geometry)
                self._rectangle_tool_picker.show()
            elif self.current_tool == SELECTION_TOOL.POLYGON:
                if image_rect.contains(mouse_pos):
                    if self._current_polygon is None:
                        self._current_polygon = EditablePolygon()
                        self._current_polygon.label = self._current_label
                        self._current_polygon.tag = self._dataset
                        self._current_polygon.signals.deleted.connect(
                            self.delete_polygon_slot)
                        self._scene.addItem(self._current_polygon)
                        self._current_polygon.addPoint(mouse_pos)
                    else:
                        self._current_polygon.addPoint(mouse_pos)
            elif self.current_tool == SELECTION_TOOL.ELLIPSE:
                if image_rect.contains(mouse_pos):
                    self.setDragMode(QGraphicsView.NoDrag)
                    ellipse_rec = QtCore.QRectF(mouse_pos.x(), mouse_pos.y(),
                                                0, 0)
                    self._current_ellipse = EditableEllipse()
                    self._current_ellipse.tag = self.dataset
                    self._current_ellipse.label = self._current_label
                    self._current_ellipse.setRect(ellipse_rec)
                    self._scene.addItem(self._current_ellipse)

            elif self.current_tool == SELECTION_TOOL.FREE:
                # consider only the points into the image
                if image_rect.contains(mouse_pos):
                    self.setDragMode(QGraphicsView.NoDrag)
                    self._last_point_drawn = mouse_pos
                    self._current_free_path = QGraphicsPathItem()
                    self._current_free_path.setOpacity(0.6)
                    self._current_free_path.setPen(self._free_Path_pen)
                    painter = QPainterPath()
                    painter.moveTo(self._last_point_drawn)
                    self._current_free_path.setPath(painter)
                    self._scene.addItem(self._current_free_path)

            elif self.current_tool == SELECTION_TOOL.EXTREME_POINTS:
                if image_rect.contains(mouse_pos):
                    if not self._extreme_points.full():

                        def delete_point(idx):
                            del self._extreme_points.queue[idx]

                        idx = self._extreme_points.qsize()
                        editable_pt = EditablePolygonPoint(idx)
                        editable_pt.signals.deleted.connect(delete_point)
                        editable_pt.setPos(mouse_pos)
                        self._scene.addItem(editable_pt)
                        self._extreme_points.put(editable_pt)

        else:
            self.setDragMode(QGraphicsView.ScrollHandDrag)
        super(ImageViewer, self).mousePressEvent(evt)

    @gui_exception
    def mouseMoveEvent(self, evt: QtGui.QMouseEvent) -> None:
        mouse_pos = self.mapToScene(evt.pos())
        image_rect: QRectF = self._pixmap.boundingRect()
        if self.current_tool == SELECTION_TOOL.BOX:
            if not self._rectangle_tool_origin.isNull():
                geometry = QRect(self._rectangle_tool_origin,
                                 evt.pos()).normalized()
                self._rectangle_tool_picker.setGeometry(geometry)
        elif self.current_tool == SELECTION_TOOL.POLYGON:
            if self._current_polygon and image_rect.contains(mouse_pos):
                if self._current_polygon.count > 0:
                    last_point: QPointF = self._current_polygon.last_point
                    self._polygon_guide_line.setZValue(1)
                    self._polygon_guide_line.show()
                    mouse_pos = self.mapToScene(evt.pos())
                    self._polygon_guide_line.setLine(last_point.x(),
                                                     last_point.y(),
                                                     mouse_pos.x(),
                                                     mouse_pos.y())
            else:
                self._polygon_guide_line.hide()
        elif self.current_tool == SELECTION_TOOL.ELLIPSE:
            if self._current_ellipse and image_rect.contains(mouse_pos):
                ellipse_rect = self._current_ellipse.rect()
                ellipse_pos = QPointF(ellipse_rect.x(), ellipse_rect.y())
                distance = math.hypot(mouse_pos.x() - ellipse_pos.x(),
                                      mouse_pos.y() - ellipse_pos.y())
                ellipse_rect.setWidth(distance)
                ellipse_rect.setHeight(distance)
                self._current_ellipse.setRect(ellipse_rect)
        elif self.current_tool == SELECTION_TOOL.FREE and evt.buttons(
        ) and QtCore.Qt.LeftButton:
            if self._current_free_path and image_rect.contains(mouse_pos):
                painter: QPainterPath = self._current_free_path.path()
                self._last_point_drawn = self.mapToScene(evt.pos())
                painter.lineTo(self._last_point_drawn)
                self._current_free_path.setPath(painter)
        super(ImageViewer, self).mouseMoveEvent(evt)

    @gui_exception
    def mouseReleaseEvent(self, evt: QtGui.QMouseEvent) -> None:
        image_rect: QRectF = self._pixmap.boundingRect()
        if self.current_tool == SELECTION_TOOL.BOX:
            roi: QRect = self._rectangle_tool_picker.geometry()
            roi: QRectF = self.mapToScene(roi).boundingRect()
            self._rectangle_tool_picker.hide()
            if image_rect == roi.united(image_rect):
                rect = EditableBox(roi)
                rect.label = self.current_label
                rect.tag = self._dataset
                self._scene.addItem(rect)
                self.current_tool = SELECTION_TOOL.POINTER
                self.setDragMode(QGraphicsView.ScrollHandDrag)

        elif self.current_tool == SELECTION_TOOL.ELLIPSE and self._current_ellipse:
            roi: QRect = self._current_ellipse.boundingRect()
            if image_rect == roi.united(image_rect):
                self.current_tool = SELECTION_TOOL.POINTER
                self.setDragMode(QGraphicsView.ScrollHandDrag)
            else:
                self._current_ellipse.delete_item()
        elif self.current_tool == SELECTION_TOOL.FREE and self._current_free_path:
            # create polygon
            self._current_free_path: QGraphicsPathItem
            path_rect = self._current_free_path.boundingRect()
            if image_rect == path_rect.united(image_rect):
                path = self._current_free_path.path()
                path_polygon = EditablePolygon()
                path_polygon.tag = self.dataset
                path_polygon.label = self.current_label
                self._scene.addItem(path_polygon)
                for i in range(0, path.elementCount(), 10):
                    x, y = path.elementAt(i).x, path.elementAt(i).y
                    path_polygon.addPoint(QPointF(x, y))
            self._scene.removeItem(self._current_free_path)
            self.current_tool = SELECTION_TOOL.POINTER
            self.setDragMode(QGraphicsView.ScrollHandDrag)
        super(ImageViewer, self).mouseReleaseEvent(evt)

    def remove_annotations(self):
        for item in self._scene.items():
            if isinstance(item, EditableItem):
                item.delete_item()

    def remove_annotations_by_label(self, label_name):
        for item in self._scene.items():
            if isinstance(item, EditableItem):
                if item.label and item.label.name == label_name:
                    item.delete_item()

    def enable_items(self, value):
        for item in self._scene.items():
            if isinstance(item, EditableItem):
                item.setEnabled(value)

    def clear_extreme_points(self):
        if self._extreme_points.qsize() > 0:
            for pt in self._extreme_points.queue:
                self._scene.removeItem(pt)
            self._extreme_points.queue.clear()
Exemplo n.º 34
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.BB.Pe.x - scene.BB.Ps.x
        height = scene.BB.Pe.y - scene.BB.Ps.y
        scext = QtCore.QRectF(scene.BB.Ps.x, -scene.BB.Pe.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
Exemplo n.º 35
0
class SlideViewer(QWidget):
    eventSignal = pyqtSignal(PyQt5.QtCore.QEvent)

    def __init__(self, parent: QWidget = None, viewer_top_else_left=True):
        super().__init__(parent)
        self.init_view()
        self.init_labels(word_wrap=viewer_top_else_left)
        self.init_layout(viewer_top_else_left)

    def init_view(self):
        self.scene = MyGraphicsScene()
        self.view = QGraphicsView()
        self.view.setScene(self.scene)
        self.view.setTransformationAnchor(QGraphicsView.NoAnchor)
        self.view.viewport().installEventFilter(self)

        self.rubber_band = QRubberBand(QRubberBand.Rectangle, self)
        self.mouse_press_view = QPoint()

        self.view.horizontalScrollBar().sliderMoved.connect(
            self.on_view_changed)
        self.view.verticalScrollBar().sliderMoved.connect(self.on_view_changed)
        self.scale_initializer_deffered_function = None
        self.slide_view_params = None
        self.slide_helper = None

    def init_labels(self, word_wrap):
        # word_wrap = True
        self.level_downsample_label = QLabel()
        self.level_downsample_label.setWordWrap(word_wrap)
        self.level_size_label = QLabel()
        self.level_size_label.setWordWrap(word_wrap)
        self.selected_rect_label = QLabel()
        self.selected_rect_label.setWordWrap(word_wrap)
        self.mouse_pos_scene_label = QLabel()
        self.mouse_pos_scene_label.setWordWrap(word_wrap)
        self.view_rect_scene_label = QLabel()
        self.view_rect_scene_label.setWordWrap(word_wrap)
        self.labels_layout = QVBoxLayout()
        self.labels_layout.setAlignment(Qt.AlignTop)
        self.labels_layout.addWidget(self.level_downsample_label)
        self.labels_layout.addWidget(self.level_size_label)
        self.labels_layout.addWidget(self.mouse_pos_scene_label)
        # self.labels_layout.addWidget(self.selected_rect_label)
        self.labels_layout.addWidget(self.view_rect_scene_label)

    def init_layout(self, viewer_top_else_left=True):
        main_layout = QVBoxLayout(
            self) if viewer_top_else_left else QHBoxLayout(self)
        main_layout.addWidget(self.view, )
        main_layout.addLayout(self.labels_layout)
        # main_layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(main_layout)

    """
    If you want to start view frome some point at some level, specify <level> and <level_rect> params. 
    level_rect : rect in dimensions of slide at level=level. If None - fits the whole size of slide
    """

    def load(self,
             slide_view_params: SlideViewParams,
             preffered_rects_count=2000,
             zoom_step=1.15):
        self.zoom_step = zoom_step
        self.slide_view_params = slide_view_params
        self.slide_helper = SlideHelper(slide_view_params.slide_path)

        self.slide_graphics = SlideGraphicsGroup(slide_view_params,
                                                 preffered_rects_count)
        self.scene.clear()
        self.scene.addItem(self.slide_graphics)

        if self.slide_view_params.level == -1 or self.slide_view_params.level is None:
            self.slide_view_params.level = self.slide_helper.get_max_level()

        self.slide_graphics.update_visible_level(self.slide_view_params.level)
        self.scene.setSceneRect(
            self.slide_helper.get_rect_for_level(self.slide_view_params.level))

        def scale_initializer_deffered_function():
            self.view.resetTransform()
            # print("size when loading: ", self.view.viewport().size())
            if self.slide_view_params.level_rect:
                # self.view.fitInView(QRectF(*self.slide_view_params.level_rect), Qt.KeepAspectRatioByExpanding)
                self.view.fitInView(QRectF(*self.slide_view_params.level_rect),
                                    Qt.KeepAspectRatio)
                # print("after fit: ", self.get_current_view_scene_rect())
            else:
                start_margins = QMarginsF(200, 200, 200, 200)
                start_image_rect_ = self.slide_helper.get_rect_for_level(
                    self.slide_view_params.level)
                self.view.fitInView(start_image_rect_ + start_margins,
                                    Qt.KeepAspectRatio)

        self.scale_initializer_deffered_function = scale_initializer_deffered_function

    def eventFilter(self, qobj: 'QObject', event: QEvent):
        self.eventSignal.emit(event)
        event_processed = False
        # print("size when event: ", event, event.type(), self.view.viewport().size())
        if isinstance(event, QShowEvent):
            """
            we need it deffered because fitInView logic depends on current viewport size. Expecting at this point widget is finally resized before being shown at first
            """
            if self.scale_initializer_deffered_function:
                # TODO labels start to occupy some space after view was already fitted, and labels will reduce size of viewport
                # self.update_labels()
                self.scale_initializer_deffered_function()
                self.on_view_changed()
                self.scale_initializer_deffered_function = None
        elif isinstance(event, QWheelEvent):
            event_processed = self.process_viewport_wheel_event(event)
            # we handle wheel event to prevent GraphicsView interpret it as scrolling
        elif isinstance(event, QMouseEvent):
            event_processed = self.process_mouse_event(event)

        return event_processed

    def process_viewport_wheel_event(self, event: QWheelEvent):
        # print("size when wheeling: ", self.view.viewport().size())
        zoom_in = self.zoom_step
        zoom_out = 1 / zoom_in
        zoom_ = zoom_in if event.angleDelta().y() > 0 else zoom_out
        self.update_scale(event.pos(), zoom_)
        event.accept()
        self.on_view_changed()
        return True

    def process_mouse_event(self, event: QMouseEvent):
        if self.slide_helper is None:
            return False

        if event.button() == Qt.MiddleButton:
            if event.type() == QEvent.MouseButtonPress:
                self.slide_graphics.update_grid_visibility(
                    not self.slide_graphics.slide_view_params.grid_visible)
                # items=self.scene.items()
                # QMessageBox.information(None, "Items", str(items))
                return True
            # self.update_scale(QPoint(), 1.15)
        elif event.button() == Qt.LeftButton:
            if event.type() == QEvent.MouseButtonPress:
                self.mouse_press_view = QPoint(event.pos())
                self.rubber_band.setGeometry(
                    QRect(self.mouse_press_view, QSize()))
                self.rubber_band.show()
                return True
            elif event.type() == QEvent.MouseButtonRelease:
                self.rubber_band.hide()
                self.remember_selected_rect_params()
                self.slide_graphics.update_selected_rect_0_level(
                    self.slide_view_params.selected_rect_0_level)
                self.update_labels()
                self.scene.invalidate()
                return True
        elif event.type() == QEvent.MouseMove:
            self.mouse_pos_scene_label.setText(
                "mouse_scene: " +
                point_to_str(self.view.mapToScene(event.pos())))
            if not self.mouse_press_view.isNull():
                self.rubber_band.setGeometry(
                    QRect(self.mouse_press_view, event.pos()).normalized())
            return True

        return False

    def remember_selected_rect_params(self):
        pos_scene = self.view.mapToScene(self.rubber_band.pos())
        rect_scene = self.view.mapToScene(
            self.rubber_band.rect()).boundingRect()
        downsample = self.slide_helper.get_downsample_for_level(
            self.slide_view_params.level)
        selected_qrectf_0_level = QRectF(pos_scene * downsample,
                                         rect_scene.size() * downsample)
        self.slide_view_params.selected_rect_0_level = selected_qrectf_0_level.getRect(
        )

    def update_scale(self, mouse_pos: QPoint, zoom):
        old_mouse_pos_scene = self.view.mapToScene(mouse_pos)
        old_view_scene_rect = self.view.mapToScene(
            self.view.viewport().rect()).boundingRect()

        old_level = self.get_best_level_for_scale(
            self.get_current_view_scale())
        old_level_downsample = self.slide_helper.get_downsample_for_level(
            old_level)
        new_level = self.get_best_level_for_scale(
            self.get_current_view_scale() * zoom)
        new_level_downsample = self.slide_helper.get_downsample_for_level(
            new_level)

        level_scale_delta = 1 / (new_level_downsample / old_level_downsample)

        r = old_view_scene_rect.topLeft()
        m = old_mouse_pos_scene
        new_view_scene_rect_top_left = (m - (m - r) / zoom) * level_scale_delta
        new_view_scene_rect = QRectF(
            new_view_scene_rect_top_left,
            old_view_scene_rect.size() * level_scale_delta / zoom)

        new_scale = self.get_current_view_scale(
        ) * zoom * new_level_downsample / old_level_downsample
        transform = QTransform().scale(new_scale, new_scale).translate(
            -new_view_scene_rect.x(), -new_view_scene_rect.y())

        new_rect = self.slide_helper.get_rect_for_level(new_level)
        self.scene.setSceneRect(new_rect)
        self.slide_view_params.level = new_level
        self.reset_view_transform()
        self.view.setTransform(transform, False)
        self.slide_graphics.update_visible_level(new_level)
        self.update_labels()

    def get_best_level_for_scale(self, scale):
        scene_width = self.scene.sceneRect().size().width()
        candidates = [0]
        for level in self.slide_helper.get_levels():
            w, h = self.slide_helper.get_level_size(level)
            if scene_width * scale <= w:
                candidates.append(level)
        best_level = max(candidates)
        return best_level

    def update_labels(self):
        level_downsample = self.slide_helper.get_downsample_for_level(
            self.slide_view_params.level)
        level_size = self.slide_helper.get_level_size(
            self.slide_view_params.level)
        self.level_downsample_label.setText(
            "level, downsample: {}, {:.0f}".format(
                self.slide_view_params.level, level_downsample))
        self.level_size_label.setText(
            "level_size: ({}, {})".format(*level_size))
        self.view_rect_scene_label.setText(
            "view_scene: ({:.0f},{:.0f},{:.0f},{:.0f})".format(
                *self.get_current_view_scene_rect().getRect()))
        if self.slide_view_params.selected_rect_0_level:
            self.selected_rect_label.setText(
                "selected rect (0-level): ({:.0f},{:.0f},{:.0f},{:.0f})".
                format(*self.slide_view_params.selected_rect_0_level))

    def on_view_changed(self):
        if self.scale_initializer_deffered_function is None and self.slide_view_params:
            self.slide_view_params.level_rect = self.get_current_view_scene_rect(
            ).getRect()
        self.update_labels()

    def reset_view_transform(self):
        self.view.resetTransform()
        self.view.horizontalScrollBar().setValue(0)
        self.view.verticalScrollBar().setValue(0)

    def get_current_view_scene_rect(self):
        return self.view.mapToScene(self.view.viewport().rect()).boundingRect()

    def get_current_view_scale(self):
        scale = self.view.transform().m11()
        return scale
Exemplo n.º 36
0
class Viewer(QGraphicsView):
    def __init__(self, gridsize_label, position_label, help_label):
        QGraphicsView.__init__(self)

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

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

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

        # Tracking ports

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

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

        self.initialize()

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

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

        self.update_grid()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.update_grid()

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

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

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

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

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

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

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

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


#            event.accept()

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

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

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

                new_center = self.mapToScene(rb_center)

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

            self.update_grid()

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

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

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

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

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

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

            Keyboard shortcuts:
              Esc: Reset view
              F1: Show/hide alias names
              F2: Show/hide ports
              F3: Show/hide subports (ports in underlying references)
            """
            msg = QMessageBox.about(self, 'PHIDL Help', help_str)
            msg.raise_()
Exemplo n.º 37
0
class ImageView(QGraphicsView):
    @staticmethod
    def close_enough(point1, point2):
        d = 20
        return abs(point1.x() - point2.x()) < d and abs(point1.y() -
                                                        point2.y()) < d

    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)

        self.rband = None
        self.rband_state = None
        self.rband_corner = None  # If mouse is over a corner
        self.rband_origin = QPoint()
        self.rband_endpoint = QPoint()

    def mousePressEvent(self, event):
        """Go to the next / previous image, or be able to drag the image with a hand."""
        if self.rband_state == "initial":
            self.rband = QRubberBand(QRubberBand.Rectangle, self)
            self.rband_origin = event.pos()
            self.rband.setGeometry(QRect(self.rband_origin, QSize()))
            self.rband.show()
            self.rband_state = "set-endpoint"
        elif self.rband_state == "drawn":
            if self.rband_corner == "nw":
                self.rband_state = "set-origin"
            elif self.rband_corner == "se":
                self.rband_state = "set-endpoint"
            elif self.rband_corner == "inside":
                self.rband_state = "move"
                self.setCursor(QCursor(Qt.ClosedHandCursor))
                self.rband_previous_pos = event.pos()
        else:
            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 mouseMoveEvent(self, event):
        if self.rband_state == "set-endpoint":
            self.rband.setGeometry(
                QRect(self.rband_origin, event.pos()).normalized())
            self.rband_endpoint = event.pos()
        elif self.rband_state == "set-origin":
            self.rband.setGeometry(
                QRect(event.pos(), self.rband_endpoint).normalized())
            self.rband_origin = event.pos()
        elif self.rband_state == "move":
            old_pos = self.rband.geometry()
            new_pos = old_pos.translated(event.pos() - self.rband_previous_pos)
            trace(0)
            self.rband.setGeometry(new_pos)
            self.rband_previous_pos = event.pos()
        elif self.rband_state == "drawn":
            if ImageView.close_enough(self.rband_origin, event.pos()):
                self.rband_corner = "nw"
                self.setCursor(QCursor(Qt.SizeFDiagCursor))
            elif ImageView.close_enough(self.rband_endpoint, event.pos()):
                self.rband_corner = "se"
                self.setCursor(QCursor(Qt.SizeFDiagCursor))
            elif self.rband.geometry().contains(event.pos()):
                self.rband_corner = "inside"
                self.setCursor(QCursor(Qt.OpenHandCursor))
            else:
                self.rband_corner = None
                self.setCursor(QCursor(Qt.ArrowCursor))
        QGraphicsView.mouseMoveEvent(self, event)

    def mouseReleaseEvent(self, event):
        #print("State %s", self.rband_state)
        if self.rband_state == "set-endpoint" or self.rband_state == "set-origin":
            self.rband_state = "drawn"
        elif self.rband_state == "move":
            self.setCursor(QCursor(Qt.ArrowCursor))
            self.rband_state = "drawn"
            self.rband_origin = self.rband.geometry().topLeft()
            self.rband_endpoint = self.rband.geometry().bottomRight()
        else:
            self.setCursor(QCursor(Qt.ArrowCursor))
            self.setDragMode(QGraphicsView.NoDrag)
        QGraphicsView.mouseReleaseEvent(self, event)

    def keyPressEvent(self, event):
        if self.rband_state == "drawn":
            if event.key() == Qt.Key_Escape:
                self.setCursor(QCursor(Qt.ArrowCursor))
                self.rband.hide()
                self.rband_state = None
                self.setMouseTracking(False)
            elif event.key() in [Qt.Key_Return, Qt.Key_Enter, Qt.Key_Space]:
                self.setCursor(QCursor(Qt.ArrowCursor))
                self.rband.hide()
                self.rband_state = None
                self.setMouseTracking(False)
                #print("CB ", self.get_coords())
                self.crop_callback(self.get_coords())
        event.accept()

    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 crop(self, callback):
        self.crop_callback = callback
        self.rband_state = "initial"
        self.setMouseTracking(True)

    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)
Exemplo n.º 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()
Exemplo n.º 39
0
class QMainLabel(QLabel):
    def __init__(self, parentQWidget):
        super(QMainLabel, self).__init__(parentQWidget)
        self.original_image_pixmap = None
        self.original_mask_pixmap = None
        self.target_size = self.parent().main_label_size

    def set_size(self, size):
        self.target_size = size

    def load_pixmap(self, image, mask=None):
        self.original_image_pixmap = QPixmap(image)

        if mask:
            self.original_mask_pixmap = QPixmap(mask)
            combo = self.merge_image_mask(self.original_image_pixmap,
                                          self.original_mask_pixmap)
            self.setPixmap(combo)
            return

        self.setPixmap(self.original_image_pixmap)

    def merge_image_mask(self, image, mask):

        print(type(image), type(mask))

        if type(image) == QPixmap and type(mask) == QPixmap:
            pil_image = ImageQt.fromqpixmap(image)
            pil_mask = ImageQt.fromqpixmap(mask)
        else:
            pil_image = image
            pil_mask = mask

        np_image = np.array(pil_image)
        np_mask = np.array(pil_mask)

        print(np_image.shape, np_mask.shape)

        prob = np.float32(np_mask) / 255.0
        np_combo = np.uint8(np_image * (1 - prob) +
                            np_mask * prob * np.array([[[0., 1., 0.]]]))

        pil_combo = Image.fromarray(np_combo)
        combo = ImageQt.toqpixmap(pil_combo)

        return combo

    def restore_original(self):
        print('Ctrl+Z')

        image = self.original_image_pixmap
        mask = self.original_mask_pixmap

        if image and mask:
            image = self.merge_image_mask(image, mask)

        self.setPixmap(image)

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

    def mouseMoveEvent(self, eventQMouseEvent):
        self.currentQRubberBand.setGeometry(
            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')

        crop_PIL = ImageQt.fromqpixmap(cropQPixmap)
        crop_PIL = pad_to_square(crop_PIL, self.target_size)
        cropQPixmap = ImageQt.toqpixmap(crop_PIL)
        self.setPixmap(cropQPixmap)
Exemplo n.º 40
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: self._prev.state = states.normal
        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):
        points = self.pointsAt(position)
        index = self.points().tolist().index(points[0]) if points else None
        return index

    # 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