示例#1
0
    def drawBg(self, event, painter):
        painter.save()
        painter.setPen(Qt.NoPen)

        if self.checked:
            painter.setBrush(self.bgColorOn)
        else:
            painter.setBrush(self.bgColorOff)

        rect = QRect(0, 0, self.width(), self.height())
        # 半径为高度的一半
        radius = rect.height() / 2
        # 圆的宽度为高度
        circleWidth = rect.height()

        path = QPainterPath()
        path.moveTo(radius, rect.left())
        path.arcTo(QRectF(rect.left(), rect.top(), circleWidth, circleWidth),
                   90, 180)
        path.lineTo(rect.width() - radius, rect.height())
        path.arcTo(
            QRectF(rect.width() - rect.height(), rect.top(), circleWidth,
                   circleWidth), 270, 180)
        path.lineTo(radius, rect.top())

        painter.drawPath(path)
        painter.restore()
示例#2
0
 def paintHorizontalCell(self, painter: QPainter, hv: QHeaderView,
                         cellIndex: QModelIndex, leafIndex: QModelIndex,
                         logicalLeafIndex: int,
                         styleOptions: QStyleOptionHeader,
                         sectionRect: QRect, top: int):
     uniopt = QStyleOptionHeader(styleOptions)
     self.setForegroundBrush(uniopt, cellIndex)
     self.setBackgroundBrush(uniopt, cellIndex)
     height = self.cellSize(cellIndex, hv, uniopt).height()
     if cellIndex == leafIndex:
         height = sectionRect.height() - top
     left = self.currentCellLeft(cellIndex, leafIndex, logicalLeafIndex,
                                 sectionRect.left(), hv)
     width = self.currentCellWidth(cellIndex, leafIndex,
                                   logicalLeafIndex, hv)
     r = QRect(left, top, width, height)
     uniopt.text = cellIndex.data(Qt.DisplayRole)
     painter.save()
     uniopt.rect = r
     if cellIndex.data(Qt.UserRole):
         hv.style().drawControl(QStyle.CE_HeaderSection, uniopt,
                                painter, hv)
         m = QTransform()
         m.rotate(-90)
         painter.setWorldMatrix(m, True)
         new_r = QRect(0, 0, r.height(), r.width())
         new_r.moveCenter(QPoint(-r.center().y(), r.center().x()))
         uniopt.rect = new_r
         hv.style().drawControl(QStyle.CE_HeaderLabel, uniopt, painter,
                                hv)
     else:
         hv.style().drawControl(QStyle.CE_Header, uniopt, painter, hv)
     painter.restore()
     return top + height
