tor-commits
Threads by month
- ----- 2025 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 1 participants
- 213407 discussions

[arm/release] Added support for File->Exit and Configuation->Reset Tor.
by atagar@torproject.org 17 Jul '11
by atagar@torproject.org 17 Jul '11
17 Jul '11
commit 62f118867dca5848d798bc2747a87b517bf81db9
Author: Kamran Riaz Khan <krkhan(a)inspirated.com>
Date: Thu Jun 2 15:28:07 2011 +0500
Added support for File->Exit and Configuation->Reset Tor.
Event handlers can return a key which shall be carried all the way
back to the controller which can use it for the next override in case
it's recognized. Exit and Reset Tor return 'q' and 'x' keys
respectively.
cli.__all__ is updated to include menu module.
---
src/cli/__init__.py | 2 +-
src/cli/controller.py | 5 ++++-
src/cli/menu.py | 15 +++++++++++----
src/util/menuItem.py | 2 +-
4 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/src/cli/__init__.py b/src/cli/__init__.py
index 1564f68..81fabeb 100644
--- a/src/cli/__init__.py
+++ b/src/cli/__init__.py
@@ -2,5 +2,5 @@
Panels, popups, and handlers comprising the arm user interface.
"""
-__all__ = ["configPanel", "controller", "descriptorPopup", "headerPanel", "logPanel", "popups", "torrcPanel"]
+__all__ = ["configPanel", "controller", "descriptorPopup", "headerPanel", "logPanel", "menu", "popups", "torrcPanel"]
diff --git a/src/cli/controller.py b/src/cli/controller.py
index d073312..bb258c3 100644
--- a/src/cli/controller.py
+++ b/src/cli/controller.py
@@ -518,7 +518,10 @@ def drawTorMonitor(stdscr, startTime):
menu = cli.menu.Menu()
menuKeys = menu.showMenu(keys=menuKeys)
if menuKeys != []:
- overrideKey = ord('m')
+ for key in (ord('m'), ord('q'), ord('x')):
+ if key in menuKeys:
+ menuKeys.remove(key)
+ overrideKey = key
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 beceb01..47e8d09 100644
--- a/src/cli/menu.py
+++ b/src/cli/menu.py
@@ -19,7 +19,7 @@ class Menu():
DEFAULT_ROOT = menuItem.MenuItem(label="Root", children=(
menuItem.MenuItem(label="File", children=(
menuItem.MenuItem(label="Exit",
- callback=self._callbackDefault),)),
+ callback=lambda item: self._callbackReturnKey(ord('q'))),)),
menuItem.MenuItem(label="Logs", children=(
menuItem.MenuItem(label="Events",
callback=lambda item: self._callbackPressKey('log', ord('e'))),
@@ -88,7 +88,7 @@ class Menu():
menuItem.MenuItem(label="Reload",
callback=lambda item: self._callbackPressKey('configFile', ord('r'))),
menuItem.MenuItem(label="Reset Tor",
- callback=self._callbackDefault),))
+ callback=lambda item: self._callbackReturnKey(ord('x'))),))
))
self._first = [0]
@@ -291,6 +291,7 @@ class Menu():
cascaded, returnkeys = self._cascadeNLevel()
if cascaded == False:
index = self._first[TOPLEVEL] + self._selection[TOPLEVEL] + 1
+ returnkeys.append(ord('m'))
for i in range(index):
returnkeys.append(curses.KEY_RIGHT)
returnkeys.append(curses.KEY_DOWN)
@@ -298,6 +299,7 @@ class Menu():
elif key == curses.KEY_LEFT:
index = self._first[TOPLEVEL] + self._selection[TOPLEVEL] - 1
index = index % self._rootItem.getChildrenCount()
+ returnkeys.append(ord('m'))
for i in range(index):
returnkeys.append(curses.KEY_RIGHT)
returnkeys.append(curses.KEY_DOWN)
@@ -306,7 +308,9 @@ class Menu():
self._removeLevel()
break
elif uiTools.isSelectionKey(key):
- self._handleEvent()
+ returnkey = self._handleEvent()
+ if returnkey:
+ returnkeys.append(returnkey)
self._removeLevel()
break
@@ -374,7 +378,7 @@ class Menu():
item = self._getCurrentItem()
if item.isLeaf():
- item.select()
+ return item.select()
else:
self._cascadeNLevel()
@@ -429,3 +433,6 @@ class Menu():
panel = control.getPanel(panel)
panel.handleKey(key)
+ def _callbackReturnKey(self, key):
+ return key
+
diff --git a/src/util/menuItem.py b/src/util/menuItem.py
index 6868db6..b48c433 100644
--- a/src/util/menuItem.py
+++ b/src/util/menuItem.py
@@ -35,5 +35,5 @@ class MenuItem():
return len(self._children)
def select(self):
- self._callback(self)
+ return self._callback(self)
1
0

17 Jul '11
commit b5c7dca851bb7f1e13c90bd667136398fa89ce01
Author: Damian Johnson <atagar(a)torproject.org>
Date: Tue May 31 20:50:03 2011 -0700
Minor api, formatting, and documentation changes
Revising some of the merged changes for the menus.
---
src/cli/controller.py | 10 +++-------
src/cli/popups.py | 15 +++++----------
src/util/menuItem.py | 22 ++++++++++++----------
src/util/panel.py | 25 +++++++++++++++++--------
4 files changed, 37 insertions(+), 35 deletions(-)
diff --git a/src/cli/controller.py b/src/cli/controller.py
index bb258c3..fcbaed5 100644
--- a/src/cli/controller.py
+++ b/src/cli/controller.py
@@ -7,6 +7,7 @@ import time
import curses
import threading
+import cli.menu
import cli.popups
import cli.headerPanel
import cli.logPanel
@@ -17,7 +18,6 @@ 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
@@ -77,9 +77,6 @@ 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)
@@ -110,7 +107,7 @@ class LabelPanel(panel.Panel):
"""
def __init__(self, stdscr):
- panel.Panel.__init__(self, stdscr, "msg", 0, 1)
+ panel.Panel.__init__(self, stdscr, "msg", 0, height=1)
self.msgText = ""
self.msgAttr = curses.A_NORMAL
@@ -144,7 +141,6 @@ 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
@@ -304,7 +300,7 @@ class Controller:
if attr == None:
if not self._isPaused:
- msg = "page %i / %i - m: menu, q: quit, p: pause, h: page help" % (self._page + 1, len(self._pagePanels))
+ msg = "page %i / %i - m: menu, p: pause, h: page help, q: quit" % (self._page + 1, len(self._pagePanels))
attr = curses.A_NORMAL
else:
msg = "Paused"
diff --git a/src/cli/popups.py b/src/cli/popups.py
index b3eb105..0e50aa1 100644
--- a/src/cli/popups.py
+++ b/src/cli/popups.py
@@ -8,7 +8,7 @@ import cli.controller
from util import panel, uiTools
-def init(height = -1, width = -1, top = -1, left = -1):
+def init(height = -1, width = -1, top = 0, left = 0):
"""
Preparation for displaying a popup. This creates a popup with a valid
subwindow instance. If that's successful then the curses lock is acquired
@@ -19,19 +19,14 @@ def init(height = -1, width = -1, top = -1, left = -1):
Arguments:
height - maximum height of the popup
width - maximum width of the popup
+ top - top position, relative to the sticky content
+ left - left position from the screen
"""
control = cli.controller.getController()
- topSize = sum(stickyPanel.getHeight() for stickyPanel in control.getStickyPanels())
- leftSize = 0
-
- if top != -1:
- topSize = topSize + top
- if left != -1:
- leftSize = left
+ stickyHeight = sum(stickyPanel.getHeight() for stickyPanel in control.getStickyPanels())
- popup = panel.Panel(control.getScreen(), "popup", topSize, height, width)
- popup.setLeft(leftSize)
+ popup = panel.Panel(control.getScreen(), "popup", top + stickyHeight, left, height, width)
popup.setVisible(True)
# Redraws the popup to prepare a subwindow instance. If none is spawned then
diff --git a/src/util/menuItem.py b/src/util/menuItem.py
index b48c433..277c78a 100644
--- a/src/util/menuItem.py
+++ b/src/util/menuItem.py
@@ -1,25 +1,27 @@
"""
-Menu Item class, used by the drop-down menus
+Menu Item class, used by the drop-down menus.
"""
class MenuItem():
- """Contains title, callback handler and possible children"""
-
+ """
+ Contains title, callback handler and possible children.
+ """
+
def __init__(self, label=None, callback=None, children=[], enabled=None):
self._label = label
self._callback = callback
self._children = children
self._enabled = enabled
-
+
def getLabel(self):
return self._label
-
+
def isLeaf(self):
return self._children == []
-
+
def isParent(self):
return self._children != []
-
+
def isEnabled(self):
if self._enabled == None:
return True
@@ -27,13 +29,13 @@ class MenuItem():
return self._enabled()
else:
return self._enabled
-
+
def getChildren(self):
return self._children
-
+
def getChildrenCount(self):
return len(self._children)
-
+
def select(self):
return self._callback(self)
diff --git a/src/util/panel.py b/src/util/panel.py
index 4fc2158..93b44c2 100644
--- a/src/util/panel.py
+++ b/src/util/panel.py
@@ -43,7 +43,7 @@ class Panel():
redraw().
"""
- def __init__(self, parent, name, top, height=-1, width=-1):
+ def __init__(self, parent, name, top, left=0, height=-1, width=-1):
"""
Creates a durable wrapper for a curses subwindow in the given parent.
@@ -51,6 +51,7 @@ class Panel():
parent - parent curses window
name - identifier for the panel
top - positioning of top within parent
+ left - positioning of the left edge within the parent
height - maximum height of panel (uses all available space if -1)
width - maximum width of panel (uses all available space if -1)
"""
@@ -74,7 +75,7 @@ class Panel():
self.pauseTime = -1
self.top = top
- self.left = 0
+ self.left = left
self.height = height
self.width = width
@@ -256,25 +257,33 @@ class Panel():
self.top = top
self.win = None
- def getHeight(self):
+ def getLeft(self):
"""
- Provides the height used for subwindows (-1 if it isn't limited).
+ Provides the left position where this subwindow is placed within its
+ parent.
"""
- return self.height
-
+ return self.left
+
def setLeft(self, left):
"""
- Changes the position where subwindows are placed within its parent.
+ Changes the left position where this subwindow is placed within its parent.
Arguments:
- top - positioning of top within parent
+ left - positioning of top within parent
"""
if self.left != left:
self.left = left
self.win = None
+ def getHeight(self):
+ """
+ Provides the height used for subwindows (-1 if it isn't limited).
+ """
+
+ return self.height
+
def setHeight(self, height):
"""
Changes the height used for subwindows. This uses all available space if -1.
1
0
commit ccd77c1e77c30265a6d36732697854cf6afc069b
Merge: 32c6f17 62f1188
Author: Damian Johnson <atagar(a)torproject.org>
Date: Thu Jun 2 08:59:45 2011 -0700
Merging krkhan's menus work
src/cli/__init__.py | 2 +-
src/cli/controller.py | 17 ++-
src/cli/menu.py | 438 +++++++++++++++++++++++++++++++++++++++++++++++++
src/cli/popups.py | 9 +-
src/util/menuItem.py | 39 +++++
src/util/panel.py | 18 ++-
6 files changed, 518 insertions(+), 5 deletions(-)
1
0
commit f56e2b85d5dd133c40955e9438f4109c31cd9f30
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sat Jun 4 20:20:16 2011 -0700
Replacing list comprehension with map
Couple minor refactoring changes from a code review comment of Robert's. I'm
actually not sure why the first was working since it was missing the
brackets...
---
src/cli/popups.py | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/cli/popups.py b/src/cli/popups.py
index b90f95d..52e5376 100644
--- a/src/cli/popups.py
+++ b/src/cli/popups.py
@@ -26,7 +26,7 @@ def init(height = -1, width = -1, top = 0, left = 0, belowStatic = True):
control = cli.controller.getController()
if belowStatic:
- stickyHeight = sum(stickyPanel.getHeight() for stickyPanel in control.getStickyPanels())
+ stickyHeight = sum(map(getHeight, control.getStickyPanels()))
else: stickyHeight = 0
popup = panel.Panel(control.getScreen(), "popup", top + stickyHeight, left, height, width)
@@ -272,7 +272,7 @@ def showMenu(title, options, oldSelection):
selection without a carrot if -1)
"""
- maxWidth = max([len(label) for label in options]) + 9
+ maxWidth = max(map(len, options)) + 9
popup, _, _ = init(len(options) + 2, maxWidth)
if not popup: return
key, selection = 0, oldSelection if oldSelection != -1 else 0
1
0

17 Jul '11
commit 856226d684220b746b44c2f44a1c3d3d03f8384b
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sat Jun 4 14:05:23 2011 -0700
Moving Kamran's menu to avoid namespace conflicts
My 'src/cli/menu' module was conflicting with his 'src/cli/menu.py' class so
I've moved his implementation to 'src/cli/menu_alt'.
---
src/cli/__init__.py | 2 +-
src/cli/controller.py | 6 +-
src/cli/menu.py | 438 -----------------------------------------
src/cli/menu_alt/__init__.py | 6 +
src/cli/menu_alt/menu.py | 439 ++++++++++++++++++++++++++++++++++++++++++
src/cli/menu_alt/menuItem.py | 41 ++++
src/util/menuItem.py | 41 ----
7 files changed, 490 insertions(+), 483 deletions(-)
diff --git a/src/cli/__init__.py b/src/cli/__init__.py
index 81fabeb..1564f68 100644
--- a/src/cli/__init__.py
+++ b/src/cli/__init__.py
@@ -2,5 +2,5 @@
Panels, popups, and handlers comprising the arm user interface.
"""
-__all__ = ["configPanel", "controller", "descriptorPopup", "headerPanel", "logPanel", "menu", "popups", "torrcPanel"]
+__all__ = ["configPanel", "controller", "descriptorPopup", "headerPanel", "logPanel", "popups", "torrcPanel"]
diff --git a/src/cli/controller.py b/src/cli/controller.py
index fac43a4..997d9d3 100644
--- a/src/cli/controller.py
+++ b/src/cli/controller.py
@@ -7,8 +7,8 @@ import time
import curses
import threading
-import cli.menu
import cli.menu.menu
+import cli.menu_alt.menu
import cli.popups
import cli.headerPanel
import cli.logPanel
@@ -512,10 +512,10 @@ def drawTorMonitor(stdscr, startTime):
elif key == ord('p') or key == ord('P'):
control.setPaused(not control.isPaused())
elif key == ord('n') or key == ord('N'):
- menu = cli.menu.Menu()
+ menu = cli.menu_alt.menu.Menu()
menuKeys = menu.showMenu(keys=menuKeys)
if menuKeys != []:
- for key in (ord('m'), ord('q'), ord('x')):
+ for key in (ord('n'), ord('q'), ord('x')):
if key in menuKeys:
menuKeys.remove(key)
overrideKey = key
diff --git a/src/cli/menu.py b/src/cli/menu.py
deleted file mode 100644
index 47e8d09..0000000
--- a/src/cli/menu.py
+++ /dev/null
@@ -1,438 +0,0 @@
-"""
-A drop-down menu for sending actions to panels.
-"""
-
-import curses
-
-import cli.controller
-import popups
-
-from cli.graphing.graphPanel import Bounds as GraphBounds
-from util import log, panel, uiTools, menuItem
-
-PARENTLEVEL, TOPLEVEL = (-1, 0)
-
-class Menu():
- """Displays a popup menu and sends keys to appropriate panels"""
-
- def __init__(self, item=None):
- DEFAULT_ROOT = menuItem.MenuItem(label="Root", children=(
- menuItem.MenuItem(label="File", children=(
- menuItem.MenuItem(label="Exit",
- callback=lambda item: self._callbackReturnKey(ord('q'))),)),
- menuItem.MenuItem(label="Logs", children=(
- menuItem.MenuItem(label="Events",
- callback=lambda item: self._callbackPressKey('log', ord('e'))),
- menuItem.MenuItem(label="Clear",
- callback=lambda item: self._callbackPressKey('log', ord('c'))),
- menuItem.MenuItem(label="Save",
- callback=lambda item: self._callbackPressKey('log', ord('a'))),
- menuItem.MenuItem(label="Filter",
- callback=lambda item: self._callbackPressKey('log', ord('f'))),
- menuItem.MenuItem(label="Duplicates", children=(
- menuItem.MenuItem(label="Hidden",
- callback=lambda item: self._callbackSet('log', 'showDuplicates', False, ord('u')),
- enabled=lambda: self._getItemEnabled('log', 'showDuplicates', False)),
- menuItem.MenuItem(label="Visible",
- callback=lambda item: self._callbackSet('log', 'showDuplicates', True, ord('u')),
- enabled=lambda: self._getItemEnabled('log', 'showDuplicates', True)),
- )))),
- menuItem.MenuItem(label="View", children=(
- menuItem.MenuItem(label="Graph",
- callback=lambda item: self._callbackView('graph')),
- menuItem.MenuItem(label="Connections",
- callback=lambda item: self._callbackView('conn')),
- menuItem.MenuItem(label="Configuration",
- callback=lambda item: self._callbackView('configState')),
- menuItem.MenuItem(label="Configuration File",
- callback=lambda item: self._callbackView('configFile')),)),
- menuItem.MenuItem(label="Graph", children=(
- menuItem.MenuItem(label="Stats",
- callback=lambda item: self._callbackPressKey('graph', ord('s'))),
- menuItem.MenuItem(label="Size", children=(
- menuItem.MenuItem(label="Increase",
- callback=lambda item: self._callbackPressKey('graph', ord('m'))),
- menuItem.MenuItem(label="Decrease",
- callback=lambda item: self._callbackPressKey('graph', ord('n'))),
- )),
- menuItem.MenuItem(label="Update Interval",
- callback=lambda item: self._callbackPressKey('graph', ord('i'))),
- menuItem.MenuItem(label="Bounds", children=(
- menuItem.MenuItem(label="Local Max",
- callback=lambda item: self._callbackSet('graph', 'bounds', GraphBounds.LOCAL_MAX, ord('b')),
- enabled=lambda: self._getItemEnabled('graph', 'bounds', GraphBounds.LOCAL_MAX)),
- menuItem.MenuItem(label="Global Max",
- callback=lambda item: self._callbackSet('graph', 'bounds', GraphBounds.GLOBAL_MAX, ord('b')),
- enabled=lambda: self._getItemEnabled('graph', 'bounds', GraphBounds.GLOBAL_MAX)),
- menuItem.MenuItem(label="Tight",
- callback=lambda item: self._callbackSet('graph', 'bounds', GraphBounds.TIGHT, ord('b')),
- enabled=lambda: self._getItemEnabled('graph', 'bounds', GraphBounds.TIGHT)),
- )),)),
- menuItem.MenuItem(label="Connections", children=(
- menuItem.MenuItem(label="Identity",
- callback=lambda item: self._callbackPressKey('conn', ord('l'))),
- menuItem.MenuItem(label="Resolver",
- callback=lambda item: self._callbackPressKey('conn', ord('u'))),
- menuItem.MenuItem(label="Sort Order",
- callback=lambda item: self._callbackPressKey('conn', ord('s'))),
- )),
- menuItem.MenuItem(label="Configuration" , children=(
- menuItem.MenuItem(label="Comments", children=(
- menuItem.MenuItem(label="Hidden",
- callback=lambda item: self._callbackSet('configFile', 'stripComments', True, ord('s')),
- enabled=lambda: self._getItemEnabled('configFile', 'stripComments', True)),
- menuItem.MenuItem(label="Visible",
- callback=lambda item: self._callbackSet('configFile', 'stripComments', False, ord('s')),
- enabled=lambda: self._getItemEnabled('configFile', 'stripComments', False)),
- )),
- menuItem.MenuItem(label="Reload",
- callback=lambda item: self._callbackPressKey('configFile', ord('r'))),
- menuItem.MenuItem(label="Reset Tor",
- callback=lambda item: self._callbackReturnKey(ord('x'))),))
- ))
-
- self._first = [0]
- self._selection = [0]
-
- if item and item.isParent():
- self._rootItem = item
- else:
- self._rootItem = DEFAULT_ROOT
-
- def showMenu(self, keys=[]):
- keys.reverse()
- returnkeys = []
-
- popup, width, height = popups.init(height=3)
- if popup:
- try:
- while True:
- popup.win.erase()
- popup.win.box()
-
- self._drawTopLevel(popup, width, height)
-
- popup.win.refresh()
-
- control = cli.controller.getController()
-
- if keys == []:
- key = control.getScreen().getch()
- else:
- key = keys.pop()
-
- if key == curses.KEY_RIGHT:
- self._moveTopLevelRight(width)
- elif key == curses.KEY_LEFT:
- self._moveTopLevelLeft(width)
- elif key == curses.KEY_DOWN:
- cascaded, returnkeys = self._cascadeNLevel()
- break
- elif key == 27:
- break
- elif uiTools.isSelectionKey(key):
- self._handleEvent()
- break
-
- finally:
- popups.finalize()
-
- return returnkeys
-
- def _appendLevel(self):
- self._first.append(0)
- self._selection.append(0)
-
- def _removeLevel(self):
- self._first.pop()
- self._selection.pop()
-
- def _getCurrentTopLevelItem(self):
- index = self._first[TOPLEVEL] + self._selection[TOPLEVEL]
- return self._rootItem.getChildren()[index]
-
- def _getCurrentItem(self, level=0):
- item = self._rootItem
- if level == 0:
- sums = [sum(values) for values in zip(self._first, self._selection)]
- else:
- sums = [sum(values) for values in zip(self._first[:level], self._selection[:level])]
-
- for index in sums:
- if item.isParent():
- item = item.getChildren()[index]
- else:
- break
-
- return item
-
- def _calculateTopLevelWidths(self, width=0):
- labels = [menuItem.getLabel() for menuItem in self._rootItem.getChildren()]
-
- # width per label is set according to the longest label
- labelwidth = max(map(len, labels)) + 2
-
- # total number of labels that can be printed in supplied width
- printable = min(width / labelwidth - 1, self._rootItem.getChildrenCount())
-
- return (labelwidth, printable)
-
- def _calculateNLevelWidths(self, level=0):
- parent = self._getCurrentItem(level)
-
- if parent.isLeaf():
- return 0
-
- labels = [menuItem.getLabel() for menuItem in parent.getChildren()]
-
- labelwidth = max(map(len, labels))
-
- return labelwidth
-
- def _calculateNLevelHeights(self, height=0, level=0):
- control = cli.controller.getController()
- height, _ = control.getScreen().getmaxyx()
- topSize = sum(stickyPanel.getHeight() for stickyPanel in control.getStickyPanels())
- height = height - topSize
-
- parent = self._getCurrentItem(level)
-
- if parent.isLeaf():
- return 0
-
- printable = min(height - 4, parent.getChildrenCount())
-
- return printable if printable else parent.getChildrenCount()
-
- def _moveTopLevelRight(self, width):
- _, printable = self._calculateTopLevelWidths(width)
-
- if self._selection[TOPLEVEL] < printable - 1:
- self._selection[TOPLEVEL] = self._selection[TOPLEVEL] + 1
- else:
- self._selection[TOPLEVEL] = 0
- if printable < self._rootItem.getChildrenCount():
- self._first[TOPLEVEL] = (self._first[TOPLEVEL] + printable) % self._rootItem.getChildrenCount()
-
- 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[TOPLEVEL] > 0:
- self._selection[TOPLEVEL] = self._selection[TOPLEVEL] - 1
- else:
- if self._first[TOPLEVEL] == 0:
- self._first[TOPLEVEL] = ((self._rootItem.getChildrenCount() / printable) * printable) % self._rootItem.getChildrenCount()
- 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[TOPLEVEL] > printable:
- self._selection[TOPLEVEL] = printable - 1
-
- def _drawTopLevel(self, popup, width, height):
- labelwidth, printable = self._calculateTopLevelWidths(width)
- children = self._rootItem.getChildren()[self._first[TOPLEVEL]:self._first[TOPLEVEL] + printable]
-
- top = 1
- left = 1
- 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, item.getLabel().center(labelwidth), labelformat)
- left = left + labelwidth
-
- popup.addch(top, left, curses.ACS_VLINE)
- left = left + 1
-
- def _cascadeNLevel(self):
- parent = self._getCurrentItem()
-
- if parent.isLeaf():
- return (False, [])
-
- self._appendLevel()
-
- labelwidth = self._calculateNLevelWidths(level=PARENTLEVEL)
- printable = self._calculateNLevelHeights(level=PARENTLEVEL)
-
- toplabelwidth, _ = self._calculateTopLevelWidths()
- left = (toplabelwidth + 2) * self._selection[TOPLEVEL]
-
- popup, width, height = popups.init(height=printable+2, width=labelwidth+2, top=2, left=left)
-
- while self._getCurrentItem().isEnabled() == False:
- self._moveNLevelDown(height)
-
- if popup.win:
- returnkeys = []
- try:
- while True:
- popup.win.erase()
- popup.win.box()
-
- self._drawNLevel(popup, width, height)
-
- popup.win.refresh()
-
- control = cli.controller.getController()
- key = control.getScreen().getch()
-
- if key == curses.KEY_DOWN:
- self._moveNLevelDown(height)
- elif key == curses.KEY_UP:
- self._moveNLevelUp(height)
- elif key == curses.KEY_RIGHT:
- cascaded, returnkeys = self._cascadeNLevel()
- if cascaded == False:
- index = self._first[TOPLEVEL] + self._selection[TOPLEVEL] + 1
- returnkeys.append(ord('m'))
- for i in range(index):
- returnkeys.append(curses.KEY_RIGHT)
- returnkeys.append(curses.KEY_DOWN)
- break
- elif key == curses.KEY_LEFT:
- index = self._first[TOPLEVEL] + self._selection[TOPLEVEL] - 1
- index = index % self._rootItem.getChildrenCount()
- returnkeys.append(ord('m'))
- for i in range(index):
- returnkeys.append(curses.KEY_RIGHT)
- returnkeys.append(curses.KEY_DOWN)
- break
- elif key == 27:
- self._removeLevel()
- break
- elif uiTools.isSelectionKey(key):
- returnkey = self._handleEvent()
- if returnkey:
- returnkeys.append(returnkey)
- self._removeLevel()
- break
-
- finally:
- popups.finalize()
-
- return (True, returnkeys)
-
- return (False, [])
-
- def _drawNLevel(self, popup, width, height):
- printable = self._calculateNLevelHeights(level=PARENTLEVEL)
- parent = self._getCurrentItem(level=PARENTLEVEL)
- children = parent.getChildren()[self._first[PARENTLEVEL]:self._first[PARENTLEVEL] + printable]
-
- top = 1
- left = 1
- for (index, item) in enumerate(children):
- labelformat = curses.A_STANDOUT if index == self._selection[PARENTLEVEL] else curses.A_NORMAL
-
- if not item.isEnabled():
- labelformat = labelformat | uiTools.getColor('yellow')
-
- popup.addstr(top, left, item.getLabel(), labelformat)
- top = top + 1
-
- def _moveNLevelDown(self, height):
- printable = self._calculateNLevelHeights(level=PARENTLEVEL)
- parent = self._getCurrentItem(level=PARENTLEVEL)
-
- if self._selection[PARENTLEVEL] < printable - 1:
- self._selection[PARENTLEVEL] = self._selection[PARENTLEVEL] + 1
- else:
- self._selection[PARENTLEVEL] = 0
- if printable < parent.getChildrenCount():
- self._first[PARENTLEVEL] = (self._first[PARENTLEVEL] + printable) % parent.getChildrenCount()
-
- if self._first[PARENTLEVEL] + self._selection[PARENTLEVEL] == parent.getChildrenCount():
- self._first[PARENTLEVEL] = 0
- self._selection[PARENTLEVEL] = 0
-
- while self._getCurrentItem().isEnabled() == False:
- self._moveNLevelDown(height)
-
- def _moveNLevelUp(self, height):
- printable = self._calculateNLevelHeights(level=PARENTLEVEL)
- parent = self._getCurrentItem(level=PARENTLEVEL)
-
- if self._selection[PARENTLEVEL] > 0:
- self._selection[PARENTLEVEL] = self._selection[PARENTLEVEL] - 1
- else:
- if self._first[PARENTLEVEL] == 0:
- self._first[PARENTLEVEL] = ((parent.getChildrenCount() / printable) * printable) % parent.getChildrenCount()
- else:
- self._first[PARENTLEVEL] = abs(self._first[PARENTLEVEL] - printable) % parent.getChildrenCount()
- self._selection[PARENTLEVEL] = parent.getChildrenCount() - self._first[PARENTLEVEL] - 1
-
- if self._selection[PARENTLEVEL] > printable:
- self._selection[PARENTLEVEL] = printable - 1
-
- while self._getCurrentItem().isEnabled() == False:
- self._moveNLevelUp(height)
-
- def _handleEvent(self):
- item = self._getCurrentItem()
-
- if item.isLeaf():
- return item.select()
- else:
- self._cascadeNLevel()
-
- def _callbackDefault(self, item):
- log.log(log.NOTICE, "%s selected" % item.getLabel())
-
- def _callbackView(self, panelname):
- control = cli.controller.getController()
-
- start = control.getPage()
- panels = control.getDisplayPanels(includeSticky=False)
- panelnames = [panel.getName() for panel in panels]
- while not panelname in panelnames:
- control.nextPage()
- panels = control.getDisplayPanels(includeSticky=False)
- panelnames = [panel.getName() for panel in panels]
-
- if control.getPage() == start:
- log.log(log.ERR, "Panel %s not found" % panelname)
- break
-
- def _getItemEnabled(self, panel, attr, value):
- control = cli.controller.getController()
- if control:
- panel = control.getPanel(panel)
-
- if panel:
- return getattr(panel, attr, None) != value
-
- return False
-
- def _callbackSet(self, panel, attr, value, key=None):
- control = cli.controller.getController()
- panel = control.getPanel(panel)
-
- panelattr = getattr(panel, attr, None)
-
- if panelattr != None:
- if hasattr(panelattr, '__call__'):
- panelattr(value)
- elif panelattr != value and key != None:
- start = panelattr
- while panelattr != value:
- panel.handleKey(key)
- panelattr = getattr(panel, attr, None)
- if panelattr == start:
- log.log(log.ERR, "Could not set %s.%s" % (panel, attr))
- break
-
- def _callbackPressKey(self, panel, key):
- control = cli.controller.getController()
- panel = control.getPanel(panel)
- panel.handleKey(key)
-
- def _callbackReturnKey(self, key):
- return key
-
diff --git a/src/cli/menu_alt/__init__.py b/src/cli/menu_alt/__init__.py
new file mode 100644
index 0000000..6d7b6b7
--- /dev/null
+++ b/src/cli/menu_alt/__init__.py
@@ -0,0 +1,6 @@
+"""
+Resources for displaying the menu.
+"""
+
+__all__ = ["menuItem", "menu"]
+
diff --git a/src/cli/menu_alt/menu.py b/src/cli/menu_alt/menu.py
new file mode 100644
index 0000000..7e10366
--- /dev/null
+++ b/src/cli/menu_alt/menu.py
@@ -0,0 +1,439 @@
+"""
+A drop-down menu for sending actions to panels.
+"""
+
+import curses
+
+import cli.controller
+import cli.menu_alt.menuItem as menuItem
+import cli.popups
+
+from cli.graphing.graphPanel import Bounds as GraphBounds
+from util import log, panel, uiTools
+
+PARENTLEVEL, TOPLEVEL = (-1, 0)
+
+class Menu():
+ """Displays a popup menu and sends keys to appropriate panels"""
+
+ def __init__(self, item=None):
+ DEFAULT_ROOT = menuItem.MenuItem(label="Root", children=(
+ menuItem.MenuItem(label="File", children=(
+ menuItem.MenuItem(label="Exit",
+ callback=lambda item: self._callbackReturnKey(ord('q'))),)),
+ menuItem.MenuItem(label="Logs", children=(
+ menuItem.MenuItem(label="Events",
+ callback=lambda item: self._callbackPressKey('log', ord('e'))),
+ menuItem.MenuItem(label="Clear",
+ callback=lambda item: self._callbackPressKey('log', ord('c'))),
+ menuItem.MenuItem(label="Save",
+ callback=lambda item: self._callbackPressKey('log', ord('a'))),
+ menuItem.MenuItem(label="Filter",
+ callback=lambda item: self._callbackPressKey('log', ord('f'))),
+ menuItem.MenuItem(label="Duplicates", children=(
+ menuItem.MenuItem(label="Hidden",
+ callback=lambda item: self._callbackSet('log', 'showDuplicates', False, ord('u')),
+ enabled=lambda: self._getItemEnabled('log', 'showDuplicates', False)),
+ menuItem.MenuItem(label="Visible",
+ callback=lambda item: self._callbackSet('log', 'showDuplicates', True, ord('u')),
+ enabled=lambda: self._getItemEnabled('log', 'showDuplicates', True)),
+ )))),
+ menuItem.MenuItem(label="View", children=(
+ menuItem.MenuItem(label="Graph",
+ callback=lambda item: self._callbackView('graph')),
+ menuItem.MenuItem(label="Connections",
+ callback=lambda item: self._callbackView('conn')),
+ menuItem.MenuItem(label="Configuration",
+ callback=lambda item: self._callbackView('configState')),
+ menuItem.MenuItem(label="Configuration File",
+ callback=lambda item: self._callbackView('configFile')),)),
+ menuItem.MenuItem(label="Graph", children=(
+ menuItem.MenuItem(label="Stats",
+ callback=lambda item: self._callbackPressKey('graph', ord('s'))),
+ menuItem.MenuItem(label="Size", children=(
+ menuItem.MenuItem(label="Increase",
+ callback=lambda item: self._callbackPressKey('graph', ord('m'))),
+ menuItem.MenuItem(label="Decrease",
+ callback=lambda item: self._callbackPressKey('graph', ord('n'))),
+ )),
+ menuItem.MenuItem(label="Update Interval",
+ callback=lambda item: self._callbackPressKey('graph', ord('i'))),
+ menuItem.MenuItem(label="Bounds", children=(
+ menuItem.MenuItem(label="Local Max",
+ callback=lambda item: self._callbackSet('graph', 'bounds', GraphBounds.LOCAL_MAX, ord('b')),
+ enabled=lambda: self._getItemEnabled('graph', 'bounds', GraphBounds.LOCAL_MAX)),
+ menuItem.MenuItem(label="Global Max",
+ callback=lambda item: self._callbackSet('graph', 'bounds', GraphBounds.GLOBAL_MAX, ord('b')),
+ enabled=lambda: self._getItemEnabled('graph', 'bounds', GraphBounds.GLOBAL_MAX)),
+ menuItem.MenuItem(label="Tight",
+ callback=lambda item: self._callbackSet('graph', 'bounds', GraphBounds.TIGHT, ord('b')),
+ enabled=lambda: self._getItemEnabled('graph', 'bounds', GraphBounds.TIGHT)),
+ )),)),
+ menuItem.MenuItem(label="Connections", children=(
+ menuItem.MenuItem(label="Identity",
+ callback=lambda item: self._callbackPressKey('conn', ord('l'))),
+ menuItem.MenuItem(label="Resolver",
+ callback=lambda item: self._callbackPressKey('conn', ord('u'))),
+ menuItem.MenuItem(label="Sort Order",
+ callback=lambda item: self._callbackPressKey('conn', ord('s'))),
+ )),
+ menuItem.MenuItem(label="Configuration" , children=(
+ menuItem.MenuItem(label="Comments", children=(
+ menuItem.MenuItem(label="Hidden",
+ callback=lambda item: self._callbackSet('configFile', 'stripComments', True, ord('s')),
+ enabled=lambda: self._getItemEnabled('configFile', 'stripComments', True)),
+ menuItem.MenuItem(label="Visible",
+ callback=lambda item: self._callbackSet('configFile', 'stripComments', False, ord('s')),
+ enabled=lambda: self._getItemEnabled('configFile', 'stripComments', False)),
+ )),
+ menuItem.MenuItem(label="Reload",
+ callback=lambda item: self._callbackPressKey('configFile', ord('r'))),
+ menuItem.MenuItem(label="Reset Tor",
+ callback=lambda item: self._callbackReturnKey(ord('x'))),))
+ ))
+
+ self._first = [0]
+ self._selection = [0]
+
+ if item and item.isParent():
+ self._rootItem = item
+ else:
+ self._rootItem = DEFAULT_ROOT
+
+ def showMenu(self, keys=[]):
+ keys.reverse()
+ returnkeys = []
+
+ popup, width, height = cli.popups.init(height=3)
+ if popup:
+ try:
+ while True:
+ popup.win.erase()
+ popup.win.box()
+
+ self._drawTopLevel(popup, width, height)
+
+ popup.win.refresh()
+
+ control = cli.controller.getController()
+
+ if keys == []:
+ key = control.getScreen().getch()
+ else:
+ key = keys.pop()
+
+ if key == curses.KEY_RIGHT:
+ self._moveTopLevelRight(width)
+ elif key == curses.KEY_LEFT:
+ self._moveTopLevelLeft(width)
+ elif key == curses.KEY_DOWN:
+ cascaded, returnkeys = self._cascadeNLevel()
+ break
+ elif key == 27:
+ break
+ elif uiTools.isSelectionKey(key):
+ self._handleEvent()
+ break
+
+ finally:
+ cli.popups.finalize()
+
+ return returnkeys
+
+ def _appendLevel(self):
+ self._first.append(0)
+ self._selection.append(0)
+
+ def _removeLevel(self):
+ self._first.pop()
+ self._selection.pop()
+
+ def _getCurrentTopLevelItem(self):
+ index = self._first[TOPLEVEL] + self._selection[TOPLEVEL]
+ return self._rootItem.getChildren()[index]
+
+ def _getCurrentItem(self, level=0):
+ item = self._rootItem
+ if level == 0:
+ sums = [sum(values) for values in zip(self._first, self._selection)]
+ else:
+ sums = [sum(values) for values in zip(self._first[:level], self._selection[:level])]
+
+ for index in sums:
+ if item.isParent():
+ item = item.getChildren()[index]
+ else:
+ break
+
+ return item
+
+ def _calculateTopLevelWidths(self, width=0):
+ labels = [menuItem.getLabel() for menuItem in self._rootItem.getChildren()]
+
+ # width per label is set according to the longest label
+ labelwidth = max(map(len, labels)) + 2
+
+ # total number of labels that can be printed in supplied width
+ printable = min(width / labelwidth - 1, self._rootItem.getChildrenCount())
+
+ return (labelwidth, printable)
+
+ def _calculateNLevelWidths(self, level=0):
+ parent = self._getCurrentItem(level)
+
+ if parent.isLeaf():
+ return 0
+
+ labels = [menuItem.getLabel() for menuItem in parent.getChildren()]
+
+ labelwidth = max(map(len, labels))
+
+ return labelwidth
+
+ def _calculateNLevelHeights(self, height=0, level=0):
+ control = cli.controller.getController()
+ height, _ = control.getScreen().getmaxyx()
+ topSize = sum(stickyPanel.getHeight() for stickyPanel in control.getStickyPanels())
+ height = height - topSize
+
+ parent = self._getCurrentItem(level)
+
+ if parent.isLeaf():
+ return 0
+
+ printable = min(height - 4, parent.getChildrenCount())
+
+ return printable if printable else parent.getChildrenCount()
+
+ def _moveTopLevelRight(self, width):
+ _, printable = self._calculateTopLevelWidths(width)
+
+ if self._selection[TOPLEVEL] < printable - 1:
+ self._selection[TOPLEVEL] = self._selection[TOPLEVEL] + 1
+ else:
+ self._selection[TOPLEVEL] = 0
+ if printable < self._rootItem.getChildrenCount():
+ self._first[TOPLEVEL] = (self._first[TOPLEVEL] + printable) % self._rootItem.getChildrenCount()
+
+ 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[TOPLEVEL] > 0:
+ self._selection[TOPLEVEL] = self._selection[TOPLEVEL] - 1
+ else:
+ if self._first[TOPLEVEL] == 0:
+ self._first[TOPLEVEL] = ((self._rootItem.getChildrenCount() / printable) * printable) % self._rootItem.getChildrenCount()
+ 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[TOPLEVEL] > printable:
+ self._selection[TOPLEVEL] = printable - 1
+
+ def _drawTopLevel(self, popup, width, height):
+ labelwidth, printable = self._calculateTopLevelWidths(width)
+ children = self._rootItem.getChildren()[self._first[TOPLEVEL]:self._first[TOPLEVEL] + printable]
+
+ top = 1
+ left = 1
+ 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, item.getLabel().center(labelwidth), labelformat)
+ left = left + labelwidth
+
+ popup.addch(top, left, curses.ACS_VLINE)
+ left = left + 1
+
+ def _cascadeNLevel(self):
+ parent = self._getCurrentItem()
+
+ if parent.isLeaf():
+ return (False, [])
+
+ self._appendLevel()
+
+ labelwidth = self._calculateNLevelWidths(level=PARENTLEVEL)
+ printable = self._calculateNLevelHeights(level=PARENTLEVEL)
+
+ toplabelwidth, _ = self._calculateTopLevelWidths()
+ left = (toplabelwidth + 2) * self._selection[TOPLEVEL]
+
+ popup, width, height = cli.popups.init(height=printable+2, width=labelwidth+2, top=2, left=left)
+
+ while self._getCurrentItem().isEnabled() == False:
+ self._moveNLevelDown(height)
+
+ if popup.win:
+ returnkeys = []
+ try:
+ while True:
+ popup.win.erase()
+ popup.win.box()
+
+ self._drawNLevel(popup, width, height)
+
+ popup.win.refresh()
+
+ control = cli.controller.getController()
+ key = control.getScreen().getch()
+
+ if key == curses.KEY_DOWN:
+ self._moveNLevelDown(height)
+ elif key == curses.KEY_UP:
+ self._moveNLevelUp(height)
+ elif key == curses.KEY_RIGHT:
+ cascaded, returnkeys = self._cascadeNLevel()
+ if cascaded == False:
+ index = self._first[TOPLEVEL] + self._selection[TOPLEVEL] + 1
+ returnkeys.append(ord('n'))
+ for i in range(index):
+ returnkeys.append(curses.KEY_RIGHT)
+ returnkeys.append(curses.KEY_DOWN)
+ break
+ elif key == curses.KEY_LEFT:
+ index = self._first[TOPLEVEL] + self._selection[TOPLEVEL] - 1
+ index = index % self._rootItem.getChildrenCount()
+ returnkeys.append(ord('n'))
+ for i in range(index):
+ returnkeys.append(curses.KEY_RIGHT)
+ returnkeys.append(curses.KEY_DOWN)
+ break
+ elif key == 27:
+ self._removeLevel()
+ break
+ elif uiTools.isSelectionKey(key):
+ returnkey = self._handleEvent()
+ if returnkey:
+ returnkeys.append(returnkey)
+ self._removeLevel()
+ break
+
+ finally:
+ cli.popups.finalize()
+
+ return (True, returnkeys)
+
+ return (False, [])
+
+ def _drawNLevel(self, popup, width, height):
+ printable = self._calculateNLevelHeights(level=PARENTLEVEL)
+ parent = self._getCurrentItem(level=PARENTLEVEL)
+ children = parent.getChildren()[self._first[PARENTLEVEL]:self._first[PARENTLEVEL] + printable]
+
+ top = 1
+ left = 1
+ for (index, item) in enumerate(children):
+ labelformat = curses.A_STANDOUT if index == self._selection[PARENTLEVEL] else curses.A_NORMAL
+
+ if not item.isEnabled():
+ labelformat = labelformat | uiTools.getColor('yellow')
+
+ popup.addstr(top, left, item.getLabel(), labelformat)
+ top = top + 1
+
+ def _moveNLevelDown(self, height):
+ printable = self._calculateNLevelHeights(level=PARENTLEVEL)
+ parent = self._getCurrentItem(level=PARENTLEVEL)
+
+ if self._selection[PARENTLEVEL] < printable - 1:
+ self._selection[PARENTLEVEL] = self._selection[PARENTLEVEL] + 1
+ else:
+ self._selection[PARENTLEVEL] = 0
+ if printable < parent.getChildrenCount():
+ self._first[PARENTLEVEL] = (self._first[PARENTLEVEL] + printable) % parent.getChildrenCount()
+
+ if self._first[PARENTLEVEL] + self._selection[PARENTLEVEL] == parent.getChildrenCount():
+ self._first[PARENTLEVEL] = 0
+ self._selection[PARENTLEVEL] = 0
+
+ while self._getCurrentItem().isEnabled() == False:
+ self._moveNLevelDown(height)
+
+ def _moveNLevelUp(self, height):
+ printable = self._calculateNLevelHeights(level=PARENTLEVEL)
+ parent = self._getCurrentItem(level=PARENTLEVEL)
+
+ if self._selection[PARENTLEVEL] > 0:
+ self._selection[PARENTLEVEL] = self._selection[PARENTLEVEL] - 1
+ else:
+ if self._first[PARENTLEVEL] == 0:
+ self._first[PARENTLEVEL] = ((parent.getChildrenCount() / printable) * printable) % parent.getChildrenCount()
+ else:
+ self._first[PARENTLEVEL] = abs(self._first[PARENTLEVEL] - printable) % parent.getChildrenCount()
+ self._selection[PARENTLEVEL] = parent.getChildrenCount() - self._first[PARENTLEVEL] - 1
+
+ if self._selection[PARENTLEVEL] > printable:
+ self._selection[PARENTLEVEL] = printable - 1
+
+ while self._getCurrentItem().isEnabled() == False:
+ self._moveNLevelUp(height)
+
+ def _handleEvent(self):
+ item = self._getCurrentItem()
+
+ if item.isLeaf():
+ return item.select()
+ else:
+ self._cascadeNLevel()
+
+ def _callbackDefault(self, item):
+ log.log(log.NOTICE, "%s selected" % item.getLabel())
+
+ def _callbackView(self, panelname):
+ control = cli.controller.getController()
+
+ start = control.getPage()
+ panels = control.getDisplayPanels(includeSticky=False)
+ panelnames = [panel.getName() for panel in panels]
+ while not panelname in panelnames:
+ control.nextPage()
+ panels = control.getDisplayPanels(includeSticky=False)
+ panelnames = [panel.getName() for panel in panels]
+
+ if control.getPage() == start:
+ log.log(log.ERR, "Panel %s not found" % panelname)
+ break
+
+ def _getItemEnabled(self, panel, attr, value):
+ control = cli.controller.getController()
+ if control:
+ panel = control.getPanel(panel)
+
+ if panel:
+ return getattr(panel, attr, None) != value
+
+ return False
+
+ def _callbackSet(self, panel, attr, value, key=None):
+ control = cli.controller.getController()
+ panel = control.getPanel(panel)
+
+ panelattr = getattr(panel, attr, None)
+
+ if panelattr != None:
+ if hasattr(panelattr, '__call__'):
+ panelattr(value)
+ elif panelattr != value and key != None:
+ start = panelattr
+ while panelattr != value:
+ panel.handleKey(key)
+ panelattr = getattr(panel, attr, None)
+ if panelattr == start:
+ log.log(log.ERR, "Could not set %s.%s" % (panel, attr))
+ break
+
+ def _callbackPressKey(self, panel, key):
+ control = cli.controller.getController()
+ panel = control.getPanel(panel)
+ panel.handleKey(key)
+
+ def _callbackReturnKey(self, key):
+ return key
+
diff --git a/src/cli/menu_alt/menuItem.py b/src/cli/menu_alt/menuItem.py
new file mode 100644
index 0000000..277c78a
--- /dev/null
+++ b/src/cli/menu_alt/menuItem.py
@@ -0,0 +1,41 @@
+"""
+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=[], enabled=None):
+ self._label = label
+ self._callback = callback
+ self._children = children
+ self._enabled = enabled
+
+ def getLabel(self):
+ return self._label
+
+ def isLeaf(self):
+ return self._children == []
+
+ def isParent(self):
+ return self._children != []
+
+ def isEnabled(self):
+ if self._enabled == None:
+ return True
+ elif hasattr(self._enabled, '__call__'):
+ return self._enabled()
+ else:
+ return self._enabled
+
+ def getChildren(self):
+ return self._children
+
+ def getChildrenCount(self):
+ return len(self._children)
+
+ def select(self):
+ return self._callback(self)
+
diff --git a/src/util/menuItem.py b/src/util/menuItem.py
deleted file mode 100644
index 277c78a..0000000
--- a/src/util/menuItem.py
+++ /dev/null
@@ -1,41 +0,0 @@
-"""
-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=[], enabled=None):
- self._label = label
- self._callback = callback
- self._children = children
- self._enabled = enabled
-
- def getLabel(self):
- return self._label
-
- def isLeaf(self):
- return self._children == []
-
- def isParent(self):
- return self._children != []
-
- def isEnabled(self):
- if self._enabled == None:
- return True
- elif hasattr(self._enabled, '__call__'):
- return self._enabled()
- else:
- return self._enabled
-
- def getChildren(self):
- return self._children
-
- def getChildrenCount(self):
- return len(self._children)
-
- def select(self):
- return self._callback(self)
-
1
0
commit c1aecf68b13bf2eb12a104b98dab9dde6a2a46f0
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sat Jun 4 13:52:09 2011 -0700
Alternative menu implementation
This is a smaller and (I think) simpler implementation of a menu. Its model
and presentation logic are done so the menu can be opened and used, but
handlers haven't been attached yet so nothing happens when a selection is
made.
---
README | 5 +
src/cli/controller.py | 5 +-
src/cli/menu/__init__.py | 6 ++
src/cli/menu/item.py | 146 ++++++++++++++++++++++++++++++
src/cli/menu/menu.py | 222 ++++++++++++++++++++++++++++++++++++++++++++++
src/cli/popups.py | 15 ++--
src/util/panel.py | 2 +-
7 files changed, 393 insertions(+), 8 deletions(-)
diff --git a/README b/README
index b20ec1c..0f26163 100644
--- a/README
+++ b/README
@@ -176,6 +176,11 @@ Layout:
connEntry.py - individual connections to or from the system
entries.py - common parent for connPanel display entries
+ menu/
+ __init__.py
+ menu.py - provides an interactive menu
+ item.py - individual items within the menu
+
__init__.py
controller.py - main display loop, handling input and layout
headerPanel.py - top of all pages, providing general information
diff --git a/src/cli/controller.py b/src/cli/controller.py
index fcbaed5..fac43a4 100644
--- a/src/cli/controller.py
+++ b/src/cli/controller.py
@@ -8,6 +8,7 @@ import curses
import threading
import cli.menu
+import cli.menu.menu
import cli.popups
import cli.headerPanel
import cli.logPanel
@@ -510,7 +511,7 @@ 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'):
+ elif key == ord('n') or key == ord('N'):
menu = cli.menu.Menu()
menuKeys = menu.showMenu(keys=menuKeys)
if menuKeys != []:
@@ -518,6 +519,8 @@ def drawTorMonitor(stdscr, startTime):
if key in menuKeys:
menuKeys.remove(key)
overrideKey = key
+ elif key == ord('m') or key == ord('M'):
+ cli.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/__init__.py b/src/cli/menu/__init__.py
new file mode 100644
index 0000000..e6b5f10
--- /dev/null
+++ b/src/cli/menu/__init__.py
@@ -0,0 +1,6 @@
+"""
+Resources for displaying the menu.
+"""
+
+__all__ = ["item", "menu"]
+
diff --git a/src/cli/menu/item.py b/src/cli/menu/item.py
new file mode 100644
index 0000000..bfc7ffd
--- /dev/null
+++ b/src/cli/menu/item.py
@@ -0,0 +1,146 @@
+"""
+Menu item, representing an option in the drop-down menu.
+"""
+
+class MenuItem():
+ """
+ Option in a drop-down menu.
+ """
+
+ def __init__(self, label, callback):
+ self._label = label
+ self._callback = callback
+ self._parent = None
+
+ def getLabel(self):
+ """
+ Provides a tuple of three strings representing the prefix, label, and
+ suffix for this item.
+ """
+
+ return ("", self._label, "")
+
+ def getParent(self):
+ """
+ Provides the Submenu we're contained within.
+ """
+
+ return self._parent
+
+ def getHierarchy(self):
+ """
+ Provides a list with all of our parents, up to the root.
+ """
+
+ myHierarchy = [self]
+ while myHierarchy[-1].getParent():
+ myHierarchy.append(myHierarchy[-1].getParent())
+
+ myHierarchy.reverse()
+ return myHierarchy
+
+ def getRoot(self):
+ """
+ Provides the base submenu we belong to.
+ """
+
+ if self._parent: return self._parent.getRoot()
+ else: return self
+
+ def select(self):
+ """
+ Performs the callback for the menu item, returning true if we should close
+ the menu and false otherwise.
+ """
+
+ if self._callback: return self._callback()
+ else: return False
+
+ def next(self):
+ """
+ Provides the next option for the submenu we're in, raising a ValueError
+ if we don't have a parent.
+ """
+
+ return self._getSibling(1)
+
+ def prev(self):
+ """
+ Provides the previous option for the submenu we're in, raising a ValueError
+ if we don't have a parent.
+ """
+
+ return self._getSibling(-1)
+
+ def _getSibling(self, offset):
+ """
+ Provides our sibling with a given index offset from us, raising a
+ ValueError if we don't have a parent.
+
+ Arguments:
+ offset - index offset for the sibling to be returned
+ """
+
+ if self._parent:
+ mySiblings = self._parent.getChildren()
+
+ try:
+ myIndex = mySiblings.index(self)
+ return mySiblings[(myIndex + offset) % len(mySiblings)]
+ except ValueError:
+ # We expect a bidirectional references between submenus and their
+ # children. If we don't have this then our menu's screwed up.
+
+ msg = "The '%s' submenu doesn't contain '%s' (children: '%s')" % (self, self._parent, "', '".join(mySiblings))
+ raise ValueError(msg)
+ else: raise ValueError("Menu option '%s' doesn't have a parent" % self)
+
+ def __str__(self):
+ return self._label
+
+class Submenu(MenuItem):
+ """
+ Menu item that lists other menu options.
+ """
+
+ def __init__(self, label):
+ MenuItem.__init__(self, label, None)
+ self._children = []
+
+ def getLabel(self):
+ """
+ Provides our label with a ">" suffix to indicate that we have suboptions.
+ """
+
+ myLabel = MenuItem.getLabel(self)[1]
+ return ("", myLabel, " >")
+
+ def add(self, menuItem):
+ """
+ Adds the given menu item to our listing. This raises a ValueError if the
+ item already has a parent.
+
+ Arguments:
+ menuItem - menu option to be added
+ """
+
+ if menuItem.getParent():
+ raise ValueError("Menu option '%s' already has a parent" % menuItem)
+ else:
+ menuItem._parent = self
+ self._children.append(menuItem)
+
+ def getChildren(self):
+ """
+ Provides the menu and submenus we contain.
+ """
+
+ return list(self._children)
+
+ def isEmpty(self):
+ """
+ True if we have no children, false otherwise.
+ """
+
+ return not bool(self._children)
+
diff --git a/src/cli/menu/menu.py b/src/cli/menu/menu.py
new file mode 100644
index 0000000..02f87ee
--- /dev/null
+++ b/src/cli/menu/menu.py
@@ -0,0 +1,222 @@
+
+import curses
+
+import cli.popups
+import cli.controller
+import cli.menu.item
+
+from util import uiTools
+
+def makeMenu():
+ """
+ Constructs the base menu and all of its contents.
+ """
+
+ baseMenu = cli.menu.item.Submenu("")
+
+ fileMenu = cli.menu.item.Submenu("File")
+ fileMenu.add(cli.menu.item.MenuItem("Exit", None))
+ baseMenu.add(fileMenu)
+
+ logsMenu = cli.menu.item.Submenu("Logs")
+ logsMenu.add(cli.menu.item.MenuItem("Events", None))
+ logsMenu.add(cli.menu.item.MenuItem("Clear", None))
+ logsMenu.add(cli.menu.item.MenuItem("Save", None))
+ logsMenu.add(cli.menu.item.MenuItem("Filter", None))
+
+ duplicatesSubmenu = cli.menu.item.Submenu("Duplicates")
+ duplicatesSubmenu.add(cli.menu.item.MenuItem("Hidden", None))
+ duplicatesSubmenu.add(cli.menu.item.MenuItem("Visible", None))
+ logsMenu.add(duplicatesSubmenu)
+ baseMenu.add(logsMenu)
+
+ viewMenu = cli.menu.item.Submenu("View")
+ viewMenu.add(cli.menu.item.MenuItem("Graph", None))
+ viewMenu.add(cli.menu.item.MenuItem("Connections", None))
+ viewMenu.add(cli.menu.item.MenuItem("Configuration", None))
+ viewMenu.add(cli.menu.item.MenuItem("Configuration File", None))
+ baseMenu.add(viewMenu)
+
+ graphMenu = cli.menu.item.Submenu("Graph")
+ graphMenu.add(cli.menu.item.MenuItem("Stats", None))
+
+ sizeSubmenu = cli.menu.item.Submenu("Size")
+ sizeSubmenu.add(cli.menu.item.MenuItem("Increase", None))
+ sizeSubmenu.add(cli.menu.item.MenuItem("Decrease", None))
+ graphMenu.add(sizeSubmenu)
+
+ graphMenu.add(cli.menu.item.MenuItem("Update Interval", None))
+
+ boundsSubmenu = cli.menu.item.Submenu("Bounds")
+ boundsSubmenu.add(cli.menu.item.MenuItem("Local Max", None))
+ boundsSubmenu.add(cli.menu.item.MenuItem("Global Max", None))
+ boundsSubmenu.add(cli.menu.item.MenuItem("Tight", None))
+ graphMenu.add(boundsSubmenu)
+ baseMenu.add(graphMenu)
+
+ connectionsMenu = cli.menu.item.Submenu("Connections")
+ connectionsMenu.add(cli.menu.item.MenuItem("Identity", None))
+ connectionsMenu.add(cli.menu.item.MenuItem("Resolver", None))
+ connectionsMenu.add(cli.menu.item.MenuItem("Sort Order", None))
+ baseMenu.add(connectionsMenu)
+
+ configurationMenu = cli.menu.item.Submenu("Configuration")
+
+ commentsSubmenu = cli.menu.item.Submenu("Comments")
+ commentsSubmenu.add(cli.menu.item.MenuItem("Hidden", None))
+ commentsSubmenu.add(cli.menu.item.MenuItem("Visible", None))
+ configurationMenu.add(commentsSubmenu)
+
+ configurationMenu.add(cli.menu.item.MenuItem("Reload", None))
+ configurationMenu.add(cli.menu.item.MenuItem("Reset Tor", None))
+ baseMenu.add(configurationMenu)
+
+ return baseMenu
+
+class MenuCursor:
+ """
+ Tracks selection and key handling in the menu.
+ """
+
+ def __init__(self, initialSelection):
+ self._selection = initialSelection
+ self._isDone = False
+
+ def isDone(self):
+ """
+ Provides true if a selection has indicated that we should close the menu.
+ False otherwise.
+ """
+
+ return self._isDone
+
+ def getSelection(self):
+ """
+ Provides the currently selected menu item.
+ """
+
+ return self._selection
+
+ def handleKey(self, key):
+ isSelectionSubmenu = isinstance(self._selection, cli.menu.item.Submenu)
+ selectionHierarchy = self._selection.getHierarchy()
+
+ if uiTools.isSelectionKey(key):
+ if isSelectionSubmenu:
+ if not self._selection.isEmpty():
+ self._selection = self._selection.getChildren()[0]
+ else: self._isDone = self._selection.select()
+ elif key == curses.KEY_UP:
+ self._selection = self._selection.prev()
+ elif key == curses.KEY_DOWN:
+ self._selection = self._selection.next()
+ elif key == curses.KEY_LEFT:
+ if len(selectionHierarchy) <= 3:
+ # shift to the previous main submenu
+ prevSubmenu = selectionHierarchy[1].prev()
+ self._selection = prevSubmenu.getChildren()[0]
+ else:
+ # go up a submenu level
+ self._selection = self._selection.getParent()
+ elif key == curses.KEY_RIGHT:
+ if isSelectionSubmenu:
+ # open submenu (same as making a selection)
+ if not self._selection.isEmpty():
+ self._selection = self._selection.getChildren()[0]
+ else:
+ # shift to the next main submenu
+ nextSubmenu = selectionHierarchy[1].next()
+ self._selection = nextSubmenu.getChildren()[0]
+ elif key in (27, ord('m'), ord('M')):
+ # close menu
+ self._isDone = True
+
+def showMenu():
+ popup, _, _ = cli.popups.init(1, belowStatic = False)
+ if not popup: return
+ control = cli.controller.getController()
+
+ try:
+ # generates the menu and uses the initial selection of the first item in
+ # the file menu
+ menu = makeMenu()
+ cursor = MenuCursor(menu.getChildren()[0].getChildren()[0])
+
+ while not cursor.isDone():
+ # sets the background color
+ popup.win.clear()
+ popup.win.bkgd(' ', curses.A_STANDOUT | uiTools.getColor("red"))
+ selectionHierarchy = cursor.getSelection().getHierarchy()
+
+ # renders the menu bar, noting where the open submenu is positioned
+ drawLeft, selectionLeft = 0, 0
+
+ for topLevelItem in menu.getChildren():
+ drawFormat = curses.A_BOLD
+ if topLevelItem == selectionHierarchy[1]:
+ drawFormat |= curses.A_UNDERLINE
+ selectionLeft = drawLeft
+
+ drawLabel = " %s " % topLevelItem.getLabel()[1]
+ popup.addstr(0, drawLeft, drawLabel, drawFormat)
+ popup.addch(0, drawLeft + len(drawLabel), curses.ACS_VLINE)
+
+ drawLeft += len(drawLabel) + 1
+
+ # recursively shows opened submenus
+ _drawSubmenu(cursor, 1, 1, selectionLeft)
+
+ popup.win.refresh()
+
+ key = control.getScreen().getch()
+ cursor.handleKey(key)
+
+ # redraws the rest of the interface if we're rendering on it again
+ if not cursor.isDone():
+ for panelImpl in control.getDisplayPanels():
+ panelImpl.redraw(True)
+ finally: cli.popups.finalize()
+
+def _drawSubmenu(cursor, level, top, left):
+ selectionHierarchy = cursor.getSelection().getHierarchy()
+
+ # checks if there's nothing to display
+ if len(selectionHierarchy) < level + 2: return
+
+ # fetches the submenu and selection we're displaying
+ submenu = selectionHierarchy[level]
+ selection = selectionHierarchy[level + 1]
+
+ # gets the size of the prefix, middle, and suffix columns
+ allLabelSets = [entry.getLabel() for entry in submenu.getChildren()]
+ prefixColSize = max([len(entry[0]) for entry in allLabelSets])
+ middleColSize = max([len(entry[1]) for entry in allLabelSets])
+ suffixColSize = max([len(entry[2]) for entry in allLabelSets])
+
+ # formatted string so we can display aligned menu entries
+ labelFormat = " %%-%is%%-%is%%-%is " % (prefixColSize, middleColSize, suffixColSize)
+ menuWidth = len(labelFormat % ("", "", ""))
+
+ popup, _, _ = cli.popups.init(len(submenu.getChildren()), menuWidth, top, left, belowStatic = False)
+ if not popup: return
+
+ try:
+ # sets the background color
+ popup.win.bkgd(' ', curses.A_STANDOUT | uiTools.getColor("red"))
+
+ drawTop, selectionTop = 0, 0
+ for menuItem in submenu.getChildren():
+ if menuItem == selection:
+ drawFormat = curses.A_BOLD | uiTools.getColor("white")
+ selectionTop = drawTop
+ else: drawFormat = curses.A_NORMAL
+
+ popup.addstr(drawTop, 0, labelFormat % menuItem.getLabel(), drawFormat)
+ drawTop += 1
+
+ popup.win.refresh()
+
+ # shows the next submenu
+ _drawSubmenu(cursor, level + 1, top + selectionTop, left + menuWidth)
+ finally: cli.popups.finalize()
+
diff --git a/src/cli/popups.py b/src/cli/popups.py
index 0e50aa1..b90f95d 100644
--- a/src/cli/popups.py
+++ b/src/cli/popups.py
@@ -8,7 +8,7 @@ import cli.controller
from util import panel, uiTools
-def init(height = -1, width = -1, top = 0, left = 0):
+def init(height = -1, width = -1, top = 0, left = 0, belowStatic = True):
"""
Preparation for displaying a popup. This creates a popup with a valid
subwindow instance. If that's successful then the curses lock is acquired
@@ -17,14 +17,17 @@ def init(height = -1, width = -1, top = 0, left = 0):
Otherwise this leaves curses unlocked and returns None.
Arguments:
- height - maximum height of the popup
- width - maximum width of the popup
- top - top position, relative to the sticky content
- left - left position from the screen
+ height - maximum height of the popup
+ width - maximum width of the popup
+ top - top position, relative to the sticky content
+ left - left position from the screen
+ belowStatic - positions popup below static content if true
"""
control = cli.controller.getController()
- stickyHeight = sum(stickyPanel.getHeight() for stickyPanel in control.getStickyPanels())
+ if belowStatic:
+ stickyHeight = sum(stickyPanel.getHeight() for stickyPanel in control.getStickyPanels())
+ else: stickyHeight = 0
popup = panel.Panel(control.getScreen(), "popup", top + stickyHeight, left, height, width)
popup.setVisible(True)
diff --git a/src/util/panel.py b/src/util/panel.py
index 93b44c2..6fae341 100644
--- a/src/util/panel.py
+++ b/src/util/panel.py
@@ -484,7 +484,7 @@ class Panel():
# direction) from actual content to prevent crash when shrank
if self.win and self.maxX > x and self.maxY > y:
try:
- self.win.addstr(y, x, msg[:self.maxX - x - 1], attr)
+ self.win.addstr(y, x, msg[:self.maxX - x], attr)
except:
# this might produce a _curses.error during edge cases, for instance
# when resizing with visible popups
1
0
commit fbd07955c5376457a5a9ecc4e778dd4a9f97deb9
Author: Kamran Riaz Khan <krkhan(a)inspirated.com>
Date: Mon May 30 01:33:22 2011 +0500
Added drop-down second level menus.
Second level menus can now be brought down using the arrow key.
Popup init is modified to support top and left gaps, setLeft()
is added to Panel for left padding. Constructor arguments for Panel
are left unchanged so that existing panel-using code isn't broken.
---
src/cli/menu.py | 154 +++++++++++++++++++++++++++++++++++++++++++++++++----
src/cli/popups.py | 9 +++-
src/util/panel.py | 18 ++++++-
3 files changed, 168 insertions(+), 13 deletions(-)
diff --git a/src/cli/menu.py b/src/cli/menu.py
index 71b56a4..69538e0 100644
--- a/src/cli/menu.py
+++ b/src/cli/menu.py
@@ -8,19 +8,40 @@ import cli.controller
import popups
from util import log, panel, uiTools, menuItem
-TOPLEVEL = 0
+TOPLEVEL, SECONDLEVEL = range(2)
class Menu():
"""Displays a popup menu and sends keys to appropriate panels"""
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)))
+ menuItem.MenuItem(label="File" , children=(
+ menuItem.MenuItem(label="Exit" , callback=self._callbackDefault),)),
+ menuItem.MenuItem(label="Logs" , children=(
+ menuItem.MenuItem(label="Events" , callback=self._callbackDefault),
+ menuItem.MenuItem(label="Clear" , callback=self._callbackDefault),
+ menuItem.MenuItem(label="Save" , callback=self._callbackDefault),
+ menuItem.MenuItem(label="Filter" , callback=self._callbackDefault),
+ menuItem.MenuItem(label="Duplicates" , callback=self._callbackDefault),)),
+ menuItem.MenuItem(label="View" , children=(
+ menuItem.MenuItem(label="Graph" , callback=self._callbackDefault),
+ menuItem.MenuItem(label="Connections" , callback=self._callbackDefault),
+ menuItem.MenuItem(label="Configuration" , callback=self._callbackDefault),
+ menuItem.MenuItem(label="Configuration File" , callback=self._callbackDefault),)),
+ menuItem.MenuItem(label="Graph" , children=(
+ menuItem.MenuItem(label="Stats" , callback=self._callbackDefault),
+ menuItem.MenuItem(label="Size" , callback=self._callbackDefault),
+ menuItem.MenuItem(label="Update Interval" , callback=self._callbackDefault),
+ menuItem.MenuItem(label="Bounds" , callback=self._callbackDefault),)),
+ menuItem.MenuItem(label="Connections" , children=(
+ menuItem.MenuItem(label="Identity" , callback=self._callbackDefault),
+ menuItem.MenuItem(label="Resolver" , callback=self._callbackDefault),
+ menuItem.MenuItem(label="Sort Order" , callback=self._callbackDefault),)),
+ menuItem.MenuItem(label="Configuration" , children=(
+ menuItem.MenuItem(label="Comments" , callback=self._callbackDefault),
+ menuItem.MenuItem(label="Reload" , callback=self._callbackDefault),
+ menuItem.MenuItem(label="Reset Tor" , callback=self._callbackDefault),))
+ ))
self._first = [0]
self._selection = [0]
@@ -51,6 +72,10 @@ class Menu():
elif key == curses.KEY_LEFT:
if len(self._selection) == 1:
self._moveTopLevelLeft(width)
+ elif key == curses.KEY_DOWN:
+ if len(self._selection) == 1:
+ self._dropSecondLevel()
+ break
elif uiTools.isSelectionKey(key):
self._handleEvent()
break
@@ -58,17 +83,42 @@ class Menu():
finally:
popups.finalize()
- def _calculateTopLevelWidths(self, width):
+ def _getCurrentTopLevelItem(self):
+ index = self._first[TOPLEVEL] + self._selection[TOPLEVEL]
+ return self._rootItem.getChildren()[index]
+
+ def _calculateTopLevelWidths(self, width=0):
labels = [menuItem.getLabel() for menuItem in self._rootItem.getChildren()]
# width per label is set according to the longest label
labelwidth = max(map(len, labels)) + 2
- # total number of labels that can be printed in current width
+ # total number of labels that can be printed in supplied width
printable = min(width / labelwidth - 1, self._rootItem.getChildrenCount())
return (labelwidth, printable)
+ def _calculateSecondLevelWidths(self):
+ parent = self._getCurrentTopLevelItem()
+
+ labels = [menuItem.getLabel() for menuItem in parent.getChildren()]
+
+ labelwidth = max(map(len, labels))
+
+ return labelwidth
+
+ def _calculateSecondLevelHeights(self, height=0):
+ control = cli.controller.getController()
+ height, _ = control.getScreen().getmaxyx()
+ topSize = sum(stickyPanel.getHeight() for stickyPanel in control.getStickyPanels())
+ height = height - topSize
+
+ parent = self._getCurrentTopLevelItem()
+
+ printable = min(height - 4, parent.getChildrenCount())
+
+ return printable if printable else parent.getChildrenCount()
+
def _moveTopLevelRight(self, width):
_, printable = self._calculateTopLevelWidths(width)
@@ -90,7 +140,7 @@ class Menu():
self._selection[TOPLEVEL] = self._selection[TOPLEVEL] - 1
else:
if self._first[TOPLEVEL] == 0:
- self._first[TOPLEVEL] = (self._rootItem.getChildrenCount() / printable) * printable
+ self._first[TOPLEVEL] = ((self._rootItem.getChildrenCount() / printable) * printable) % self._rootItem.getChildrenCount()
else:
self._first[TOPLEVEL] = abs(self._first[TOPLEVEL] - printable) % self._rootItem.getChildrenCount()
self._selection[TOPLEVEL] = self._rootItem.getChildrenCount() - self._first[TOPLEVEL] - 1
@@ -115,6 +165,90 @@ class Menu():
popup.addch(top, left, curses.ACS_VLINE)
left = left + 1
+ def _dropSecondLevel(self):
+ self._first.append(0)
+ self._selection.append(0)
+
+ labelwidth = self._calculateSecondLevelWidths()
+ printable = self._calculateSecondLevelHeights()
+
+ toplabelwidth, _ = self._calculateTopLevelWidths()
+ left = (toplabelwidth + 2) * self._selection[TOPLEVEL]
+
+ popup, width, height = popups.init(height=printable+2, width=labelwidth+2, top=2, left=left)
+
+ if popup.win:
+ try:
+ while True:
+ popup.win.erase()
+ popup.win.box()
+
+ self._drawSecondLevel(popup, width, height)
+
+ popup.win.refresh()
+
+ control = cli.controller.getController()
+ key = control.getScreen().getch()
+
+ if key == curses.KEY_DOWN:
+ self._moveSecondLevelDown(height)
+ elif key == curses.KEY_UP:
+ self._moveSecondLevelUp(height)
+ elif uiTools.isSelectionKey(key):
+ self._handleEvent()
+ self._first.pop()
+ self._selection.pop()
+ break
+
+ finally:
+ popups.finalize()
+
+ def _drawSecondLevel(self, popup, width, height):
+ printable = self._calculateSecondLevelHeights()
+ parent = self._getCurrentTopLevelItem()
+ children = parent.getChildren()[self._first[SECONDLEVEL]:self._first[SECONDLEVEL] + printable]
+
+ toplabelwidth, _ = self._calculateTopLevelWidths(width)
+
+ top = 1
+ left = 1
+ for (index, item) in enumerate(children):
+ labelformat = curses.A_STANDOUT if index == self._selection[SECONDLEVEL] else curses.A_NORMAL
+
+ popup.addstr(top, left, item.getLabel(), labelformat)
+ top = top + 1
+
+ def _moveSecondLevelDown(self, height):
+ printable = self._calculateSecondLevelHeights()
+ parent = self._getCurrentTopLevelItem()
+
+ if self._selection[SECONDLEVEL] < printable - 1:
+ self._selection[SECONDLEVEL] = self._selection[SECONDLEVEL] + 1
+ else:
+ self._selection[SECONDLEVEL] = 0
+ if printable < parent.getChildrenCount():
+ self._first[SECONDLEVEL] = (self._first[SECONDLEVEL] + printable) % parent.getChildrenCount()
+
+ if self._first[SECONDLEVEL] + self._selection[SECONDLEVEL] == parent.getChildrenCount():
+ self._first[SECONDLEVEL] = 0
+ self._selection[SECONDLEVEL] = 0
+
+ def _moveSecondLevelUp(self, height):
+ printable = self._calculateSecondLevelHeights()
+ parent = self._getCurrentTopLevelItem()
+
+ if self._selection[SECONDLEVEL] > 0:
+ self._selection[SECONDLEVEL] = self._selection[SECONDLEVEL] - 1
+ else:
+ if self._first[SECONDLEVEL] == 0:
+ self._first[SECONDLEVEL] = ((parent.getChildrenCount() / printable) * printable) % parent.getChildrenCount()
+ else:
+ self._first[SECONDLEVEL] = abs(self._first[SECONDLEVEL] - printable) % parent.getChildrenCount()
+ self._selection[SECONDLEVEL] = parent.getChildrenCount() - self._first[SECONDLEVEL] - 1
+
+ if self._selection[SECONDLEVEL] > printable:
+ self._selection[SECONDLEVEL] = printable - 1
+
def _handleEvent(self):
item = self._rootItem
sums = [sum(values) for values in zip(self._first, self._selection)]
diff --git a/src/cli/popups.py b/src/cli/popups.py
index 7ed5302..b3eb105 100644
--- a/src/cli/popups.py
+++ b/src/cli/popups.py
@@ -8,7 +8,7 @@ import cli.controller
from util import panel, uiTools
-def init(height = -1, width = -1):
+def init(height = -1, width = -1, top = -1, left = -1):
"""
Preparation for displaying a popup. This creates a popup with a valid
subwindow instance. If that's successful then the curses lock is acquired
@@ -23,8 +23,15 @@ def init(height = -1, width = -1):
control = cli.controller.getController()
topSize = sum(stickyPanel.getHeight() for stickyPanel in control.getStickyPanels())
+ leftSize = 0
+
+ if top != -1:
+ topSize = topSize + top
+ if left != -1:
+ leftSize = left
popup = panel.Panel(control.getScreen(), "popup", topSize, height, width)
+ popup.setLeft(leftSize)
popup.setVisible(True)
# Redraws the popup to prepare a subwindow instance. If none is spawned then
diff --git a/src/util/panel.py b/src/util/panel.py
index a104a07..4fc2158 100644
--- a/src/util/panel.py
+++ b/src/util/panel.py
@@ -74,6 +74,7 @@ class Panel():
self.pauseTime = -1
self.top = top
+ self.left = 0
self.height = height
self.width = width
@@ -261,6 +262,18 @@ class Panel():
"""
return self.height
+
+ def setLeft(self, left):
+ """
+ Changes the position where subwindows are placed within its parent.
+
+ Arguments:
+ top - positioning of top within parent
+ """
+
+ if self.left != left:
+ self.left = left
+ self.win = None
def setHeight(self, height):
"""
@@ -303,6 +316,7 @@ class Panel():
newHeight, newWidth = self.parent.getmaxyx()
setHeight, setWidth = self.getHeight(), self.getWidth()
newHeight = max(0, newHeight - self.top)
+ newWidth = max(0, newWidth - self.left)
if setHeight != -1: newHeight = min(newHeight, setHeight)
if setWidth != -1: newWidth = min(newWidth, setWidth)
return (newHeight, newWidth)
@@ -569,7 +583,7 @@ class Panel():
# temporary subwindow for user input
displayWidth = self.getPreferredSize()[1]
- inputSubwindow = self.parent.subwin(1, displayWidth - x, self.top, x)
+ inputSubwindow = self.parent.subwin(1, displayWidth - x, self.top, self.left + x)
# prepopulates the initial text
if initialText: inputSubwindow.addstr(0, 0, initialText)
@@ -682,7 +696,7 @@ class Panel():
# would mean far more complicated code and no more selective refreshing)
if recreate:
- self.win = self.parent.subwin(newHeight, newWidth, self.top, 0)
+ self.win = self.parent.subwin(newHeight, newWidth, self.top, self.left)
# note: doing this log before setting win produces an infinite loop
msg = "recreating panel '%s' with the dimensions of %i/%i" % (self.getName(), newHeight, newWidth)
1
0

[arm/release] Replaced namedtuples with MenuItem instances, fixed left arrow key on
by atagar@torproject.org 17 Jul '11
by atagar@torproject.org 17 Jul '11
17 Jul '11
commit cf4ae8454debdf8a9ace9a4f4cc3e4536152d1dd
Author: Kamran Riaz Khan <krkhan(a)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)
+
1
0

[arm/release] Support long top menus on smaller screens, code review fixes.
by atagar@torproject.org 17 Jul '11
by atagar@torproject.org 17 Jul '11
17 Jul '11
commit fd920dfd4fc88d14b7e569b2513b449cc63cae99
Author: Kamran Riaz Khan <krkhan(a)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)
1
0

17 Jul '11
commit f7375855453621fed4919021853bdab5ec017fd6
Author: Kamran Riaz Khan <krkhan(a)inspirated.com>
Date: Tue May 31 02:38:07 2011 +0500
fix: Remove calculateSecondLevel*() methods.
---
src/cli/menu.py | 23 +----------------------
1 files changed, 1 insertions(+), 22 deletions(-)
diff --git a/src/cli/menu.py b/src/cli/menu.py
index 8ce97c4..5a51797 100644
--- a/src/cli/menu.py
+++ b/src/cli/menu.py
@@ -148,27 +148,6 @@ class Menu():
return (labelwidth, printable)
- def _calculateSecondLevelWidths(self):
- parent = self._getCurrentTopLevelItem()
-
- labels = [menuItem.getLabel() for menuItem in parent.getChildren()]
-
- labelwidth = max(map(len, labels))
-
- return labelwidth
-
- def _calculateSecondLevelHeights(self, height=0):
- control = cli.controller.getController()
- height, _ = control.getScreen().getmaxyx()
- topSize = sum(stickyPanel.getHeight() for stickyPanel in control.getStickyPanels())
- height = height - topSize
-
- parent = self._getCurrentTopLevelItem()
-
- printable = min(height - 4, parent.getChildrenCount())
-
- return printable if printable else parent.getChildrenCount()
-
def _calculateNLevelWidths(self, level=0):
parent = self._getCurrentItem(level)
@@ -317,7 +296,7 @@ class Menu():
self._selection[PARENTLEVEL] = 0
def _moveNLevelUp(self, height):
- printable = self._calculateSecondLevelHeights()
+ printable = self._calculateNLevelHeights(level=PARENTLEVEL)
parent = self._getCurrentItem(level=PARENTLEVEL)
if self._selection[PARENTLEVEL] > 0:
1
0