Example #1
0
 def __init__(self, parent):
     QWidget.__init__(self, parent)
     self.layout = QTextLayout()
     self.layout.setFont(self.font())
     self.layout.setCacheEnabled(True)
     self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
     self.last_layout_rect = None
Example #2
0
 def __init__(self, parent):
     QWidget.__init__(self, parent)
     self.layout = QTextLayout()
     self.layout.setFont(self.font())
     self.layout.setCacheEnabled(True)
     self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
     self.last_layout_rect = None
Example #3
0
class Message(QWidget):

    def __init__(self, parent):
        QWidget.__init__(self, parent)
        self.layout = QTextLayout()
        self.layout.setFont(self.font())
        self.layout.setCacheEnabled(True)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        self.last_layout_rect = None

    def setText(self, text):
        self.layout.setText(text)
        self.last_layout_rect = None
        self.update()

    def sizeHint(self):
        return QSize(10, 10)

    def do_layout(self):
        ly = self.layout
        ly.beginLayout()
        w = self.width() - 5
        height = 0
        leading = self.fontMetrics().leading()
        while True:
            line = ly.createLine()
            if not line.isValid():
                break
            line.setLineWidth(w)
            height += leading
            line.setPosition(QPointF(5, height))
            height += line.height()
        ly.endLayout()

    def paintEvent(self, ev):
        if self.last_layout_rect != self.rect():
            self.do_layout()
        p = QPainter(self)
        br = self.layout.boundingRect()
        y = 0
        if br.height() < self.height():
            y = (self.height() - br.height()) / 2
        self.layout.draw(p, QPointF(0, y))
Example #4
0
class Message(QWidget):

    def __init__(self, parent):
        QWidget.__init__(self, parent)
        self.layout = QTextLayout()
        self.layout.setFont(self.font())
        self.layout.setCacheEnabled(True)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        self.last_layout_rect = None

    def setText(self, text):
        self.layout.setText(text)
        self.last_layout_rect = None
        self.update()

    def sizeHint(self):
        return QSize(10, 10)

    def do_layout(self):
        ly = self.layout
        ly.beginLayout()
        w = self.width() - 5
        height = 0
        leading = self.fontMetrics().leading()
        while True:
            line = ly.createLine()
            if not line.isValid():
                break
            line.setLineWidth(w)
            height += leading
            line.setPosition(QPointF(5, height))
            height += line.height()
        ly.endLayout()

    def paintEvent(self, ev):
        if self.last_layout_rect != self.rect():
            self.do_layout()
        p = QPainter(self)
        br = self.layout.boundingRect()
        y = 0
        if br.height() < self.height():
            y = (self.height() - br.height()) / 2
        self.layout.draw(p, QPointF(0, y))
Example #5
0
    def _refreshTextFormat(self):
        if not self._webView:
            return

        textFormat = []  # typedef QList<QTextLayout::FormatRange>
        if self._webView.url().isEmpty():
            hostName = QUrl(self.text()).host()
        else:
            hostName = self._webView.url().host()

        if hostName:
            hostPos = self.text().find(hostName)
            if hostPos > 0:
                format_ = QTextCharFormat()
                palette = self.palette()
                color = Colors.mid(palette.color(QPalette.Base),
                                   palette.color(QPalette.Text), 1, 1)
                format_.setForeground(color)

                schemePart = QTextLayout.FormatRange()
                schemePart.start = 0
                schemePart.length = hostPos
                schemePart.format = format_

                hostPart = QTextLayout.FormatRange()
                hostPart.start = hostPos
                hostPart.length = len(hostName)

                remainingPart = QTextLayout.FormatRange()
                remainingPart.start = hostPos + len(hostName)
                remainingPart.length = len(self.text()) - remainingPart.start
                remainingPart.format = format_

                textFormat.append(schemePart)
                textFormat.append(hostPart)
                textFormat.append(remainingPart)

        self.setTextFormat(textFormat)
