Beispiel #1
0
    def tabDropAction(cls, pos, tabRect, allowSelect):
        if not tabRect.contains(pos):
            return cls._NoAction

        # QPoint
        c = tabRect.center()
        # QSize
        csize = QSize(tabRect.width() * 0.7, tabRect.height() * 0.7)
        center = QRect(c.x() - csize.width() // 2,
                       c.y() - csize.height() // 2, csize.width(),
                       csize.height())

        if allowSelect and center.contains(pos):
            return cls._SelectTab
        elif pos.x() < c.x():
            return cls._PrependTab
        else:
            return cls._AppendTab
Beispiel #2
0
class Declaration(QWidget):

    hyperlink_activated = pyqtSignal(object)
    context_menu_requested = pyqtSignal(object, object)

    def __init__(self, html_name, data, is_first=False, parent=None):
        QWidget.__init__(self, parent)
        self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum)
        self.data = data
        self.is_first = is_first
        self.html_name = html_name
        self.lines_for_copy = []
        self.do_layout()
        self.setMouseTracking(True)

    def do_layout(self):
        fm = self.fontMetrics()
        bounding_rect = lambda text: fm.boundingRect(0, 0, 10000, 10000, Cell.FLAGS, text)
        line_spacing = 2
        side_margin = Cell.SIDE_MARGIN
        self.rows = []
        ypos = line_spacing + (1 if self.is_first else 0)
        if 'href' in self.data:
            name = self.data['href']
            if isinstance(name, list):
                name = self.html_name
            br1 = bounding_rect(name)
            sel = self.data['selector'] or ''
            if self.data['type'] == 'inline':
                sel = 'style=""'
            br2 = bounding_rect(sel)
            self.hyperlink_rect = QRect(side_margin, ypos, br1.width(), br1.height())
            self.rows.append([
                Cell(name, self.hyperlink_rect, color_role=QPalette.Link),
                Cell(sel, QRect(br1.right() + side_margin, ypos, br2.width(), br2.height()), right_align=True)
            ])
            ypos += max(br1.height(), br2.height()) + 2 * line_spacing
            self.lines_for_copy.append(name + ' ' + sel)

        for prop in self.data['properties']:
            text = prop.name + ':\xa0'
            br1 = bounding_rect(text)
            vtext = prop.value + '\xa0' + ('!' if prop.important else '') + prop.important
            br2 = bounding_rect(vtext)
            self.rows.append([
                Cell(text, QRect(side_margin, ypos, br1.width(), br1.height()), color_role=QPalette.LinkVisited, is_overriden=prop.is_overriden),
                Cell(vtext, QRect(br1.right() + side_margin, ypos, br2.width(), br2.height()), swatch=prop.color, is_overriden=prop.is_overriden)
            ])
            self.lines_for_copy.append(text + vtext)
            if prop.is_overriden:
                self.lines_for_copy[-1] += ' [overriden]'
            ypos += max(br1.height(), br2.height()) + line_spacing
        self.lines_for_copy.append('--------------------------\n')

        self.height_hint = ypos + line_spacing
        self.width_hint = max(row[-1].rect.right() + side_margin for row in self.rows) if self.rows else 0

    def sizeHint(self):
        return QSize(self.width_hint, self.height_hint)

    def paintEvent(self, ev):
        p = QPainter(self)
        p.setClipRect(ev.rect())
        palette = self.palette()
        p.setPen(palette.color(QPalette.WindowText))
        if not self.is_first:
            p.drawLine(0, 0, self.width(), 0)
        try:
            for row in self.rows:
                for cell in row:
                    p.save()
                    try:
                        cell.draw(p, self.width(), palette)
                    finally:
                        p.restore()

        finally:
            p.end()

    def mouseMoveEvent(self, ev):
        if hasattr(self, 'hyperlink_rect'):
            pos = ev.pos()
            hovering = self.hyperlink_rect.contains(pos)
            self.update_hover(hovering)
            cursor = Qt.ArrowCursor
            for r, row in enumerate(self.rows):
                for cell in row:
                    if cell.rect.contains(pos):
                        cursor = Qt.PointingHandCursor if cell.rect is self.hyperlink_rect else Qt.IBeamCursor
                    if r == 0:
                        break
                if cursor != Qt.ArrowCursor:
                    break
            self.setCursor(cursor)
        return QWidget.mouseMoveEvent(self, ev)

    def mousePressEvent(self, ev):
        if hasattr(self, 'hyperlink_rect') and ev.button() == Qt.LeftButton:
            pos = ev.pos()
            if self.hyperlink_rect.contains(pos):
                self.emit_hyperlink_activated()
        return QWidget.mousePressEvent(self, ev)

    def emit_hyperlink_activated(self):
        dt = self.data['type']
        data = {'type':dt, 'name':self.html_name, 'syntax':'html'}
        if dt == 'inline':  # style attribute
            data['sourceline_address'] = self.data['href']
        elif dt == 'elem':  # <style> tag
            data['sourceline_address'] = self.data['href']
            data['rule_address'] = self.data['rule_address']
        else:  # stylesheet
            data['name'] = self.data['href']
            data['rule_address'] = self.data['rule_address']
            data['syntax'] = 'css'
        self.hyperlink_activated.emit(data)

    def leaveEvent(self, ev):
        self.update_hover(False)
        self.setCursor(Qt.ArrowCursor)
        return QWidget.leaveEvent(self, ev)

    def update_hover(self, hovering):
        cell = self.rows[0][0]
        if (hovering and cell.override_color is None) or (
                not hovering and cell.override_color is not None):
            cell.override_color = QColor(Qt.red) if hovering else None
            self.update()

    def contextMenuEvent(self, ev):
        self.context_menu_requested.emit(self, ev)
