# HG changeset patch # User Radek Brich # Date 1357123716 -3600 # Node ID d77f1ae3786c8351e8a5ec7874b712acfe8eb19b # Parent 369c8ef5070aa919acfab919d8839abf5f300f81 Add Widget.spot property. TreeView: move spot with cursor node. ScrollView: scroll when spot moves. diff -r 369c8ef5070a -r d77f1ae3786c tuikit/scrollview.py --- a/tuikit/scrollview.py Wed Jan 02 00:16:12 2013 +0100 +++ b/tuikit/scrollview.py Wed Jan 02 11:48:36 2013 +0100 @@ -8,8 +8,7 @@ """Scrolling view Shows scrollbars when needed. - Scrolling area is determined based on child widgets - size request. + Scrolling area is determined according to child widget's size request. """ @@ -25,6 +24,7 @@ super().add(widget, **kwargs) if widget != self.vscroll: widget.connect('sizereq', self._on_child_sizereq) + widget.connect('spotmove', self._on_child_spotmove) def _handle_resize(self, ev): super()._handle_resize(ev) @@ -38,6 +38,14 @@ 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) + def _update_vscroll_max(self): max_height = 0 for child in self.children: diff -r 369c8ef5070a -r d77f1ae3786c tuikit/treeview.py --- a/tuikit/treeview.py Wed Jan 02 00:16:12 2013 +0100 +++ b/tuikit/treeview.py Wed Jan 02 11:48:36 2013 +0100 @@ -17,17 +17,17 @@ """ - def __init__(self, root, collapsed=[]): + def __init__(self, root, collapsed_nodes=[]): self._node = root self._index = 0 self._stack = [] - self._collapsed = collapsed + self._collapsed_nodes = collapsed_nodes def __next__(self): node = None while node is None: try: - if self._node in self._collapsed: + if self._node in self._collapsed_nodes: raise IndexError() node = self._node.children[self._index] if node is None: @@ -177,16 +177,15 @@ def __init__(self, model=None, width=20, height=20): Widget.__init__(self, width, height) - self.allow_focus = True - # cursor - self.cnode = None - # model self._model = None - self.collapsed = [] + # cursor + self._cursor_node = None + + self.collapsed_nodes = [] self.add_events( 'expand', TreeEvent, # node expanded, event carries the affected node @@ -196,7 +195,7 @@ self.model = model def __iter__(self): - return TreeIter(self._model.root, self.collapsed) + return TreeIter(self._model.root, self.collapsed_nodes) @property def model(self): @@ -211,29 +210,38 @@ if self._model: self._model.connect('node_added', self.on_model_node_added) try: - self.cnode = self._model.root.children[0] + self.cursor_node = self._model.root.children[0] except IndexError: pass self._update_sizereq() def on_model_node_added(self, ev): - if self.cnode is None: - self.cnode = ev.node + if self.cursor_node is None: + self.cursor_node = ev.node self._update_sizereq() self.redraw() + @property + def cursor_node(self): + return self._cursor_node + + @cursor_node.setter + def cursor_node(self, value): + self._cursor_node = value + self._update_spot() + def collapse(self, path, collapse=True): node = self._model.find(path) self.collapse_node(node, collapse) def collapse_node(self, node, collapse=True): if collapse: - if not node in self.collapsed and len(node.children) > 0: - self.collapsed.append(node) + if not node in self.collapsed_nodes and len(node.children) > 0: + self.collapsed_nodes.append(node) self.emit('collapse', node) else: try: - self.collapsed.remove(node) + self.collapsed_nodes.remove(node) self.emit('expand', node) except ValueError: pass @@ -262,12 +270,12 @@ lines &= ~(1 << level-1) # draw lines and titles head = ''.join(head) - if node in self.collapsed: + if node in self.collapsed_nodes: sep = '+' else: sep = ' ' ev.driver.puts(ev.x, y, head + sep + str(node)) - if node is self.cnode: + if node is self.cursor_node: ev.driver.pushcolor('active') ev.driver.puts(ev.x + len(head), y, sep + str(node) + ' ') ev.driver.popcolor() @@ -291,7 +299,7 @@ i = parent.children.index(node) if i > 0: node = parent.children[i-1] - while node not in self.collapsed and len(node.children) > 0: + while node not in self.collapsed_nodes and len(node.children) > 0: node = node.children[-1] return node else: @@ -300,7 +308,7 @@ return parent def next_node(self, node): - if node in self.collapsed or len(node.children) == 0: + if node in self.collapsed_nodes or len(node.children) == 0: # next sibling parent = node.parent while parent is not None: @@ -315,24 +323,24 @@ return node.children[0] def move_up(self): - prev = self.prev_node(self.cnode) + prev = self.prev_node(self.cursor_node) if prev is not None: - self.cnode = prev + self.cursor_node = prev return True return False def move_down(self): - node = self.next_node(self.cnode) + node = self.next_node(self.cursor_node) if node is not None: - self.cnode = node + self.cursor_node = node return True return False def move_left(self): - self.collapse_node(self.cnode, True) + self.collapse_node(self.cursor_node, True) def move_right(self): - self.collapse_node(self.cnode, False) + self.collapse_node(self.cursor_node, False) def _update_sizereq(self): height = 0 @@ -340,3 +348,11 @@ height = num self.sizereq.h = height + def _update_spot(self): + """Update spot to current position of cursor node.""" + for num, (_level, _index, _count, node) in enumerate(self): + if node is self.cursor_node: + self._spot.x = _level * 2 + self._spot.y = num + self.emit('spotmove') + diff -r 369c8ef5070a -r d77f1ae3786c tuikit/widget.py --- a/tuikit/widget.py Wed Jan 02 00:16:12 2013 +0100 +++ b/tuikit/widget.py Wed Jan 02 11:48:36 2013 +0100 @@ -50,24 +50,30 @@ #: Hidden widget does not affect layout. self.hidden = False - # cursor + #: Cursor is position where text input will occur, + #: i.e. classic blinking cursor in console. + #: None means no cursor (hidden). self.cursor = None + # See spot property. + self._spot = Coords() + # redraw request self._redraw = True # event handlers self.add_events( 'resize', Event, - 'sizereq', Event, 'draw', DrawEvent, - 'focus', FocusEvent, - 'unfocus', FocusEvent, 'keypress', KeyboardEvent, 'mousedown', MouseEvent, 'mouseup', MouseEvent, 'mousemove', MouseEvent, - 'mousewheel', MouseEvent) + 'mousewheel', MouseEvent, + 'sizereq', Event, + 'spotmove', Event, + 'focus', FocusEvent, + 'unfocus', FocusEvent) @property @@ -116,6 +122,17 @@ return self._sizereq @property + def spot(self): + """Spot of visibility. + + This is one point which should be always visible. + It affects scrolling (moving spot in widget placed in ScrollView scrolls the view). + + """ + return self._spot + + + @property def top(self): """Top widget (same for every widget in one application).""" return self._top