commit cf4ae8454debdf8a9ace9a4f4cc3e4536152d1dd Author: Kamran Riaz Khan krkhan@inspirated.com Date: Sun May 29 15:32:34 2011 +0500
Replaced namedtuples with MenuItem instances, fixed left arrow key on top level menu.
The MenuItem class is added replacing LeafEntry and ParentEntry namedtuples. Replaced "entry" with "item" and defined the constant TOPLEVEL to improve readability.
The scrolling calculations in _moveTopLevelLeft contained a bug, menus with large number of top items did not scroll to the end. Fixed by adding a check to see if we're "spilling" to left of first entry. --- src/cli/menu.py | 98 +++++++++++++++++++++++++------------------------- src/util/menuItem.py | 34 +++++++++++++++++ 2 files changed, 83 insertions(+), 49 deletions(-)
diff --git a/src/cli/menu.py b/src/cli/menu.py index bedb98e..71b56a4 100644 --- a/src/cli/menu.py +++ b/src/cli/menu.py @@ -3,34 +3,32 @@ A drop-down menu for sending actions to panels. """
import curses -from collections import namedtuple
import cli.controller import popups -from util import log, panel, uiTools +from util import log, panel, uiTools, menuItem
-LeafEntry = namedtuple('LeafEntry', ['title', 'callback']) -ParentEntry = namedtuple('ParentEntry', ['title', 'children']) +TOPLEVEL = 0
class Menu(): """Displays a popup menu and sends keys to appropriate panels"""
- def __init__(self, entry=None): - DEFAULT_ROOT = ParentEntry(title="Root", children=( - LeafEntry(title="File" , callback=self._callbackDefault), - LeafEntry(title="Logs" , callback=self._callbackDefault), - LeafEntry(title="View" , callback=self._callbackDefault), - LeafEntry(title="Graph" , callback=self._callbackDefault), - LeafEntry(title="Connections" , callback=self._callbackDefault), - LeafEntry(title="Configuration" , callback=self._callbackDefault))) + def __init__(self, item=None): + DEFAULT_ROOT = menuItem.MenuItem(label="Root", children=( + menuItem.MenuItem(label="File" , callback=self._callbackDefault), + menuItem.MenuItem(label="Logs" , callback=self._callbackDefault), + menuItem.MenuItem(label="View" , callback=self._callbackDefault), + menuItem.MenuItem(label="Graph" , callback=self._callbackDefault), + menuItem.MenuItem(label="Connections" , callback=self._callbackDefault), + menuItem.MenuItem(label="Configuration" , callback=self._callbackDefault)))
self._first = [0] self._selection = [0]
- if entry and isinstance(entry, ParentEntry): - self._rootEntry = entry + if item and item.isParent(): + self._rootItem = item else: - self._rootEntry = DEFAULT_ROOT + self._rootItem = DEFAULT_ROOT
def showMenu(self): popup, width, height = popups.init(height=3) @@ -61,73 +59,75 @@ class Menu(): popups.finalize()
def _calculateTopLevelWidths(self, width): - titles = [menuItem.title for menuItem in self._rootEntry.children] + labels = [menuItem.getLabel() for menuItem in self._rootItem.getChildren()]
- # width per title is set according to the longest title - titlewidth = max(map(len, titles)) + 2 + # width per label is set according to the longest label + labelwidth = max(map(len, labels)) + 2
- # total number of titles that can be printed in current width - printable = min(width / titlewidth - 1, len(self._rootEntry.children)) + # total number of labels that can be printed in current width + printable = min(width / labelwidth - 1, self._rootItem.getChildrenCount())
- return (titlewidth, printable) + return (labelwidth, printable)
def _moveTopLevelRight(self, width): _, printable = self._calculateTopLevelWidths(width)
- if self._selection[0] < printable - 1: - self._selection[0] = self._selection[0] + 1 + if self._selection[TOPLEVEL] < printable - 1: + self._selection[TOPLEVEL] = self._selection[TOPLEVEL] + 1 else: - self._selection[0] = 0 - if printable < len(self._rootEntry.children): - self._first[0] = (self._first[0] + printable) % len(self._rootEntry.children) + self._selection[TOPLEVEL] = 0 + if printable < self._rootItem.getChildrenCount(): + self._first[TOPLEVEL] = (self._first[TOPLEVEL] + printable) % self._rootItem.getChildrenCount()
- if self._first[0] + self._selection[0] == len(self._rootEntry.children): - self._first[0] = 0 - self._selection[0] = 0 + if self._first[TOPLEVEL] + self._selection[TOPLEVEL] == self._rootItem.getChildrenCount(): + self._first[TOPLEVEL] = 0 + self._selection[TOPLEVEL] = 0
def _moveTopLevelLeft(self, width): _, printable = self._calculateTopLevelWidths(width)
- if self._selection[0] > 0: - self._selection[0] = self._selection[0] - 1 + if self._selection[TOPLEVEL] > 0: + self._selection[TOPLEVEL] = self._selection[TOPLEVEL] - 1 else: - self._first[0] = abs(self._first[0] - printable) % len(self._rootEntry.children) - self._selection[0] = len(self._rootEntry.children) - self._first[0] - 1 + if self._first[TOPLEVEL] == 0: + self._first[TOPLEVEL] = (self._rootItem.getChildrenCount() / printable) * printable + else: + self._first[TOPLEVEL] = abs(self._first[TOPLEVEL] - printable) % self._rootItem.getChildrenCount() + self._selection[TOPLEVEL] = self._rootItem.getChildrenCount() - self._first[TOPLEVEL] - 1
- if self._selection[0] > printable: - self._selection[0] = printable - 1 + if self._selection[TOPLEVEL] > printable: + self._selection[TOPLEVEL] = printable - 1
def _drawTopLevel(self, popup, width, height): - titlewidth, printable = self._calculateTopLevelWidths(width) - children = self._rootEntry.children[self._first[0]:self._first[0] + printable] + labelwidth, printable = self._calculateTopLevelWidths(width) + children = self._rootItem.getChildren()[self._first[TOPLEVEL]:self._first[TOPLEVEL] + printable]
top = 1 left = 1 - for (index, entry) in enumerate(children): - titleformat = curses.A_STANDOUT if index == self._selection[0] else curses.A_NORMAL + for (index, item) in enumerate(children): + labelformat = curses.A_STANDOUT if index == self._selection[TOPLEVEL] else curses.A_NORMAL
popup.addch(top, left, curses.ACS_VLINE) left = left + 1 - popup.addstr(top, left, entry.title.center(titlewidth), titleformat) - left = left + titlewidth + popup.addstr(top, left, item.getLabel().center(labelwidth), labelformat) + left = left + labelwidth
popup.addch(top, left, curses.ACS_VLINE) left = left + 1
def _handleEvent(self): - entry = self._rootEntry + item = self._rootItem sums = [sum(values) for values in zip(self._first, self._selection)]
for index in sums: - if isinstance(entry, ParentEntry): - entry = entry.children[index] + if item.isParent(): + item = item.getChildren()[index] else: break
- log.log(log.ERR, "first: %d" % self._first[0]) - if isinstance(entry, LeafEntry): - entry.callback(entry) + if item.isLeaf(): + item.select()
- def _callbackDefault(self, entry): - log.log(log.NOTICE, "%s selected" % entry.title) + def _callbackDefault(self, item): + log.log(log.NOTICE, "%s selected" % item.getLabel())
diff --git a/src/util/menuItem.py b/src/util/menuItem.py new file mode 100644 index 0000000..4800a0f --- /dev/null +++ b/src/util/menuItem.py @@ -0,0 +1,34 @@ +""" +Menu Item class, used by the drop-down menus +""" + +class MenuItem(): + """Contains title, callback handler and possible children""" + + def __init__(self, label=None, callback=None, children=[], parent=None): + self._label = label + self._callback = callback + self._children = children + self._parent = parent + + def getLabel(self): + return self._label + + def isLeaf(self): + return self._children == [] + + def isParent(self): + return self._children != [] + + def getChildren(self): + return self._children + + def getParent(self): + return self._parent + + def getChildrenCount(self): + return len(self._children) + + def select(self): + self._callback(self) +
tor-commits@lists.torproject.org