def __init__(self, text=None, attr=None, cs=None, cursor=None, maxcol=None, check_width=True): """ text -- list of strings, one for each line attr -- list of run length encoded attributes for text cs -- list of run length encoded character set for text cursor -- (x,y) of cursor or None maxcol -- screen columns taken by this canvas check_width -- check and fix width of all lines in text """ Canvas.__init__(self) if text == None: text = [] if check_width: widths = [] for t in text: if type(t) != bytes: raise CanvasError("Canvas text must be plain strings encoded in the screen's encoding", repr(text)) widths.append( calc_width( t, 0, len(t)) ) else: assert type(maxcol) == int widths = [maxcol] * len(text) if maxcol is None: if widths: # find maxcol ourselves maxcol = max(widths) else: maxcol = 0 if attr == None: attr = [[] for x in range(len(text))] if cs == None: cs = [[] for x in range(len(text))] # pad text and attr to maxcol for i in range(len(text)): w = widths[i] if w > maxcol: raise CanvasError("Canvas text is wider than the maxcol specified \n%r\n%r\n%r"%(maxcol,widths,text)) if w < maxcol: text[i] = text[i] + bytes().rjust(maxcol-w) a_gap = len(text[i]) - rle_len( attr[i] ) if a_gap < 0: raise CanvasError("Attribute extends beyond text \n%r\n%r" % (text[i],attr[i]) ) if a_gap: rle_append_modify( attr[i], (None, a_gap)) cs_gap = len(text[i]) - rle_len( cs[i] ) if cs_gap < 0: raise CanvasError("Character Set extends beyond text \n%r\n%r" % (text[i],cs[i]) ) if cs_gap: rle_append_modify( cs[i], (None, cs_gap)) self._attr = attr self._cs = cs self.cursor = cursor self._text = text self._maxcol = maxcol
def test_rle_append(self): rle0 = [('A', 10), ('B', 15)] rle3, rle4 = rle0[:], rle0[:] util.rle_append_modify(rle3, ('B', 5)) util.rle_append_modify(rle4, ('K', 1)) self.assertListEqual(rle3, [('A', 10), ('B', 20)]) self.assertListEqual(rle4, [('A', 10), ('B', 15), ('K', 1)])
def attrrange( start_offs, end_offs, destw ): """ Add attributes based on attributes between start_offs and end_offs. """ if start_offs == end_offs: [(at,run)] = arange(start_offs,end_offs) rle_append_modify( linea, ( at, destw )) return if destw == end_offs-start_offs: for at, run in arange(start_offs,end_offs): rle_append_modify( linea, ( at, run )) return # encoded version has different width o = start_offs for at, run in arange(start_offs, end_offs): if o+run == end_offs: rle_append_modify( linea, ( at, destw )) return tseg = text[o:o+run] tseg, cs = apply_target_encoding( tseg ) segw = rle_len(cs) rle_append_modify( linea, ( at, segw )) o += run destw -= segw
def render(self, size, focus=False): # Build a view of the architecture viewport = [] attrs = [] map = self.dungeon.current_floor maxcol, maxrow = size top, left = 0, 0 # TODO actually compute the offset more cleverly here :) # TODO optimize me more?? somehow? for screen_row in range(maxrow): viewport_chars = [] attr_row = [] if screen_row < top or screen_row >= map.size.rows + top: # Outside the bounds of the map; just show blank space self._render_padding(maxcol, chars=viewport_chars, attrs=attr_row) viewport.append(b''.join(viewport_chars)) attrs.append(attr_row) continue # Blank space for the left padding self._render_padding(left, chars=viewport_chars, attrs=attr_row) for col in range(map.size.cols): pos = Position(screen_row - top, col) char, palette = rendering_for(map.tile(pos).topmost) # XXX this is getting way inefficient man; surely a better approach encoded_char = char.encode(urwid.util._target_encoding) viewport_chars.append(encoded_char) rle_append_modify(attr_row, (palette, len(encoded_char))) # Blank space for the right padding self._render_padding((maxcol - map.size.cols - left), chars=viewport_chars, attrs=attr_row) viewport.append(b''.join(viewport_chars)) attrs.append(attr_row) map_canv = urwid.TextCanvas(viewport, attr=attrs) return map_canv
def _render_padding(self, width, chars, attrs): if not width: return encoded_char = (self.empty_char * width).encode(urwid.util._target_encoding) chars.append(encoded_char) rle_append_modify(attrs, (None, len(encoded_char)))