Ejemplo n.º 1
0
 def on_font_size(self, instance, value):
     """Helper function to manage strings with metrics passed as arguments (eg '12dp') """
     try:
         fValue = float(value)
     except:
         fValue = dpi2px(value[:-2], value[-2:])
     self.fFontSize = fValue
Ejemplo n.º 2
0
def metricToPixels(value):
    result = None
    if isinstance(value, basestring):
        match = re.match(r"([0-9]+)([a-z]+)", value, re.I)
        if match:
            res = match.groups()
            return dpi2px(res[0], res[1])
    elif type(value) is int:
        return value
    return 100
Ejemplo n.º 3
0
def metricToPixels(value):
    result = None
    if isinstance(value, basestring):
        match = re.match(r"([0-9]+)([a-z]+)", value, re.I)
        if match:
            res = match.groups()
            return dpi2px(res[0], res[1])
    elif type(value) is int:
        return value
    return 100
Ejemplo n.º 4
0
def get_size_in_pixels(size):
    res = 0
    if size:
        try:
            res = float(size)
        except ValueError:
            regex = r'([\d]+)(\D+)'
            searched = re.findall(regex, size)
            if searched:
                resize = searched[0]
                res = dpi2px(resize[0], resize[1])
    return res
Ejemplo n.º 5
0
def pt(value):
    '''Convert from points to pixels
    '''
    return dpi2px(value, 'pt')
Ejemplo n.º 6
0
    def _pre_render(self):
        # split markup, words, and lines
        # result: list of word with position and width/height
        # during the first pass, we don't care about h/valign
        self._lines = lines = []
        self._refs = {}
        self._anchors = {}
        spush = self._push_style
        spop = self._pop_style
        options = self.options
        options['_ref'] = None
        options['script'] = 'normal'
        for item in self.markup:
            if item == '[b]':
                spush('bold')
                options['bold'] = True
                self.resolve_font_name()
            elif item == '[/b]':
                spop('bold')
                self.resolve_font_name()
            elif item == '[i]':
                spush('italic')
                options['italic'] = True
                self.resolve_font_name()
            elif item == '[/i]':
                spop('italic')
                self.resolve_font_name()
            elif item[:6] == '[size=':
                item = item[6:-1]
                try:
                    if item[-2:] in ('px', 'pt', 'in', 'cm', 'mm', 'dp', 'sp'):
                        size = dpi2px(item[:-2], item[-2:])
                    else:
                        size = int(item)
                except ValueError:
                    raise
                    size = options['font_size']
                spush('font_size')
                options['font_size'] = size
            elif item == '[/size]':
                spop('font_size')
            elif item[:7] == '[color=':
                color = parse_color(item[7:-1])
                spush('color')
                options['color'] = color
            elif item == '[/color]':
                spop('color')
            elif item[:6] == '[font=':
                fontname = item[6:-1]
                spush('font_name')
                options['font_name'] = fontname
                self.resolve_font_name()
            elif item == '[/font]':
                spop('font_name')
                self.resolve_font_name()
            elif item[:5] == '[sub]':
                spush('font_size')
                spush('script')
                options['font_size'] = options['font_size'] * .5
                options['script'] = 'subscript'
            elif item == '[/sub]':
                spop('font_size')
                spop('script')
            elif item[:5] == '[sup]':
                spush('font_size')
                spush('script')
                options['font_size'] = options['font_size'] * .5
                options['script'] = 'superscript'
            elif item == '[/sup]':
                spop('font_size')
                spop('script')
            elif item[:5] == '[ref=':
                ref = item[5:-1]
                spush('_ref')
                options['_ref'] = ref
            elif item == '[/ref]':
                spop('_ref')
            elif item[:8] == '[anchor=':
                ref = item[8:-1]
                if len(lines):
                    x, y = lines[-1][0:2]
                else:
                    x = y = 0
                self._anchors[ref] = x, y
            else:
                item = item.replace('&bl;',
                                    '[').replace('&br;',
                                                 ']').replace('&', '&')
                self._pre_render_label(item, options, lines)

        # calculate the texture size
        w, h = self.text_size
        if h is None or h < 0:
            h = None
        if w is None or w < 0:
            w = None
        if w is None:
            if not lines:
                w = 1
            else:
                w = max([line[0] for line in lines])
        if h is None:
            if not lines:
                h = 1
            else:
                h = sum([line[1] for line in lines])
        return int(ceil(w)), int(ceil(h))
