Exemple #1
0
    def __updateGeometry(self):
        """
        Update the shadow geometry to fit the widget's changed
        geometry.

        """
        widget = self.__widget
        parent = self.__widgetParent
        radius = self.radius_
        pos = widget.pos()
        if parent != widget.parentWidget():
            pos = widget.parentWidget().mapTo(parent, pos)

        geom = QRect(pos, widget.size())
        geom.adjust(-radius, -radius, radius, radius)
        if geom != self.geometry():
            self.setGeometry(geom)

        # Set the widget mask (punch a hole through to the `widget` instance.
        rect = self.rect()

        mask = QRegion(rect)
        transparent = QRegion(rect.adjusted(radius, radius, -radius, -radius))

        mask = mask.subtracted(transparent)
        self.setMask(mask)
Exemple #2
0
    def removeTab(self, index):
        """
        Remove a tab at `index`.
        """
        if index >= 0 and index < self.count():
            tab = self.__tabs.pop(index)
            layout_index = self.layout().indexOf(tab.button)
            if layout_index != -1:
                self.layout().takeAt(layout_index)

            self.__group.removeButton(tab.button)

            tab.button.removeEventFilter(self)

            if tab.button is self.__sloppyButton:
                self.__sloppyButton = None
                self.__sloppyRegion = QRegion()

            tab.button.deleteLater()
            tab.button.setParent(None)

            if self.currentIndex() == index:
                if self.count():
                    self.setCurrentIndex(max(index - 1, 0))
                else:
                    self.setCurrentIndex(-1)
    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())
            )
Exemple #4
0
    def paintEvent(self, e):
        """ 
        Overload the standard paintEvent function
        """

        #p = QPainter(self.graphicsView)                         ## our painter
        p = QPainter(self)  ## our painter
        #r1 = QRegion ( QRect(100,100,200,80), QRegion.Ellipse() )
        r1 = QRegion(QRect(self.x, 10, 5, 100))
        r2 = QRegion(QRect(100, 120, 10, 30))  ## r2 = rectangular region
        r3 = QRegion(r1.intersect(r2))  ## r3 = intersection
        #p.setClipRegion( r1 )              ## set clip region
        self.drawPoints(p)  ## paint clipped graphics
    def paintEvent(self, e):
        """ 
        Overload the standard paintEvent function
        """

        #p = QPainter(self.graphicsView)                         ## our painter
        p = QPainter(self)                         ## our painter
        #r1 = QRegion ( QRect(100,100,200,80), QRegion.Ellipse() )
        r1 = QRegion ( QRect(self.x,10,5,100))
        r2 = QRegion ( QRect(100,120,10,30) ) ## r2 = rectangular region
        r3 = QRegion (r1.intersect( r2 ))    ## r3 = intersection
        #p.setClipRegion( r1 )              ## set clip region
        self.drawPoints(p)          ## paint clipped graphics
Exemple #6
0
    def setCurrentIndex(self, index):
        """
        Set the current tab index.
        """
        if self.__currentIndex != index:
            self.__currentIndex = index

            self.__sloppyRegion = QRegion()
            self.__sloppyButton = None

            if index != -1:
                self.__tabs[index].button.setChecked(True)

            self.currentChanged.emit(index)
Exemple #7
0
 def _paint_widget(self, p):
     if self._widget is not None and (self.mode() == Mode.DEBUG or self.mode() == Mode.EDIT_LOGIC):
         p.setClipRect(Block.padding + 5, 5 + Block.padding, self.width() - 2 * Block.padding - 10,
                       25)
         p.translate(self.padding + 5, 5 + self.padding)
         self._widget.render(p, QPoint(), QRegion(0, 0, self.width(), 25),
                             QWidget.IgnoreMask)