示例#3
0
    def drawBox(self, painter):
        """ Paint box """
        color = self._color
        rect = QRect(0, 0, self._box_sqsize, self._box_sqsize)

        for sz in range(3):
            painter.setPen(color.lighter(200 // (sz + 1)))
            painter.drawRect(rect.x() + sz,
                             rect.y() + sz,
                             rect.width() - (sz * 2),
                             rect.height() - (sz * 2))

        painter.fillRect(rect.x() + 3,
                         rect.y() + 3,
                         rect.width() - 6,
                         rect.height() - 6, color.lighter(200))

        if self._checked:
            painter.setPen(QColor(0, 0, 0))
            painter.drawLine(rect.x() + 2,
                             rect.y() + (rect.height() // 2),
                             rect.width() // 2,
                             rect.y() + (rect.height() - 2))

            painter.drawLine(rect.width() // 2,
                             rect.y() + (rect.height() - 2),
                             rect.width() - 1,
                             rect.y() + 2)
示例#4
0
    def centerMultiScreen(self):
        mouse_pointer_position = QApplication.desktop().cursor().pos()
        screen = QApplication.desktop().screenNumber(mouse_pointer_position)
        print("current screen " + str(screen))

        self.window_one = QRect(QApplication.desktop().screenGeometry(0))
        self.window_two = QRect(QApplication.desktop().screenGeometry(1))

        if screen == 0:
            window_geometry = QRect(QApplication.desktop().screenGeometry(1))
            self.resize(window_geometry.width(), window_geometry.height())
            center_point = QApplication.desktop().screenGeometry(1).center()
            self.arrowsSet.height_k = (self.window_two.height() / self.window_one.height())
            self.arrowsSet.width_k = (self.window_two.width() / self.window_one.width())
        elif screen == 1:
            window_geometry = QRect(QApplication.desktop().screenGeometry(0))
            self.resize(window_geometry.width(), window_geometry.height())
            center_point = QApplication.desktop().screenGeometry(0).center()
            self.arrowsSet.height_k = (self.window_one.height() / self.window_two.height())
            self.arrowsSet.width_k = (self.window_one.width() / self.window_two.width())
        else:
            window_geometry = self.frameGeometry()
            center_point = QDesktopWidget.availableGeometry().center()
        window_geometry.moveCenter(center_point)
        self.move(window_geometry.topLeft())
示例#5
0
    def _calculate_output_image_parameters(self,
                                           web_viewport: QRect,
                                           img_width: Optional[int],
                                           img_height: Optional[int]
                                           ) -> Tuple[QRect, QSize]:
        """
        Calculate parameters of the resulting image to render - coordinates
        and size of rescaled and truncated image. Return
        ``(image_viewport, image_size)`` tuple.

        ``web_viewport`` is a QRect to render, in webpage coordinates.

        FIXME: add tests for it, to make the behavior clear.
        """
        if img_width is None:
            img_width = web_viewport.width()
            ratio = 1.0
        else:
            if img_width == 0 or web_viewport.width() == 0:
                ratio = 1.0
            else:
                ratio = img_width / float(web_viewport.width())
        image_viewport = QRect(
            QPoint(0, 0),
            QSize(img_width, round(web_viewport.height() * ratio)))
        if img_height is None:
            img_height = image_viewport.height()
        image_size = QSize(img_width, img_height)
        return image_viewport, image_size
示例#6
0
class ElevationSquare(QGraphicsItem):
    """A red-green filled square with altitudes"""
    def __init__(self, start, end, levels, parent=None):
        super().__init__(parent)
        self.start, self.end = start, end
        self.levels = levels
        self.rect = QRect(0, 0, 100, 100)

    def paint(self, painter: QPainter, option, widget=None):
        painter.setPen(QPen(Qt.black, 0))
        self.rect = getRect(widget)

        gradient = QLinearGradient(self.rect.topLeft(), self.rect.bottomLeft())
        gradient.setColorAt(0, Qt.red)
        gradient.setColorAt(1, Qt.green)
        painter.setBrush(gradient)
        painter.drawRect(self.rect)

        metrics = painter.fontMetrics()
        for level in self.levels:
            text = str(int(level))
            w, h = metrics.width(text), metrics.height()
            y = self.rect.height() - (level - self.start) / (
                self.end -
                self.start) * self.rect.height() + self.rect.y() - h / 2
            x = self.rect.x() - w - 10
            text_rect = QRectF(x, y, w, h)
            painter.drawText(text_rect, Qt.AlignRight, text)

    def boundingRect(self):
        adjust = 2
        return QRectF(self.rect.x() - adjust,
                      self.rect.y() - adjust,
                      self.rect.width() + adjust,
                      self.rect.height() + adjust)
示例#7
0
    def setTrackGeometry(self, rect: QtCore.QRect, sidebar_width: int,
                         separator_height: int, show_top_sep: bool) -> None:
        handle_width = sidebar_width

        if show_top_sep:
            self.top_separator.setVisible(True)
            self.top_separator.setGeometry(rect.x(),
                                           rect.y() - separator_height,
                                           rect.width(), separator_height)
        else:
            self.top_separator.setVisible(False)

        self.handle.setVisible(True)
        self.handle.setGeometry(rect.x(), rect.y(), handle_width,
                                rect.height())

        self.track_editor.setVisible(True)
        self.track_editor.setGeometry(rect.x() + handle_width, rect.y(),
                                      rect.width() - handle_width,
                                      rect.height())

        self.__hide_label_small_track = (rect.height() <
                                         self.label.height() + 4)
        self.label.move(rect.x() + handle_width + 4, rect.y() + 2)
        self.label.setVisible(not self.__hide_label_under_mouse
                              and not self.__hide_label_small_track)

        self.separator.setVisible(True)
        self.separator.setGeometry(rect.x(),
                                   rect.y() + rect.height(), rect.width(),
                                   separator_height)
示例#8
0
    def paintEvent(self, e: QPaintEvent) -> None:
        painter = QPainter(self)
        painter.setPen(QPen(Qt.black, 2))
        # paint background
        brush = QBrush()
        brush.setColor(QColor('black'))
        brush.setStyle(Qt.SolidPattern)
        rect = QRect(0, 0, painter.device().width(), painter.device().height())
        painter.fillRect(rect, brush)

        pix_ratio = self.pix.rect().width() / self.pix.rect().height()
        w_ratio = rect.width() / rect.height()

        if pix_ratio > w_ratio:
            w = rect.width()
            h = rect.width() / pix_ratio
            x = 0
            y = (rect.height() - h) / 2
        else:
            h = rect.height()
            w = rect.height() * pix_ratio
            x = (rect.width() - w) / 2
            y = 0
        self.pix_rect = QRect(int(x), int(y), int(w), int(h))
        painter.drawPixmap(self.pix_rect, self.pix, self.pix.rect())

        for rid, r in self.robot_manager.robots.items():
            pos = r.pos.pos
            xr = pos.x * w / 3000 + x
            yr = (2000 - pos.y) * h / 2000 + y
            painter.setBrush(Qt.red)
            center = QPoint(int(xr), int(yr))
            painter.drawEllipse(center, ROBOT_SIZE, ROBOT_SIZE)
            head = center + QPoint(ROBOT_SIZE * cos(-pos.theta),
                                   ROBOT_SIZE * sin(-pos.theta))
            painter.setPen(QPen(Qt.black, 2))
            painter.drawLine(center, head)
            a1 = head + QPoint(ARROW_SIZE * cos(-pos.theta + ARROW_ANGLE),
                               ARROW_SIZE * sin(-pos.theta + ARROW_ANGLE))
            a2 = head + QPoint(ARROW_SIZE * cos(-pos.theta - ARROW_ANGLE),
                               ARROW_SIZE * sin(-pos.theta - ARROW_ANGLE))
            painter.setBrush(Qt.black)
            painter.drawPolygon(a1, head, a2)

        pos_cmd = self.getPosCmd()
        if pos_cmd is not None:
            x, y, theta = pos_cmd
            if theta is not None:
                painter.drawLine(self.press_pos.x(), self.press_pos.y(),
                                 self.current_pos.x(), self.current_pos.y())
                a1 = self.current_pos + QPoint(
                    ARROW_SIZE * cos(-theta + ARROW_ANGLE),
                    ARROW_SIZE * sin(-theta + ARROW_ANGLE))
                a2 = self.current_pos + QPoint(
                    ARROW_SIZE * cos(-theta - ARROW_ANGLE),
                    ARROW_SIZE * sin(-theta - ARROW_ANGLE))
                painter.setBrush(Qt.black)
                painter.drawPolygon(a1, self.current_pos, a2)
示例#9
0
class VisualWindow(QWidget):
    def __init__(self, parent=None):
        super(VisualWindow, self).__init__(parent)
        self.setWindowFlags(QtCore.Qt.Dialog)
        self.arrowsSet = Arrows()
        self.initUI()

    def initUI(self):
        self.setLayout(self.arrowsSet)
        self.setColorPalette(confParser.config_file.read("color", "bg_color"))
        self.setHidden(True)

    def find_available_desktops(self):
        number_available_desktops = QDesktopWidget().screenCount()
        if number_available_desktops > 1:
            self.centerMultiScreen()
        else:
            self.centerSingleScreen()

    def centerSingleScreen(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def centerMultiScreen(self):
        mouse_pointer_position = QApplication.desktop().cursor().pos()
        screen = QApplication.desktop().screenNumber(mouse_pointer_position)
        print("current screen " + str(screen))

        self.window_one = QRect(QApplication.desktop().screenGeometry(0))
        self.window_two = QRect(QApplication.desktop().screenGeometry(1))

        if screen == 0:
            window_geometry = QRect(QApplication.desktop().screenGeometry(1))
            self.resize(window_geometry.width(), window_geometry.height())
            center_point = QApplication.desktop().screenGeometry(1).center()
            self.arrowsSet.height_k = (self.window_two.height() / self.window_one.height())
            self.arrowsSet.width_k = (self.window_two.width() / self.window_one.width())
        elif screen == 1:
            window_geometry = QRect(QApplication.desktop().screenGeometry(0))
            self.resize(window_geometry.width(), window_geometry.height())
            center_point = QApplication.desktop().screenGeometry(0).center()
            self.arrowsSet.height_k = (self.window_one.height() / self.window_two.height())
            self.arrowsSet.width_k = (self.window_one.width() / self.window_two.width())
        else:
            window_geometry = self.frameGeometry()
            center_point = QDesktopWidget.availableGeometry().center()
        window_geometry.moveCenter(center_point)
        self.move(window_geometry.topLeft())

    def setColorPalette(self, current_bg_color):
        confParser.config_file.write("color", "bg_color", current_bg_color)
        background_color = QColor()
        background_color.setNamedColor(current_bg_color)
        p = self.palette()
        p.setColor(self.backgroundRole(), background_color)
        self.setPalette(p)
示例#10
0
    def paintEvent(self, e):

        painter = QPainter(self)

        draw_rect = e.rect()

        # SLIDER---------------------------------------------------------------------

        # BAR --------

        painter.setPen(self._bgColor.lighter(200))

        painter.drawRect(draw_rect.adjusted(0, 0, -1, -1))

        painter.fillRect(draw_rect.adjusted(1, 1, -1, -1), self._bgColor)

        # THUMB --------

        painter.setPen(self._thumbColor.lighter())

        painter.drawRect(self._thumbRect.adjusted(0, 0, -1, -1))

        painter.fillRect(self._thumbRect.adjusted(1, 1, -1, -1),
                         self._thumbColor)

        # VALUE LABEL --------

        value_text = str(self._value)

        value_label_size = QSize(self._fontMetrics.width(value_text),
                                 self._fontMetrics.height())

        value_indicator_rect = QRect(self._thumbRect.right() + 2,
                                     self._thumbRect.top(),
                                     value_label_size.width() + 10,
                                     self._thumbRect.height())

        if value_indicator_rect.right() > draw_rect.right():
            value_indicator_rect.setRect(
                self._thumbRect.left() - value_indicator_rect.width() - 1,
                value_indicator_rect.top(), value_indicator_rect.width(),
                value_indicator_rect.height())

        painter.setPen(self._indicatorColor.lighter())

        painter.drawRect(value_indicator_rect.adjusted(0, 0, -1, -1))

        painter.fillRect(value_indicator_rect.adjusted(1, 1, -1, -1),
                         self._indicatorColor)

        painter.setPen(Qt.white)

        painter.drawText(
            value_indicator_rect.left() + value_indicator_rect.width() / 2 -
            value_label_size.width() / 2,
            value_indicator_rect.top() + value_indicator_rect.height() / 2 +
            value_label_size.height() / 3, value_text)
示例#11
0
 def paintEvent(self, event):
     QWidget.paintEvent(self, event)
     width, height = self.width(), self.height()
     polygon = QPolygon()
     for i, rate in enumerate(self.loads):
         x = width - i * self.pointDistance
         y = height - rate * height
         if x < self.boxWidth:
             break
         polygon.append(QPoint(x, y))
     painter = QPainter(self)
     pen = QPen()
     pen.setColor(Qt.darkGreen)
     painter.setPen(pen)
     painter.setRenderHint(QPainter.Antialiasing, True)
     #画网格
     painter.setOpacity(0.5)
     gridSize = self.pointDistance * 4
     deltaX = (width - self.boxWidth) % gridSize + self.boxWidth
     deltaY = height % gridSize
     for i in range(int(width / gridSize)):
         x = deltaX + gridSize * i
         painter.drawLine(x, 0, x, height)
     for j in range(int(height / gridSize)):
         y = j * gridSize + deltaY
         painter.drawLine(self.boxWidth, y, width, y)
     #画折线
     pen.setColor(Qt.darkCyan)
     pen.setWidth(2)
     painter.setPen(pen)
     painter.setOpacity(1)
     painter.drawPolyline(polygon)
     #画展示框
     if len(self.loads) > 0:
         rate = self.loads[0]
     else:
         rate = 1.0
     rect1 = QRect(4, height * 0.05, self.boxWidth - 9, height * 0.7)
     rect2 = QRect(4, height * 0.8, self.boxWidth - 9, height * 0.2)
     centerX = int(rect1.width() / 2) + 1
     pen.setWidth(1)
     for i in range(rect1.height()):
         if i % 4 == 0:
             continue
         if (rect1.height() - i) / rect1.height() > rate:
             pen.setColor(Qt.darkGreen)
         else:
             pen.setColor(Qt.green)
         painter.setPen(pen)
         for j in range(rect1.width()):
             if centerX - 1 <= j <= centerX + 1:
                 continue
             painter.drawPoint(rect1.x() + j, rect1.y() + i)
     pen.setColor(Qt.black)
     painter.setPen(pen)
     painter.drawText(rect2, Qt.AlignHCenter | Qt.AlignVCenter, str(int(rate * 100)) + "%")
示例#12
0
 def _calculate_tiling(self, to_paint: QRect) -> _TilingOptions:
     tile_maxsize = defaults.TILE_MAXSIZE
     tile_hsize = min(tile_maxsize, to_paint.width())
     tile_vsize = min(tile_maxsize, to_paint.height())
     htiles = 1 + (to_paint.width() - 1) // tile_hsize
     vtiles = 1 + (to_paint.height() - 1) // tile_vsize
     tile_size = QSize(tile_hsize, tile_vsize)
     return _TilingOptions(horizontal_count=htiles,
                           vertical_count=vtiles,
                           tile_size=tile_size)
示例#13
0
    def font_charBmp(font, char):
        metric = QFontMetrics(font).boundingRect(char)
        char_rect = QRect(0, 0, metric.width() + 1, metric.height())
        chr_img = QImage(char_rect.width() + 1, char_rect.height(),
                         QImage.Format_Mono)
        chr_img.fill(0)

        # set img painter and draw char to bmp
        painter = QPainter(chr_img)
        painter.setPen(QPen(Qt.white))
        painter.setFont(font)
        painter.drawText(char_rect, Qt.AlignJustify, char)
        painter.end()
        del (painter)

        # crop left / right
        x0 = 0
        x1 = char_rect.width()
        while x0 < x1 - 1:
            data_col = 0
            for col in range(char_rect.height()):
                data_col += chr_img.pixel(x0, col) & 0x00FFFFFF
            if not data_col:
                x0 += 1
            else:
                break
        char_rect.setX(x0)

        while x1 > x0 + 1:
            x1 -= 1
            data_col = 0
            for col in range(char_rect.height()):
                data_col += chr_img.pixel(x1, col) & 0x00FFFFFF
            if not data_col:
                char_rect.setWidth(x1 - x0)
            else:
                break

        # crop bottom
        y1 = char_rect.height()
        while y1 > 1:
            y1 -= 1
            data_row = 0
            for row in range(char_rect.width()):
                data_row += chr_img.pixel(row, y1) & 0x00FFFFFF
            if not data_row:
                char_rect.setHeight(y1)
            else:
                break

        chr_img = chr_img.copy(char_rect)
        # chr_img.save( '.\\img\\0%s.bmp' % char, 'bmp' )
        return chr_img
示例#14
0
class GraphicsTile(QGraphicsItem):
    def __init__(self, x_y_w_h, slide_path, level, downsample):
        super().__init__()
        self.x_y_w_h = x_y_w_h
        self.slide_rect_0 = QRect(int(x_y_w_h[0] * downsample),
                                  int(self.x_y_w_h[1] * downsample),
                                  x_y_w_h[2], x_y_w_h[3])
        self.slide_path = slide_path
        self.level = level
        self.downsample = downsample
        self.setAcceptedMouseButtons(Qt.NoButton)
        self.setAcceptHoverEvents(True)
        self.cache_key = slide_path + str(level) + str(self.slide_rect_0)

        # self.setCacheMode(QGraphicsItem.ItemCoordinateCache, self.rect.size())
        # self.setFlag(QGraphicsItem.ItemClipsToShape, True)

    def pilimage_to_pixmap(self, pilimage):
        qim = ImageQt(pilimage)
        pix = QtGui.QPixmap.fromImage(qim)
        return pix

    def boundingRect(self):
        return QRectF(0, 0, self.slide_rect_0.width(),
                      self.slide_rect_0.height())

    def paint(self,
              painter: QtGui.QPainter,
              option: QStyleOptionGraphicsItem,
              widget: typing.Optional[QWidget] = ...):
        # print("pos ", self.pos())
        # print("paint ", self.slide_rect_0, option.rect, option.exposedRect)
        self.pixmap = QPixmapCache.find(self.cache_key)
        if not self.pixmap:
            # print("read", self.slide_rect_0)
            with openslide.open_slide(self.slide_path) as slide:
                tile_pilimage = slide.read_region(
                    (self.slide_rect_0.x(), self.slide_rect_0.y()), self.level,
                    (self.slide_rect_0.width(), self.slide_rect_0.height()))
                self.pixmap = self.pilimage_to_pixmap(tile_pilimage)
                QPixmapCache.insert(self.cache_key, self.pixmap)

        # painter.drawPixmap(self.slide_rect_0, self.pixmap)
        painter.drawPixmap(self.boundingRect().toRect(), self.pixmap)

    def __str__(self) -> str:
        return "{}: slide_path: {}, slide_rect_0: {}".format(
            self.__class__.__name__, self.slide_path, self.slide_rect_0)

    def __repr__(self) -> str:
        return self.__str__()
示例#15
0
    def setGeometry(self, rect: QtCore.QRect, maxPriority: int) -> None:
        min_sizes = []
        children = []
        stretch_weights = []
        if self.__orientation == Qt.Horizontal:
            total_size = rect.width()
        else:
            total_size = rect.height()

        first = True
        for child in self.children():
            if child.hasContent(maxPriority):
                if not first:
                    total_size -= self.spacing()
                    first = False

                child.setVisible(True)
                if self.__orientation == Qt.Horizontal:
                    child_min_size = child.minimumSize(maxPriority).width()
                else:
                    child_min_size = child.minimumSize(maxPriority).height()
                min_sizes.append(child_min_size)
                children.append(child)
                stretch_weights.append(child.stretch())

            else:
                child.setVisible(False)

        sizes = self._computeSizes(total_size, children, min_sizes,
                                   stretch_weights)

        if self.__orientation == Qt.Horizontal:
            pos = rect.left()
        else:
            pos = rect.top()

        for idx, child in enumerate(children):
            if idx > 0:
                pos += self.spacing()

            size = sizes[idx]
            if self.__orientation == Qt.Horizontal:
                child.setGeometry(
                    QtCore.QRect(pos, rect.top(), size, rect.height()),
                    maxPriority)
            else:
                child.setGeometry(
                    QtCore.QRect(rect.left(), pos, rect.width(), size),
                    maxPriority)

            pos += size
示例#16
0
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget
        @type QWidget
        """
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)
        screenSize = QRect()
        desktop = QDesktopWidget()
        screenSize = desktop.availableGeometry(self)

        aps_ratio = 83 / 100  # set prefer ratio if you want

        height = screenSize.height() * aps_ratio
        print('height', height, screenSize.width(), screenSize.height())
        self.setFixedSize(screenSize.width(), height)

        self.prevGraphicsView.setFrameShape(QFrame.NoFrame)
        self.currGraphicsView.setFrameShape(QFrame.NoFrame)

        self.prevImgPath = ''
        self.currImgPath = ''
        self.prevXMLPath = ''
        self.currXMLPath = ''
        self.prev_image_list = None

        self.prevScene = QGraphicsScene()
        self.prevGraphicsView.setScene(self.prevScene)
        self.currScene = QGraphicsScene()
        self.currGraphicsView.setScene(self.currScene)

        self.num_of_index = ' '
        self.curr_image_list = []
        self.prev_xml_list = []
        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.origin = QPoint()

        self.prev_count_mouse_click = None
        self.curr_count_mouse_click = None

        self.prevGraphicsView.mousePressEvent = self.prev_mouse_press
        self.prevGraphicsView.mouseMoveEvent = self.prev_mouse_move
        self.prevGraphicsView.mouseReleaseEvent = self.prev_mouse_release
        self.currGraphicsView.mousePressEvent = self.curr_mouse_press
        self.currGraphicsView.mouseMoveEvent = self.curr_mouse_move
        self.currGraphicsView.mouseReleaseEvent = self.curr_mouse_release

        self.overlay = Overlay()
示例#17
0
    def font_charBmp(font, char):
        metric = QFontMetrics( font ).boundingRect( char )
        char_rect = QRect( 0, 0, metric.width(), metric.height() )
        chr_img = QImage( char_rect.width()+1, char_rect.height(), QImage.Format_Mono )
        chr_img.fill(0)

        # set img painter and draw char to bmp
        painter = QPainter( chr_img )
        painter.setPen( QPen(Qt.white) )
        painter.setFont( font )
        painter.drawText( char_rect, Qt.AlignJustify, char )
        painter.end()
        del(painter)

        # crop left / right
        x0 = 0
        x1 = char_rect.width()
        while x0 < x1 - 1:
            data_col = 0
            for col in range( char_rect.height() ):
                data_col += chr_img.pixel(x0, col) & 0x00FFFFFF
            if not data_col:
                x0 += 1
            else: break
        char_rect.setX(x0)

        while x1 > x0 + 1:
            x1 -= 1
            data_col = 0
            for col in range( char_rect.height() ):
                data_col += chr_img.pixel(x1, col) & 0x00FFFFFF
            if not data_col:
                char_rect.setWidth(x1 - x0)
            else: break

        # crop bottom
        y1 = char_rect.height()
        while y1 > 1:
            y1 -= 1
            data_row = 0
            for row in range( char_rect.width() ):
                data_row += chr_img.pixel(row, y1) & 0x00FFFFFF
            if not data_row:
                char_rect.setHeight(y1)
            else: break

        chr_img = chr_img.copy( char_rect )
        # chr_img.save( '.\\img\\0%s.bmp' % char, 'bmp' )
        return chr_img
示例#18
0
    def drawBackground(self, painter, rect):
        roomRect = QRect(rect.x() + (rect.width() - self.roomWidth) * .5,
                         rect.y() + (rect.height() - self.roomHeight) * .5,
                         self.roomWidth, self.roomHeight)
        gridWidth = roomRect.width() - (roomRect.width() % self.gridSize)
        gridHeight = roomRect.height() - (roomRect.height() % self.gridSize)
        left = int((self.roomWidth - gridWidth + 2 * roomRect.left()) * .5)
        top = int((self.roomHeight - gridHeight + 2 * roomRect.top()) * .5)
        painter.setPen(QPen(QColor("black"), 2, Qt.SolidLine))
        if self.grid:
            for x in range(left, int(roomRect.right()), self.gridSize):
                for y in range(top, int(roomRect.bottom()), self.gridSize):
                    painter.drawPoint(x, y)

        painter.drawRect(roomRect)
示例#19
0
def verticalGradient(painter: QPainter, spanRect: QRect, clipRect: QRect):
    keyColor = BASE_COLOR
    key = "verticalGradient %d %d %d %d %d" % (spanRect.width(
    ), spanRect.height(), clipRect.width(), clipRect.height(), keyColor.rgb())

    pixmap = QPixmapCache.find(key)
    if pixmap is None:
        pixmap = QPixmap(clipRect.size())
        p = QPainter(pixmap)
        rect = QRect(0, 0, clipRect.width(), clipRect.height())
        verticalGradientHelper(p, spanRect, rect)
        p.end()
        QPixmapCache.insert(key, pixmap)

    painter.drawPixmap(clipRect.topLeft(), pixmap)
示例#20
0
    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)
示例#21
0
def calculate_relative_position(parent_rect: QtCore.QRect, own_size: QtCore.QSize,
                                constraint: RelativeLayoutConstraint):
    """
    Calculates the position of the element, given its size, the position and size of the parent and a relative layout
    constraint. The position is the position of the parent plus the weighted size of the parent, the weighted size of
    the element and an offset. The weights and the offset are given by the constraint for each direction.

    :param parent_rect: parent coordinates and size as rectangle
    :param own_size: size of the element (width and height)
    :param constraint: relative layout constraint to apply
    :return: tuple of recommended x and y positions of the element
    """
    """
        Returns the left, upper corner of an object if the parent rectangle (QRect) is given and our own size (QSize)
        and a relative layout constraint (see RelativeLayoutConstraint).
    """
    x = (parent_rect.x()
         + constraint.x[0] * parent_rect.width()
         + constraint.x[1] * own_size.width()
         + constraint.x[2])
    y = (parent_rect.y()
         + constraint.y[0] * parent_rect.height()
         + constraint.y[1] * own_size.height()
         + constraint.y[2])
    return x, y
示例#22
0
 def capturedArea(self):
     captured = QRect(self.mCaptureStart, self.tilePosition()).normalized()
     if (captured.width() == 0):
         captured.adjust(-1, 0, 1, 0)
     if (captured.height() == 0):
         captured.adjust(0, -1, 0, 1)
     return captured
示例#23
0
    def paint(self, painter, option, widget=None):
        rect = QRect(self.border, self.attrH - self.radius,
                     self.attrW - self.border, self.attrH)

        self.AttrsData[self] = self.attrData
        name = self.key
        self._attrBrush.setColor(QColor(247, 151, 47, 255))
        if self.alternate:
            self._attrBrushAlt.setColor(
                convert_to_QColor([19, 17, 15, 255], True, 20))

        self._attrPen.setColor(QColor(16, 102, 162, 255))
        painter.setPen(self._attrPen)
        painter.setBrush(self._attrBrush)

        painter.drawRect(rect)
        painter.setPen(QColor(69, 149, 62, 255))
        painter.setFont(self._attrTextFont)

        if self.node.drawingConnection:
            if self.knobL.slotType == 'slot' and self.knobR.slotType == 'slot':
                painter.setPen(QColor(100, 100, 100, 255))

        textRect = QRect(rect.left() + self.radius, rect.top(),
                         rect.width() - 2 * self.radius, rect.height())
        painter.drawText(textRect, center, name)
示例#24
0
 def playVideo(self):
     """
     播放视频
     :return:
     """
     if self.playCapture.isOpened():
         ret, frame = self.playCapture.read()
         if ret:
             # self.treeview_videofiledir.setDisabled(True)
             # 获取视频播放label的大小
             s = self.picturelabel.rect()
             # frame重置大小
             R_frame = cv2.resize(frame, (QRect.width(s), QRect.height(s)))
             if R_frame.ndim == 3:
                 R_frame_RGB = cv2.cvtColor(R_frame, cv2.COLOR_BGR2RGB)
             elif R_frame.ndim == 2:
                 R_frame_RGB = cv2.cvtColor(R_frame, cv2.COLOR_GRAY2BGR)
             qImage = QtGui.QImage(R_frame_RGB[:], R_frame_RGB.shape[1],
                                   R_frame_RGB.shape[0],
                                   QtGui.QImage.Format_RGB888)
             pixmap = QPixmap.fromImage(qImage)
             self.picturelabel.setPixmap(pixmap)
         else:
             # 释放VideoCapture
             self.playCapture.release()
             # 关闭线程
             self.timer.stop()
示例#25
0
 def onRectSet(self, r: QRect):
     """Rectangle has been selected"""
     self.selected_rectangle = r
     if self.graphicsView.hasImage() and r.width() > 1 and r.height() > 1:
         self.confirm_area_action.setDisabled(False)
     else:
         self.confirm_area_action.setDisabled(True)
示例#26
0
 def request(self, qrect, along_through=None):
     assert isinstance(qrect, QRect)
     # Widen request with a 1-pixel halo, to make sure edges on the tile borders are shown.
     qrect = QRect(qrect.x(), qrect.y(), qrect.width() + 1, qrect.height() + 1)
     s = rect2slicing(qrect)
     arrayreq = self._arraySource2D.request(s, along_through)
     return SegmentationEdgesItemRequest(arrayreq, self._layer, qrect, self._is_clickable)
示例#27
0
    def is_inside_limit(limit: QRect, pos: QPoint):
        if pos.x() < limit.x() or pos.x() > limit.width():
            return False
        elif pos.y() < limit.y() or pos.y() > limit.height():
            return False

        return True
    def paintEvent(self, event):
        content_rect = self.contentsRect()
        if self.spinner_size:
            size = min(self.spinner_size, content_rect.width(),
                       content_rect.height())
        else:
            size = min(content_rect.width(), content_rect.height())
        dot_count = 5
        dot_size = int(size / dot_count) * 1.5

        spinner_rect = QRect(content_rect.left(), content_rect.top(), size,
                             size)

        painter = QPainter(self)
        painter.setClipRect(content_rect)

        if self.timer_id:
            diff_height = content_rect.height() - size
            offs_y = 0
            if diff_height > 0:
                if self.vertical_align == Qt.AlignVCenter:
                    offs_y = diff_height / 2
                elif self.vertical_align == Qt.AlignBottom:
                    offs_y = diff_height

            x_center = spinner_rect.left(
            ) + spinner_rect.width() / 2 - dot_size / 2
            y_center = spinner_rect.top(
            ) + offs_y + spinner_rect.height() / 2 - dot_size / 2

            painter.save()
            for i in range(dot_count):
                if self.counter % dot_count == i:
                    painter.setBrush(QBrush(QColor(0, 0, 0)))
                    d_size = dot_size * 1.1
                else:
                    painter.setBrush(QBrush(QColor(200, 200, 200)))
                    d_size = dot_size

                r = size / 2 - dot_size / 2
                x = r * math.cos(2 * math.pi * i / dot_count)
                y = r * math.sin(2 * math.pi * i / dot_count)
                painter.drawEllipse(x_center + x, y_center + y, d_size, d_size)
            painter.restore()

        if self.message:
            # painter.setPen(QPen(Qt.black))
            if self.font_size:
                f = painter.font()
                f.setPointSize(self.font_size)
                painter.setFont(f)

            text_rect = QRect(content_rect)
            text_rect.translate(
                spinner_rect.width() +
                SpinnerWidget.SPINNER_TO_TEXT_DISTANCE if self.timer_id else 0,
                0)
            painter.drawText(text_rect, Qt.AlignLeft | Qt.AlignVCenter,
                             self.message)
        painter.end()
示例#29
0
 def paint(self, painter, rect):
     update_rect = rect & self.rect()
     if not update_rect:
         return
     image_rect = QRect(update_rect.topLeft() - self.rect().topLeft(), update_rect.size())
     image = cache.image(self)
     self._waiting = not image
     if image:
         painter.drawImage(update_rect, image, image_rect)
     else:
         # schedule an image to be generated, if done our update() method is called
         cache.generate(self)
         # find suitable image to be scaled from other size
         image = cache.image(self, False)
         if image:
             hscale = float(image.width()) / self.width()
             vscale = float(image.height()) / self.height()
             image_rect = QRectF(image_rect.x() * hscale, image_rect.y() * vscale,
                                 image_rect.width() * hscale, image_rect.height() * vscale)
             painter.drawImage(QRectF(update_rect), image, image_rect)
         else:
             # draw blank paper, using the background color of the cache rendering (if set)
             # or from the document itself.
             color = (cache.options(self.document()).paperColor()
                      or cache.options().paperColor() or self.document().paperColor())
             painter.fillRect(update_rect, color)
示例#30
0
    def paint(self, painter, option, index):
        """Performs custom painting of value of data in the model and decorations.

         Performs custom painting of value of data in the model at the specified index
         plus any decorations used in that column.

         Args:
            painter - QPainter
            option - QStyleOptionViewItem
            index - QModelIndex
        """
        xOffset = 0
        # First added for #15, the painting of custom amount information.  This can
        # be used as a pattern for painting any column of information.
        value_painter = self._get_value_painter(index)
        self._display_text = value_painter is None
        QStyledItemDelegate.paint(self, painter, option, index)
        if value_painter is not None:
            value_option = QStyleOptionViewItem(option)
            rect = value_option.rect
            rect = QRect(rect.left(), rect.top(), rect.width() - xOffset, rect.height())
            value_option.rect = rect
            value_painter.paint(painter, value_option, index)

        decorations = self._get_decorations(index, bool(option.state & QStyle.State_Selected))
        for dec in decorations:
            pixmap = dec.pixmap
            x = option.rect.right() - pixmap.width() - xOffset
            y = option.rect.center().y() - (pixmap.height() // 2)
            rect = QRect(x, y, pixmap.width(), pixmap.height())
            painter.drawPixmap(rect, pixmap)
            xOffset += pixmap.width()
示例#31
0
    def _draw_pixmap(self, painter, option, item):
        """Draw the actual pixmap of the thumbnail.

        This calculates the size of the pixmap, applies padding and
        appropriately centers the image.

        Args:
            painter: The QPainter.
            option: The QStyleOptionViewItem.
            item: The ThumbnailItem.
        """
        painter.save()
        # Original thumbnail pixmap
        pixmap = item.icon().pixmap(256)
        # Rectangle that can be filled by the pixmap
        rect = QRect(
            option.rect.x() + self.padding,
            option.rect.y() + self.padding,
            option.rect.width() - 2 * self.padding,
            option.rect.height() - 2 * self.padding,
        )
        # Size the pixmap should take
        size = pixmap.size().scaled(rect.size(), Qt.KeepAspectRatio)
        # Coordinates to center the pixmap
        diff_x = (rect.width() - size.width()) / 2.0
        diff_y = (rect.height() - size.height()) / 2.0
        x = int(option.rect.x() + self.padding + diff_x)
        y = int(option.rect.y() + self.padding + diff_y)
        # Draw
        painter.drawPixmap(x, y, size.width(), size.height(), pixmap)
        painter.restore()
        if item.marked:
            self._draw_mark(painter, option, x + size.width(),
                            y + size.height())
示例#32
0
    def __init__(self, parent: QWidget, rect: QRect = None):
        super().__init__(parent)

        if rect is None:
            x = parent.x() + parent.width() / 2 - 150
            y = parent.y() + parent.height() / 2 - 50
            window_rect = QRect(x, y, 300, 100)
        else:
            x = rect.x() + rect.width() / 2 - 150
            y = rect.y() + rect.height() / 2 - 100
            window_rect = QRect(x, y, 300, 100)
        self.setGeometry(window_rect)

        self.action = QHBoxLayout()
        self.action.addStretch()
        self.action.addStretch()

        self.text = QLabel()
        self.text.setWordWrap(True)
        self.text.setStyleSheet("color:#666666;")

        layout = QVBoxLayout()
        layout.setSpacing(18)
        layout.addWidget(self.text, alignment=Qt.AlignTop)
        layout.addLayout(self.action)
        layout.setContentsMargins(12, 12, 12, 0)

        widget = QWidget()
        widget.setLayout(layout)
        widget.setContentsMargins(0, 8, 0, 0)
        widget.setObjectName(Parapluie.Object_Raised_Off)
        self.setCentralWidget(widget)
示例#33
0
    def __init__(self, pos: QRect, inputSlot, editor=None, scene=None, parent=None, qcolor=QColor(0, 0, 255)):
        """
        Couples the functionality of the lazyflow operator OpSubRegion which gets a subregion of interest
        and the functionality of the resizable rectangle Item.
        Keeps the two functionality separated


        :param pos: initial position
        :param inputSlot: Should be the output slot of another operator from which you would like monitor a subregion
        :param scene: the scene where to put the graphics item
        :param parent: the parent object if any
        :param qcolor: initial color of the rectangle
        """
        assert inputSlot.meta.getTaggedShape()["c"] == 1

        assert parent is None, "FIXME: QT structure does not seem to be implemented thoroughly. parent is always None!"
        self._rectItem = QGraphicsResizableRect(pos.x(), pos.y(), pos.height(), pos.width(), scene, parent, editor)
        # self._rectItem.color=qcolor  # FIXME: color can't be set

        # sub region corresponding to the rectangle region
        self._opsub = OpSubRegion(graph=inputSlot.operator.graph, parent=inputSlot.operator.parent)

        self._inputSlot = inputSlot  # input slot which connect to the sub array

        self.boxLabel = None  # a reference to the label in the labellist model
        self._initConnect()
    def _draw_volume(self, painter, within_bounds=True, clip_screen=True):
        if within_bounds:
            (bounds, render_uv) = self._bounds2uv(self._screen_bounds_display,
                                                  self._scale_display,
                                                  clip_screen=clip_screen)
            draw_rect = QRect(QPoint(*bounds[0]), QPoint(*bounds[1]))
        else:
            render_uv = [(-1, 1), (1, -1)]
            draw_rect = self.rect()

        self._resolution_display = [
            draw_rect.width() // self._scale_display,
            draw_rect.height() // self._scale_display
        ]

        job = RenderJob(modelview=self._view * self._model *
                        self._state.aspect_xform,
                        projection=self._projection,
                        resolution=self._resolution_display,
                        uv=render_uv,
                        rect=draw_rect)
        self._state.display_volume.render(job)

        render = self._state.display_volume.last_render
        if render is not None and render.image is not None:
            self._render_times.append(render.duration)
            painter.drawImage(
                render.rect,
                QImage(render.image, render.image.shape[1],
                       render.image.shape[0], QImage.Format_RGBA8888))
 def paintEvent(self, e):
     '''
     重写绘图事件
     '''
     painter = QPainter(self)
     if self.display_image is None:
         painter.setPen(Qt.black)
         painter.setFont(QFont("Arial", 30))
         painter.drawText(e.rect(), Qt.AlignCenter, "Identity Finder")
     else:
         window_rect = self.rect()
         image_rect = QRect(0, 0, self.display_width, self.display_height)
         ratio_of_image = image_rect.width() / image_rect.height()
         ratio_of_window = window_rect.width() / window_rect.height()
         if ratio_of_image > ratio_of_window:
             window_rect.setHeight(window_rect.width()/ratio_of_image)
             delta = (self.rect().height()-window_rect.height())*0.5
             window_rect.setY(delta)
             window_rect.setHeight(window_rect.height()+delta)
         else:
             window_rect.setWidth(window_rect.height()*ratio_of_image)
             delta = (self.rect().width()-window_rect.width())*0.5
             window_rect.setX(delta)
             window_rect.setWidth(window_rect.width()+delta)
         painter.drawImage(window_rect, self.display_image, image_rect)
     return
示例#36
0
 def subControlRect(self, control, option, subControl, widget=None):
     rect = super(SliderStyle, self).subControlRect(
         control, option, subControl, widget)
     if subControl == QStyle.SC_SliderHandle:
         if option.orientation == Qt.Horizontal:
             # 高度1/3
             radius = int(widget.height() / 3)
             offset = int(radius / 3)
             if option.state & QStyle.State_MouseOver:
                 x = min(rect.x() - offset, widget.width() - radius)
                 x = x if x >= 0 else 0
             else:
                 radius = offset
                 x = min(rect.x(), widget.width() - radius)
             rect = QRect(x, int((rect.height() - radius) / 2),
                          radius, radius)
         else:
             # 宽度1/3
             radius = int(widget.width() / 3)
             offset = int(radius / 3)
             if option.state & QStyle.State_MouseOver:
                 y = min(rect.y() - offset, widget.height() - radius)
                 y = y if y >= 0 else 0
             else:
                 radius = offset
                 y = min(rect.y(), widget.height() - radius)
             rect = QRect(int((rect.width() - radius) / 2),
                          y, radius, radius)
         return rect
     return rect
示例#37
0
 def __updateHandles(self):
     """
     Private method to update the handles.
     """
     r = QRect(self.__selection)
     s2 = self.__handleSize // 2
     
     self.__TLHandle.moveTopLeft(r.topLeft())
     self.__TRHandle.moveTopRight(r.topRight())
     self.__BLHandle.moveBottomLeft(r.bottomLeft())
     self.__BRHandle.moveBottomRight(r.bottomRight())
     
     self.__LHandle.moveTopLeft(QPoint(r.x(), r.y() + r.height() // 2 - s2))
     self.__THandle.moveTopLeft(QPoint(r.x() + r.width() // 2 - s2, r.y()))
     self.__RHandle.moveTopRight(
         QPoint(r.right(), r.y() + r.height() // 2 - s2))
     self.__BHandle.moveBottomLeft(
         QPoint(r.x() + r.width() // 2 - s2, r.bottom()))
示例#38
0
    def apply_selection(self, rect: QRect):
        self.selection_active = False

        self.group.set_position(rect.x(), rect.y())
        self.group.set_size(rect.width(), rect.height())

        if self.rect_was_displayed and self.visibility_checkbox.isChecked():
            self.__add_roi_rect()
        self.rect_was_displayed = False
示例#39
0
 def __normalizeSelection(self, sel):
     """
     Private method to normalize the given selection.
     
     @param sel selection to be normalized (QRect)
     @return normalized selection (QRect)
     """
     rect = QRect(sel)
     if rect.width() <= 0:
         left = rect.left()
         width = rect.width()
         rect.setLeft(left + width - 1)
         rect.setRight(left)
     if rect.height() <= 0:
         top = rect.top()
         height = rect.height()
         rect.setTop(top + height - 1)
         rect.setBottom(top)
     return rect
示例#40
0
    def _paint_icon(self, iconic, painter, rect, mode, state, options):
        """Paint a single icon."""
        painter.save()
        color = options['color']
        char = options['char']

        color_options = {
            QIcon.On: {
                QIcon.Normal: (options['color_on'], options['on']),
                QIcon.Disabled: (options['color_on_disabled'],
                                 options['on_disabled']),
                QIcon.Active: (options['color_on_active'],
                               options['on_active']),
                QIcon.Selected: (options['color_on_selected'],
                                 options['on_selected'])
            },

            QIcon.Off: {
                QIcon.Normal: (options['color_off'], options['off']),
                QIcon.Disabled: (options['color_off_disabled'],
                                 options['off_disabled']),
                QIcon.Active: (options['color_off_active'],
                               options['off_active']),
                QIcon.Selected: (options['color_off_selected'],
                                 options['off_selected'])
            }
        }

        color, char = color_options[state][mode]

        painter.setPen(QColor(color))

        # A 16 pixel-high icon yields a font size of 14, which is pixel perfect
        # for font-awesome. 16 * 0.875 = 14
        # The reason why the glyph size is smaller than the icon size is to
        # account for font bearing.

        draw_size = 0.875 * qRound(rect.height() * options['scale_factor'])
        prefix = options['prefix']

        # Animation setup hook
        animation = options.get('animation')
        if animation is not None:
            animation.setup(self, painter, rect)

        painter.setFont(iconic.font(prefix, draw_size))
        if 'offset' in options:
            rect = QRect(rect)
            rect.translate(options['offset'][0] * rect.width(),
                           options['offset'][1] * rect.height())

        painter.setOpacity(options.get('opacity', 1.0))

        painter.drawText(rect, Qt.AlignCenter | Qt.AlignVCenter, char)
        painter.restore()
 def scene_item_rects_updated(self, items):
     """The user moved or resized items in the scene
     """
     debug_print('GraphicsItemView.item_rects_updated')
     for index, item in zip(self.indexes_of_items(items), items):
         # item.sceneBoundingRect() is the items rects in the correct
         # coordinates system
         debug_print('Row [{0}] updated'.format(index.row()))
         rect = item.sceneBoundingRect()
         # Cumbersome conversion to ints
         rect = QRect(rect.left(), rect.top(), rect.width(), rect.height())
         self.model().setData(index, rect, RectRole)
示例#42
0
    def set_rect(self, new_rect):
        """Sets a new QRect in integer coordinates
        """

        # Cumbersome conversion to ints
        current = self.sceneBoundingRect()
        current = QRect(current.left(), current.top(),
                        current.width(), current.height())
        if current != new_rect:
            msg = 'Update rect for [{0}] from [{1}] to [{2}]'
            debug_print(msg.format(self, current, new_rect))
            self.prepareGeometryChange()

            # setrect() expects floating point rect
            self.setRect(QRectF(new_rect))
示例#43
0
    def drawBox(self, painter):
        """ Paint box """
        color = self._color
        rect = QRect(0, 0, self._box_sqsize, self._box_sqsize)

        for sz in range(3):
            painter.setPen(color.lighter(200 // (sz+1)))
            painter.drawRect( rect.x()+sz, rect.y()+sz, rect.width()-(sz*2), rect.height()-(sz*2) )

        painter.fillRect(rect.x()+3, rect.y()+3, rect.width()-6, rect.height()-6, color.lighter(200))

        if self._checked:
            painter.setPen(QColor(0, 0, 0))
            painter.drawLine(
                rect.x()+2,
                rect.y() + (rect.height()//2),
                rect.width()//2,
                rect.y() + (rect.height()-2))

            painter.drawLine(
                rect.width()//2,
                rect.y() + (rect.height()-2),
                rect.width()-1,
                rect.y() + 2)
示例#44
0
 def _handleMousePressEvent(self, event, superMethod):
     callsuper = True
     pos = event.pos()
     index = self.indexAt(pos)
     if index.isValid():
         selected = index in self.selectedIndexes()
         rect = self.visualRect(index)
         relativePos = QPoint(pos.x()-rect.x(), pos.y()-rect.y())
         delegate = self.itemDelegate(index)
         if hasattr(delegate, 'handleClick'):
             rect = QRect(0, 0, rect.width(), rect.height())
             if delegate.handleClick(index, relativePos, rect, selected):
                 callsuper = False
     if callsuper:
         superMethod(self, event)
示例#45
0
文件: slice.py 项目: amerlyq/piony
class SliceWidget(QGraphicsItem):
    @inject.params(gs=GState)
    def __init__(self, slicee, r=None, R=None, gs=None, parent=None):
        logger.info('%s init', self.__class__.__qualname__)
        self._engine = SliceLayoutEngine(r=r, R=R, spacing=4)
        super().__init__(parent)
        self.sty = gs.sty['Bud']
        self.cfg = gs.cfg
        self.text = gs.bud['slices'][0].get('name')
        self._text_rf = QRect(0, 0, 16, 16)
        self.font = QFont(str(self.sty['Text']['font']), self._text_rf.height())
        self.build(slicee)

    def build(self, slicee):
        # BUG: engine don't set boundings
        rings = map(lambda rg: RingWidget(rg, parent=self), slicee['rings'])
        self._engine.insert(rings)

    def boundingRect(self):
        R = self._engine.R
        return QRectF(-R, -R, 2*R, 2*R)

    def paint(self, p, option, wdg):
        if __debug__ and piony.G_DEBUG_VISUALS:
            self._drawDbg(p)
        if self.text:
            self.drawText(p)
        # if self._ring:
        #     self._ring.paint(p, option, wdg)
        for item in self._engine.items:
            item.paint(p, option, wdg)

    def drawText(self, p):
        sz = self._text_rf.size() * float(self.sty['Text']['scale'])
        base.adjustFontSize(p, self.text, sz)
        p.setPen(QColor(*list(self.sty['Text']['color'])))
        if __debug__ and piony.G_DEBUG_VISUALS:
            p.drawRect(self._text_rf)
        if self.text and self._text_rf:
            p.drawText(self._text_rf, Qt.AlignCenter, self.text)

    # <Dbg> --------------------
    if __debug__:
        def _drawDbg(self, p):
            p.setPen(Qt.NoPen)
            p.setBrush(QColor(0, 255, 255, 50))
            p.drawRect(self.boundingRect())
示例#46
0
 def resizeEvent(self, evt):
     """
     Protected method to handle resize events.
     
     @param evt resize event (QResizeEvent)
     """
     if self.__selection.isNull():
         return
     
     r = QRect(self.__selection)
     r.setTopLeft(self.__limitPointToRect(r.topLeft(), self.rect()))
     r.setBottomRight(self.__limitPointToRect(r.bottomRight(), self.rect()))
     if r.width() <= 1 or r.height() <= 1:
         # This just results in ugly drawing...
         self.__selection = QRect()
     else:
         self.__selection = self.__normalizeSelection(r)
示例#47
0
文件: FrameLess.py 项目: IMAN4K/QtPro
    def __mouseMove(self, event):
        if self._leftButtonPressed:
            if self._mousePress != Edge.NoEdge:
                left = self._rubberBand.frameGeometry().left()
                top = self._rubberBand.frameGeometry().top()
                right = self._rubberBand.frameGeometry().right()
                bottom = self._rubberBand.frameGeometry().bottom()
                if self._mousePress == Edge.Top:
                    top = event.globalPos().y()
                else:
                    if self._mousePress == Edge.Bottom:
                        bottom = event.globalPos().y()
                    else:
                        if self._mousePress == Edge.Right:
                            right = event.globalPos().x()
                        else:
                            if self._mousePress == Edge.Left:
                                left = event.globalPos().x()
                            else:
                                if self._mousePress == Edge.TopRight:
                                    top = event.globalPos().y()
                                    right = event.globalPos().x()
                                else:
                                    if self._mousePress == Edge.TopLeft:
                                        top = event.globalPos().y()
                                        left = event.globalPos().x()
                                    else:
                                        if self._mousePress == Edge.BottomLeft:
                                            bottom = event.globalPos().y()
                                            left = event.globalPos().x()
                                        else:
                                            if self._mousePress == Edge.BottomRight:
                                                bottom = event.globalPos().y()
                                                right = event.globalPos().x()

                newRect = QRect(QPoint(left, top), QPoint(right, bottom))
                if newRect.width() < self._parent.minimumWidth():
                    left = self.frameGeometry().x()
                else:
                    if newRect.height() < self._parent.minimumHeight():
                        top = self.frameGeometry().y()
                self._parent.setGeometry(QRect(QPoint(left, top), QPoint(right, bottom)))
                self._rubberBand.setGeometry(QRect(QPoint(left, top), QPoint(right, bottom)))
        else:
            self.__updateCursorShape(event.globalPos())
 def scene_box_added(self, rect):
     """The user added a box
     """
     m = self.model()
     row = len(self._rows)
     if not m.insertRow(row):
         raise InselectError('Could not insert row')
     else:
         # Cumbersome conversion to ints
         rect = QRect(rect.left(), rect.top(), rect.width(), rect.height())
         if not m.setData(m.index(row, 0), rect, RectRole):
             raise InselectError('Could not set rect')
         else:
             # Select the new box
             self.scene.clearSelection()
             item = next(self.items_of_rows([row]))
             item.setSelected(True)
             item.update()
示例#49
0
 def _calculate_image_parameters(self, web_viewport, img_width, img_height):
     """
     :return: (image_viewport, image_size)
     """
     if img_width is None:
         img_width = web_viewport.width()
         ratio = 1.0
     else:
         if img_width == 0 or web_viewport.width() == 0:
             ratio = 1.0
         else:
             ratio = img_width / float(web_viewport.width())
     image_viewport = QRect(
         QPoint(0, 0),
         QSize(img_width, round(web_viewport.height() * ratio)))
     if img_height is None:
         img_height = image_viewport.height()
     image_size = QSize(img_width, img_height)
     return image_viewport, image_size
示例#50
0
 def _rect_on_view_python(self, elem_geometry):
     """Python implementation for rect_on_view."""
     if elem_geometry is None:
         geometry = self._elem.geometry()
     else:
         geometry = elem_geometry
     frame = self._elem.webFrame()
     rect = QRect(geometry)
     while frame is not None:
         rect.translate(frame.geometry().topLeft())
         rect.translate(frame.scrollPosition() * -1)
         frame = frame.parentFrame()
     # We deliberately always adjust the zoom here, even with
     # adjust_zoom=False
     if elem_geometry is None:
         zoom = self._elem.webFrame().zoomFactor()
         if not config.get('ui', 'zoom-text-only'):
             rect.moveTo(rect.left() / zoom, rect.top() / zoom)
             rect.setWidth(rect.width() / zoom)
             rect.setHeight(rect.height() / zoom)
     return rect
示例#51
0
    def _paint_icon(self, iconic, painter, rect, mode, state, options):
        """Paint a single icon"""
        painter.save()
        color, char = options['color'], options['char']

        if mode == QIcon.Disabled:
            color = options.get('color_disabled', color)
            char = options.get('disabled', char)
        elif mode == QIcon.Active:
            color = options.get('color_active', color)
            char = options.get('active', char)
        elif mode == QIcon.Selected:
            color = options.get('color_selected', color)
            char = options.get('selected', char)

        painter.setPen(QColor(color))
        # A 16 pixel-high icon yields a font size of 14, which is pixel perfect
        # for font-awesome. 16 * 0.875 = 14
        # The reason for not using full-sized glyphs is the negative bearing of
        # fonts.
        draw_size = 0.875 * qRound(rect.height() * options['scale_factor'])
        prefix = options['prefix']

        # Animation setup hook
        animation = options.get('animation')
        if animation is not None:
            animation.setup(self, painter, rect)

        painter.setFont(iconic.font(prefix, draw_size))
        if 'offset' in options:
            rect = QRect(rect)
            rect.translate(options['offset'][0] * rect.width(),
                           options['offset'][1] * rect.height())

        painter.setOpacity(options.get('opacity', 1.0))

        painter.drawText(rect, Qt.AlignCenter | Qt.AlignVCenter, char)
        painter.restore()
示例#52
0
    def paintEvent(self, ev):
        """Called when paint is needed, finds out which page to magnify."""
        layout = self.parent().surface().pageLayout()
        pos = self.geometry().center() - self.parent().surface().pos()
        page = layout.pageAt(pos)
        if not page:
            return
        pagePos = pos - page.pos()

        max_zoom = self.parent().surface().view().MAX_ZOOM * self.MAX_EXTRA_ZOOM
        newPage = Page(page, min(max_zoom, self._scale * page.scale()))
        if not newPage.same_page(self._page):
            if self._page:
                self._page.magnifier = None
            self._page = newPage
            self._page.magnifier = self

        relx = pagePos.x() / float(page.width())
        rely = pagePos.y() / float(page.height())

        image = cache.image(self._page)
        img_rect = QRect(self.rect())
        img_rect.setSize( img_rect.size()*self._page._retinaFactor );

        if not image:
            cache.generate(self._page)
            image = cache.image(self._page, False)
            if image:
                img_rect.setWidth(img_rect.width() * image.width() / self._page.physWidth())
                img_rect.setHeight(img_rect.height() * image.height() / self._page.physHeight())
        if image:
            img_rect.moveCenter(QPoint(relx * image.width(), rely * image.height()))
            p = QPainter(self)
            p.drawImage(self.rect(), image, img_rect)
            p.setRenderHint(QPainter.Antialiasing, True)
            p.setPen(QPen(QColor(192, 192, 192, 128), 6))
            p.drawEllipse(self.rect().adjusted(2, 2, -2, -2))
示例#53
0
class Page(object):
    """Represents a page from a Poppler.Document.
    
    It maintains its own size and can draw itself using the cache.
    It also can maintain a list of links and return links at certain
    points or rectangles.
    
    The visible attribute (setVisible and visible) defaults to True but
    can be set to False to hide the page from a Surface (this is done by
    the Layout).
    
    """
    def __init__(self, document, pageNumber):
        self._document = document
        self._pageNumber = pageNumber
        self._pageSize = document.page(pageNumber).pageSize()
        self._rotation = popplerqt5.Poppler.Page.Rotate0
        self._rect = QRect()
        self._scale = 1.0
        self._visible = True
        self._layout = lambda: None
        self._waiting = True # whether image still needs to be generated
        
    def document(self):
        """Returns the document."""
        return self._document
        
    def pageNumber(self):
        """Returns the page number."""
        return self._pageNumber
    
    def pageSize(self):
        """The page size in points (1/72 inch), taking rotation into account."""
        return self._pageSize
        
    def layout(self):
        """Returns the Layout if we are part of one."""
        return self._layout()
    
    def visible(self):
        """Returns True if this page is visible (will be displayed)."""
        return self._visible
        
    def setVisible(self, visible):
        """Sets whether  this page is visible (will be displayed)."""
        self._visible = visible
        
    def rect(self):
        """Returns our QRect(), with position and size."""
        return self._rect
    
    def size(self):
        """Returns our size."""
        return self._rect.size()
    
    def height(self):
        """Returns our height."""
        return self._rect.height()
        
    def width(self):
        """Returns our width."""
        return self._rect.width()
        
    def pos(self):
        """Returns our position."""
        return self._rect.topLeft()
    
    def setPos(self, point):
        """Sets our position (affects the Layout)."""
        self._rect.moveTopLeft(point)
    
    def setRotation(self, rotation):
        """Sets our Poppler.Page.Rotation."""
        old, self._rotation = self._rotation, rotation
        if (old ^ rotation) & 1:
            self._pageSize.transpose()
            self.computeSize()
    
    def rotation(self):
        """Returns our rotation."""
        return self._rotation
    
    def computeSize(self):
        """Recomputes our size."""
        xdpi, ydpi = self.layout().dpi() if self.layout() else (72.0, 72.0)
        x = round(self._pageSize.width() * xdpi / 72.0 * self._scale)
        y = round(self._pageSize.height() * ydpi / 72.0 * self._scale)
        self._rect.setSize(QSize(x, y))
        
    def setScale(self, scale):
        """Changes the display scale."""
        self._scale = scale
        self.computeSize()
        
    def scale(self):
        """Returns our display scale."""
        return self._scale
    
    def scaleForWidth(self, width):
        """Returns the scale we need to display ourselves at the given width."""
        if self.layout():
            return width * 72.0 / self.layout().dpi()[0] / self._pageSize.width()
        else:
            return float(width) / self._pageSize.width()
        
    def scaleForHeight(self, height):
        """Returns the scale we need to display ourselves at the given height."""
        if self.layout():
            return height * 72.0 / self.layout().dpi()[1] / self._pageSize.height()
        else:
            return float(height) / self._pageSize.height()
        
    def setWidth(self, width):
        """Change our scale to force our width to the given value."""
        self.setScale(self.scaleForWidth(width))

    def setHeight(self, height):
        """Change our scale to force our height to the given value."""
        self.setScale(self.scaleForHeight(height))
    
    def paint(self, painter, rect):
        update_rect = rect & self.rect()
        if not update_rect:
            return
        image_rect = QRect(update_rect.topLeft() - self.rect().topLeft(), update_rect.size())
        image = cache.image(self)
        self._waiting = not image
        if image:
            painter.drawImage(update_rect, image, image_rect)
        else:
            # schedule an image to be generated, if done our update() method is called
            cache.generate(self)
            # find suitable image to be scaled from other size
            image = cache.image(self, False)
            if image:
                hscale = float(image.width()) / self.width()
                vscale = float(image.height()) / self.height()
                image_rect = QRectF(image_rect.x() * hscale, image_rect.y() * vscale,
                                    image_rect.width() * hscale, image_rect.height() * vscale)
                painter.drawImage(QRectF(update_rect), image, image_rect)
            else:
                # draw blank paper, using the background color of the cache rendering (if set)
                # or from the document itself.
                color = (cache.options(self.document()).paperColor()
                         or cache.options().paperColor() or self.document().paperColor())
                painter.fillRect(update_rect, color)

    def update(self):
        """Called when an image is drawn."""
        # only redraw when we were waiting for a correctly sized image.
        if self._waiting and self.layout():
            self.layout().updatePage(self)
    
    def repaint(self):
        """Call this to force a repaint (e.g. when the rendering options are changed)."""
        self._waiting = True
        cache.generate(self)
    
    def image(self, rect, xdpi=72.0, ydpi=None, options=None):
        """Returns a QImage of the specified rectangle (relative to our top-left position).
        
        xdpi defaults to 72.0 and ydpi defaults to xdpi.
        options may be a render.RenderOptions instance that will set some document
        rendering options just before rendering the image.
        """
        if ydpi is None:
            ydpi = xdpi
        hscale = (xdpi * self.pageSize().width()) / (72.0 * self.width())
        vscale = (ydpi * self.pageSize().height()) / (72.0 * self.height())
        x = rect.x() * hscale
        y = rect.y() * vscale
        w = rect.width() * hscale
        h = rect.height() * vscale
        with lock(self.document()):
            options and options.write(self.document())
            page = self.document().page(self._pageNumber)
            image = page.renderToImage(xdpi, ydpi, x, y, w, h, self._rotation)
        image.setDotsPerMeterX(int(xdpi * 39.37))
        image.setDotsPerMeterY(int(ydpi * 39.37))
        return image
    
    def linksAt(self, point):
        """Returns a list() of zero or more links touched by point (relative to surface).
        
        The list is sorted with the smallest rectangle first.
        
        """
        # Poppler.Link objects have their linkArea() ranging in width and height
        # from 0.0 to 1.0, so divide by resp. height and width of the Page.
        point = point - self.pos()
        x = float(point.x()) / self.width()
        y = float(point.y()) / self.height()
        # rotate
        if self._rotation:
            if self._rotation == popplerqt5.Poppler.Page.Rotate90:
                x, y = y, 1-x
            elif self._rotation == popplerqt5.Poppler.Page.Rotate180:
                x, y = 1-x, 1-y
            else: # 270
                x, y = 1-y, x
        return list(sorted(cache.links(self).at(x, y), key=lambda link: link.linkArea().width()))
        
    def linksIn(self, rect):
        """Returns an unordered set() of links enclosed in rectangle (relative to surface)."""
        rect = rect.normalized()
        rect.translate(-self.pos())
        left   = float(rect.left())   / self.width()
        top    = float(rect.top())    / self.height()
        right  = float(rect.right())  / self.width()
        bottom = float(rect.bottom()) / self.height()
        # rotate
        if self._rotation:
            if self._rotation == popplerqt5.Poppler.Page.Rotate90:
                left, top, right, bottom = top, 1-right, bottom, 1-left
            elif self._rotation == popplerqt5.Poppler.Page.Rotate180:
                left, top, right, bottom = 1-right, 1-bottom, 1-left, 1-top
            else: # 270
                left, top, right, bottom = 1-bottom, left, 1-top, right
        return cache.links(self).inside(left, top, right, bottom)

    def linkRect(self, linkarea):
        """Returns a QRect encompassing the linkArea (of a link) in coordinates of our rect()."""
        left, top, right, bottom = linkarea.normalized().getCoords()
        # rotate
        if self._rotation:
            if self._rotation == popplerqt5.Poppler.Page.Rotate90:
                left, top, right, bottom = 1-bottom, left, 1-top, right
            elif self._rotation == popplerqt5.Poppler.Page.Rotate180:
                left, top, right, bottom = 1-right, 1-bottom, 1-left, 1-top
            else: # 270
                left, top, right, bottom = top, 1-right, bottom, 1-left
        rect = QRect()
        rect.setCoords(left * self.width(), top * self.height(), right * self.width(), bottom * self.height())
        rect.translate(self.pos())
        return rect
        
    def text(self, rect):
        """Returns text inside rectangle (relative to surface)."""
        rect = rect.normalized()
        rect.translate(-self.pos())
        w, h = self.pageSize().width(), self.pageSize().height()
        left   = float(rect.left())   / self.width()  * w
        top    = float(rect.top())    / self.height() * h
        right  = float(rect.right())  / self.width()  * w
        bottom = float(rect.bottom()) / self.height() * h
        if self._rotation:
            if self._rotation == popplerqt5.Poppler.Page.Rotate90:
                left, top, right, bottom = top, w-right, bottom, w-left
            elif self._rotation == popplerqt5.Poppler.Page.Rotate180:
                left, top, right, bottom = w-right, h-bottom, w-left, h-top
            else: # 270
                left, top, right, bottom = h-bottom, left, h-top, right
        rect = QRectF()
        rect.setCoords(left, top, right, bottom)
        with lock(self.document()):
            page = self.document().page(self._pageNumber)
            return page.text(rect)
        
    def searchRect(self, rectF):
        """Returns a QRect encompassing the given rect (in points) to our position, size and rotation."""
        rect = rectF.normalized()
        left, top, right, bottom = rect.getCoords()
        w, h = self.pageSize().width(), self.pageSize().height()
        hscale = self.width()  / float(w)
        vscale = self.height() / float(h)
        if self._rotation:
            if self._rotation == popplerqt5.Poppler.Page.Rotate90:
                left, top, right, bottom = w-bottom, left, w-top, right
            elif self._rotation == popplerqt5.Poppler.Page.Rotate180:
                left, top, right, bottom = w-right, h-bottom, w-left, h-top
            else: # 270
                left, top, right, bottom = top, h-right, bottom, h-left
        rect = QRect()
        rect.setCoords(left * hscale, top * vscale, right * hscale, bottom * vscale)
        return rect
示例#54
0
class SnapshotRegionGrabber(QWidget):
    """
    Class implementing a grabber widget for a rectangular snapshot region.
    
    @signal grabbed(QPixmap) emitted after the region was grabbed
    """
    grabbed = pyqtSignal(QPixmap)
    
    StrokeMask = 0
    FillMask = 1
    
    Rectangle = 0
    Ellipse = 1
    
    def __init__(self, mode=Rectangle):
        """
        Constructor
        
        @param mode region grabber mode (SnapshotRegionGrabber.Rectangle or
            SnapshotRegionGrabber.Ellipse)
        """
        super(SnapshotRegionGrabber, self).__init__(
            None,
            Qt.X11BypassWindowManagerHint | Qt.WindowStaysOnTopHint |
            Qt.FramelessWindowHint | Qt.Tool)
        
        assert mode in [SnapshotRegionGrabber.Rectangle,
                        SnapshotRegionGrabber.Ellipse]
        self.__mode = mode
        
        self.__selection = QRect()
        self.__mouseDown = False
        self.__newSelection = False
        self.__handleSize = 10
        self.__mouseOverHandle = None
        self.__showHelp = True
        self.__grabbing = False
        self.__dragStartPoint = QPoint()
        self.__selectionBeforeDrag = QRect()
        
        # naming conventions for handles
        # T top, B bottom, R Right, L left
        # 2 letters: a corner
        # 1 letter: the handle on the middle of the corresponding side
        self.__TLHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__TRHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__BLHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__BRHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__LHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__THandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__RHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__BHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__handles = [self.__TLHandle, self.__TRHandle, self.__BLHandle,
                          self.__BRHandle, self.__LHandle, self.__THandle,
                          self.__RHandle, self.__BHandle]
        self.__helpTextRect = QRect()
        self.__helpText = self.tr(
            "Select a region using the mouse. To take the snapshot, press"
            " the Enter key or double click. Press Esc to quit.")
        
        self.__pixmap = QPixmap()
        
        self.setMouseTracking(True)
        
        QTimer.singleShot(200, self.__initialize)
    
    def __initialize(self):
        """
        Private slot to initialize the rest of the widget.
        """
        self.__desktop = QApplication.desktop()
        x = self.__desktop.x()
        y = self.__desktop.y()
        if qVersion() >= "5.0.0":
            self.__pixmap = QApplication.screens()[0].grabWindow(
                self.__desktop.winId(), x, y,
                self.__desktop.width(), self.__desktop.height())
        else:
            self.__pixmap = QPixmap.grabWindow(
                self.__desktop.winId(), x, y,
                self.__desktop.width(), self.__desktop.height())
        self.resize(self.__pixmap.size())
        self.move(x, y)
        self.setCursor(Qt.CrossCursor)
        self.show()

        self.grabMouse()
        self.grabKeyboard()
    
    def paintEvent(self, evt):
        """
        Protected method handling paint events.
        
        @param evt paint event (QPaintEvent)
        """
        if self.__grabbing:     # grabWindow() should just get the background
            return
        
        painter = QPainter(self)
        pal = QPalette(QToolTip.palette())
        font = QToolTip.font()
        
        handleColor = pal.color(QPalette.Active, QPalette.Highlight)
        handleColor.setAlpha(160)
        overlayColor = QColor(0, 0, 0, 160)
        textColor = pal.color(QPalette.Active, QPalette.Text)
        textBackgroundColor = pal.color(QPalette.Active, QPalette.Base)
        painter.drawPixmap(0, 0, self.__pixmap)
        painter.setFont(font)
        
        r = QRect(self.__selection)
        if not self.__selection.isNull():
            grey = QRegion(self.rect())
            if self.__mode == SnapshotRegionGrabber.Ellipse:
                reg = QRegion(r, QRegion.Ellipse)
            else:
                reg = QRegion(r)
            grey = grey.subtracted(reg)
            painter.setClipRegion(grey)
            painter.setPen(Qt.NoPen)
            painter.setBrush(overlayColor)
            painter.drawRect(self.rect())
            painter.setClipRect(self.rect())
            drawRect(painter, r, handleColor)
        
        if self.__showHelp:
            painter.setPen(textColor)
            painter.setBrush(textBackgroundColor)
            self.__helpTextRect = painter.boundingRect(
                self.rect().adjusted(2, 2, -2, -2),
                Qt.TextWordWrap, self.__helpText).translated(
                -self.__desktop.x(), -self.__desktop.y())
            self.__helpTextRect.adjust(-2, -2, 4, 2)
            drawRect(painter, self.__helpTextRect, textColor,
                     textBackgroundColor)
            painter.drawText(
                self.__helpTextRect.adjusted(3, 3, -3, -3),
                Qt.TextWordWrap, self.__helpText)
        
        if self.__selection.isNull():
            return
        
        # The grabbed region is everything which is covered by the drawn
        # rectangles (border included). This means that there is no 0px
        # selection, since a 0px wide rectangle will always be drawn as a line.
        txt = "{0:n}, {1:n} ({2:n} x {3:n})".format(
            self.__selection.x(), self.__selection.y(),
            self.__selection.width(), self.__selection.height())
        textRect = painter.boundingRect(self.rect(), Qt.AlignLeft, txt)
        boundingRect = textRect.adjusted(-4, 0, 0, 0)
        
        if textRect.width() < r.width() - 2 * self.__handleSize and \
           textRect.height() < r.height() - 2 * self.__handleSize and \
           r.width() > 100 and \
           r.height() > 100:
            # center, unsuitable for small selections
            boundingRect.moveCenter(r.center())
            textRect.moveCenter(r.center())
        elif r.y() - 3 > textRect.height() and \
                r.x() + textRect.width() < self.rect().width():
            # on top, left aligned
            boundingRect.moveBottomLeft(QPoint(r.x(), r.y() - 3))
            textRect.moveBottomLeft(QPoint(r.x() + 2, r.y() - 3))
        elif r.x() - 3 > textRect.width():
            # left, top aligned
            boundingRect.moveTopRight(QPoint(r.x() - 3, r.y()))
            textRect.moveTopRight(QPoint(r.x() - 5, r.y()))
        elif r.bottom() + 3 + textRect.height() < self.rect().bottom() and \
                r.right() > textRect.width():
            # at bottom, right aligned
            boundingRect.moveTopRight(QPoint(r.right(), r.bottom() + 3))
            textRect.moveTopRight(QPoint(r.right() - 2, r.bottom() + 3))
        elif r.right() + textRect.width() + 3 < self.rect().width():
            # right, bottom aligned
            boundingRect.moveBottomLeft(QPoint(r.right() + 3, r.bottom()))
            textRect.moveBottomLeft(QPoint(r.right() + 5, r.bottom()))
        
        # If the above didn't catch it, you are running on a very
        # tiny screen...
        drawRect(painter, boundingRect, textColor, textBackgroundColor)
        painter.drawText(textRect, Qt.AlignHCenter, txt)
        
        if (r.height() > self.__handleSize * 2 and
            r.width() > self.__handleSize * 2) or \
           not self.__mouseDown:
            self.__updateHandles()
            painter.setPen(Qt.NoPen)
            painter.setBrush(handleColor)
            painter.setClipRegion(
                self.__handleMask(SnapshotRegionGrabber.StrokeMask))
            painter.drawRect(self.rect())
            handleColor.setAlpha(60)
            painter.setBrush(handleColor)
            painter.setClipRegion(
                self.__handleMask(SnapshotRegionGrabber.FillMask))
            painter.drawRect(self.rect())
    
    def resizeEvent(self, evt):
        """
        Protected method to handle resize events.
        
        @param evt resize event (QResizeEvent)
        """
        if self.__selection.isNull():
            return
        
        r = QRect(self.__selection)
        r.setTopLeft(self.__limitPointToRect(r.topLeft(), self.rect()))
        r.setBottomRight(self.__limitPointToRect(r.bottomRight(), self.rect()))
        if r.width() <= 1 or r.height() <= 1:
            # This just results in ugly drawing...
            self.__selection = QRect()
        else:
            self.__selection = self.__normalizeSelection(r)
    
    def mousePressEvent(self, evt):
        """
        Protected method to handle mouse button presses.
        
        @param evt mouse press event (QMouseEvent)
        """
        self.__showHelp = not self.__helpTextRect.contains(evt.pos())
        if evt.button() == Qt.LeftButton:
            self.__mouseDown = True
            self.__dragStartPoint = evt.pos()
            self.__selectionBeforeDrag = QRect(self.__selection)
            if not self.__selection.contains(evt.pos()):
                self.__newSelection = True
                self.__selection = QRect()
            else:
                self.setCursor(Qt.ClosedHandCursor)
        elif evt.button() == Qt.RightButton:
            self.__newSelection = False
            self.__selection = QRect()
            self.setCursor(Qt.CrossCursor)
        self.update()
    
    def mouseMoveEvent(self, evt):
        """
        Protected method to handle mouse movements.
        
        @param evt mouse move event (QMouseEvent)
        """
        shouldShowHelp = not self.__helpTextRect.contains(evt.pos())
        if shouldShowHelp != self.__showHelp:
            self.__showHelp = shouldShowHelp
            self.update()
        
        if self.__mouseDown:
            if self.__newSelection:
                p = evt.pos()
                r = self.rect()
                self.__selection = self.__normalizeSelection(
                    QRect(self.__dragStartPoint,
                          self.__limitPointToRect(p, r)))
            elif self.__mouseOverHandle is None:
                # moving the whole selection
                r = self.rect().normalized()
                s = self.__selectionBeforeDrag.normalized()
                p = s.topLeft() + evt.pos() - self.__dragStartPoint
                r.setBottomRight(
                    r.bottomRight() - QPoint(s.width(), s.height()) +
                    QPoint(1, 1))
                if not r.isNull() and r.isValid():
                    self.__selection.moveTo(self.__limitPointToRect(p, r))
            else:
                # dragging a handle
                r = QRect(self.__selectionBeforeDrag)
                offset = evt.pos() - self.__dragStartPoint
                
                if self.__mouseOverHandle in \
                   [self.__TLHandle, self.__THandle, self.__TRHandle]:
                    r.setTop(r.top() + offset.y())
                
                if self.__mouseOverHandle in \
                   [self.__TLHandle, self.__LHandle, self.__BLHandle]:
                    r.setLeft(r.left() + offset.x())
                
                if self.__mouseOverHandle in \
                   [self.__BLHandle, self.__BHandle, self.__BRHandle]:
                    r.setBottom(r.bottom() + offset.y())
                
                if self.__mouseOverHandle in \
                   [self.__TRHandle, self.__RHandle, self.__BRHandle]:
                    r.setRight(r.right() + offset.x())
                
                r.setTopLeft(self.__limitPointToRect(r.topLeft(), self.rect()))
                r.setBottomRight(
                    self.__limitPointToRect(r.bottomRight(), self.rect()))
                self.__selection = self.__normalizeSelection(r)
            
            self.update()
        else:
            if self.__selection.isNull():
                return
            
            found = False
            for r in self.__handles:
                if r.contains(evt.pos()):
                    self.__mouseOverHandle = r
                    found = True
                    break
            
            if not found:
                self.__mouseOverHandle = None
                if self.__selection.contains(evt.pos()):
                    self.setCursor(Qt.OpenHandCursor)
                else:
                    self.setCursor(Qt.CrossCursor)
            else:
                if self.__mouseOverHandle in [self.__TLHandle,
                                              self.__BRHandle]:
                    self.setCursor(Qt.SizeFDiagCursor)
                elif self.__mouseOverHandle in [self.__TRHandle,
                                                self.__BLHandle]:
                    self.setCursor(Qt.SizeBDiagCursor)
                elif self.__mouseOverHandle in [self.__LHandle,
                                                self.__RHandle]:
                    self.setCursor(Qt.SizeHorCursor)
                elif self.__mouseOverHandle in [self.__THandle,
                                                self.__BHandle]:
                    self.setCursor(Qt.SizeVerCursor)
    
    def mouseReleaseEvent(self, evt):
        """
        Protected method to handle mouse button releases.
        
        @param evt mouse release event (QMouseEvent)
        """
        self.__mouseDown = False
        self.__newSelection = False
        if self.__mouseOverHandle is None and \
           self.__selection.contains(evt.pos()):
            self.setCursor(Qt.OpenHandCursor)
        self.update()
    
    def mouseDoubleClickEvent(self, evt):
        """
        Protected method to handle mouse double clicks.
        
        @param evt mouse double click event (QMouseEvent)
        """
        self.__grabRect()
    
    def keyPressEvent(self, evt):
        """
        Protected method to handle key presses.
        
        @param evt key press event (QKeyEvent)
        """
        if evt.key() == Qt.Key_Escape:
            self.grabbed.emit(QPixmap())
        elif evt.key() in [Qt.Key_Enter, Qt.Key_Return]:
            self.__grabRect()
        else:
            evt.ignore()
    
    def __updateHandles(self):
        """
        Private method to update the handles.
        """
        r = QRect(self.__selection)
        s2 = self.__handleSize // 2
        
        self.__TLHandle.moveTopLeft(r.topLeft())
        self.__TRHandle.moveTopRight(r.topRight())
        self.__BLHandle.moveBottomLeft(r.bottomLeft())
        self.__BRHandle.moveBottomRight(r.bottomRight())
        
        self.__LHandle.moveTopLeft(QPoint(r.x(), r.y() + r.height() // 2 - s2))
        self.__THandle.moveTopLeft(QPoint(r.x() + r.width() // 2 - s2, r.y()))
        self.__RHandle.moveTopRight(
            QPoint(r.right(), r.y() + r.height() // 2 - s2))
        self.__BHandle.moveBottomLeft(
            QPoint(r.x() + r.width() // 2 - s2, r.bottom()))
    
    def __handleMask(self, maskType):
        """
        Private method to calculate the handle mask.
        
        @param maskType type of the mask to be used
            (SnapshotRegionGrabber.FillMask or
            SnapshotRegionGrabber.StrokeMask)
        @return calculated mask (QRegion)
        """
        mask = QRegion()
        for rect in self.__handles:
            if maskType == SnapshotRegionGrabber.StrokeMask:
                r = QRegion(rect)
                mask += r.subtracted(QRegion(rect.adjusted(1, 1, -1, -1)))
            else:
                mask += QRegion(rect.adjusted(1, 1, -1, -1))
        return mask
    
    def __limitPointToRect(self, point, rect):
        """
        Private method to limit the given point to the given rectangle.
        
        @param point point to be limited (QPoint)
        @param rect rectangle the point shall be limited to (QRect)
        @return limited point (QPoint)
        """
        q = QPoint()
        if point.x() < rect.x():
            q.setX(rect.x())
        elif point.x() < rect.right():
            q.setX(point.x())
        else:
            q.setX(rect.right())
        if point.y() < rect.y():
            q.setY(rect.y())
        elif point.y() < rect.bottom():
            q.setY(point.y())
        else:
            q.setY(rect.bottom())
        return q
    
    def __normalizeSelection(self, sel):
        """
        Private method to normalize the given selection.
        
        @param sel selection to be normalized (QRect)
        @return normalized selection (QRect)
        """
        rect = QRect(sel)
        if rect.width() <= 0:
            left = rect.left()
            width = rect.width()
            rect.setLeft(left + width - 1)
            rect.setRight(left)
        if rect.height() <= 0:
            top = rect.top()
            height = rect.height()
            rect.setTop(top + height - 1)
            rect.setBottom(top)
        return rect
    
    def __grabRect(self):
        """
        Private method to grab the selected rectangle (i.e. do the snapshot).
        """
        if self.__mode == SnapshotRegionGrabber.Ellipse:
            ell = QRegion(self.__selection, QRegion.Ellipse)
            if not ell.isEmpty():
                self.__grabbing = True
                
                xOffset = self.__pixmap.rect().x() - ell.boundingRect().x()
                yOffset = self.__pixmap.rect().y() - ell.boundingRect().y()
                translatedEll = ell.translated(xOffset, yOffset)
                
                pixmap2 = QPixmap(ell.boundingRect().size())
                pixmap2.fill(Qt.transparent)
                
                pt = QPainter()
                pt.begin(pixmap2)
                if pt.paintEngine().hasFeature(QPaintEngine.PorterDuff):
                    pt.setRenderHints(
                        QPainter.Antialiasing |
                        QPainter.HighQualityAntialiasing |
                        QPainter.SmoothPixmapTransform,
                        True)
                    pt.setBrush(Qt.black)
                    pt.setPen(QPen(QBrush(Qt.black), 0.5))
                    pt.drawEllipse(translatedEll.boundingRect())
                    pt.setCompositionMode(QPainter.CompositionMode_SourceIn)
                else:
                    pt.setClipRegion(translatedEll)
                    pt.setCompositionMode(QPainter.CompositionMode_Source)
                
                pt.drawPixmap(pixmap2.rect(), self.__pixmap,
                              ell.boundingRect())
                pt.end()
                
                self.grabbed.emit(pixmap2)
        else:
            r = QRect(self.__selection)
            if not r.isNull() and r.isValid():
                self.__grabbing = True
                self.grabbed.emit(self.__pixmap.copy(r))
示例#55
0
 def paintEvent(self, evt):
     """
     Protected method handling paint events.
     
     @param evt paint event (QPaintEvent)
     """
     if self.__grabbing:     # grabWindow() should just get the background
         return
     
     painter = QPainter(self)
     pal = QPalette(QToolTip.palette())
     font = QToolTip.font()
     
     handleColor = pal.color(QPalette.Active, QPalette.Highlight)
     handleColor.setAlpha(160)
     overlayColor = QColor(0, 0, 0, 160)
     textColor = pal.color(QPalette.Active, QPalette.Text)
     textBackgroundColor = pal.color(QPalette.Active, QPalette.Base)
     painter.drawPixmap(0, 0, self.__pixmap)
     painter.setFont(font)
     
     r = QRect(self.__selection)
     if not self.__selection.isNull():
         grey = QRegion(self.rect())
         if self.__mode == SnapshotRegionGrabber.Ellipse:
             reg = QRegion(r, QRegion.Ellipse)
         else:
             reg = QRegion(r)
         grey = grey.subtracted(reg)
         painter.setClipRegion(grey)
         painter.setPen(Qt.NoPen)
         painter.setBrush(overlayColor)
         painter.drawRect(self.rect())
         painter.setClipRect(self.rect())
         drawRect(painter, r, handleColor)
     
     if self.__showHelp:
         painter.setPen(textColor)
         painter.setBrush(textBackgroundColor)
         self.__helpTextRect = painter.boundingRect(
             self.rect().adjusted(2, 2, -2, -2),
             Qt.TextWordWrap, self.__helpText).translated(
             -self.__desktop.x(), -self.__desktop.y())
         self.__helpTextRect.adjust(-2, -2, 4, 2)
         drawRect(painter, self.__helpTextRect, textColor,
                  textBackgroundColor)
         painter.drawText(
             self.__helpTextRect.adjusted(3, 3, -3, -3),
             Qt.TextWordWrap, self.__helpText)
     
     if self.__selection.isNull():
         return
     
     # The grabbed region is everything which is covered by the drawn
     # rectangles (border included). This means that there is no 0px
     # selection, since a 0px wide rectangle will always be drawn as a line.
     txt = "{0:n}, {1:n} ({2:n} x {3:n})".format(
         self.__selection.x(), self.__selection.y(),
         self.__selection.width(), self.__selection.height())
     textRect = painter.boundingRect(self.rect(), Qt.AlignLeft, txt)
     boundingRect = textRect.adjusted(-4, 0, 0, 0)
     
     if textRect.width() < r.width() - 2 * self.__handleSize and \
        textRect.height() < r.height() - 2 * self.__handleSize and \
        r.width() > 100 and \
        r.height() > 100:
         # center, unsuitable for small selections
         boundingRect.moveCenter(r.center())
         textRect.moveCenter(r.center())
     elif r.y() - 3 > textRect.height() and \
             r.x() + textRect.width() < self.rect().width():
         # on top, left aligned
         boundingRect.moveBottomLeft(QPoint(r.x(), r.y() - 3))
         textRect.moveBottomLeft(QPoint(r.x() + 2, r.y() - 3))
     elif r.x() - 3 > textRect.width():
         # left, top aligned
         boundingRect.moveTopRight(QPoint(r.x() - 3, r.y()))
         textRect.moveTopRight(QPoint(r.x() - 5, r.y()))
     elif r.bottom() + 3 + textRect.height() < self.rect().bottom() and \
             r.right() > textRect.width():
         # at bottom, right aligned
         boundingRect.moveTopRight(QPoint(r.right(), r.bottom() + 3))
         textRect.moveTopRight(QPoint(r.right() - 2, r.bottom() + 3))
     elif r.right() + textRect.width() + 3 < self.rect().width():
         # right, bottom aligned
         boundingRect.moveBottomLeft(QPoint(r.right() + 3, r.bottom()))
         textRect.moveBottomLeft(QPoint(r.right() + 5, r.bottom()))
     
     # If the above didn't catch it, you are running on a very
     # tiny screen...
     drawRect(painter, boundingRect, textColor, textBackgroundColor)
     painter.drawText(textRect, Qt.AlignHCenter, txt)
     
     if (r.height() > self.__handleSize * 2 and
         r.width() > self.__handleSize * 2) or \
        not self.__mouseDown:
         self.__updateHandles()
         painter.setPen(Qt.NoPen)
         painter.setBrush(handleColor)
         painter.setClipRegion(
             self.__handleMask(SnapshotRegionGrabber.StrokeMask))
         painter.drawRect(self.rect())
         handleColor.setAlpha(60)
         painter.setBrush(handleColor)
         painter.setClipRegion(
             self.__handleMask(SnapshotRegionGrabber.FillMask))
         painter.drawRect(self.rect())
示例#56
0
class BrushingModel(QObject):
    brushSizeChanged = pyqtSignal(int)
    brushColorChanged = pyqtSignal(QColor)
    brushStrokeAvailable = pyqtSignal(QPointF, object)
    drawnNumberChanged = pyqtSignal(int)

    minBrushSize = 1
    maxBrushSize = 61
    defaultBrushSize = 3
    defaultDrawnNumber = 1
    defaultColor = Qt.white
    erasingColor = Qt.black
    erasingNumber = 100

    def __init__(self, parent=None):
        QObject.__init__(self, parent=parent)
        self.sliceRect = None
        self.bb = QRect()  # bounding box enclosing the drawing
        self.brushSize = self.defaultBrushSize
        self.drawColor = self.defaultColor
        self._temp_color = None
        self._temp_number = None
        self.drawnNumber = self.defaultDrawnNumber

        self.pos = None
        self.erasing = False
        self._hasMoved = False

        self.drawOnto = None

        # an empty scene, where we add all drawn line segments
        # a QGraphicsLineItem, and which we can use to then
        # render to an image
        self.scene = QGraphicsScene()

    def toggleErase(self):
        self.erasing = not (self.erasing)
        if self.erasing:
            self.setErasing()
        else:
            self.disableErasing()

    def setErasing(self):
        self.erasing = True
        self._temp_color = self.drawColor
        self._temp_number = self.drawnNumber
        self.setBrushColor(self.erasingColor)
        self.brushColorChanged.emit(self.erasingColor)
        self.setDrawnNumber(self.erasingNumber)

    def disableErasing(self):
        self.erasing = False
        self.setBrushColor(self._temp_color)
        self.brushColorChanged.emit(self.drawColor)
        self.setDrawnNumber(self._temp_number)

    def setBrushSize(self, size):
        self.brushSize = size
        self.brushSizeChanged.emit(self.brushSize)

    def setDrawnNumber(self, num):
        self.drawnNumber = num
        self.drawnNumberChanged.emit(num)

    def getBrushSize(self):
        return self.brushSize

    def brushSmaller(self):
        b = self.brushSize
        if b > self.minBrushSize:
            self.setBrushSize(b - 1)

    def brushBigger(self):
        b = self.brushSize
        if self.brushSize < self.maxBrushSize:
            self.setBrushSize(b + 1)

    def setBrushColor(self, color):
        self.drawColor = QColor(color)
        self.brushColorChanged.emit(self.drawColor)

    def beginDrawing(self, pos, sliceRect):
        """

        pos -- QPointF-like
        """
        self.sliceRect = sliceRect
        self.scene.clear()
        self.bb = QRect()
        self.pos = QPointF(pos.x(), pos.y())
        self._hasMoved = False

    def endDrawing(self, pos):
        has_moved = self._hasMoved  # _hasMoved will change after calling moveTo
        if has_moved:
            self.moveTo(pos)
        else:
            assert self.pos == pos
            self.moveTo(QPointF(pos.x() + 0.0001, pos.y() + 0.0001))  # move a little

        # Qt seems to use strange rules for determining which pixels to set when rendering a brush stroke to a QImage.
        # We seem to get better results if we do the following:
        # 1) Slightly offset the source window because apparently there is a small shift in the data
        # 2) Render the scene to an image that is MUCH larger than the scene resolution (4x by 4x)
        # 3) Downsample each 4x4 patch from the large image back to a single pixel in the final image,
        #     applying some threshold to determine if the final pixel is on or off.

        tempi = QImage(
            QSize(4 * self.bb.width(), 4 * self.bb.height()), QImage.Format_ARGB32_Premultiplied
        )  # TODO: format
        tempi.fill(0)
        painter = QPainter(tempi)
        # Offset the source window.  At first I thought the right offset was 0.5, because
        #  that would seem to make sure points are rounded to pixel CENTERS, but
        #  experimentation indicates that 0.25 is slightly better for some reason...
        source_rect = QRectF(QPointF(self.bb.x() + 0.25, self.bb.y() + 0.25), QSizeF(self.bb.width(), self.bb.height()))
        target_rect = QRectF(QPointF(0, 0), QSizeF(4 * self.bb.width(), 4 * self.bb.height()))
        self.scene.render(painter, target=target_rect, source=source_rect)
        painter.end()

        # Now downsample: convert each 4x4 patch into a single pixel by summing and dividing
        ndarr = qimage2ndarray.rgb_view(tempi)[:, :, 0].astype(int)
        ndarr = ndarr.reshape((ndarr.shape[0],) + (ndarr.shape[1] // 4,) + (4,))
        ndarr = ndarr.sum(axis=-1)
        ndarr = ndarr.transpose()
        ndarr = ndarr.reshape((ndarr.shape[0],) + (ndarr.shape[1] // 4,) + (4,))
        ndarr = ndarr.sum(axis=-1)
        ndarr = ndarr.transpose()
        ndarr //= 4 * 4

        downsample_threshold = (7.0 / 16) * 255
        labels = numpy.where(ndarr >= downsample_threshold, numpy.uint8(self.drawnNumber), numpy.uint8(0))
        labels = labels.swapaxes(0, 1)
        assert labels.shape[0] == self.bb.width()
        assert labels.shape[1] == self.bb.height()

        ##
        ## ensure that at least one pixel is label when the brush size is 1
        ##
        ## this happens when the user just clicked without moving
        ## in that case the lineitem will be so tiny, that it won't be rendered
        ## into a single pixel by the code above
        if not has_moved and self.brushSize <= 1 and numpy.count_nonzero(labels) == 0:
            labels[labels.shape[0] // 2, labels.shape[1] // 2] = self.drawnNumber

        self.brushStrokeAvailable.emit(QPointF(self.bb.x(), self.bb.y()), labels)

    def dumpDraw(self, pos):
        res = self.endDrawing(pos)
        self.beginDrawing(pos, self.sliceRect)
        return res

    def moveTo(self, pos):
        # data coordinates
        oldX, oldY = self.pos.x(), self.pos.y()
        x, y = pos.x(), pos.y()

        line = QGraphicsLineItem(oldX, oldY, x, y)
        line.setPen(QPen(QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
        self.scene.addItem(line)
        self._hasMoved = True

        # update bounding Box
        if not self.bb.isValid():
            self.bb = QRect(QPoint(oldX, oldY), QSize(1, 1))
        # grow bounding box
        self.bb.setLeft(min(self.bb.left(), max(0, x - self.brushSize // 2 - 1)))
        self.bb.setRight(max(self.bb.right(), min(self.sliceRect[0] - 1, x + self.brushSize // 2 + 1)))
        self.bb.setTop(min(self.bb.top(), max(0, y - self.brushSize // 2 - 1)))
        self.bb.setBottom(max(self.bb.bottom(), min(self.sliceRect[1] - 1, y + self.brushSize // 2 + 1)))

        # update/move position
        self.pos = pos
示例#57
0
    def updateBrush(self, cursorPos, _list = None):
        # get the current tile layer
        currentLayer = self.currentTileLayer()
        layerWidth = currentLayer.width()
        layerHeight = currentLayer.height()
        numTiles = layerWidth * layerHeight
        paintCorner = 0
        # if we are in vertex paint mode, the bottom right corner on the map will appear as an invalid tile offset...
        if (self.mBrushMode == BrushMode.PaintVertex):
            if (cursorPos.x() == layerWidth):
                cursorPos.setX(cursorPos.x() - 1)
                paintCorner |= 1

            if (cursorPos.y() == layerHeight):
                cursorPos.setY(cursorPos.y() - 1)
                paintCorner |= 2

        # if the cursor is outside of the map, bail out
        if (not currentLayer.bounds().contains(cursorPos)):
            return
        terrainTileset = None
        terrainId = -1
        if (self.mTerrain):
            terrainTileset = self.mTerrain.tileset()
            terrainId = self.mTerrain.id()

        # allocate a buffer to build the terrain tilemap (TODO: this could be retained per layer to save regular allocation)
        newTerrain = []
        for i in range(numTiles):
            newTerrain.append(0)
            
        # allocate a buffer of flags for each tile that may be considered (TODO: this could be retained per layer to save regular allocation)
        checked = array('B')
        for i in range(numTiles):
            checked.append(0)
        # create a consideration list, and push the start points
        transitionList = QList()
        initialTiles = 0
        if (_list):
            # if we were supplied a list of start points
            for p in _list:
                transitionList.append(p)
                initialTiles += 1

        else:
            transitionList.append(cursorPos)
            initialTiles = 1

        brushRect = QRect(cursorPos, cursorPos)
        # produce terrain with transitions using a simple, relative naive approach (considers each tile once, and doesn't allow re-consideration if selection was bad)
        while (not transitionList.isEmpty()):
            # get the next point in the consideration list
            p = transitionList.takeFirst()
            x = p.x()
            y = p.y()
            i = y*layerWidth + x
            # if we have already considered this point, skip to the next
            # TODO: we might want to allow re-consideration if prior tiles... but not for now, this would risk infinite loops
            if (checked[i]):
                continue
            tile = currentLayer.cellAt(p).tile
            currentTerrain = terrain(tile)
            # get the tileset for this tile
            tileset = None
            if (terrainTileset):
                # if we are painting a terrain, then we'll use the terrains tileset
                tileset = terrainTileset
            elif (tile):
                # if we're erasing terrain, use the individual tiles tileset (to search for transitions)
                tileset = tile.tileset()
            else:
                # no tile here and we're erasing terrain, not much we can do
                continue

            # calculate the ideal tile for this position
            preferredTerrain = 0xFFFFFFFF
            mask = 0
            if (initialTiles):
                # for the initial tiles, we will insert the selected terrain and add the surroundings for consideration
                if (self.mBrushMode == BrushMode.PaintTile):
                    # set the whole tile to the selected terrain
                    preferredTerrain = makeTerrain(terrainId)
                    mask = 0xFFFFFFFF
                else:
                    # Bail out if encountering a tile from a different tileset
                    if (tile and tile.tileset() != tileset):
                        continue
                    # calculate the corner mask
                    mask = 0xFF << (3 - paintCorner)*8
                    # mask in the selected terrain
                    preferredTerrain = (currentTerrain & ~mask) | (terrainId << (3 - paintCorner)*8)

                initialTiles -= 1
                # if there's nothing to paint... skip this tile
                if (preferredTerrain == currentTerrain and (not tile or tile.tileset() == tileset)):
                    continue
            else:
                # Bail out if encountering a tile from a different tileset
                if (tile and tile.tileset() != tileset):
                    continue
                # following tiles each need consideration against their surroundings
                preferredTerrain = currentTerrain
                mask = 0
                # depending which connections have been set, we update the preferred terrain of the tile accordingly
                if (y > 0 and checked[i - layerWidth]):
                    preferredTerrain = ((terrain(newTerrain[i - layerWidth]) << 16) | (preferredTerrain & 0x0000FFFF))&0xFFFFFFFF
                    mask |= 0xFFFF0000

                if (y < layerHeight - 1 and checked[i + layerWidth]):
                    preferredTerrain = ((terrain(newTerrain[i + layerWidth]) >> 16) | (preferredTerrain & 0xFFFF0000))&0xFFFFFFFF
                    mask |= 0x0000FFFF

                if (x > 0 and checked[i - 1]):
                    preferredTerrain = (((terrain(newTerrain[i - 1]) << 8) & 0xFF00FF00) | (preferredTerrain & 0x00FF00FF))&0xFFFFFFFF
                    mask |= 0xFF00FF00

                if (x < layerWidth - 1 and checked[i + 1]):
                    preferredTerrain = (((terrain(newTerrain[i + 1]) >> 8) & 0x00FF00FF) | (preferredTerrain & 0xFF00FF00))&0xFFFFFFFF
                    mask |= 0x00FF00FF

            # find the most appropriate tile in the tileset
            paste = None
            if (preferredTerrain != 0xFFFFFFFF):
                paste = findBestTile(tileset, preferredTerrain, mask)
                if (not paste):
                    continue

            # add tile to the brush
            newTerrain[i] = paste
            checked[i] = True
            # expand the brush rect to fit the edit set
            brushRect |= QRect(p, p)
            # consider surrounding tiles if terrain constraints were not satisfied
            if (y > 0 and not checked[i - layerWidth]):
                above = currentLayer.cellAt(x, y - 1).tile
                if (topEdge(paste) != bottomEdge(above)):
                    transitionList.append(QPoint(x, y - 1))

            if (y < layerHeight - 1 and not checked[i + layerWidth]):
                below = currentLayer.cellAt(x, y + 1).tile
                if (bottomEdge(paste) != topEdge(below)):
                    transitionList.append(QPoint(x, y + 1))

            if (x > 0 and not checked[i - 1]):
                left = currentLayer.cellAt(x - 1, y).tile
                if (leftEdge(paste) != rightEdge(left)):
                    transitionList.append(QPoint(x - 1, y))

            if (x < layerWidth - 1 and not checked[i + 1]):
                right = currentLayer.cellAt(x + 1, y).tile
                if (rightEdge(paste) != leftEdge(right)):
                    transitionList.append(QPoint(x + 1, y))

        # create a stamp for the terrain block
        stamp = TileLayer(QString(), brushRect.left(), brushRect.top(), brushRect.width(), brushRect.height())
        for y in range(brushRect.top(), brushRect.bottom()+1):
            for x in range(brushRect.left(), brushRect.right()+1):
                i = y*layerWidth + x
                if (not checked[i]):
                    continue
                tile = newTerrain[i]
                if (tile):
                    stamp.setCell(x - brushRect.left(), y - brushRect.top(), Cell(tile))
                else:
                    # TODO: we need to do something to erase tiles where checked[i] is True, and newTerrain[i] is NULL
                    # is there an eraser stamp? investigate how the eraser works...
                    pass

        # set the new tile layer as the brush
        self.brushItem().setTileLayer(stamp)
        del checked
        del newTerrain
        self.mPaintX = cursorPos.x()
        self.mPaintY = cursorPos.y()
        self.mOffsetX = cursorPos.x() - brushRect.left()
        self.mOffsetY = cursorPos.y() - brushRect.top()
示例#58
0
class Surface(QWidget):
    
    rightClicked = pyqtSignal(QPoint)
    linkClicked = pyqtSignal(QEvent, page.Page, popplerqt5.Poppler.Link)
    linkHovered = pyqtSignal(page.Page, popplerqt5.Poppler.Link)
    linkLeft = pyqtSignal()
    linkHelpRequested = pyqtSignal(QPoint, page.Page, popplerqt5.Poppler.Link)    
    selectionChanged = pyqtSignal(QRect)
    
    def __init__(self, view):
        super(Surface, self).__init__(view)
        self.setBackgroundRole(QPalette.Dark)
        self._view = weakref.ref(view)
        self._currentLinkId = None
        self._selecting = False
        self._magnifying = False
        self._magnifier = None
        self.setMagnifier(magnifier.Magnifier())
        self.setMagnifierModifiers(Qt.CTRL)
        self._selection = QRect()
        self._rubberBand = CustomRubberBand(self)
        self._scrolling = False
        self._scrollTimer = QTimer(interval=100, timeout=self._scrollTimeout)
        self._pageLayout = None
        self._highlights = weakref.WeakKeyDictionary()
        self.setPageLayout(layout.Layout())
        self.setContextMenuPolicy(Qt.PreventContextMenu)
        self.setLinksEnabled(True)
        self.setSelectionEnabled(True)
        self.setShowUrlTips(True)
        
        self.view().cursorNeedUpdate.connect(self.updateCursor)
 
    def pageLayout(self):
        return self._pageLayout
        
    def setPageLayout(self, layout):
        old, self._pageLayout = self._pageLayout, layout
        if old:
            old.redraw.disconnect(self.redraw)
            old.changed.disconnect(self.updateLayout)
        layout.redraw.connect(self.redraw)
        layout.changed.connect(self.updateLayout)
    
    def view(self):
        """Returns our associated View."""
        return self._view()
    
    def viewportRect(self):
        """Returns the rectangle of us that is visible in the View."""
        return self.view().viewport().rect().translated(-self.pos())
        
    def setSelectionEnabled(self, enabled):
        """Enables or disables selecting rectangular regions."""
        self._selectionEnabled = enabled
        if not enabled:
            self.clearSelection()
            self._rubberBand.hide()
            self._selecting = False
    
    def selectionEnabled(self):
        """Returns True if selecting rectangular regions is enabled."""
        return self._selectionEnabled
        
    def setLinksEnabled(self, enabled):
        """Enables or disables the handling of Poppler.Links in the pages."""
        self._linksEnabled = enabled
    
    def linksEnabled(self):
        """Returns True if the handling of Poppler.Links in the pages is enabled."""
        return self._linksEnabled
    
    def setShowUrlTips(self, enabled):
        """Enables or disables showing the URL in a tooltip when hovering a link.
        
        (Of course also setLinksEnabled(True) if you want this.)
        
        """
        self._showUrlTips = enabled
        
    def showUrlTips(self):
        """Returns True if URLs are shown in a tooltip when hovering a link."""
        return self._showUrlTips
        
    def setMagnifier(self, magnifier):
        """Sets the Magnifier to use (or None to disable the magnifier).
        
        The Surface takes ownership of the Magnifier.
        
        """
        if self._magnifier:
            self._magnifier.setParent(None)
        magnifier.setParent(self.view())
        self._magnifier = magnifier
    
    def magnifier(self):
        """Returns the currently set magnifier."""
        return self._magnifier
    
    def setMagnifierModifiers(self, modifiers):
        """Sets the modifiers (e.g. Qt.CTRL) to show the magnifier.
        
        Use None to show the magnifier always (instead of dragging).
        
        """
        self._magnifierModifiers = modifiers
    
    def magnifierModifiers(self):
        """Returns the currently set keyboard modifiers (e.g. Qt.CTRL) to show the magnifier."""
        return self._magnifierModifiers
        
    def hasSelection(self):
        """Returns True if there is a selection."""
        return bool(self._selection)
        
    def setSelection(self, rect):
        """Sets the selection rectangle."""
        rect = rect.normalized()
        old, self._selection = self._selection, rect
        self._rubberBand.setVisible(rect.isValid())
        self._rubberBand.setGeometry(rect)
        if rect != old:
            self.selectionChanged.emit(rect)
        
    def selection(self):
        """Returns the selection rectangle (normalized) or an invalid QRect()."""
        return QRect(self._selection)
    
    def clearSelection(self):
        """Hides the selection rectangle."""
        self.setSelection(QRect())
        
    def selectedPages(self):
        """Return a list of the Page objects the selection encompasses."""
        return list(self.pageLayout().pagesAt(self.selection()))
    
    def selectedPage(self):
        """Return the Page thas is selected for the largest part, or None."""
        pages = self.selectedPages()
        if not pages:
            return
        def key(page):
            size = page.rect().intersected(self.selection()).size()
            return size.width() + size.height()
        return max(pages, key = key)
    
    def selectedPageRect(self, page):
        """Return the QRect on the page that falls in the selection."""
        return self.selection().normalized().intersected(page.rect()).translated(-page.pos())

    def selectedText(self):
        """Return all text falling in the selection."""
        return '\n'.join(page.text(self.selection()) for page in self.selectedPages())
    
    def redraw(self, rect):
        """Called when the Layout wants to redraw a rectangle."""
        self.update(rect)
        
    def updateLayout(self):
        """Conforms ourselves to our layout (that must already be updated.)"""
        self.clearSelection()
        self.resize(self._pageLayout.size())
        self.update()
        
    def highlight(self, highlighter, areas, msec=0):
        """Highlights the list of areas using the given highlighter.
        
        Every area is a two-tuple (page, rect), where rect is a rectangle inside (0, 0, 1, 1) like the
        linkArea attribute of a Poppler.Link.
        
        """
        d = collections.defaultdict(list)
        for page, area in areas:
            d[page].append(area)
        d = weakref.WeakKeyDictionary(d)
        if msec:
            def clear(selfref=weakref.ref(self)):
                self = selfref()
                if self:
                    self.clearHighlight(highlighter)
            t = QTimer(singleShot = True, timeout = clear)
            t.start(msec)
        else:
            t = None
        self.clearHighlight(highlighter)
        self._highlights[highlighter] = (d, t)
        self.update(sum((page.rect() for page in d), QRegion()))
        
    def clearHighlight(self, highlighter):
        """Removes the highlighted areas of the given highlighter."""
        try:
            (d, t) = self._highlights[highlighter]
        except KeyError:
            return
        del self._highlights[highlighter]
        self.update(sum((page.rect() for page in d), QRegion()))
    
    def paintEvent(self, ev):
        """Handle PaintEvent on the surface to highlight the selection."""
        painter = QPainter(self)
        pages = list(self.pageLayout().pagesAt(ev.rect()))
        for page in pages:
            page.paint(painter, ev.rect())
        
        for highlighter, (d, t) in self._highlights.items():
            rects = []
            for page in pages:
                try:
                    rects.extend(map(page.linkRect, d[page]))
                except KeyError:
                    continue
            if rects:
                highlighter.paintRects(painter, rects)
    
    def handleMousePressEvent(self, ev):
        """Handle mouse press for various operations
            - links to source,
            - magnifier, 
            - selection highlight,
            
            If event was used, return true to indicate processing should stop.
        """
        
        # As the event comes from the view, we need to map it locally.
        pos = self.mapFromParent(ev.pos())
               
        # selecting?
        if self._selectionEnabled:
            if self.hasSelection():
                edge = selectionEdge(pos, self.selection())
                if edge == _OUTSIDE:
                    self.clearSelection()
                else:
                    if ev.button() != Qt.RightButton or edge != _INSIDE:
                        self._selecting = True
                        self._selectionEdge = edge
                        self._selectionRect = self.selection()
                        self._selectionPos = pos
                        if edge == _INSIDE:
                            self.setCursor(Qt.SizeAllCursor)
                    return True
            if not self._selecting:
                if ev.modifiers() & Qt.ShiftModifier and ev.button() == Qt.LeftButton and self._linksEnabled:
                    page, link = self.pageLayout().linkAt(pos)
                    if link:
                        self.linkClickEvent(ev, page, link)
                        return True
                if ev.button() == Qt.RightButton or int(ev.modifiers()) & _SCAM:
                    if not (int(ev.modifiers()) & _SCAM == self._magnifierModifiers 
                            and  ev.button() == Qt.LeftButton):
                        self._selecting = True
                        self._selectionEdge = _RIGHT | _BOTTOM
                        self._selectionRect = QRect(pos, QSize(0, 0))
                        self._selectionPos = pos
                        return True
        
        # link?
        if self._linksEnabled:
            page, link = self.pageLayout().linkAt(pos)
            if link:
                self.linkClickEvent(ev, page, link)
                return True
        # magnifier?
        if (self._magnifier and
            int(ev.modifiers()) & _SCAM == self._magnifierModifiers and
            ev.button() == Qt.LeftButton):
            self._magnifier.moveCenter(pos)
            self._magnifier.show()
            self._magnifier.raise_()
            self._magnifying = True
            self.setCursor(QCursor(Qt.BlankCursor))
            return True

        return False
        
    def handleMouseReleaseEvent(self, ev):
        """Handle mouse release events for various operations:
            - hide magnifier,
            - selection.
            
            If event was used, return true to indicate processing should stop.
        """
        consumed = False
        if self._magnifying:
            self._magnifier.hide()
            self._magnifying = False
            self.unsetCursor() 
            consumed = True
        elif self._selecting:
            self._selecting = False
            selection = self._selectionRect.normalized()
            if selection.width() < 8 and selection.height() < 8:
                self.clearSelection()
            else:
                self.setSelection(selection)
            if self._scrolling:
                self.stopScrolling()
            self.unsetCursor() 
            consumed = True
        if ev.button() == Qt.RightButton:
            # As the event comes from the view, we need to map it locally.
            self.rightClick(self.mapFromParent(ev.pos()))
            consumed = True
        
        return consumed
            
    def handleMouseMoveEvent(self, ev):
        """Handle mouse move events for various operations:
            - move magnifier,
            - selection extension.
            
            If event was used, return true to indicate processing should stop.
        """
        consumed = False 
        if self._magnifying:
            # As the event comes from the view, we need to map it locally.
            self._magnifier.moveCenter(self.mapFromParent(ev.pos()))
            consumed = True
        elif self._selecting:
            # As the event comes from the view, we need to map it locally.
            pos = self.mapFromParent(ev.pos())
            self._moveSelection(pos)
            self._rubberBand.show()
            # check if we are dragging close to the edge of the view, scroll if needed
            view = self.viewportRect()
            dx = pos.x() - view.left() - 12
            if dx >= 0:
                dx = pos.x() - view.right() + 12
                if dx < 0:
                    dx = 0
            dy = pos.y() - view.top() - 12
            if dy >= 0:
                dy = pos.y() - view.bottom() + 12
                if dy < 0:
                    dy = 0
            if dx or dy:
                self.startScrolling(dx, dy)
            elif self._scrolling:
                self.stopScrolling()
            consumed = True
              
        return consumed
        
    def handleMoveEvent(self, ev):
        """Handle  move events for various operations:
            - move magnifier,
            - selection extension.
            
            If event was used, return true to indicate processing should stop.
        """
        consumed = False
        pos = self.mapFromGlobal(QCursor.pos())
        if self._selecting:
            self._moveSelection(pos)
            consumed = True
        elif self._magnifying:
            self._magnifier.moveCenter(pos)
            consumed = True

        return consumed
        
    def handleHelpEvent(self, ev):
        """Handle help event: show link if any."""
        if self._linksEnabled:
            page, link = self.pageLayout().linkAt(self.mapFromParent(ev.pos()))
            if link:
                self.linkHelpEvent(ev.globalPos(), page, link)
        return True

    def updateKineticCursor(self, active):
        """Cursor handling when kinetic move starts/stops.
        
        - reset the cursor and hide tooltips if visible at start,
        - update the cursor and show the appropriate tooltips at stop.
        
        Used as a slot linked to the kineticStarted() signal.
        """
        if active:
            self.unsetCursor()
            if QToolTip.isVisible():
                QToolTip.hideText()
        else:
            self.updateCursor(QCursor.pos())
            if self._linksEnabled:
                page, link = self.pageLayout().linkAt(self.mapFromGlobal(QCursor.pos()))
                if link:
                    self.linkHelpEvent(QCursor.pos(), page, link)

    def updateCursor(self, evpos):
        """Set the cursor to the right glyph, depending on action""" 
        pos = self.mapFromGlobal(evpos)
        cursor = None
        edge = _OUTSIDE
        if self._selectionEnabled and self.hasSelection():
            edge = selectionEdge(pos, self.selection())
            
        if edge is not _OUTSIDE:
            if edge in (_TOP, _BOTTOM):
                cursor = Qt.SizeVerCursor
            elif edge in (_LEFT, _RIGHT):
                cursor = Qt.SizeHorCursor
            elif edge in (_LEFT | _TOP, _RIGHT | _BOTTOM):
                cursor = Qt.SizeFDiagCursor
            elif edge in (_TOP | _RIGHT, _BOTTOM | _LEFT):
                cursor = Qt.SizeBDiagCursor
            elif edge is _INSIDE:
                cursor = Qt.SizeAllCursor

        elif self._linksEnabled:
            page, link = self.pageLayout().linkAt(pos)
            if link:
                cursor = Qt.PointingHandCursor
                lid = id(link)
            else:
                lid = None
            if lid != self._currentLinkId:
                if self._currentLinkId is not None:
                    self.linkHoverLeave()
                self._currentLinkId = lid
                if link:
                    self.linkHoverEnter(page, link)
        
        self.setCursor(cursor) if cursor else self.unsetCursor()
    
    def linkHelpEvent(self, globalPos, page, link):
        """Called when a QHelpEvent occurs on a link.
        
        The default implementation shows a tooltip if showUrls() is True,
        and emits the linkHelpRequested() signal.
        
        """
        if self._showUrlTips and isinstance(link, popplerqt5.Poppler.LinkBrowse):
            QToolTip.showText(globalPos, link.url(), self, page.linkRect(link.linkArea()))
        self.linkHelpRequested.emit(globalPos, page, link)
        
    def rightClick(self, pos):
        """Called when the right mouse button is released.
        
        (Use this instead of the contextMenuEvent as that one also
        fires when starting a right-button selection.)
        The default implementation emits the rightClicked(pos) signal and also
        sends a ContextMenu event to the View widget.
        
        """
        self.rightClicked.emit(pos)
        QApplication.postEvent(self.view().viewport(), QContextMenuEvent(QContextMenuEvent.Mouse, pos + self.pos()))
        
    def linkClickEvent(self, ev, page, link):
        """Called when a link is clicked.
        
        The default implementation emits the linkClicked(event, page, link) signal.
        
        """
        self.linkClicked.emit(ev, page, link)
        
    def linkHoverEnter(self, page, link):
        """Called when the mouse hovers over a link.
        
        The default implementation emits the linkHovered(page, link) signal.
        
        """
        self.linkHovered.emit(page, link)
        
    def linkHoverLeave(self):
        """Called when the mouse does not hover a link anymore.
        
        The default implementation emits the linkLeft() signal.
        
        """
        self.linkLeft.emit()

    def startScrolling(self, dx, dy):
        """Starts scrolling dx, dy about 10 times a second.
        
        Stops automatically when the end is reached.
        
        """
        self._scrolling = QPoint(dx, dy)
        self._scrollTimer.isActive() or self._scrollTimer.start()
        
    def stopScrolling(self):
        """Stops scrolling."""
        self._scrolling = False
        self._scrollTimer.stop()
        
    def _scrollTimeout(self):
        """(Internal) Called by the _scrollTimer."""
        # change the scrollbars, but check how far they really moved.
        pos = self.pos()
        self.view().fastScrollBy(self._scrolling)
        diff = pos - self.pos()
        if not diff:
            self.stopScrolling()
    
    def _moveSelection(self, pos):
        """(Internal) Moves the dragged selection edge or corner to the given pos (QPoint)."""
        diff = pos - self._selectionPos
        self._selectionPos = pos
        edge = self._selectionEdge
        self._selectionRect.adjust(
            diff.x() if edge & _LEFT   else 0,
            diff.y() if edge & _TOP    else 0,
            diff.x() if edge & _RIGHT  else 0,
            diff.y() if edge & _BOTTOM else 0)
        rect = self._selectionRect.normalized()
        self._rubberBand.setVisible(rect.isValid())
        self._rubberBand.setGeometry(rect)
        if self.cursor().shape() in (Qt.SizeBDiagCursor, Qt.SizeFDiagCursor):
            # we're dragging a corner, use correct diagonal cursor
            bdiag = (edge in (3, 12)) ^ (self._selectionRect.width() * self._selectionRect.height() >= 0)
            self.setCursor(Qt.SizeBDiagCursor if bdiag else Qt.SizeFDiagCursor)