def handleKey(self, key): self.valsLock.acquire() isKeystrokeConsumed = True if uiTools.isScrollKey(key): pageHeight = self.getPreferredSize()[0] - 1 if self._showDetails: pageHeight -= (DETAILS_HEIGHT + 1) isChanged = self._scroller.handleKey(key, self._entryLines, pageHeight) if isChanged: self.redraw(True) elif uiTools.isSelectionKey(key): self._showDetails = not self._showDetails self.redraw(True) elif key == ord('s') or key == ord('S'): self.showSortDialog() elif key == ord('u') or key == ord('U'): # provides a menu to pick the connection resolver title = "Resolver Util:" options = ["auto"] + list(connections.Resolver) connResolver = connections.getResolver("tor") currentOverwrite = connResolver.overwriteResolver if currentOverwrite == None: oldSelection = 0 else: oldSelection = options.index(currentOverwrite) selection = cli.popups.showMenu(title, options, oldSelection) # applies new setting if selection != -1: selectedOption = options[selection] if selection != 0 else None connResolver.overwriteResolver = selectedOption elif key == ord('l') or key == ord('L'): # provides a menu to pick the primary information we list connections by title = "List By:" options = list(entries.ListingType) # dropping the HOSTNAME listing type until we support displaying that content options.remove(cli.connections.entries.ListingType.HOSTNAME) oldSelection = options.index(self.getListingType()) selection = cli.popups.showMenu(title, options, oldSelection) # applies new setting if selection != -1: self.setListingType(options[selection]) elif key == ord('d') or key == ord('D'): # presents popup for raw consensus data descriptorPopup.showDescriptorPopup(self) elif (key == ord('c') or key == ord('C')) and self.isClientsAllowed(): countPopup.showCountDialog(countPopup.CountType.CLIENT_LOCALE, self._clientLocaleUsage) elif (key == ord('e') or key == ord('E')) and self.isExitsAllowed(): countPopup.showCountDialog(countPopup.CountType.EXIT_PORT, self._exitPortUsage) else: isKeystrokeConsumed = False self.valsLock.release() return isKeystrokeConsumed
def handleKey(self, key): self.valsLock.acquire() isKeystrokeConsumed = True if uiTools.isScrollKey(key): pageHeight = self.getPreferredSize()[0] - 1 if self._showDetails: pageHeight -= (DETAILS_HEIGHT + 1) isChanged = self._scroller.handleKey(key, self._entryLines, pageHeight) if isChanged: self.redraw(True) elif uiTools.isSelectionKey(key): self._showDetails = not self._showDetails self.redraw(True) elif key == ord('s') or key == ord('S'): self.showSortDialog() elif key == ord('u') or key == ord('U'): # provides a menu to pick the connection resolver title = "Resolver Util:" options = ["auto"] + connections.Resolver.values() connResolver = connections.getResolver("tor") currentOverwrite = connResolver.overwriteResolver if currentOverwrite == None: oldSelection = 0 else: oldSelection = options.index(currentOverwrite) selection = cli.popups.showMenu(title, options, oldSelection) # applies new setting if selection != -1: selectedOption = options[selection] if selection != 0 else None connResolver.overwriteResolver = selectedOption elif key == ord('l') or key == ord('L'): # provides a menu to pick the primary information we list connections by title = "List By:" options = entries.ListingType.values() # dropping the HOSTNAME listing type until we support displaying that content options.remove(cli.connections.entries.ListingType.HOSTNAME) oldSelection = options.index(self._listingType) selection = cli.popups.showMenu(title, options, oldSelection) # applies new setting if selection != -1: self.setListingType(options[selection]) elif key == ord('d') or key == ord('D'): # presents popup for raw consensus data descriptorPopup.showDescriptorPopup(self) elif (key == ord('c') or key == ord('C')) and self.isClientsAllowed(): countPopup.showCountDialog(countPopup.CountType.CLIENT_LOCALE, self._clientLocaleUsage) elif (key == ord('e') or key == ord('E')) and self.isExitsAllowed(): countPopup.showCountDialog(countPopup.CountType.EXIT_PORT, self._exitPortUsage) else: isKeystrokeConsumed = False self.valsLock.release() return isKeystrokeConsumed
def handleKey(self, key): self.valsLock.acquire() if uiTools.isScrollKey(key): pageHeight = self.getPreferredSize()[0] - 1 detailPanelHeight = self._config["features.config.selectionDetails.height"] if detailPanelHeight > 0 and detailPanelHeight + 2 <= pageHeight: pageHeight -= (detailPanelHeight + 1) isChanged = self.scroller.handleKey(key, self.confContents, pageHeight) if isChanged: self.redraw(True) self.valsLock.release()
def handleKey(self, key): self.valsLock.acquire() if uiTools.isScrollKey(key): pageHeight = self.getPreferredSize()[0] - 1 detailPanelHeight = self._config[ "features.config.selectionDetails.height"] if detailPanelHeight > 0 and detailPanelHeight + 2 <= pageHeight: pageHeight -= (detailPanelHeight + 1) isChanged = self.scroller.handleKey(key, self.confContents, pageHeight) if isChanged: self.redraw(True) self.valsLock.release()
def handleKey(self, key): isKeystrokeConsumed = True if uiTools.isScrollKey(key): pageHeight = self.getPreferredSize()[0] - 1 newScroll = uiTools.getScrollPosition(key, self.scroll, pageHeight, self.lastContentHeight) if self.scroll != newScroll: self.valsLock.acquire() self.scroll = newScroll self.redraw(True) self.valsLock.release() elif key in (ord('u'), ord('U')): self.valsLock.acquire() self.showDuplicates = not self.showDuplicates self.redraw(True) self.valsLock.release() elif key == ord('c') or key == ord('C'): msg = "This will clear the log. Are you sure (c again to confirm)?" keyPress = popups.showMsg(msg, attr = curses.A_BOLD) if keyPress in (ord('c'), ord('C')): self.clear() elif key == ord('f') or key == ord('F'): # Provides menu to pick regular expression filters or adding new ones: # for syntax see: http://docs.python.org/library/re.html#regular-expression-syntax options = ["None"] + self.filterOptions + ["New..."] oldSelection = 0 if not self.regexFilter else 1 # does all activity under a curses lock to prevent redraws when adding # new filters panel.CURSES_LOCK.acquire() try: selection = popups.showMenu("Log Filter:", options, oldSelection) # applies new setting if selection == 0: self.setFilter(None) elif selection == len(options) - 1: # selected 'New...' option - prompt user to input regular expression self.showFilterPrompt() elif selection != -1: self.makeFilterSelection(self.filterOptions[selection - 1]) finally: panel.CURSES_LOCK.release() if len(self.filterOptions) > MAX_REGEX_FILTERS: del self.filterOptions[MAX_REGEX_FILTERS:] elif key == ord('e') or key == ord('E'): self.showEventSelectionPrompt() elif key == ord('a') or key == ord('A'): self.showSnapshotPrompt() else: isKeystrokeConsumed = False return isKeystrokeConsumed
def handleKey(self, key): isKeystrokeConsumed = True if uiTools.isSelectionKey(key): self.prompt() elif uiTools.isScrollKey(key) and not self.isInputMode: pageHeight = self.getPreferredSize()[0] - 1 displayLength = len(self.interpretor.getDisplayContents(PROMPT_LINE)) newScroll = uiTools.getScrollPosition(key, self.scroll, pageHeight, displayLength) if self.scroll != newScroll: self.scroll = newScroll self.redraw(True) else: isKeystrokeConsumed = False return isKeystrokeConsumed
def handleKey(self, key): if uiTools.isScrollKey(key): pageHeight = self.getPreferredSize()[0] - 1 newScroll = uiTools.getScrollPosition(key, self.scroll, pageHeight, self.lastContentHeight) if self.scroll != newScroll: self.valsLock.acquire() self.scroll = newScroll self.redraw(True) self.valsLock.release() elif key in (ord('u'), ord('U')): self.valsLock.acquire() self.showDuplicates = not self.showDuplicates self.redraw(True) self.valsLock.release()
def handleKey(self, key): self.valsLock.acquire() if uiTools.isScrollKey(key): pageHeight = self.getPreferredSize()[0] - 1 newScroll = uiTools.getScrollPosition(key, self.scroll, pageHeight, self._lastContentHeight) if self.scroll != newScroll: self.scroll = newScroll self.redraw(True) elif key == ord('n') or key == ord('N'): self.showLineNum = not self.showLineNum self._lastContentHeightArgs = None self.redraw(True) elif key == ord('s') or key == ord('S'): self.stripComments = not self.stripComments self._lastContentHeightArgs = None self.redraw(True) self.valsLock.release()
def handleKey(self, key): # cursor or scroll movement #if key in (curses.KEY_UP, curses.KEY_DOWN, curses.KEY_PPAGE, curses.KEY_NPAGE): if uiTools.isScrollKey(key): pageHeight = self.getPreferredSize()[0] - 1 if self.showingDetails: pageHeight -= 8 self.connectionsLock.acquire() try: # determines location parameter to use if self.isCursorEnabled: try: currentLoc = self.connections.index(self.cursorSelection) except ValueError: currentLoc = self.cursorLoc # fall back to nearby entry else: currentLoc = self.scroll # location offset if key == curses.KEY_UP: shift = -1 elif key == curses.KEY_DOWN: shift = 1 elif key == curses.KEY_PPAGE: shift = -pageHeight + 1 if self.isCursorEnabled else -pageHeight elif key == curses.KEY_NPAGE: shift = pageHeight - 1 if self.isCursorEnabled else pageHeight elif key == curses.KEY_HOME: shift = -currentLoc elif key == curses.KEY_END: shift = len(self.connections) # always below the lower bound newLoc = currentLoc + shift # restricts to valid bounds maxLoc = len(self.connections) - 1 if self.isCursorEnabled else len(self.connections) - pageHeight newLoc = max(0, min(newLoc, maxLoc)) # applies to proper parameter if self.isCursorEnabled and self.connections: self.cursorSelection, self.cursorLoc = self.connections[newLoc], newLoc else: self.scroll = newLoc finally: self.connectionsLock.release() elif key == ord('r') or key == ord('R'): self.allowDNS = not self.allowDNS if not self.allowDNS: hostnames.setPaused(True) elif self.listingType == LIST_HOSTNAME: hostnames.setPaused(False) else: return # skip following redraw self.redraw(True)
def handleKey(self, key): self.valsLock.acquire() isKeystrokeConsumed = True if uiTools.isScrollKey(key): pageHeight = self.getPreferredSize()[0] - 1 newScroll = uiTools.getScrollPosition(key, self.scroll, pageHeight, self._lastContentHeight) if self.scroll != newScroll: self.scroll = newScroll self.redraw(True) elif key == ord("n") or key == ord("N"): self.setLineNumberVisible(not self.showLineNum) elif key == ord("s") or key == ord("S"): self.setCommentsVisible(self.stripComments) elif key == ord("r") or key == ord("R"): self.reloadTorrc() else: isKeystrokeConsumed = False self.valsLock.release() return isKeystrokeConsumed
def handleKey(self, key): self.valsLock.acquire() isKeystrokeConsumed = True if uiTools.isScrollKey(key): pageHeight = self.getPreferredSize()[0] - 1 newScroll = uiTools.getScrollPosition(key, self.scroll, pageHeight, self._lastContentHeight) if self.scroll != newScroll: self.scroll = newScroll self.redraw(True) elif key == ord('n') or key == ord('N'): self.setLineNumberVisible(not self.showLineNum) elif key == ord('s') or key == ord('S'): self.setCommentsVisible(self.stripComments) elif key == ord('r') or key == ord('R'): self.reloadTorrc() else: isKeystrokeConsumed = False self.valsLock.release() return isKeystrokeConsumed
def handleKey(self, key): self.valsLock.acquire() isKeystrokeConsumed = True if uiTools.isScrollKey(key): pageHeight = self.getPreferredSize()[0] - 1 detailPanelHeight = self._config["features.config.selectionDetails.height"] if detailPanelHeight > 0 and detailPanelHeight + 2 <= pageHeight: pageHeight -= (detailPanelHeight + 1) isChanged = self.scroller.handleKey(key, self._getConfigOptions(), pageHeight) if isChanged: self.redraw(True) elif uiTools.isSelectionKey(key) and self._getConfigOptions(): # Prompts the user to edit the selected configuration value. The # interface is locked to prevent updates between setting the value # and showing any errors. panel.CURSES_LOCK.acquire() try: selection = self.getSelection() configOption = selection.get(Field.OPTION) if selection.isUnset(): initialValue = "" else: initialValue = selection.get(Field.VALUE) promptMsg = "%s Value (esc to cancel): " % configOption isPrepopulated = self._config["features.config.prepopulateEditValues"] newValue = popups.inputPrompt(promptMsg, initialValue if isPrepopulated else "") if newValue != None and newValue != initialValue: try: if selection.get(Field.TYPE) == "Boolean": # if the value's a boolean then allow for 'true' and 'false' inputs if newValue.lower() == "true": newValue = "1" elif newValue.lower() == "false": newValue = "0" elif selection.get(Field.TYPE) == "LineList": # setOption accepts list inputs when there's multiple values newValue = newValue.split(",") torTools.getConn().setOption(configOption, newValue) # forces the label to be remade with the new value selection.labelCache = None # resets the isDefault flag customOptions = torConfig.getCustomOptions() selection.fields[Field.IS_DEFAULT] = not configOption in customOptions self.redraw(True) except Exception, exc: popups.showMsg("%s (press any key)" % exc) finally: panel.CURSES_LOCK.release() elif key == ord('a') or key == ord('A'): self.showAll = not self.showAll self.redraw(True) elif key == ord('s') or key == ord('S'): self.showSortDialog() elif key == ord('v') or key == ord('V'): self.showWriteDialog() else: isKeystrokeConsumed = False self.valsLock.release() return isKeystrokeConsumed
def showConfirmationDialog(torrcContents, torrcLocation): """ Shows a confirmation dialog with the given torrc contents, returning CANCEL, NEXT, or BACK based on the selection. Arguments: torrcContents - lines of torrc contents to be presented torrcLocation - path where the torrc will be placed """ torrcLines = torrcContents.split("\n") options = ["Cancel", "Back to Setup", "Start Tor"] control = cli.controller.getController() screenHeight = control.getScreen().getmaxyx()[0] stickyHeight = sum( [stickyPanel.getHeight() for stickyPanel in control.getStickyPanels()]) isScrollbarVisible = len(torrcLines) + stickyHeight + 5 > screenHeight xOffset = 3 if isScrollbarVisible else 0 popup, width, height = cli.popups.init(len(torrcLines) + 5, 84 + xOffset) if not popup: return False try: scroll, selection = 0, 2 curses.cbreak() while True: popup.win.erase() popup.win.box() # renders the scrollbar if isScrollbarVisible: popup.addScrollBar(scroll, scroll + height - 5, len(torrcLines), 1, height - 4, 1) # shows the path where the torrc will be placed titleMsg = "The following will be placed at '%s':" % torrcLocation popup.addstr(0, 0, titleMsg, curses.A_STANDOUT) # renders the torrc contents for i in range(scroll, min(len(torrcLines), height - 5 + scroll)): # parses the argument and comment from options option, arg, comment = uiTools.cropStr(torrcLines[i], width - 4 - xOffset), "", "" div = option.find("#") if div != -1: option, comment = option[:div], option[div:] div = option.strip().find(" ") if div != -1: option, arg = option[:div], option[div:] drawX = 2 + xOffset popup.addstr(i + 1 - scroll, drawX, option, curses.A_BOLD | uiTools.getColor("green")) drawX += len(option) popup.addstr(i + 1 - scroll, drawX, arg, curses.A_BOLD | uiTools.getColor("cyan")) drawX += len(arg) popup.addstr(i + 1 - scroll, drawX, comment, uiTools.getColor("white")) # divider between the torrc and the options popup.addch(height - 4, 0, curses.ACS_LTEE) popup.addch(height - 4, width, curses.ACS_RTEE) popup.hline(height - 4, 1, width - 1) if isScrollbarVisible: popup.addch(height - 4, 2, curses.ACS_BTEE) # renders the selection options confirmationMsg = "Run tor with the above configuration?" popup.addstr(height - 3, width - len(confirmationMsg) - 1, confirmationMsg, uiTools.getColor("green") | curses.A_BOLD) drawX = width - 1 for i in range(len(options) - 1, -1, -1): optionLabel = " %s " % options[i] drawX -= (len(optionLabel) + 4) selectionFormat = curses.A_STANDOUT if i == selection else curses.A_NORMAL popup.addstr(height - 2, drawX, "[", uiTools.getColor("green")) popup.addstr( height - 2, drawX + 1, optionLabel, uiTools.getColor("green") | selectionFormat | curses.A_BOLD) popup.addstr(height - 2, drawX + len(optionLabel) + 1, "]", uiTools.getColor("green")) drawX -= 1 # space gap between the options popup.win.refresh() key = cli.controller.getController().getScreen().getch() if key == curses.KEY_LEFT: selection = (selection - 1) % len(options) elif key == curses.KEY_RIGHT: selection = (selection + 1) % len(options) elif uiTools.isScrollKey(key): scroll = uiTools.getScrollPosition(key, scroll, height - 5, len(torrcLines)) elif uiTools.isSelectionKey(key): if selection == 0: return CANCEL elif selection == 1: return BACK else: return NEXT elif key in (27, ord('q'), ord('Q')): return CANCEL finally: cli.popups.finalize()
def showDescriptorPopup(connPanel): """ Presents consensus descriptor in popup window with the following controls: Up, Down, Page Up, Page Down - scroll descriptor Right, Left - next / previous connection Enter, Space, d, D - close popup Arguments: connPanel - connection panel providing the dialog """ # hides the title of the connection panel connPanel.setTitleVisible(False) connPanel.redraw(True) control = cli.controller.getController() panel.CURSES_LOCK.acquire() isDone = False try: while not isDone: selection = connPanel.getSelection() if not selection: break fingerprint = selection.foreign.getFingerprint() if fingerprint == "UNKNOWN": fingerprint = None displayText = getDisplayText(fingerprint) displayColor = cli.connections.connEntry.CATEGORY_COLOR[selection.getType()] showLineNumber = fingerprint != None # determines the maximum popup size the displayText can fill pHeight, pWidth = getPreferredSize(displayText, connPanel.maxX, showLineNumber) popup, _, height = cli.popups.init(pHeight, pWidth) if not popup: break scroll, isChanged = 0, True try: while not isDone: if isChanged: draw(popup, fingerprint, displayText, displayColor, scroll, showLineNumber) isChanged = False key = control.getScreen().getch() if uiTools.isScrollKey(key): # TODO: This is a bit buggy in that scrolling is by displayText # lines rather than the displayed lines, causing issues when # content wraps. The result is that we can't have a scrollbar and # can't scroll to the bottom if there's a multi-line being # displayed. However, trying to correct this introduces a big can # of worms and after hours decided that this isn't worth the # effort... newScroll = uiTools.getScrollPosition(key, scroll, height - 2, len(displayText)) if scroll != newScroll: scroll, isChanged = newScroll, True elif uiTools.isSelectionKey(key) or key in (ord('d'), ord('D')): isDone = True # closes popup elif key in (curses.KEY_LEFT, curses.KEY_RIGHT): # navigation - pass on to connPanel and recreate popup connPanel.handleKey(curses.KEY_UP if key == curses.KEY_LEFT else curses.KEY_DOWN) break finally: cli.popups.finalize() finally: connPanel.setTitleVisible(True) connPanel.redraw(True) panel.CURSES_LOCK.release()
def handleKey(self, key): self.valsLock.acquire() isKeystrokeConsumed = True if uiTools.isScrollKey(key): pageHeight = self.getPreferredSize()[0] - 1 detailPanelHeight = CONFIG["features.config.selectionDetails.height"] if detailPanelHeight > 0 and detailPanelHeight + 2 <= pageHeight: pageHeight -= (detailPanelHeight + 1) isChanged = self.scroller.handleKey(key, self._getConfigOptions(), pageHeight) if isChanged: self.redraw(True) elif uiTools.isSelectionKey(key) and self._getConfigOptions(): # Prompts the user to edit the selected configuration value. The # interface is locked to prevent updates between setting the value # and showing any errors. panel.CURSES_LOCK.acquire() try: selection = self.getSelection() configOption = selection.get(Field.OPTION) if selection.isUnset(): initialValue = "" else: initialValue = selection.get(Field.VALUE) promptMsg = "%s Value (esc to cancel): " % configOption isPrepopulated = CONFIG["features.config.prepopulateEditValues"] newValue = popups.inputPrompt(promptMsg, initialValue if isPrepopulated else "") if newValue != None and newValue != initialValue: try: if selection.get(Field.TYPE) == "Boolean": # if the value's a boolean then allow for 'true' and 'false' inputs if newValue.lower() == "true": newValue = "1" elif newValue.lower() == "false": newValue = "0" elif selection.get(Field.TYPE) == "LineList": # setOption accepts list inputs when there's multiple values newValue = newValue.split(",") torTools.getConn().setOption(configOption, newValue) # forces the label to be remade with the new value selection.labelCache = None # resets the isDefault flag customOptions = torConfig.getCustomOptions() selection.fields[Field.IS_DEFAULT] = not configOption in customOptions self.redraw(True) except Exception, exc: popups.showMsg("%s (press any key)" % exc) finally: panel.CURSES_LOCK.release() elif key == ord('a') or key == ord('A'): self.showAll = not self.showAll self.redraw(True) elif key == ord('s') or key == ord('S'): self.showSortDialog() elif key == ord('v') or key == ord('V'): self.showWriteDialog() else: isKeystrokeConsumed = False self.valsLock.release() return isKeystrokeConsumed
def showHelpPopup(): """ Presents a popup with instructions for the current page's hotkeys. This returns the user input used to close the popup. If the popup didn't close properly, this is an arrow, enter, or scroll key then this returns None. """ popup, _, height = init(9, 80) if not popup: return exitKey = None try: control = cli.controller.getController() pagePanels = control.getDisplayPanels() # the first page is the only one with multiple panels, and it looks better # with the log entries first, so reversing the order pagePanels.reverse() helpOptions = [] for entry in pagePanels: helpOptions += entry.getHelp() # test doing afterward in case of overwriting popup.win.box() popup.addstr(0, 0, "Page %i Commands:" % (control.getPage() + 1), curses.A_STANDOUT) for i in range(len(helpOptions)): if i / 2 >= height - 2: break # draws entries in the form '<key>: <description>[ (<selection>)]', for # instance... # u: duplicate log entries (hidden) key, description, selection = helpOptions[i] if key: description = ": " + description row = (i / 2) + 1 col = 2 if i % 2 == 0 else 41 popup.addstr(row, col, key, curses.A_BOLD) col += len(key) popup.addstr(row, col, description) col += len(description) if selection: popup.addstr(row, col, " (") popup.addstr(row, col + 2, selection, curses.A_BOLD) popup.addstr(row, col + 2 + len(selection), ")") # tells user to press a key if the lower left is unoccupied if len(helpOptions) < 13 and height == 9: popup.addstr(7, 2, "Press any key...") popup.win.refresh() curses.cbreak() exitKey = control.getScreen().getch() finally: finalize() if not uiTools.isSelectionKey(exitKey) and \ not uiTools.isScrollKey(exitKey) and \ not exitKey in (curses.KEY_LEFT, curses.KEY_RIGHT): return exitKey else: return None
def showConfirmationDialog(torrcContents, torrcLocation): """ Shows a confirmation dialog with the given torrc contents, returning CANCEL, NEXT, or BACK based on the selection. Arguments: torrcContents - lines of torrc contents to be presented torrcLocation - path where the torrc will be placed """ torrcLines = torrcContents.split("\n") options = ["Cancel", "Back to Setup", "Start Tor"] control = cli.controller.getController() screenHeight = control.getScreen().getmaxyx()[0] stickyHeight = sum([stickyPanel.getHeight() for stickyPanel in control.getStickyPanels()]) isScrollbarVisible = len(torrcLines) + stickyHeight + 5 > screenHeight xOffset = 3 if isScrollbarVisible else 0 popup, width, height = cli.popups.init(len(torrcLines) + 5, 84 + xOffset) if not popup: return False try: scroll, selection = 0, 2 curses.cbreak() while True: popup.win.erase() popup.win.box() # renders the scrollbar if isScrollbarVisible: popup.addScrollBar(scroll, scroll + height - 5, len(torrcLines), 1, height - 4, 1) # shows the path where the torrc will be placed titleMsg = "The following will be placed at '%s':" % torrcLocation popup.addstr(0, 0, titleMsg, curses.A_STANDOUT) # renders the torrc contents for i in range(scroll, min(len(torrcLines), height - 5 + scroll)): # parses the argument and comment from options option, arg, comment = uiTools.cropStr(torrcLines[i], width - 4 - xOffset), "", "" div = option.find("#") if div != -1: option, comment = option[:div], option[div:] div = option.strip().find(" ") if div != -1: option, arg = option[:div], option[div:] drawX = 2 + xOffset popup.addstr(i + 1 - scroll, drawX, option, curses.A_BOLD | uiTools.getColor("green")) drawX += len(option) popup.addstr(i + 1 - scroll, drawX, arg, curses.A_BOLD | uiTools.getColor("cyan")) drawX += len(arg) popup.addstr(i + 1 - scroll, drawX, comment, uiTools.getColor("white")) # divider between the torrc and the options popup.addch(height - 4, 0, curses.ACS_LTEE) popup.addch(height - 4, width, curses.ACS_RTEE) popup.hline(height - 4, 1, width - 1) if isScrollbarVisible: popup.addch(height - 4, 2, curses.ACS_BTEE) # renders the selection options confirmationMsg = "Run tor with the above configuration?" popup.addstr(height - 3, width - len(confirmationMsg) - 1, confirmationMsg, uiTools.getColor("green") | curses.A_BOLD) drawX = width - 1 for i in range(len(options) - 1, -1, -1): optionLabel = " %s " % options[i] drawX -= (len(optionLabel) + 4) selectionFormat = curses.A_STANDOUT if i == selection else curses.A_NORMAL popup.addstr(height - 2, drawX, "[", uiTools.getColor("green")) popup.addstr(height - 2, drawX + 1, optionLabel, uiTools.getColor("green") | selectionFormat | curses.A_BOLD) popup.addstr(height - 2, drawX + len(optionLabel) + 1, "]", uiTools.getColor("green")) drawX -= 1 # space gap between the options popup.win.refresh() key = cli.controller.getController().getScreen().getch() if key == curses.KEY_LEFT: selection = (selection - 1) % len(options) elif key == curses.KEY_RIGHT: selection = (selection + 1) % len(options) elif uiTools.isScrollKey(key): scroll = uiTools.getScrollPosition(key, scroll, height - 5, len(torrcLines)) elif uiTools.isSelectionKey(key): if selection == 0: return CANCEL elif selection == 1: return BACK else: return NEXT elif key in (27, ord('q'), ord('Q')): return CANCEL finally: cli.popups.finalize()
def showDescriptorPopup(connPanel): """ Presents consensus descriptor in popup window with the following controls: Up, Down, Page Up, Page Down - scroll descriptor Right, Left - next / previous connection Enter, Space, d, D - close popup Arguments: connPanel - connection panel providing the dialog """ # hides the title of the connection panel connPanel.setTitleVisible(False) connPanel.redraw(True) control = cli.controller.getController() panel.CURSES_LOCK.acquire() isDone = False try: while not isDone: selection = connPanel.getSelection() if not selection: break fingerprint = selection.foreign.getFingerprint() if fingerprint == "UNKNOWN": fingerprint = None displayText = getDisplayText(fingerprint) displayColor = cli.connections.connEntry.CATEGORY_COLOR[ selection.getType()] showLineNumber = fingerprint != None # determines the maximum popup size the displayText can fill pHeight, pWidth = getPreferredSize(displayText, connPanel.maxX, showLineNumber) popup, _, height = cli.popups.init(pHeight, pWidth) if not popup: break scroll, isChanged = 0, True try: while not isDone: if isChanged: draw(popup, fingerprint, displayText, displayColor, scroll, showLineNumber) isChanged = False key = control.getScreen().getch() if uiTools.isScrollKey(key): # TODO: This is a bit buggy in that scrolling is by displayText # lines rather than the displayed lines, causing issues when # content wraps. The result is that we can't have a scrollbar and # can't scroll to the bottom if there's a multi-line being # displayed. However, trying to correct this introduces a big can # of worms and after hours decided that this isn't worth the # effort... newScroll = uiTools.getScrollPosition( key, scroll, height - 2, len(displayText)) if scroll != newScroll: scroll, isChanged = newScroll, True elif uiTools.isSelectionKey(key) or key in (ord('d'), ord('D')): isDone = True # closes popup elif key in (curses.KEY_LEFT, curses.KEY_RIGHT): # navigation - pass on to connPanel and recreate popup connPanel.handleKey(curses.KEY_UP if key == curses. KEY_LEFT else curses.KEY_DOWN) break finally: cli.popups.finalize() finally: connPanel.setTitleVisible(True) connPanel.redraw(True) panel.CURSES_LOCK.release()