Example #1
0
 def replace(self):
     log.trace("Icon is %r", self._icon)
     self._icon_geometry = rect = self._icon.geometry()
     log.trace("IconRect is : %s,%s | %s,%s",rect.x(), rect.y(), rect.width(), rect.height())
     from PyQt4.QtGui import QApplication, QCursor
     from PyQt4.QtCore import QRect
     desktop = QApplication.desktop()
     log.trace("Screen id is %d", desktop.screenNumber(rect.topLeft()))
     screen = desktop.availableGeometry(desktop.screenNumber(rect.topLeft()))
     pos = screen
     log.trace("AvailableRect is : %s,%s | %s,%s",pos.x(), pos.y(), pos.width(), pos.height())
     pos = desktop.screenGeometry(desktop.screenNumber(rect.topLeft()))
     log.trace("ScreenRect is : %s,%s | %s,%s",pos.x(), pos.y(), pos.width(), pos.height())
     pos = QCursor.pos()
     log.trace("Cursor is : %s,%s",pos.x(), pos.y())
     if not rect.contains(pos) or (rect.x() == 0 and rect.y() == 0):
         # Avoid any modulo 0
         if rect.width() == 0 or rect.height() == 0:
             rect = QRect(pos.x(), pos.y(), rect.width(), rect.height())
         else:
             rect = QRect(pos.x()-pos.x()%rect.width(), pos.y()-pos.y()%rect.height(), rect.width(), rect.height())
         log.trace("Adjusting X/Y to %d/%d", rect.x(), rect.y())
         pos = rect
         log.trace("New rect is : %s,%s | %s,%s",pos.x(), pos.y(), pos.width(), pos.height())
     x = rect.x() + rect.width() - self.width()
     y = rect.y() - self.height()
     # Prevent the systray to be hidden
     if y < 0:
         y = rect.y() + rect.height()
     if x < 0:
         x = rect.x()
     log.trace("Move systray menu to %d/%d", x, y)
     self.move(x, y)
 def paintVerticalCell(self, painter: QPainter, hv: QHeaderView,
                       cellIndex: QModelIndex, leafIndex: QModelIndex,
                       logicalLeafIndex: int,
                       styleOptions: QStyleOptionHeader,
                       sectionRect: QRect, left: int):
     uniopt = QStyleOptionHeader(styleOptions)
     self.setForegroundBrush(uniopt, cellIndex)
     self.setBackgroundBrush(uniopt, cellIndex)
     width = self.cellSize(cellIndex, hv, uniopt).width()
     if cellIndex == leafIndex:
         width = sectionRect.width() - left
     top = self.currentCellLeft(cellIndex, leafIndex, logicalLeafIndex,
                                sectionRect.top(), hv)
     height = 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 = QMatrix()
         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 left + width
Example #3
0
def read_state(load=True):
    home = os.path.expanduser('~')

    r = QRect(0, 0, 640, 480)
    r.moveCenter(QApplication.desktop().availableGeometry().center())
    geometry = [r.x(), r.y(), r.width(), r.height()]

    state = dict(last_file_parent=home,
                 last_dir_parent=home,
                 last_save=home,
                 geometry=geometry,
                 zoom_factor=1.0,
                 history=[],
                 history_current=-1,
                 scroll_values={})
    try:
        if load and os.path.exists(state_file):
            f = gzip.open(state_file, 'rb')
            try:
                loaded = json.load(f)
                state.update(loaded)
            finally:
                f.close()
    except:
        show_error(_('Failed to load saved application state'))
    return state
Example #4
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)
Example #5
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)
Example #6
0
def read_state(load=True):
    home = os.path.expanduser('~')

    r = QRect(0, 0, 640, 480)
    r.moveCenter(QApplication.desktop().availableGeometry().center())
    geometry = [r.x(), r.y(), r.width(), r.height()]

    state = dict(last_file_parent=home,
                 last_dir_parent=home,
                 last_save=home,
                 geometry=geometry,
                 zoom_factor=1.0,
                 history=[],
                 history_current=-1,
                 scroll_values={})
    try:
        if load and os.path.exists(state_file):
            f = gzip.open(state_file, 'rb')
            try:            
                loaded = json.load(f)
                state.update(loaded)
            finally:
                f.close()
    except:
        show_error(_('Failed to load saved application state'))
    return state
Example #7
0
def ensure_on_screen(rect):
    """ Ensure that the given rect is contained on screen.

    If the origin of the rect is not contained within the closest
    desktop screen, the rect will be moved so that it is fully on the
    closest screen. If the rect is larger than the closest screen, the
    origin will never be less than the screen origin.

    Parameters
    ----------
    rect : QRect
        The geometry rect of interest.

    """
    d = QApplication.desktop()
    pos = rect.topLeft()
    drect = d.screenGeometry(pos)
    if not drect.contains(pos):
        x = pos.x()
        if x < drect.x() or x > drect.right():
            dw = drect.width() - rect.width()
            x = max(drect.x(), drect.x() + dw)
        y = pos.y()
        if x < drect.top() or y > drect.bottom():
            dh = drect.height() - rect.height()
            y = max(drect.y(), drect.y() + dh)
        rect = QRect(x, y, rect.width(), rect.height())
    return rect
Example #8
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)
Example #9
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)
Example #10
0
 def sizeHint(self, option, index):
     text = forceString(index.data())
     fontMetric = QtGui.QFontMetrics(option.font)
     rect = QRect(option.rect)
     rect = fontMetric.boundingRect(rect, Qt.Horizontal | Qt.TextWordWrap,
                                    text)
     height1 = rect.height()
     height2 = fontMetric.height() * 7
     return QSize(rect.width(), min(height1, height2))
Example #11
0
    def verticalGradient(cls, painter: QPainter, spanRect: QRect, clipRect: QRect, lightColored=False):
        if StyleHelper.usePixmapCache():
            keyColor = cls.baseColor(lightColored)
            key = "mh_vertical {1} {2} {3} {4} {5}".format(
                spanRect.width(), spanRect.height(), clipRect.width(),
                clipRect.height(), keyColor.rgb())

            pixmap = QPixmap()
            if not QPixmapCache.find(key, pixmap):
                pixmap = QPixmap(clipRect.size())
                p = QPainter(pixmap)
                rect = QRect(0, 0, clipRect.width(), clipRect.height())
                StyleHelper._verticalGradientHelper(p, spanRect, rect, lightColored)
                p.end()
                QPixmapCache.insert(key, pixmap)

            painter.drawPixmap(clipRect.topLeft(), pixmap)
        else:
            StyleHelper._verticalGradientHelper(painter, spanRect, clipRect, lightColored)
Example #12
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()
Example #13
0
 def paint(self, painter, option, index):
     painter.setFont(option.font)
     painter.setBrush(QBrush(Qt.black))
     if option.state & QStyle.State_Selected:
         painter.setPen(QPen(Qt.white))
     rect = QRect(option.rect)
     rect.setLeft(rect.left() + 4)
     rect.setTop(rect.top() + 4)
     rect.setWidth(rect.width() - 8)
     rect.setHeight(rect.height() - 8)
     painter.drawText(rect, Qt.Horizontal | Qt.TextWordWrap,
                      forceString(index.data()))
Example #14
0
 def replace(self):
     log.trace("Icon is %r", self._icon)
     self._icon_geometry = rect = self._icon.geometry()
     log.trace("IconRect is : %s,%s | %s,%s", rect.x(), rect.y(),
               rect.width(), rect.height())
     from PyQt4.QtGui import QApplication, QCursor
     from PyQt4.QtCore import QRect
     desktop = QApplication.desktop()
     log.trace("Screen id is %d", desktop.screenNumber(rect.topLeft()))
     screen = desktop.availableGeometry(desktop.screenNumber(
         rect.topLeft()))
     pos = screen
     log.trace("AvailableRect is : %s,%s | %s,%s", pos.x(), pos.y(),
               pos.width(), pos.height())
     pos = desktop.screenGeometry(desktop.screenNumber(rect.topLeft()))
     log.trace("ScreenRect is : %s,%s | %s,%s", pos.x(), pos.y(),
               pos.width(), pos.height())
     pos = QCursor.pos()
     log.trace("Cursor is : %s,%s", pos.x(), pos.y())
     if not rect.contains(pos) or (rect.x() == 0 and rect.y() == 0):
         # Avoid any modulo 0
         if rect.width() == 0 or rect.height() == 0:
             rect = QRect(pos.x(), pos.y(), rect.width(), rect.height())
         else:
             rect = QRect(pos.x() - pos.x() % rect.width(),
                          pos.y() - pos.y() % rect.height(), rect.width(),
                          rect.height())
         log.trace("Adjusting X/Y to %d/%d", rect.x(), rect.y())
         pos = rect
         log.trace("New rect is : %s,%s | %s,%s", pos.x(), pos.y(),
                   pos.width(), pos.height())
     x = rect.x() + rect.width() - self.width()
     y = rect.y() - self.height()
     # Prevent the systray to be hidden
     if y < 0:
         y = rect.y() + rect.height()
     if x < 0:
         x = rect.x()
     log.trace("Move systray menu to %d/%d", x, y)
     self.move(x, y)
Example #15
0
 def _handleMousePressEvent(self, event, superMethod):
     pos = event.pos()
     index = self.indexAt(pos)
     selected = index in self.selectedIndexes()
     superMethod(self, event)
     if not index.isValid():
         return
     rect = self.visualRect(index)
     relativePos = QPoint(pos.x()-rect.x(), pos.y()-rect.y())
     delegate = self.itemDelegate(index)
     # handleClick(index, relativePos, itemRect, selected)
     if hasattr(delegate, 'handleClick'):
         rect = QRect(0, 0, rect.width(), rect.height())
         delegate.handleClick(index, relativePos, rect, selected)
Example #16
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)
Example #17
0
    def paint(self, painter, option, index):
        """ Draw a button-style on root items """
        model = index.model()
        assert model


        if not model.parent(index).isValid():
            # this is a top-level item.
            buttonOption = QStyleOptionButton()

            buttonOption.state = option.state
            buttonOption.state &= ~QStyle.State_HasFocus

            buttonOption.rect = option.rect
            buttonOption.palette = option.palette
            buttonOption.features = QStyleOptionButton.None

            self.m_view.style().drawControl(QStyle.CE_PushButton, buttonOption, painter, self.m_view)

            branchOption = QStyleOption()
            i = 15  ### hardcoded in qcommonstyle.cpp
            r = option.rect
            branchOption.rect = QRect(r.left() + i/2, r.top() + (r.height() - i)/2, i, i)
            branchOption.palette = option.palette
#            branchOption.state = QStyle.State_Children

            if self.m_view.isExpanded(index):
                branchOption.state |= QStyle.State_Open

            self.m_view.style().drawPrimitive(QStyle.PE_IndicatorBranch, branchOption, painter, self.m_view)

            # draw text
            textrect = QRect(r.left() + i*2, r.top(), r.width() - ((5*i)/2), r.height())
            text = self.elidedText(option.fontMetrics, textrect.width(), Qt.ElideMiddle,
                              model.data(index, Qt.DisplayRole).toString())
            self.m_view.style().drawItemText(painter, textrect,Qt.AlignLeft|Qt.AlignVCenter,
                                             option.palette, self.m_view.isEnabled(), text)

            icon_variant = index.data(Qt.DecorationRole)
            icon = QIcon(icon_variant)
            self.m_view.style().drawItemPixmap(
                                               painter, option.rect,
                                               Qt.AlignLeft,
                                               icon.pixmap(icon.actualSize(QSize(20 ,20)))
                                               )

        else:
            QItemDelegate.paint(self, painter, option, index)
Example #18
0
    def mouse_over_widget(self, widget, pos, empty=False):
        """ Update the overlays based on the mouse position.

        This handler should be invoked when the mouse hovers over a
        single widget (such as a floating dock container) as opposed to
        an area of docked widgets. The guide rose will be displayed in
        the center of the widget with no border guides.

        Parameters
        ----------
        widget : QWidget
            The widget under the mouse.

        pos : QPoint
            The hover position, expressed in the local coordinates of
            the widget.

        empty : bool, optional
            Whether the widget represents an empty widget. If this is
            True, a single center guide will be shown instead of the
            guide rose.

        """
        Mode = QGuideRose.Mode
        rose = self._rose
        target_mode = Mode.AreaCenter if empty else Mode.CompassEx
        self._target_rose_mode = target_mode
        if rose.mode() != target_mode:
            rose.setMode(Mode.NoMode)
            self._rose_timer.start(self.rose_delay)
            self._band_timer.start(self.band_delay)
        origin = widget.mapToGlobal(QPoint(0, 0))
        geo = QRect(origin, widget.size())
        dirty = rose.geometry() != geo
        if dirty:
            rose.hide()
            rose.setMode(Mode.NoMode)
            rose.setGeometry(geo)
        guide = rose.guideAt(pos, target_mode)
        if dirty or guide != self._last_guide:
            self._last_guide = guide
            self._target_band_geo = self._band_geometry(widget, guide)
            self._band_timer.start(self.band_delay)
        rose.setCenterPoint(QPoint(geo.width() / 2, geo.height() / 2))
        rose.mouseOver(pos)
        rose.show()
Example #19
0
 def paintEvent(self, event):
     QWidget.paintEvent(self, event)
     p = QPainter(self)
     p.setFont(self.font)
     if self.pixmap:
         p.drawPixmap(QPoint(0,0), self.pixmap)
     r = QRect(self.rect().topLeft() + QPoint(0, 180), QSize(self.rect().size().width(), p.fontMetrics().height()))
     p.fillRect(r, self.palette().midlight())
     if self.progress:
         pr = QRect(r)
         pr.setWidth( (r.width() * self.progress) / 100 )
         p.fillRect(pr, self.palette().dark())
     p.setBrush(Qt.NoBrush)
     p.setPen(QPen(self.palette().text(), 1))
     p.drawText(QRectF(r), self.title, QTextOption(Qt.AlignHCenter))
     p.setPen(QPen(self.palette().shadow(), 1))
     p.drawRect(self.rect().adjusted(0,0,-1,-1))
