[tor-commits] [arm/release] Support long top menus on smaller screens, code review fixes.
atagar at torproject.org
atagar at torproject.org
Sun Jul 17 06:08:21 UTC 2011
commit fd920dfd4fc88d14b7e569b2513b449cc63cae99
Author: Kamran Riaz Khan <krkhan at inspirated.com>
Date: Sat May 28 18:29:15 2011 +0500
Support long top menus on smaller screens, code review fixes.
The top-menu now displays "remaining" entries when right/left arrow keys
are pressed enough times on shorter screens.
Menus are no longer persistence and therefore are removed from
Controller's init.
Code review fixes:
* Menu.draw() is renamed to Menu.showMenu().
* Overzealous map()s are replaced in favor of list comprehensions.
* Popups are drawn through popup.add*() methods instead of drawing
to windows directly.
---
src/cli/controller.py | 12 ++-----
src/cli/menu.py | 78 +++++++++++++++++++++++++++++++++++--------------
2 files changed, 60 insertions(+), 30 deletions(-)
diff --git a/src/cli/controller.py b/src/cli/controller.py
index c506302..25c3051 100644
--- a/src/cli/controller.py
+++ b/src/cli/controller.py
@@ -81,7 +81,7 @@ def initController(stdscr, startTime):
menu = cli.menu.Menu()
# initializes the controller
- ARM_CONTROLLER = Controller(stdscr, stickyPanels, pagePanels, menu)
+ ARM_CONTROLLER = Controller(stdscr, stickyPanels, pagePanels)
# additional configuration for the graph panel
graphPanel = ARM_CONTROLLER.getPanel("graph")
@@ -135,7 +135,7 @@ class Controller:
Tracks the global state of the interface
"""
- def __init__(self, stdscr, stickyPanels, pagePanels, menu):
+ def __init__(self, stdscr, stickyPanels, pagePanels):
"""
Creates a new controller instance. Panel lists are ordered as they appear,
top to bottom on the page.
@@ -150,7 +150,6 @@ class Controller:
self._screen = stdscr
self._stickyPanels = stickyPanels
self._pagePanels = pagePanels
- self._menu = menu
self._page = 0
self._isPaused = False
self._forceRedraw = False
@@ -188,9 +187,6 @@ class Controller:
self._forceRedraw = True
self.setMsg()
- def getMenu(self):
- return self._menu
-
def isPaused(self):
"""
True if the interface is paused, false otherwise.
@@ -517,8 +513,8 @@ def drawTorMonitor(stdscr, startTime):
elif key == ord('p') or key == ord('P'):
control.setPaused(not control.isPaused())
elif key == ord('m') or key == ord('M'):
- menu = control.getMenu()
- menu.draw()
+ menu = cli.menu.Menu()
+ menu.showMenu()
elif key == ord('q') or key == ord('Q'):
# provides prompt to confirm that arm should exit
if CONFIG["features.confirmQuit"]:
diff --git a/src/cli/menu.py b/src/cli/menu.py
index 0395abb..bedb98e 100644
--- a/src/cli/menu.py
+++ b/src/cli/menu.py
@@ -4,7 +4,6 @@ A drop-down menu for sending actions to panels.
import curses
from collections import namedtuple
-from operator import attrgetter
import cli.controller
import popups
@@ -25,16 +24,22 @@ class Menu():
LeafEntry(title="Connections" , callback=self._callbackDefault),
LeafEntry(title="Configuration" , callback=self._callbackDefault)))
+ self._first = [0]
self._selection = [0]
- self._rootEntry = (entry and isinstance(entry, ParentEntry)) and entry or DEFAULT_ROOT
- def draw(self):
+ if entry and isinstance(entry, ParentEntry):
+ self._rootEntry = entry
+ else:
+ self._rootEntry = DEFAULT_ROOT
+
+ def showMenu(self):
popup, width, height = popups.init(height=3)
if popup:
try:
- popup.win.box()
-
while True:
+ popup.win.erase()
+ popup.win.box()
+
self._drawTopLevel(popup, width, height)
popup.win.refresh()
@@ -44,12 +49,10 @@ class Menu():
if key == curses.KEY_RIGHT:
if len(self._selection) == 1:
- # selection is on top menu
- self._selection[0] = (self._selection[0] + 1) % len(self._rootEntry.children)
+ self._moveTopLevelRight(width)
elif key == curses.KEY_LEFT:
if len(self._selection) == 1:
- # selection is on top menu
- self._selection[0] = (self._selection[0] - 1) % len(self._rootEntry.children)
+ self._moveTopLevelLeft(width)
elif uiTools.isSelectionKey(key):
self._handleEvent()
break
@@ -57,40 +60,71 @@ class Menu():
finally:
popups.finalize()
- def _drawTopLevel(self, popup, width, height):
- titles = map(attrgetter('title'), self._rootEntry.children)
+ def _calculateTopLevelWidths(self, width):
+ titles = [menuItem.title for menuItem in self._rootEntry.children]
# width per title is set according to the longest title
- titlewidth = max(map(lambda title: len(title), titles)) + 2
+ titlewidth = max(map(len, titles)) + 2
# total number of titles that can be printed in current width
- printable = width / titlewidth - 1
+ printable = min(width / titlewidth - 1, len(self._rootEntry.children))
+
+ return (titlewidth, printable)
+
+ def _moveTopLevelRight(self, width):
+ _, printable = self._calculateTopLevelWidths(width)
+
+ if self._selection[0] < printable - 1:
+ self._selection[0] = self._selection[0] + 1
+ else:
+ self._selection[0] = 0
+ if printable < len(self._rootEntry.children):
+ self._first[0] = (self._first[0] + printable) % len(self._rootEntry.children)
+
+ if self._first[0] + self._selection[0] == len(self._rootEntry.children):
+ self._first[0] = 0
+ self._selection[0] = 0
+
+ def _moveTopLevelLeft(self, width):
+ _, printable = self._calculateTopLevelWidths(width)
+
+ if self._selection[0] > 0:
+ self._selection[0] = self._selection[0] - 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._selection[0] > printable:
+ self._selection[0] = printable - 1
+
+ def _drawTopLevel(self, popup, width, height):
+ titlewidth, printable = self._calculateTopLevelWidths(width)
+ children = self._rootEntry.children[self._first[0]:self._first[0] + printable]
top = 1
left = 1
- for (index, entry) in enumerate(self._rootEntry.children[:printable]):
- titleformat = curses.A_NORMAL
-
- if index == self._selection[0]:
- titleformat = curses.A_STANDOUT
+ for (index, entry) in enumerate(children):
+ titleformat = curses.A_STANDOUT if index == self._selection[0] else curses.A_NORMAL
- popup.win.addch(top, left, curses.ACS_VLINE)
+ popup.addch(top, left, curses.ACS_VLINE)
left = left + 1
- popup.win.addstr(top, left, entry.title.center(titlewidth), titleformat)
+ popup.addstr(top, left, entry.title.center(titlewidth), titleformat)
left = left + titlewidth
- popup.win.addch(top, left, curses.ACS_VLINE)
+ popup.addch(top, left, curses.ACS_VLINE)
left = left + 1
def _handleEvent(self):
entry = self._rootEntry
+ sums = [sum(values) for values in zip(self._first, self._selection)]
- for index in self._selection:
+ for index in sums:
if isinstance(entry, ParentEntry):
entry = entry.children[index]
else:
break
+ log.log(log.ERR, "first: %d" % self._first[0])
if isinstance(entry, LeafEntry):
entry.callback(entry)
More information about the tor-commits
mailing list