コード例 #1
0
ファイル: bidilabel.py プロジェクト: insiderr/insiderr-app
    def render(self, real=False):
        """Return a tuple (width, height) to create the image
        with the user constraints.

        2 differents methods are used:
          * if the user does not set the width, split the line
            and calculate max width + height
          * if the user sets a width, blit per glyph
        """

        options = self.options
        render_text = self._render_text
        get_extents = self.get_extents
        uw, uh = self.text_size
        max_lines = int(options.get("max_lines", 0))
        w, h = 0, 0
        x, y = 0, 0
        if real:
            self._render_begin()
            halign = options["halign"]
            valign = options["valign"]
            if valign == "bottom":
                y = self.height - self._internal_height
            elif valign == "middle":
                y = int((self.height - self._internal_height) / 2)
        else:
            self._internal_height = 0

        glyph_space_w = get_extents(" ")[0]

        # no width specified, faster method
        if uw is None:
            index = 0
            text, rtl, has_rtl = get_display(self.text, base_dir="L")

            for line in text.split("\n"):
                index += 1
                if max_lines > 0 and index > max_lines:
                    break
                lw, lh = get_extents(line)
                lh = lh * options["line_height"]
                if real:
                    x = 0
                    if halign[0] == "c":
                        # center
                        x = int((self.width - lw) / 2.0)
                    elif halign[0] == "r":
                        # right
                        x = int(self.width - lw)
                    if len(line):
                        render_text(line, x, y)
                    y += int(lh)
                else:
                    w = max(w, int(lw))
                    self._internal_height += int(lh)
            h = self._internal_height if uh is None else uh

        # constraint
        else:

            text = self.text
            width = uw + int(options.get("padding_x", 0)) * 2

            # Shorten the text that we actually display
            if options["shorten"]:
                last_word_width = get_extents(text[text.rstrip().rfind(" ") :])[0]
                if get_extents(text)[0] > uw - last_word_width:
                    text = self.shorten(text)

            index = 0
            if self.force_single_line:
                # test if we need to reverse order of words:
                if self.rtl:
                    rtext, rtl, has_rtl = get_display(text, base_dir="R")
                    lines = [rtext]
                else:
                    rtext, rtl, has_rtl = get_display(text, base_dir="L")
                    lines = [rtext]
            else:
                lines = self._split_smart(text)
            for line in lines:
                index += 1
                if max_lines > 0 and index > max_lines:
                    break
                lw, lh = get_extents(line)
                lh = lh * options["line_height"]
                if real:
                    x = 0
                    if halign[0] == "c":
                        # center
                        x = int((width - lw) / 2.0)
                    elif halign[0] == "r":
                        # right
                        x = int(width - lw)
                    elif halign[0] == "j":
                        # justify, recalc avg spaces
                        words = line.split()
                        sw = get_extents(" ")[0]
                        _spaces = len(words) - 1
                        if _spaces > 0:
                            just_space = ((uw - lw + sw * _spaces) * 1.0) / (_spaces * 1.0)
                        else:
                            just_space = 0
                        # render per word with new spaces
                        for word in words:
                            cw = get_extents(word)[0]
                            render_text(word, x, y)
                            x += cw + just_space
                        line = ""
                    if len(line):
                        x = max(1, x)
                        render_text(line, x, y)
                    y += int(lh)
                else:
                    w = uw
                    if self.rtl and self.force_single_line and not real:
                        w = max(lw, uw)
                    self._internal_height += int(lh)
            h = self._internal_height if uh is None else uh

        if not real:
            # was only the first pass
            # return with/height
            w = int(max(w, 1))
            h = int(max(h, 1))
            return w, h

        # get data from provider
        data = self._render_end()
        assert data

        # If the text is 1px width, usually, the data is black.
        # Don't blit that kind of data, otherwise, you have a little black bar.
        if data is not None and data.width > 1:
            self.texture.blit_data(data)
コード例 #2
0
ファイル: bidilabel.py プロジェクト: insiderr/insiderr-app
    def _split_smart(self, text):
        # Do a "smart" split. If autowidth or autosize is set,
        # we are not doing smart split, just a split on line break.
        # Otherwise, we are trying to split as soon as possible, to prevent
        # overflow on the widget.

        # depend of the options, split the text on line, or word
        if not self.text_size[0]:
            lines = text.split(u"\n")
            return lines

        # return the text width + tab support
        def text_width(text, _tab_width):
            text = text.replace("\t", " " * _tab_width)
            w, h = self.get_extents(text)
            return w

        def _tokenize(text):
            # Tokenize a text string from some delimiters
            if text is None:
                return
            delimiters = self.delimiters  # u' ,\'".;:\n\r\t'
            oldindex = 0
            for index, char in enumerate(text):
                if char not in delimiters:
                    continue
                if oldindex != index:
                    yield text[oldindex:index]
                yield text[index : index + 1]
                oldindex = index + 1
            yield text[oldindex:]

        # no autosize, do wordwrap.
        FL_IS_NEWLINE = 1
        x = flags = 0
        line = []
        lines = []
        _join = u"".join
        lines_append = lines.append
        width = self.text_size[0]
        _tab_width = 4  ##

        # try to add each word on current line.
        for word in _tokenize(text):
            # if word==u'':
            #    continue
            is_newline = word == u"\n"
            w = text_width(word, _tab_width)
            # if we have more than the width, or if it's a newline,
            # push the current line, and create a new one
            if (x + w > width) or is_newline:
                # now we check if we already started a new line and
                # the word is still to big
                if x == 0 or w > width:
                    # if the word is too long commit the current and start a new one
                    if w > width and line:
                        lines_append(_join(line))
                        flags = 0
                        line = []
                        x = 0
                    # try to find the max chars that fits in the line
                    newword = word
                    wordfound = True
                    while len(newword) > 0 and wordfound:
                        wordfound = False
                        for i in range(0, len(newword)):
                            word = newword[0 : len(newword) - i]
                            w = text_width(word, _tab_width)
                            if x + w <= width:
                                newword = newword[len(newword) - i :]
                                wordfound = True
                                if newword:
                                    lines_append(_join(word))
                                    flags = 0
                                    line = []
                                    x = 0
                                break
                elif line:
                    lines_append(_join(line))
                    flags = 0
                    line = []
                    x = 0
                else:
                    x += w
                    line.append(word)
            if is_newline:
                flags |= FL_IS_NEWLINE
            else:
                x += w
                line.append(word)
        if line or flags & FL_IS_NEWLINE:
            lines_append(_join(line))

        # test if we need to reverse order of words:
        if self.rtl:
            for i, l in enumerate(lines):
                # rtext = reverse_tokenize(l)
                rtext, rtl, has_rtl = get_display(l, base_dir="R")
                lines[i] = rtext

        return lines