commit 7121ff8a9b5db7c970b9ec920ccabbc6607dc856 Author: Damian Johnson atagar@torproject.org Date: Fri May 22 09:39:07 2015 -0700
Revise popup dialogs to use 'with'
Our popup dialogs acquire a curses lock for its duration. We were doing it via a init() and finalize() method, which were always used in a try/finally block. However, this is exactly the use case for python's 'with' keyword so using that instead.
Not entirely happy with this code (it's still pending a rewrite), but better. --- nyx/connections/count_popup.py | 106 +++++------ nyx/connections/descriptor_popup.py | 68 ++++--- nyx/log_panel.py | 8 +- nyx/menu/menu.py | 73 ++++---- nyx/popups.py | 348 ++++++++++++++++------------------- 5 files changed, 281 insertions(+), 322 deletions(-)
diff --git a/nyx/connections/count_popup.py b/nyx/connections/count_popup.py index 00aeb31..e61dc26 100644 --- a/nyx/connections/count_popup.py +++ b/nyx/connections/count_popup.py @@ -28,84 +28,80 @@ def showCountDialog(count_type, counts): no_stats_msg = "Usage stats aren't available yet, press any key..."
if is_no_stats: - popup, width, height = nyx.popups.init(3, len(no_stats_msg) + 4) + height, width = 3, len(no_stats_msg) + 4 else: - popup, width, height = nyx.popups.init(4 + max(1, len(counts)), 80) + height, width = 4 + max(1, len(counts)), 80
- if not popup: - return + with nyx.popups.popup_window(height, width) as (popup, height, width): + if popup: + control = nyx.controller.get_controller()
- try: - control = nyx.controller.get_controller() + popup.win.box()
- popup.win.box() + # dialog title
- # dialog title + if count_type == CountType.CLIENT_LOCALE: + title = 'Client Locales' + elif count_type == CountType.EXIT_PORT: + title = 'Exiting Port Usage' + else: + title = '' + log.warn('Unrecognized count type: %s' % count_type)
- if count_type == CountType.CLIENT_LOCALE: - title = 'Client Locales' - elif count_type == CountType.EXIT_PORT: - title = 'Exiting Port Usage' - else: - title = '' - log.warn('Unrecognized count type: %s' % count_type) + popup.addstr(0, 0, title, curses.A_STANDOUT)
- popup.addstr(0, 0, title, curses.A_STANDOUT) + if is_no_stats: + popup.addstr(1, 2, no_stats_msg, curses.A_BOLD, 'cyan') + else: + sorted_counts = sorted(counts.iteritems(), key=operator.itemgetter(1)) + sorted_counts.reverse()
- if is_no_stats: - popup.addstr(1, 2, no_stats_msg, curses.A_BOLD, 'cyan') - else: - sorted_counts = sorted(counts.iteritems(), key=operator.itemgetter(1)) - sorted_counts.reverse() + # constructs string formatting for the max key and value display width
- # constructs string formatting for the max key and value display width + key_width, val_width, value_total = 3, 1, 0
- key_width, val_width, value_total = 3, 1, 0 + for k, v in sorted_counts: + key_width = max(key_width, len(k)) + val_width = max(val_width, len(str(v))) + value_total += v
- for k, v in sorted_counts: - key_width = max(key_width, len(k)) - val_width = max(val_width, len(str(v))) - value_total += v + # extra space since we're adding usage informaion
- # extra space since we're adding usage informaion - - if count_type == CountType.EXIT_PORT: - key_width += EXIT_USAGE_WIDTH + if count_type == CountType.EXIT_PORT: + key_width += EXIT_USAGE_WIDTH
- label_format = '%%-%is %%%ii (%%%%%%-2i)' % (key_width, val_width) + label_format = '%%-%is %%%ii (%%%%%%-2i)' % (key_width, val_width)
- for i in range(height - 4): - k, v = sorted_counts[i] + for i in range(height - 4): + k, v = sorted_counts[i]
- # includes a port usage column + # includes a port usage column
- if count_type == CountType.EXIT_PORT: - usage = connection.port_usage(k) + if count_type == CountType.EXIT_PORT: + usage = connection.port_usage(k)
- if usage: - key_format = '%%-%is %%s' % (key_width - EXIT_USAGE_WIDTH) - k = key_format % (k, usage[:EXIT_USAGE_WIDTH - 3]) + if usage: + key_format = '%%-%is %%s' % (key_width - EXIT_USAGE_WIDTH) + k = key_format % (k, usage[:EXIT_USAGE_WIDTH - 3])
- label = label_format % (k, v, v * 100 / value_total) - popup.addstr(i + 1, 2, label, curses.A_BOLD, 'green') + label = label_format % (k, v, v * 100 / value_total) + popup.addstr(i + 1, 2, label, curses.A_BOLD, 'green')
- # All labels have the same size since they're based on the max widths. - # If this changes then this'll need to be the max label width. + # All labels have the same size since they're based on the max widths. + # If this changes then this'll need to be the max label width.
- label_width = len(label) + label_width = len(label)
- # draws simple bar graph for percentages + # draws simple bar graph for percentages
- fill_width = v * (width - 4 - label_width) / value_total + fill_width = v * (width - 4 - label_width) / value_total
- for j in range(fill_width): - popup.addstr(i + 1, 3 + label_width + j, ' ', curses.A_STANDOUT, 'red') + for j in range(fill_width): + popup.addstr(i + 1, 3 + label_width + j, ' ', curses.A_STANDOUT, 'red')
- popup.addstr(height - 2, 2, 'Press any key...') + popup.addstr(height - 2, 2, 'Press any key...')
- popup.win.refresh() + popup.win.refresh()
- curses.cbreak() - control.key_input() - finally: - nyx.popups.finalize() + curses.cbreak() + control.key_input() diff --git a/nyx/connections/descriptor_popup.py b/nyx/connections/descriptor_popup.py index f05631a..0409ab8 100644 --- a/nyx/connections/descriptor_popup.py +++ b/nyx/connections/descriptor_popup.py @@ -66,43 +66,37 @@ def show_descriptor_popup(conn_panel):
popup_height, popup_width = get_preferred_size(display_text, conn_panel.max_x, show_line_number)
- popup, _, height = nyx.popups.init(popup_height, popup_width) - - if not popup: - break - - scroll, is_changed = 0, True - - try: - while not is_done: - if is_changed: - draw(popup, fingerprint, display_text, display_color, scroll, show_line_number) - is_changed = False - - key = control.key_input() - - if key.is_scroll(): - # TODO: This is a bit buggy in that scrolling is by display_text - # 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... - - new_scroll = ui_tools.get_scroll_position(key, scroll, height - 2, len(display_text)) - - if scroll != new_scroll: - scroll, is_changed = new_scroll, True - elif key.is_selection() or key.match('d'): - is_done = True # closes popup - elif key.match('left', 'right'): - # navigation - pass on to conn_panel and recreate popup - - conn_panel.handle_key(panel.KeyInput(curses.KEY_UP) if key.match('left') else panel.KeyInput(curses.KEY_DOWN)) - break - finally: - nyx.popups.finalize() + with nyx.popups.popup_window(popup_height, popup_width) as (popup, _, height): + if popup: + scroll, is_changed = 0, True + + while not is_done: + if is_changed: + draw(popup, fingerprint, display_text, display_color, scroll, show_line_number) + is_changed = False + + key = control.key_input() + + if key.is_scroll(): + # TODO: This is a bit buggy in that scrolling is by display_text + # 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... + + new_scroll = ui_tools.get_scroll_position(key, scroll, height - 2, len(display_text)) + + if scroll != new_scroll: + scroll, is_changed = new_scroll, True + elif key.is_selection() or key.match('d'): + is_done = True # closes popup + elif key.match('left', 'right'): + # navigation - pass on to conn_panel and recreate popup + + conn_panel.handle_key(panel.KeyInput(curses.KEY_UP) if key.match('left') else panel.KeyInput(curses.KEY_DOWN)) + break finally: conn_panel.set_title_visible(True) conn_panel.redraw(True) diff --git a/nyx/log_panel.py b/nyx/log_panel.py index 4180f57..4912cd7 100644 --- a/nyx/log_panel.py +++ b/nyx/log_panel.py @@ -140,10 +140,8 @@ class LogPanel(panel.Panel, threading.Thread):
# allow user to enter new types of events to log - unchanged if left blank
- popup, width, height = nyx.popups.init(11, 80) - - if popup: - try: + with nyx.popups.popup_window(11, 80) as (popup, width, height): + if popup: # displays the available flags
popup.win.box() @@ -167,8 +165,6 @@ class LogPanel(panel.Panel, threading.Thread): self.redraw(True) except ValueError as exc: nyx.popups.show_msg('Invalid flags: %s' % str(exc), 2) - finally: - nyx.popups.finalize()
def show_snapshot_prompt(self): """ diff --git a/nyx/menu/menu.py b/nyx/menu/menu.py index 59f9a4e..34e9a67 100644 --- a/nyx/menu/menu.py +++ b/nyx/menu/menu.py @@ -76,64 +76,59 @@ class MenuCursor:
def show_menu(): - popup, _, _ = nyx.popups.init(1, below_static = False) + with nyx.popups.popup_window(1, below_static = False) as (popup, width, height): + if popup: + control = nyx.controller.get_controller()
- if not popup: - return - - control = nyx.controller.get_controller() + # generates the menu and uses the initial selection of the first item in + # the file menu
- try: - # generates the menu and uses the initial selection of the first item in - # the file menu + menu = nyx.menu.actions.make_menu() + cursor = MenuCursor(menu.get_children()[0].get_children()[0])
- menu = nyx.menu.actions.make_menu() - cursor = MenuCursor(menu.get_children()[0].get_children()[0]) + while not cursor.is_done(): + # sets the background color
- while not cursor.is_done(): - # sets the background color + popup.win.clear() + popup.win.bkgd(' ', curses.A_STANDOUT | ui_tools.get_color("red")) + selection_hierarchy = cursor.get_selection().get_hierarchy()
- popup.win.clear() - popup.win.bkgd(' ', curses.A_STANDOUT | ui_tools.get_color("red")) - selection_hierarchy = cursor.get_selection().get_hierarchy() + # provide a message saying how to close the menu
- # provide a message saying how to close the menu + control.set_msg('Press m or esc to close the menu.', curses.A_BOLD, True)
- control.set_msg('Press m or esc to close the menu.', curses.A_BOLD, True) + # renders the menu bar, noting where the open submenu is positioned
- # renders the menu bar, noting where the open submenu is positioned + draw_left, selection_left = 0, 0
- draw_left, selection_left = 0, 0 + for top_level_item in menu.get_children(): + draw_format = curses.A_BOLD
- for top_level_item in menu.get_children(): - draw_format = curses.A_BOLD + if top_level_item == selection_hierarchy[1]: + draw_format |= curses.A_UNDERLINE + selection_left = draw_left
- if top_level_item == selection_hierarchy[1]: - draw_format |= curses.A_UNDERLINE - selection_left = draw_left + draw_label = ' %s ' % top_level_item.get_label()[1] + popup.addstr(0, draw_left, draw_label, draw_format) + popup.addch(0, draw_left + len(draw_label), curses.ACS_VLINE)
- draw_label = ' %s ' % top_level_item.get_label()[1] - popup.addstr(0, draw_left, draw_label, draw_format) - popup.addch(0, draw_left + len(draw_label), curses.ACS_VLINE) + draw_left += len(draw_label) + 1
- draw_left += len(draw_label) + 1 + # recursively shows opened submenus
- # recursively shows opened submenus + _draw_submenu(cursor, 1, 1, selection_left)
- _draw_submenu(cursor, 1, 1, selection_left) + popup.win.refresh()
- popup.win.refresh() + curses.cbreak() + cursor.handle_key(control.key_input())
- curses.cbreak() - cursor.handle_key(control.key_input()) + # redraws the rest of the interface if we're rendering on it again
- # redraws the rest of the interface if we're rendering on it again + if not cursor.is_done(): + control.redraw()
- if not cursor.is_done(): - control.redraw() - finally: - control.set_msg() - nyx.popups.finalize() + control.set_msg()
def _draw_submenu(cursor, level, top, left): diff --git a/nyx/popups.py b/nyx/popups.py index 2f98e73..355d7f1 100644 --- a/nyx/popups.py +++ b/nyx/popups.py @@ -10,52 +10,55 @@ from nyx import __version__, __release_date__ from nyx.util import panel, ui_tools
-def init(height = -1, width = -1, top = 0, left = 0, below_static = True): +def popup_window(height = -1, width = -1, top = 0, left = 0, below_static = 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 - and this returns a tuple of the... - (popup, draw width, draw height) - Otherwise this leaves curses unlocked and returns None. + Provides a popup dialog you can use in a 'with' block...
- 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 - below_static - positions popup below static content if true - """ + with popup_window(5, 10) as (popup, width, height): + if popup: + ... do stuff...
- control = nyx.controller.get_controller() + This popup has a lock on the curses interface for the duration of the block, + preventing other draw operations from taking place. If the popup isn't + visible then the popup it returns will be **None**.
- if below_static: - sticky_height = sum([sticky_panel.get_height() for sticky_panel in control.get_sticky_panels()]) - else: - sticky_height = 0 + :param int height: maximum height of the popup + :param int width: maximum width of the popup + :param int top: top position, relative to the sticky content + :param int left: left position from the screen + :param bool below_static: positions popup below static content if True + + :returns: tuple of the form (subwindow, width, height) when used in a with block + """
- popup = panel.Panel(control.get_screen(), 'popup', top + sticky_height, left, height, width) - popup.set_visible(True) + class _Popup(object): + def __enter__(self): + control = nyx.controller.get_controller()
- # Redraws the popup to prepare a subwindow instance. If none is spawned then - # the panel can't be drawn (for instance, due to not being visible). + if below_static: + sticky_height = sum([sticky_panel.get_height() for sticky_panel in control.get_sticky_panels()]) + else: + sticky_height = 0
- popup.redraw(True) + popup = panel.Panel(control.get_screen(), 'popup', top + sticky_height, left, height, width) + popup.set_visible(True)
- if popup.win is not None: - panel.CURSES_LOCK.acquire() - return (popup, popup.max_x - 1, popup.max_y) - else: - return (None, 0, 0) + # Redraws the popup to prepare a subwindow instance. If none is spawned then + # the panel can't be drawn (for instance, due to not being visible).
+ popup.redraw(True)
-def finalize(): - """ - Cleans up after displaying a popup, releasing the cureses lock and redrawing - the rest of the display. - """ + if popup.win is not None: + panel.CURSES_LOCK.acquire() + return (popup, popup.max_x - 1, popup.max_y) + else: + return (None, 0, 0)
- nyx.controller.get_controller().request_redraw() - panel.CURSES_LOCK.release() + def __exit__(self, exit_type, value, traceback): + nyx.controller.get_controller().request_redraw() + panel.CURSES_LOCK.release() + + return _Popup()
def input_prompt(msg, initial_value = ''): @@ -112,68 +115,61 @@ def show_help_popup(): properly, this is an arrow, enter, or scroll key then this returns None. """
- popup, _, height = init(9, 80) - - if not popup: - return - - exit_key = None - - try: - control = nyx.controller.get_controller() - page_panels = control.get_display_panels() + with popup_window(9, 80) as (popup, _, height): + if popup: + exit_key = None + control = nyx.controller.get_controller() + page_panels = control.get_display_panels()
- # the first page is the only one with multiple panels, and it looks better - # with the log entries first, so reversing the order + # the first page is the only one with multiple panels, and it looks better + # with the log entries first, so reversing the order
- page_panels.reverse() + page_panels.reverse()
- help_options = [] + help_options = []
- for entry in page_panels: - help_options += entry.get_help() + for entry in page_panels: + help_options += entry.get_help()
- # test doing afterward in case of overwriting + # test doing afterward in case of overwriting
- popup.win.box() - popup.addstr(0, 0, 'Page %i Commands:' % (control.get_page() + 1), curses.A_STANDOUT) + popup.win.box() + popup.addstr(0, 0, 'Page %i Commands:' % (control.get_page() + 1), curses.A_STANDOUT)
- for i in range(len(help_options)): - if i / 2 >= height - 2: - break + for i in range(len(help_options)): + if i / 2 >= height - 2: + break
- # draws entries in the form '<key>: <description>[ (<selection>)]', for - # instance... - # u: duplicate log entries (hidden) + # draws entries in the form '<key>: <description>[ (<selection>)]', for + # instance... + # u: duplicate log entries (hidden)
- key, description, selection = help_options[i] + key, description, selection = help_options[i]
- if key: - description = ': ' + description + if key: + description = ': ' + description
- row = (i / 2) + 1 - col = 2 if i % 2 == 0 else 41 + 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) + 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), ')') + 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 + # tells user to press a key if the lower left is unoccupied
- if len(help_options) < 13 and height == 9: - popup.addstr(7, 2, 'Press any key...') + if len(help_options) < 13 and height == 9: + popup.addstr(7, 2, 'Press any key...')
- popup.win.refresh() - curses.cbreak() - exit_key = control.key_input() - finally: - finalize() + popup.win.refresh() + curses.cbreak() + exit_key = control.key_input()
if not exit_key.is_selection() and not exit_key.is_scroll() and \ not exit_key.match('left', 'right'): @@ -187,27 +183,21 @@ def show_about_popup(): Presents a popup with author and version information. """
- popup, _, height = init(9, 80) - - if not popup: - return + with popup_window(9, 80) as (popup, _, height): + if popup: + control = nyx.controller.get_controller()
- try: - control = nyx.controller.get_controller() - - popup.win.box() - popup.addstr(0, 0, 'About:', curses.A_STANDOUT) - popup.addstr(1, 2, 'nyx, version %s (released %s)' % (__version__, __release_date__), curses.A_BOLD) - popup.addstr(2, 4, 'Written by Damian Johnson (atagar@torproject.org)') - popup.addstr(3, 4, 'Project page: www.atagar.com/nyx') - popup.addstr(5, 2, 'Released under the GPL v3 (http://www.gnu.org/licenses/gpl.html)') - popup.addstr(7, 2, 'Press any key...') - popup.win.refresh() + popup.win.box() + popup.addstr(0, 0, 'About:', curses.A_STANDOUT) + popup.addstr(1, 2, 'nyx, version %s (released %s)' % (__version__, __release_date__), curses.A_BOLD) + popup.addstr(2, 4, 'Written by Damian Johnson (atagar@torproject.org)') + popup.addstr(3, 4, 'Project page: www.atagar.com/nyx') + popup.addstr(5, 2, 'Released under the GPL v3 (http://www.gnu.org/licenses/gpl.html)') + popup.addstr(7, 2, 'Press any key...') + popup.win.refresh()
- curses.cbreak() - control.key_input() - finally: - finalize() + curses.cbreak() + control.key_input()
def show_sort_dialog(title, options, old_selection, option_colors): @@ -230,66 +220,59 @@ def show_sort_dialog(title, options, old_selection, option_colors): option_colors - mappings of options to their color """
- popup, _, _ = init(9, 80) + with popup_window(9, 80) as (popup, _, _): + if popup: + new_selections = [] # new ordering + cursor_location = 0 # index of highlighted option + curses.cbreak() # wait indefinitely for key presses (no timeout)
- if not popup: - return + selection_options = list(options) + selection_options.append('Cancel')
- new_selections = [] # new ordering + while len(new_selections) < len(old_selection): + popup.win.erase() + popup.win.box() + popup.addstr(0, 0, title, curses.A_STANDOUT)
- try: - cursor_location = 0 # index of highlighted option - curses.cbreak() # wait indefinitely for key presses (no timeout) + _draw_sort_selection(popup, 1, 2, 'Current Order: ', old_selection, option_colors) + _draw_sort_selection(popup, 2, 2, 'New Order: ', new_selections, option_colors)
- selection_options = list(options) - selection_options.append('Cancel') + # presents remaining options, each row having up to four options with + # spacing of nineteen cells
- while len(new_selections) < len(old_selection): - popup.win.erase() - popup.win.box() - popup.addstr(0, 0, title, curses.A_STANDOUT) + row, col = 4, 0
- _draw_sort_selection(popup, 1, 2, 'Current Order: ', old_selection, option_colors) - _draw_sort_selection(popup, 2, 2, 'New Order: ', new_selections, option_colors) + for i in range(len(selection_options)): + option_format = curses.A_STANDOUT if cursor_location == i else curses.A_NORMAL + popup.addstr(row, col * 19 + 2, selection_options[i], option_format) + col += 1
- # presents remaining options, each row having up to four options with - # spacing of nineteen cells + if col == 4: + row, col = row + 1, 0
- row, col = 4, 0 + popup.win.refresh()
- for i in range(len(selection_options)): - option_format = curses.A_STANDOUT if cursor_location == i else curses.A_NORMAL - popup.addstr(row, col * 19 + 2, selection_options[i], option_format) - col += 1 + key = nyx.controller.get_controller().key_input()
- if col == 4: - row, col = row + 1, 0 + if key.match('left'): + cursor_location = max(0, cursor_location - 1) + elif key.match('right'): + cursor_location = min(len(selection_options) - 1, cursor_location + 1) + elif key.match('up'): + cursor_location = max(0, cursor_location - 4) + elif key.match('down'): + cursor_location = min(len(selection_options) - 1, cursor_location + 4) + elif key.is_selection(): + selection = selection_options[cursor_location]
- popup.win.refresh() - - key = nyx.controller.get_controller().key_input() - - if key.match('left'): - cursor_location = max(0, cursor_location - 1) - elif key.match('right'): - cursor_location = min(len(selection_options) - 1, cursor_location + 1) - elif key.match('up'): - cursor_location = max(0, cursor_location - 4) - elif key.match('down'): - cursor_location = min(len(selection_options) - 1, cursor_location + 4) - elif key.is_selection(): - selection = selection_options[cursor_location] - - if selection == 'Cancel': - break - else: - new_selections.append(selection) - selection_options.remove(selection) - cursor_location = min(cursor_location, len(selection_options) - 1) - elif key == 27: - break # esc - cancel - finally: - finalize() + if selection == 'Cancel': + break + else: + new_selections.append(selection) + selection_options.remove(selection) + cursor_location = min(cursor_location, len(selection_options) - 1) + elif key == 27: + break # esc - cancel
if len(new_selections) == len(old_selection): return new_selections @@ -343,50 +326,45 @@ def show_menu(title, options, old_selection): """
max_width = max(map(len, options)) + 9 - popup, _, _ = init(len(options) + 2, max_width)
- if not popup: - return + with popup_window(len(options) + 2, max_width) as (popup, _, _): + if popup: + selection = old_selection if old_selection != -1 else 0
- selection = old_selection if old_selection != -1 else 0 + # hides the title of the first panel on the page
- try: - # hides the title of the first panel on the page + control = nyx.controller.get_controller() + top_panel = control.get_display_panels(include_sticky = False)[0] + top_panel.set_title_visible(False) + top_panel.redraw(True)
- control = nyx.controller.get_controller() - top_panel = control.get_display_panels(include_sticky = False)[0] - top_panel.set_title_visible(False) - top_panel.redraw(True) + curses.cbreak() # wait indefinitely for key presses (no timeout)
- curses.cbreak() # wait indefinitely for key presses (no timeout) + while True: + popup.win.erase() + popup.win.box() + popup.addstr(0, 0, title, curses.A_STANDOUT)
- while True: - popup.win.erase() - popup.win.box() - popup.addstr(0, 0, title, curses.A_STANDOUT) + for i in range(len(options)): + label = options[i] + format = curses.A_STANDOUT if i == selection else curses.A_NORMAL + tab = '> ' if i == old_selection else ' ' + popup.addstr(i + 1, 2, tab) + popup.addstr(i + 1, 4, ' %s ' % label, format)
- for i in range(len(options)): - label = options[i] - format = curses.A_STANDOUT if i == selection else curses.A_NORMAL - tab = '> ' if i == old_selection else ' ' - popup.addstr(i + 1, 2, tab) - popup.addstr(i + 1, 4, ' %s ' % label, format) + popup.win.refresh()
- popup.win.refresh() + key = control.key_input()
- key = control.key_input() - - if key.match('up'): - selection = max(0, selection - 1) - elif key.match('down'): - selection = min(len(options) - 1, selection + 1) - elif key.is_selection(): - break - elif key.match('esc'): - selection = -1 - break - finally: - top_panel.set_title_visible(True) - finalize() + if key.match('up'): + selection = max(0, selection - 1) + elif key.match('down'): + selection = min(len(options) - 1, selection + 1) + elif key.is_selection(): + break + elif key.match('esc'): + selection = -1 + break
+ top_panel.set_title_visible(True) return selection
tor-commits@lists.torproject.org