Beispiel #3
0
class Declaration(QWidget):

    hyperlink_activated = pyqtSignal(object)
    context_menu_requested = pyqtSignal(object, object)

    def __init__(self, html_name, data, is_first=False, parent=None):
        QWidget.__init__(self, parent)
        self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum)
        self.data = data
        self.is_first = is_first
        self.html_name = html_name
        self.lines_for_copy = []
        self.do_layout()
        self.setMouseTracking(True)

    def do_layout(self):
        fm = self.fontMetrics()
        bounding_rect = lambda text: fm.boundingRect(0, 0, 10000, 10000, Cell.
                                                     FLAGS, text)
        line_spacing = 2
        side_margin = Cell.SIDE_MARGIN
        self.rows = []
        ypos = line_spacing + (1 if self.is_first else 0)
        if 'href' in self.data:
            name = self.data['href']
            if isinstance(name, list):
                name = self.html_name
            br1 = bounding_rect(name)
            sel = self.data['selector'] or ''
            if self.data['type'] == 'inline':
                sel = 'style=""'
            br2 = bounding_rect(sel)
            self.hyperlink_rect = QRect(side_margin, ypos, br1.width(),
                                        br1.height())
            self.rows.append([
                Cell(name, self.hyperlink_rect, color_role=QPalette.Link),
                Cell(sel,
                     QRect(br1.right() + side_margin, ypos, br2.width(),
                           br2.height()),
                     right_align=True)
            ])
            ypos += max(br1.height(), br2.height()) + 2 * line_spacing
            self.lines_for_copy.append(name + ' ' + sel)

        for prop in self.data['properties']:
            text = prop.name + ':\xa0'
            br1 = bounding_rect(text)
            vtext = prop.value + '\xa0' + ('!' if prop.important else
                                           '') + prop.important
            br2 = bounding_rect(vtext)
            self.rows.append([
                Cell(text,
                     QRect(side_margin, ypos, br1.width(), br1.height()),
                     color_role=QPalette.LinkVisited,
                     is_overriden=prop.is_overriden),
                Cell(vtext,
                     QRect(br1.right() + side_margin, ypos, br2.width(),
                           br2.height()),
                     swatch=prop.color,
                     is_overriden=prop.is_overriden)
            ])
            self.lines_for_copy.append(text + vtext)
            if prop.is_overriden:
                self.lines_for_copy[-1] += ' [overriden]'
            ypos += max(br1.height(), br2.height()) + line_spacing
        self.lines_for_copy.append('--------------------------\n')

        self.height_hint = ypos + line_spacing
        self.width_hint = max(row[-1].rect.right() + side_margin
                              for row in self.rows) if self.rows else 0

    def sizeHint(self):
        return QSize(self.width_hint, self.height_hint)

    def paintEvent(self, ev):
        p = QPainter(self)
        p.setClipRect(ev.rect())
        palette = self.palette()
        p.setPen(palette.color(QPalette.WindowText))
        if not self.is_first:
            p.drawLine(0, 0, self.width(), 0)
        try:
            for row in self.rows:
                for cell in row:
                    p.save()
                    try:
                        cell.draw(p, self.width(), palette)
                    finally:
                        p.restore()

        finally:
            p.end()

    def mouseMoveEvent(self, ev):
        if hasattr(self, 'hyperlink_rect'):
            pos = ev.pos()
            hovering = self.hyperlink_rect.contains(pos)
            self.update_hover(hovering)
            cursor = Qt.ArrowCursor
            for r, row in enumerate(self.rows):
                for cell in row:
                    if cell.rect.contains(pos):
                        cursor = Qt.PointingHandCursor if cell.rect is self.hyperlink_rect else Qt.IBeamCursor
                    if r == 0:
                        break
                if cursor != Qt.ArrowCursor:
                    break
            self.setCursor(cursor)
        return QWidget.mouseMoveEvent(self, ev)

    def mousePressEvent(self, ev):
        if hasattr(self, 'hyperlink_rect') and ev.button() == Qt.LeftButton:
            pos = ev.pos()
            if self.hyperlink_rect.contains(pos):
                self.emit_hyperlink_activated()
        return QWidget.mousePressEvent(self, ev)

    def emit_hyperlink_activated(self):
        dt = self.data['type']
        data = {'type': dt, 'name': self.html_name, 'syntax': 'html'}
        if dt == 'inline':  # style attribute
            data['sourceline_address'] = self.data['href']
        elif dt == 'elem':  # <style> tag
            data['sourceline_address'] = self.data['href']
            data['rule_address'] = self.data['rule_address']
        else:  # stylesheet
            data['name'] = self.data['href']
            data['rule_address'] = self.data['rule_address']
            data['syntax'] = 'css'
        self.hyperlink_activated.emit(data)

    def leaveEvent(self, ev):
        self.update_hover(False)
        self.setCursor(Qt.ArrowCursor)
        return QWidget.leaveEvent(self, ev)

    def update_hover(self, hovering):
        cell = self.rows[0][0]
        if (hovering and cell.override_color is None) or (
                not hovering and cell.override_color is not None):
            cell.override_color = QColor(Qt.red) if hovering else None
            self.update()

    def contextMenuEvent(self, ev):
        self.context_menu_requested.emit(self, ev)
