Drop Container.offset, add special layout for that - OffsetLayout.
authorRadek Brich <radek.brich@devl.cz>
Sun, 20 Jan 2013 00:49:19 +0100
changeset 64 03f591f5fe5c
parent 63 2a0e04091898
child 65 5f0697950f15
Drop Container.offset, add special layout for that - OffsetLayout. Add Widget.bring_up(): moves child to end of children list.
demo_menu.py
demo_tableview.py
demo_treeview.py
tuikit/common.py
tuikit/container.py
tuikit/layout.py
tuikit/menubar.py
tuikit/scrollview.py
tuikit/tableview.py
tuikit/widget.py
--- a/demo_menu.py	Sat Jan 19 13:05:21 2013 +0100
+++ b/demo_menu.py	Sun Jan 20 00:49:19 2013 +0100
@@ -44,6 +44,8 @@
         menubtn = MenuButton('MenuButton', menu)
         self.top.add(menubtn, halign='center', valign='center')
 
+        helpwin.bring_up()
+
     def on_top_keypress(self, ev):
         if ev.keyname == 'escape':
             self.terminate()
--- a/demo_tableview.py	Sat Jan 19 13:05:21 2013 +0100
+++ b/demo_tableview.py	Sun Jan 20 00:49:19 2013 +0100
@@ -5,7 +5,6 @@
 locale.setlocale(locale.LC_ALL, '')
 
 from tuikit import Application
-from tuikit.layout import VerticalLayout
 from tuikit.tableview import TableView, TableModel
 
 
@@ -27,9 +26,7 @@
         for x in range(10):
             view.addcolumn(title='head'+str(x))
 
-        self.top.add(view, expand=True, fill=True)
-
-        self.top.layout = VerticalLayout()
+        self.top.add(view, halign='fill', valign='fill')
 
     def on_top_keypress(self, ev):
         if ev.keyname == 'escape':
--- a/demo_treeview.py	Sat Jan 19 13:05:21 2013 +0100
+++ b/demo_treeview.py	Sun Jan 20 00:49:19 2013 +0100
@@ -4,12 +4,12 @@
 import locale
 locale.setlocale(locale.LC_ALL, '')
 
-from tuikit import Application, TreeView, TreeModel, ScrollView, VerticalLayout
+from tuikit import Application, TreeView, TreeModel, ScrollView
 
 
 class MyApplication(Application):
     def __init__(self):
-        Application.__init__(self, top_layout=VerticalLayout)
+        Application.__init__(self)
         self.top.add_handler('keypress', self.on_top_keypress)
 
         model = TreeModel()
@@ -27,7 +27,7 @@
 
         scroll = ScrollView()
         scroll.add(view)
-        self.top.add(scroll, expand=True, fill=True)
+        self.top.add(scroll, halign='fill', valign='fill')
 
     def on_top_keypress(self, ev):
         if ev.keyname == 'escape':
--- a/tuikit/common.py	Sat Jan 19 13:05:21 2013 +0100
+++ b/tuikit/common.py	Sun Jan 20 00:49:19 2013 +0100
@@ -34,13 +34,32 @@
     return type(name, (Select,), {'_options': args})
 
 
-class Coords:
+class Coords(Emitter):
 
     '''2D coordinates.'''
 
     def __init__(self, x=0, y=0):
-        self.x = x
-        self.y = y
+        self._x = x
+        self._y = y
+        self.add_events('change', Event)
+
+    @property
+    def x(self):
+        return self._x
+
+    @x.setter
+    def x(self, value):
+        self._x = value
+        self.emit('change')
+
+    @property
+    def y(self):
+        return self._y
+
+    @y.setter
+    def y(self, value):
+        self._y = value
+        self.emit('change')
 
     def __getitem__(self, key):
         try:
@@ -60,6 +79,7 @@
         return 'Coords(x={0.x},y={0.y})'.format(self)
 
     def update(self, x=None, y=None):
+        old_x, old_y = self._x, self._y
         if isinstance(x, Coords) and y is None:
             self.x, self.y = x
         else:
@@ -71,6 +91,8 @@
                 self.y = y
             elif y is not None:
                 raise ValueError('Coords.update(): second parameter must be int')
+        if self._x != old_x or self._y != old_y:
+            self.emit('change')
 
 
 class Size(Emitter):
--- a/tuikit/container.py	Sat Jan 19 13:05:21 2013 +0100
+++ b/tuikit/container.py	Sun Jan 20 00:49:19 2013 +0100
@@ -17,9 +17,6 @@
         self.children = []
         self._hint_class = {}
 
-        #: Offset for child widgets
-        self.offset = Coords()
-
         self.focuschild = None
         self.mousechild = None
 
@@ -61,6 +58,11 @@
         for hint_name, hint_class in zip(hints[::2], hints[1::2]):
             self._hint_class[hint_name] = hint_class
 