Ejemplo n.º 7
0
    def _pre_render(self):
        # split markup, words, and lines
        # result: list of word with position and width/height
        # during the first pass, we don't care about h/valign
        self._cached_lines = lines = []
        self._refs = {}
        self._anchors = {}
        clipped = False
        w = h = 0
        uw, uh = self.text_size
        spush = self._push_style
        spop = self._pop_style
        opts = options = self.options
        options['_ref'] = None
        options['script'] = 'normal'
        shorten = options['shorten']
        # if shorten, then don't split lines to fit uw, because it will be
        # flattened later when shortening and broken up lines if broken
        # mid-word will have space mid-word when lines are joined
        uw_temp = None if shorten else uw
        xpad = options['padding_x']
        uhh = (None if uh is not None and options['valign'][-1] != 'p' or
               options['shorten'] else uh)
        options['strip'] = options['strip'] or options['halign'][-1] == 'y'
        for item in self.markup:
            if item == '[b]':
                spush('bold')
                options['bold'] = True
                self.resolve_font_name()
            elif item == '[/b]':
                spop('bold')
                self.resolve_font_name()
            elif item == '[i]':
                spush('italic')
                options['italic'] = True
                self.resolve_font_name()
            elif item == '[/i]':
                spop('italic')
                self.resolve_font_name()
            elif item[:6] == '[size=':
                item = item[6:-1]
                try:
                    if item[-2:] in ('px', 'pt', 'in', 'cm', 'mm', 'dp', 'sp'):
                        size = dpi2px(item[:-2], item[-2:])
                    else:
                        size = int(item)
                except ValueError:
                    raise
                    size = options['font_size']
                spush('font_size')
                options['font_size'] = size
            elif item == '[/size]':
                spop('font_size')
            elif item[:7] == '[color=':
                color = parse_color(item[7:-1])
                spush('color')
                options['color'] = color
            elif item == '[/color]':
                spop('color')
            elif item[:6] == '[font=':
                fontname = item[6:-1]
                spush('font_name')
                options['font_name'] = fontname
                self.resolve_font_name()
            elif item == '[/font]':
                spop('font_name')
                self.resolve_font_name()
            elif item[:5] == '[sub]':
                spush('font_size')
                spush('script')
                options['font_size'] = options['font_size'] * .5
                options['script'] = 'subscript'
            elif item == '[/sub]':
                spop('font_size')
                spop('script')
            elif item[:5] == '[sup]':
                spush('font_size')
                spush('script')
                options['font_size'] = options['font_size'] * .5
                options['script'] = 'superscript'
            elif item == '[/sup]':
                spop('font_size')
                spop('script')
            elif item[:5] == '[ref=':
                ref = item[5:-1]
                spush('_ref')
                options['_ref'] = ref
            elif item == '[/ref]':
                spop('_ref')
            elif not clipped and item[:8] == '[anchor=':
                ref = item[8:-1]
                if len(lines):
                    x, y = lines[-1].x, lines[-1].y
                else:
                    x = y = 0
                self._anchors[ref] = x, y
            elif not clipped:
                item = item.replace('&bl;', '[').replace(
                    '&br;', ']').replace('&amp;', '&')
                opts = copy(options)
                extents = self.get_cached_extents()
                opts['space_width'] = extents(' ')[0]
                w, h, clipped = layout_text(item, lines, (w, h),
                    (uw_temp, uhh), opts, extents, True, False)

        if len(lines):  # remove any trailing spaces from the last line
            old_opts = self.options
            self.options = copy(opts)
            w, h, clipped = layout_text('', lines, (w, h), (uw_temp, uhh),
                self.options, self.get_cached_extents(), True, True)
            self.options = old_opts

        if shorten:
            options['_ref'] = None  # no refs for you!
            w, h, lines = self.shorten_post(lines, w, h)
            self._cached_lines = lines
        # when valign is not top, for markup we layout everything (text_size[1]
        # is temporarily set to None) and after layout cut to size if too tall
        elif uh != uhh and h > uh and len(lines) > 1:
            if options['valign'][-1] == 'm':  # bottom
                i = 0
                while i < len(lines) - 1 and h > uh:
                    h -= lines[i].h
                    i += 1
                del lines[:i]
            else:  # middle
                i = 0
                top = int(h / 2. + uh / 2.)  # remove extra top portion
                while i < len(lines) - 1 and h > top:
                    h -= lines[i].h
                    i += 1
                del lines[:i]
                i = len(lines) - 1  # remove remaining bottom portion
                while i and h > uh:
                    h -= lines[i].h
                    i -= 1
                del lines[i + 1:]

        # now justify the text
        if options['halign'][-1] == 'y' and uw is not None:
            # XXX: update refs to justified pos
            # when justify, each line shouldv'e been stripped already
            split = partial(re.split, re.compile('( +)'))
            uww = uw - 2 * xpad
            chr = type(self.text)
            space = chr(' ')
            empty = chr('')

            for i in range(len(lines)):
                line = lines[i]
                words = line.words
                # if there's nothing to justify, we're done
                if (not line.w or int(uww - line.w) <= 0 or not len(words) or
                    line.is_last_line):
                    continue

                done = False
                parts = [None, ] * len(words)  # contains words split by space
                idxs = [None, ] * len(words)  # indices of the space in parts
                # break each word into spaces and add spaces until it's full
                # do first round of split in case we don't need to split all
                for w in range(len(words)):
                    word = words[w]
                    sw = word.options['space_width']
                    p = parts[w] = split(word.text)
                    idxs[w] = [v for v in range(len(p)) if
                               p[v].startswith(' ')]
                    # now we have the indices of the spaces in split list
                    for k in idxs[w]:
                        # try to add single space at each space
                        if line.w + sw > uww:
                            done = True
                            break
                        line.w += sw
                        word.lw += sw
                        p[k] += space
                    if done:
                        break

                # there's not a single space in the line?
                if not any(idxs):
                    continue

                # now keep adding spaces to already split words until done
                while not done:
                    for w in range(len(words)):
                        if not idxs[w]:
                            continue
                        word = words[w]
                        sw = word.options['space_width']
                        p = parts[w]
                        for k in idxs[w]:
                            # try to add single space at each space
                            if line.w + sw > uww:
                                done = True
                                break
                            line.w += sw
                            word.lw += sw
                            p[k] += space
                        if done:
                            break

                # if not completely full, push last words to right edge
                diff = int(uww - line.w)
                if diff > 0:
                    # find the last word that had a space
                    for w in range(len(words) - 1, -1, -1):
                        if not idxs[w]:
                            continue
                        break
                    old_opts = self.options
                    self.options = word.options
                    word = words[w]
                    # split that word into left/right and push right till uww
                    l_text = empty.join(parts[w][:idxs[w][-1]])
                    r_text = empty.join(parts[w][idxs[w][-1]:])
                    left = LayoutWord(word.options,
                        self.get_extents(l_text)[0], word.lh, l_text)
                    right = LayoutWord(word.options,
                        self.get_extents(r_text)[0], word.lh, r_text)
                    left.lw = max(left.lw, word.lw + diff - right.lw)
                    self.options = old_opts

                    # now put words back together with right/left inserted
                    for k in range(len(words)):
                        if idxs[k]:
                            words[k].text = empty.join(parts[k])
                    words[w] = right
                    words.insert(w, left)
                else:
                    for k in range(len(words)):
                        if idxs[k]:
                            words[k].text = empty.join(parts[k])
                line.w = uww
                w = max(w, uww)

        self._internal_size = w, h
        if uw:
            w = uw
        if uh:
            h = uh
        if h > 1 and w < 2:
            w = 2
        if w < 1:
            w = 1
        if h < 1:
            h = 1
        return w, h