Exemple #8
0
    def removeTab(self, index):
        """
        Remove a tab at `index`.
        """
        if index >= 0 and index < self.count():
            tab = self.__tabs.pop(index)
            layout_index = self.layout().indexOf(tab.button)
            if layout_index != -1:
                self.layout().takeAt(layout_index)

            self.__group.removeButton(tab.button)

            tab.button.removeEventFilter(self)

            if tab.button is self.__sloppyButton:
                self.__sloppyButton = None
                self.__sloppyRegion = QRegion()

            tab.button.deleteLater()
            tab.button.setParent(None)

            if self.currentIndex() == index:
                if self.count():
                    self.setCurrentIndex(max(index - 1, 0))
                else:
                    self.setCurrentIndex(-1)
    def __init__(self, parent=None, **kwargs):
        QWidget.__init__(self, parent, **kwargs)
        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        self.setLayout(layout)

        self.setSizePolicy(QSizePolicy.Fixed,
                           QSizePolicy.Expanding)
        self.__tabs = []

        self.__currentIndex = -1
        self.__changeOnHover = False

        self.__iconSize = QSize(26, 26)

        self.__group = QButtonGroup(self, exclusive=True)
        self.__group.buttonPressed[QAbstractButton].connect(
            self.__onButtonPressed
        )
        self.setMouseTracking(True)

        self.__sloppyButton = None
        self.__sloppyRegion = QRegion()
        self.__sloppyTimer = QTimer(self, singleShot=True)
        self.__sloppyTimer.timeout.connect(self.__onSloppyTimeout)
Exemple #10
0
 def draw(self, painter):
     src_pixmap, offset = self.sourcePixmap()
     painter.save()
     painter.setOpacity(self.transparency)
     painter.drawPixmap(offset, src_pixmap)
     painter.restore()
     
     #now find the clipping region:
     src_r = QRegion(self.sourceBoundingRect().toRect())
     effect_r = QRegion(self.boundingRect().toRect())
     
     clip_region = effect_r.subtracted(src_r)
     
     painter.save()
     painter.setClipRegion(clip_region)
     QGraphicsDropShadowEffect.draw(self, painter)
     painter.restore()
Exemple #11
0
 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()))
Exemple #12
0
    def __calcSloppyRegion(self, current):
        """
        Given a current mouse cursor position return a region of the widget
        where hover/move events should change the current tab only on a
        timeout.

        """
        p1 = current + QPoint(0, 2)
        p2 = current + QPoint(0, -2)
        p3 = self.pos() + QPoint(self.width() + 10, 0)
        p4 = self.pos() + QPoint(self.width() + 10, self.height())
        return QRegion(QPolygon([p1, p2, p3, p4]))
Exemple #13
0
    def __init__(self):
        self.snapshots = snapshots.Snapshots()
        self.config = self.snapshots.config

        if len(sys.argv) > 1:
            if not self.config.set_current_profile(sys.argv[1]):
                logger.warning("Failed to change Profile_ID %s" % sys.argv[1],
                               self)

        self.qapp = qt4tools.create_qapplication(self.config.APP_NAME)

        import icon
        self.icon = icon
        self.qapp.setWindowIcon(icon.BIT_LOGO)

        self.status_icon = QSystemTrayIcon(icon.BIT_LOGO)
        #self.status_icon.actionCollection().clear()
        self.contextMenu = QMenu()

        self.menuProfileName = self.contextMenu.addAction(
            _('Profile: "%s"') % self.config.get_profile_name())
        qt4tools.set_font_bold(self.menuProfileName)
        self.contextMenu.addSeparator()

        self.menuStatusMessage = self.contextMenu.addAction(_('Done'))
        self.menuProgress = self.contextMenu.addAction('')
        self.menuProgress.setVisible(False)
        self.contextMenu.addSeparator()
        self.startBIT = self.contextMenu.addAction(icon.BIT_LOGO,
                                                   _('Start BackInTime'))
        QObject.connect(self.startBIT, SIGNAL('triggered()'), self.onStartBIT)
        self.status_icon.setContextMenu(self.contextMenu)

        self.pixmap = icon.BIT_LOGO.pixmap(24)
        self.progressBar = QProgressBar()
        self.progressBar.setMinimum(0)
        self.progressBar.setMaximum(100)
        self.progressBar.setValue(0)
        self.progressBar.setTextVisible(False)
        self.progressBar.resize(24, 6)
        self.progressBar.render(self.pixmap,
                                sourceRegion=QRegion(0, -14, 24, 6),
                                flags=QWidget.RenderFlags(
                                    QWidget.DrawChildren))

        self.first_error = self.config.is_notify_enabled()
        self.popup = None
        self.last_message = None

        self.timer = QTimer()
        QObject.connect(self.timer, SIGNAL('timeout()'), self.update_info)

        self.ppid = os.getppid()
    def setCurrentIndex(self, index):
        """
        Set the current tab index.
        """
        if self.__currentIndex != index:
            self.__currentIndex = index

            self.__sloppyRegion = QRegion()
            self.__sloppyButton = None

            if index != -1:
                self.__tabs[index].button.setChecked(True)

            self.currentChanged.emit(index)