+    def bring_up_child(self, child):
+        if child in self.children:
+            self.children.remove(child)
+            self.children.append(child)
+
     @property
     def layout(self):
         return self._layout
@@ -100,7 +102,10 @@
         event - in that case, True stops event propagation.
 
         """
-        idx_current = self.children.index(self.focuschild)
+        if self.focuschild is None:
+            idx_current = 0
+        else:
+            idx_current = self.children.index(self.focuschild)
         idx_new = idx_current
         cycled = False
         while True:
@@ -150,8 +155,8 @@
 
         for child in [ch for ch in self.children if not ch.floater]:
             child.draw(driver,
-                x + self.offset.x + child.x,
-                y + self.offset.y + child.y)
+                x + child.x,
+                y + child.y)
 
         driver.clipstack.pop()
 
@@ -168,13 +173,13 @@
         # draw our floaters
         for child in [ch for ch in self.children if ch.floater]:
             child.draw(driver,
-                x + self.offset.x + child.x,
-                y + self.offset.y + child.y)
+                x + child.x,
+                y + child.y)
         # delve into child containers, draw their floaters
         for child in [ch for ch in self.children if not ch.floater and isinstance(ch, Container)]:
             child.draw_floaters(driver,
-                x + self.offset.x + child.x,
-                y + self.offset.y + child.y)
+                x + child.x,
+                y + child.y)
 
     def on_resize(self, ev):
         for child in self.children:
@@ -221,7 +226,7 @@
             if self.floaters_mouse_event(ev):
                 return True
         for child in reversed([ch for ch in self.children if not ch.floater]):
-            if child.enclose(ev.wx - self.offset.x, ev.wy - self.offset.y):
+            if child.enclose(ev.wx, ev.wy):
                 child_ev = ev.make_child_event(self, child)
                 child.emit(ev.event_name, child_ev)
                 if ev.event_name == 'mousedown':
@@ -241,7 +246,7 @@
                 return True
         # test our floaters
         for child in reversed([ch for ch in self.children if ch.floater]):
-            if child.enclose(ev.wx - self.offset.x, ev.wy - self.offset.y):
+            if child.enclose(ev.wx, ev.wy):
                 child_ev = ev.make_child_event(self, child)
                 child.emit(ev.event_name, child_ev)
                 if ev.event_name == 'mousedown':
--- a/tuikit/layout.py	Sat Jan 19 13:05:21 2013 +0100
+++ b/tuikit/layout.py	Sun Jan 20 00:49:19 2013 +0100
@@ -186,6 +186,36 @@
         self._resize(ax1, ax2)
 
 
+class OffsetLayout(Layout):
+
+    """Offsets widget position, useful for scrollable area."""
+
+    def __init__(self):
+        Layout.__init__(self)
+        self._offset = Coords()
+        self._offset.add_handler('change', lambda ev: self._update_children_position())
+        self.register_hints('position', Coords)
+
+    @property
+    def offset(self):
+        """Offset of child widgets."""
+        return self._offset
+
+    def on_resize(self, ev):
+        for child in self._get_children():
+            w, h = child.sizereq
+            child._size.update(w=w, h=h)
+
+    def move_child(self, child, x, y):
+        child.hints('position').update(x, y)
+
+    def _update_children_position(self):
+        ox, oy = self._offset
+        for child in self.children:
+            x, y = child.hints['position']
+            child._pos.update(x=x+ox, y=y+oy)
+
+
 class GridLayout(Layout):
     def __init__(self, numcols=2):
         Layout.__init__(self)
--- a/tuikit/menubar.py	Sat Jan 19 13:05:21 2013 +0100
+++ b/tuikit/menubar.py	Sun Jan 20 00:49:19 2013 +0100
@@ -22,6 +22,12 @@
         widget.move(0, 1)
         widget.hide()
 
+    def on_keypress(self, ev):
+        if ev.keyname == 'escape':
+            if not self.menu.hidden:
+                self.menu.hide()
+                return True
+
     def on_click(self, ev):
         self.menu.show()
 
@@ -76,7 +82,4 @@
             return res
         elif ev.keyname == 'down':
             return self.focuschild.show_menu()
-        elif menu_visible and ev.keyname == 'escape':
-            self.focuschild.menu.hide()
-            return True
 
--- a/tuikit/scrollview.py	Sat Jan 19 13:05:21 2013 +0100
+++ b/tuikit/scrollview.py	Sun Jan 20 00:49:19 2013 +0100
@@ -1,10 +1,11 @@
 # -*- coding: utf-8 -*-
 
-from tuikit.container import Container
+from tuikit.layout import AnchorLayout, OffsetLayout
 from tuikit.scrollbar import VScrollbar
+from tuikit.common import Borders
 
 
-class ScrollView(Container):
+class ScrollView(AnchorLayout):
     """Scrolling view
 
     Shows scrollbars when needed.