Ejemplo n.º 8
0
    def _pre_render(self):
        # split markup, words, and lines
        # result: list of word with position and width/height
        # during the first pass, we don't care about h/valign
        self._cached_lines = lines = []
        self._refs = {}
        self._anchors = {}
        clipped = False
        w = h = 0
        uw, uh = self.text_size
        spush = self._push_style
        spop = self._pop_style
        options = self.options
        options['_ref'] = None
        options['_anchor'] = None
        options['script'] = 'normal'
        shorten = options['shorten']
        # if shorten, then don't split lines to fit uw, because it will be
        # flattened later when shortening and broken up lines if broken
        # mid-word will have space mid-word when lines are joined
        uw_temp = None if shorten else uw
        xpad = options['padding_x']
        uhh = (None if uh is not None and options['valign'] != 'top'
               or options['shorten'] else uh)
        options['strip'] = options['strip'] or options['halign'] == 'justify'
        find_base_dir = Label.find_base_direction
        base_dir = options['base_direction']
        self._resolved_base_dir = None
        for item in self.markup:
            if item == '[b]':
                spush('bold')
                options['bold'] = True
                self.resolve_font_name()
            elif item == '[/b]':
                spop('bold')
                self.resolve_font_name()
            elif item == '[i]':
                spush('italic')
                options['italic'] = True
                self.resolve_font_name()
            elif item == '[/i]':
                spop('italic')
                self.resolve_font_name()
            elif item == '[u]':
                spush('underline')
                options['underline'] = True
                self.resolve_font_name()
            elif item == '[/u]':
                spop('underline')
                self.resolve_font_name()
            elif item == '[s]':
                spush('strikethrough')
                options['strikethrough'] = True
                self.resolve_font_name()
            elif item == '[/s]':
                spop('strikethrough')
                self.resolve_font_name()
            elif item[:6] == '[size=':
                item = item[6:-1]
                try:
                    if item[-2:] in ('px', 'pt', 'in', 'cm', 'mm', 'dp', 'sp'):
                        size = dpi2px(item[:-2], item[-2:])
                    else:
                        size = int(item)
                except ValueError:
                    raise
                    size = options['font_size']
                spush('font_size')
                options['font_size'] = size
            elif item == '[/size]':
                spop('font_size')
            elif item[:7] == '[color=':
                color = parse_color(item[7:-1])
                spush('color')
                options['color'] = color
            elif item == '[/color]':
                spop('color')
            elif item[:6] == '[font=':
                fontname = item[6:-1]
                spush('font_name')
                options['font_name'] = fontname
                self.resolve_font_name()
            elif item == '[/font]':
                spop('font_name')
                self.resolve_font_name()
            elif item[:13] == '[font_family=':
                spush('font_family')
                options['font_family'] = item[13:-1]
            elif item == '[/font_family]':
                spop('font_family')
            elif item[:14] == '[font_context=':
                fctx = item[14:-1]
                if not fctx or fctx.lower() == 'none':
                    fctx = None
                spush('font_context')
                options['font_context'] = fctx
            elif item == '[/font_context]':
                spop('font_context')
            elif item[:15] == '[font_features=':
                spush('font_features')
                options['font_features'] = item[15:-1]
            elif item == '[/font_features]':
                spop('font_features')
            elif item[:15] == '[text_language=':
                lang = item[15:-1]
                if not lang or lang.lower() == 'none':
                    lang = None
                spush('text_language')
                options['text_language'] = lang
            elif item == '[/text_language]':
                spop('text_language')
            elif item[:5] == '[sub]':
                spush('font_size')
                spush('script')
                options['font_size'] = options['font_size'] * .5
                options['script'] = 'subscript'
            elif item == '[/sub]':
                spop('font_size')
                spop('script')
            elif item[:5] == '[sup]':
                spush('font_size')
                spush('script')
                options['font_size'] = options['font_size'] * .5
                options['script'] = 'superscript'
            elif item == '[/sup]':
                spop('font_size')
                spop('script')
            elif item[:5] == '[ref=':
                ref = item[5:-1]
                spush('_ref')
                options['_ref'] = ref
            elif item == '[/ref]':
                spop('_ref')
            elif not clipped and item[:8] == '[anchor=':
                options['_anchor'] = item[8:-1]
            elif not clipped:
                item = item.replace('&bl;',
                                    '[').replace('&br;',
                                                 ']').replace('&amp;', '&')
                if not base_dir:
                    base_dir = self._resolved_base_dir = find_base_dir(item)
                opts = copy(options)
                extents = self.get_cached_extents()
                opts['space_width'] = extents(' ')[0]
                w, h, clipped = layout_text(item,
                                            lines, (w, h), (uw_temp, uhh),
                                            opts,
                                            extents,
                                            append_down=True,
                                            complete=False)

        if len(lines):  # remove any trailing spaces from the last line
            old_opts = self.options
            self.options = copy(opts)
            w, h, clipped = layout_text('',
                                        lines, (w, h), (uw_temp, uhh),
                                        self.options,
                                        self.get_cached_extents(),
                                        append_down=True,
                                        complete=True)
            self.options = old_opts

        self.is_shortened = False
        if shorten:
            options['_ref'] = None  # no refs for you!
            options['_anchor'] = None
            w, h, lines = self.shorten_post(lines, w, h)
            self._cached_lines = lines
        # when valign is not top, for markup we layout everything (text_size[1]
        # is temporarily set to None) and after layout cut to size if too tall
        elif uh != uhh and h > uh and len(lines) > 1:
            if options['valign'] == 'bottom':
                i = 0
                while i < len(lines) - 1 and h > uh:
                    h -= lines[i].h
                    i += 1
                del lines[:i]
            else:  # middle
                i = 0
                top = int(h / 2. + uh / 2.)  # remove extra top portion
                while i < len(lines) - 1 and h > top:
                    h -= lines[i].h
                    i += 1
                del lines[:i]
                i = len(lines) - 1  # remove remaining bottom portion
                while i and h > uh:
                    h -= lines[i].h
                    i -= 1
                del lines[i + 1:]

        # now justify the text
        if options['halign'] == 'justify' and uw is not None:
            # XXX: update refs to justified pos
            # when justify, each line should've been stripped already
            split = partial(re.split, re.compile('( +)'))
            uww = uw - 2 * xpad
            chr = type(self.text)
            space = chr(' ')
            empty = chr('')

            for i in range(len(lines)):
                line = lines[i]
                words = line.words
                # if there's nothing to justify, we're done
                if (not line.w or int(uww - line.w) <= 0 or not len(words)
                        or line.is_last_line):
                    continue

                done = False
                parts = [
                    None,
                ] * len(words)  # contains words split by space
                idxs = [
                    None,
                ] * len(words)  # indices of the space in parts
                # break each word into spaces and add spaces until it's full
                # do first round of split in case we don't need to split all
                for w in range(len(words)):
                    word = words[w]
                    sw = word.options['space_width']
                    p = parts[w] = split(word.text)
                    idxs[w] = [
                        v for v in range(len(p)) if p[v].startswith(' ')
                    ]
                    # now we have the indices of the spaces in split list
                    for k in idxs[w]:
                        # try to add single space at each space
                        if line.w + sw > uww:
                            done = True
                            break
                        line.w += sw
                        word.lw += sw
                        p[k] += space
                    if done:
                        break

                # there's not a single space in the line?
                if not any(idxs):
                    continue

                # now keep adding spaces to already split words until done
                while not done:
                    for w in range(len(words)):
                        if not idxs[w]:
                            continue
                        word = words[w]
                        sw = word.options['space_width']
                        p = parts[w]
                        for k in idxs[w]:
                            # try to add single space at each space
                            if line.w + sw > uww:
                                done = True
                                break
                            line.w += sw
                            word.lw += sw
                            p[k] += space
                        if done:
                            break

                # if not completely full, push last words to right edge
                diff = int(uww - line.w)
                if diff > 0:
                    # find the last word that had a space
                    for w in range(len(words) - 1, -1, -1):
                        if not idxs[w]:
                            continue
                        break
                    old_opts = self.options
                    self.options = word.options
                    word = words[w]
                    # split that word into left/right and push right till uww
                    l_text = empty.join(parts[w][:idxs[w][-1]])
                    r_text = empty.join(parts[w][idxs[w][-1]:])
                    left = LayoutWord(word.options,
                                      self.get_extents(l_text)[0], word.lh,
                                      l_text)
                    right = LayoutWord(word.options,
                                       self.get_extents(r_text)[0], word.lh,
                                       r_text)
                    left.lw = max(left.lw, word.lw + diff - right.lw)
                    self.options = old_opts

                    # now put words back together with right/left inserted
                    for k in range(len(words)):
                        if idxs[k]:
                            words[k].text = empty.join(parts[k])
                    words[w] = right
                    words.insert(w, left)
                else:
                    for k in range(len(words)):
                        if idxs[k]:
                            words[k].text = empty.join(parts[k])
                line.w = uww
                w = max(w, uww)

        self._internal_size = w, h
        if uw:
            w = uw
        if uh:
            h = uh
        if h > 1 and w < 2:
            w = 2
        if w < 1:
            w = 1
        if h < 1:
            h = 1
        return int(w), int(h)
