|
@@ -38,15 +38,21 @@ class Node(object):
|
|
|
return selected_nodes
|
|
|
|
|
|
def get_label(self, active_root):
|
|
|
- return 'node'
|
|
|
+ return ''
|
|
|
+
|
|
|
+ def _clear_children(self):
|
|
|
+ self._children = []
|
|
|
|
|
|
def get_children(self):
|
|
|
return self._children
|
|
|
|
|
|
- def append_child(self, child):
|
|
|
+ def _append_child(self, child):
|
|
|
child._parent = self
|
|
|
self._children.append(child)
|
|
|
|
|
|
+ def get_header_height(self):
|
|
|
+ return 0
|
|
|
+
|
|
|
def select(self):
|
|
|
self._selected = True
|
|
|
|
|
@@ -68,6 +74,9 @@ class StaticNode(Node):
|
|
|
super(StaticNode, self).__init__()
|
|
|
self.label = label
|
|
|
|
|
|
+ def append_child(self, child):
|
|
|
+ self._append_child(child)
|
|
|
+
|
|
|
def get_label(self):
|
|
|
return self.label
|
|
|
|
|
@@ -77,24 +86,25 @@ class SelectionPad(object):
|
|
|
self._pad = curses.newpad(1, 1)
|
|
|
self._pad.keypad(1)
|
|
|
|
|
|
- def refresh(self, pminrow, smaxrow, smaxcol):
|
|
|
+ def refresh(self, pminrow, sminrow, smaxrow, smaxcol):
|
|
|
# window.refresh([pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol])
|
|
|
- # pminrow and pmincol specify the upper left-hand corner of the rectangle to be displayed in the pad.
|
|
|
- # sminrow, smincol, smaxrow, and smaxcol specify the edges of the rectangle to be displayed on the screen.
|
|
|
+ # pminrow and pmincol specify the upper left-hand corner of the rectangle to be displayed in the pad.
|
|
|
+ # sminrow, smincol, smaxrow, and smaxcol specify the edges of the rectangle to be displayed on the screen.
|
|
|
# The lower right-hand corner of the rectangle to be displayed in the pad is calculated from the screen coordinates, since the rectangles must be the same size.
|
|
|
- self._pad.refresh(pminrow, 0, 0, 0, smaxrow, smaxcol)
|
|
|
+ self._pad.refresh(pminrow, 0, sminrow, 0, smaxrow, smaxcol)
|
|
|
|
|
|
def addstr(self, line_index, col_index, text, attr = 0):
|
|
|
text_encoded = text.encode(locale.getpreferredencoding())
|
|
|
try:
|
|
|
self._pad.addstr(line_index, col_index, text_encoded, attr)
|
|
|
except Exception, ex:
|
|
|
- raise Exception('pad(width=%d, height=%d).addstr(%d, %d, "%s", %d) failed' % (self.get_width(), self.get_height(), line_index, col_index, text_encoded, attr))
|
|
|
+ raise Exception('pad(width=%d, height=%d).addstr(%d, %d, %s, %d) failed'
|
|
|
+ % (self.get_width(), self.get_height(), line_index, col_index, repr(text_encoded), attr))
|
|
|
|
|
|
def clear(self):
|
|
|
self._pad.clear()
|
|
|
|
|
|
- def get_height(self):
|
|
|
+ def get_height(self):
|
|
|
return self._pad.getmaxyx()[0]
|
|
|
|
|
|
def get_width(self):
|
|
@@ -104,7 +114,11 @@ class SelectionPad(object):
|
|
|
return self._pad.getch()
|
|
|
|
|
|
def resize(self, nlines, ncols):
|
|
|
- self._pad.resize(nlines, ncols)
|
|
|
+ try:
|
|
|
+ self._pad.resize(nlines, ncols)
|
|
|
+ except Exception, ex:
|
|
|
+ raise Exception('pad(width=%d, height=%d).resize(%d, %d) failed'
|
|
|
+ % (self.get_width(), self.get_height(), nlines, ncols))
|
|
|
|
|
|
def resize_height(self, nlines):
|
|
|
self.resize(nlines, self.get_width())
|
|
@@ -125,33 +139,40 @@ def select(stdscr, active_root, multiple = False):
|
|
|
def get_active_node():
|
|
|
return active_root.get_children()[active_index]
|
|
|
|
|
|
+ def get_visible_pad_height():
|
|
|
+ return get_screen_height() - active_root.get_header_height()
|
|
|
+
|
|
|
def refresh():
|
|
|
pad.clear()
|
|
|
pad.resize_width(1)
|
|
|
- pad.resize_height(active_root.child_count())
|
|
|
- for child_index in range(len(active_root.get_children())):
|
|
|
- child = active_root.get_children()[child_index]
|
|
|
- label = child.get_label()
|
|
|
- if len(label) > pad.get_width():
|
|
|
- pad.resize_width(len(label))
|
|
|
- pad.addstr(
|
|
|
- child_index,
|
|
|
- 0,
|
|
|
- label,
|
|
|
- (curses.A_UNDERLINE if child_index == active_index else 0)
|
|
|
- | (curses.A_BOLD if child.selected() else 0)
|
|
|
- )
|
|
|
- pad.refresh(
|
|
|
- max(
|
|
|
- 0,
|
|
|
- min(
|
|
|
- active_root.child_count() - get_screen_height(),
|
|
|
- active_index - int(get_screen_height() / 2)
|
|
|
+ if len(active_root.get_children()) > 0:
|
|
|
+ pad.resize_height(active_root.child_count())
|
|
|
+ for child_index in range(len(active_root.get_children())):
|
|
|
+ child = active_root.get_children()[child_index]
|
|
|
+ label = child.get_label()
|
|
|
+ # if the last line is the longest addstr() fails if
|
|
|
+ # the width does not include one additional char.
|
|
|
+ if len(label) > pad.get_width():
|
|
|
+ pad.resize_width(len(label) + 1)
|
|
|
+ pad.addstr(
|
|
|
+ child_index,
|
|
|
+ 0,
|
|
|
+ label,
|
|
|
+ (curses.A_UNDERLINE if child_index == active_index else 0)
|
|
|
+ | (curses.A_BOLD if child.selected() else 0)
|
|
|
)
|
|
|
- ),
|
|
|
- get_screen_height() - 1,
|
|
|
- stdscr.getmaxyx()[1] - 1
|
|
|
- )
|
|
|
+ pad.refresh(
|
|
|
+ max(
|
|
|
+ 0,
|
|
|
+ min(
|
|
|
+ active_root.child_count() - get_visible_pad_height(),
|
|
|
+ active_index - int(get_visible_pad_height() / 2)
|
|
|
+ )
|
|
|
+ ),
|
|
|
+ active_root.get_header_height(),
|
|
|
+ get_screen_height() - 1,
|
|
|
+ stdscr.getmaxyx()[1] - 1
|
|
|
+ )
|
|
|
|
|
|
while True:
|
|
|
refresh()
|
|
@@ -162,17 +183,17 @@ def select(stdscr, active_root, multiple = False):
|
|
|
if key == curses.KEY_RESIZE:
|
|
|
refresh()
|
|
|
elif key in [curses.KEY_DOWN, KEY_SDOWN, ord('j'), ord('J')]:
|
|
|
- if key in [KEY_SDOWN, ord('J')]:
|
|
|
+ if multiple and key in [KEY_SDOWN, ord('J')]:
|
|
|
get_active_node().toggle()
|
|
|
active_index = min(active_root.child_count() - 1, active_index + 1)
|
|
|
elif key in [curses.KEY_UP, KEY_SUP, ord('k'), ord('K')]:
|
|
|
- if key in [KEY_SUP, ord('K')]:
|
|
|
+ if multiple and key in [KEY_SUP, ord('K')]:
|
|
|
get_active_node().toggle()
|
|
|
active_index = max(0, active_index - 1)
|
|
|
elif key == curses.KEY_NPAGE:
|
|
|
- active_index = min(active_root.child_count() - 1, active_index + int(get_screen_height() / 2))
|
|
|
+ active_index = min(active_root.child_count() - 1, active_index + int(get_visible_pad_height() / 2))
|
|
|
elif key == curses.KEY_PPAGE:
|
|
|
- active_index = max(0, active_index - int(get_screen_height() / 2))
|
|
|
+ active_index = max(0, active_index - int(get_visible_pad_height() / 2))
|
|
|
elif key in [ord(' ')]:
|
|
|
if multiple:
|
|
|
get_active_node().toggle()
|