def calc_line_pos( text, line_layout, pref_col ): """ Calculate the closest linear position to pref_col given a line layout structure. Returns None if no position found. """ closest_sc = None closest_pos = None current_sc = 0 if pref_col == 'left': for seg in line_layout: s = LayoutSegment(seg) if s.offs is not None: return s.offs return elif pref_col == 'right': for seg in line_layout: s = LayoutSegment(seg) if s.offs is not None: closest_pos = s s = closest_pos if s is None: return if s.end is None: return s.offs return calc_text_pos( text, s.offs, s.end, s.sc-1)[0] for seg in line_layout: s = LayoutSegment(seg) if s.offs is not None: if s.end is not None: if (current_sc <= pref_col and pref_col < current_sc + s.sc): # exact match within this segment return calc_text_pos( text, s.offs, s.end, pref_col - current_sc )[0] elif current_sc <= pref_col: closest_sc = current_sc + s.sc - 1 closest_pos = s if closest_sc is None or ( abs(pref_col-current_sc) < abs(pref_col-closest_sc) ): # this screen column is closer closest_sc = current_sc closest_pos = s.offs if current_sc > closest_sc: # we're moving past break current_sc += s.sc if closest_pos is None or type(closest_pos) == type(0): return closest_pos # return the last positions in the segment "closest_pos" s = closest_pos return calc_text_pos( text, s.offs, s.end, s.sc-1)[0]
def html_span(s, aspec, cursor=-1): fg_r, fg_g, fg_b, bg_r, bg_g, bg_b = aspec.get_rgb_values() # use real colours instead of default fg/bg if fg_r is None: fg_r, fg_g, fg_b = _d_fg_r, _d_fg_g, _d_fg_b if bg_r is None: bg_r, bg_g, bg_b = _d_bg_r, _d_bg_g, _d_bg_b html_fg = "#%02x%02x%02x" % (fg_r, fg_g, fg_b) html_bg = "#%02x%02x%02x" % (bg_r, bg_g, bg_b) if aspec.standout: html_fg, html_bg = html_bg, html_fg extra = (";text-decoration:underline" * aspec.underline + ";font-weight:bold" * aspec.bold) def html_span(fg, bg, s): if not s: return "" return ('<span style="color:%s;' 'background:%s%s">%s</span>' % (fg, bg, extra, html_escape(s))) if cursor >= 0: c_off, _ign = util.calc_text_pos(s, 0, len(s), cursor) c2_off = util.move_next_char(s, c_off, len(s)) return (html_span(html_fg, html_bg, s[:c_off]) + html_span(html_bg, html_fg, s[c_off:c2_off]) + html_span(html_fg, html_bg, s[c2_off:])) else: return html_span(html_fg, html_bg, s)
def html_span(s, aspec, cursor = -1): fg_r, fg_g, fg_b, bg_r, bg_g, bg_b = aspec.get_rgb_values() # use real colours instead of default fg/bg if fg_r is None: fg_r, fg_g, fg_b = _d_fg_r, _d_fg_g, _d_fg_b if bg_r is None: bg_r, bg_g, bg_b = _d_bg_r, _d_bg_g, _d_bg_b html_fg = "#%02x%02x%02x" % (fg_r, fg_g, fg_b) html_bg = "#%02x%02x%02x" % (bg_r, bg_g, bg_b) if aspec.standout: html_fg, html_bg = html_bg, html_fg extra = (";text-decoration:underline" * aspec.underline + ";font-weight:bold" * aspec.bold) def html_span(fg, bg, s): if not s: return "" return ('<span style="color:%s;' 'background:%s%s">%s</span>' % (fg, bg, extra, html_escape(s))) if cursor >= 0: c_off, _ign = util.calc_text_pos(s, 0, len(s), cursor) c2_off = util.move_next_char(s, c_off, len(s)) return (html_span(html_fg, html_bg, s[:c_off]) + html_span(html_bg, html_fg, s[c_off:c2_off]) + html_span(html_fg, html_bg, s[c2_off:])) else: return html_span(html_fg, html_bg, s)
def __init__(self, fill_char, cols, rows): Canvas.__init__(self) end, col = calc_text_pos(fill_char, 0, len(fill_char), 1) assert col == 1, "Invalid fill_char: %r" % fill_char self._text, cs = apply_target_encoding(fill_char[:end]) self._cs = cs[0][0] self.size = cols, rows self.cursor = None
def _last_row(self, row): """On the last row we need to slide the bottom right character into place. Calculate the new line, attr and an insert sequence to do that. eg. last row: XXXXXXXXXXXXXXXXXXXXYZ Y will be drawn after Z, shifting Z into position. """ new_row = row[:-1] z_attr, z_cs, last_text = row[-1] last_cols = util.calc_width(last_text, 0, len(last_text)) last_offs, z_col = util.calc_text_pos(last_text, 0, len(last_text), last_cols-1) if last_offs == 0: z_text = last_text del new_row[-1] # we need another segment y_attr, y_cs, nlast_text = row[-2] nlast_cols = util.calc_width(nlast_text, 0, len(nlast_text)) z_col += nlast_cols nlast_offs, y_col = util.calc_text_pos(nlast_text, 0, len(nlast_text), nlast_cols-1) y_text = nlast_text[nlast_offs:] if nlast_offs: new_row.append((y_attr, y_cs, nlast_text[:nlast_offs])) else: z_text = last_text[last_offs:] y_attr, y_cs = z_attr, z_cs nlast_cols = util.calc_width(last_text, 0, last_offs) nlast_offs, y_col = util.calc_text_pos(last_text, 0, last_offs, nlast_cols-1) y_text = last_text[nlast_offs:last_offs] if nlast_offs: new_row.append((y_attr, y_cs, last_text[:nlast_offs])) new_row.append((z_attr, z_cs, z_text)) return new_row, z_col-y_col, (y_attr, y_cs, y_text)
def code_span(s, fg, bg, cursor=-1): code_fg = _code_colours[fg] code_bg = _code_colours[bg] if cursor >= 0: c_off, _ign = util.calc_text_pos(s, 0, len(s), cursor) c2_off = util.move_next_char(s, c_off, len(s)) return (code_fg + code_bg + s[:c_off] + "\n" + code_bg + code_fg + s[c_off:c2_off] + "\n" + code_fg + code_bg + s[c2_off:] + "\n") else: return code_fg + code_bg + s + "\n"
def code_span( s, fg, bg, cursor = -1): code_fg = _code_colours[ fg ] code_bg = _code_colours[ bg ] if cursor >= 0: c_off, _ign = util.calc_text_pos(s, 0, len(s), cursor) c2_off = util.move_next_char(s, c_off, len(s)) return ( code_fg + code_bg + s[:c_off] + "\n" + code_bg + code_fg + s[c_off:c2_off] + "\n" + code_fg + code_bg + s[c2_off:] + "\n") else: return code_fg + code_bg + s + "\n"
def html_span( s, fg, bg, cursor = -1): html_fg = _html_colours[ fg ] html_bg = _html_colours[ bg ] def html_span(fg, bg, s): if not s: return "" return '<span style="color:%s;background:%s">%s</span>' % \ (fg, bg, html_escape(s)) if cursor >= 0: c_off, _ign = util.calc_text_pos(s, 0, len(s), cursor) c2_off = util.move_next_char(s, c_off, len(s)) return (html_span(html_fg, html_bg, s[:c_off]) + html_span(html_bg, html_fg, s[c_off:c2_off]) + html_span(html_fg, html_bg, s[c2_off:])) else: return html_span(html_fg, html_bg, s)
def html_span(s, fg, bg, cursor=-1): html_fg = _html_colours[fg] html_bg = _html_colours[bg] def html_span(fg, bg, s): if not s: return "" return '<span style="color:%s;background:%s">%s</span>' % \ (fg, bg, html_escape(s)) if cursor >= 0: c_off, _ign = util.calc_text_pos(s, 0, len(s), cursor) c2_off = util.move_next_char(s, c_off, len(s)) return (html_span(html_fg, html_bg, s[:c_off]) + html_span(html_bg, html_fg, s[c_off:c2_off]) + html_span(html_fg, html_bg, s[c2_off:])) else: return html_span(html_fg, html_bg, s)
def calculate_text_segments( self, text, width, wrap ): """ Calculate the segments of text to display given width screen columns to display them. text - text to display width - number of available screen columns wrap - wrapping mode used Returns a layout structure without aligmnent applied. """ b = [] p = 0 if wrap == 'clip': # no wrapping to calculate, so it's easy. while p<=len(text): n_cr = text.find("\n", p) if n_cr == -1: n_cr = len(text) sc = calc_width(text, p, n_cr) l = [(0,n_cr)] if p!=n_cr: l = [(sc, p, n_cr)] + l b.append(l) p = n_cr+1 return b while p<=len(text): # look for next eligible line break n_cr = text.find("\n", p) if n_cr == -1: n_cr = len(text) sc = calc_width(text, p, n_cr) if sc == 0: # removed character hint b.append([(0,n_cr)]) p = n_cr+1 continue if sc <= width: # this segment fits b.append([(sc,p,n_cr), # removed character hint (0,n_cr)]) p = n_cr+1 continue pos, sc = calc_text_pos( text, p, n_cr, width ) # FIXME: handle pathological width=1 double-byte case if wrap == 'any': b.append([(sc,p,pos)]) p = pos continue assert wrap == 'space' if text[pos] == " ": # perfect space wrap b.append([(sc,p,pos), # removed character hint (0,pos)]) p = pos+1 continue if is_wide_char(text, pos): # perfect next wide b.append([(sc,p,pos)]) p = pos continue prev = pos while prev > p: prev = move_prev_char(text, p, prev) if text[prev] == " ": sc = calc_width(text,p,prev) l = [(0,prev)] if p!=prev: l = [(sc,p,prev)] + l b.append(l) p = prev+1 break if is_wide_char(text,prev): # wrap after wide char next = move_next_char(text, prev, pos) sc = calc_width(text,p,next) b.append([(sc,p,next)]) p = next break else: # unwrap previous line space if possible to # fit more text (we're breaking a word anyway) if b and (len(b[-1]) == 2 or ( len(b[-1])==1 and len(b[-1][0])==2 )): # look for removed space above if len(b[-1]) == 1: [(h_sc, h_off)] = b[-1] p_sc = 0 p_off = p_end = h_off else: [(p_sc, p_off, p_end), (h_sc, h_off)] = b[-1] if (p_sc < width and h_sc==0 and text[h_off] == " "): # combine with previous line del b[-1] p = p_off pos, sc = calc_text_pos( text, p, n_cr, width ) b.append([(sc,p,pos)]) # check for trailing " " or "\n" p = pos if p < len(text) and ( text[p] in (" ","\n")): # removed character hint b[-1].append((0,p)) p += 1 continue # force any char wrap b.append([(sc,p,pos)]) p = pos return b