[tor-commits] [nyx/master] Revise popup dialogs to use 'with'
atagar at torproject.org
atagar at torproject.org
Fri May 22 16:39:54 UTC 2015
commit 7121ff8a9b5db7c970b9ec920ccabbc6607dc856
Author: Damian Johnson <atagar at 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 at 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 at 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
More information about the tor-commits
mailing list