/usr/share/arm/cli/menu/menu.py is in tor-arm 1.4.5.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | """
Display logic for presenting the menu.
"""
import curses
import cli.popups
import cli.controller
import cli.menu.item
import cli.menu.actions
from util import uiTools
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 = cli.menu.actions.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()
# provide a message saying how to close the menu
control.setMsg("Press m or esc to close the menu.", curses.A_BOLD, True)
# 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()
curses.cbreak()
key = control.getScreen().getch()
cursor.handleKey(key)
# redraws the rest of the interface if we're rendering on it again
if not cursor.isDone(): control.redraw()
finally:
control.setMsg()
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()
|