Beispiel #4
0
class TabIcon(QWidget):
    class Data:
        def __init__(self):
            self.framesCount = 0
            self.animationInterval = 0
            self.animationPixmap = QPixmap()
            self.audioPlayingPixmap = QPixmap()
            self.audioMutedPixmap = QPixmap()

    def __init__(self, parent):
        '''
        @param parent QWidget
        '''
        super().__init__(parent)
        self._tab = None  # WebTab
        self._updateTimer = None  # QTimer
        self._hideTimer = None  # QTimer
        self._sitePixmap = QPixmap()
        self._currentFrame = 0
        self._animationRunning = False
        self._audioIconDisplayed = False
        self._audioIconRect = QRect()

        self.setObjectName('tab-icon')

        self._updateTimer = QTimer(self)
        self._updateTimer.setInterval(self.data().animationInterval)
        self._updateTimer.timeout.connect(self._updateAnimationFrame)

        self._hideTimer = QTimer(self)
        self._hideTimer.setInterval(250)
        self._hideTimer.timeout.connect(self._hide)

        self.resize(16, 16)

    def setWebTab(self, tab):
        '''
        @param: tab WebTab
        '''
        self._tab = tab

        self._tab.webView().loadStarted.connect(self._showLoadingAnimation)
        #self._tab.webView().loadFinished.connect(self._hideLoadingAnimation)
        self._tab.webView().loadProgress.connect(self._hideLoadingAnimation)
        self._tab.webView().iconChanged.connect(self.updateIcon)
        self._tab.webView().backgroundActivityChanged.connect(
            lambda: self.update())

        def pageChangedCb(page):
            '''
            @param: page WebPage
            '''
            page.recentlyAudibleChanged.connect(self._updateAudioIcon)

        pageChangedCb(self._tab.webView().page())
        self._tab.webView().pageChanged.connect(pageChangedCb)

        self.updateIcon()

    def updateIcon(self):
        self._sitePixmap = self._tab.icon(True).pixmap(16)  # allowNull
        if self._sitePixmap.isNull():
            if self._tab.url().isEmpty() or self._tab.url().scheme(
            ) == const.APP_SCHEME:
                self._hide()
            else:
                self._hideTimer.start()
        else:
            self._show()
        self.update()

    _s_data = None

    def data(self):
        '''
        @return: Data
        '''
        if self._s_data is None:
            self._s_data = data = self.Data()
            data.animationInterval = 70
            data.animationPixmap = QIcon(':/icons/other/loading.png').pixmap(
                288, 16)
            data.framesCount = data.animationPixmap.width(
            ) / data.animationPixmap.height()
            data.audioPlayingPixmap = QIcon.fromTheme(
                'audio-volume-high',
                QIcon(':/icons/other/audioplaying.svg')).pixmap(16)
            data.audioMutedPixmap = QIcon.fromTheme(
                'audio-volume-muted',
                QIcon(':/icons/other/audiomuted.svg')).pixmap(16)
        return self._s_data

    # Q_SIGNALS
    resized = pyqtSignal()

    # private Q_SLOTS:
    def _showLoadingAnimation(self):
        self._currentFrame = 0
        self._updateAnimationFrame()
        self._show()

    def _hideLoadingAnimation(self, progress):
        if progress == 100:
            self._animationRunning = False
            self._updateTimer.stop()
            self.updateIcon()

    def _updateAudioIcon(self, recentlyAudible):
        if self._tab.isMuted() or recentlyAudible:
            self._audioIconDisplayed = True
            self._show()
        else:
            self._audioIconDisplayed = False
            self._hide()

        self.update()

    def _updateAnimationFrame(self):
        if not self._animationRunning:
            self._updateTimer.start()
            self._animationRunning = True

        self.update()
        self._currentFrame = (self._currentFrame + 1) % self.data().framesCount

    # private:
    def _show(self):
        if not self._shouldBeVisible():
            return

        self._hideTimer.stop()

        if self.isVisible() and self.width() == 16:
            return

        self.setFixedSize(16, max(self.minimumHeight(), 16))
        self.resized.emit()
        super().show()

    def _hide(self):
        if self._shouldBeVisible():
            return

        if self.isHidden() and self.width() == 1:
            return

        self.setFixedSize(1, max(self.minimumHeight(), 16))
        self.resized.emit()
        super().hide()

    def _shouldBeVisible(self):
        return not self._sitePixmap.isNull() or self._animationRunning or \
            self._audioIconDisplayed or (self._tab and self._tab.isPinned())

    # override
    def event(self, event):
        '''
        @param: event QEvent
        '''
        if event.type() == QEvent.ToolTip:
            # QHelpEvent
            if self._audioIconDisplayed and self._audioIconRect.contains(
                    event.pos()):
                QToolTip.showText(
                    event.globalPos(),
                    self._tab.isMuted() and _('Unmute Tab') or _('Mute Tab'),
                    self)
                event.accept()
                return True
        return super().event(event)

    # override
    def paintEvent(self, event):
        '''
        @param event QPaintEvent
        '''
        p = QPainter(self)
        p.setRenderHint(QPainter.Antialiasing)

        size = 16
        pixmapSize = round(size *
                           self.data().animationPixmap.devicePixelRatioF())

        # Center the pixmap in rect
        r = QRect(self.rect())
        r.setX((r.width() - size) / 2)
        r.setY((r.height() - size) / 2)
        r.setWidth(size)
        r.setHeight(size)

        if self._animationRunning:
            p.drawPixmap(
                r,
                self.data().animationPixmap,
                QRect(self._currentFrame * pixmapSize, 0, pixmapSize,
                      pixmapSize))
        elif self._audioIconDisplayed and not self._tab.isPinned():
            self._audioIconRect = QRect(r)
            p.drawPixmap(
                r,
                self._tab.isMuted() and self.data().audioMutedPixmap
                or self.data().audioPlayingPixmap)
        elif not self._sitePixmap.isNull():
            p.drawPixmap(r, self._sitePixmap)
        elif self._tab and self._tab.isPinned():
            p.drawPixmap(r, IconProvider.emptyWebIcon().pixmap(size))

        # Draw audio icon on top of site icon for pinned tabs
        if not self._animationRunning and self._audioIconDisplayed and self._tab.isPinned(
        ):
            s = size - 4
            r0 = QRect(self.width() - 4, 0, s, s)
            self._audioIconRect = r0
            c = self.palette().color(QPalette.Window)
            c.setAlpha(180)
            p.setPen(c)
            p.setBrush(c)
            p.drawEllipse(r)
            p.drawPixmap(
                r,
                self._tab.isMuted() and self.data().audioMutedPixmap
                or self.data().audioPlayingPixmap)

        # Draw background activity indicator
        if self._tab and self._tab.isPinned() and self._tab.webView(
        ).backgroundActivity():
            s = 5
            # Background
            r1 = QRect(self.width() - s - 2,
                       self.height() - s - 2, s + 2, s + 2)
            c1 = self.palette().color(QPalette.Window)
            c1.setAlpha(180)
            p.setPen(Qt.transparent)
            p.setBrush(c1)
            p.drawEllipse(r1)
            # Forground
            r2 = QRect(self.width() - s - 1, self.height() - s - 1, s, s)
            c2 = self.palette().color(QPalette.Text)
            p.setPen(Qt.transparent)
            p.setBrush(c2)
            p.drawEllipse(r2)

    # override
    def mousePressEvent(self, event):
        '''
        @param event QMouseEvent
        '''
        if self._audioIconDisplayed and event.button() == Qt.LeftButton and \
                self._audioIconRect.contains(event.pos()):
            self._tab.toggleMuted()
            return

        super().mousePressEvent(event)