Example #6
0
def parse_text_formatting(text):
    pos = 0
    tokens = []
    for m in re.finditer(r'</?([a-zA-Z1-6]+)/?>', text):
        q = text[pos:m.start()]
        if q:
            tokens.append((False, q))
        tokens.append((True, (m.group(1).lower(), '/' in m.group()[:2])))
        pos = m.end()
    if tokens:
        if text[pos:]:
            tokens.append((False, text[pos:]))
    else:
        tokens = [(False, text)]

    ranges, open_ranges, text = [], [], []
    offset = 0
    for is_tag, tok in tokens:
        if is_tag:
            tag, closing = tok
            if closing:
                if open_ranges:
                    r = open_ranges.pop()
                    r[-1] = offset - r[-2]
                    if r[-1] > 0:
                        ranges.append(r)
            else:
                if tag in {'b', 'strong', 'i', 'em'}:
                    open_ranges.append([tag, offset, -1])
        else:
            offset += len(tok)
            text.append(tok)
    text = ''.join(text)
    formats = []
    for tag, start, length in chain(ranges, open_ranges):
        fmt = QTextCharFormat()
        if tag in {'b', 'strong'}:
            fmt.setFontWeight(QFont.Bold)
        elif tag in {'i', 'em'}:
            fmt.setFontItalic(True)
        else:
            continue
        if length == -1:
            length = len(text) - start
        if length > 0:
            r = QTextLayout.FormatRange()
            r.format = fmt
            r.start, r.length = start, length
            formats.append(r)
    return text, formats
Example #7
0
        def do_tag(block, words, lo, hi, pos, fmts):
            for word in words[lo:hi]:
                if word == '\n':
                    if fmts:
                        block.layout().setAdditionalFormats(fmts)
                    pos, block, fmts = 0, block.next(), []
                    continue

                if tag in {'replace', 'insert', 'delete'}:
                    fmt = getattr(self.left, '%s_format' % ('replacereplace' if tag == 'replace' else tag))
                    f = QTextLayout.FormatRange()
                    f.start, f.length, f.format = pos, len(word), fmt
                    fmts.append(f)
                pos += len(word)
            return block, pos, fmts
Example #8
0
 def parse_single_block(self, block):
     ud, is_new_ud = self.get_user_data(block)
     orig_state = ud.state
     pblock = block.previous()
     if pblock.isValid():
         start_state = pblock.userData()
         if start_state is None:
             start_state = self.user_data_factory().state
         else:
             start_state = start_state.state.copy()
     else:
         start_state = self.user_data_factory().state
     ud.clear(state=start_state, doc_name=self.doc_name)  # Ensure no stale user data lingers
     formats = []
     for i, num, fmt in run_loop(ud, self.state_map, self.formats, unicode_type(block.text())):
         if fmt is not None:
             r = QTextLayout.FormatRange()
             r.start, r.length, r.format = i, num, fmt
             formats.append(r)
     force_next_highlight = is_new_ud or ud.state != orig_state
     return formats, force_next_highlight
Example #9
0
    def __init__(self, text='', width=0, font=None, img=None, max_height=100, align=Qt.AlignCenter):
        self.layouts = []
        self._position = Point(0, 0)
        self.leading = self.line_spacing = 0
        if font is not None:
            fm = QFontMetrics(font, img)
            self.leading = fm.leading()
            self.line_spacing = fm.lineSpacing()
        for text in text.split('<br>') if text else ():
            text, formats = parse_text_formatting(sanitize(text))
            l = QTextLayout(unescape_formatting(text), font, img)
            l.setAdditionalFormats(formats)
            to = QTextOption(align)
            to.setWrapMode(QTextOption.WrapAtWordBoundaryOrAnywhere)
            l.setTextOption(to)

            l.beginLayout()
            height = 0
            while height + 3*self.leading < max_height:
                line = l.createLine()
                if not line.isValid():
                    break
                line.setLineWidth(width)
                height += self.leading
                line.setPosition(QPointF(0, height))
                height += line.height()
            max_height -= height
            l.endLayout()
            if self.layouts:
                self.layouts.append(self.leading)
            else:
                self._position = Point(l.position().x(), l.position().y())
            self.layouts.append(l)
        if self.layouts:
            self.layouts.append(self.leading)