Example #20
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 - QStyleOptionViewItemV4
            index - QModelIndex
        """
        self.initStyleOption(option, index)
        # I don't know why I have to do this. option.version returns 4, but still, when I try to
        # access option.features, boom-crash. The workaround is to force a V4.
        option = QStyleOptionViewItemV4(option)
        decorations = self._get_decorations(index, bool(option.state & QStyle.State_Selected))
        if decorations:
            option.decorationPosition = QStyleOptionViewItemV4.Right
            decorationWidth = sum(dec.pixmap.width() for dec in decorations)
            decorationHeight = max(dec.pixmap.height() for dec in decorations)
            option.decorationSize = QSize(decorationWidth, decorationHeight)
            option.features |= QStyleOptionViewItemV4.HasDecoration
        self._prepare_paint_options(option, index)

        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 = QStyleOptionViewItemV4(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)

        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()
Example #21
0
    def _drawStyledBar(self, painter, option):
        rect = option.rect
        key = "fancy styledbar %d %d %d" % (rect.width(), rect.height(),
                                            theme.baseColor.rgb())
        pixmap = QPixmap()
        p = painter
        if theme.usePixmapCache() and not QPixmapCache.find(key, pixmap):
            pixmap = QPixmap(rect.size())
            p = QPainter(pixmap)
            rect = QRect(0, 0, rect.width(), rect.height())

        horizontal = option.state & QStyle.State_Horizontal
        offset = self.window().mapToGlobal(
            option.rect.topLeft()) - self.mapToGlobal(option.rect.topLeft())
        gradientSpan = QRect(offset, self.window().size())

        if horizontal:
            theme.horizontalGradient(p, gradientSpan, rect)
        else:
            theme.verticalGradient(p, gradientSpan, rect)

        painter.setPen(theme.borderColor)

        if horizontal:
            lighter = QColor(255, 255, 255, 40)
            if self._topBorder:
                p.drawLine(rect.topLeft(), rect.topRight())
                p.setPen(lighter)
                p.drawLine(rect.topLeft() + QPoint(0, 1),
                           rect.topRight() + QPoint(0, 1))
            else:
                p.drawLine(rect.bottomLeft(), rect.bottomRight())
                p.setPen(lighter)
                p.drawLine(rect.topLeft(), rect.topRight())
        else:
            p.drawLine(rect.topLeft(), rect.bottomLeft())
            p.drawLine(rect.topRight(), rect.bottomRight())

        if theme.usePixmapCache() and not QPixmapCache.find(key, pixmap):
            painter.drawPixmap(rect.topLeft(), pixmap)
            p.end()
            del p
            QPixmapCache.insert(key, pixmap)
Example #22
0
 def paintEvent(self, event):
     '''Overrides QWidtget's paintEvent.'''
     # pylint: disable=C0103
     QtGui.QWidget.paintEvent(self, event)
     self._painter.begin(self)
     pixmap_dest_rect = QRect(self._image_origin * self._zoom, 
                              self._pixmap.size()*self._zoom)
     self._painter.drawPixmap(pixmap_dest_rect, self._pixmap)
     if not self._selection_rect.isNull():
         # preparing the darkened frame:
         sel_rect = self._selection_rect.normalized()
         frame = QtGui.QPixmap(event.rect().size())
         frame.fill(QtGui.QColor(0, 0, 0, 127))
         frame_painter = QtGui.QPainter(frame)
         # erase the selected area from the frame:
         frame_painter.setCompositionMode(
                             QtGui.QPainter.CompositionMode_DestinationIn)
         sel_rect_scaled = QRect(sel_rect.topLeft() * self._zoom,
                                 sel_rect.size() * self._zoom)
         frame_painter.fillRect(sel_rect_scaled, QtGui.QColor(0, 0, 0, 0))
         # draw selection border :
         frame_painter.setCompositionMode(
                             QtGui.QPainter.CompositionMode_SourceOver)
         frame_painter.setPen(self._hl_color1)
         frame_painter.drawRect(sel_rect_scaled)
         # draw the resize grip (if possible)
         if sel_rect_scaled.width() > 20 and sel_rect_scaled.height() > 20:
             handle_rect = QRect(sel_rect_scaled.bottomRight(), 
                                 self._handle_size)
             frame_painter.fillRect(handle_rect, self._hl_color2)
             frame_painter.drawRect(handle_rect)
         frame_painter.end()
         # painting the darkened frame:
         self._painter.drawPixmap(0, 0, frame)
         
     self._painter.end()
Example #23
0
    def paintEvent(self, event):
        '''Overrides QWidtget's paintEvent.'''
        # pylint: disable=C0103
        QtGui.QWidget.paintEvent(self, event)
        self._painter.begin(self)
        pixmap_dest_rect = QRect(self._image_origin * self._zoom,
                                 self._pixmap.size() * self._zoom)
        self._painter.drawPixmap(pixmap_dest_rect, self._pixmap)
        if not self._selection_rect.isNull():
            # preparing the darkened frame:
            sel_rect = self._selection_rect.normalized()
            frame = QtGui.QPixmap(event.rect().size())
            frame.fill(QtGui.QColor(0, 0, 0, 127))
            frame_painter = QtGui.QPainter(frame)
            # erase the selected area from the frame:
            frame_painter.setCompositionMode(
                QtGui.QPainter.CompositionMode_DestinationIn)
            sel_rect_scaled = QRect(sel_rect.topLeft() * self._zoom,
                                    sel_rect.size() * self._zoom)
            frame_painter.fillRect(sel_rect_scaled, QtGui.QColor(0, 0, 0, 0))
            # draw selection border :
            frame_painter.setCompositionMode(
                QtGui.QPainter.CompositionMode_SourceOver)
            frame_painter.setPen(self._hl_color1)
            frame_painter.drawRect(sel_rect_scaled)
            # draw the resize grip (if possible)
            if sel_rect_scaled.width() > 20 and sel_rect_scaled.height() > 20:
                handle_rect = QRect(sel_rect_scaled.bottomRight(),
                                    self._handle_size)
                frame_painter.fillRect(handle_rect, self._hl_color2)
                frame_painter.drawRect(handle_rect)
            frame_painter.end()
            # painting the darkened frame:
            self._painter.drawPixmap(0, 0, frame)

        self._painter.end()
Example #24
0
    def paint(self, painter, option, index):
        self.initStyleOption(option, index)
        if hasattr(option, "checkState"):
            if option.checkState == Qt.Unchecked:
                option.checkState = Qt.PartiallyChecked
            elif option.checkState == Qt.PartiallyChecked:
                option.checkState = Qt.Unchecked
            elif option.checkState == Qt.Checked:
                option.font = QFont(option.font)
                option.font.setStrikeOut(True)
        # ref: qt4-x11-4.6.2/src/gui/styles/qcommonstyle.cpp
        painter.save()
        painter.setClipRect(option.rect)
        # QApplication.style().drawControl(
        #     QStyle.CE_ItemViewItem, option, painter,
        #     getattr(option, "widget", None))
        style = QApplication.style()
        widget = getattr(option, "widget", None)
        # log.debug("widget: %r style: %r" % (widget, style.metaObject().className()))
        style.drawPrimitive(
            QStyle.PE_PanelItemViewItem, option, painter, widget)

        if option.checkState == Qt.Checked:
            painter.setOpacity(0.3)
        text_rect = style.subElementRect(
            QStyle.SE_ItemViewItemText, option, widget)
        item_text = option.fontMetrics.elidedText(
            option.text, option.textElideMode, text_rect.width())
        painter.setFont(option.font)
        style.drawItemText(painter, text_rect, option.displayAlignment,
                           option.palette, True, item_text, QPalette.Text)

        check_rect = style.subElementRect(
            QStyle.SE_ItemViewItemCheckIndicator, option, widget)
        if option.checkState == Qt.PartiallyChecked:
            brush = option.palette.brush(QPalette.Base)
            painter.fillRect(check_rect, brush)
            bullet_rect = QRect(check_rect)
            if bullet_rect.width() > BULLET_SIZE:
                bullet_rect.setLeft(
                    bullet_rect.left() +
                    (bullet_rect.width() - BULLET_SIZE) / 2)
                bullet_rect.setWidth(BULLET_SIZE)
            if bullet_rect.height() > BULLET_SIZE:
                bullet_rect.setTop(
                    bullet_rect.top() +
                    (bullet_rect.height() - BULLET_SIZE) / 2)
                bullet_rect.setHeight(BULLET_SIZE)
            painter.setPen(QPen(option.palette.color(QPalette.Text)))
            painter.setBrush(option.palette.brush(QPalette.Text))
            painter.drawEllipse(bullet_rect)
        else:
            check_opt = QStyleOptionButton()
            check_opt.rect = check_rect
            check_opt.state = option.state & ~QStyle.State_HasFocus
            if option.checkState == Qt.Checked:
                check_opt.state |= QStyle.State_On
            else:
                check_opt.state |= QStyle.State_Off
            style.drawPrimitive(
                QStyle.PE_IndicatorItemViewItemCheck, check_opt, painter,
                widget)
        painter.restore()
Example #25
0
class SelectByRect(QgsMapTool):
    def __init__(self, canvas):
        self.mCanvas = canvas
        QgsMapTool.__init__(self, canvas)
        self.mCursor = Qt.ArrowCursor
        self.mRubberBand = None
        self.mDragging = False
        self.mSelectRect = QRect()

#     QgsRubberBand* mRubberBand;
#     def reset(self):
#         self.startPoint = None
#         self.endPoint = None
#         self.isDrawing = False
#         SelectByRect.RubberRect.reset(QGis.Polygon)
#         self.layer = self.canvas.currentLayer()

    def canvasPressEvent(self, e):
        self.mSelectRect.setRect(0, 0, 0, 0)
        self.mRubberBand = QgsRubberBand(self.mCanvas, QGis.Polygon)
#         self.reset()
#         self.startPoint = self.toMapCoordinates(e.pos())
#         self.isDrawing = True

    def canvasMoveEvent(self, e):
        if (e.buttons() != Qt.LeftButton):
            return
        if (not self.mDragging):
            self.mDragging = True
            self.mSelectRect.setTopLeft(e.pos())
        self.mSelectRect.setBottomRight(e.pos())
        QgsMapToolSelectUtils.setRubberBand(self.mCanvas, self.mSelectRect,
                                            self.mRubberBand)
#         if not self.isDrawing:
#             return
#         SelectByRect.RubberRect.reset(QGis.Polygon)
#         self.endPoint = self.toMapCoordinates(e.pos())
#         self.rect = QgsRectangle(self.startPoint, self.endPoint)
#         SelectByRect.RubberRect.addGeometry(QgsGeometry.fromRect(self.rect), None)
#         SelectByRect.RubberRect.show()

    def canvasReleaseEvent(self, e):
        selectedFeatures = None
        vlayer = QgsMapToolSelectUtils.getCurrentVectorLayer(self.mCanvas)
        if (vlayer == None):
            if (self.mRubberBand != None):
                self.mRubberBand.reset(QGis.Polygon)
                del self.mRubberBand
                self.mRubberBand = None
                self.mDragging = False
            return

        if (not self.mDragging):
            QgsMapToolSelectUtils.expandSelectRectangle(
                self.mSelectRect, vlayer, e.pos())
        else:
            if (self.mSelectRect.width() == 1):
                self.mSelectRect.setLeft(self.mSelectRect.left() + 1)
            if (self.mSelectRect.height() == 1):
                self.mSelectRect.setBottom(self.mSelectRect.bottom() + 1)

        if (self.mRubberBand != None):
            QgsMapToolSelectUtils.setRubberBand(self.mCanvas, self.mSelectRect,
                                                self.mRubberBand)
            selectGeom = self.mRubberBand.asGeometry()
            # QgsMapToolSelectUtils.setSelectFeatures( self.mCanvas, selectGeom, e )
            selectedFeatures = QgsMapToolSelectUtils.setSelectFeatures1(
                self.mCanvas, selectGeom, e)
            del selectGeom

            self.mRubberBand.reset(QGis.Polygon)
            del self.mRubberBand
            self.mRubberBand = None
        self.mDragging = False
        self.emit(SIGNAL("getSelectedFeatures"), selectedFeatures)
Example #26
0
class Phantom(QObject):
    def __init__(self, args, parent=None):
        QObject.__init__(self, parent)

        # variable declarations
        self.m_loadStatus = self.m_state = ''
        self.m_var = self.m_paperSize = self.m_loadScript_cache = {}
        self.m_verbose = args.verbose
        self.m_page = WebPage(self)
        self.m_clipRect = QRect()
        # setup the values from args
        self.m_script = args.script.read()
        self.m_scriptFile = args.script.name
        self.m_scriptDir = os.path.dirname(args.script.name) + '/'
        self.m_args = args.script_args
        self.m_upload_file = args.upload_file
        autoLoadImages = False if args.load_images == 'no' else True
        pluginsEnabled = True if args.load_plugins == 'yes' else False

        args.script.close()

        do_action('PhantomInitPre', Bunch(locals()))

        palette = self.m_page.palette()
        palette.setBrush(QPalette.Base, Qt.transparent)
        self.m_page.setPalette(palette)

        if not args.proxy:
            QNetworkProxyFactory.setUseSystemConfiguration(True)
        else:
            proxy = QNetworkProxy(QNetworkProxy.HttpProxy, args.proxy[0],
                                  int(args.proxy[1]))
            QNetworkProxy.setApplicationProxy(proxy)

        self.m_page.settings().setAttribute(QWebSettings.AutoLoadImages,
                                            autoLoadImages)
        self.m_page.settings().setAttribute(QWebSettings.PluginsEnabled,
                                            pluginsEnabled)
        self.m_page.settings().setAttribute(
            QWebSettings.FrameFlatteningEnabled, True)
        self.m_page.settings().setAttribute(
            QWebSettings.OfflineStorageDatabaseEnabled, True)
        self.m_page.settings().setAttribute(QWebSettings.LocalStorageEnabled,
                                            True)
        self.m_page.settings().setLocalStoragePath(
            QDesktopServices.storageLocation(QDesktopServices.DataLocation))
        self.m_page.settings().setOfflineStoragePath(
            QDesktopServices.storageLocation(QDesktopServices.DataLocation))

        # Ensure we have a document.body.
        self.m_page.mainFrame().setHtml('<html><body></body></html>')

        self.m_page.mainFrame().setScrollBarPolicy(Qt.Horizontal,
                                                   Qt.ScrollBarAlwaysOff)
        self.m_page.mainFrame().setScrollBarPolicy(Qt.Vertical,
                                                   Qt.ScrollBarAlwaysOff)

        m_netAccessMan = NetworkAccessManager(args.disk_cache,
                                              args.ignore_ssl_errors, self)
        self.m_page.setNetworkAccessManager(m_netAccessMan)

        # inject our properties and slots into javascript
        self.m_page.mainFrame().javaScriptWindowObjectCleared.connect(
            self.inject)
        self.m_page.loadFinished.connect(self.finish)

        do_action('PhantomInitPost', Bunch(locals()))

    def execute(self):
        if self.m_script.startswith('#!'):
            self.m_script = '//' + self.m_script

        if self.m_scriptFile.lower().endswith('.coffee'):
            coffee = CSConverter(self)
            self.m_script = coffee.convert(self.m_script)

        self.m_page.mainFrame().evaluateJavaScript(self.m_script)

    def finish(self, success):
        self.m_loadStatus = 'success' if success else 'fail'
        self.m_page.mainFrame().evaluateJavaScript(self.m_script)

    def inject(self):
        self.m_page.mainFrame().addToJavaScriptWindowObject('phantom', self)

    def renderPdf(self, fileName):
        p = QPrinter()
        p.setOutputFormat(QPrinter.PdfFormat)
        p.setOutputFileName(fileName)
        p.setResolution(pdf_dpi)
        paperSize = self.m_paperSize

        if not len(paperSize):
            pageSize = QSize(self.m_page.mainFrame().contentsSize())
            paperSize['width'] = str(pageSize.width()) + 'px'
            paperSize['height'] = str(pageSize.height()) + 'px'
            paperSize['border'] = '0px'

        if paperSize.get('width') and paperSize.get('height'):
            sizePt = QSizeF(ceil(self.stringToPointSize(paperSize['width'])),
                            ceil(self.stringToPointSize(paperSize['height'])))
            p.setPaperSize(sizePt, QPrinter.Point)
        elif 'format' in paperSize:
            orientation = QPrinter.Landscape if paperSize.get(
                'orientation') and paperSize['orientation'].lower(
                ) == 'landscape' else QPrinter.Portrait
            orientation = QPrinter.Orientation(orientation)
            p.setOrientation(orientation)

            formats = {
                'A3': QPrinter.A3,
                'A4': QPrinter.A4,
                'A5': QPrinter.A5,
                'Legal': QPrinter.Legal,
                'Letter': QPrinter.Letter,
                'Tabloid': QPrinter.Tabloid
            }

            p.setPaperSize(QPrinter.A4)  # fallback
            for format, size in formats.items():
                if format.lower() == paperSize['format'].lower():
                    p.setPaperSize(size)
                    break
        else:
            return False

        border = floor(self.stringToPointSize(
            paperSize['border'])) if paperSize.get('border') else 0
        p.setPageMargins(border, border, border, border, QPrinter.Point)

        self.m_page.mainFrame().print_(p)
        return True

    def returnValue(self):
        return self.m_returnValue

    def stringToPointSize(self, string):
        units = (('mm', 72 / 25.4), ('cm', 72 / 2.54), ('in', 72.0),
                 ('px', 72.0 / pdf_dpi / 2.54), ('', 72.0 / pdf_dpi / 2.54))

        for unit, format in units:
            if string.endswith(unit):
                value = string.rstrip(unit)
                return float(value) * format
        return 0

    ##
    # Properties and methods exposed to JavaScript
    ##

    @pyqtProperty('QStringList')
    def args(self):
        return self.m_args

    @pyqtProperty('QVariantMap')
    def clipRect(self):
        result = {
            'width': self.m_clipRect.width(),
            'height': self.m_clipRect.height(),
            'top': self.m_clipRect.top(),
            'left': self.m_clipRect.left()
        }
        return result

    @clipRect.setter
    def clipRect(self, size):
        names = ('width', 'height', 'top', 'left')
        for item in names:
            try:
                globals()[item] = int(size[item])
                if globals()[item] < 0:
                    if item not in ('top', 'left'):
                        globals()[item] = 0
            except KeyError:
                globals()[item] = getattr(self.m_clipRect, item)()

        self.m_clipRect = QRect(left, top, width, height)

    @pyqtProperty(str)
    def content(self):
        return self.m_page.mainFrame().toHtml()

    @content.setter
    def content(self, content):
        self.m_page.mainFrame().setHtml(content)

    @pyqtSlot()
    @pyqtSlot(int)
    def exit(self, code=0):
        self.m_returnValue = code
        self.m_page.loadFinished.disconnect(self.finish)
        QTimer.singleShot(0, qApp, SLOT('quit()'))

    @pyqtProperty(str)
    def loadStatus(self):
        return self.m_loadStatus

    @pyqtSlot(str, result=bool)
    def loadScript(self, script):
        if script in self.m_loadScript_cache:
            self.m_page.mainFrame().evaluateJavaScript(
                self.m_loadScript_cache[script])
            return True

        scriptFile = script
        try:
            script = codecs.open(self.m_scriptDir + script, encoding='utf-8')
            script = script.read()
        except IOError:
            return False

        if script.startswith('#!'):
            script = '//' + script

        if scriptFile.lower().endswith('.coffee'):
            coffee = CSConverter(self)
            script = coffee.convert(script)

        self.m_loadScript_cache[scriptFile] = script
        self.m_page.mainFrame().evaluateJavaScript(script)
        return True

    @pyqtSlot(str, name='open')
    def open_(self, address):
        qDebug('Opening address %s' % address)
        self.m_page.triggerAction(QWebPage.Stop)
        self.m_loadStatus = 'loading'
        self.m_page.mainFrame().setUrl(QUrl(address))

    @pyqtProperty('QVariantMap')
    def paperSize(self):
        return self.m_paperSize

    @paperSize.setter
    def paperSize(self, size):
        self.m_paperSize = size

    @pyqtSlot(str, result=bool)
    def render(self, fileName):
        fileInfo = QFileInfo(fileName)
        path = QDir()
        path.mkpath(fileInfo.absolutePath())

        if fileName.lower().endswith('.pdf'):
            return self.renderPdf(fileName)

        viewportSize = QSize(self.m_page.viewportSize())
        pageSize = QSize(self.m_page.mainFrame().contentsSize())

        bufferSize = QSize()
        if not self.m_clipRect.isEmpty():
            bufferSize = self.m_clipRect.size()
        else:
            bufferSize = self.m_page.mainFrame().contentsSize()

        if pageSize == '':
            return False

        image = QImage(bufferSize, QImage.Format_ARGB32)
        image.fill(qRgba(255, 255, 255, 0))
        p = QPainter(image)

        p.setRenderHint(QPainter.Antialiasing, True)
        p.setRenderHint(QPainter.TextAntialiasing, True)
        p.setRenderHint(QPainter.SmoothPixmapTransform, True)

        self.m_page.setViewportSize(pageSize)

        if not self.m_clipRect.isEmpty():
            p.translate(-self.m_clipRect.left(), -self.m_clipRect.top())
            self.m_page.mainFrame().render(p, QRegion(self.m_clipRect))
        else:
            self.m_page.mainFrame().render(p)

        p.end()
        self.m_page.setViewportSize(viewportSize)
        return image.save(fileName)

    @pyqtSlot('QWebElement', str)
    def setFormInputFile(self, el, fileTag):
        self.m_page.m_nextFileTag = fileTag
        el.evaluateJavaScript('''(function(target){
                              var evt = document.createEvent('MouseEvents');
                              evt.initMouseEvent("click", true, true, window,
                              0, 0, 0, 0, 0, false, false, false, false, 0, null);
                              target.dispatchEvent(evt);})(this);''')

    @pyqtSlot(int)
    def sleep(self, ms):
        startTime = QTime.currentTime()
        while True:
            QApplication.processEvents(QEventLoop.AllEvents, 25)
            if startTime.msecsTo(QTime.currentTime()) > ms:
                break
            usleep(0.005)

    @pyqtProperty(str)
    def state(self):
        return self.m_state

    @state.setter
    def state(self, value):
        self.m_state = value

    @pyqtProperty(str)
    def userAgent(self):
        return self.m_page.m_userAgent

    @userAgent.setter
    def userAgent(self, ua):
        self.m_page.m_userAgent = ua

    @pyqtSlot(str, result='QVariant')
    @pyqtSlot(int, result='QVariant')
    @pyqtSlot(str, 'QVariant')
    @pyqtSlot(int, 'QVariant')
    def ctx(self, name, value=None):
        if not value:
            return self.m_var.get(name)
        self.m_var[name] = value

    @pyqtProperty('QVariantMap')
    def version(self):
        version = {
            'major': version_major,
            'minor': version_minor,
            'patch': version_patch
        }
        return version

    @pyqtProperty('QVariantMap')
    def viewportSize(self):
        size = self.m_page.viewportSize()
        result = {'width': size.width(), 'height': size.height()}
        return result

    @viewportSize.setter
    def viewportSize(self, size):
        names = ('width', 'height')
        for item in names:
            try:
                globals()[item] = int(size[item])
                if globals()[item] < 0:
                    globals()[item] = 0
            except KeyError:
                globals()[item] = getattr(self.m_page.viewportSize(), item)()

        self.m_page.setViewportSize(QSize(width, height))

    do_action('Phantom', Bunch(locals()))
Example #27
0
class StartupScreen(VispaWidget):

    # inherited parameters
    BACKGROUND_SHAPE = 'ROUNDRECT'
    SELECTABLE_FLAG = False
    AUTOSIZE = True
    AUTOSIZE_KEEP_ASPECT_RATIO = False

    PROTOTYPING_DESCRIPTION = """Prototyping"""

    EXECUTING_DESCRIPTION = """Executing"""

    VERIFYING_DESCRIPTION = """Verifying"""

    def __init__(self, parent):
        self._descriptionWidgets = []
        self._descriptionActiveRects = [
            QRect(), QRect(), QRect()
        ]  # descriptions will be visible if mouse cursor is in the rect
        VispaWidget.__init__(self, parent)
        self._filenewIcon = QIcon(QPixmap(":/resources/filenew.svg"))
        self._fileopenIcon = QIcon(QPixmap(":/resources/fileopen.svg"))
        self.setImage(
            QSvgRenderer(":/resources/startup_development_cycle.svg"))
        self.setDragable(False)
        self.setMouseTracking(
            True)  # receive mouse events even if no button is pressed
        self._hideDescriptions = False

        self.createPrototypingWidget()
        self.createExecutionWidget()
        self.createVerifyingWidget()

    def createDescriptionWidget(self, arrowDirection, description):
        widget = VispaWidget(self.parent())
        widget.enableAutosizing(True, False)
        widget.setSelectable(False)
        widget.setArrowShape(arrowDirection)
        widget.setVisible(not self._hideDescriptions)
        widget.setDragable(False)
        self._descriptionWidgets.append(widget)
        return widget

    def createPrototypingWidget(self):
        self._prototypingDescriptionWidget = self.createDescriptionWidget(
            VispaWidget.ARROW_SHAPE_BOTTOM, self.PROTOTYPING_DESCRIPTION)

        bodyWidget = QWidget(self._prototypingDescriptionWidget)
        bodyWidget.setLayout(QGridLayout())
        bodyWidget.layout().setContentsMargins(0, 0, 0, 0)

        bodyWidget.layout().addWidget(QLabel("Design physics analysis:"), 0, 0)
        analysisDesignerButton = QToolButton()
        analysisDesignerButton.setText("Analysis Designer")
        analysisDesignerButton.setIcon(self._filenewIcon)
        self.connect(analysisDesignerButton, SIGNAL("clicked(bool)"),
                     self.parent().newAnalysisDesignerSlot)
        bodyWidget.layout().addWidget(analysisDesignerButton, 0, 1)
        bodyWidget.layout().addWidget(QLabel("Create physics event:"), 1, 0)
        pxlButton = QToolButton()
        pxlButton.setText("PXL Editor")
        pxlButton.setIcon(self._filenewIcon)
        self.connect(pxlButton, SIGNAL("clicked(bool)"),
                     self.parent().newPxlSlot)
        bodyWidget.layout().addWidget(pxlButton, 1, 1)

        self._prototypingDescriptionWidget.setBodyWidget(bodyWidget)

    def createExecutionWidget(self):
        self._executionDescriptionWidget = self.createDescriptionWidget(
            VispaWidget.ARROW_SHAPE_RIGHT, self.EXECUTING_DESCRIPTION)

        bodyWidget = QWidget(self._executionDescriptionWidget)
        bodyWidget.setLayout(QGridLayout())
        bodyWidget.layout().setContentsMargins(0, 0, 0, 0)

        label = QLabel("Open and run existing analysis:")
        bodyWidget.layout().addWidget(label, 0, 0)
        analysisDesignerButton = QToolButton()
        analysisDesignerButton.setText("Open analysis file")
        analysisDesignerButton.setIcon(self._fileopenIcon)
        self.connect(analysisDesignerButton, SIGNAL("clicked(bool)"),
                     self.parent().openAnalysisFileSlot)
        bodyWidget.layout().addWidget(analysisDesignerButton, 0, 1)
        self._analysisDesignerRecentFilesList = QListWidget()
        self._analysisDesignerRecentFilesList.setFixedSize(
            label.sizeHint().width() +
            analysisDesignerButton.sizeHint().width(), 150)
        self.connect(self._analysisDesignerRecentFilesList,
                     SIGNAL("doubleClicked(QModelIndex)"),
                     self.parent().openAnalysisFileSlot)
        bodyWidget.layout().addWidget(self._analysisDesignerRecentFilesList, 1,
                                      0, 1, 2)

        self._executionDescriptionWidget.setBodyWidget(bodyWidget)

    def analysisDesignerRecentFilesList(self):
        return self._analysisDesignerRecentFilesList

    def createVerifyingWidget(self):
        self._verifyingDescriptionWidget = self.createDescriptionWidget(
            VispaWidget.ARROW_SHAPE_LEFT, self.VERIFYING_DESCRIPTION)

        bodyWidget = QWidget(self._verifyingDescriptionWidget)
        bodyWidget.setLayout(QGridLayout())
        bodyWidget.layout().setContentsMargins(0, 0, 0, 0)

        label = QLabel("Browse an existing PXL data file:")
        bodyWidget.layout().addWidget(label, 0, 0)
        analysisDesignerButton = QToolButton()
        analysisDesignerButton.setText("Open PXL file")
        analysisDesignerButton.setIcon(self._fileopenIcon)
        self.connect(analysisDesignerButton, SIGNAL("clicked(bool)"),
                     self.parent().openPxlFileSlot)
        bodyWidget.layout().addWidget(analysisDesignerButton, 0, 1)
        self._pxlEditorRecentFilesList = QListWidget()
        self._pxlEditorRecentFilesList.setFixedSize(
            label.sizeHint().width() +
            analysisDesignerButton.sizeHint().width(), 150)
        self.connect(self._pxlEditorRecentFilesList,
                     SIGNAL("doubleClicked(QModelIndex)"),
                     self.parent().openPxlFileSlot)
        bodyWidget.layout().addWidget(self._pxlEditorRecentFilesList, 1, 0, 1,
                                      2)

        self._verifyingDescriptionWidget.setBodyWidget(bodyWidget)

    def pxlEditorRecentFilesList(self):
        return self._pxlEditorRecentFilesList

    def mouseMoveEvent(self, event):
        if bool(event.buttons()):
            VispaWidget.mouseMoveEvent(self, event)
        elif self._hideDescriptions:
            for i in range(len(self._descriptionWidgets)):
                self._descriptionWidgets[i].setVisible(
                    self._descriptionActiveRects[i].contains(event.pos()))

    def moveEvent(self, event):
        VispaWidget.moveEvent(self, event)
        self.rearangeDescriptionWidgets()

    def rearangeContent(self):
        VispaWidget.rearangeContent(self)
        self.rearangeDescriptionWidgets()

    def rearangeDescriptionWidgets(self):
        self._activeSize = QSize(0.3 * self.width(), 0.1 * self.height())
        self._prototypingRect = QRect(
            QPoint(0.5 * (self.width() - self._activeSize.width()), 0),
            self._activeSize)
        self._executionRect = QRect(QPoint(0, 0.635 * self.height()),
                                    self._activeSize)
        self._verifyingRect = QRect(
            QPoint(self.width() - self._activeSize.width(),
                   0.635 * self.height()), self._activeSize)
        self._descriptionActiveRects[0] = self._prototypingRect
        self._descriptionActiveRects[1] = self._executionRect
        self._descriptionActiveRects[2] = self._verifyingRect

        self._prototypingDescriptionWidget.move(
            self.mapToParent(self._prototypingRect.topLeft()) +
            QPoint((self._prototypingRect.width() -
                    self._prototypingDescriptionWidget.width()) *
                   0.5, -self._prototypingDescriptionWidget.height()))
        self._executionDescriptionWidget.move(
            self.mapToParent(self._executionRect.topLeft()) - QPoint(
                self._executionDescriptionWidget.width(), -0.5 *
                (self._executionRect.height() -
                 self._executionDescriptionWidget.height())))
        self._verifyingDescriptionWidget.move(
            self.mapToParent(self._verifyingRect.topRight()) - QPoint(
                0, -0.5 * (self._verifyingRect.height() -
                           self._verifyingDescriptionWidget.height())))

    def boundingRect(self):
        br = VispaWidget.boundingRect(self)
        for w in self._descriptionWidgets:
            br = br.united(w.boundingRect())
        return br

    def setVisible(self, visible):
        VispaWidget.setVisible(self, visible)
        self._executionDescriptionWidget.setVisible(
            visible and not self._hideDescriptions)
        self._prototypingDescriptionWidget.setVisible(
            visible and not self._hideDescriptions)
        self._verifyingDescriptionWidget.setVisible(
            visible and not self._hideDescriptions)
Example #28
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 = 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

        tempi = QImage(QSize(self.bb.width(), self.bb.height()), QImage.Format_ARGB32_Premultiplied) #TODO: format
        tempi.fill(0)
        painter = QPainter(tempi)
        self.scene.render(painter, target=QRectF(), source=QRectF(QPointF(self.bb.x(), self.bb.y()), QSizeF(self.bb.width(), self.bb.height())))
        painter.end()

        ndarr = qimage2ndarray.rgb_view(tempi)[:,:,0]
        labels = numpy.where(ndarr>0,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
Example #29
0
class StartupScreen(VispaWidget):
    
    # inherited parameters
    BACKGROUND_SHAPE = 'ROUNDRECT'
    SELECTABLE_FLAG = False
    AUTOSIZE = True
    AUTOSIZE_KEEP_ASPECT_RATIO = False
    
    PROTOTYPING_DESCRIPTION = """Prototyping"""
    
    EXECUTING_DESCRIPTION = """Executing"""
    
    VERIFYING_DESCRIPTION = """Verifying"""
        
    def __init__(self, parent):
        self._descriptionWidgets = []
        self._descriptionActiveRects = [QRect(), QRect(), QRect()]   # descriptions will be visible if mouse cursor is in the rect
        VispaWidget.__init__(self, parent)
        self._filenewIcon = QIcon(QPixmap(":/resources/filenew.svg"))
        self._fileopenIcon = QIcon(QPixmap(":/resources/fileopen.svg"))
        self.setImage(QSvgRenderer(":/resources/startup_development_cycle.svg"))
        self.setDragable(False)
        self.setMouseTracking(True)     # receive mouse events even if no button is pressed
        self._hideDescriptions = False
        
        self.createPrototypingWidget()
        self.createExecutionWidget()
        self.createVerifyingWidget()
        
    def createDescriptionWidget(self, arrowDirection, description):
        widget = VispaWidget(self.parent())
        widget.enableAutosizing(True, False)
        widget.setSelectable(False)
        widget.setArrowShape(arrowDirection)
        widget.setVisible(not self._hideDescriptions)
        widget.setDragable(False)
        self._descriptionWidgets.append(widget)
        return widget
    
    def createPrototypingWidget(self):
        self._prototypingDescriptionWidget = self.createDescriptionWidget(VispaWidget.ARROW_SHAPE_BOTTOM, self.PROTOTYPING_DESCRIPTION)
        
        bodyWidget = QWidget(self._prototypingDescriptionWidget)
        bodyWidget.setLayout(QGridLayout())
        bodyWidget.layout().setContentsMargins(0, 0, 0, 0)
        
        bodyWidget.layout().addWidget(QLabel("Design physics analysis:"), 0, 0)
        analysisDesignerButton = QToolButton()
        analysisDesignerButton.setText("Analysis Designer")
        analysisDesignerButton.setIcon(self._filenewIcon)
        self.connect(analysisDesignerButton, SIGNAL("clicked(bool)"), self.parent().newAnalysisDesignerSlot)
        bodyWidget.layout().addWidget(analysisDesignerButton, 0, 1)
        bodyWidget.layout().addWidget(QLabel("Create physics event:"), 1, 0)
        pxlButton = QToolButton()
        pxlButton.setText("PXL Editor")
        pxlButton.setIcon(self._filenewIcon)
        self.connect(pxlButton, SIGNAL("clicked(bool)"), self.parent().newPxlSlot)
        bodyWidget.layout().addWidget(pxlButton, 1, 1)
    
        self._prototypingDescriptionWidget.setBodyWidget(bodyWidget)
        
    def createExecutionWidget(self):
        self._executionDescriptionWidget = self.createDescriptionWidget(VispaWidget.ARROW_SHAPE_RIGHT, self.EXECUTING_DESCRIPTION)
        
        bodyWidget = QWidget(self._executionDescriptionWidget)
        bodyWidget.setLayout(QGridLayout())
        bodyWidget.layout().setContentsMargins(0, 0, 0, 0)
        
        label=QLabel("Open and run existing analysis:")
        bodyWidget.layout().addWidget(label, 0, 0)
        analysisDesignerButton = QToolButton()
        analysisDesignerButton.setText("Open analysis file")
        analysisDesignerButton.setIcon(self._fileopenIcon)
        self.connect(analysisDesignerButton, SIGNAL("clicked(bool)"), self.parent().openAnalysisFileSlot)
        bodyWidget.layout().addWidget(analysisDesignerButton, 0, 1)
        self._analysisDesignerRecentFilesList=QListWidget()
        self._analysisDesignerRecentFilesList.setFixedSize(label.sizeHint().width()+analysisDesignerButton.sizeHint().width(),150)
        self.connect(self._analysisDesignerRecentFilesList, SIGNAL("doubleClicked(QModelIndex)"), self.parent().openAnalysisFileSlot)
        bodyWidget.layout().addWidget(self._analysisDesignerRecentFilesList, 1, 0, 1, 2)
        
        self._executionDescriptionWidget.setBodyWidget(bodyWidget)

    def analysisDesignerRecentFilesList(self):
        return self._analysisDesignerRecentFilesList
        
    def createVerifyingWidget(self):
        self._verifyingDescriptionWidget = self.createDescriptionWidget(VispaWidget.ARROW_SHAPE_LEFT, self.VERIFYING_DESCRIPTION)
        
        bodyWidget = QWidget(self._verifyingDescriptionWidget)
        bodyWidget.setLayout(QGridLayout())
        bodyWidget.layout().setContentsMargins(0, 0, 0, 0)
        
        label=QLabel("Browse an existing PXL data file:")
        bodyWidget.layout().addWidget(label, 0, 0)
        analysisDesignerButton = QToolButton()
        analysisDesignerButton.setText("Open PXL file")
        analysisDesignerButton.setIcon(self._fileopenIcon)
        self.connect(analysisDesignerButton, SIGNAL("clicked(bool)"), self.parent().openPxlFileSlot)
        bodyWidget.layout().addWidget(analysisDesignerButton, 0, 1)
        self._pxlEditorRecentFilesList=QListWidget()
        self._pxlEditorRecentFilesList.setFixedSize(label.sizeHint().width()+analysisDesignerButton.sizeHint().width(),150)
        self.connect(self._pxlEditorRecentFilesList, SIGNAL("doubleClicked(QModelIndex)"), self.parent().openPxlFileSlot)
        bodyWidget.layout().addWidget(self._pxlEditorRecentFilesList, 1, 0, 1, 2)
        
        self._verifyingDescriptionWidget.setBodyWidget(bodyWidget)
        
    def pxlEditorRecentFilesList(self):
        return self._pxlEditorRecentFilesList
        
    def mouseMoveEvent(self, event):
        if bool(event.buttons()):
            VispaWidget.mouseMoveEvent(self, event)
        elif self._hideDescriptions:
            for i in range(len(self._descriptionWidgets)):
                self._descriptionWidgets[i].setVisible(self._descriptionActiveRects[i].contains(event.pos()))
                
    def moveEvent(self, event):
        VispaWidget.moveEvent(self, event)
        self.rearangeDescriptionWidgets()
        
    def rearangeContent(self):
        VispaWidget.rearangeContent(self)
        self.rearangeDescriptionWidgets()
        
    def rearangeDescriptionWidgets(self):
        self._activeSize = QSize(0.3 * self.width(), 0.1 * self.height())
        self._prototypingRect = QRect(QPoint(0.5 * (self.width() - self._activeSize.width()), 0), self._activeSize)
        self._executionRect = QRect(QPoint(0, 0.635 * self.height()), self._activeSize)
        self._verifyingRect = QRect(QPoint(self.width() -self._activeSize.width(), 0.635 * self.height()), self._activeSize)
        self._descriptionActiveRects[0] = self._prototypingRect
        self._descriptionActiveRects[1] = self._executionRect 
        self._descriptionActiveRects[2] = self._verifyingRect
        
        self._prototypingDescriptionWidget.move(self.mapToParent(self._prototypingRect.topLeft()) + QPoint((self._prototypingRect.width() - self._prototypingDescriptionWidget.width()) * 0.5, - self._prototypingDescriptionWidget.height()))
        self._executionDescriptionWidget.move(self.mapToParent(self._executionRect.topLeft()) - QPoint(self._executionDescriptionWidget.width(), - 0.5 * (self._executionRect.height() - self._executionDescriptionWidget.height())))
        self._verifyingDescriptionWidget.move(self.mapToParent(self._verifyingRect.topRight()) - QPoint(0, - 0.5 * (self._verifyingRect.height() - self._verifyingDescriptionWidget.height())))
        
    def boundingRect(self):
        br = VispaWidget.boundingRect(self)
        for w in self._descriptionWidgets:
            br = br.united(w.boundingRect())
        return br

    def setVisible(self, visible):
        VispaWidget.setVisible(self, visible)
        self._executionDescriptionWidget.setVisible(visible and not self._hideDescriptions)
        self._prototypingDescriptionWidget.setVisible(visible and not self._hideDescriptions)
        self._verifyingDescriptionWidget.setVisible(visible and not self._hideDescriptions)
Example #30
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 = 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

        tempi = QImage(QSize(self.bb.width(), self.bb.height()),
                       QImage.Format_ARGB32_Premultiplied)  #TODO: format
        tempi.fill(0)
        painter = QPainter(tempi)
        self.scene.render(painter,
                          target=QRectF(),
                          source=QRectF(
                              QPointF(self.bb.x(), self.bb.y()),
                              QSizeF(self.bb.width(), self.bb.height())))
        painter.end()

        ndarr = qimage2ndarray.rgb_view(tempi)[:, :, 0]
        labels = numpy.where(ndarr > 0, 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
Example #31
0
class WebPage(QObject):
    javaScriptAlertSent = pyqtSignal(str)
    javaScriptConsoleMessageSent = pyqtSignal(str, int, str)
    loadStarted = pyqtSignal()
    loadFinished = pyqtSignal(str)
    resourceReceived = pyqtSignal('QVariantMap')
    resourceRequested = pyqtSignal('QVariantMap')

    def __init__(self, parent=None):
        QObject.__init__(self, parent)

        # variable declarations
        self.m_paperSize = {}
        self.m_clipRect = QRect()
        self.m_libraryPath = ''

        self.setObjectName('WebPage')
        self.m_webPage = CustomPage(self)
        self.m_mainFrame = self.m_webPage.mainFrame()

        self.m_webPage.loadStarted.connect(self.loadStarted)
        self.m_webPage.loadFinished.connect(self.finish)

        # Start with transparent background
        palette = self.m_webPage.palette()
        palette.setBrush(QPalette.Base, Qt.transparent)
        self.m_webPage.setPalette(palette)

        # Page size does not need to take scrollbars into account
        self.m_webPage.mainFrame().setScrollBarPolicy(Qt.Horizontal,
                                                      Qt.ScrollBarAlwaysOff)
        self.m_webPage.mainFrame().setScrollBarPolicy(Qt.Vertical,
                                                      Qt.ScrollBarAlwaysOff)

        self.m_webPage.settings().setAttribute(
            QWebSettings.OfflineStorageDatabaseEnabled, True)
        self.m_webPage.settings().setOfflineStoragePath(
            QDesktopServices.storageLocation(QDesktopServices.DataLocation))
        self.m_webPage.settings().setAttribute(
            QWebSettings.LocalStorageDatabaseEnabled, True)
        self.m_webPage.settings().setAttribute(
            QWebSettings.OfflineWebApplicationCacheEnabled, True)
        self.m_webPage.settings().setOfflineWebApplicationCachePath(
            QDesktopServices.storageLocation(QDesktopServices.DataLocation))
        self.m_webPage.settings().setAttribute(
            QWebSettings.FrameFlatteningEnabled, True)
        self.m_webPage.settings().setAttribute(
            QWebSettings.LocalStorageEnabled, True)
        self.m_webPage.settings().setLocalStoragePath(
            QDesktopServices.storageLocation(QDesktopServices.DataLocation))

        # Ensure we have a document.body.
        self.m_webPage.mainFrame().setHtml('<html><body></body></html>')

        self.m_webPage.setViewportSize(QSize(400, 300))

        do_action('WebPageInit', Bunch(locals()))

    def applySettings(self, defaults):
        opt = self.m_webPage.settings()

        opt.setAttribute(QWebSettings.AutoLoadImages, defaults['loadImages'])
        opt.setAttribute(QWebSettings.PluginsEnabled, defaults['loadPlugins'])
        opt.setAttribute(QWebSettings.LocalContentCanAccessRemoteUrls,
                         defaults['localAccessRemote'])
        if 'userAgent' in defaults:
            self.m_webPage.m_userAgent = defaults['userAgent']

    def finish(self, ok):
        status = 'success' if ok else 'fail'
        self.loadFinished.emit(status)

    def mainFrame(self):
        return self.m_mainFrame

    def renderImage(self):
        frameRect = QRect(QPoint(0, 0), self.m_mainFrame.contentsSize())
        if not self.m_clipRect.isEmpty():
            frameRect = self.m_clipRect

        viewportSize = self.m_webPage.viewportSize()
        self.m_webPage.setViewportSize(self.m_mainFrame.contentsSize())

        image = QImage(frameRect.size(), QImage.Format_ARGB32)
        image.fill(qRgba(255, 255, 255, 0))

        painter = QPainter()

        # We use tiling approach to work-around Qt software rasterizer bug
        # when dealing with very large paint device.
        # See http://code.google.com/p/phantomjs/issues/detail?id=54.
        tileSize = 4096
        htiles = (image.width() + tileSize - 1) / tileSize
        vtiles = (image.height() + tileSize - 1) / tileSize
        for x in range(htiles):
            for y in range(vtiles):
                tileBuffer = QImage(tileSize, tileSize, QImage.Format_ARGB32)
                tileBuffer.fill(qRgba(255, 255, 255, 0))

                # Render the web page onto the small tile first
                painter.begin(tileBuffer)
                painter.setRenderHint(QPainter.Antialiasing, True)
                painter.setRenderHint(QPainter.TextAntialiasing, True)
                painter.setRenderHint(QPainter.SmoothPixmapTransform, True)
                painter.translate(-frameRect.left(), -frameRect.top())
                painter.translate(-x * tileSize, -y * tileSize)
                self.m_mainFrame.render(painter, QRegion(frameRect))
                painter.end()

                # Copy the tile to the main buffer
                painter.begin(image)
                painter.setCompositionMode(QPainter.CompositionMode_Source)
                painter.drawImage(x * tileSize, y * tileSize, tileBuffer)
                painter.end()

        self.m_webPage.setViewportSize(viewportSize)
        return image

    def renderPdf(self, fileName):
        p = QPrinter()
        p.setOutputFormat(QPrinter.PdfFormat)
        p.setOutputFileName(fileName)
        p.setResolution(pdf_dpi)
        paperSize = self.m_paperSize

        if not len(paperSize):
            pageSize = QSize(self.m_webPage.mainFrame().contentsSize())
            paperSize['width'] = str(pageSize.width()) + 'px'
            paperSize['height'] = str(pageSize.height()) + 'px'
            paperSize['border'] = '0px'

        if paperSize.get('width') and paperSize.get('height'):
            sizePt = QSizeF(ceil(self.stringToPointSize(paperSize['width'])),
                            ceil(self.stringToPointSize(paperSize['height'])))
            p.setPaperSize(sizePt, QPrinter.Point)
        elif 'format' in paperSize:
            orientation = QPrinter.Landscape if paperSize.get(
                'orientation') and paperSize['orientation'].lower(
                ) == 'landscape' else QPrinter.Portrait
            orientation = QPrinter.Orientation(orientation)
            p.setOrientation(orientation)

            formats = {
                'A0': QPrinter.A0,
                'A1': QPrinter.A1,
                'A2': QPrinter.A2,
                'A3': QPrinter.A3,
                'A4': QPrinter.A4,
                'A5': QPrinter.A5,
                'A6': QPrinter.A6,
                'A7': QPrinter.A7,
                'A8': QPrinter.A8,
                'A9': QPrinter.A9,
                'B0': QPrinter.B0,
                'B1': QPrinter.B1,
                'B2': QPrinter.B2,
                'B3': QPrinter.B3,
                'B4': QPrinter.B4,
                'B5': QPrinter.B5,
                'B6': QPrinter.B6,
                'B7': QPrinter.B7,
                'B8': QPrinter.B8,
                'B9': QPrinter.B9,
                'B10': QPrinter.B10,
                'C5E': QPrinter.C5E,
                'Comm10E': QPrinter.Comm10E,
                'DLE': QPrinter.DLE,
                'Executive': QPrinter.Executive,
                'Folio': QPrinter.Folio,
                'Ledger': QPrinter.Ledger,
                'Legal': QPrinter.Legal,
                'Letter': QPrinter.Letter,
                'Tabloid': QPrinter.Tabloid
            }

            p.setPaperSize(QPrinter.A4)  # fallback
            for format, size in formats.items():
                if format.lower() == paperSize['format'].lower():
                    p.setPaperSize(size)
                    break
        else:
            return False

        border = floor(self.stringToPointSize(
            paperSize['border'])) if paperSize.get('border') else 0
        p.setPageMargins(border, border, border, border, QPrinter.Point)

        self.m_webPage.mainFrame().print_(p)
        return True

    def setNetworkAccessManager(self, networkAccessManager):
        self.m_webPage.setNetworkAccessManager(networkAccessManager)
        networkAccessManager.resourceRequested.connect(self.resourceRequested)
        networkAccessManager.resourceReceived.connect(self.resourceReceived)

    def stringToPointSize(self, string):
        units = (('mm', 72 / 25.4), ('cm', 72 / 2.54), ('in', 72.0),
                 ('px', 72.0 / pdf_dpi / 2.54), ('', 72.0 / pdf_dpi / 2.54))

        for unit, format in units:
            if string.endswith(unit):
                value = string.rstrip(unit)
                return float(value) * format
        return 0

    def userAgent(self):
        return self.m_webPage.m_userAgent

    ##
    # Properties and methods exposed to JavaScript
    ##

    @pyqtSlot(str)
    def _appendScriptElement(self, scriptUrl):
        self.m_mainFrame.evaluateJavaScript('''
            var el = document.createElement('script');
            el.onload = function() { alert('%(scriptUrl)s'); };
            el.src = '%(scriptUrl)s';
            document.body.appendChild(el);
        ''' % {'scriptUrl': scriptUrl})

    @pyqtProperty('QVariantMap')
    def clipRect(self):
        result = {
            'width': self.m_clipRect.width(),
            'height': self.m_clipRect.height(),
            'top': self.m_clipRect.top(),
            'left': self.m_clipRect.left()
        }
        return result

    @clipRect.setter
    def clipRect(self, size):
        names = ('width', 'height', 'top', 'left')
        for item in names:
            try:
                globals()[item] = int(size[item])
                if globals()[item] < 0:
                    if item not in ('top', 'left'):
                        globals()[item] = 0
            except KeyError:
                globals()[item] = getattr(self.m_clipRect, item)()

        self.m_clipRect = QRect(left, top, width, height)

    @pyqtProperty(str)
    def content(self):
        return self.m_mainFrame.toHtml()

    @content.setter
    def content(self, content):
        self.m_mainFrame.setHtml(content)

    @pyqtSlot(str, result='QVariant')
    def evaluate(self, code):
        function = '(%s)()' % code
        return self.m_mainFrame.evaluateJavaScript(function)

    @pyqtSlot(str, result=bool)
    def injectJs(self, filePath):
        return injectJsInFrame(filePath, self.m_libraryPath, self.m_mainFrame)

    @pyqtSlot(str, str, 'QVariantMap')
    @pyqtSlot(str, 'QVariantMap', 'QVariantMap')
    def openUrl(self, address, op, settings):
        operation = op
        body = QByteArray()

        self.applySettings(settings)
        self.m_webPage.triggerAction(QWebPage.Stop)

        if type(op) is dict:
            operation = op.get('operation')
            body = QByteArray(op.get('data', ''))

        if operation == '':
            operation = 'get'

        networkOp = QNetworkAccessManager.CustomOperation
        operation = operation.lower()
        if operation == 'get':
            networkOp = QNetworkAccessManager.GetOperation
        elif operation == 'head':
            networkOp = QNetworkAccessManager.HeadOperation
        elif operation == 'put':
            networkOp = QNetworkAccessManager.PutOperation
        elif operation == 'post':
            networkOp = QNetworkAccessManager.PostOperation
        elif operation == 'delete':
            networkOp = QNetworkAccessManager.DeleteOperation

        if networkOp == QNetworkAccessManager.CustomOperation:
            self.m_mainFrame.evaluateJavaScript(
                'console.error("Unknown network operation: %s");' % operation)
            return

        self.m_mainFrame.load(QNetworkRequest(QUrl(address)), networkOp, body)

    @pyqtProperty('QVariantMap')
    def paperSize(self):
        return self.m_paperSize

    @paperSize.setter
    def paperSize(self, size):
        self.m_paperSize = size

    @pyqtSlot(str, result=bool)
    def render(self, fileName):
        if self.m_mainFrame.contentsSize() == '':
            return False

        fileInfo = QFileInfo(fileName)
        path = QDir()
        path.mkpath(fileInfo.absolutePath())

        if fileName.lower().endswith('.pdf'):
            return self.renderPdf(fileName)

        image = self.renderImage()

        return image.save(fileName)

    @pyqtProperty(str)
    def libraryPath(self):
        return self.m_libraryPath

    @libraryPath.setter
    def libraryPath(self, dirPath):
        self.m_libraryPath = dirPath

    @pyqtSlot(str, str)
    def uploadFile(self, selector, fileName):
        el = self.m_mainFrame.findFirstElement(selector)
        if el.isNull():
            return

        self.m_webPage.m_uploadFile = fileName
        el.evaluateJavaScript('''
            (function (el) {
                var ev = document.createEvent('MouseEvents');
                ev.initEvent('click', true, true);
                el.dispatchEvent(ev);
            })(this)
        ''')

    @pyqtProperty('QVariantMap')
    def viewportSize(self):
        size = self.m_webPage.viewportSize()
        result = {'width': size.width(), 'height': size.height()}
        return result

    @viewportSize.setter
    def viewportSize(self, size):
        names = ('width', 'height')
        for item in names:
            try:
                globals()[item] = int(size[item])
                if globals()[item] < 0:
                    globals()[item] = 0
            except KeyError:
                globals()[item] = getattr(self.m_webPage.viewportSize(),
                                          item)()

        self.m_webPage.setViewportSize(QSize(width, height))

    do_action('WebPage', Bunch(locals()))
Example #32
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):
        QObject.__init__(self)
        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.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):
        print "Setting Drawnnumer", 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 = color
        self.brushColorChanged.emit(self.drawColor)
    
    def beginDrawing(self, pos, sliceRect):
        self.sliceRect = sliceRect
        self.scene.clear()
        self.bb = QRect()
        self.pos = QPointF(pos.x()+0.0001, pos.y()+0.0001)
        line = self.moveTo(pos)
        return line

    def endDrawing(self, pos):
        self.moveTo(pos)

        tempi = QImage(QSize(self.bb.width(), self.bb.height()), QImage.Format_ARGB32_Premultiplied) #TODO: format
        tempi.fill(0)
        painter = QPainter(tempi)
        self.scene.render(painter, target=QRectF(), source=QRectF(QPointF(self.bb.x(), self.bb.y()), QSizeF(self.bb.width(), self.bb.height())))
        painter.end()
        
        ndarr = qimage2ndarray.rgb_view(tempi)[:,:,0]
        labels = numpy.where(ndarr>0,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()

        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):
        oldX, oldY = self.pos.x(), self.pos.y()
        x,y = pos.x(), pos.y()
        
        #print "BrushingModel.moveTo(pos=%r)" % (pos) 
        line = QGraphicsLineItem(oldX, oldY, x, y)
        line.setPen(QPen( QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
        self.scene.addItem(line)

        #update bounding Box 
        if not self.bb.isValid():
            self.bb = QRect(QPoint(x,y), 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
Example #33
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 = 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. / 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
Example #34
0
    def createMetricTools(self):
      '''
      Called once countThread is over.
      '''
      if not self.configuration:
# First, create configuration dictionary
        i = 0
        for timeFamily, timeList in self.timeline.timeMap.items():
          if len(timeList):
# One sub dictionary per time family
            self.configuration.append([timeFamily, []])
            for oneMetric in timeList:
# One sub sub dictionary per family sub time
#  checked indicate if item is displayed
#  color indicate which color to use
              if i < len(self.timeline.colors):
                self.configuration[-1][1].append([oneMetric, [['checked', True],
                                                              ['color', self.timeline.colors[i][0]],
                                                              ['checkBox', None],
                                                              ['colorWidget', None],
                                                              ['colorWidgetIndex', -1],
                                                              ['orderedNodeList', {'dates':None, 'nodes':None}],
                                                              ['dateLimits', [long(0), long(0xffffffffffffffff)]],
                                                              ['mainPixmap', [True, None]],
                                                              ['zoomPixmap', [True, None]]]])
              else:
                self.configuration[-1][1].append([oneMetric, [['checked', False],
                                                              ['color', ''],
                                                              ['checkBox', None],
                                                              ['colorWidget', None],
                                                              ['colorWidgetIndex', -1],
                                                              ['orderedNodeList', {'dates':None, 'nodes':None}],
                                                              ['dateLimits', [long(0), long(0xffffffffffffffff)]],
                                                              ['mainPixmap', [True, None]],
                                                              ['zoomPixmap', [True, None]]]])

              i += 1
          else:
            self.configuration.append([timeFamily, []])

# Configuration object created, now create graphical view of it
        # self.dumpOptionsConf()
        i = 0
        for family in self.configuration:
          if family[1]:
            box = QGroupBox(family[0])
            oneTime = QVBoxLayout()
            for time in family[1]:
              hbox = QHBoxLayout()
              time[1][2][1] = QCheckBox(':'.join(time[0]))
              self.connect(time[1][2][1], SIGNAL("stateChanged(int)"), self.checkboxClick)
              time[1][3][1] = QComboBox()
              for color in self.timeline.colors:
                time[1][3][1].addItem(color[0])

              palette = time[1][2][1].palette()
              if i < len(self.timeline.colors):
                time[1][2][1].setChecked(time[1][0][1])
                # Colorize foreground
                palette.setColor(QPalette.WindowText, self.timeline.colors[i][1])
                time[1][3][1].setCurrentIndex(i)
                time[1][4][1] = i
              else:
# In case every colors are already used, don't check time (default) and don't select any color
                palette.setColor(QPalette.WindowText, Qt.gray)
                time[1][0][1] = False
                time[1][3][1].setEnabled(False)
              time[1][2][1].setPalette(palette)
              
              self.connect(time[1][3][1], SIGNAL("currentIndexChanged(const QString&)"), self.colorChange)
              hbox.addWidget(time[1][2][1])
              hbox.addWidget(time[1][3][1])
              oneTime.addLayout(hbox)
              i += 1
            box.setLayout(oneTime)

            optimum = box.minimumSizeHint()
            box.setFixedSize(optimum)
            if optimum.width() > self.familyLayout.sizeHint().width():
                geom = QRect(0, 0, optimum.width(), self.familyLayout.sizeHint().height() + optimum.height())
            else:
                geom = QRect(0, 0, self.familyLayout.sizeHint().width(), self.familyLayout.sizeHint().height() + optimum.height())
            self.familyLayout.addWidget(box)

            self.familyLayout.setGeometry(geom)
            self.familyWidget.setFixedSize(geom.width(), geom.height())
            self.familyScroll.setWidget(self.familyWidget)

          
      else:
# Configuration object already created, we are called because am item has been
#  unchecked or its color has changed.
       pass
Example #35
0
class XSnapshotWidget(QWidget):
    def __init__(self, parent=None):
        super(XSnapshotWidget, self).__init__(parent)

        # define custom properties
        self._region = QRect()
        self._filepath = ''

        # define custom properties
        palette = self.palette()
        palette.setColor(palette.Window, QColor('white'))
        self.setPalette(palette)
        self.setWindowOpacity(0.5)
        self.setWindowFlags(Qt.SplashScreen)
        self.setFocus()

    def accept(self):
        """
        Prompts the user for the filepath to save and then saves the image.
        """
        filetypes = 'PNG Files (*.png);;JPG Files (*.jpg);;All Files (*.*)'
        filename = QFileDialog.getSaveFileName(None, 'Save Snapshot',
                                               self.filepath(), filetypes)

        if type(filename) == tuple:
            filename = filename[0]

        filename = str(filename)
        if not filename:
            self.reject()
        else:
            self.setFilepath(filename)
            self.save()

    def filepath(self):
        """
        Returns the filepath that is going to be asved for this snapshot widget.
        
        :return     <str>
        """
        return self._filepath

    def hideWindow(self):
        """
        Sets the window to hide/show while taking the snapshot.
        
        :param      window | <QMainWindow> || <QDialog>
        """
        return self._hideWindow

    def keyPressEvent(self, event):
        """
        Listens for the escape key to cancel out from this snapshot.
        
        :param      event | <QKeyPressEvent>
        """
        # reject on a cancel
        if event.key() == Qt.Key_Escape:
            self.reject()

        super(XSnapshotWidget, self).keyPressEvent(event)

    def mousePressEvent(self, event):
        """
        Starts the selection process for this widget and snapshot area.
        
        :param      event | <QMousePressEvent>
        """
        self._region.setX(event.pos().x())
        self._region.setY(event.pos().y())
        super(XSnapshotWidget, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        """
        Drags the selection view for this widget.
        
        :param      event | <QMouseMoveEvent>
        """
        w = event.pos().x() - self._region.x()
        h = event.pos().y() - self._region.y()

        self._region.setWidth(w)
        self._region.setHeight(h)
        self.repaint()

        super(XSnapshotWidget, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        """
        Finishes the selection event.
        
        :param      event | <QMouseReleaseEvent>
        """
        self.accept()
        super(XSnapshotWidget, self).mouseReleaseEvent(event)

    def paintEvent(self, event):
        """
        Handles the drawing for this widget and its selection region.
        
        :param      event | <QPaintEvent>
        """
        pen = QPen(Qt.DashLine)
        pen.setColor(QColor('red'))
        painter = QPainter(self)
        painter.setPen(pen)
        clr = QColor('black')
        clr.setAlpha(100)
        painter.setBrush(clr)

        painter.drawRect(self._region)

    def reject(self):
        """
        Rejects the snapshot and closes the widget.
        """
        if self.hideWindow():
            self.hideWindow().show()

        self.close()
        self.deleteLater()

    def region(self):
        """
        Returns the selection region defined by the rectangle for snapshoting.
        
        :return     <QRect>
        """
        return self._region

    def save(self):
        """
        Saves the snapshot based on the current region.
        """
        # close down the snapshot widget
        if self.hideWindow():
            self.hideWindow().hide()

        self.hide()
        QApplication.processEvents()
        time.sleep(1)

        # create the pixmap to save
        wid = QApplication.desktop().winId()

        if not self._region.isNull():
            x = self._region.x()
            y = self._region.y()
            w = self._region.width()
            h = self._region.height()
        else:
            x = self.x()
            y = self.y()
            w = self.width()
            h = self.height()

        pixmap = QPixmap.grabWindow(wid, x, y, w, h)
        pixmap.save(self.filepath())

        self.close()
        self.deleteLater()
        if self.hideWindow():
            self.hideWindow().show()

    def show(self):
        """
        Shows this widget and hides the specified window if necessary.
        """
        super(XSnapshotWidget, self).show()

        if self.hideWindow():
            self.hideWindow().hide()
            QApplication.processEvents()

    def setFilepath(self, filepath):
        """
        Sets the filepath that will be saved for this snapshot.
        
        :param      filepath | <str>
        """
        self._filepath = filepath

    def setHideWindow(self, window):
        """
        Sets the window that will be hidden while this snapshot is being
        taken.
        
        :param      window | <QMainWindow>
        """
        self._hideWindow = window

    def setRegion(self, rect):
        """
        Sets the region rectangle to the inputed rect.
        
        :param      rect | <QRect>
        """
        if rect is not None:
            self._region = rect

    @staticmethod
    def capture(rect=None, filepath='', prompt=True, hideWindow=None):
        """
        Prompts the user to capture the screen.
        
        :param      rect     | <QRect>
                    filepath | <str>
                    prompt   | <bool>
        
        :return     (<str> filepath, <bool> accepted)
        """
        widget = XSnapshotWidget(QApplication.desktop())
        widget.setRegion(rect)
        widget.setHideWindow(hideWindow)
        widget.setFilepath(filepath)
        widget.move(1, 1)
        widget.resize(QApplication.desktop().size())

        if prompt or not filepath:
            widget.show()
        else:
            widget.save()
Example #36
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 = popplerqt4.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 image(self):
        """Render the page as an image or our size. Return a QImage."""
        d = self._document
        w, h, r = self.width(), self.height(), self.rotation()
        page = d.page(self._pageNumber)
        pageSize = page.pageSize()
        if r & 1:
            pageSize.transpose()
        xres = 72.0 * w / pageSize.width()
        yres = 72.0 * h / pageSize.height()
        threshold = cache.options().oversampleThreshold() or cache.options(
            d).oversampleThreshold()
        multiplier = 2 if xres < threshold else 1
        with lock(d):
            cache.options().write(d)
            cache.options(d).write(d)
            image = page.renderToImage(xres * multiplier, yres * multiplier, 0,
                                       0, w * multiplier, h * multiplier, r)
        if multiplier == 2:
            image = image.scaledToWidth(w, Qt.SmoothTransformation)
        return image

    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 layout).
        
        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.
        """
        rect = rect.normalized().intersected(self.rect())
        if not rect:
            return
        rect.translate(-self.pos())
        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 == popplerqt4.Poppler.Page.Rotate90:
                x, y = y, 1 - x
            elif self._rotation == popplerqt4.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 == popplerqt4.Poppler.Page.Rotate90:
                left, top, right, bottom = top, 1 - right, bottom, 1 - left
            elif self._rotation == popplerqt4.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 == popplerqt4.Poppler.Page.Rotate90:
                left, top, right, bottom = 1 - bottom, left, 1 - top, right
            elif self._rotation == popplerqt4.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 == popplerqt4.Poppler.Page.Rotate90:
                left, top, right, bottom = top, w - right, bottom, w - left
            elif self._rotation == popplerqt4.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 == popplerqt4.Poppler.Page.Rotate90:
                left, top, right, bottom = w - bottom, left, w - top, right
            elif self._rotation == popplerqt4.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