Ejemplo n.º 9
0
def sp(value):
    '''Convert from scale-independent pixels to pixels
    '''
    return dpi2px(value, 'sp')
Ejemplo n.º 10
0
def mm(value):
    '''Convert from millimeters to pixels
    '''
    return dpi2px(value, 'mm')
Ejemplo n.º 11
0
def inch(value):
    '''Convert from inches to pixels
    '''
    return dpi2px(value, 'in')
Ejemplo n.º 12
0
def pt(value):
    '''Convert from points to pixels
    '''
    return dpi2px(value, 'pt')
Ejemplo n.º 13
0
    def _pre_render(self):
        # split markup, words, and lines
        # result: list of word with position and width/height
        # during the first pass, we don't care about h/valign
        self._lines = lines = []
        self._refs = {}
        self._anchors = {}
        spush = self._push_style
        spop = self._pop_style
        options = self.options
        options["_ref"] = None
        options["script"] = "normal"
        for item in self.markup:
            if item == "[b]":
                spush("bold")
                options["bold"] = True
                self.resolve_font_name()
            elif item == "[/b]":
                spop("bold")
                self.resolve_font_name()
            elif item == "[i]":
                spush("italic")
                options["italic"] = True
                self.resolve_font_name()
            elif item == "[/i]":
                spop("italic")
                self.resolve_font_name()
            elif item[:6] == "[size=":
                item = item[6:-1]
                try:
                    if item[-2:] in ("px", "pt", "in", "cm", "mm", "dp", "sp"):
                        size = dpi2px(item[:-2], item[-2:])
                    else:
                        size = int(item)
                except ValueError:
                    raise
                    size = options["font_size"]
                spush("font_size")
                options["font_size"] = size
            elif item == "[/size]":
                spop("font_size")
            elif item[:7] == "[color=":
                color = parse_color(item[7:-1])
                spush("color")
                options["color"] = color
            elif item == "[/color]":
                spop("color")
            elif item[:6] == "[font=":
                fontname = item[6:-1]
                spush("font_name")
                options["font_name"] = fontname
                self.resolve_font_name()
            elif item == "[/font]":
                spop("font_name")
                self.resolve_font_name()
            elif item[:5] == "[sub]":
                spush("font_size")
                spush("script")
                options["font_size"] = options["font_size"] * 0.5
                options["script"] = "subscript"
            elif item == "[/sub]":
                spop("font_size")
                spop("script")
            elif item[:5] == "[sup]":
                spush("font_size")
                spush("script")
                options["font_size"] = options["font_size"] * 0.5
                options["script"] = "superscript"
            elif item == "[/sup]":
                spop("font_size")
                spop("script")
            elif item[:5] == "[ref=":
                ref = item[5:-1]
                spush("_ref")
                options["_ref"] = ref
            elif item == "[/ref]":
                spop("_ref")
            elif item[:8] == "[anchor=":
                ref = item[8:-1]
                if len(lines):
                    x, y = lines[-1][0:2]
                else:
                    x = y = 0
                self._anchors[ref] = x, y
            else:
                item = item.replace("&bl;", "[").replace("&br;", "]").replace("&amp;", "&")
                self._pre_render_label(item, options, lines)

        # calculate the texture size
        w, h = self.text_size
        if h < 0:
            h = None
        if w < 0:
            w = None
        if w is None:
            if not lines:
                w = 1
            else:
                w = max([line[0] for line in lines])
        if h is None:
            if not lines:
                h = 1
            else:
                h = sum([line[1] for line in lines])
        return w, h
