# HG changeset patch # User Radek Brich # Date 1395999869 -3600 # Node ID e50dae408fe9d2d6a2886cb55983a8d026b49b48 # Parent c1e79acb9fcbcbe986e10c9cb5781d6f37621069 Add origin to Buffer. Use it to simplify hierarchical drawing. diff -r c1e79acb9fcb -r e50dae408fe9 tuikit/core/buffer.py --- a/tuikit/core/buffer.py Thu Mar 27 08:03:51 2014 +0100 +++ b/tuikit/core/buffer.py Fri Mar 28 10:44:29 2014 +0100 @@ -1,5 +1,5 @@ from tuikit.core.signal import Signal -from tuikit.core.coords import Size, Rect +from tuikit.core.coords import Point, Size, Rect from tuikit.core.theme import default_theme from contextlib import contextmanager @@ -93,6 +93,7 @@ @property def clip_rect(self): + """Return clipping rectangle in buffer coordinates.""" try: return self._clip_rect except AttributeError: @@ -125,7 +126,42 @@ self.clip_rect = original_rect -class Buffer(BufferOperationsMixin, BufferClippingMixin): +class BufferOriginMixin: + + @property + def origin(self): + """Origin coordinates for `putch`. + + Drawing is relative to origin. + + """ + try: + return self._origin + except AttributeError: + self._origin = Point(0, 0) + return self._origin + + @origin.setter + def origin(self, value): + self.origin.update(value) + + def reset_origin(self): + self.origin.update(0, 0) + + def move_origin(self, relx, rely): + self.origin.move(relx, rely) + + @contextmanager + def moved_origin(self, relx, rely): + ox, oy = self.origin + try: + self.origin.move(relx, rely) + yield + finally: + self.origin.update(ox, oy) + + +class Buffer(BufferOperationsMixin, BufferClippingMixin, BufferOriginMixin): """Rectangular character buffer. @@ -145,6 +181,7 @@ @property def size(self): + """Width and height of buffer, in characters.""" return self._size.readonly() def resize(self, w, h): @@ -182,12 +219,18 @@ self._current_attr = attr def putch(self, x, y, ch): - """Set character on xy coords to c.""" + """Set character on `x`, `y` coords to `ch`. + + Coords are adjusted by origin. + + """ + x += self.origin.x + y += self.origin.y if self.testxy(x, y): self._data[y * self._size.w + x].set(ch, self._current_attr) -class ProxyBuffer(BufferOperationsMixin, BufferClippingMixin): +class ProxyBuffer(BufferOperationsMixin, BufferClippingMixin, BufferOriginMixin): """Special buffer which proxies the operations to another buffer or buffer-like class.""" @@ -223,7 +266,13 @@ self.target.setattr(attr_desc) def putch(self, x, y, ch): - """Set character on xy coords to c.""" + """Set character on `x`, `y` coords to `ch`. + + Coords are adjusted by origin. + + """ + x += self.origin.x + y += self.origin.y if self.testxy(x, y): self.target.putch(x, y, ch) diff -r c1e79acb9fcb -r e50dae408fe9 tuikit/core/container.py --- a/tuikit/core/container.py Thu Mar 27 08:03:51 2014 +0100 +++ b/tuikit/core/container.py Fri Mar 28 10:44:29 2014 +0100 @@ -28,13 +28,14 @@ Widget.resize(self, w, h) self.layout.resize() - def draw(self, buffer, x=0, y=0): + def draw(self, buffer): """Draw child widgets.""" + Widget.draw(self, buffer) for child in self.children: - cx = x + child.x - cy = y + child.y - with buffer.clip(cx, cy, child.width, child.height): - child.draw(buffer, cx, cy) + with buffer.moved_origin(child.x, child.y): + with buffer.clip(buffer.origin.x, buffer.origin.y, + child.width, child.height): + child.draw(buffer) def set_theme(self, theme): Widget.set_theme(self, theme) diff -r c1e79acb9fcb -r e50dae408fe9 tuikit/core/coords.py --- a/tuikit/core/coords.py Thu Mar 27 08:03:51 2014 +0100 +++ b/tuikit/core/coords.py Fri Mar 28 10:44:29 2014 +0100 @@ -16,6 +16,13 @@ def __repr__(self): return 'Point(x={0.x},y={0.y})'.format(self) + def move(self, relx, rely): + self.x += relx + self.y += rely + + def moved(self, relx, rely): + return Point(self.x + relx, self.y + rely) + def update(self, *args, **kwargs): """Update point. @@ -129,6 +136,10 @@ return (self.x <= x < self.x + self.w and self.y <= y < self.y + self.h) + def moved(self, relx, rely): + """Return new Rect with same size, moved by `relx`, `rely`.""" + return Rect(self.x + relx, self.y + rely, self.w, self.h) + def intersect(self, other): x1 = max(self.x, other.x) y1 = max(self.y, other.y) diff -r c1e79acb9fcb -r e50dae408fe9 tuikit/core/widget.py --- a/tuikit/core/widget.py Thu Mar 27 08:03:51 2014 +0100 +++ b/tuikit/core/widget.py Fri Mar 28 10:44:29 2014 +0100 @@ -1,6 +1,8 @@ from tuikit.core.coords import Point, Size from tuikit.core.theme import default_theme +import logging + class Widget: @@ -9,8 +11,10 @@ _num_instances = 0 def __init__(self): + self._num_instances += 1 + self._log = logging.getLogger(__name__) + #: Widget name is used for logging etc. Not visible anywhere. - self._num_instances += 1 self.name = '{}{}'.format( self.__class__.__name__, self._num_instances) @@ -60,14 +64,28 @@ def resize(self, w, h): self._size.update(w, h) - ## appearance ## + ## drawing, looks ## - def draw(self, buffer, x, y): - pass + def draw(self, buffer): + """Draw self into buffer.""" + self._log.debug('%s draw into %r at %s (exposed %s)', + self.name, buffer, buffer.origin, self.exposed(buffer)) def set_theme(self, theme): self.theme = theme + @staticmethod + def exposed(buffer): + """Exposed part of widget. + + Only this area needs to be drawn. + + Returns exposed Rect in widget's local coordinates, + where 0,0 is left top corner of widget to be drawn. + + """ + return buffer.clip_rect.moved(-buffer.origin.x, -buffer.origin.y) + ## timeouts ## def add_timeout(self, delay, callback, *args): diff -r c1e79acb9fcb -r e50dae408fe9 tuikit/core/window.py --- a/tuikit/core/window.py Thu Mar 27 08:03:51 2014 +0100 +++ b/tuikit/core/window.py Fri Mar 28 10:44:29 2014 +0100 @@ -38,13 +38,14 @@ self.redraw() def redraw(self): + self.buffer.reset_origin() Container.draw(self, self.buffer) self.buffer.puts(10, 5, '{0.w} {0.h}'.format(self.size)) self.buffer.frame() - def draw(self, buffer, x=0, y=0): - """Draw this window into `buffer` at x/y coords.""" - buffer.draw(self.buffer, x, y) + def draw(self, buffer): + """Draw this window into `buffer`.""" + buffer.draw(self.buffer) class WindowManager(Container): diff -r c1e79acb9fcb -r e50dae408fe9 tuikit/widgets/button.py --- a/tuikit/widgets/button.py Thu Mar 27 08:03:51 2014 +0100 +++ b/tuikit/widgets/button.py Fri Mar 28 10:44:29 2014 +0100 @@ -51,24 +51,25 @@ return self.color_highlighted return self.color - def draw(self, buffer, x, y): + def draw(self, buffer): + Widget.draw(self, buffer) pad = self.width - len(self.label) - len(self.prefix) - len(self.suffix) lpad, rpad = self._divide_padding(pad) with buffer.attr(self._get_color()): # prefix - buffer.puts(x, y, self.prefix) + buffer.puts(0, 0, self.prefix) pos = len(self.prefix) # left pad - buffer.puts(x + pos, y, ' ' * lpad) + buffer.puts(pos, 0, ' ' * lpad) pos += lpad # label - buffer.puts(x + pos, y, self.label) + buffer.puts(pos, 0, self.label) pos += len(self.label) # right pad - buffer.puts(x + pos, y, ' ' * rpad) + buffer.puts(pos, 0, ' ' * rpad) pos += rpad # suffix - buffer.puts(x + pos, y, self.suffix) + buffer.puts(pos, 0, self.suffix) def on_mousedown(self, ev): self.highlight = True diff -r c1e79acb9fcb -r e50dae408fe9 tuikit/widgets/label.py --- a/tuikit/widgets/label.py Thu Mar 27 08:03:51 2014 +0100 +++ b/tuikit/widgets/label.py Fri Mar 28 10:44:29 2014 +0100 @@ -12,6 +12,6 @@ def set_theme(self, theme): self.color = self.theme.normal - def draw(self, buffer, x, y): + def draw(self, buffer): with buffer.attr(self.color): - buffer.puts(x, y, self.label) + buffer.puts(0, 0, self.label)