Exemple #15
0
 def rubberBandRegion(self, rect):
     viewport = self.viewport()
     mask = QStyleHintReturnMask()
     option = QStyleOptionRubberBand()
     option.initFrom(viewport)
     option.rect = rect
     option.opaque = False
     option.shape = QRubberBand.Rectangle
     tmp = QRegion()
     tmp += rect
     if viewport.style().styleHint(QStyle.SH_RubberBand_Mask, option,
                                   viewport, mask):
         tmp &= mask.region
     return tmp
Exemple #16
0
    def __init__(self, parent=None, **kwargs):
        QWidget.__init__(self, parent, **kwargs)
        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        self.setLayout(layout)

        self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)
        self.__tabs = []

        self.__currentIndex = -1
        self.__changeOnHover = False

        self.__iconSize = QSize(26, 26)

        self.__group = QButtonGroup(self, exclusive=True)
        self.__group.buttonPressed[QAbstractButton].connect(
            self.__onButtonPressed)
        self.setMouseTracking(True)

        self.__sloppyButton = None
        self.__sloppyRegion = QRegion()
        self.__sloppyTimer = QTimer(self, singleShot=True)
        self.__sloppyTimer.timeout.connect(self.__onSloppyTimeout)
Exemple #17
0
def autoCropRect(image):
    """Returns a QRect specifying the contents of the QImage.
    
    Edges of the image are trimmed if they have the same color.
    
    """
    # pick the color at most of the corners
    colors = collections.defaultdict(int)
    w, h = image.width(), image.height()
    for x, y in (0, 0), (w - 1, 0), (w - 1, h - 1), (0, h - 1):
        colors[image.pixel(x, y)] += 1
    most = max(colors, key=colors.get)
    # let Qt do the masking work
    mask = image.createMaskFromColor(most)
    return QRegion(QBitmap.fromImage(mask)).boundingRect()
    def visualRegionForSelection(self, selection):
        print "visualRegionForSelection"

        ranges = selection.count()

        if (ranges == 0):
            return QRect()

        region = QRegion()
        # for (int i = 0; i < ranges; ++i)
        #         QItemSelectionRange range = selection.at(i);
        #         for (int row = range.top(); row <= range.bottom(); ++row)
        #                 for (int col = range.left(); col <= range.right(); ++col)
        #                         QModelIndex index = model()->index(row, col, rootIndex());
        #                         region += visualRect(index);
        return region
Exemple #19
0
    def renderImage(self):
        contentsSize = self.m_mainFrame.contentsSize()
        contentsSize -= QSize(self.m_scrollPosition.x(), self.m_scrollPosition.y())
        frameRect = QRect(QPoint(0, 0), contentsSize)
        if not self.m_clipRect.isEmpty():
            frameRect = self.m_clipRect

        viewportSize = self.m_webPage.viewportSize()
        self.m_webPage.setViewportSize(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
Exemple #20
0
    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)
Exemple #21
0
    def update_info(self):
        if not tools.is_process_alive(self.ppid):
            self.prepare_exit()
            self.qapp.exit(0)
            return

        message = self.snapshots.get_take_snapshot_message()
        if message is None and self.last_message is None:
            message = (0, _('Working...'))

        if not message is None:
            if message != self.last_message:
                self.last_message = message
                self.menuStatusMessage.setText('\n'.join(tools.wrap_line(self.last_message[1],\
                                                                         size = 80,\
                                                                         delimiters = '',\
                                                                         new_line_indicator = '') \
                                                                        ))
                self.status_icon.setToolTip(self.last_message[1])

        pg = progress.ProgressFile(self.config)
        if pg.isFileReadable():
            pg.load()
            percent = pg.get_int_value('percent')
            if percent != self.progressBar.value():
                self.progressBar.setValue(percent)
                self.progressBar.render(self.pixmap,
                                        sourceRegion=QRegion(0, -14, 24, 6),
                                        flags=QWidget.RenderFlags(
                                            QWidget.DrawChildren))
                self.status_icon.setIcon(QIcon(self.pixmap))

            self.menuProgress.setText(' | '.join(self.getMenuProgress(pg)))
            self.menuProgress.setVisible(True)
        else:
            self.status_icon.setIcon(self.icon.BIT_LOGO)
            self.menuProgress.setVisible(False)