Beispiel #5
0
class Declaration(QWidget):

    hyperlink_activated = pyqtSignal(object)

    def __init__(self, html_name, data, is_first=False, parent=None):
        QWidget.__init__(self, parent)
        self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum)
        self.data = data
        self.is_first = is_first
        self.html_name = html_name
        self.do_layout()
        self.setMouseTracking(True)

    def do_layout(self):
        fm = self.fontMetrics()
        bounding_rect = lambda text: fm.boundingRect(0, 0, 10000, 10000, Cell.FLAGS, text)
        line_spacing = 2
        side_margin = Cell.SIDE_MARGIN
        self.rows = []
        ypos = line_spacing + (1 if self.is_first else 0)
        if "href" in self.data:
            name = self.data["href"]
            if isinstance(name, list):
                name = self.html_name
            br1 = bounding_rect(name)
            sel = self.data["selector"] or ""
            if self.data["type"] == "inline":
                sel = 'style=""'
            br2 = bounding_rect(sel)
            self.hyperlink_rect = QRect(side_margin, ypos, br1.width(), br1.height())
            self.rows.append(
                [
                    Cell(name, self.hyperlink_rect, color_role=QPalette.Link),
                    Cell(sel, QRect(br1.right() + side_margin, ypos, br2.width(), br2.height()), right_align=True),
                ]
            )
            ypos += max(br1.height(), br2.height()) + 2 * line_spacing

        for prop in self.data["properties"]:
            text = prop.name + ":\xa0"
            br1 = bounding_rect(text)
            vtext = prop.value + "\xa0" + ("!" if prop.important else "") + prop.important
            br2 = bounding_rect(vtext)
            self.rows.append(
                [
                    Cell(
                        text,
                        QRect(side_margin, ypos, br1.width(), br1.height()),
                        color_role=QPalette.LinkVisited,
                        is_overriden=prop.is_overriden,
                    ),
                    Cell(
                        vtext,
                        QRect(br1.right() + side_margin, ypos, br2.width(), br2.height()),
                        swatch=prop.color,
                        is_overriden=prop.is_overriden,
                    ),
                ]
            )
            ypos += max(br1.height(), br2.height()) + line_spacing

        self.height_hint = ypos + line_spacing
        self.width_hint = max(row[-1].rect.right() + side_margin for row in self.rows) if self.rows else 0

    def sizeHint(self):
        return QSize(self.width_hint, self.height_hint)

    def paintEvent(self, ev):
        p = QPainter(self)
        p.setClipRect(ev.rect())
        palette = self.palette()
        p.setPen(palette.color(QPalette.WindowText))
        if not self.is_first:
            p.drawLine(0, 0, self.width(), 0)
        try:
            for row in self.rows:
                for cell in row:
                    p.save()
                    try:
                        cell.draw(p, self.width(), palette)
                    finally:
                        p.restore()

        finally:
            p.end()

    def mouseMoveEvent(self, ev):
        if hasattr(self, "hyperlink_rect"):
            pos = ev.pos()
            hovering = self.hyperlink_rect.contains(pos)
            self.update_hover(hovering)
            cursor = Qt.ArrowCursor
            for r, row in enumerate(self.rows):
                for cell in row:
                    if cell.rect.contains(pos):
                        cursor = Qt.PointingHandCursor if cell.rect is self.hyperlink_rect else Qt.IBeamCursor
                    if r == 0:
                        break
                if cursor != Qt.ArrowCursor:
                    break
            self.setCursor(cursor)
        return QWidget.mouseMoveEvent(self, ev)

    def mousePressEvent(self, ev):
        if hasattr(self, "hyperlink_rect"):
            pos = ev.pos()
            if self.hyperlink_rect.contains(pos):
                self.emit_hyperlink_activated()
        return QWidget.mousePressEvent(self, ev)

    def emit_hyperlink_activated(self):
        dt = self.data["type"]
        data = {"type": dt, "name": self.html_name, "syntax": "html"}
        if dt == "inline":  # style attribute
            data["sourceline_address"] = self.data["href"]
        elif dt == "elem":  # <style> tag
            data["sourceline_address"] = self.data["href"]
            data["rule_address"] = self.data["rule_address"]
        else:  # stylesheet
            data["name"] = self.data["href"]
            data["rule_address"] = self.data["rule_address"]
            data["syntax"] = "css"
        self.hyperlink_activated.emit(data)

    def leaveEvent(self, ev):
        self.update_hover(False)
        self.setCursor(Qt.ArrowCursor)
        return QWidget.leaveEvent(self, ev)

    def update_hover(self, hovering):
        cell = self.rows[0][0]
        if (hovering and cell.override_color is None) or (not hovering and cell.override_color is not None):
            cell.override_color = QColor(Qt.red) if hovering else None
            self.update()