Documentation, fix names of focus methods.
--- a/docs/conf.py Mon Dec 17 21:07:59 2012 +0100
+++ b/docs/conf.py Mon Dec 17 23:19:58 2012 +0100
@@ -38,7 +38,7 @@
# General information about the project.
project = u'Tuikit'
-copyright = u'2011, Radek Brich'
+copyright = u'2011-2012, Radek Brich'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
--- a/docs/events.rst Mon Dec 17 21:07:59 2012 +0100
+++ b/docs/events.rst Mon Dec 17 23:19:58 2012 +0100
@@ -9,8 +9,8 @@
Normal widgets should implement only on_draw() method, which is called from draw().
-Keypress event, focus
----------------------
+Keypress event
+--------------
Keyboard events go in top down order, from top window to focused widget in each level. When implementing on_keypress method,
add super().on_keypress(). Anything before that will be executed in top down walk, anything after in bottom up. Return True if you want to stop
@@ -24,18 +24,26 @@
3 5 container
4 4 edit box
-Each container maintains its focus child and allows to cycle focus between children (See Container.focusnext). Focus cycling works throughout
+Focus
+-----
+
+Basics:
+ * Only one node in hierarchy can have focus.
+ * All parent containers have focus, so they can relay events to focused child.
+ * Top container has always focus.
+
+Each container maintains its focus child and allows to cycle focus between children (See Container.focus_next). Focus cycling works throughout
container levels - if focus was on last child and would go to the first, 'tab' key is not handled thus allowing parent level to cycle focus.
When focus changes, two events are generated: focus on new widget, unfocus on previous one.
Mousedown causes focus change when allowed (Widget.allow_focus).
- * tab key - change focus to next widget
- * shift-tab - previous widget (FIXME: not implemented)
+ * Use grab_focus() on widget to make it receive keyboard events. This will clean old focus and set focus to this child.
+ * Global shortcuts can be handled in keypress event from top widget. All keyboard events go through there.
+ * Tab key changes focus to next widget. Shift-tab changes back to previous widget (FIXME: not implemented).
+ * Hide on focused widget causes focus change like if tab key was pressed.
-Hide on focused widget causes focus change like if tab key was pressed.
-
-See Container.trapfocus, Widget.canfocus(), Widget.hasfocus(), Widget.setfocus() for more information.
+See Container.trap_focus, Widget.can_focus(), Widget.has_focus(), Widget.set_focus() for more information.
Other event propagation
--- a/docs/index.rst Mon Dec 17 21:07:59 2012 +0100
+++ b/docs/index.rst Mon Dec 17 23:19:58 2012 +0100
@@ -16,7 +16,6 @@
events
redraw
colors
- tableview
.. inheritance-diagram:: tuikit.application
tuikit.emitter
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/treeview.rst Mon Dec 17 23:19:58 2012 +0100
@@ -0,0 +1,23 @@
+TreeView
+========
+
+.. toctree::
+ :maxdepth: 3
+ :titlesonly:
+
+.. automodule:: tuikit.treeview
+ :members:
+ :show-inheritance:
+
+
+Path
+----
+The path may be string or list. Components are names or indexes.
+String path uses slash char as separator, names as components.
+
+Examples:
+ * '/'
+ * '/a/b/c'
+ * ['a', 'b', 'c']
+ * [0, 3, 1]
+
--- a/docs/widget.rst Mon Dec 17 21:07:59 2012 +0100
+++ b/docs/widget.rst Mon Dec 17 23:19:58 2012 +0100
@@ -7,6 +7,8 @@
container
button
+ treeview
+ tableview
.. autoclass:: tuikit.widget.Widget
:members:
--- a/tests/test_treeview.py Mon Dec 17 21:07:59 2012 +0100
+++ b/tests/test_treeview.py Mon Dec 17 23:19:58 2012 +0100
@@ -24,7 +24,7 @@
"""
self.model = TreeModel()
self.model.add('/', ['a', 'b'])
- self.model.add('/a', [TreeNode('c'), TreeNode('d')])
+ self.model.add(['a'], [TreeNode('c'), TreeNode('d')])
self.model.add((0,1), ['e', TreeNode('f')])
self.model.add([0,1,0], 'g')
self.model.add('/a/d/f', TreeNode('h'))
--- a/tuikit/button.py Mon Dec 17 21:07:59 2012 +0100
+++ b/tuikit/button.py Mon Dec 17 23:19:58 2012 +0100
@@ -79,7 +79,7 @@
def getcolor(self):
- if self.highlight or self.hasfocus():
+ if self.highlight or self.has_focus():
return self.bghi
return self.bg
--- a/tuikit/container.py Mon Dec 17 21:07:59 2012 +0100
+++ b/tuikit/container.py Mon Dec 17 23:19:58 2012 +0100
@@ -33,7 +33,7 @@
self.colorprefix = None
- self.trapfocus = False # if True, tab cycles inside container
+ self.trap_focus = False # if True, tab cycles inside container
def add(self, widget, **kw):
@@ -42,7 +42,7 @@
widget.parent = self
widget.settop(self.top)
widget.hints.update(kw)
- if self.focuschild is None and widget.canfocus():
+ if self.focuschild is None and widget.can_focus():
self.focuschild = widget
@@ -60,7 +60,24 @@
child.settop(top)
- def focusnext(self):
+ def focus_next(self):
+ """Focus next child.
+
+ Sets focus to next child, if there is one
+ which can be focused. Cycles from last child
+ to first when needed. Return value depends on
+ this cycling:
+
+ * False means there wasn't any child to focus
+ before end of list, so first child was focused.
+
+ * True when focus is set to next child in normal
+ way or when self.trap_focus is set.
+
+ Return value is supposed to be returned from keypress
+ event - in that case, True stops event propagation.
+
+ """
idx_current = self.children.index(self.focuschild)
idx_new = idx_current + 1
cycled = False
@@ -68,9 +85,9 @@
if idx_new >= len(self.children):
idx_new = 0
cycled = True
- if self.children[idx_new].canfocus():
- self.children[idx_new].setfocus()
- return self.trapfocus or not cycled
+ if self.children[idx_new].can_focus():
+ self.children[idx_new].set_focus()
+ return self.trap_focus or not cycled
idx_new += 1
def on_keypress(self, keyname, char):
@@ -80,7 +97,7 @@
if handled:
return True
if keyname == 'tab':
- return self.focusnext()
+ return self.focus_next()
def on_resize(self):
super().on_resize()
--- a/tuikit/menu.py Mon Dec 17 21:07:59 2012 +0100
+++ b/tuikit/menu.py Mon Dec 17 23:19:58 2012 +0100
@@ -93,8 +93,7 @@
self.emit('activate', self.selected[1])
elif isinstance(self.selected[1], Widget):
self.selected[1].show()
- self.selected[1].setfocus()
+ self.selected[1].set_focus()
else:
- self.menubar.resetfocus()
self.selected[1]()
--- a/tuikit/menubar.py Mon Dec 17 21:07:59 2012 +0100
+++ b/tuikit/menubar.py Mon Dec 17 23:19:58 2012 +0100
@@ -94,7 +94,7 @@
def on_submenu_focus(self):
- self.setfocus()
+ self.set_focus()
def select(self, item):
--- a/tuikit/treeview.py Mon Dec 17 21:07:59 2012 +0100
+++ b/tuikit/treeview.py Mon Dec 17 23:19:58 2012 +0100
@@ -7,6 +7,12 @@
class TreeIter:
+ """Iterates nodes under root in depth-first order.
+
+ This is useful for displaying the tree.
+
+ """
+
def __init__(self, root, collapsed=[]):
self._node = root
self._index = 0
@@ -42,6 +48,16 @@
class TreeNode:
+ """Node of tree.
+
+ Maintains its parent and children.
+
+ Attributes:
+ * name - used for searching
+ * title - this is displayed on screen
+
+ """
+
def __init__(self, name, title=None, parent=None, model=None):
self.model = model
self.children = []
@@ -60,12 +76,14 @@
@property
def path(self):
+ """Path of this node in model."""
if self.parent:
return self.parent.path + '/' + self.name
else:
return self.name
def add(self, node):
+ """Add child and connect it to self."""
node.parent = self
node.model = self.model
self.children.append(node)
@@ -73,6 +91,13 @@
class TreeModel(Emitter):
+ """Tree data model.
+
+ Tree model stores all nodes of tree but knows nothing about displaying them.
+ Same model can be used in many views.
+
+ """
+
def __init__(self):
self.add_events('node_added') # node added, arg is the node
self.root = TreeNode('', model=self)
@@ -144,6 +169,8 @@
class TreeView(Widget):
+ """Tree view displays data from tree model."""
+
def __init__(self, model=None, width=20, height=20):
Widget.__init__(self, width, height)
--- a/tuikit/widget.py Mon Dec 17 21:07:59 2012 +0100
+++ b/tuikit/widget.py Mon Dec 17 23:19:58 2012 +0100
@@ -127,7 +127,7 @@
self.emit('draw', driver, x, y)
- if self.hasfocus():
+ if self.has_focus():
if self.cursor:
cx, cy = self.cursor
driver.showcursor(x + cx, y + cy)
@@ -136,25 +136,36 @@
def on_mousedown(self, ev):
super().on_mousedown(ev)
- self.setfocus()
+ self.set_focus()
### focus
- def canfocus(self):
+ def can_focus(self):
return not self.hidden and self.allow_focus
- def hasfocus(self):
+ def has_focus(self):
if self.parent is None:
return True
- return (self.parent.hasfocus() \
+ return (self.parent.has_focus() \
and self.parent.focuschild == self)
- def setfocus(self):
- if self.hasfocus() or not self.canfocus():
+ def set_focus(self):
+ """Focus the widget.
+
+ This changes focus state of parent widget,
+ but it does not check if parent widget actually
+ has focus. It still works if it has not,
+ but keyboard events will go to really focused widget,
+ not this one.
+
+ See also grab_focus() which cares about parents.
+
+ """
+ if self.has_focus() or not self.can_focus():
return
if self.parent.focuschild:
self.parent.focuschild.emit('unfocus', self)
@@ -162,6 +173,13 @@
self.emit('focus')
+ def grab_focus(self):
+ """Focus the widget and its parents."""
+ self.set_focus()
+ if self.parent and not self.parent.has_focus():
+ self.parent.grab_focus()
+
+
###
def hint(self, key):
@@ -194,8 +212,8 @@
def hide(self):
'''Hide widget. Convenience method.'''
self.hidden = True
- if self.hasfocus():
- self.parent.focusnext()
+ if self.has_focus():
+ self.parent.focus_next()
self.redraw()