Ejemplo n.º 14
0
def inch(value):
    '''Convert from inches to pixels
    '''
    return dpi2px(value, 'in')
Ejemplo n.º 15
0
def cm(value):
    '''Convert from centimeters to pixels
    '''
    return dpi2px(value, 'cm')
Ejemplo n.º 16
0
def cm(value):
    '''Convert from centimeters to pixels
    '''
    return dpi2px(value, 'cm')
Ejemplo n.º 17
0
def mm(value):
    '''Convert from millimeters to pixels
    '''
    return dpi2px(value, 'mm')
Ejemplo n.º 18
0
def dp(value):
    '''Convert from density-independent pixels to pixels
    '''
    return dpi2px(value, 'dp')
Ejemplo n.º 19
0
def dp(value):
    '''Convert from density-independent pixels to pixels
    '''
    return dpi2px(value, 'dp')
Ejemplo n.º 20
0
    def _pre_render(self):
        # split markup, words, and lines
        # result: list of word with position and width/height
        # during the first pass, we don't care about h/valign
        self._cached_lines = lines = []
        self._refs = {}
        self._anchors = {}
        clipped = False
        w = h = 0
        uw, uh = self.text_size
        spush = self._push_style
        spop = self._pop_style
        opts = options = self.options
        options["_ref"] = None
        options["_anchor"] = None
        options["script"] = "normal"
        shorten = options["shorten"]
        # if shorten, then don't split lines to fit uw, because it will be
        # flattened later when shortening and broken up lines if broken
        # mid-word will have space mid-word when lines are joined
        uw_temp = None if shorten else uw
        xpad = options["padding_x"]
        uhh = None if uh is not None and options["valign"][-1] != "p" or options["shorten"] else uh
        options["strip"] = options["strip"] or options["halign"][-1] == "y"
        for item in self.markup:
            if item == "[b]":
                spush("bold")
                options["bold"] = True
                self.resolve_font_name()
            elif item == "[/b]":
                spop("bold")
                self.resolve_font_name()
            elif item == "[i]":
                spush("italic")
                options["italic"] = True
                self.resolve_font_name()
            elif item == "[/i]":
                spop("italic")
                self.resolve_font_name()
            elif item[:6] == "[size=":
                item = item[6:-1]
                try:
                    if item[-2:] in ("px", "pt", "in", "cm", "mm", "dp", "sp"):
                        size = dpi2px(item[:-2], item[-2:])
                    else:
                        size = int(item)
                except ValueError:
                    raise
                    size = options["font_size"]
                spush("font_size")
                options["font_size"] = size
            elif item == "[/size]":
                spop("font_size")
            elif item[:7] == "[color=":
                color = parse_color(item[7:-1])
                spush("color")
                options["color"] = color
            elif item == "[/color]":
                spop("color")
            elif item[:6] == "[font=":
                fontname = item[6:-1]
                spush("font_name")
                options["font_name"] = fontname
                self.resolve_font_name()
            elif item == "[/font]":
                spop("font_name")
                self.resolve_font_name()
            elif item[:5] == "[sub]":
                spush("font_size")
                spush("script")
                options["font_size"] = options["font_size"] * 0.5
                options["script"] = "subscript"
            elif item == "[/sub]":
                spop("font_size")
                spop("script")
            elif item[:5] == "[sup]":
                spush("font_size")
                spush("script")
                options["font_size"] = options["font_size"] * 0.5
                options["script"] = "superscript"
            elif item == "[/sup]":
                spop("font_size")
                spop("script")
            elif item[:5] == "[ref=":
                ref = item[5:-1]
                spush("_ref")
                options["_ref"] = ref
            elif item == "[/ref]":
                spop("_ref")
            elif not clipped and item[:8] == "[anchor=":
                options["_anchor"] = item[8:-1]
            elif not clipped:
                item = item.replace("&bl;", "[").replace("&br;", "]").replace("&amp;", "&")
                opts = copy(options)
                extents = self.get_cached_extents()
                opts["space_width"] = extents(" ")[0]
                w, h, clipped = layout_text(item, lines, (w, h), (uw_temp, uhh), opts, extents, True, False)

        if len(lines):  # remove any trailing spaces from the last line
            old_opts = self.options
            self.options = copy(opts)
            w, h, clipped = layout_text(
                "", lines, (w, h), (uw_temp, uhh), self.options, self.get_cached_extents(), True, True
            )
            self.options = old_opts

        if shorten:
            options["_ref"] = None  # no refs for you!
            options["_anchor"] = None
            w, h, lines = self.shorten_post(lines, w, h)
            self._cached_lines = lines
        # when valign is not top, for markup we layout everything (text_size[1]
        # is temporarily set to None) and after layout cut to size if too tall
        elif uh != uhh and h > uh and len(lines) > 1:
            if options["valign"][-1] == "m":  # bottom
                i = 0
                while i < len(lines) - 1 and h > uh:
                    h -= lines[i].h
                    i += 1
                del lines[:i]
            else:  # middle
                i = 0
                top = int(h / 2.0 + uh / 2.0)  # remove extra top portion
                while i < len(lines) - 1 and h > top:
                    h -= lines[i].h
                    i += 1
                del lines[:i]
                i = len(lines) - 1  # remove remaining bottom portion
                while i and h > uh:
                    h -= lines[i].h
                    i -= 1
                del lines[i + 1 :]

        # now justify the text
        if options["halign"][-1] == "y" and uw is not None:
            # XXX: update refs to justified pos
            # when justify, each line shouldv'e been stripped already
            split = partial(re.split, re.compile("( +)"))
            uww = uw - 2 * xpad
            chr = type(self.text)
            space = chr(" ")
            empty = chr("")

            for i in range(len(lines)):
                line = lines[i]
                words = line.words
                # if there's nothing to justify, we're done
                if not line.w or int(uww - line.w) <= 0 or not len(words) or line.is_last_line:
                    continue

                done = False
                parts = [None] * len(words)  # contains words split by space
                idxs = [None] * len(words)  # indices of the space in parts
                # break each word into spaces and add spaces until it's full
                # do first round of split in case we don't need to split all
                for w in range(len(words)):
                    word = words[w]
                    sw = word.options["space_width"]
                    p = parts[w] = split(word.text)
                    idxs[w] = [v for v in range(len(p)) if p[v].startswith(" ")]
                    # now we have the indices of the spaces in split list
                    for k in idxs[w]:
                        # try to add single space at each space
                        if line.w + sw > uww:
                            done = True
                            break
                        line.w += sw
                        word.lw += sw
                        p[k] += space
                    if done:
                        break

                # there's not a single space in the line?
                if not any(idxs):
                    continue

                # now keep adding spaces to already split words until done
                while not done:
                    for w in range(len(words)):
                        if not idxs[w]:
                            continue
                        word = words[w]
                        sw = word.options["space_width"]
                        p = parts[w]
                        for k in idxs[w]:
                            # try to add single space at each space
                            if line.w + sw > uww:
                                done = True
                                break
                            line.w += sw
                            word.lw += sw
                            p[k] += space
                        if done:
                            break

                # if not completely full, push last words to right edge
                diff = int(uww - line.w)
                if diff > 0:
                    # find the last word that had a space
                    for w in range(len(words) - 1, -1, -1):
                        if not idxs[w]:
                            continue
                        break
                    old_opts = self.options
                    self.options = word.options
                    word = words[w]
                    # split that word into left/right and push right till uww
                    l_text = empty.join(parts[w][: idxs[w][-1]])
                    r_text = empty.join(parts[w][idxs[w][-1] :])
                    left = LayoutWord(word.options, self.get_extents(l_text)[0], word.lh, l_text)
                    right = LayoutWord(word.options, self.get_extents(r_text)[0], word.lh, r_text)
                    left.lw = max(left.lw, word.lw + diff - right.lw)
                    self.options = old_opts

                    # now put words back together with right/left inserted
                    for k in range(len(words)):
                        if idxs[k]:
                            words[k].text = empty.join(parts[k])
                    words[w] = right
                    words.insert(w, left)
                else:
                    for k in range(len(words)):
                        if idxs[k]:
                            words[k].text = empty.join(parts[k])
                line.w = uww
                w = max(w, uww)

        self._internal_size = w, h
        if uw:
            w = uw
        if uh:
            h = uh
        if h > 1 and w < 2:
            w = 2
        if w < 1:
            w = 1
        if h < 1:
            h = 1
        return int(w), int(h)