Exemple #22
0
    def paintEvent(self, ev):
        color = self.palette().color(QPalette.Highlight)
        painter = QPainter(self)

        # Filled rectangle.
        painter.setClipRect(self.rect())
        color.setAlpha(50)
        painter.fillRect(self.rect().adjusted(2, 2, -2, -2), color)

        # Thin rectangle outside.
        color.setAlpha(150)
        painter.setPen(color)
        painter.drawRect(self.rect().adjusted(0, 0, -1, -1))

        # Pseudo-handles at the corners and sides
        color.setAlpha(100)
        pen = QPen(color)
        pen.setWidth(8)
        painter.setPen(pen)
        painter.setBackgroundMode(Qt.OpaqueMode)
        # Clip at 4 corners
        region = QRegion(QRect(0, 0, 20, 20))
        region += QRect(self.rect().width() - 20, 0, 20, 20)
        region += QRect(self.rect().width() - 20,
                        self.rect().height() - 20, 20, 20)
        region += QRect(0, self.rect().height() - 20, 20, 20)
        # Clip middles
        region += QRect(0,
                        self.rect().height() / 2 - 10,
                        self.rect().width(), 20)
        region += QRect(self.rect().width() / 2 - 10, 0, 20,
                        self.rect().height())

        # Draw thicker rectangles, clipped at corners and sides.
        painter.setClipRegion(region)
        painter.drawRect(self.rect())
Exemple #23
0
    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()))
Exemple #24
0
def _render_qwebpage_tiled(web_page, logger,
                           web_rect, render_rect, canvas_size):
    """
    Render web page tile-by-tile.

    This function works around bugs in QPaintEngine that occur when render_rect
    is larger than 32k pixels in either dimension.

    """
    # One bug is worked around by rendering the page one tile at a time onto a
    # small-ish temporary image.  The magic happens in viewport-window
    # transformation: painter viewport is moved appropriately so that rendering
    # region is overlayed onto a temporary "render" image which is then pasted
    # into the resulting one.
    #
    # The other bug manifests itself when you do painter.drawImage when pasting
    # the rendered tiles.  Once you reach 32'768 along either dimension all of
    # a sudden drawImage simply stops drawing anything.  This is a known
    # limitation of Qt painting system where coordinates are signed short ints.
    # The simplest workaround that comes to mind is to use pillow for pasting.
    tile_conf = _calculate_tiling(
        to_paint=render_rect.intersected(QRect(QPoint(0, 0), canvas_size)))

    canvas = Image.new('RGBA', _qsize_to_tuple(canvas_size))
    ratio = render_rect.width() / float(web_rect.width())
    tile_qimage = QImage(tile_conf['tile_size'], QImage.Format_ARGB32)
    painter = QPainter(tile_qimage)
    try:
        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.setRenderHint(QPainter.TextAntialiasing, True)
        painter.setRenderHint(QPainter.SmoothPixmapTransform, True)
        painter.setWindow(web_rect)
        # painter.setViewport here seems superfluous (actual viewport is being
        # set inside the loop below), but it is not.  For some reason, if
        # viewport is reset after setClipRect, clipping rectangle is adjusted,
        # which is not what we want.
        painter.setViewport(render_rect)
        # painter.setClipRect(web_rect)
        for i in xrange(tile_conf['horizontal_count']):
            left = i * tile_qimage.width()
            for j in xrange(tile_conf['vertical_count']):
                top = j * tile_qimage.height()
                painter.setViewport(render_rect.translated(-left, -top))
                logger.log("Rendering with viewport=%s"
                           % painter.viewport(), min_level=2)

                clip_rect = QRect(
                    QPoint(floor(left / ratio),
                           floor(top / ratio)),
                    QPoint(ceil((left + tile_qimage.width()) / ratio),
                           ceil((top + tile_qimage.height()) / ratio)))
                web_page.mainFrame().render(painter, QRegion(clip_rect))
                tile_image = qimage_to_pil_image(tile_qimage)

                # If this is the bottommost tile, its bottom may have stuff
                # left over from rendering the previous tile.  Make sure these
                # leftovers don't garble the bottom of the canvas which can be
                # larger than render_rect because of "height=" option.
                rendered_vsize = min(render_rect.height() - top,
                                     tile_qimage.height())
                if rendered_vsize < tile_qimage.height():
                    box = (0, 0, tile_qimage.width(), rendered_vsize)
                    tile_image = tile_image.crop(box)

                logger.log("Pasting rendered tile to coords: %s" %
                           ((left, top),), min_level=2)
                canvas.paste(tile_image, (left, top))
    finally:
        # It is important to end painter explicitly in python code, because
        # Python finalizer invocation order, unlike C++ destructors, is not
        # deterministic and there is a possibility of image's finalizer running
        # before painter's which may break tests and kill your cat.
        painter.end()
    return WrappedPillowImage(canvas)