Example #37
0
class ImageView(QtGui.QScrollArea):
    def __init__(self,parent):
        '''constructor of ImageView'''
        QtGui.QWidget.__init__(self)
        self.parent = parent
        self.selection = None
        self.image = None
        self.zoom = 100
        #if (!ic) ic=new IconCache();
        self.setFocusPolicy(QtCore.Qt.WheelFocus)
        self.setSizePolicy(QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding)
        self.d =ImageViewPrivate(self)
        self.setWidget(self.d)
        self.setWidgetResizable(True)
        self.setBackgroundRole(QtGui.QPalette.Dark)
        self.setMouseTracking(True)
        self.mouse_x = -1
        self.mouse_y = -1
        self.mouse_ex = 0
        self.mouse_ey = 0
        self.data_rect = QtCore.QRect(0,0,1,1)
        #self.setMode(view)
     
    def saveImage(self,name):
        '''Save image in viewer under given name'''
        if self.image: 
            save_success = self.image.saveImage(name)
            if save_success:
                return True 
            else :
                return False
        else:
            print("[ImageView][Save Image Failed]:No image to save")
            return False
        
    def selectionFromImageCoords(self,selectionRect):
        '''Return selection rectangle converted from image coordinate system to window coordinate syste'''
        x= (selectionRect.left())*self.data_rect.width()/self.image.x()+self.data_rect.left()
        y= (selectionRect.top())*self.data_rect.height()/self.image.y()+self.data_rect.top()
        xr=(selectionRect.right()+1)*self.data_rect.width()/self.image.x()+self.data_rect.left()-1
        yr=(selectionRect.bottom()+1)*self.data_rect.height()/self.image.y()+self.data_rect.top()-1
        return QRect(x,y,xr,yr)
    
    def selectPointToImageCoords(self,point):
        '''Return selected point converted to image coordinate system'''
        dw=self.data_rect.width()
        dh=self.data_rect.height()
        x=int(floor((point.x()-self.data_rect.left())* self.image.x()/dw))-1
        y=int(floor((point.y()-self.data_rect.top())* self.image.y()/dh))-1
        return QPoint(x,y)
        
    def selectionToImageCoords(self,selectionRect):
        '''Return selection rectangle converted to image coordinate system@param selectionRect rectangle to convert'''
        dw=self.data_rect.width()
        dh=self.data_rect.height()
        x=int(floor((selectionRect.left()-self.data_rect.left())* self.image.x()/dw))
        y=int(floor((selectionRect.top()-self.data_rect.top())* self.image.y()/dh))
        xr=int(floor((selectionRect.right()-self.data_rect.left()) * self.image.x()/dw))
        yr=int(floor((selectionRect.bottom()-self.data_rect.top())*self.image.y()/dh))
        #print(QRect(x,y,xr,yr))
        return QRect(x,y,xr,yr)

    def setDataRect(self):
        '''Update data_rect'''
        #Get image dimensions
        dx=self.image.x()
        dy=self.image.y()
        if dx == 0 or dy == 0:
            print("Null Image")
            return
        #printInfo ="setDataRect %f_%f" %(dx,dy)
        #print(printInfo)
        #Get image screen dimensions (may differ if zoom is set)
        screen_dx=dx*self.zoom/100.0
        screen_dy=dy*self.zoom/100.0
        x=self.d.width()
        y=self.d.height()
        wx=x
        wy=dy*wx/dx
        if wy > y:
            wy=y
            wx=dx*wy/dy
        if self.isSet("center"):#居中画图而不拉伸
            self.data_rect=QRect(max((x-screen_dx)/2,0),max((y-screen_dy)/2,0),screen_dx,screen_dy)
        else:
            self.data_rect=QRect(max((x-wx)/2,0),max((y-wy)/2,0),wx,wy)
            
    def getSelection(self):
        '''return the selection rectangle from (x0,y0,x1,y1) to (x,y,width,height)'''
        if not self.selection:
            return None
        width = self.selection.width() - self.selection.left()
        height = self.selection.height() - self.selection.top()
        return QRect(self.selection.left(),self.selection.top(),width,height)
    
    def repaint(self,x,y,p,src):
        '''Repaint the image using given painter and size of output window
        @param x width of output window
        @param y height of output window
        @param p QPainter to use
        @param src Which part of image to repaint (when not in fullscreen)'''
        '''TypeError: QPainter.setRenderHint(QPainter.RenderHint, bool on=True): first argument of unbound method must have type 'QPainter'''
        #p.setRenderHint(QtGui.QPainter.SmoothPixmapTransform,True)
        p.setRenderHint(QtGui.QPainter.Antialiasing,True)
        p.setPen = Qt.blue
        black = QtGui.QColor(0,0,0)
        if not self.image:
            #No image is loaded
            p.drawRect(0,0,x-1,y-1)
            p.fillRect(1,1,x-2,y-2,black)
            p.drawText(0,0,x,y,Qt.AlignVCenter | Qt.AlignCenter,QString(NOIMAGELOAD))
            return

        if self.image.x<=0 and self.image.y()<=0:
            #Invalid image is loaded
            p.drawRect(0,0,x-1,y-1)
            p.fillRect(1,1,x-2,y-2,black)
            p.drawText(0,0,x,y,Qt.AlignVCenter | Qt.AlignCenter,QString("Invalid image"))
            return
        #Rectangle specifying entire window
        rect = QRect(0,0,x,y)
        #Determine target rectangle at screen
        #Update data rectangle for mouse navigation
        self.setDataRect()
        #Repaint stripes around image if needed
        if self.data_rect.left() > src.left():
            #repaint stripe on left
            tmp = QRect(0,0,self.data_rect.left(),y)
            p.fillRect(tmp & src,black)
        if self.data_rect.right()<src.right():
            #repaint on right
            tmp = QRect(self.data_rect.right(),0,x-self.data_rect.right(),y)
            p.fillRect(tmp & src,black)
        if self.data_rect.top()>src.top():
            #repaint on top
            tmp = QRect(self.data_rect.left(),0,self.data_rect.width(),self.data_rect.top())
            p.fillRect(tmp & src,black)
        if self.data_rect.bottom()<src.bottom():
            #repaint on bottom
            tmp = QRect(self.data_rect.left(),self.data_rect.bottom(),self.data_rect.width(),y-self.data_rect.bottom())
            p.fillRect(tmp & src,black)
        #Show scaled to window
        #Set target to data rectangle
        target=self.data_rect
        #Draw entire image scaled
        source = QRect(0,0,self.image.x(),self.image.y())
        self.image.draw(p,source,target)#Stop Here
          
    def getImage(self):
        ''' Return image shown in the widget (or NULL if nothing is shown)
        If the image is modified, update() should be called to redraw the new image'''
        return self.image
    
    def moveRubberBand(self,newGeom):
        '''Move the rubberband after updating the zoom level'''
        if not rb: return
        self.rb.setGeometry(newGeom)  
        
    def rectCheck(self):
        ''' Called when selection is finished (on releasing the mouse button) and on start'''
        pass
        #if self.selection.isValid():
             ##"Snap rect to grid"
            #self.setDataRect()
            #self.d.moveRubberBand(self.selectionFromImageCoords(self.selection))
   

    def cancelRect(self):
        self.d.cancelRect()
        self.rectCheck()
    
    def flushImage(self):
        '''Use after new image is loaded to flush/redraw various data'''
        self.update()
        self.cancelRect()
        #emit zoomChanged(zoom);
        #emit info("");


    def loadImage(self,name):
        '''Open image with given name in viewer'''    
        if self.image: del self.image
        self.image = Image(name)
        if not self.image:
            return False
        
        self.flushImage()
        return True
        
    
    def sizeHint(self):
        '''sizeHint() 方法给出一个推荐的大小。这里我们重写这个方法'''
        '''Return size hint for the widget'''
        if self.image:
            #Size of image
            return QtCore.QSize(self.image.x(),self.image.y())
        else:
            #Some default,very Important
            return QtCore.QSize(840,630)

    #Load state of specified optional feature from settings (default value is false)
    def isSet(self,name):
        globalSettings = QtCore.QSettings("JiZhe","CTAnalysis")
        return globalSettings.value("view/"+name).toBool()
    
    #Return minimum size neede to display the widget
    def minSize(self):
        if self.image :
        #if self.image and self.isSet("scale"):
            #Size of image
            x = self.image.x()
            y = self.image.y()
            x = x * self.zoom / 100.0
            y = y * self.zoom / 100.0
            return QtCore.QSize(x,y)
        else:
            #No minimum
            return QtCore.QSize(0,0)
        

    #Change internal widget's minimum size.Schedule this and internal widget to repaint.
    def update(self):
        self.d.setMinimumSize(self.minSize())
        self.d.update()
        #QtGui.QScrollArea.update()?

    def mouseCoordEvent(self,e):
        pass
    
    def selPoint(self,point):
        '''Select a point and then do region grow'''
        region_grow_seed_point = self.selectPointToImageCoords(point)
        self.parent.region_grow(region_grow_seed_point)
    
    def selRect(self,r):
        '''Update selection rectangle position'''
        if r.width()<=0 or r.height()<=0:
            self.selection=QRect()
        else:
            self.selection = self.selectionToImageCoords(r)
            #print(self.selection)
            x1=self.selection.left()
            x2=self.selection.right()
            y1=self.selection.top()
            y2=self.selection.bottom()
            w=self.selection.width()
            h=self.selection.height()