Ejemplo n.º 21
0
def sp(value):
    '''Convert from scale-independent pixels to pixels
    '''
    return dpi2px(value, 'sp')
Ejemplo n.º 22
0
    def _pre_render(self):
        # split markup, words, and lines
        # result: list of word with position and width/height
        # during the first pass, we don't care about h/valign
        self._lines = lines = []
        self._refs = {}
        self._anchors = {}
        spush = self._push_style
        spop = self._pop_style
        options = self.options
        options['_ref'] = None
        for item in self.markup:
            if item == '[b]':
                spush('bold')
                options['bold'] = True
                self.resolve_font_name()
            elif item == '[/b]':
                spop('bold')
                self.resolve_font_name()
            elif item == '[i]':
                spush('italic')
                options['italic'] = True
                self.resolve_font_name()
            elif item == '[/i]':
                spop('italic')
                self.resolve_font_name()
            elif item[:6] == '[size=':
                item = item[6:-1]
                try:
                    if item[-2:] in ('px', 'pt', 'in', 'cm', 'mm'):
                        size = dpi2px(item[:-2], item[-2:])
                    else:
                        size = int(item)
                except ValueError:
                    raise
                    size = options['font_size']
                spush('font_size')
                options['font_size'] = size
            elif item == '[/size]':
                spop('font_size')
            elif item[:7] == '[color=':
                color = parse_color(item[7:-1])
                spush('color')
                options['color'] = color
            elif item == '[/color]':
                spop('color')
            elif item[:6] == '[font=':
                fontname = item[6:-1]
                spush('font_name')
                options['font_name'] = fontname
                self.resolve_font_name()
            elif item == '[/font]':
                spop('font_name')
                self.resolve_font_name()
            elif item[:5] == '[ref=':
                ref = item[5:-1]
                spush('_ref')
                options['_ref'] = ref
            elif item == '[/ref]':
                spop('_ref')
            elif item[:8] == '[anchor=':
                ref = item[8:-1]
                if len(lines):
                    x, y = lines[-1][0:2]
                else:
                    x = y = 0
                self._anchors[ref] = x, y
            else:
                item = item.replace('&bl;', '[').replace(
                        '&br;', ']').replace('&amp;', '&')
                self._pre_render_label(item, options, lines)

        # calculate the texture size
        w, h = self.text_size
        if h < 0:
            h = None
        if w < 0:
            w = None
        if w is None:
            w = max([line[0] for line in lines])
        if h is None:
            h = sum([line[1] for line in lines])
        return w, h