class TabBarWidget(QWidget):
    """
    A tab bar widget using tool buttons as tabs.
    """
    # TODO: A uniform size box layout.

    currentChanged = Signal(int)

    def __init__(self, parent=None, **kwargs):
        QWidget.__init__(self, parent, **kwargs)
        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        self.setLayout(layout)

        self.setSizePolicy(QSizePolicy.Fixed,
                           QSizePolicy.Expanding)
        self.__tabs = []

        self.__currentIndex = -1
        self.__changeOnHover = False

        self.__iconSize = QSize(26, 26)

        self.__group = QButtonGroup(self, exclusive=True)
        self.__group.buttonPressed[QAbstractButton].connect(
            self.__onButtonPressed
        )
        self.setMouseTracking(True)

        self.__sloppyButton = None
        self.__sloppyRegion = QRegion()
        self.__sloppyTimer = QTimer(self, singleShot=True)
        self.__sloppyTimer.timeout.connect(self.__onSloppyTimeout)

    def setChangeOnHover(self, changeOnHover):
        """
        If set to ``True`` the tab widget will change the current index when
        the mouse hovers over a tab button.

        """
        if self.__changeOnHover != changeOnHover:
            self.__changeOnHover = changeOnHover

    def changeOnHover(self):
        """
        Does the current tab index follow the mouse cursor.
        """
        return self.__changeOnHover

    def count(self):
        """
        Return the number of tabs in the widget.
        """
        return len(self.__tabs)

    def addTab(self, text, icon=None, toolTip=None):
        """
        Add a new tab and return it's index.
        """
        return self.insertTab(self.count(), text, icon, toolTip)

    def insertTab(self, index, text, icon=None, toolTip=None):
        """
        Insert a tab at `index`
        """
        button = TabButton(self, objectName="tab-button")
        button.setSizePolicy(QSizePolicy.Expanding,
                             QSizePolicy.Expanding)
        button.setIconSize(self.__iconSize)
        button.setMouseTracking(True)

        self.__group.addButton(button)

        button.installEventFilter(self)

        tab = _Tab(text, icon, toolTip, button, None, None)
        self.layout().insertWidget(index, button)

        self.__tabs.insert(index, tab)
        self.__updateTab(index)

        if self.currentIndex() == -1:
            self.setCurrentIndex(0)
        return index

    def removeTab(self, index):
        """
        Remove a tab at `index`.
        """
        if index >= 0 and index < self.count():
            self.layout().takeItem(index)
            tab = self.__tabs.pop(index)
            self.__group.removeButton(tab.button)

            tab.button.removeEventFilter(self)

            if tab.button is self.__sloppyButton:
                self.__sloppyButton = None
                self.__sloppyRegion = QRegion()

            tab.button.deleteLater()

            if self.currentIndex() == index:
                if self.count():
                    self.setCurrentIndex(max(index - 1, 0))
                else:
                    self.setCurrentIndex(-1)

    def setTabIcon(self, index, icon):
        """
        Set the `icon` for tab at `index`.
        """
        self.__tabs[index] = self.__tabs[index]._replace(icon=icon)
        self.__updateTab(index)

    def setTabToolTip(self, index, toolTip):
        """
        Set `toolTip` for tab at `index`.
        """
        self.__tabs[index] = self.__tabs[index]._replace(toolTip=toolTip)
        self.__updateTab(index)

    def setTabText(self, index, text):
        """
        Set tab `text` for tab at `index`
        """
        self.__tabs[index] = self.__tabs[index]._replace(text=text)
        self.__updateTab(index)

    def setTabPalette(self, index, palette):
        """
        Set the tab button palette.
        """
        self.__tabs[index] = self.__tabs[index]._replace(palette=palette)
        self.__updateTab(index)

    def setCurrentIndex(self, index):
        """
        Set the current tab index.
        """
        if self.__currentIndex != index:
            self.__currentIndex = index

            self.__sloppyRegion = QRegion()
            self.__sloppyButton = None

            if index != -1:
                self.__tabs[index].button.setChecked(True)

            self.currentChanged.emit(index)

    def currentIndex(self):
        """
        Return the current index.
        """
        return self.__currentIndex

    def button(self, index):
        """
        Return the `TabButton` instance for index.
        """
        return self.__tabs[index].button

    def setIconSize(self, size):
        if self.__iconSize != size:
            self.__iconSize = size
            for tab in self.__tabs:
                tab.button.setIconSize(self.__iconSize)

    def __updateTab(self, index):
        """
        Update the tab button.
        """
        tab = self.__tabs[index]
        b = tab.button

        if tab.text:
            b.setText(tab.text)

        if tab.icon is not None and not tab.icon.isNull():
            b.setIcon(tab.icon)

        if tab.palette:
            b.setPalette(tab.palette)

    def __onButtonPressed(self, button):
        for i, tab in enumerate(self.__tabs):
            if tab.button is button:
                self.setCurrentIndex(i)
                break

    def __calcSloppyRegion(self, current):
        """
        Given a current mouse cursor position return a region of the widget
        where hover/move events should change the current tab only on a
        timeout.

        """
        p1 = current + QPoint(0, 2)
        p2 = current + QPoint(0, -2)
        p3 = self.pos() + QPoint(self.width()+10, 0)
        p4 = self.pos() + QPoint(self.width()+10, self.height())
        return QRegion(QPolygon([p1, p2, p3, p4]))

    def __setSloppyButton(self, button):
        """
        Set the current sloppy button (a tab button inside sloppy region)
        and reset the sloppy timeout.

        """
        if not button.isChecked():
            self.__sloppyButton = button
            delay = self.style().styleHint(QStyle.SH_Menu_SubMenuPopupDelay, None)
            # The delay timeout is the same as used by Qt in the QMenu.
            self.__sloppyTimer.start(delay)
        else:
            self.__sloppyTimer.stop()

    def __onSloppyTimeout(self):
        if self.__sloppyButton is not None:
            button = self.__sloppyButton
            self.__sloppyButton = None
            if not button.isChecked():
                index = [tab.button for tab in self.__tabs].index(button)
                self.setCurrentIndex(index)

    def eventFilter(self, receiver, event):
        if event.type() == QEvent.MouseMove and \
                isinstance(receiver, TabButton):
            pos = receiver.mapTo(self, event.pos())
            if self.__sloppyRegion.contains(pos):
                self.__setSloppyButton(receiver)
            else:
                if not receiver.isChecked():
                    index = [tab.button for tab in self.__tabs].index(receiver)
                    self.setCurrentIndex(index)
                #also update sloppy region if mouse is moved on the same icon
                self.__sloppyRegion = self.__calcSloppyRegion(pos)

        return QWidget.eventFilter(self, receiver, event)

    def leaveEvent(self, event):
        self.__sloppyButton = None
        self.__sloppyRegion = QRegion()

        return QWidget.leaveEvent(self, event)