def paintVerticalCell(self, painter: QPainter, hv: QHeaderView, cellIndex: QModelIndex, leafIndex: QModelIndex, logicalLeafIndex: int, styleOptions: QStyleOptionHeader, sectionRect: QRect, left: int):
uniopt = QStyleOptionHeader(styleOptions)
self.setForegroundBrush(uniopt, cellIndex)
self.setBackgroundBrush(uniopt, cellIndex)
width=self.cellSize(cellIndex, hv, uniopt).width()
if cellIndex==leafIndex:
    width=sectionRect.width()-left
top=self.currentCellLeft(cellIndex, leafIndex, logicalLeafIndex, sectionRect.top(), hv)
height=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 = QMatrix()
    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 left+width

def paintVerticalSection(self, painter: QPainter, sectionRect: QRect, logicalLeafIndex: int, hv: QHeaderView, styleOptions: QStyleOptionHeader, leafIndex: QModelIndex):
oldBO = painter.brushOrigin()
left = sectionRect.x()
indexes = QModelIndexList(self.parentIndexes(leafIndex))
for i in range(indexes.size()):
    realStyleOptions = QStyleOptionHeader(styleOptions)
    if i<indexes.size()-1 and (realStyleOptions.state&QStyle.State_Sunken or realStyleOptions.state&QStyle.State_On):
        t = QStyle.State(QStyle.State_Sunken | QStyle.State_On)
        realStyleOptions.state = realStyleOptions.state&~t #FIXME: parent items are not highlighted
    left=self.paintVerticalCell(painter, hv, indexes[i], leafIndex, logicalLeafIndex, realStyleOptions, sectionRect, left)
painter.setBrushOrigin(oldBO)

def __init__(self, orientation: Qt.Orientation, parent: QWidget):
super().__init__(orientation, parent)
self._pd = self.private_data()
self.sectionResized.connect(self.on_sectionResized)
self.setHighlightSections(self.options.get("highlightSections"))
self.setClickable(self.options.get("clickable"))
self.show() #force to be visible
getattr(parent, "set%sHeader"%("Horizontal", "Vertical")[orientation!=Qt.Horizontal])(self)
self.sectionMoved.connect(self.on_sectionMoved)

def on_sectionMoved(self, logicalIndex, oldVisualIndex, newVisualIndex):
    view, model = self.parent(), self.parent().model()
    if not hasattr(model, "reorder"):
        return #reorder underlying data of models with /reorder/ def only
    if getattr(self, "manual_move", False):
        self.manual_move=False
        return
    self.manual_move=True
    self.moveSection(newVisualIndex, oldVisualIndex) #cancel move
    if model.reorder(oldVisualIndex, newVisualIndex, self.orientation()):
        #Reorder column widths / row heights
        horizontal = self.orientation()==Qt.Horizontal
        itemSize = (view.rowHeight, view.columnWidth)[horizontal]
        setItemSize = (view.setRowHeight, view.setColumnWidth)[horizontal]
        rng = sorted((oldVisualIndex, newVisualIndex))
        options = [(itemSize(i), i) for i in range(rng[0], rng[1]+1)]
        options.insert(newVisualIndex-rng[0], options.pop(oldVisualIndex-rng[0]))
        for i, col in enumerate(range(rng[0], rng[1]+1)):
            setItemSize(col, options[i][0])
        getattr(view, "select"+("Row", "Column")[horizontal])(newVisualIndex) #FIXME: don't select if sorting is enable?
        if self.isSortIndicatorShown():
            sortIndIndex = next((i for i, o in enumerate(options) if o[1]==self.sortIndicatorSection()), None)
            if sortIndIndex is not None: #sort indicator is among sections being reordered
                self.setSortIndicator(sortIndIndex+rng[0], self.sortIndicatorOrder()) #FIXME: does unnecessary sorting
        model.layoutChanged.emit() #update view

def styleOptionForCell(self, logicalInd: int)->QStyleOptionHeader:
opt = QStyleOptionHeader()
self.initStyleOption(opt)
if self.isSortIndicatorShown() and self.sortIndicatorSection()==logicalInd:
    opt.sortIndicator = (QStyleOptionHeader.SortUp, QStyleOptionHeader.SortDown)[self.sortIndicatorOrder()==Qt.AscendingOrder]
if self.window().isActiveWindow():
    opt.state = opt.state|QStyle.State_Active
opt.textAlignment = Qt.AlignCenter
opt.iconAlignment = Qt.AlignVCenter
opt.section = logicalInd
visual = self.visualIndex(logicalInd)
if self.count() == 1:
    opt.position = QStyleOptionHeader.OnlyOneSection
else:
    if visual == 0:
        opt.position = QStyleOptionHeader.Beginning
    else:
        opt.position = QStyleOptionHeader.End if visual==self.count()-1 else QStyleOptionHeader.Middle
if self.isClickable():
    #            if logicalIndex == d.hover:
    #            ...
    if self.highlightSections() and self.selectionModel():
        if self.orientation()==Qt.Horizontal:
            if self.selectionModel().columnIntersectsSelection(logicalInd, self.rootIndex()):
                opt.state = opt.state|QStyle.State_On
            if self.selectionModel().isColumnSelected(logicalInd, self.rootIndex()):
                opt.state = opt.state|QStyle.State_Sunken
        else:
            if self.selectionModel().rowIntersectsSelection(logicalInd, self.rootIndex()):
                opt.state = opt.state|QStyle.State_On
            if self.selectionModel().isRowSelected(logicalInd, self.rootIndex()):
                opt.state = opt.state|QStyle.State_Sunken
if self.selectionModel():
    previousSelected=False
    if self.orientation()==Qt.Horizontal:
        previousSelected = self.selectionModel().isColumnSelected(self.logicalIndex(visual - 1), self.rootIndex())
    else:
        previousSelected = self.selectionModel().isRowSelected(self.logicalIndex(visual - 1), self.rootIndex())
    nextSelected=False
    if self.orientation()==Qt.Horizontal:
        nextSelected = self.selectionModel().isColumnSelected(self.logicalIndex(visual + 1), self.rootIndex())
    else:
        nextSelected = self.selectionModel().isRowSelected(self.logicalIndex(visual + 1), self.rootIndex())
    if previousSelected and nextSelected:
        opt.selectedPosition = QStyleOptionHeader.NextAndPreviousAreSelected
    else:
        if previousSelected:
            opt.selectedPosition = QStyleOptionHeader.PreviousIsSelected
        else:
            if nextSelected:
                opt.selectedPosition = QStyleOptionHeader.NextIsSelected
            else:
                opt.selectedPosition = QStyleOptionHeader.NotAdjacent
return opt

def sectionSizeFromContents(self, logicalIndex: int)->QSize:
if self._pd.headerModel:
    curLeafIndex = QModelIndex(self._pd.leafIndex(logicalIndex))
    if curLeafIndex.isValid():
        styleOption = QStyleOptionHeader(self.styleOptionForCell(logicalIndex))
        s = QSize(self._pd.cellSize(curLeafIndex, self, styleOption))
        curLeafIndex=curLeafIndex.parent()
        while curLeafIndex.isValid():
            if self.orientation() == Qt.Horizontal:
                s.setHeight(s.height()+self._pd.cellSize(curLeafIndex, self, styleOption).height())
            else:
                s.setWidth(s.width()+self._pd.cellSize(curLeafIndex, self, styleOption).width())
            curLeafIndex=curLeafIndex.parent()
        return s
return super().sectionSizeFromContents(logicalIndex)

def paintSection(self, painter: QPainter, rect: QRect, logicalIndex: int):
if rect.isValid():
    leafIndex = QModelIndex(self._pd.leafIndex(logicalIndex))
    if leafIndex.isValid():
        if self.orientation() == Qt.Horizontal:
            self._pd.paintHorizontalSection(painter, rect, logicalIndex, self, self.styleOptionForCell(logicalIndex), leafIndex)
        else:
            self._pd.paintVerticalSection(painter, rect, logicalIndex, self, self.styleOptionForCell(logicalIndex), leafIndex)
        return
super().paintSection(painter, rect, logicalIndex)

def on_sectionResized(self, logicalIndex: int):
if self.isSectionHidden(logicalIndex):
    return
leafIndex = QModelIndex(self._pd.leafIndex(logicalIndex))
if leafIndex.isValid():
    leafsList = QModelIndexList(self._pd.leafs(self._pd.findRootIndex(leafIndex)))
    for n in range(leafsList.indexOf(leafIndex), 0, -1):
        logicalIndex-=1
        w = self.viewport().width()
        h = self.viewport().height()
        pos = self.sectionViewportPosition(logicalIndex)
        r = QRect(pos, 0, w - pos, h)
        if self.orientation() == Qt.Horizontal:
            if self.isRightToLeft():
                r.setRect(0, 0, pos + self.sectionSize(logicalIndex), h)
        else:
            r.setRect(0, pos, w, h - pos)
        self.viewport().update(r.normalized())

def setModel(self, model):
    super().setModel(model)
    model.layoutChanged.connect(self.layoutChanged)
    self.layoutChanged()

def layoutChanged(self):
    if self.model():
        self._pd.initFromNewModel(self.orientation(), self.model())
        axis = ("column", "row")[self.orientation()!=Qt.Horizontal]
        cnt = getattr(self.model(), axis+"Count")(QModelIndex())
        if cnt:
            self.initializeSections(0, cnt-1)
MultiIndexHeaderView=HierarchicalHeaderView

class DataFrameModel(QtCore.QAbstractTableModel):
    #na_values:least|greatest - for sorting
    options = {"striped": True, "stripesColor": "#fafafa", "na_values": "least",
               "tooltip_min_len": 21}
    def __init__(self, dataframe=None):
        super().__init__()
        self.setDataFrame(dataframe if dataframe is not None else pd.DataFrame())

    def setDataFrame(self, dataframe):
        self.df = dataframe.copy()
        #        self.df_full = self.df
        self.layoutChanged.emit()

    def rowCount(self, parent):
        return len(self.df)

    def columnCount(self, parent):
        return len(self.df.columns)

    def readLevel(self, y=0, xs=0, xe=None, orient=None):
        c = getattr(self.df, ("columns", "index")[orient!=HorizontalHeaderDataRole])
        if not hasattr(c, "levels"): #not MultiIndex
            return [QtGui.QStandardItem(str(i)) for i in c]
        sibl = []
        section_start, v, xe = xs, None, xe or len(c)
        for i in range(xs, xe):
            label = c.labels[y][i]
            if label!=v:
                if y+1<len(c.levels) and i>xs:
                    children = self.readLevel(y+1, section_start, i, orient=orient)
                    sibl[-1].appendRow(children)
                item = QtGui.QStandardItem(str(c.levels[y][label]))
                sibl.append(item)
                section_start = i
                v=label
        if y+1<len(c.levels):
            children = self.readLevel(y+1, section_start, orient=orient)
            sibl[-1].appendRow(children)
        return sibl

    def data(self, index, role):
        row, col = index.row(), index.column()
        if role in (Qt.DisplayRole, Qt.ToolTipRole):
            ret = self.df.iat[row, col]
            if ret is not None and ret==ret: #convert to str except for None, NaN, NaT
                if isinstance(ret, float):
                    ret = "{:n}".format(ret)
                elif isinstance(ret, datetime.date):
                    #FIXME: show microseconds optionally
                    ret = ret.strftime(("%x", "%c")[isinstance(ret, datetime.datetime)])
                else: ret = str(ret)
                if role == Qt.ToolTipRole:
                    if len(ret)<self.options["tooltip_min_len"]: ret = ""
                return ret
        elif role == Qt.BackgroundRole:
            if self.options["striped"] and row%2:
                return QBrush(QColor(self.options["stripesColor"]))
        elif role in (HorizontalHeaderDataRole, VerticalHeaderDataRole):
            hm = QtGui.QStandardItemModel()
            hm.appendRow(self.readLevel(orient=role))
            return hm

    def reorder(self, oldIndex, newIndex, orientation):
        "Reorder columns / rows"
        horizontal = orientation==Qt.Horizontal
        cols = list(self.df.columns if horizontal else self.df.index)
        cols.insert(newIndex, cols.pop(oldIndex))
        self.df = self.df[cols] if horizontal else self.df.T[cols].T
        return True

    #    def filter(self, filt=None):
    #        self.df = self.df_full if filt is None else self.df[filt]
    #        self.layoutChanged.emit()

    def headerData(self, section, orientation, role):
        if role != Qt.DisplayRole: return
        label = getattr(self.df, ("columns", "index")[orientation!=Qt.Horizontal])[section]
        #        return label if type(label) is tuple else label
        return ("\n", " | ")[orientation!=Qt.Horizontal].join(str(i) for i in label) if type(label) is tuple else str(label)

    def dataFrame(self):
        return self.df

    def sort(self, column, order):
        #        print("sort", column, order) #FIXME: double sort after setSortingEnabled(True)
        if len(self.df):
            asc = order==Qt.AscendingOrder
            na_pos = 'first' if (self.options["na_values"]=="least")==asc else 'last'
            self.df.sort_values(self.df.columns[column], ascending=asc,
                                inplace=True, na_position=na_pos)
            self.layoutChanged.emit()

if __name__=="__main__":
    import sys, locale
    locale.setlocale(locale.LC_ALL, '') #system locale settings
    app = QtGui.QApplication(sys.argv)
    form = QtGui.QWidget()
    form.setAttribute(Qt.WA_DeleteOnClose) #http://stackoverflow.com/a/27178019/1119602
    form.setMinimumSize(700, 260)
    view = QtGui.QTableView()
    QtGui.QVBoxLayout(form).addWidget(view)
    form.show()

    #Prepare data
    tuples=[('bar', 'one', 'q'), ('bar', 'two', 'q'), ('baz', 'one', 'q'), ('baz', 'two', 'q'),
            ('foo', 'one', 'q'), ('foo', 'two', 'q'), ('qux', 'one', 'q'), ('qux', 'two', 'q')]
    index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second', 'third'])
    df=pd.DataFrame(pd.np.random.randn(6, 6), index=index[:6], columns=index[:6])
    print("DataFrame:\n%s"%df)

    #Prepare view
    #    oldh, oldv = view.horizontalHeader(), view.verticalHeader()
    #    oldh.setParent(form), oldv.setParent(form) #Save old headers for some reason
    MultiIndexHeaderView(Qt.Horizontal, view)
    MultiIndexHeaderView(Qt.Vertical, view)
    view.horizontalHeader().setMovable(True) #reorder DataFrame columns manually

    #Set data
    view.setModel(DataFrameModel(df))
    view.resizeColumnsToContents()
    view.resizeRowsToContents()

    #Set sorting enabled (after setting model)
    view.setSortingEnabled(True)
    sys.exit(app.exec())
Example #39
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 = 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./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
Example #40
0
class ImageAreaSelector (QtGui.QWidget):
    '''This widget provides means to visually crop a portion of
    an image by selecting it'''
     # pylint: disable=W0612
    NAME = 'ImageAreaSelector'
    DESCRIPTION = 'A widget used to select part of an image'
    AUTHOR = 'Gabriele "Whisky" Visconti'
    WEBSITE = ''
    # pylint: enable=W0612
    
    selection_changed = QtCore.pyqtSignal()
    
    def __init__(self, pixmap, parent=None):
        '''Constructor'''
        QtGui.QWidget.__init__(self, parent)
        self._pixmap = pixmap
        
        self._selection_rect = QRect() 
        self._image_origin = QPoint()
        self._resize_start = None
        self._drag_start = None
        self._handle_size = QSize(-10, -10)
        self._painter = QtGui.QPainter()
        self._hl_color1 = QtGui.QPalette().color(QtGui.QPalette.Highlight)
        self._hl_color2 = QtGui.QPalette().color(QtGui.QPalette.Highlight)
        self._hl_color2.setAlpha(150)
        self._zoom = 1.0
        
        self.adjust_minum_size()
        self.setBackgroundRole(QtGui.QPalette.Dark)
        self.setMouseTracking(True)
        self.setCursor(Qt.CrossCursor)
        
# -------------------- [BEGIN] QT_OVERRIDE

    def mousePressEvent (self, event):
        '''Overrides QWidget's mousePressEvent. Handles starting
        a new selection, starting a drag operation'''
        # pylint: disable=C0103
        mouse_pos = event.pos() / self._zoom
        sel_rect = self._selection_rect
        
        if not event.button() == Qt.LeftButton:
            return
        
        if (not sel_rect.isNull()) and sel_rect.contains(mouse_pos, True):
            handle_rect = QRect(sel_rect.bottomRight(), self._handle_size)
            if handle_rect.contains(mouse_pos):
                self._resize_start = mouse_pos
            else:
                self._drag_start = mouse_pos
        else:
            self._resize_start = mouse_pos
            sel_rect.setTopLeft    (mouse_pos)
            self._selection_rect.setSize(QSize(0, 0))
        

    
    def mouseMoveEvent (self, event):
        '''Overrides QWidget's mouseMoveEvent. Handles resizing
        and dragging operations on selection'''
        # pylint: disable=C0103
        sel_rect = self._selection_rect
        if self._resize_start:
            resize_end = event.pos() / self._zoom
            sel_rect.setBottomRight(sel_rect.bottomRight() +
                                    (resize_end - self._resize_start))
            self._resize_start = resize_end
            self.make_selection_square()
            self.update()
        elif self._drag_start is not None:
            drag_end = event.pos() / self._zoom
            sel_rect.translate(drag_end - self._drag_start)
            self._drag_start = drag_end
            self.update()
            
        # cursor shape:
        mouse_pos = event.pos() / self._zoom
        if (not sel_rect.isNull()) and sel_rect.contains(mouse_pos, True):
            handle_rect = QRect(sel_rect.bottomRight(), self._handle_size)
            if handle_rect.contains(mouse_pos):
                self.setCursor(Qt.SizeFDiagCursor)
            else:
                self.setCursor(Qt.OpenHandCursor)
                
        else:
            self.setCursor(Qt.CrossCursor)
        
            
    
    def mouseReleaseEvent (self, event):
        '''Overrides QWidget's mouseReleaseEvent. Handles ending a resizing or
        draggin operation on the selection'''
        # pylint: disable=C0103
        self._selection_rect = self._selection_rect.normalized()
        self._resize_start = None
        self._drag_start = None
        self.update()
        if not self._selection_rect.isNull():
            self.selection_changed.emit()
        
    
    def paintEvent(self, event):
        '''Overrides QWidtget's paintEvent.'''
        # pylint: disable=C0103
        QtGui.QWidget.paintEvent(self, event)
        self._painter.begin(self)
        pixmap_dest_rect = QRect(self._image_origin * self._zoom, 
                                 self._pixmap.size()*self._zoom)
        self._painter.drawPixmap(pixmap_dest_rect, self._pixmap)
        if not self._selection_rect.isNull():
            # preparing the darkened frame:
            sel_rect = self._selection_rect.normalized()
            frame = QtGui.QPixmap(event.rect().size())
            frame.fill(QtGui.QColor(0, 0, 0, 127))
            frame_painter = QtGui.QPainter(frame)
            # erase the selected area from the frame:
            frame_painter.setCompositionMode(
                                QtGui.QPainter.CompositionMode_DestinationIn)
            sel_rect_scaled = QRect(sel_rect.topLeft() * self._zoom,
                                    sel_rect.size() * self._zoom)
            frame_painter.fillRect(sel_rect_scaled, QtGui.QColor(0, 0, 0, 0))
            # draw selection border :
            frame_painter.setCompositionMode(
                                QtGui.QPainter.CompositionMode_SourceOver)
            frame_painter.setPen(self._hl_color1)
            frame_painter.drawRect(sel_rect_scaled)
            # draw the resize grip (if possible)
            if sel_rect_scaled.width() > 20 and sel_rect_scaled.height() > 20:
                handle_rect = QRect(sel_rect_scaled.bottomRight(), 
                                    self._handle_size)
                frame_painter.fillRect(handle_rect, self._hl_color2)
                frame_painter.drawRect(handle_rect)
            frame_painter.end()
            # painting the darkened frame:
            self._painter.drawPixmap(0, 0, frame)
            
        self._painter.end()
        
        
    def resizeEvent(self, event):
        '''Overrides QWidget's resizeEvent. Handles image centering.'''
        # pylint: disable=C0103
        self.adjust_image_origin()
        
# -------------------- [END] QT_OVERRIDE

    def adjust_image_origin(self):
        '''Recalculates the top left corner's image position, so the
        image is painted centered'''
        # pylint: disable=C0103
        new_size = self.size() / self._zoom
        pix_size = self._pixmap.size()
        
        dx = (new_size.width()  - pix_size.width() ) /2
        dy = (new_size.height() - pix_size.height()) /2
        
        new_image_origin = QPoint(dx, dy)
        self._selection_rect.translate(new_image_origin - self._image_origin)
        self._image_origin = new_image_origin
        log.info('image origin: %s' % new_image_origin)
        
    def select_unscaled(self):
        '''Selects, if possible, a 96 x 96 square centered around the original
        image. In this way the image won't be scaled but won't take up all the 
        96 x 96 area.'''
        # pylint: disable=C0103
        pix_size = self._pixmap.size()
        if pix_size.width() <= 96 and pix_size.height() <= 96:
            viewport_size = self.size()
            x =   (viewport_size.width () - 96) / 2
            y =   (viewport_size.height() - 96) / 2
            self._selection_rect.setTopLeft(QPoint(x, y))
            self._selection_rect.setSize(QSize(96, 96))
            self.update()
            self.selection_changed.emit()
            
            
    def select_all(self):
        '''Selects the whole image. Currently broken for images taller
        than wide.'''
        # TODO: make me work!
        self._selection_rect.setTopLeft(self._image_origin)
        self._selection_rect.setSize(self._pixmap.size())
        self.update()
        self.selection_changed.emit()
        
        
    def rotate_left(self):
        '''Rotates the image counterclockwise.'''
        self._pixmap = self._pixmap.transformed(QtGui.QTransform().rotate(-90))
        self.adjust_minum_size()
        self.adjust_image_origin()
        self.update()
        self.selection_changed.emit()


    def rotate_right(self):
        '''Rotates the image clockwise'''
        self._pixmap = self._pixmap.transformed(QtGui.QTransform().rotate(90))
        self.adjust_minum_size()
        self.adjust_image_origin()
        self.update()
        self.selection_changed.emit()
        
    
    def adjust_minum_size(self):
        '''Sets the new minimum size, calculated upon the image size
        and the _zoom factor.'''
        pixmap = self._pixmap
        if pixmap.width() < 96 or pixmap.height() < 96:
            min_size = QSize(96, 96)
        else:
            min_size = pixmap.size()
            
        self.setMinimumSize(min_size*self._zoom)


    def make_selection_square(self):
        '''Modify the selected area making it square'''
        wid = self._selection_rect.width ()
        self._selection_rect.setSize(QSize(wid, wid))
        
    
    def set_zoom(self, zoomlevel):
        '''Sets the specified zoomlevel'''
        self._zoom = zoomlevel
        self.adjust_minum_size()
        self.adjust_image_origin()
        self.update()
        self.selection_changed.emit()
        
        
    def fit_zoom(self):
        '''Chooses a zoomlevel that makes visible the entire image.
        Currently broken.'''
        widget_wid = self.size().width ()
        widget_hei = self.size().height()
        
        pixmap_wid = self._pixmap.width ()
        pixmap_hei = self._pixmap.height()
        
        self._zoom = (min(widget_wid, widget_hei) / 
                      min(pixmap_wid, pixmap_hei))
                      
        self.adjust_minum_size()
        self.adjust_image_origin()
        self.update()
        self.selection_changed.emit()
        
    def get_selected_pixmap(self):
        '''Returns the pixmap contained in the selection rect.
        Currently doesn't handle transparency correctly'''
        sel_rect_scaled = QRect(self._selection_rect.topLeft() * self._zoom,
                                self._selection_rect.size() * self._zoom)
        return QtGui.QPixmap.grabWidget(self, sel_rect_scaled)