Ejemplo n.º 23
0
class cScrollableLabelLargeInner(RecycleView):
    """ The "real' scrollable label (without background) """

    # to have similar properties as a Label
    font_size = Property('20sp')
    text = StringProperty('')
    oOrcaWidget = Property(None)
    # Internal Property which handles fonmt resizing (not working as RecycleView can't manage change of cached widget)
    fFontSize = BoundedNumericProperty(dpi2px(20, 'sp'),
                                       min=4.0,
                                       max=96.0,
                                       errorhandler=lambda x: 96.0
                                       if x > 96.0 else 4.0)

    def __init__(self, **kwargs):

        #we create a new class on the fly top ass  the font args to the creation process, as the view adapter creates without arguments
        self.cLineLayout = type('cLineLayout', cLineLayoutBase.__bases__,
                                dict(cLineLayoutBase.__dict__))
        # passes myself to the embedded class. Not good style but Recycleview limits passing customized parameters
        self.cLineLayout.oScrollableLabelLargeInner = self

        self.oOrcaWidget = kwargs.get('ORCAWIDGET', None)
        # maximal len (in chars) of a single ine of the given text
        self.iMaxLen = 0
        # Setting the scrolltypes / bars for the Recycleview
        self.scroll_type = ['bars', 'content']
        self.scroll_wheel_distance = dp(114)
        self.bar_width = dp(10)
        # The original passed Data array
        self.aData = []
        # Internal Flag to distinguish between first show and (re) setting text
        self.bInit = False
        # The maximum width of a char
        self.iMaxCharwidth = 0
        # The maximum  characters per line
        self.iMaxCharsPerLine = 0
        if "font_size" in kwargs:
            self.on_font_size(None, kwargs["font_size"])

        # Retieving the genuine font propertes of a label to pass only those arguments to the label (removing pos, hints, background colors , etc
        self.aFontProperties = Label._font_properties + ("background_color", )
        # standard font args, if nothing is given
        self.kwFontArgs = {
            "halign": "left",
            "valign": "top",
            "max_lines": 1,
            "font_size": 20
        }

        # add / update the font args to be passed to the Label
        for k in kwargs:
            if k in self.aFontProperties:
                self.kwFontArgs[k] = kwargs[k]
        self.kwFontArgs["font_size"] = self.fFontSize
        self.kwFontArgs.pop("text", None)

        # Parameter Flag to disable horizontal scrolling
        self.bNoXScroll = kwargs.get("noxscroll", False)
        self.bMarkup = kwargs.get("markup", False)
        #A dummy label to get th width a the larges character
        self.oLabel = Label(**RemoveNoClassArgs(self.kwFontArgs, Label))

        super(self.__class__,
              self).__init__(**RemoveNoClassArgs(kwargs, RecycleView))
        # This manages the distance between lines
        self.layout_manager.default_size = (
            None, self.oLabel._label.get_extents('W')[1])
        #self.layout_manager.default_size = (None, self.fFontSize*1.1)
        self.layout_manager.orientation = 'vertical'

        # we need to handle size changes
        self.bind(size=self.update_size)
        self.bind(text=self.on_textinner)
        self.text = kwargs.get("text", "")

    def on_fFontSize(self, instance, value):
        """ Will handle font size changes  """
        if self.layout_manager is not None:
            self.kwFontArgs["font_size"] = self.fFontSize
            self.oLabel.font_size = self.fFontSize
            self.layout_manager.default_size = (
                None, self.oLabel._label.get_extents('W')[1])
            self.SetData(self.aData)

    def on_font_size(self, instance, value):
        """Helper function to manage strings with metrics passed as arguments (eg '12dp') """
        try:
            fValue = float(value)
        except:
            fValue = dpi2px(value[:-2], value[-2:])
        self.fFontSize = fValue

    def on_textinner(self, instance, value):
        """ helper to have a Label like funtionality to set the caption """
        self.update_size(None, None)

    def IncreaseFontSize(self, *args):
        """ Increase the Font size """
        self.fFontSize += 1.0

    def DecreaseFontSize(self, *args):
        """ Decrease the Font size """
        self.fFontSize -= 1.0

    def SetData(self, aData):
        """ Passes the data to the Recycle view and sets the layout manager size """
        self.data = [{
            'text': ToUnicode(x),
            "font_size": self.fFontSize
        } for x in aData]

        if self.bNoXScroll:
            self.layout_manager.width = self.width
        else:
            self.layout_manager.width = (
                self.iMaxCharwidth) * self.iMaxCharsPerLine
        self.viewclass = self.cLineLayout
        self.refresh_from_data()

    def update_size(self, instance, value):
        """ Fits the text into layout_manager line.
        If noxscroll, all line with be split up to fit to the widget size.
        if x scrolling is enabled, we look, if the the maximum line lenght exceed the TEXTURE SIZE.
        In that case we split the lines as well and set the scrolling window size to the texture size.
        if x scrolling is enabled, and all lines fit to the texture size, we pass the unchanged array """

        if self.size == [100, 100]:
            return

        bDoLineBreak = False
        self.iMaxCharwidth = self.oLabel._label.get_extents('W')[0]
        self.iMaxCharsPerLine = int(self.width / self.iMaxCharwidth)

        if not self.bNoXScroll:
            self.aData = self.text.split('\n')

            self.iMaxLen = len(max(self.aData, key=len))
            if (self.iMaxCharwidth * self.iMaxLen) > GL_MAX_TEXTURE_SIZE:
                self.iMaxCharsPerLine = int(GL_MAX_TEXTURE_SIZE /
                                            self.iMaxCharwidth)
                bDoLineBreak = True
            else:
                self.iMaxCharsPerLine = self.iMaxLen
        else:
            bDoLineBreak = True

        if bDoLineBreak:
            if self.oLabel is not None:
                if len(self.text) > 10000:
                    aData = self.text.split('\n')
                    i = 0
                    iEnd = len(aData)

                    while i < iEnd:
                        if len(aData[i]) > self.iMaxCharsPerLine:
                            aData.insert(i + 1,
                                         aData[i][self.iMaxCharsPerLine:])
                            aData[i] = aData[i][:self.iMaxCharsPerLine]
                            iEnd += 1
                        i += 1
                else:
                    self.oLabel.size = self.size
                    self.oLabel.text_size = (self.width, None)
                    self.oLabel.text = self.text
                    self.oLabel._label.render()
                    aData = []
                    for oLine in self.oLabel._label._cached_lines:
                        if len(oLine.words) > 0:
                            uText = u''
                            for oWord in oLine.words:
                                if self.bMarkup:
                                    uText += self.AddMarkUps(oWord)
                                else:
                                    uText += oWord.text
                            aData.append(uText)
                        else:
                            aData.append(u'')
                    self.oLabel.text = ""

            self.aData = aData
            self.SetData(aData)
        else:
            self.SetData(self.aData)

    def AddMarkUps(self, oWord):

        uText = oWord.text
        if oWord.options["bold"]:
            uText = self.AddMarkUp(uText, "b")
        if oWord.options["italic"]:
            uText = self.AddMarkUp(uText, "i")
        if oWord.options["underline"]:
            uText = self.AddMarkUp(uText, "u")
        if oWord.options["strikethrough"]:
            uText = self.AddMarkUp(uText, "s")
        if oWord.options["font_name"] != "Roboto":
            uText = self.AddMarkUp(uText, "font", oWord.options["font_name"])
        if oWord.options["font_size"] != self.fFontSize:
            uText = self.AddMarkUp(uText, "size",
                                   ToUnicode(oWord.options["font_size"]))

        if oWord.options["color"] != [1, 1, 1, 1]:
            uHexColor = u''
            for iColor in oWord.options["color"]:
                uHexColor += ToHex(int(iColor * 255))
            uText = self.AddMarkUp(uText, "color", '#' + uHexColor)

        return uText

    def AddMarkUp(self, uText, uMarkUp, uValue=None):
        if uValue is None:
            return "[{1}]{0}[/{1}]".format(uText, uMarkUp)
        else:
            return "[{1}={2}]{0}[/{1}]".format(uText, uMarkUp, uValue)