@@ -13,50 +14,47 @@
     """
 
     def __init__(self):
-        Container.__init__(self)
+        AnchorLayout.__init__(self)
         self._default_size.update(20, 20)
 
+        self.inner = OffsetLayout()
+        AnchorLayout.add(self, self.inner, halign='fill', valign='fill', margin=Borders(r=1))
+
         self.vscroll = VScrollbar()
         self.vscroll.add_handler('change', self._on_vscroll_change)
-        self.vscroll.evade_layout = 2
-        self.add(self.vscroll)
+        AnchorLayout.add(self, self.vscroll, halign='right', valign='fill')
 
     def add(self, widget, **kwargs):
-        Container.add(self, widget, **kwargs)
-        if widget != self.vscroll:
-            widget.add_handler('sizereq', self._on_child_sizereq)
-            widget.add_handler('spotmove', self._on_child_spotmove)
+        self.inner.add(widget, **kwargs)
+        widget.add_handler('sizereq', self._on_child_sizereq)
+        widget.add_handler('spotmove', self._on_child_spotmove)
 
     def on_resize(self, ev):
-        self.vscroll.move(x = self.size.w - 1)
-        self.vscroll.resize(h = self.height)
         self._update_vscroll_max()
 
     def _on_vscroll_change(self, ev):
-        self.offset.y = - self.vscroll.pos
+        self.inner.offset.y = - self.vscroll.scroll_pos
 
     def _on_child_sizereq(self, ev):
         self._update_vscroll_max()
 
     def _on_child_spotmove(self, ev):
         child = ev.originator
-        spot = child.y + child.spot.y
-        if spot < self.vscroll.pos:
-            self.vscroll.pos = spot
-        if spot > (self.size.h - 1) + self.vscroll.pos:
-            self.vscroll.pos = spot - (self.size.h - 1)
+        spot = child.y - self.inner.offset.y + child.spot.y
+        if spot < self.vscroll.scroll_pos:
+            self.vscroll.scroll_pos = spot
+        if spot > (self.height - 1) + self.vscroll.scroll_pos:
+            self.vscroll.scroll_pos = spot - (self.height - 1)
 
     def _update_vscroll_max(self):
         max_height = 0
-        for child in self.children:
-            if child == self.vscroll:
-                continue
-            child_height = child.x + child.sizereq.h
+        for child in self.inner.children:
+            child_height = child.y - self.inner.offset.y + child.sizereq.h
             if child_height > max_height:
                 max_height = child_height
-        if max_height < self.size.h:
+        if max_height < self.height:
             self.vscroll.hide()
         else:
-            self.vscroll.max = max_height - self.size.h
+            self.vscroll.scroll_max = max_height - self.height
             self.vscroll.show()
 
--- a/tuikit/tableview.py	Sat Jan 19 13:05:21 2013 +0100
+++ b/tuikit/tableview.py	Sun Jan 20 00:49:19 2013 +0100
@@ -64,8 +64,9 @@
 
 
 class TableView(Widget):
-    def __init__(self, model=None, width=20, height=20):
-        Widget.__init__(self, width, height)
+    def __init__(self, model=None):
+        Widget.__init__(self)
+        self._default_size.update(20, 20)
 
         self.allow_focus = True
 
@@ -79,8 +80,8 @@
         self.headsize = 1
 
         self.offset = Coords()
+        #: Active cell (cursor)
         self.acell = Coords()
-        '''Active cell (cursor).'''
 
         self.add_events(
             'scroll', Event,
@@ -106,7 +107,7 @@
             self.columns.append(col)
 
     def compute_column_sizes(self):
-        total_space = self.size.w - self.spacing * len(self.columns)
+        total_space = self.width - self.spacing * len(self.columns)
         no_expand_cols = [col for col in self.columns if not col.expand]
         no_expand_size = sum([col.sizereq for col in no_expand_cols])
         expand_cols = [col for col in self.columns if col.expand]
@@ -161,7 +162,7 @@
     def on_draw(self, ev):
         ev.driver.pushcolor('normal')
         self.rowcount = self.model.getcount()
-        numrows = min(self.rowcount - self.offset.y, self.size.h - self.headsize)
+        numrows = min(self.rowcount - self.offset.y, self.height - self.headsize)
         rows = self.model.getrows(self.offset.y, self.offset.y + numrows)
         self.compute_column_sizes()
         self.draw_head(ev.driver, ev.x, ev.y)
--- a/tuikit/widget.py	Sat Jan 19 13:05:21 2013 +0100
+++ b/tuikit/widget.py	Sun Jan 20 00:49:19 2013 +0100
@@ -89,7 +89,7 @@
     def y(self):
         return self._pos.y
 
-    def move(self, x, y):
+    def move(self, x=None, y=None):
         if self.floater:
             self._pos.update(x, y)
         if self.parent:
@@ -263,6 +263,10 @@
         self.hidden = False
         self.redraw()
 
+    def bring_up(self):
+        if self.parent:
+            self.parent.bring_up_child(self)
+
 
     ## timeout ##