class MincutConnec(QgsMapTool):

    canvasClicked = pyqtSignal()

    def __init__(self, iface, controller):
        """ Class constructor """

        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.controller = controller
        # Call superclass constructor and set current action
        QgsMapTool.__init__(self, self.canvas)

        self.dragging = False

        # Vertex marker
        color = QColor(255, 100, 255)
        self.vertex_marker = QgsVertexMarker(self.canvas)
        self.vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
        self.vertex_marker.setColor(color)
        self.vertex_marker.setIconSize(15)
        self.vertex_marker.setPenWidth(3)

        # Rubber band
        self.rubber_band = QgsRubberBand(self.canvas, QGis.Line)
        self.rubber_band.setColor(color)
        self.rubber_band.setWidth(1)

        # Select rectangle
        self.select_rect = QRect()

        # TODO: Parametrize
        self.connec_group = ["Wjoin", "Tap", "Fountain", "Greentap"]
        #self.snapperManager = SnappingConfigManager(self.iface)
        self.snapper = QgsMapCanvasSnapper(self.canvas)

    def activate(self):
        pass

    def canvasPressEvent(self, event):  #@UnusedVariable
        self.select_rect.setRect(0, 0, 0, 0)
        self.rubber_band.reset()

    def canvasMoveEvent(self, event):
        """ With left click the digitizing is finished """

        if event.buttons() == Qt.LeftButton:
            if not self.dragging:
                self.dragging = True
                self.select_rect.setTopLeft(event.pos())
            self.select_rect.setBottomRight(event.pos())
            self.set_rubber_band()

        else:
            # Hide highlight
            self.vertex_marker.hide()

            # Get the click
            x = event.pos().x()
            y = event.pos().y()
            event_point = QPoint(x, y)

            # Snapping
            (retval, result) = self.snapper.snapToBackgroundLayers(
                event_point)  # @UnusedVariable

            # That's the snapped point
            if result:
                # Check feature
                for snap_point in result:
                    element_type = snap_point.layer.name()
                    if element_type in self.connec_group:
                        # Get the point
                        point = QgsPoint(snap_point.snappedVertex)
                        # Add marker
                        self.vertex_marker.setCenter(point)
                        self.vertex_marker.show()
                        break

    def canvasReleaseEvent(self, event):
        """ With left click the digitizing is finished """

        if event.button() == Qt.LeftButton:

            # Get the click
            x = event.pos().x()
            y = event.pos().y()
            event_point = QPoint(x, y)

            # Not dragging, just simple selection
            if not self.dragging:

                # Snap to node
                (retval, result) = self.snapper.snapToBackgroundLayers(
                    event_point)  # @UnusedVariable

                # That's the snapped point
                if result:
                    # Check feature
                    for snapped_point in result:
                        element_type = snapped_point.layer.name()
                        if element_type in self.connec_group:
                            feat_type = 'connec'
                        else:
                            continue

                        point = QgsPoint(
                            snapped_point.snappedVertex)  # @UnusedVariable
                        # layer.removeSelection()
                        # layer.select([result[0].snappedAtGeometry])

                        #snapped_point.layer.removeSelection()
                        snapped_point.layer.select(
                            [snapped_point.snappedAtGeometry])

            else:

                # Set valid values for rectangle's width and height
                if self.select_rect.width() == 1:
                    self.select_rect.setLeft(self.select_rect.left() + 1)

                if self.select_rect.height() == 1:
                    self.select_rect.setBottom(self.select_rect.bottom() + 1)

                self.set_rubber_band()
                self.select_multiple_features(self.selected_rectangle)
                self.dragging = False

            # Refresh map canvas
            self.rubber_band.reset()
            self.refresh_map_canvas()

    def set_rubber_band(self):

        # Coordinates transform
        transform = self.canvas.getCoordinateTransform()

        # Coordinates
        ll = transform.toMapCoordinates(self.select_rect.left(),
                                        self.select_rect.bottom())
        lr = transform.toMapCoordinates(self.select_rect.right(),
                                        self.select_rect.bottom())
        ul = transform.toMapCoordinates(self.select_rect.left(),
                                        self.select_rect.top())
        ur = transform.toMapCoordinates(self.select_rect.right(),
                                        self.select_rect.top())

        # Rubber band
        self.rubber_band.reset()
        self.rubber_band.addPoint(ll, False)
        self.rubber_band.addPoint(lr, False)
        self.rubber_band.addPoint(ur, False)
        self.rubber_band.addPoint(ul, False)
        self.rubber_band.addPoint(ll, True)

        self.selected_rectangle = QgsRectangle(ll, ur)

    def select_multiple_features(self, rectangle):

        if self.connec_group is None:
            return

        if QGis.QGIS_VERSION_INT >= 21600:

            # Selection for all connec group layers
            for layer_name in self.connec_group:
                # Get layer by his name
                layer = self.controller.get_layer_by_layername(layer_name,
                                                               log_info=True)
                if layer:
                    self.group_pointers_connec.append(layer)
                    layer.selectByRect(rectangle)

        else:
            for layer_name in self.connec_group:
                self.iface.setActiveLayer(layer)
                layer.removeSelection()
                layer.select(rectangle, True)
Example #42
0
    def __layout(self):
        # position itself over `widget`
        widget = self.__widget
        if widget is None:
            return

        alignment = self.__alignment
        policy = self.sizePolicy()

        if widget.isWindow():
            bounds = widget.geometry()
        else:

            bounds = QRect(widget.mapToGlobal(QPoint(0, 0)),
                           widget.size())
        if self.isWindow():
            bounds = bounds
        else:
            bounds = QRect(self.parent().mapFromGlobal(bounds.topLeft()),
                           bounds.size())

        sh = self.sizeHint()
        minsh = self.minimumSizeHint()
        minsize = self.minimumSize()
        if minsize.isNull():
            minsize = minsh
        maxsize = bounds.size().boundedTo(self.maximumSize())
        minsize = minsize.boundedTo(maxsize)
        effectivesh = sh.expandedTo(minsize).boundedTo(maxsize)

        hpolicy = policy.horizontalPolicy()
        vpolicy = policy.verticalPolicy()

        def getsize(hint, minimum, maximum, policy):
            if policy == QSizePolicy.Ignored:
                return maximum
            elif policy & QSizePolicy.ExpandFlag:
                return maximum
            else:
                return max(hint, minimum)

        width = getsize(effectivesh.width(), minsize.width(),
                        maxsize.width(), hpolicy)

        heightforw = self.heightForWidth(width)
        if heightforw > 0:
            height = getsize(heightforw, minsize.height(),
                             maxsize.height(), vpolicy)
        else:
            height = getsize(effectivesh.height(), minsize.height(),
                             maxsize.height(), vpolicy)

        size = QSize(width, height)
        if alignment & Qt.AlignLeft:
            x = bounds.x()
        elif alignment & Qt.AlignRight:
            x = bounds.right() - size.width()
        else:
            x = bounds.x() + max(0, bounds.width() - size.width()) // 2

        if alignment & Qt.AlignTop:
            y = bounds.y()
        elif alignment & Qt.AlignBottom:
            y = bounds.bottom() - size.height()
        else:
            y = bounds.y() + max(0, bounds.height() - size.height()) // 2

        geom = QRect(QPoint(x, y), size)
        self.setGeometry(geom)
Example #43
0
    def createMetricTools(self):
        '''
      Called once countThread is over.
      '''
        if not self.configuration:
            # First, create configuration dictionary
            i = 0
            for timeFamily, timeList in self.timeline.timeMap.items():
                if len(timeList):
                    # One sub dictionary per time family
                    self.configuration.append([timeFamily, []])
                    for oneMetric in timeList:
                        # One sub sub dictionary per family sub time
                        #  checked indicate if item is displayed
                        #  color indicate which color to use
                        if i < len(self.timeline.colors):
                            self.configuration[-1][1].append([
                                oneMetric,
                                [['checked', True],
                                 ['color', self.timeline.colors[i][0]],
                                 ['checkBox', None], ['colorWidget', None],
                                 ['colorWidgetIndex', -1],
                                 [
                                     'orderedNodeList', {
                                         'dates': None,
                                         'nodes': None
                                     }
                                 ],
                                 [
                                     'dateLimits',
                                     [long(0),
                                      long(0xffffffffffffffff)]
                                 ], ['mainPixmap', [True, None]],
                                 ['zoomPixmap', [True, None]]]
                            ])
                        else:
                            self.configuration[-1][1].append([
                                oneMetric,
                                [['checked', False], ['color', ''],
                                 ['checkBox', None], ['colorWidget', None],
                                 ['colorWidgetIndex', -1],
                                 [
                                     'orderedNodeList', {
                                         'dates': None,
                                         'nodes': None
                                     }
                                 ],
                                 [
                                     'dateLimits',
                                     [long(0),
                                      long(0xffffffffffffffff)]
                                 ], ['mainPixmap', [True, None]],
                                 ['zoomPixmap', [True, None]]]
                            ])

                        i += 1
                else:
                    self.configuration.append([timeFamily, []])

# Configuration object created, now create graphical view of it
# self.dumpOptionsConf()
            i = 0
            for family in self.configuration:
                if family[1]:
                    box = QGroupBox(family[0])
                    oneTime = QVBoxLayout()
                    for time in family[1]:
                        hbox = QHBoxLayout()
                        time[1][2][1] = QCheckBox(':'.join(time[0]))
                        self.connect(time[1][2][1],
                                     SIGNAL("stateChanged(int)"),
                                     self.checkboxClick)
                        time[1][3][1] = QComboBox()
                        for color in self.timeline.colors:
                            time[1][3][1].addItem(color[0])

                        palette = time[1][2][1].palette()
                        if i < len(self.timeline.colors):
                            time[1][2][1].setChecked(time[1][0][1])
                            # Colorize foreground
                            palette.setColor(QPalette.WindowText,
                                             self.timeline.colors[i][1])
                            time[1][3][1].setCurrentIndex(i)
                            time[1][4][1] = i
                        else:
                            # In case every colors are already used, don't check time (default) and don't select any color
                            palette.setColor(QPalette.WindowText, Qt.gray)
                            time[1][0][1] = False
                            time[1][3][1].setEnabled(False)
                        time[1][2][1].setPalette(palette)

                        self.connect(
                            time[1][3][1],
                            SIGNAL("currentIndexChanged(const QString&)"),
                            self.colorChange)
                        hbox.addWidget(time[1][2][1])
                        hbox.addWidget(time[1][3][1])
                        oneTime.addLayout(hbox)
                        i += 1
                    box.setLayout(oneTime)

                    optimum = box.minimumSizeHint()
                    box.setFixedSize(optimum)
                    if optimum.width() > self.familyLayout.sizeHint().width():
                        geom = QRect(
                            0, 0, optimum.width(),
                            self.familyLayout.sizeHint().height() +
                            optimum.height())
                    else:
                        geom = QRect(
                            0, 0,
                            self.familyLayout.sizeHint().width(),
                            self.familyLayout.sizeHint().height() +
                            optimum.height())
                    self.familyLayout.addWidget(box)

                    self.familyLayout.setGeometry(geom)
                    self.familyWidget.setFixedSize(geom.width(), geom.height())
                    self.familyScroll.setWidget(self.familyWidget)

        else:
            # Configuration object already created, we are called because am item has been
            #  unchecked or its color has changed.
            pass
Example #44
0
class SelectArea(QLabel):
    doneSignal = pyqtSignal(QPixmap)

    def __init__(self, *args, **kwargs):
        super(SelectArea, self).__init__(*args, **kwargs)

        self.pixmap = take_screenshot()

        self.setPixmap(self.pixmap)

        self.setCursor(Qt.CrossCursor)

        self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
        self.showFullScreen()
        self.move(0, 0)
        self.resize(self.pixmap.size())

        self.selected = QRect(0, 0, 0, 0)
        self.first_point = None

    def paintEvent(self, event):
        super(SelectArea, self).paintEvent(event)

        painter = QPainter(self)

        drawRegion = QRegion(self.pixmap.rect())
        drawRegion = drawRegion.subtract(QRegion(self.selected))

        painter.setClipRegion(drawRegion)

        painter.setBrush(QBrush(QColor(0, 0, 0, 120)))
        painter.drawRect(self.pixmap.rect())

        painter.setClipping(False)

        if self.selected:
            # направляющие линии

            painter.setPen(QPen(QColor(255, 255, 255)))
            painter.setBrush(QBrush(QColor(0, 0, 0, 0)))

            vertical = self.selected.normalized()
            vertical.setLeft(-1)
            vertical.setRight(self.pixmap.rect().right() + 1)

            horizontal = self.selected.normalized()
            horizontal.setTop(-1)
            horizontal.setBottom(self.pixmap.rect().bottom() + 1)

            painter.drawRects(
                vertical,
                horizontal
            )

            # координаты начала

            bound = self.pixmap.rect()
            bound.setBottomRight(self.selected.topLeft() - QPoint(5, 5))

            painter.drawText(
                bound,
                Qt.AlignBottom | Qt.AlignRight,
                '(%d, %d)' % (self.selected.topLeft().x(), self.selected.topLeft().y())
            )

            # ширина/высота

            bound = self.pixmap.rect()
            bound.setTopLeft(self.selected.bottomRight() + QPoint(5, 5))

            painter.drawText(
                bound,
                Qt.AlignTop | Qt.AlignLeft,
                '(%d, %d)' % (self.selected.width(), self.selected.height())
            )

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

    def mousePressEvent(self, event):
        self.first_point = event.pos()
        self.selected.setTopLeft(self.first_point)

    def mouseMoveEvent(self, event):
        self.move_selection(event.pos())

    def mouseReleaseEvent(self, event):
        self.move_selection(event.pos())
        self.finish()

    def move_selection(self, now_point):
        self.selected = QRect(self.first_point, now_point).normalized()
        self.update()

    def finish(self):
        self.doneSignal.emit(self.pixmap.copy(self.selected))
        self.close()
Example #45
0
class ImageAreaSelector(QtGui.QWidget):
    '''This widget provides means to visually crop a portion of
    an image by selecting it'''
    # pylint: disable=W0612
    NAME = 'ImageAreaSelector'
    DESCRIPTION = 'A widget used to select part of an image'
    AUTHOR = 'Gabriele "Whisky" Visconti'
    WEBSITE = ''
    # pylint: enable=W0612

    selection_changed = QtCore.pyqtSignal()

    def __init__(self, pixmap, parent=None):
        '''Constructor'''
        QtGui.QWidget.__init__(self, parent)
        self._pixmap = pixmap

        self._selection_rect = QRect()
        self._image_origin = QPoint()
        self._resize_start = None
        self._drag_start = None
        self._handle_size = QSize(-10, -10)
        self._painter = QtGui.QPainter()
        self._hl_color1 = QtGui.QPalette().color(QtGui.QPalette.Highlight)
        self._hl_color2 = QtGui.QPalette().color(QtGui.QPalette.Highlight)
        self._hl_color2.setAlpha(150)
        self._zoom = 1.0

        self.adjust_minum_size()
        self.setBackgroundRole(QtGui.QPalette.Dark)
        self.setMouseTracking(True)
        self.setCursor(Qt.CrossCursor)

# -------------------- [BEGIN] QT_OVERRIDE

    def mousePressEvent(self, event):
        '''Overrides QWidget's mousePressEvent. Handles starting
        a new selection, starting a drag operation'''
        # pylint: disable=C0103
        mouse_pos = event.pos() / self._zoom
        sel_rect = self._selection_rect

        if not event.button() == Qt.LeftButton:
            return

        if (not sel_rect.isNull()) and sel_rect.contains(mouse_pos, True):
            handle_rect = QRect(sel_rect.bottomRight(), self._handle_size)
            if handle_rect.contains(mouse_pos):
                self._resize_start = mouse_pos
            else:
                self._drag_start = mouse_pos
        else:
            self._resize_start = mouse_pos
            sel_rect.setTopLeft(mouse_pos)
            self._selection_rect.setSize(QSize(0, 0))

    def mouseMoveEvent(self, event):
        '''Overrides QWidget's mouseMoveEvent. Handles resizing
        and dragging operations on selection'''
        # pylint: disable=C0103
        sel_rect = self._selection_rect
        if self._resize_start:
            resize_end = event.pos() / self._zoom
            sel_rect.setBottomRight(sel_rect.bottomRight() +
                                    (resize_end - self._resize_start))
            self._resize_start = resize_end
            self.make_selection_square()
            self.update()
        elif self._drag_start is not None:
            drag_end = event.pos() / self._zoom
            sel_rect.translate(drag_end - self._drag_start)
            self._drag_start = drag_end
            self.update()

        # cursor shape:
        mouse_pos = event.pos() / self._zoom
        if (not sel_rect.isNull()) and sel_rect.contains(mouse_pos, True):
            handle_rect = QRect(sel_rect.bottomRight(), self._handle_size)
            if handle_rect.contains(mouse_pos):
                self.setCursor(Qt.SizeFDiagCursor)
            else:
                self.setCursor(Qt.OpenHandCursor)

        else:
            self.setCursor(Qt.CrossCursor)

    def mouseReleaseEvent(self, event):
        '''Overrides QWidget's mouseReleaseEvent. Handles ending a resizing or
        draggin operation on the selection'''
        # pylint: disable=C0103
        self._selection_rect = self._selection_rect.normalized()
        self._resize_start = None
        self._drag_start = None
        self.update()
        if not self._selection_rect.isNull():
            self.selection_changed.emit()

    def paintEvent(self, event):
        '''Overrides QWidtget's paintEvent.'''
        # pylint: disable=C0103
        QtGui.QWidget.paintEvent(self, event)
        self._painter.begin(self)
        pixmap_dest_rect = QRect(self._image_origin * self._zoom,
                                 self._pixmap.size() * self._zoom)
        self._painter.drawPixmap(pixmap_dest_rect, self._pixmap)
        if not self._selection_rect.isNull():
            # preparing the darkened frame:
            sel_rect = self._selection_rect.normalized()
            frame = QtGui.QPixmap(event.rect().size())
            frame.fill(QtGui.QColor(0, 0, 0, 127))
            frame_painter = QtGui.QPainter(frame)
            # erase the selected area from the frame:
            frame_painter.setCompositionMode(
                QtGui.QPainter.CompositionMode_DestinationIn)
            sel_rect_scaled = QRect(sel_rect.topLeft() * self._zoom,
                                    sel_rect.size() * self._zoom)
            frame_painter.fillRect(sel_rect_scaled, QtGui.QColor(0, 0, 0, 0))
            # draw selection border :
            frame_painter.setCompositionMode(
                QtGui.QPainter.CompositionMode_SourceOver)
            frame_painter.setPen(self._hl_color1)
            frame_painter.drawRect(sel_rect_scaled)
            # draw the resize grip (if possible)
            if sel_rect_scaled.width() > 20 and sel_rect_scaled.height() > 20:
                handle_rect = QRect(sel_rect_scaled.bottomRight(),
                                    self._handle_size)
                frame_painter.fillRect(handle_rect, self._hl_color2)
                frame_painter.drawRect(handle_rect)
            frame_painter.end()
            # painting the darkened frame:
            self._painter.drawPixmap(0, 0, frame)

        self._painter.end()

    def resizeEvent(self, event):
        '''Overrides QWidget's resizeEvent. Handles image centering.'''
        # pylint: disable=C0103
        self.adjust_image_origin()

# -------------------- [END] QT_OVERRIDE

    def adjust_image_origin(self):
        '''Recalculates the top left corner's image position, so the
        image is painted centered'''
        # pylint: disable=C0103
        new_size = self.size() / self._zoom
        pix_size = self._pixmap.size()

        dx = (new_size.width() - pix_size.width()) / 2
        dy = (new_size.height() - pix_size.height()) / 2

        new_image_origin = QPoint(dx, dy)
        self._selection_rect.translate(new_image_origin - self._image_origin)
        self._image_origin = new_image_origin
        log.info('image origin: %s' % new_image_origin)

    def select_unscaled(self):
        '''Selects, if possible, a 96 x 96 square centered around the original
        image. In this way the image won't be scaled but won't take up all the 
        96 x 96 area.'''
        # pylint: disable=C0103
        pix_size = self._pixmap.size()
        if pix_size.width() <= 96 and pix_size.height() <= 96:
            viewport_size = self.size()
            x = (viewport_size.width() - 96) / 2
            y = (viewport_size.height() - 96) / 2
            self._selection_rect.setTopLeft(QPoint(x, y))
            self._selection_rect.setSize(QSize(96, 96))
            self.update()
            self.selection_changed.emit()

    def select_all(self):
        '''Selects the whole image. Currently broken for images taller
        than wide.'''
        # TODO: make me work!
        self._selection_rect.setTopLeft(self._image_origin)
        self._selection_rect.setSize(self._pixmap.size())
        self.update()
        self.selection_changed.emit()

    def rotate_left(self):
        '''Rotates the image counterclockwise.'''
        self._pixmap = self._pixmap.transformed(QtGui.QTransform().rotate(-90))
        self.adjust_minum_size()
        self.adjust_image_origin()
        self.update()
        self.selection_changed.emit()

    def rotate_right(self):
        '''Rotates the image clockwise'''
        self._pixmap = self._pixmap.transformed(QtGui.QTransform().rotate(90))
        self.adjust_minum_size()
        self.adjust_image_origin()
        self.update()
        self.selection_changed.emit()

    def adjust_minum_size(self):
        '''Sets the new minimum size, calculated upon the image size
        and the _zoom factor.'''
        pixmap = self._pixmap
        if pixmap.width() < 96 or pixmap.height() < 96:
            min_size = QSize(96, 96)
        else:
            min_size = pixmap.size()

        self.setMinimumSize(min_size * self._zoom)

    def make_selection_square(self):
        '''Modify the selected area making it square'''
        wid = self._selection_rect.width()
        self._selection_rect.setSize(QSize(wid, wid))

    def set_zoom(self, zoomlevel):
        '''Sets the specified zoomlevel'''
        self._zoom = zoomlevel
        self.adjust_minum_size()
        self.adjust_image_origin()
        self.update()
        self.selection_changed.emit()

    def fit_zoom(self):
        '''Chooses a zoomlevel that makes visible the entire image.
        Currently broken.'''
        widget_wid = self.size().width()
        widget_hei = self.size().height()

        pixmap_wid = self._pixmap.width()
        pixmap_hei = self._pixmap.height()

        self._zoom = (min(widget_wid, widget_hei) /
                      min(pixmap_wid, pixmap_hei))

        self.adjust_minum_size()
        self.adjust_image_origin()
        self.update()
        self.selection_changed.emit()

    def get_selected_pixmap(self):
        '''Returns the pixmap contained in the selection rect.
        Currently doesn't handle transparency correctly'''
        sel_rect_scaled = QRect(self._selection_rect.topLeft() * self._zoom,
                                self._selection_rect.size() * self._zoom)
        return QtGui.QPixmap.grabWidget(self, sel_rect_scaled)
