commit 5fd9b5f74a86eb7e641366ae1c0a1a47404cf873 Author: Kamran Riaz Khan krkhan@inspirated.com Date: Fri May 27 18:01:25 2011 +0500
Initial commit for the menu code. Currently displays a top-bar in a popup and dispatches the menu entry to the callback function, which shall later on be used to determine the panel/key combination for taking specified action. --- src/cli/controller.py | 18 +++++++- src/cli/menu.py | 99 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 3 deletions(-)
diff --git a/src/cli/controller.py b/src/cli/controller.py index e94f7f6..c506302 100644 --- a/src/cli/controller.py +++ b/src/cli/controller.py @@ -17,6 +17,7 @@ import cli.graphing.bandwidthStats import cli.graphing.connStats import cli.graphing.resourceStats import cli.connections.connPanel +import cli.menu
from util import connections, conf, enum, log, panel, sysTools, torConfig, torTools
@@ -76,8 +77,11 @@ def initController(stdscr, startTime): # fourth page: torrc pagePanels.append([cli.torrcPanel.TorrcPanel(stdscr, cli.torrcPanel.Config.TORRC, config)])
+ # top menu + menu = cli.menu.Menu() + # initializes the controller - ARM_CONTROLLER = Controller(stdscr, stickyPanels, pagePanels) + ARM_CONTROLLER = Controller(stdscr, stickyPanels, pagePanels, menu)
# additional configuration for the graph panel graphPanel = ARM_CONTROLLER.getPanel("graph") @@ -131,7 +135,7 @@ class Controller: Tracks the global state of the interface """
- def __init__(self, stdscr, stickyPanels, pagePanels): + def __init__(self, stdscr, stickyPanels, pagePanels, menu): """ Creates a new controller instance. Panel lists are ordered as they appear, top to bottom on the page. @@ -140,11 +144,13 @@ class Controller: stdscr - curses window stickyPanels - panels shown at the top of each page pagePanels - list of pages, each being a list of the panels on it + menu - popup drop-down menu """
self._screen = stdscr self._stickyPanels = stickyPanels self._pagePanels = pagePanels + self._menu = menu self._page = 0 self._isPaused = False self._forceRedraw = False @@ -182,6 +188,9 @@ class Controller: self._forceRedraw = True self.setMsg()
+ def getMenu(self): + return self._menu + def isPaused(self): """ True if the interface is paused, false otherwise. @@ -299,7 +308,7 @@ class Controller:
if attr == None: if not self._isPaused: - msg = "page %i / %i - q: quit, p: pause, h: page help" % (self._page + 1, len(self._pagePanels)) + msg = "page %i / %i - m: menu, q: quit, p: pause, h: page help" % (self._page + 1, len(self._pagePanels)) attr = curses.A_NORMAL else: msg = "Paused" @@ -507,6 +516,9 @@ def drawTorMonitor(stdscr, startTime): control.prevPage() 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() 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 new file mode 100644 index 0000000..315d349 --- /dev/null +++ b/src/cli/menu.py @@ -0,0 +1,99 @@ +""" +A drop-down menu for sending actions to panels. +""" + +import curses +from collections import namedtuple +from operator import attrgetter + +import cli.controller +import popups +from util import log, panel, uiTools + +LeafEntry = namedtuple('LeafEntry', ['title', 'callback']) +ParentEntry = namedtuple('ParentEntry', ['title', 'children']) + +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))) + + self._selection = [0] + self._rootEntry = (entry and isinstance(entry, ParentEntry)) and entry or DEFAULT_ROOT + + def draw(self): + popup, width, height = popups.init(height=3) + if popup: + try: + popup.win.box() + + while True: + self._drawTopLevel(popup, width, height) + + popup.win.refresh() + + control = cli.controller.getController() + key = control.getScreen().getch() + + 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) + 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) + elif uiTools.isSelectionKey(key): + self._handleEvent() + break + + finally: + popups.finalize() + + def _drawTopLevel(self, popup, width, height): + titles = map(attrgetter('title'), self._rootEntry.children) + + # width per title is set according to the longest title + titlewidth = max(map(lambda title: len(title), titles)) + 2 + + # total number of titles that can be printed in current width + printable = (width - 2) / titlewidth + + 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 + + popup.win.addch(top, left, curses.ACS_VLINE) + left = left + 1 + popup.win.addstr(top, left, entry.title.center(titlewidth), titleformat) + left = left + titlewidth + + popup.win.addch(top, left, curses.ACS_VLINE) + left = left + 1 + + def _handleEvent(self): + entry = self._rootEntry + + for index in self._selection: + if isinstance(entry, ParentEntry): + entry = entry.children[index] + else: + break + + if isinstance(entry, LeafEntry): + entry.callback(entry) + + def _callbackDefault(self, entry): + log.log(log.NOTICE, "%s selected" % entry.title) +
tor-commits@lists.torproject.org