Exemple #26
0
 def resizeEvent(self, ev):
     """Called on resize, sets our circular mask."""
     self.setMask(QRegion(self.rect(), QRegion.Ellipse))
Exemple #27
0
def _render_qwebpage_tiled(web_page, logger, viewport_size, image_size):
    tile_maxsize = defaults.TILE_MAXSIZE

    draw_width = viewport_size.width()
    draw_height = min(viewport_size.height(), image_size.height())

    # One bug is worked around by rendering the page one tile at a time onto a
    # small-ish temporary image.  The magic happens in viewport-window
    # transformation:
    #
    # - Sizes of tile painter viewport and tile painter window match
    #   webpage viewport size to avoid rescaling.
    # - Tile painter window is moved appropriately so that tile region is
    #   overlayed onto the temporary image.
    tile_hsize = min(tile_maxsize, draw_width)
    tile_vsize = min(tile_maxsize, draw_height)
    htiles = 1 + (draw_width - 1) // tile_hsize
    vtiles = 1 + (draw_height - 1) // tile_vsize
    tile_image = QImage(QSize(tile_hsize, tile_vsize), QImage.Format_ARGB32)
    ratio = viewport_size.width() / float(web_page.viewportSize().width())

    # The other bug manifests itself when you do painter.drawImage trying to
    # concatenate tiles onto a single image and once you reach 32'768 along
    # either dimension all of a sudden drawImage simply stops drawing anything.
    # The simplest workaround that comes to mind is to use pillow for pasting
    # images.
    pil_image = Image.new(mode='RGBA',
                          size=(image_size.width(), image_size.height()))

    painter = QPainter(tile_image)
    try:
        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.setRenderHint(QPainter.TextAntialiasing, True)
        painter.setRenderHint(QPainter.SmoothPixmapTransform, True)
        painter.setWindow(QRect(QPoint(0, 0), web_page.viewportSize()))
        painter_viewport = QRect(QPoint(0, 0), viewport_size)
        for i in xrange(htiles):
            for j in xrange(vtiles):
                left, top = i * tile_hsize, j * tile_vsize
                painter.setViewport(painter_viewport.translated(-left, -top))
                logger.log("Rendering with viewport=%s" % painter.viewport(),
                           min_level=2)

                clip_rect = QRect(
                    QPoint(floor(left / ratio), floor(top / ratio)),
                    QPoint(ceil((left + tile_hsize) / ratio),
                           ceil((top + tile_vsize) / ratio)))
                web_page.mainFrame().render(painter, QRegion(clip_rect))
                pil_tile_image = qimage_to_pil_image(tile_image)
                if viewport_size.height() - top < tile_vsize:
                    # If this is the last tile, make sure that the bottom of
                    # the image is not garbled: the last tile's bottom may be
                    # clipped and will then have stuff left over from rendering
                    # the previous tile.  Crop it, because the image can be
                    # taller than the viewport because of "height=" option.
                    box = (0, 0, tile_hsize, viewport_size.height() - top)
                    pil_tile_image = pil_tile_image.crop(box)

                if logger:
                    logger.log("Pasting rendered tile to coords: %s" %
                               ((left, top), ),
                               min_level=2)
                pil_image.paste(pil_tile_image, (left, top))
        # Make sure that painter.end() is invoked before destroying the
        # underlying image.
    finally:
        painter.end()
    return pil_image