Example #46
0
class PlottingThread(QThread):
    def __init__(self, parent):
        QThread.__init__(self)
        self.result = None
        self.parent = parent
        self._stopped = False
        self.mutex = QMutex()
        self.filePrefix = None
        self.fileFormat = None
        self.wallColoring = None
        self.cellColoring = None
        self.pointColoring = None
        self.extraDrawing = []
        self.pointSize = None
        self.pointLineColor = None
        self.pointLineThickness = None
        self.ellipsisDraw = None
        self.overSampling = None
        self.wallThickness = None
        self.bgColor = None
        self.loading = False
        self._crop = QRect(0, 0, 1, 1)
        self._pix = None
        self._end_image_plot = False
        self._loading_arguments = {}
        self.retryObject = None

    def end_step(self):
        return len(self.result) + 1

    def stop(self, value=True):
        self.mutex.lock()
        self._stopped = value
        self.mutex.unlock()

    def stopped(self):
        self.mutex.lock()
        val = self._stopped
        self.mutex.unlock()
        return val

    def nextImage(self):
        QCoreApplication.postEvent(self.parent, NextImageEvent())

    def abort(self, reason, **others):
        e = AbortPlottingEvent(reason)
        if others:
            e.others = others
        QCoreApplication.postEvent(self.parent, e)

    def finished(self):
        if self.loading:
            QCoreApplication.postEvent(self.parent, FinishLoadingEvent())
            self.loading = False
        else:
            QCoreApplication.postEvent(self.parent, FinishPlottingEvent())

    def image_ready(self):
        QCoreApplication.postEvent(self.parent, ImageReadyPlottingEvent())

    def update_nb_images(self, nb):
        QCoreApplication.postEvent(self.parent, UpdateNbImageEvent(nb))

    @property
    def crop_left(self):
        return self._crop.left()

    @crop_left.setter
    def crop_left(self, value):
        self._crop.moveLeft(int(value))

    @property
    def crop_top(self):
        return self._crop.top()

    @crop_top.setter
    def crop_top(self, value):
        self._crop.moveTop(int(value))

    @property
    def crop_width(self):
        return self._crop.width()

    @crop_width.setter
    def crop_width(self, value):
        self._crop.setWidth(int(value))

    @property
    def crop_height(self):
        return self._crop.height()

    @crop_height.setter
    def crop_height(self, value):
        self._crop.setHeight(int(value))

    def reset_crop(self):
        self._crop = QRect(QPoint(0, 0), self.img_size)

    @property
    def crop(self):
        return QRect(self._crop)

    @crop.deleter
    def crop(self):
        self.reset_crop()

    @property
    def end_image_plot(self):
        '''
        If true, plot the growth data on the end image rather than the start image of the growth calculation.
        '''
        return self._end_image_plot

    @end_image_plot.setter
    def end_image_plot(self, value):
        self._end_image_plot = bool(value)

    @property
    def pix(self):
        '''Thread-safe image storage.'''
        self.mutex.lock()
        pix = self._pix
        self.mutex.unlock()
        return pix

    @pix.setter
    def pix(self, value):
        self.mutex.lock()
        self._pix = value
        self.mutex.unlock()

    def render_valid(self):
        if self.result is None:
            log_debug("result is None")
            return False
        if self.parent is None:
            log_debug("parent is None")
            return False
        if self.ellipsisDraw is None:
            log_debug("ellipsisDraw is None")
            return False
        if self.cellColoring is None:
            log_debug("cellColoring is None")
            return False
        if self.wallColoring is None:
            log_debug("wallColoring is None")
            return False
        if self.pointColoring is None:
            log_debug("pointColoring is None")
            return False
        if self.pointSize is None:
            log_debug("pointSize is None")
            return False
        if self.pointLineThickness is None:
            log_debug("pointSize is None")
            return False
        if self.pointLineColor is None:
            log_debug("pointSize is None")
            return False
        if self.wallThickness is None:
            log_debug("wallThickness is None")
            return False
        if self.overSampling is None:
            log_debug("overSampling is None")
            return False
        if self.bgColor is None:
            log_debug("bgColor is None")
            return False
        return True

    def valid(self):
        if self.filePrefix is None:
            log_debug("filePrefix is None")
            return False
        if not self.filePrefix:
            log_debug("filePrefix is Empty")
            return False
        if self.fileFormat is None:
            log_debug("fileFormat is None")
            return False
        return self.render_valid()

    def drawImage(self, imageid):
        cache = image_cache.cache
        cellColoring = self.cellColoring
        wallColoring = self.wallColoring
        pointColoring = self.pointColoring
        ellipsisDraw = self.ellipsisDraw
        overSampling = self.overSampling
        extraDrawing = self.extraDrawing
        bgColor = self.bgColor.rgb()
        result = self.result
        if self.result_type == "Data":
            data = result
            img_name = result.images_name[imageid]
        else:
            data = result.data
            img_name = result.images[imageid]
        #scale = data.images_scale[img_name]
        min_scale = data.minScale()
        img = cache.image(data.image_path(img_name))
        img_data = data[img_name]
        size = self._crop.size()
        pix = QImage(size * overSampling, QImage.Format_ARGB32)
        pix.fill(bgColor)
        painter = QPainter()
        if not painter.begin(pix):
            self.abort("Cannot create painter on QImage")
            return None, None, None
        painter.setRenderHints(QPainter.SmoothPixmapTransform, True)
        painter.setRenderHints(QPainter.Antialiasing, True)
        if overSampling > 1:
            painter.scale(overSampling, overSampling)
        painter.translate(-self._crop.topLeft())
        painter.save()
        painter.translate(self.translate)
        log_debug("Translating: %gx%g" %
                  (self.translate.x(), self.translate.y()))
        painter.scale(1 / min_scale, 1 / min_scale)
        painter.save()
        matrix = img_data.matrix()
        painter.setWorldTransform(matrix, True)
        painter.drawImage(QPoint(0, 0), img)
        painter.restore()
        #pt_matrix = QTransform()
        #pt_matrix.scale(1/min_scale, 1/min_scale)
        #painter.setTransform(pt_matrix, True)
        cellColoring.startImage(painter, imageid)
        wallColoring.startImage(painter, imageid)
        for ed in extraDrawing:
            ed.startImage(painter, imageid)
        if self.result_type == "Growth":
            cells = result.cells[imageid]
            walls = result.walls[imageid]
        else:
            cells = img_data.cells
            walls = set()
            for cid in img_data.cells:
                pts = [pt for pt in data.cells[cid] if pt in img_data]
                if len(pts) > 1:
                    for i in range(len(pts)):
                        walls.add(data.wallId(pts[i - 1], pts[i]))
        # Now, draw the cells and the ellipsis
        for cid in cells:
            painter.setPen(Qt.NoPen)
            color = cellColoring(imageid, cid)
            painter.setBrush(color)
            pts = data.cellAtTime(cid, img_data.index)
            if pts:
                pts.append(pts[0])
                ppts = []
                for p1, p2 in zip(pts[:-1], pts[1:]):
                    ppts.append(img_data[p1])
                    ppts.extend(img_data.walls[p1, p2])
                ppts.append(ppts[0])
                poly = QPolygonF(ppts)
                painter.drawPolygon(poly)
        # And draw the walls
        wallThickness = self.wallThickness * min_scale
        for wid in walls:
            color = wallColoring(imageid, wid)
            if color.alpha() > 0:
                pen = QPen(color)
                pen.setWidthF(wallThickness)
                painter.setPen(pen)
                pts = [img_data[wid[0]]
                       ] + img_data.walls[wid[0], wid[1]] + [img_data[wid[1]]]
                #painter.drawLine(img_data[wid[0]], img_data[wid[1]])
                painter.drawPolyline(*pts)
        # Then, draw the points
        pointSize = self.pointSize * min_scale
        pointLineColor = self.pointLineColor
        pointLineThickness = self.pointLineThickness * min_scale
        log_debug("pointSize = %g" % pointSize)
        for pid in img_data:
            color = pointColoring(imageid, pid)
            if color.alpha() > 0:
                pen = QPen(pointLineColor)
                pen.setWidthF(pointLineThickness)
                brush = QBrush(color)
                painter.setPen(pen)
                painter.setBrush(brush)
                pos = img_data[pid]
                rect = QRectF(pos.x() - pointSize,
                              pos.y() - pointSize, 2 * pointSize,
                              2 * pointSize)
                painter.drawEllipse(rect)
        if ellipsisDraw.plot:
            for cid in cells:
                pts = data.cellAtTime(cid, img_data.index)
                if pts:
                    pts.append(pts[0])
                    ppts = []
                    for p1, p2 in zip(pts[:-1], pts[1:]):
                        ppts.append(img_data[p1])
                        ppts.extend(img_data.walls[p1, p2])
                    ppts.append(ppts[0])
                    #poly = QPolygonF(ppts)
                    #painter.drawPolygon(poly)
                    ellipsisDraw(painter, imageid, cid, ppts, min_scale)
        # At last, draw the extra data
        for ed in extraDrawing:
            ed(painter, imageid)
        tr = painter.worldTransform()
        painter.restore()
        pic_w = wallColoring.finalizeImage(painter, imageid, tr, self.crop)
        pic_c = cellColoring.finalizeImage(painter, imageid, tr, self.crop)
        for ed in extraDrawing:
            ed.finalizeImage(painter, imageid, tr, self.crop)
        painter.end()
        return pix, pic_w, pic_c

    def start(self):
        if self.isRunning():
            assert not self.rendering_all, "Cannot run twice the rendering of all images with the same object."
            return
        if parameters.instance.use_thread:
            log_debug("Starting rendering thread.")
            QThread.start(self)
            return False
        else:
            self.run()
            return True

    def render_all(self):
        self.rendering_all = True
        return self.start()

    def render_single(self, img_id, retry=False):
        if retry:
            while self.isRunning():
                self.wait(10000)
        elif self.isRunning():
            return
        self.rendering_all = False
        self.current_image = img_id
        return self.start()

    def load(self, filename):
        self.loading = True
        self.result = filename
        return self.start()

    def run(self):
        if self.loading:
            self.run_loader()
        elif self.rendering_all:
            self.run_full()
        else:
            self.run_single()

    def run_single(self):
        img = self.current_image
        self.cellColoring.init()
        self.wallColoring.init()
        self.pointColoring.init()
        log_debug("Rendering image %d" % img)
        self.pix, self.pic_w, self.pic_c = self.drawImage(img)
        if self.pic_w is not None:
            log_debug("Has wall image")
        if self.pic_c is not None:
            log_debug("Has cell image")
        if self.pix is not None:
            log_debug("Pix correctly rendered")
        log_debug("Rendered image %d  = %s" % (img, self.pix))
        self.image_ready()

    def reload(self):
        if self.retryObject is None:
            return
        self._loading_arguments.update(self.retryObject.method_args)
        self.load(self.retryObject.filename)

    def run_loader(self):
        filename = self.result
        try:
            self.retryObject = None
            # First, prepare the data by getting the images and computing how big they
            # should be
            f = open(filename)
            first_line = f.readline()
            f.close()
            if first_line.startswith("TRKR_VERSION"):
                result = Result(None)
                result.load(self.result, **self._loading_arguments)
                result_type = "Growth"
            else:
                result = TrackingData()
                result.load(self.result, **self._loading_arguments)
                result_type = "Data"
            self.result = result
            self.result_type = result_type
            if result_type == "Data":
                data = result
                images = data.images_name
                if data.cells:
                    self.has_cells = True
                    self.has_walls = True
                else:
                    self.has_cells = False
                    self.has_walls = False
                self.has_points = bool(data.cell_points)
            else:
                data = result.data
                images = result.images
                self.has_cells = False
                self.has_walls = False
                self.has_points = False
            self.images = images
            cache = image_cache.cache
            self.update_nb_images(len(result))
            bbox = QRectF()
            ms = data.minScale()
            for i in range(len(result)):
                img_name = images[i]
                img_data = data[img_name]
                img = cache.image(data.image_path(img_name))
                matrix = QTransform()
                matrix = img_data.matrix()
                sc = QTransform()
                sc.scale(1.0 / ms, 1.0 / ms)
                matrix *= sc
                r = QRectF(img.rect())
                rbox = matrix.map(QPolygonF(r)).boundingRect()
                bbox |= rbox
                log_debug(
                    "Image '%s':\n\tSize = %gx%g\n\tTransformed = %gx%g %+g %+g\n\tGlobal bbox = %gx%g %+g %+g\n"
                    % (img_name, r.width(), r.height(), rbox.width(),
                       rbox.height(), rbox.left(), rbox.top(), bbox.width(),
                       bbox.height(), bbox.left(), bbox.top()))
                log_debug("Matrix:\n%g\t%g\t%g\n%g\t%g\t%g\n" %
                          (matrix.m11(), matrix.m12(), matrix.dx(),
                           matrix.m21(), matrix.m22(), matrix.dy()))
                if result_type == "Growth":
                    if result.cells[i]:
                        self.has_cells = True
                    if result.walls[i]:
                        self.has_walls = True
                    self.has_points = bool(result.data.cell_points)
                self.nextImage()
            translate = bbox.topLeft()
            translate *= -1
            self.translate = translate
            size = bbox.size().toSize()
            self.img_size = size
            self._crop = QRect(QPoint(0, 0), size)
            self.finished()
            self._loading_arguments = {
            }  # All done, we don't need that anymore
        except RetryTrackingDataException as ex:
            ex.filename = filename
            self.retryObject = ex
            self.finished()
            return
        except Exception as ex:
            _, _, exceptionTraceback = sys.exc_info()
            self.abort(ex, traceback=exceptionTraceback)
            raise

    def run_full(self):
        if not self.valid():
            self.abort("Object was not correctly initialized")
            return
        self.stop(False)
        painter = None
        try:
            result = self.result
            self.update_nb_images(len(result))
            #            if self.result_type == "Data":
            #                data = result
            #                images = result.images_name
            #            else:
            #                data = result.data
            #                images = result.images
            #            cache = image_cache.cache
            cellColoring = self.cellColoring
            wallColoring = self.wallColoring
            pointColoring = self.pointColoring
            file_format = self.fileFormat
            file_pattern = "%s%%0%dd.%s" % (self.filePrefix,
                                            len(str(len(result))), file_format)
            wall_file_pattern = "%s%%0%dd_wall.%s" % (
                self.filePrefix, len(str(len(result))), file_format)
            cell_file_pattern = "%s%%0%dd_cell.%s" % (
                self.filePrefix, len(str(len(result))), file_format)
            cellColoring.init()
            wallColoring.init()
            pointColoring.init()
            self.nextImage()
            for i in range(len(result)):
                if self.stopped():
                    self.abort("User interruption")
                    return
                pix, pic_w, pic_c = self.drawImage(i)
                pix.save(file_pattern % (i + 1), file_format)
                if pic_w is not None:
                    self.saveExtra(pic_w, wall_file_pattern % (i + 1),
                                   file_format)
                if pic_c is not None:
                    self.saveExtra(pic_c, cell_file_pattern % (i + 1),
                                   file_format)
                self.nextImage()
            self.finished()
        except Exception as ex:
            if painter is not None:
                painter.end()
            _, _, exceptionTraceback = sys.exc_info()
            self.abort(ex, traceback=exceptionTraceback)
            raise

    def saveExtra(self, picture, file_name, file_format):
        rect = picture.boundingRect()
        pix = QImage(rect.size(), QImage.Format_ARGB32)
        pix.fill(QColor(0, 0, 0, 0).rgba())
        paint = QPainter()
        paint.begin(pix)
        paint.drawPicture(rect.topLeft() * -1, picture)
        paint.end()
        pix.save(file_name, file_format)
Example #47
0
 def resizeEvent(self, event):
     q = self.parentWidget()
     if hasFeature(q, QDockWidget.DockWidgetVerticalTitleBar):
         fh = q.isFloating() and q.style().pixelMetric(
             QStyle.PM_DockWidgetFrameWidth, None, q) or 0
         opt = QStyleOptionDockWidgetV2()
         opt.initFrom(q)
         opt.verticalTitleBar = True
         opt.rect = QRect(
             QPoint(fh, 40),  #self.geometry().height() - (fh * 3)),
             QSize(self.geometry().width() - (fh * 2), fh * 2))
         opt.title = q.windowTitle()
         opt.closable = hasFeature(q, QDockWidget.DockWidgetClosable)
         opt.floatable = hasFeature(q, QDockWidget.DockWidgetFloatable)
         floatRect = q.style().subElementRect(
             QStyle.SE_DockWidgetFloatButton, opt, q)
         if not floatRect.isNull():
             self.floatButton.setGeometry(floatRect)
         closeRect = q.style().subElementRect(
             QStyle.SE_DockWidgetCloseButton, opt, q)
         if not closeRect.isNull():
             self.closeButton.setGeometry(closeRect)
         top = fh
         if not floatRect.isNull():
             top = floatRect.x()
         elif not closeRect.isNull():
             top = closeRect.x()
         size = self.collapseButton.size()
         if not closeRect.isNull():
             size = self.closeButton.size()
         elif not floatRect.isNull():
             size = self.floatButton.size()
         collapseRect = QRect(QPoint(top, fh), size)
         self.collapseButton.setGeometry(collapseRect)
         pinRect = QRect(QPoint(top, fh + collapseRect.height() + 1), size)
         self.pinButton.setGeometry(pinRect)
     else:
         fw = q.isFloating() and q.style().pixelMetric(
             QStyle.PM_DockWidgetFrameWidth, None, q) or 0
         opt = QStyleOptionDockWidgetV2()
         opt.initFrom(q)
         opt.rect = QRect(
             QPoint(fw, fw),
             QSize(self.geometry().width() - (fw * 2),
                   self.geometry().height() - (fw * 2)))
         opt.title = q.windowTitle()
         opt.closable = hasFeature(q, QDockWidget.DockWidgetClosable)
         opt.floatable = hasFeature(q, QDockWidget.DockWidgetFloatable)
         floatRect = q.style().subElementRect(
             QStyle.SE_DockWidgetFloatButton, opt, q)
         if not floatRect.isNull():
             self.floatButton.setGeometry(floatRect)
         closeRect = q.style().subElementRect(
             QStyle.SE_DockWidgetCloseButton, opt, q)
         if not closeRect.isNull():
             self.closeButton.setGeometry(closeRect)
         top = fw
         if not floatRect.isNull():
             top = floatRect.y()
         elif not closeRect.isNull():
             top = closeRect.y()
         size = self.collapseButton.size()
         if not closeRect.isNull():
             size = self.closeButton.size()
         elif not floatRect.isNull():
             size = self.floatButton.size()
         collapseRect = QRect(QPoint(fw, top), size)
         self.collapseButton.setGeometry(collapseRect)
         pinRect = QRect(QPoint(fw + collapseRect.width() + 1, top), size)
         self.pinButton.setGeometry(pinRect)