Example #10
0
    def __init__(self,
                 text='',
                 width=0,
                 font=None,
                 img=None,
                 max_height=100,
                 align=Qt.AlignCenter):
        self.layouts = []
        self._position = Point(0, 0)
        self.leading = self.line_spacing = 0
        if font is not None:
            fm = QFontMetrics(font, img)
            self.leading = fm.leading()
            self.line_spacing = fm.lineSpacing()
        for text in text.split('<br>') if text else ():
            text, formats = parse_text_formatting(sanitize(text))
            l = QTextLayout(unescape_formatting(text), font, img)
            l.setAdditionalFormats(formats)
            to = QTextOption(align)
            to.setWrapMode(QTextOption.WrapAtWordBoundaryOrAnywhere)
            l.setTextOption(to)

            l.beginLayout()
            height = 0
            while height + 3 * self.leading < max_height:
                line = l.createLine()
                if not line.isValid():
                    break
                line.setLineWidth(width)
                height += self.leading
                line.setPosition(QPointF(0, height))
                height += line.height()
            max_height -= height
            l.endLayout()
            if self.layouts:
                self.layouts.append(self.leading)
            else:
                self._position = Point(l.position().x(), l.position().y())
            self.layouts.append(l)
        if self.layouts:
            self.layouts.append(self.leading)
    def viewItemDrawText(self, painter, option, rect, text, color, searchText=''):  # noqa C901
        '''
        @note: most of codes taken from QCommonStylePrivate::viewItemDrawText
            added highlighting and simplified for single-line textlayouts
        @param painter QPainter
        @param option QStyleOptionViewItem
        @param rect QRect
        @param text QString
        @param color QColor
        @param searchText QString
        @return: int
        '''
        if not text:
            return 0

        fontMetrics = QFontMetrics(painter.font())
        elidedText = fontMetrics.elidedText(text, option.textElideMode, rect.width())
        textOption = QTextOption()
        textOption.setWrapMode(QTextOption.NoWrap)
        textOption.setAlignment(QStyle.visualAlignment(textOption.textDirection(),
            option.displayAlignment))
        textLayout = QTextLayout()
        textLayout.setFont(painter.font())
        textLayout.setText(elidedText)
        textLayout.setTextOption(textOption)

        if searchText:
            # QList<int>
            delimiters = []
            searchStrings = [ item.strip() for item in searchText.split(' ') ]
            searchStrings = [ item for item in searchStrings if item ]
            # Look for longer parts first
            searchStrings.sort(key=lambda x: len(x), reverse=True)

            text0 = text.lower()
            for string in searchStrings:
                string0 = string.lower()
                delimiter = text0.find(string0)

                while delimiter != -1:
                    start = delimiter
                    end = delimiter + len(string)
                    alreadyContains = False
                    for idx in range(0, len(delimiters), 2):
                        dStart = delimiters[idx]
                        dEnd = delimiters[idx+1]

                        if dStart <= start and dEnd >= end:
                            alreadyContains = True
                            break

                    if not alreadyContains:
                        delimiters.append(start)
                        delimiters.append(end)

                    delimiter = text0.find(string0, end)

            # We need to sort delimiters to properly paint all parts that user typed
            delimiters.sort()

            # If we don't find any match, just paint it withoutany highlight
            if delimiters and len(delimiters) % 2 == 0:
                highlightParts = []  # QList<QTextLayout::FormatRange>

                while delimiters:
                    highlightedPart = QTextLayout.FormatRange()
                    start = delimiters.pop(0)
                    end = delimiters.pop(0)
                    highlightedPart.start = start
                    highlightedPart.length = end - start
                    highlightedPart.format.setFontWeight(QFont.Bold)
                    highlightedPart.format.setUnderlineStyle(QTextCharFormat.SingleUnderline)
                    highlightParts.append(highlightedPart)

                textLayout.setAdditionalFormats(highlightParts)

        # do layout
        self._s_viewItemDrawText(textLayout, rect.width())

        if textLayout.lineCount() <= 0:
            return 0

        textLine = textLayout.lineAt(0)

        # if elidedText after highlighting is longer than available width then
        # re-elide it and redo layout
        diff = textLine.naturalTextWidth() - rect.width()
        if diff > 0:
            # TODO: ?
            elidedText = fontMetrics.elidedText(elidedText, option.textElideMode,
                    rect.width() - diff)
            textLayout.setText(elidedText)
            # redo layout
            self._s_viewItemDrawText(textLayout, rect.width())

            if textLayout.lineCount() <= 0:
                return 0
            textLine = textLayout.lineAt(0)

        # draw line
        painter.setPen(color)
        # qreal
        width = max(rect.width(), textLayout.lineAt(0).width())
        # QRect
        layoutRect = QStyle.alignedRect(option.direction, option.displayAlignment,
                QSize(int(width), int(textLine.height())), rect)
        # QPointF
        position = layoutRect.topLeft()

        textLine.draw(painter, position)

        return int(min(rect.width(), textLayout.lineAt(0).naturalTextWidth()))