Exemple #28
0
    def leaveEvent(self, event):
        self.__sloppyButton = None
        self.__sloppyRegion = QRegion()

        return QWidget.leaveEvent(self, event)
    def leaveEvent(self, event):
        self.__sloppyButton = None
        self.__sloppyRegion = QRegion()

        return QWidget.leaveEvent(self, event)
Exemple #30
0
class TabBarWidget(QWidget):
    """
    A tab bar widget using tool buttons as tabs.
    """
    # TODO: A uniform size box layout.

    currentChanged = Signal(int)

    def __init__(self, parent=None, **kwargs):
        QWidget.__init__(self, parent, **kwargs)
        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        self.setLayout(layout)

        self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)
        self.__tabs = []

        self.__currentIndex = -1
        self.__changeOnHover = False

        self.__iconSize = QSize(26, 26)

        self.__group = QButtonGroup(self, exclusive=True)
        self.__group.buttonPressed[QAbstractButton].connect(
            self.__onButtonPressed)
        self.setMouseTracking(True)

        self.__sloppyButton = None
        self.__sloppyRegion = QRegion()
        self.__sloppyTimer = QTimer(self, singleShot=True)
        self.__sloppyTimer.timeout.connect(self.__onSloppyTimeout)

    def setChangeOnHover(self, changeOnHover):
        """
        If set to ``True`` the tab widget will change the current index when
        the mouse hovers over a tab button.

        """
        if self.__changeOnHover != changeOnHover:
            self.__changeOnHover = changeOnHover

    def changeOnHover(self):
        """
        Does the current tab index follow the mouse cursor.
        """
        return self.__changeOnHover

    def count(self):
        """
        Return the number of tabs in the widget.
        """
        return len(self.__tabs)

    def addTab(self, text, icon=None, toolTip=None):
        """
        Add a new tab and return it's index.
        """
        return self.insertTab(self.count(), text, icon, toolTip)

    def insertTab(self, index, text, icon=None, toolTip=None):
        """
        Insert a tab at `index`
        """
        button = TabButton(self, objectName="tab-button")
        button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        button.setIconSize(self.__iconSize)
        button.setMouseTracking(True)

        self.__group.addButton(button)

        button.installEventFilter(self)

        tab = _Tab(text, icon, toolTip, button, None, None)
        self.layout().insertWidget(index, button)

        self.__tabs.insert(index, tab)
        self.__updateTab(index)

        if self.currentIndex() == -1:
            self.setCurrentIndex(0)
        return index

    def removeTab(self, index):
        """
        Remove a tab at `index`.
        """
        if index >= 0 and index < self.count():
            self.layout().takeItem(index)
            tab = self.__tabs.pop(index)
            self.__group.removeButton(tab.button)

            tab.button.removeEventFilter(self)

            if tab.button is self.__sloppyButton:
                self.__sloppyButton = None
                self.__sloppyRegion = QRegion()

            tab.button.deleteLater()

            if self.currentIndex() == index:
                if self.count():
                    self.setCurrentIndex(max(index - 1, 0))
                else:
                    self.setCurrentIndex(-1)

    def setTabIcon(self, index, icon):
        """
        Set the `icon` for tab at `index`.
        """
        self.__tabs[index] = self.__tabs[index]._replace(icon=icon)
        self.__updateTab(index)

    def setTabToolTip(self, index, toolTip):
        """
        Set `toolTip` for tab at `index`.
        """
        self.__tabs[index] = self.__tabs[index]._replace(toolTip=toolTip)
        self.__updateTab(index)

    def setTabText(self, index, text):
        """
        Set tab `text` for tab at `index`
        """
        self.__tabs[index] = self.__tabs[index]._replace(text=text)
        self.__updateTab(index)

    def setTabPalette(self, index, palette):
        """
        Set the tab button palette.
        """
        self.__tabs[index] = self.__tabs[index]._replace(palette=palette)
        self.__updateTab(index)

    def setCurrentIndex(self, index):
        """
        Set the current tab index.
        """
        if self.__currentIndex != index:
            self.__currentIndex = index

            self.__sloppyRegion = QRegion()
            self.__sloppyButton = None

            if index != -1:
                self.__tabs[index].button.setChecked(True)

            self.currentChanged.emit(index)

    def currentIndex(self):
        """
        Return the current index.
        """
        return self.__currentIndex

    def button(self, index):
        """
        Return the `TabButton` instance for index.
        """
        return self.__tabs[index].button

    def setIconSize(self, size):
        if self.__iconSize != size:
            self.__iconSize = size
            for tab in self.__tabs:
                tab.button.setIconSize(self.__iconSize)

    def __updateTab(self, index):
        """
        Update the tab button.
        """
        tab = self.__tabs[index]
        b = tab.button

        if tab.text:
            b.setText(tab.text)

        if tab.icon is not None and not tab.icon.isNull():
            b.setIcon(tab.icon)

        if tab.palette:
            b.setPalette(tab.palette)

    def __onButtonPressed(self, button):
        for i, tab in enumerate(self.__tabs):
            if tab.button is button:
                self.setCurrentIndex(i)
                break

    def __calcSloppyRegion(self, current):
        """
        Given a current mouse cursor position return a region of the widget
        where hover/move events should change the current tab only on a
        timeout.

        """
        p1 = current + QPoint(0, 2)
        p2 = current + QPoint(0, -2)
        p3 = self.pos() + QPoint(self.width() + 10, 0)
        p4 = self.pos() + QPoint(self.width() + 10, self.height())
        return QRegion(QPolygon([p1, p2, p3, p4]))

    def __setSloppyButton(self, button):
        """
        Set the current sloppy button (a tab button inside sloppy region)
        and reset the sloppy timeout.

        """
        if not button.isChecked():
            self.__sloppyButton = button
            delay = self.style().styleHint(QStyle.SH_Menu_SubMenuPopupDelay,
                                           None)
            # The delay timeout is the same as used by Qt in the QMenu.
            self.__sloppyTimer.start(delay)
        else:
            self.__sloppyTimer.stop()

    def __onSloppyTimeout(self):
        if self.__sloppyButton is not None:
            button = self.__sloppyButton
            self.__sloppyButton = None
            if not button.isChecked():
                index = [tab.button for tab in self.__tabs].index(button)
                self.setCurrentIndex(index)

    def eventFilter(self, receiver, event):
        if event.type() == QEvent.MouseMove and \
                isinstance(receiver, TabButton):
            pos = receiver.mapTo(self, event.pos())
            if self.__sloppyRegion.contains(pos):
                self.__setSloppyButton(receiver)
            else:
                if not receiver.isChecked():
                    index = [tab.button for tab in self.__tabs].index(receiver)
                    self.setCurrentIndex(index)
                #also update sloppy region if mouse is moved on the same icon
                self.__sloppyRegion = self.__calcSloppyRegion(pos)

        return QWidget.eventFilter(self, receiver, event)

    def leaveEvent(self, event):
        self.__sloppyButton = None
        self.__sloppyRegion = QRegion()

        return QWidget.leaveEvent(self, event)