Example #48
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 = popplerqt4.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 layout).
        
        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.
        """
        rect = rect.normalized().intersected(self.rect())
        if not rect:
            return
        rect.translate(-self.pos())
        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 == popplerqt4.Poppler.Page.Rotate90:
                x, y = y, 1-x
            elif self._rotation == popplerqt4.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 == popplerqt4.Poppler.Page.Rotate90:
                left, top, right, bottom = top, 1-right, bottom, 1-left
            elif self._rotation == popplerqt4.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 == popplerqt4.Poppler.Page.Rotate90:
                left, top, right, bottom = 1-bottom, left, 1-top, right
            elif self._rotation == popplerqt4.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 == popplerqt4.Poppler.Page.Rotate90:
                left, top, right, bottom = top, w-right, bottom, w-left
            elif self._rotation == popplerqt4.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 == popplerqt4.Poppler.Page.Rotate90:
                left, top, right, bottom = w-bottom, left, w-top, right
            elif self._rotation == popplerqt4.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
Example #49
0
class PlottingThread(QThread):
    def __init__(self, parent):
        QThread.__init__(self)
        self.result = None
        self.parent = parent
        self._stopped = False
        self.mutex = QMutex()
        self.filePrefix = None
        self.fileFormat = None
        self.wallColoring = None
        self.cellColoring = None
        self.pointColoring = None
        self.extraDrawing = []
        self.pointSize = None
        self.pointLineColor = None
        self.pointLineThickness = None
        self.ellipsisDraw = None
        self.overSampling = None
        self.wallThickness = None
        self.bgColor = None
        self.loading = False
        self._crop = QRect(0,0,1,1)
        self._pix = None
        self._end_image_plot = False
        self._loading_arguments = {}
        self.retryObject = None

    def end_step(self):
        return len(self.result)+1

    def stop(self, value = True):
        self.mutex.lock()
        self._stopped = value
        self.mutex.unlock()

    def stopped(self):
        self.mutex.lock()
        val = self._stopped
        self.mutex.unlock()
        return val

    def nextImage(self):
        QCoreApplication.postEvent(self.parent, NextImageEvent())

    def abort(self, reason, **others):
        e = AbortPlottingEvent(reason)
        if others:
            e.others = others
        QCoreApplication.postEvent(self.parent, e)

    def finished(self):
        if self.loading:
            QCoreApplication.postEvent(self.parent, FinishLoadingEvent())
            self.loading = False
        else:
            QCoreApplication.postEvent(self.parent, FinishPlottingEvent())

    def image_ready(self):
        QCoreApplication.postEvent(self.parent, ImageReadyPlottingEvent())

    def update_nb_images(self, nb):
        QCoreApplication.postEvent(self.parent, UpdateNbImageEvent(nb))

    @property
    def crop_left(self):
        return self._crop.left()

    @crop_left.setter
    def crop_left(self, value):
        self._crop.moveLeft(int(value))

    @property
    def crop_top(self):
        return self._crop.top()

    @crop_top.setter
    def crop_top(self, value):
        self._crop.moveTop(int(value))

    @property
    def crop_width(self):
        return self._crop.width()

    @crop_width.setter
    def crop_width(self, value):
        self._crop.setWidth(int(value))

    @property
    def crop_height(self):
        return self._crop.height()

    @crop_height.setter
    def crop_height(self, value):
        self._crop.setHeight(int(value))

    def reset_crop(self):
        self._crop = QRect(QPoint(0,0), self.img_size)

    @property
    def crop(self):
        return QRect(self._crop)

    @crop.deleter
    def crop(self):
        self.reset_crop()

    @property
    def end_image_plot(self):
        '''
        If true, plot the growth data on the end image rather than the start image of the growth calculation.
        '''
        return self._end_image_plot

    @end_image_plot.setter
    def end_image_plot(self, value):
        self._end_image_plot = bool(value)

    @property
    def pix(self):
        '''Thread-safe image storage.'''
        self.mutex.lock()
        pix = self._pix
        self.mutex.unlock()
        return pix

    @pix.setter
    def pix(self, value):
        self.mutex.lock()
        self._pix = value
        self.mutex.unlock()

    def render_valid(self):
        if self.result is None:
            log_debug("result is None")
            return False
        if self.parent is None:
            log_debug("parent is None")
            return False
        if self.ellipsisDraw is None:
            log_debug("ellipsisDraw is None")
            return False
        if self.cellColoring is None:
            log_debug("cellColoring is None")
            return False
        if self.wallColoring is None:
            log_debug("wallColoring is None")
            return False
        if self.pointColoring is None:
            log_debug("pointColoring is None")
            return False
        if self.pointSize is None:
            log_debug("pointSize is None")
            return False
        if self.pointLineThickness is None:
            log_debug("pointSize is None")
            return False
        if self.pointLineColor is None:
            log_debug("pointSize is None")
            return False
        if self.wallThickness is None:
            log_debug("wallThickness is None")
            return False
        if self.overSampling is None:
            log_debug("overSampling is None")
            return False
        if self.bgColor is None:
            log_debug("bgColor is None")
            return False
        return True

    def valid(self):
        if self.filePrefix is None:
            log_debug("filePrefix is None")
            return False
        if not self.filePrefix:
            log_debug("filePrefix is Empty")
            return False
        if self.fileFormat is None:
            log_debug("fileFormat is None")
            return False
        return self.render_valid()

    def drawImage(self, imageid):
        cache = image_cache.cache
        cellColoring = self.cellColoring
        wallColoring = self.wallColoring
        pointColoring = self.pointColoring
        ellipsisDraw = self.ellipsisDraw
        overSampling = self.overSampling
        extraDrawing = self.extraDrawing
        bgColor = self.bgColor.rgb()
        result = self.result
        if self.result_type == "Data":
            data = result
            img_name = result.images_name[imageid]
        else:
            data = result.data
            img_name = result.images[imageid]
        #scale = data.images_scale[img_name]
        min_scale = data.minScale()
        img = cache.image(data.image_path(img_name))
        img_data = data[img_name]
        size = self._crop.size()
        pix = QImage(size*overSampling, QImage.Format_ARGB32)
        pix.fill(bgColor)
        painter = QPainter()
        if not painter.begin(pix):
            self.abort("Cannot create painter on QImage")
            return None, None, None
        painter.setRenderHints(QPainter.SmoothPixmapTransform, True)
        painter.setRenderHints(QPainter.Antialiasing, True)
        if overSampling > 1:
            painter.scale(overSampling, overSampling)
        painter.translate(-self._crop.topLeft())
        painter.save()
        painter.translate(self.translate)
        log_debug("Translating: %gx%g" % (self.translate.x(), self.translate.y()) )
        painter.scale(1/min_scale, 1/min_scale)
        painter.save()
        matrix = img_data.matrix()
        painter.setWorldTransform(matrix, True)
        painter.drawImage(QPoint(0,0), img)
        painter.restore()
        #pt_matrix = QTransform()
        #pt_matrix.scale(1/min_scale, 1/min_scale)
        #painter.setTransform(pt_matrix, True)
        cellColoring.startImage(painter, imageid)
        wallColoring.startImage(painter, imageid)
        for ed in extraDrawing:
            ed.startImage(painter, imageid)
        if self.result_type == "Growth":
            cells = result.cells[imageid]
            walls = result.walls[imageid]
        else:
            cells = img_data.cells
            walls = set()
            for cid in img_data.cells:
                pts = [ pt for pt in data.cells[cid] if pt in img_data ]
                if len(pts) > 1:
                    for i in range(len(pts)):
                        walls.add(data.wallId(pts[i-1], pts[i]))
        # Now, draw the cells and the ellipsis
        for cid in cells:
            painter.setPen(Qt.NoPen)
            color = cellColoring(imageid, cid)
            painter.setBrush(color)
            pts = data.cellAtTime(cid, img_data.index)
            if pts:
                pts.append(pts[0])
                ppts = []
                for p1,p2 in zip(pts[:-1], pts[1:]):
                    ppts.append(img_data[p1])
                    ppts.extend(img_data.walls[p1,p2])
                ppts.append(ppts[0])
                poly = QPolygonF(ppts)
                painter.drawPolygon(poly)
        # And draw the walls
        wallThickness = self.wallThickness*min_scale
        for wid in walls:
            color = wallColoring(imageid, wid)
            if color.alpha() > 0:
                pen = QPen(color)
                pen.setWidthF(wallThickness)
                painter.setPen(pen)
                pts = [img_data[wid[0]]] + img_data.walls[wid[0], wid[1]] + [img_data[wid[1]]]
                #painter.drawLine(img_data[wid[0]], img_data[wid[1]])
                painter.drawPolyline(*pts)
        # Then, draw the points
        pointSize = self.pointSize*min_scale
        pointLineColor = self.pointLineColor
        pointLineThickness = self.pointLineThickness*min_scale
        log_debug("pointSize = %g" % pointSize)
        for pid in img_data:
            color = pointColoring(imageid, pid)
            if color.alpha() > 0:
                pen = QPen(pointLineColor)
                pen.setWidthF(pointLineThickness)
                brush = QBrush(color)
                painter.setPen(pen)
                painter.setBrush(brush)
                pos = img_data[pid]
                rect = QRectF(pos.x()-pointSize, pos.y()-pointSize, 2*pointSize, 2*pointSize)
                painter.drawEllipse(rect)
        if ellipsisDraw.plot:
            for cid in cells:
                pts = data.cellAtTime(cid, img_data.index)
                if pts:
                    pts.append(pts[0])
                    ppts = []
                    for p1,p2 in zip(pts[:-1], pts[1:]):
                        ppts.append(img_data[p1])
                        ppts.extend(img_data.walls[p1,p2])
                    ppts.append(ppts[0])
                    #poly = QPolygonF(ppts)
                    #painter.drawPolygon(poly)
                    ellipsisDraw(painter, imageid, cid, ppts, min_scale)
        # At last, draw the extra data
        for ed in extraDrawing:
            ed(painter, imageid)
        tr = painter.worldTransform()
        painter.restore()
        pic_w = wallColoring.finalizeImage(painter, imageid, tr, self.crop)
        pic_c = cellColoring.finalizeImage(painter, imageid, tr, self.crop)
        for ed in extraDrawing:
            ed.finalizeImage(painter, imageid, tr, self.crop)
        painter.end()
        return pix, pic_w, pic_c

    def start(self):
        if self.isRunning():
            assert not self.rendering_all, "Cannot run twice the rendering of all images with the same object."
            return
        if parameters.instance.use_thread:
            log_debug("Starting rendering thread.")
            QThread.start(self)
            return False
        else:
            self.run()
            return True

    def render_all(self):
        self.rendering_all = True
        return self.start()

    def render_single(self, img_id, retry=False):
        if retry:
            while self.isRunning():
                self.wait(10000)
        elif self.isRunning():
            return
        self.rendering_all = False
        self.current_image = img_id
        return self.start()

    def load(self, filename):
        self.loading = True
        self.result = filename
        return self.start()

    def run(self):
        if self.loading:
            self.run_loader()
        elif self.rendering_all:
            self.run_full()
        else:
            self.run_single()

    def run_single(self):
        img = self.current_image
        self.cellColoring.init()
        self.wallColoring.init()
        self.pointColoring.init()
        log_debug("Rendering image %d" % img)
        self.pix, self.pic_w, self.pic_c = self.drawImage(img)
        if self.pic_w is not None:
            log_debug("Has wall image")
        if self.pic_c is not None:
            log_debug("Has cell image")
        if self.pix is not None:
            log_debug("Pix correctly rendered")
        log_debug("Rendered image %d  = %s" % (img, self.pix))
        self.image_ready()

    def reload(self):
        if self.retryObject is None:
            return
        self._loading_arguments.update(self.retryObject.method_args)
        self.load(self.retryObject.filename)

    def run_loader(self):
        filename = self.result
        try:
            self.retryObject = None
# First, prepare the data by getting the images and computing how big they
# should be
            f = open(filename)
            first_line = f.readline()
            f.close()
            if first_line.startswith("TRKR_VERSION"):
                result = Result(None)
                result.load(self.result, **self._loading_arguments)
                result_type = "Growth"
            else:
                result = TrackingData()
                result.load(self.result, **self._loading_arguments)
                result_type = "Data"
            self.result = result
            self.result_type = result_type
            if result_type == "Data":
                data = result
                images = data.images_name
                if data.cells:
                    self.has_cells = True
                    self.has_walls = True
                else:
                    self.has_cells = False
                    self.has_walls = False
                self.has_points = bool(data.cell_points)
            else:
                data = result.data
                images = result.images
                self.has_cells = False
                self.has_walls = False
                self.has_points = False
            self.images = images
            cache = image_cache.cache
            self.update_nb_images(len(result))
            bbox = QRectF()
            ms = data.minScale()
            for i in range(len(result)):
                img_name = images[i]
                img_data = data[img_name]
                img = cache.image(data.image_path(img_name))
                matrix = QTransform()
                matrix = img_data.matrix()
                sc = QTransform()
                sc.scale(1.0/ms, 1.0/ms)
                matrix *= sc
                r = QRectF(img.rect())
                rbox = matrix.map(QPolygonF(r)).boundingRect()
                bbox |= rbox
                log_debug("Image '%s':\n\tSize = %gx%g\n\tTransformed = %gx%g %+g %+g\n\tGlobal bbox = %gx%g %+g %+g\n" %
                             (img_name, r.width(), r.height(), rbox.width(), rbox.height(), rbox.left(), rbox.top(),
                              bbox.width(), bbox.height(), bbox.left(), bbox.top()))
                log_debug("Matrix:\n%g\t%g\t%g\n%g\t%g\t%g\n" %
                            (matrix.m11(), matrix.m12(), matrix.dx(), matrix.m21(), matrix.m22(), matrix.dy()))
                if result_type == "Growth":
                    if result.cells[i]:
                        self.has_cells = True
                    if result.walls[i]:
                        self.has_walls = True
                    self.has_points = bool(result.data.cell_points)
                self.nextImage()
            translate = bbox.topLeft()
            translate *= -1
            self.translate = translate
            size = bbox.size().toSize()
            self.img_size = size
            self._crop = QRect(QPoint(0,0), size)
            self.finished()
            self._loading_arguments = {} # All done, we don't need that anymore
        except RetryTrackingDataException as ex:
            ex.filename = filename
            self.retryObject = ex
            self.finished()
            return
        except Exception as ex:
            _, _, exceptionTraceback = sys.exc_info()
            self.abort(ex, traceback=exceptionTraceback)
            raise

    def run_full(self):
        if not self.valid():
            self.abort("Object was not correctly initialized")
            return
        self.stop(False)
        painter = None
        try:
            result = self.result
            self.update_nb_images(len(result))
#            if self.result_type == "Data":
#                data = result
#                images = result.images_name
#            else:
#                data = result.data
#                images = result.images
#            cache = image_cache.cache
            cellColoring = self.cellColoring
            wallColoring = self.wallColoring
            pointColoring = self.pointColoring
            file_format = self.fileFormat
            file_pattern = "%s%%0%dd.%s" % (self.filePrefix, len(str(len(result))), file_format)
            wall_file_pattern = "%s%%0%dd_wall.%s" % (self.filePrefix, len(str(len(result))), file_format)
            cell_file_pattern = "%s%%0%dd_cell.%s" % (self.filePrefix, len(str(len(result))), file_format)
            cellColoring.init()
            wallColoring.init()
            pointColoring.init()
            self.nextImage()
            for i in range(len(result)):
                if self.stopped():
                    self.abort("User interruption")
                    return
                pix, pic_w, pic_c = self.drawImage(i)
                pix.save(file_pattern % (i+1), file_format)
                if pic_w is not None:
                    self.saveExtra(pic_w, wall_file_pattern % (i+1), file_format)
                if pic_c is not None:
                    self.saveExtra(pic_c, cell_file_pattern % (i+1), file_format)
                self.nextImage()
            self.finished()
        except Exception as ex:
            if painter is not None:
                painter.end()
            _, _, exceptionTraceback = sys.exc_info()
            self.abort(ex, traceback=exceptionTraceback)
            raise

    def saveExtra(self, picture, file_name, file_format):
        rect = picture.boundingRect()
        pix = QImage(rect.size(), QImage.Format_ARGB32)
        pix.fill(QColor(0, 0, 0, 0).rgba())
        paint = QPainter()
        paint.begin(pix)
        paint.drawPicture(rect.topLeft()*-1, picture)
        paint.end()
        pix.save(file_name, file_format)
Example #50
0
class LayerPainter( object ):
    def __init__(self):
        self.layer = None

        self.rect = QRect()

        self.fm = QFontMetrics(QFont())

        self.iconSize = 20
        self.iconXOffset = 5
        self.textXOffset = 5
        self.progressXOffset = self.iconXOffset+self.iconSize+self.textXOffset
        self.progressYOffset = self.iconSize+5
        self.progressHeight = 10

        self.alphaTextWidth = self.fm.boundingRect(u"\u03B1=100.0%").width()

    def sizeHint(self, mode):
       if mode == 'ReadOnly':
           return QSize(1,self.fm.height()+5)
       elif mode == 'Expanded' or mode == 'Editable':
           return QSize(1,self.progressYOffset+self.progressHeight+5)
       else:
           raise RuntimeError("Unknown mode")

    def overEyeIcon(self, x, y):
        #with a sufficiently large height (100)
        #we make sure that the user can also click below the eye to toggle
        #the layer
        return QPoint(x,y) in QRect(self.iconXOffset,0,self.iconSize,100)

    def percentForPosition(self, x, y, parentWidth, checkBoundaries=True):
        """
        For some strange reason, self.rect.width() is sometimes 0 when this is called.
        For that reason, we can't use self._progressWidth and we must pass in the parentWidth as an argument.
        """
        if checkBoundaries and (y < self.progressYOffset or y > self.progressYOffset + self.progressHeight) \
                           or  (x < self.progressXOffset):
            return -1

        percent = (x-self.progressXOffset)/float(parentWidth-self.progressXOffset-10)
        if percent < 0:
            return 0.0
        if percent > 1:
            return 1.0
        return percent

    @property
    def _progressWidth(self):
        return self.rect.width()-self.progressXOffset-10

    def paint(self, painter, rect, palette, mode, isSelected):
        if not self.layer.visible:
            palette.setCurrentColorGroup(QPalette.Disabled)

        self.rect = rect
        painter.save()
        painter.setRenderHint(QPainter.Antialiasing, True)

        painter.setBrush(palette.text())

        if isSelected:
            painter.save()
            painter.setBrush(palette.highlight())
            painter.drawRect(rect)
            painter.restore()

        painter.translate(rect.x(), rect.y())
        painter.setFont(QFont())

        textOffsetX = self.progressXOffset
        textOffsetY = max(self.fm.height()-self.iconSize,0)/2.0+self.fm.height()

        if self.layer.visible:
            painter.drawImage(QRect(self.iconXOffset,0,self.iconSize,self.iconSize), \
                              QImage(":icons/icons/stock-eye-20.png"))
        else:
            painter.drawImage(QRect(self.iconXOffset,0,self.iconSize,self.iconSize), \
                              QImage(":icons/icons/stock-eye-20-gray.png"))

        if self.layer.direct:
            painter.save()
            painter.setBrush(palette.text())
            painter.drawEllipse(self.iconXOffset+self.iconSize/2-2, self.iconSize+3, 4,4 )
            painter.restore()

        #layer name text
        if mode != 'ReadOnly':
            painter.setBrush(palette.highlightedText())
        else:
            painter.setBrush(palette.text())

        #layer name
        painter.drawText(QPoint(textOffsetX, textOffsetY), "%s" % self.layer.name)
        #opacity
        text = u"\u03B1=%0.1f%%" % (100.0*(self.layer.opacity))
        painter.drawText(QPoint(textOffsetX+self._progressWidth-self.alphaTextWidth, textOffsetY), text)


        if mode != 'ReadOnly':
            #frame around percentage indicator
            painter.setBrush(palette.dark())
            painter.save()
            #no fill color
            b = painter.brush(); b.setStyle(Qt.NoBrush); painter.setBrush(b)
            painter.drawRect(QRect(QPoint(self.progressXOffset, self.progressYOffset), \
                                          QSize(self._progressWidth, self.progressHeight)))
            painter.restore()

            #percentage indicator
            painter.drawRect(QRect(QPoint(self.progressXOffset, self.progressYOffset), \
                                          QSize(self._progressWidth*self.layer.opacity, self.progressHeight)))

        painter.restore()
Example #51
0
class Phantom(QObject):
    def __init__(self, args, parent=None):
        QObject.__init__(self, parent)

        # variable declarations
        self.m_loadStatus = self.m_state = ''
        self.m_var = self.m_paperSize = self.m_loadScript_cache = {}
        self.m_verbose = args.verbose
        self.m_page = WebPage(self)
        self.m_clipRect = QRect()
        # setup the values from args
        self.m_script = args.script.read()
        self.m_scriptFile = args.script.name
        self.m_scriptDir = os.path.dirname(args.script.name) + '/'
        self.m_args = args.script_args
        self.m_upload_file = args.upload_file
        autoLoadImages = False if args.load_images == 'no' else True
        pluginsEnabled = True if args.load_plugins == 'yes' else False

        args.script.close()

        do_action('PhantomInitPre', Bunch(locals()))

        palette = self.m_page.palette()
        palette.setBrush(QPalette.Base, Qt.transparent)
        self.m_page.setPalette(palette)

        if not args.proxy:
            QNetworkProxyFactory.setUseSystemConfiguration(True)
        else:
            proxy = QNetworkProxy(QNetworkProxy.HttpProxy, args.proxy[0], int(args.proxy[1]))
            QNetworkProxy.setApplicationProxy(proxy)

        self.m_page.settings().setAttribute(QWebSettings.AutoLoadImages, autoLoadImages)
        self.m_page.settings().setAttribute(QWebSettings.PluginsEnabled, pluginsEnabled)
        self.m_page.settings().setAttribute(QWebSettings.FrameFlatteningEnabled, True)
        self.m_page.settings().setAttribute(QWebSettings.OfflineStorageDatabaseEnabled, True)
        self.m_page.settings().setAttribute(QWebSettings.LocalStorageEnabled, True)
        self.m_page.settings().setLocalStoragePath(QDesktopServices.storageLocation(QDesktopServices.DataLocation))
        self.m_page.settings().setOfflineStoragePath(QDesktopServices.storageLocation(QDesktopServices.DataLocation))

        # Ensure we have a document.body.
        self.m_page.mainFrame().setHtml('<html><body></body></html>')

        self.m_page.mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
        self.m_page.mainFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)

        m_netAccessMan = NetworkAccessManager(args.disk_cache, args.ignore_ssl_errors, self)
        self.m_page.setNetworkAccessManager(m_netAccessMan)

        # inject our properties and slots into javascript
        self.m_page.mainFrame().javaScriptWindowObjectCleared.connect(self.inject)
        self.m_page.loadFinished.connect(self.finish)

        do_action('PhantomInitPost', Bunch(locals()))

    def execute(self):
        if self.m_script.startswith('#!'):
            self.m_script = '//' + self.m_script

        if self.m_scriptFile.lower().endswith('.coffee'):
            coffee = CSConverter(self)
            self.m_script = coffee.convert(self.m_script)

        self.m_page.mainFrame().evaluateJavaScript(self.m_script)

    def finish(self, success):
        self.m_loadStatus = 'success' if success else 'fail'
        self.m_page.mainFrame().evaluateJavaScript(self.m_script)

    def inject(self):
        self.m_page.mainFrame().addToJavaScriptWindowObject('phantom', self)

    def renderPdf(self, fileName):
        p = QPrinter()
        p.setOutputFormat(QPrinter.PdfFormat)
        p.setOutputFileName(fileName)
        p.setResolution(pdf_dpi)
        paperSize = self.m_paperSize

        if not len(paperSize):
            pageSize = QSize(self.m_page.mainFrame().contentsSize())
            paperSize['width'] = str(pageSize.width()) + 'px'
            paperSize['height'] = str(pageSize.height()) + 'px'
            paperSize['border'] = '0px'

        if paperSize.get('width') and paperSize.get('height'):
            sizePt = QSizeF(ceil(self.stringToPointSize(paperSize['width'])),
                            ceil(self.stringToPointSize(paperSize['height'])))
            p.setPaperSize(sizePt, QPrinter.Point)
        elif 'format' in paperSize:
            orientation = QPrinter.Landscape if paperSize.get('orientation') and paperSize['orientation'].lower() == 'landscape' else QPrinter.Portrait
            orientation = QPrinter.Orientation(orientation)
            p.setOrientation(orientation)

            formats = {
                'A3': QPrinter.A3,
                'A4': QPrinter.A4,
                'A5': QPrinter.A5,
                'Legal': QPrinter.Legal,
                'Letter': QPrinter.Letter,
                'Tabloid': QPrinter.Tabloid
            }

            p.setPaperSize(QPrinter.A4) # fallback
            for format, size in formats.items():
                if format.lower() == paperSize['format'].lower():
                    p.setPaperSize(size)
                    break
        else:
            return False

        border = floor(self.stringToPointSize(paperSize['border'])) if paperSize.get('border') else 0
        p.setPageMargins(border, border, border, border, QPrinter.Point)

        self.m_page.mainFrame().print_(p)
        return True

    def returnValue(self):
        return self.m_returnValue

    def stringToPointSize(self, string):
        units = (
            ('mm', 72 / 25.4),
            ('cm', 72 / 2.54),
            ('in', 72.0),
            ('px', 72.0 / pdf_dpi / 2.54),
            ('', 72.0 / pdf_dpi / 2.54)
        )

        for unit, format in units:
            if string.endswith(unit):
                value = string.rstrip(unit)
                return float(value) * format
        return 0

    ##
    # Properties and methods exposed to JavaScript
    ##

    @pyqtProperty('QStringList')
    def args(self):
        return self.m_args

    @pyqtProperty('QVariantMap')
    def clipRect(self):
        result = {
            'width': self.m_clipRect.width(),
            'height': self.m_clipRect.height(),
            'top': self.m_clipRect.top(),
            'left': self.m_clipRect.left()
        }
        return result

    @clipRect.setter
    def clipRect(self, size):
        names = ('width', 'height', 'top', 'left')
        for item in names:
            try:
                globals()[item] = int(size[item])
                if globals()[item] < 0:
                    if item not in ('top', 'left'):
                        globals()[item] = 0
            except KeyError:
                globals()[item] = getattr(self.m_clipRect, item)()

        self.m_clipRect = QRect(left, top, width, height)

    @pyqtProperty(str)
    def content(self):
        return self.m_page.mainFrame().toHtml()

    @content.setter
    def content(self, content):
        self.m_page.mainFrame().setHtml(content)

    @pyqtSlot()
    @pyqtSlot(int)
    def exit(self, code=0):
        self.m_returnValue = code
        self.m_page.loadFinished.disconnect(self.finish)
        QTimer.singleShot(0, qApp, SLOT('quit()'))

    @pyqtProperty(str)
    def loadStatus(self):
        return self.m_loadStatus

    @pyqtSlot(str, result=bool)
    def loadScript(self, script):
        if script in self.m_loadScript_cache:
            self.m_page.mainFrame().evaluateJavaScript(self.m_loadScript_cache[script])
            return True

        scriptFile = script
        try:
            script = codecs.open(self.m_scriptDir + script, encoding='utf-8')
            script = script.read()
        except IOError:
            return False

        if script.startswith('#!'):
            script = '//' + script

        if scriptFile.lower().endswith('.coffee'):
            coffee = CSConverter(self)
            script = coffee.convert(script)

        self.m_loadScript_cache[scriptFile] = script
        self.m_page.mainFrame().evaluateJavaScript(script)
        return True

    @pyqtSlot(str, name='open')
    def open_(self, address):
        qDebug('Opening address %s' % address)
        self.m_page.triggerAction(QWebPage.Stop)
        self.m_loadStatus = 'loading'
        self.m_page.mainFrame().setUrl(QUrl(address))

    @pyqtProperty('QVariantMap')
    def paperSize(self):
        return self.m_paperSize

    @paperSize.setter
    def paperSize(self, size):
        self.m_paperSize = size

    @pyqtSlot(str, result=bool)
    def render(self, fileName):
        fileInfo = QFileInfo(fileName)
        path = QDir()
        path.mkpath(fileInfo.absolutePath())

        if fileName.lower().endswith('.pdf'):
            return self.renderPdf(fileName)

        viewportSize = QSize(self.m_page.viewportSize())
        pageSize = QSize(self.m_page.mainFrame().contentsSize())

        bufferSize = QSize()
        if not self.m_clipRect.isEmpty():
            bufferSize = self.m_clipRect.size()
        else:
            bufferSize = self.m_page.mainFrame().contentsSize()

        if pageSize == '':
            return False

        image = QImage(bufferSize, QImage.Format_ARGB32)
        image.fill(qRgba(255, 255, 255, 0))
        p = QPainter(image)

        p.setRenderHint(QPainter.Antialiasing, True)
        p.setRenderHint(QPainter.TextAntialiasing, True)
        p.setRenderHint(QPainter.SmoothPixmapTransform, True)

        self.m_page.setViewportSize(pageSize)

        if not self.m_clipRect.isEmpty():
            p.translate(-self.m_clipRect.left(), -self.m_clipRect.top())
            self.m_page.mainFrame().render(p, QRegion(self.m_clipRect))
        else:
            self.m_page.mainFrame().render(p)

        p.end()
        self.m_page.setViewportSize(viewportSize)
        return image.save(fileName)

    @pyqtSlot('QWebElement', str)
    def setFormInputFile(self, el, fileTag):
        self.m_page.m_nextFileTag = fileTag
        el.evaluateJavaScript('''(function(target){
                              var evt = document.createEvent('MouseEvents');
                              evt.initMouseEvent("click", true, true, window,
                              0, 0, 0, 0, 0, false, false, false, false, 0, null);
                              target.dispatchEvent(evt);})(this);''')

    @pyqtSlot(int)
    def sleep(self, ms):
        startTime = QTime.currentTime()
        while True:
            QApplication.processEvents(QEventLoop.AllEvents, 25)
            if startTime.msecsTo(QTime.currentTime()) > ms:
                break
            usleep(0.005)

    @pyqtProperty(str)
    def state(self):
        return self.m_state

    @state.setter
    def state(self, value):
        self.m_state = value

    @pyqtProperty(str)
    def userAgent(self):
        return self.m_page.m_userAgent

    @userAgent.setter
    def userAgent(self, ua):
        self.m_page.m_userAgent = ua

    @pyqtSlot(str, result='QVariant')
    @pyqtSlot(int, result='QVariant')
    @pyqtSlot(str, 'QVariant')
    @pyqtSlot(int, 'QVariant')
    def ctx(self, name, value=None):
        if not value:
            return self.m_var.get(name)
        self.m_var[name] = value

    @pyqtProperty('QVariantMap')
    def version(self):
        version = {
            'major': version_major,
            'minor': version_minor,
            'patch': version_patch
        }
        return version

    @pyqtProperty('QVariantMap')
    def viewportSize(self):
        size = self.m_page.viewportSize()
        result = {
            'width': size.width(),
            'height': size.height()
        }
        return result

    @viewportSize.setter
    def viewportSize(self, size):
        names = ('width', 'height')
        for item in names:
            try:
                globals()[item] = int(size[item])
                if globals()[item] < 0:
                    globals()[item] = 0
            except KeyError:
                globals()[item] = getattr(self.m_page.viewportSize(), item)()

        self.m_page.setViewportSize(QSize(width, height))

    do_action('Phantom', Bunch(locals()))
class ObstacleAreaJigSelectArea(QgsMapTool):

    def __init__(self, canvas, areaType):
        self.mCanvas = canvas
        self.areaType = areaType
        QgsMapTool.__init__(self, canvas)
        self.mCursor = Qt.ArrowCursor
        self.mRubberBand = None
        self.mDragging = False
        self.mSelectRect = QRect()
        self.mRubberBandResult = None
        self.mSnapper = QgsMapCanvasSnapper(canvas)
        self.lineCount = 0
        self.resultGeomList = []
        self.geomList = []
        self.area = None
        self.isFinished = False
#     QgsRubberBand* mRubberBand;
#     def reset(self):
#         self.startPoint = None
#         self.endPoint = None
#         self.isDrawing = False
#         SelectByRect.RubberRect.reset(QGis.Polygon)
#         self.layer = self.canvas.currentLayer()

    def canvasPressEvent(self, e):
        QgisHelper.ClearRubberBandInCanvas(define._canvas)
        self.mSelectRect.setRect( 0, 0, 0, 0 )
        self.mRubberBand = QgsRubberBand( self.mCanvas, QGis.Polygon )
        self.startPoint, self.pointID, self.layer= self.snapPoint(e.pos())

    def canvasMoveEvent(self, e):
        if self.areaType == ProtectionAreaType.Secondary:
            if self.lineCount == 0:
                define._messageLabel.setText("Select a line or arc representing the INNER edge of the secondary area.")
            elif self.lineCount == 1:
                define._messageLabel.setText("Select a line representing the OUTER edge of the secondary area.")
        elif self.areaType == ProtectionAreaType.Primary:
            define._messageLabel.setText("")
        elif self.areaType == ProtectionAreaType.PrimaryAndSecondary:
            if self.lineCount == 0:
                define._messageLabel.setText("Select a line or arc representing the INNER edge of the FIRST secondary area.")
            elif self.lineCount == 1:
                define._messageLabel.setText("Select a line representing the OUTER edge of the FIRST secondary area.")
            elif self.lineCount == 2:
                define._messageLabel.setText("Select a line or arc representing the INNER edge of the SECOND secondary area.")
            elif self.lineCount == 3:
                define._messageLabel.setText("Select a line representing the OUTER edge of the SECOND secondary area.")
        else:
            define._messageLabel.setText("")


        if ( e.buttons() != Qt.LeftButton ):
            return
        if ( not self.mDragging ):
            self.mDragging = True
            self.mSelectRect.setTopLeft( e.pos() )
        self.mSelectRect.setBottomRight( e.pos() )
        QgsMapToolSelectUtils.setRubberBand( self.mCanvas, self.mSelectRect,self.mRubberBand )

    def canvasReleaseEvent(self, e):
        self.endPoint, self.pointID, self.layer= self.snapPoint(e.pos())

        vlayer = QgsMapToolSelectUtils.getCurrentVectorLayer( self.mCanvas )
        if ( vlayer == None ):
            if ( self.mRubberBand != None):
                self.mRubberBand.reset( QGis.Polygon )
                del self.mRubberBand
                self.mRubberBand = None
                self.mDragging = False
            return


        if (not self.mDragging ):
            QgsMapToolSelectUtils.expandSelectRectangle(self. mSelectRect, vlayer, e.pos() )
        else:
            if ( self.mSelectRect.width() == 1 ):
                self.mSelectRect.setLeft( self.mSelectRect.left() + 1 )
            if ( self.mSelectRect.height() == 1 ):
                self.mSelectRect.setBottom( self.mSelectRect.bottom() + 1 )

        if ( self.mRubberBand != None ):
            QgsMapToolSelectUtils.setRubberBand( self.mCanvas, self.mSelectRect, self.mRubberBand )
            selectGeom = self.mRubberBand.asGeometry()


            selectedFeatures = QgsMapToolSelectUtils.setSelectFeaturesOrRubberband_Tas_1( self.mCanvas, selectGeom, e )
            if len(selectedFeatures) > 0:
                self.lineCount += 1
                geom = selectedFeatures[0].geometry()
                resultArray = QgisHelper.findArcOrLineInLineGeometry(geom, selectGeom)
                # if resultArray != None:
                #     bulge = MathHelper.smethod_60(resultArray[0], resultArray[int(len(resultArray)/2)], resultArray[len(resultArray)-1])
                #     bulge1 = MathHelper.smethod_60(resultArray[len(resultArray)-1], resultArray[int(len(resultArray)/2)], resultArray[0])
                #     n = 0
                pointArray0 = geom.asPolyline()
                self.resultGeomList.append(resultArray)
                self.geomList.append(pointArray0)
                if self.lineCount == 2 and self.areaType != ProtectionAreaType.PrimaryAndSecondary and self.areaType != ProtectionAreaType.Complex:
                    self.area = self.makeArea(self.resultGeomList, self.areaType)
                    pointArray = self.getPointArray(self.resultGeomList).method_14_closed()
                    self.mRubberBandResult = None
                    self.mRubberBandResult = QgsRubberBand( self.mCanvas, QGis.Polygon )
                    self.mRubberBandResult.setFillColor(QColor(255, 255, 255, 100))
                    self.mRubberBandResult.setBorderColor(QColor(0, 0, 0))
                    for point in pointArray:
                        self.mRubberBandResult.addPoint(point)
                    self.mRubberBandResult.show()


                    self.emit(SIGNAL("outputResult"), self.area, self.mRubberBandResult)
                    self.lineCount = 0
                    self.resultGeomList = []
                    self.isFinished = True
                    # self.rubberBandLine.reset(QGis.Line)
                elif self.lineCount == 4 and self.areaType == ProtectionAreaType.PrimaryAndSecondary:
                    self.area = self.makeArea(self.resultGeomList, self.areaType)
                    pointArray = self.getPointArray([self.resultGeomList[1], self.resultGeomList[3]]).method_14_closed()
                    self.mRubberBandResult = None
                    self.mRubberBandResult = QgsRubberBand( self.mCanvas, QGis.Polygon )
                    self.mRubberBandResult.setFillColor(QColor(255, 255, 255, 100))
                    self.mRubberBandResult.setBorderColor(QColor(0, 0, 0))
                    for point in pointArray:
                        self.mRubberBandResult.addPoint(point)
                    self.mRubberBandResult.show()


                    self.emit(SIGNAL("outputResult"), self.area, self.mRubberBandResult)
                    self.lineCount = 0
                    self.resultGeomList = []
                # else:
                #     return
            del selectGeom

            self.mRubberBand.reset( QGis.Polygon )
            del self.mRubberBand
            self.mRubberBand = None
        self.mDragging = False
    def getPointArray(self, geomList):
        pointArrayInner = geomList[0]
        pointArray1Outer = geomList[1]

        innerStartPoint = pointArrayInner[0]
        innerEndPoint = pointArrayInner[1]
        innerBulge = pointArrayInner[2]
        outerStartPoint = pointArray1Outer[0]
        outerEndPoint = pointArray1Outer[1]
        outerBulge = pointArray1Outer[2]

        line0 = QgsGeometry.fromPolyline([innerStartPoint, outerStartPoint])
        line1 = QgsGeometry.fromPolyline([innerEndPoint, outerEndPoint])

        # for i in range(1, len(pointArray0)):

        if line0.intersects(line1):
            tempPoint = outerStartPoint
            outerStartPoint = outerEndPoint
            outerEndPoint = tempPoint
            outerBulge = -outerBulge

        polylineArea = PolylineArea()
        polylineArea.Add(PolylineAreaPoint(innerStartPoint, innerBulge))
        polylineArea.Add(PolylineAreaPoint(innerEndPoint))
        polylineArea.Add(PolylineAreaPoint(outerEndPoint, -outerBulge))
        polylineArea.Add(PolylineAreaPoint(outerStartPoint))
        return polylineArea
    def makeArea(self, geomList, areaType):
        if areaType == ProtectionAreaType.Primary or areaType == ProtectionAreaType.Secondary:
            return self.makePrimaryAreaOrSecondaryArea(geomList, areaType)
        elif areaType == ProtectionAreaType.PrimaryAndSecondary:
            pointArray0 = geomList[0]
            pointArray1 = geomList[1]
            pointArray2 = geomList[2]
            pointArray3 = geomList[3]
            primaryArea = self.makePrimaryAreaOrSecondaryArea([pointArray0, pointArray2], ProtectionAreaType.Primary)
            secondaryArea1 = self.makePrimaryAreaOrSecondaryArea([pointArray0, pointArray1], ProtectionAreaType.Secondary)
            secondaryArea2 = self.makePrimaryAreaOrSecondaryArea([pointArray2, pointArray3], ProtectionAreaType.Secondary)
            return PrimarySecondaryObstacleArea(primaryArea, secondaryArea1, secondaryArea2)
            # if len(geomList[0]) == 2 and len(geomList[1]) == 2 and len(geomList[2]) == 2 and len(geomList[3]) == 2:
            #     for i in range(1, len(geomList)):
            #         pointArray0 = geomList[0]
            #         pointArray1 = geomList[i]
            #         line0 = QgsGeometry.fromPolyline([pointArray0[0], pointArray1[0]])
            #         line1 = QgsGeometry.fromPolyline([pointArray0[len(pointArray0) - 1], pointArray1[len(pointArray1) - 1]])
            #         if line0.intersects(line1):
            #             pointArray1.reverse()
            #     pointArray0 = geomList[0]
            #     pointArray1 = geomList[1]
            #     pointArray2 = geomList[2]
            #     pointArray3 = geomList[3]
            #     area = PrimarySecondaryObstacleArea()
            #     area.set_areas(pointArray0, pointArray1, pointArray2, pointArray3)
            #     return area
            # return None

        return None
    def makePrimaryAreaOrSecondaryArea(self, geomList, areaType):
        pointArrayInner = geomList[0]
        pointArray1Outer = geomList[1]

        innerStartPoint = pointArrayInner[0]
        innerEndPoint = pointArrayInner[1]
        innerBulge = pointArrayInner[2]
        outerStartPoint = pointArray1Outer[0]
        outerEndPoint = pointArray1Outer[1]
        outerBulge = pointArray1Outer[2]

        line0 = QgsGeometry.fromPolyline([innerStartPoint, outerStartPoint])
        line1 = QgsGeometry.fromPolyline([innerEndPoint, outerEndPoint])

        # for i in range(1, len(pointArray0)):

        if line0.intersects(line1):
            tempPoint = Point3D(outerStartPoint.get_X(), outerStartPoint.get_Y())
            outerStartPoint = Point3D(outerEndPoint.get_X(), outerEndPoint.get_Y())
            outerEndPoint = Point3D(tempPoint.get_X(), tempPoint.get_Y())
            outerBulge = -outerBulge
        if areaType == ProtectionAreaType.Primary:
            polylineArea = PolylineArea()
            polylineArea.Add(PolylineAreaPoint(innerStartPoint, innerBulge))
            polylineArea.Add(PolylineAreaPoint(innerEndPoint))
            polylineArea.Add(PolylineAreaPoint(outerEndPoint, -outerBulge))
            polylineArea.Add(PolylineAreaPoint(outerStartPoint))
            return PrimaryObstacleArea(polylineArea)
        elif areaType == ProtectionAreaType.Secondary:
            if innerBulge == 0 and outerBulge == 0:
                return SecondaryObstacleArea(innerStartPoint, innerEndPoint, outerStartPoint, outerEndPoint, MathHelper.getBearing(innerStartPoint, innerEndPoint))
            elif innerBulge != 0 and outerBulge != 0:
                if round(innerBulge, 1) != round(outerBulge, 1):
                    return None
                innerCenterPoint = MathHelper.smethod_71(innerStartPoint, innerEndPoint, innerBulge)
                outerCenterPoint = MathHelper.smethod_71(outerStartPoint, outerEndPoint, outerBulge)

                innerRadius = MathHelper.calcDistance(innerCenterPoint, innerStartPoint);
                outerRadius = MathHelper.calcDistance(outerCenterPoint, outerStartPoint);

                bearing = (MathHelper.getBearing(innerCenterPoint, innerStartPoint) + MathHelper.getBearing(innerCenterPoint, innerEndPoint)) / 2
                innerMiddlePoint = MathHelper.distanceBearingPoint(innerCenterPoint, bearing, innerRadius)
                if round(MathHelper.smethod_60(innerStartPoint, innerMiddlePoint, innerEndPoint), 4) != round(outerBulge, 4):
                    bearing += 3.14159265358979
                    innerMiddlePoint = MathHelper.distanceBearingPoint(innerCenterPoint, bearing, innerRadius)

                bearing = (MathHelper.getBearing(outerCenterPoint, outerStartPoint) + MathHelper.getBearing(outerCenterPoint, outerEndPoint)) / 2
                outerMiddlePoint = MathHelper.distanceBearingPoint(outerCenterPoint, bearing, outerRadius)
                if round(MathHelper.smethod_60(outerStartPoint, outerMiddlePoint, outerEndPoint), 4) != round(outerBulge, 4):
                    bearing += 3.14159265358979
                    outerMiddlePoint = MathHelper.distanceBearingPoint(outerCenterPoint, bearing, outerRadius)
                return SecondaryObstacleArea(innerStartPoint, innerMiddlePoint, innerEndPoint, outerStartPoint, None, outerMiddlePoint, outerEndPoint, innerBulge, innerBulge)
            return None
    def snapPoint(self, p, bNone = False):
        if define._snapping == False:
            return (define._canvas.getCoordinateTransform().toMapCoordinates( p ), None, None)
        snappingResults = self.mSnapper.snapToBackgroundLayers( p )
        if ( snappingResults[0] != 0 or len(snappingResults[1]) < 1 ):

            if bNone:
                return (None, None, None)
            else:
                return (define._canvas.getCoordinateTransform().toMapCoordinates( p ), None, None)
        else:
            return (snappingResults[1][0].snappedVertex, snappingResults[1][0].snappedAtGeometry, snappingResults[1][0].layer)
Example #53
0
class PoseWidget(QLabel):
    default_colors = (Qt.red, Qt.blue, Qt.yellow, Qt.green)

    def __init__(self,
                 ressource_directory,
                 dim: QSize,
                 player_size: QSize,
                 player_ratio_spacing: float = 0.33,
                 alpha_color="#FF00FF",
                 vertical_random_ratio=0.1,
                 key_press_event_callback=None,
                 dev_mode=False):
        """
        :param ressource_directory: String, chemin du dossier ressource.
        :param dim: QSize, taille alloué au widget.
        :param dev_mode: boolean [facultatif (defaut False)], active le mode developpement.
        """
        # Setup widget
        super().__init__()
        if dev_mode:
            self.setStyleSheet("background-color:blue")
        else:
            self.setStyleSheet("background-color:" + alpha_color)
        self.setMaximumSize(dim)
        self.setMinimumSize(dim)

        # Setup poses
        self.current_silhouette = None
        self.colors = list(self.default_colors)
        self.player_rect = QRect((dim.width() - player_size.width()) * 0.5,
                                 (dim.height() - player_size.height()) * 0.5,
                                 player_size.width(), player_size.height())
        self.player_ratio_spacing = player_ratio_spacing
        self.vertical_random_ratio = vertical_random_ratio
        self.player_pixel_spacing = 0
        self.pose_dict = {}
        self._load_all_poses(ressource_directory,
                             load_all_images=True,
                             verbose=False,
                             filter_valid=True,
                             dev_mode=dev_mode)

        # Init constant for pose drawing
        exemple_sil_pixmap = self.pose_dict[list(
            self.pose_dict.keys())[1]].get_silhouette().pixmap
        vertical_scale = self.player_rect.height() / exemple_sil_pixmap.height(
        )
        self.pose_hauteur = round(exemple_sil_pixmap.height() * vertical_scale)
        self.pose_largeur = round(exemple_sil_pixmap.width() * vertical_scale)
        self.player_pixel_spacing = self.player_ratio_spacing * self.pose_largeur

        # Event callback
        self.key_press_event_callback = key_press_event_callback

    def _load_all_poses(self,
                        ressource_directory,
                        load_all_images=False,
                        verbose=False,
                        filter_valid=True,
                        dev_mode=False):
        """Essai de charger toutes les poses ayant un fichier de conf dans le sous-dossier 'pose_configs' du dossier
        ressource fourni
        PARAMS: - ressource_directory : path-like = le chemin du dossier de ressource du jeu
                -[load_all_images]: boolean = [False] si True les images (.png/.jpg) présentent dans le dossiers
                'silhouette_storage' mais ne comportant pas de ficher de conf associées seront aussi chargées et une
                configuration automatique leur sera créé.
                -[verbose]: boolean = [False] si True, la liste des fonds trouvés sera affichée ainsi que leur validité
                (contient tous les fonds valides où non)
                -[filter_valid]: boolean = [True] si True seul les fonds correctment chargés seront revoyés.
        Postcondition : le dictionnaire pose_dict des fonds est chargé"""
        if dev_mode:
            print("   Loading Poses...", end="")
        self.pose_dict = {}
        # lister tous les nom de poses (c'est a dire tous les fichier d'extension '.conf' du dossier
        # background_storage en coupant l'extension en question)
        name_list_c = [
            path[:-5]
            for path in os.listdir(ressource_directory + "pose_configs")
            if path.find(".conf") > -1
        ]
        # Tenter de charger tous les poses listées
        for pose_name in name_list_c:
            self.pose_dict[pose_name] = Pose(self,
                                             ressource_directory,
                                             pose_name,
                                             force_conf_generation=False)
            if verbose:
                print("Loading pose", pose_name, "from config; succès :",
                      self.pose_dict[pose_name].valide)

        # ajouter les nom des fichers .png si l'option est activée, en évitant les doublons
        if load_all_images:
            name_list_i = [
                path[:-4] for path in os.listdir(ressource_directory +
                                                 "silhouette_storage")
                if path.find(".png") > -1 and not (path[:-4] in name_list_c)
            ]
            # Tenter de charger tous les fond listées en générant toujours les config
            for pose_name in name_list_i:
                self.pose_dict[pose_name] = Pose(self,
                                                 ressource_directory,
                                                 pose_name,
                                                 except_if_inexistant=False,
                                                 force_conf_generation=True)
                if verbose:
                    print("Loading background", pose_name,
                          "from image; succès :",
                          self.pose_dict[pose_name].valide)
        # ajout de l'image vide
        self.pose_dict[""] = Pose(self,
                                  ressource_directory,
                                  None,
                                  except_if_inexistant=True,
                                  force_conf_generation=False)
        if filter_valid:
            r_list = []
            for pose_name in self.pose_dict.keys():
                if not self.pose_dict[pose_name].valide:
                    r_list.append(pose_name)
            for r_pose_name in r_list:
                self.pose_dict.pop(r_pose_name, None)

        if dev_mode:
            print("OK")

    def set_poses(self, pose_names):
        """Set la pose affichée à l'écran enla designant par son nom"""
        self.current_silhouette = ()
        for pose_name in pose_names:
            if pose_name in self.pose_dict.keys():
                self.current_silhouette = self.current_silhouette + \
                                          (self.pose_dict[pose_name].get_silhouette(),)
            else:
                print("Warning: Set_Pose d'une pose inconnue :", pose_name)
        self.colors = list(self.default_colors)
        self.update()

    def paintEvent(self, *args):
        #TODO OPTIMISE FOR MULTIPLE REPETITIVE CALL
        super().paintEvent(*args)
        if self.current_silhouette is not None:
            # Génération du QPainter
            print("update started")
            painter = QPainter(self)
            # Effacer la pose précédente
            painter.eraseRect(self.rect())

            # get x axis coordonate of the center of the player 1st on the left
            left_center = self.player_rect.left(
            ) + 0.5 * self.player_rect.width() - self.player_pixel_spacing * (
                len(self.current_silhouette) - 1) * 0.5

            n = len(self.current_silhouette)
            for k in random.sample(range(n), n):
                vertical_random = self.vertical_random_ratio * self.pose_hauteur * random.random(
                )
                new_pixmap = QPixmap(self.pose_largeur, self.pose_hauteur)
                new_pixmap.fill(self.colors[k])
                new_pixmap.setMask(self.current_silhouette[k].pixmap.scaled(
                    self.pose_largeur, self.pose_hauteur).mask())
                painter.drawPixmap(
                    int(left_center + k * self.player_pixel_spacing -
                        (self.pose_largeur * 0.5)),
                    self.player_rect.top() + vertical_random,
                    self.pose_largeur, self.pose_hauteur, new_pixmap)
                #self.setPixmap(silhouette.sil_pixmap.scaled(self.width(), self.height(), Qt.KeepAspectRatio))

    def keyPressEvent(self, e):
        self.key_press_event_callback(e)
Example #54
0
class WebPage(QObject):
    javaScriptAlertSent = pyqtSignal(str)
    javaScriptConsoleMessageSent = pyqtSignal(str, int, str)
    loadStarted = pyqtSignal()
    loadFinished = pyqtSignal(str)
    resourceReceived = pyqtSignal('QVariantMap')
    resourceRequested = pyqtSignal('QVariantMap')

    def __init__(self, parent=None):
        QObject.__init__(self, parent)

        # variable declarations
        self.m_paperSize = {}
        self.m_clipRect = QRect()
        self.m_libraryPath = ''

        self.setObjectName('WebPage')
        self.m_webPage = CustomPage(self)
        self.m_mainFrame = self.m_webPage.mainFrame()

        self.m_webPage.loadStarted.connect(self.loadStarted)
        self.m_webPage.loadFinished.connect(self.finish)

        # Start with transparent background
        palette = self.m_webPage.palette()
        palette.setBrush(QPalette.Base, Qt.transparent)
        self.m_webPage.setPalette(palette)

        # Page size does not need to take scrollbars into account
        self.m_webPage.mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
        self.m_webPage.mainFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)

        self.m_webPage.settings().setAttribute(QWebSettings.OfflineStorageDatabaseEnabled, True)
        self.m_webPage.settings().setOfflineStoragePath(QDesktopServices.storageLocation(QDesktopServices.DataLocation))
        self.m_webPage.settings().setAttribute(QWebSettings.LocalStorageDatabaseEnabled, True)
        self.m_webPage.settings().setAttribute(QWebSettings.OfflineWebApplicationCacheEnabled, True)
        self.m_webPage.settings().setOfflineWebApplicationCachePath(QDesktopServices.storageLocation(QDesktopServices.DataLocation))
        self.m_webPage.settings().setAttribute(QWebSettings.FrameFlatteningEnabled, True)
        self.m_webPage.settings().setAttribute(QWebSettings.LocalStorageEnabled, True)
        self.m_webPage.settings().setLocalStoragePath(QDesktopServices.storageLocation(QDesktopServices.DataLocation))

        # Ensure we have a document.body.
        self.m_webPage.mainFrame().setHtml('<html><body></body></html>')

        self.m_webPage.setViewportSize(QSize(400, 300))

        do_action('WebPageInit')

    def applySettings(self, defaults):
        opt = self.m_webPage.settings()

        opt.setAttribute(QWebSettings.AutoLoadImages, defaults['loadImages'])
        opt.setAttribute(QWebSettings.PluginsEnabled, defaults['loadPlugins'])
        opt.setAttribute(QWebSettings.LocalContentCanAccessRemoteUrls, defaults['localAccessRemote'])
        if 'userAgent' in defaults:
            self.m_webPage.m_userAgent = defaults['userAgent']

    def finish(self, ok):
        status = 'success' if ok else 'fail'
        self.loadFinished.emit(status)

    def mainFrame(self):
        return self.m_mainFrame

    def renderImage(self):
        viewportSize = self.m_webPage.viewportSize()
        frameRect = QRect(QPoint(0, 0), viewportSize)
        if not self.m_clipRect.isEmpty():
            frameRect = self.m_clipRect

        if self.m_webPage.scrollPosition:
            self.m_webPage.mainFrame().\
                setScrollPosition(QPoint(self.m_webPage.scrollPosition.x(),
                                         self.m_webPage.scrollPosition.y() ))

        image = QImage(frameRect.size(), QImage.Format_ARGB32)
        image.fill(qRgba(255, 255, 255, 0))

        painter = QPainter()

        # We use tiling approach to work-around Qt software rasterizer bug
        # when dealing with very large paint device.
        # See http://code.google.com/p/phantomjs/issues/detail?id=54.
        tileSize = 4096
        htiles = (image.width() + tileSize - 1) / tileSize
        vtiles = (image.height() + tileSize - 1) / tileSize
        for x in range(htiles):
            for y in range(vtiles):
                tileBuffer = QImage(tileSize, tileSize, QImage.Format_ARGB32)
                tileBuffer.fill(qRgba(255, 255, 255, 0))

                # Render the web page onto the small tile first
                painter.begin(tileBuffer)
                painter.setRenderHint(QPainter.Antialiasing, True)
                painter.setRenderHint(QPainter.TextAntialiasing, True)
                painter.setRenderHint(QPainter.SmoothPixmapTransform, True)
                painter.translate(-frameRect.left(), -frameRect.top())
                painter.translate(-x * tileSize, -y * tileSize)
                self.m_mainFrame.render(painter, QRegion(frameRect))
                painter.end()

                # Copy the tile to the main buffer
                painter.begin(image)
                painter.setCompositionMode(QPainter.CompositionMode_Source)
                painter.drawImage(x * tileSize, y * tileSize, tileBuffer)
                painter.end()

        self.m_webPage.setViewportSize(viewportSize)
        return image

    def renderPdf(self, fileName):
        p = QPrinter()
        p.setOutputFormat(QPrinter.PdfFormat)
        p.setOutputFileName(fileName)
        p.setResolution(pdf_dpi)
        paperSize = self.m_paperSize

        if not len(paperSize):
            pageSize = QSize(self.m_webPage.mainFrame().contentsSize())
            paperSize['width'] = str(pageSize.width()) + 'px'
            paperSize['height'] = str(pageSize.height()) + 'px'
            paperSize['border'] = '0px'

        if paperSize.get('width') and paperSize.get('height'):
            sizePt = QSizeF(ceil(self.stringToPointSize(paperSize['width'])),
                            ceil(self.stringToPointSize(paperSize['height'])))
            p.setPaperSize(sizePt, QPrinter.Point)
        elif 'format' in paperSize:
            orientation = QPrinter.Landscape if paperSize.get('orientation') and paperSize['orientation'].lower() == 'landscape' else QPrinter.Portrait
            orientation = QPrinter.Orientation(orientation)
            p.setOrientation(orientation)

            formats = {
                'A0': QPrinter.A0,
                'A1': QPrinter.A1,
                'A2': QPrinter.A2,
                'A3': QPrinter.A3,
                'A4': QPrinter.A4,
                'A5': QPrinter.A5,
                'A6': QPrinter.A6,
                'A7': QPrinter.A7,
                'A8': QPrinter.A8,
                'A9': QPrinter.A9,
                'B0': QPrinter.B0,
                'B1': QPrinter.B1,
                'B2': QPrinter.B2,
                'B3': QPrinter.B3,
                'B4': QPrinter.B4,
                'B5': QPrinter.B5,
                'B6': QPrinter.B6,
                'B7': QPrinter.B7,
                'B8': QPrinter.B8,
                'B9': QPrinter.B9,
                'B10': QPrinter.B10,
                'C5E': QPrinter.C5E,
                'Comm10E': QPrinter.Comm10E,
                'DLE': QPrinter.DLE,
                'Executive': QPrinter.Executive,
                'Folio': QPrinter.Folio,
                'Ledger': QPrinter.Ledger,
                'Legal': QPrinter.Legal,
                'Letter': QPrinter.Letter,
                'Tabloid': QPrinter.Tabloid
            }

            p.setPaperSize(QPrinter.A4) # fallback
            for format, size in formats.items():
                if format.lower() == paperSize['format'].lower():
                    p.setPaperSize(size)
                    break
        else:
            return False

        border = floor(self.stringToPointSize(paperSize['border'])) if paperSize.get('border') else 0
        p.setPageMargins(border, border, border, border, QPrinter.Point)

        self.m_webPage.mainFrame().print_(p)
        return True

    def setNetworkAccessManager(self, networkAccessManager):
        self.m_webPage.setNetworkAccessManager(networkAccessManager)
        networkAccessManager.resourceRequested.connect(self.resourceRequested)
        networkAccessManager.resourceReceived.connect(self.resourceReceived)

    def stringToPointSize(self, string):
        units = (
            ('mm', 72 / 25.4),
            ('cm', 72 / 2.54),
            ('in', 72.0),
            ('px', 72.0 / pdf_dpi / 2.54),
            ('', 72.0 / pdf_dpi / 2.54)
        )

        for unit, format in units:
            if string.endswith(unit):
                value = string.rstrip(unit)
                return float(value) * format
        return 0

    def userAgent(self):
        return self.m_webPage.m_userAgent

    ##
    # Properties and methods exposed to JavaScript
    ##

    @pyqtSlot(str)
    def _appendScriptElement(self, scriptUrl):
        self.m_mainFrame.evaluateJavaScript('''
            var el = document.createElement('script');
            el.onload = function() { alert('%(scriptUrl)s'); };
            el.src = '%(scriptUrl)s';
            document.body.appendChild(el);
        ''' % {'scriptUrl': scriptUrl})

    @pyqtProperty('QVariantMap')
    def clipRect(self):
        result = {
            'width': self.m_clipRect.width(),
            'height': self.m_clipRect.height(),
            'top': self.m_clipRect.top(),
            'left': self.m_clipRect.left()
        }
        return result

    @clipRect.setter
    def clipRect(self, size):
        sizes = {'width': 0, 'height': 0, 'top': 0, 'left': 0}
        for item in sizes.keys():
            try:
                sizes[item] = int(size[item])
                if sizes[item] < 0:
                    if item not in ('top', 'left'):
                        sizes[item] = 0
            except (KeyError, ValueError):
                sizes[item] = self.clipRect[item]

        self.m_clipRect = QRect(sizes['left'], sizes['top'], sizes['width'], sizes['height'])

    @pyqtProperty(str)
    def content(self):
        return self.m_mainFrame.toHtml()

    @content.setter
    def content(self, content):
        self.m_mainFrame.setHtml(content)

    @pyqtSlot(str, result='QVariant')
    def evaluate(self, code):
        function = '(%s)()' % code
        return self.m_mainFrame.evaluateJavaScript(function)

    @pyqtSlot(str, result=bool)
    def injectJs(self, filePath):
        return injectJsInFrame(filePath, self.m_libraryPath, self.m_mainFrame)

    @pyqtSlot(str, str, 'QVariantMap')
    @pyqtSlot(str, 'QVariantMap', 'QVariantMap')
    def openUrl(self, address, op, settings):
        operation = op
        body = QByteArray()

        self.applySettings(settings)
        self.m_webPage.triggerAction(QWebPage.Stop)

        if type(op) is dict:
            operation = op.get('operation')
            body = QByteArray(op.get('data', ''))

        if operation == '':
            operation = 'get'

        networkOp = QNetworkAccessManager.CustomOperation
        operation = operation.lower()
        if operation == 'get':
            networkOp = QNetworkAccessManager.GetOperation
        elif operation == 'head':
            networkOp = QNetworkAccessManager.HeadOperation
        elif operation == 'put':
            networkOp = QNetworkAccessManager.PutOperation
        elif operation == 'post':
            networkOp = QNetworkAccessManager.PostOperation
        elif operation == 'delete':
            networkOp = QNetworkAccessManager.DeleteOperation

        if networkOp == QNetworkAccessManager.CustomOperation:
            self.m_mainFrame.evaluateJavaScript('console.error("Unknown network operation: %s");' % operation)
            return

        self.m_mainFrame.load(QNetworkRequest(QUrl(address)), networkOp, body)

    @pyqtProperty('QVariantMap')
    def paperSize(self):
        return self.m_paperSize

    @paperSize.setter
    def paperSize(self, size):
        self.m_paperSize = size

    @pyqtSlot(str, result=bool)
    def render(self, fileName):
        if self.m_mainFrame.contentsSize() == '':
            return False

        fileInfo = QFileInfo(fileName)
        path = QDir()
        path.mkpath(fileInfo.absolutePath())

        if fileName.lower().endswith('.pdf'):
            return self.renderPdf(fileName)

        image = self.renderImage()

        return image.save(fileName)

    @pyqtProperty(str)
    def libraryPath(self):
        return self.m_libraryPath

    @libraryPath.setter
    def libraryPath(self, dirPath):
        self.m_libraryPath = dirPath

    @pyqtSlot(str, str)
    def uploadFile(self, selector, fileName):
        el = self.m_mainFrame.findFirstElement(selector)
        if el.isNull():
            return

        self.m_webPage.m_uploadFile = fileName
        el.evaluateJavaScript('''
            (function (el) {
                var ev = document.createEvent('MouseEvents');
                ev.initEvent('click', true, true);
                el.dispatchEvent(ev);
            })(this)
        ''')

    @pyqtProperty('QVariantMap')
    def viewportSize(self):
        size = self.m_webPage.viewportSize()
        result = {
            'width': size.width(),
            'height': size.height()
        }
        return result

    @viewportSize.setter
    def viewportSize(self, size):
        sizes = {'width': 0, 'height': 0}
        for item in sizes.keys():
            try:
                sizes[item] = int(size[item])
                if sizes[item] < 0:
                    sizes[item] = 0
            except (KeyError, ValueError):
                sizes[item] = self.viewportSize[item]

        self.m_webPage.setViewportSize(QSize(sizes['width'], sizes['height']))

    @pyqtProperty('QVariantMap')
    def scrollPosition(self):
        scroll = self.m_webPage.scrollPosition
        result = {
            'left': scroll.x(),
            'top': scroll.y()
        }
        return result

    @scrollPosition.setter
    def scrollPosition(self, size):
        names = ('left', 'top')
        for item in names:
            try:
                globals()[item] = int(size[item])
                if globals()[item] < 0:
                    globals()[item] = 0
            except KeyError:
                globals()[item] = getattr(self.m_webPage.scrollPosition, item)()
        self.m_webPage.scrollPosition = QPoint(left, top)

    do_action('WebPage')
Example #55
0
    def __paintEventNoStyle(self):
        p = QPainter(self)
        opt = QStyleOptionToolButton()
        self.initStyleOption(opt)

        fm = QFontMetrics(opt.font)
        palette = opt.palette

        # highlight brush is used as the background for the icon and background
        # when the tab is expanded and as mouse hover color (lighter).
        brush_highlight = palette.highlight()
        if opt.state & QStyle.State_Sunken:
            # State 'down' pressed during a mouse press (slightly darker).
            background_brush = brush_darker(brush_highlight, 110)
        elif opt.state & QStyle.State_MouseOver:
            background_brush = brush_darker(brush_highlight, 95)
        elif opt.state & QStyle.State_On:
            background_brush = brush_highlight
        else:
            # The default button brush.
            background_brush = palette.button()

        rect = opt.rect
        icon = opt.icon
        icon_size = opt.iconSize

        # TODO: add shift for pressed as set by the style (PM_ButtonShift...)

        pm = None
        if not icon.isNull():
            if opt.state & QStyle.State_Enabled:
                mode = QIcon.Normal
            else:
                mode = QIcon.Disabled

            pm = opt.icon.pixmap(
                rect.size().boundedTo(icon_size), mode,
                QIcon.On if opt.state & QStyle.State_On else QIcon.Off)

        icon_area_rect = QRect(rect)
        icon_area_rect.setRight(int(icon_area_rect.height() * 1.26))

        text_rect = QRect(rect)
        text_rect.setLeft(icon_area_rect.right() + 10)

        # Background  (TODO: Should the tab button have native
        # toolbutton shape, drawn using PE_PanelButtonTool or even
        # QToolBox tab shape)

        # Default outline pen
        pen = QPen(palette.color(QPalette.Mid))

        p.save()
        p.setPen(Qt.NoPen)
        p.setBrush(QBrush(background_brush))
        p.drawRect(rect)

        # Draw the background behind the icon if the background_brush
        # is different.
        if not opt.state & QStyle.State_On:
            p.setBrush(brush_highlight)
            p.drawRect(icon_area_rect)
            # Line between the icon and text
            p.setPen(pen)
            p.drawLine(icon_area_rect.topRight(), icon_area_rect.bottomRight())

        if opt.state & QStyle.State_HasFocus:
            # Set the focus frame pen and draw the border
            pen = QPen(QColor(FOCUS_OUTLINE_COLOR))
            p.setPen(pen)
            p.setBrush(Qt.NoBrush)
            # Adjust for pen
            rect = rect.adjusted(0, 0, -1, -1)
            p.drawRect(rect)

        else:
            p.setPen(pen)
            # Draw the top/bottom border
            if self.position == QStyleOptionToolBoxV2.OnlyOneTab or \
                    self.position == QStyleOptionToolBoxV2.Beginning or \
                    self.selected & \
                        QStyleOptionToolBoxV2.PreviousIsSelected:

                p.drawLine(rect.topLeft(), rect.topRight())

            p.drawLine(rect.bottomLeft(), rect.bottomRight())

        p.restore()

        p.save()
        text = fm.elidedText(opt.text, Qt.ElideRight, text_rect.width())
        p.setPen(QPen(palette.color(QPalette.ButtonText)))
        p.setFont(opt.font)

        p.drawText(text_rect,
                   int(Qt.AlignVCenter | Qt.AlignLeft) | \
                   int(Qt.TextSingleLine),
                   text)
        if pm:
            pm_rect = QRect(QPoint(0, 0), pm.size())
            centered_rect = QRect(pm_rect)
            centered_rect.moveCenter(icon_area_rect.center())
            p.drawPixmap(centered_rect, pm, pm_rect)
        p.restore()
Example #56
0
class Surface(QWidget):
    
    rightClicked = pyqtSignal(QPoint)
    linkClicked = pyqtSignal(QEvent, page.Page, popplerqt4.Poppler.Link)
    linkHovered = pyqtSignal(page.Page, popplerqt4.Poppler.Link)
    linkLeft = pyqtSignal()
    linkHelpRequested = pyqtSignal(QPoint, page.Page, popplerqt4.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)
        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.setGeometry(rect)
        self._rubberBand.setVisible(bool(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 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 = weakref.WeakKeyDictionary()
        for page, areas in itertools.groupby(sorted(areas), lambda a: a[0]):
            d[page] = list(area[1] for area in areas)
        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, popplerqt4.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 emite 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)
        self._rubberBand.setGeometry(self._selectionRect.normalized())
        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)
Example #57
-37
 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)) + "%")