[tor-commits] [nyx/master] Drop popup_window() usage in menu

atagar at torproject.org atagar at torproject.org
Tue Apr 5 01:47:44 UTC 2016


commit ad18634b75e6b08e9c5ba7d63e9a7f89ed018051
Author: Damian Johnson <atagar at torproject.org>
Date:   Mon Apr 4 18:47:20 2016 -0700

    Drop popup_window() usage in menu
    
    The menu is very much due for an overhaul. In fact, is the last file in our
    hole damn codebase that hasn't been touched yet! But for now simply replacing
    its popup_window() so we can finally drop that function.
---
 nyx/curses.py    | 28 ++++++++++++-----
 nyx/menu/menu.py | 95 +++++++++++++++++++++-----------------------------------
 nyx/popups.py    | 51 ------------------------------
 3 files changed, 55 insertions(+), 119 deletions(-)

diff --git a/nyx/curses.py b/nyx/curses.py
index 3718742..95d9dda 100644
--- a/nyx/curses.py
+++ b/nyx/curses.py
@@ -29,7 +29,10 @@ if we want Windows support in the future too.
 
   Subwindow - subwindow that can be drawn within
     |- addstr - draws a string
-    +- box - draws box with the given dimensions
+    |- addstr_wrap - draws a string with line wrapping
+    |- box - draws box with the given dimensions
+    |- hline - draws a horizontal line
+    +- vline - draws a vertical line
 
   KeyInput - user keyboard input
     |- match - checks if this matches the given inputs
@@ -414,7 +417,7 @@ def is_wide_characters_supported():
   return False
 
 
-def draw(func, left = 0, top = 0, width = None, height = None):
+def draw(func, left = 0, top = 0, width = None, height = None, background = None):
   """
   Renders a subwindow. This calls the given draw function with a
   :class:`~nyx.curses._Subwindow`.
@@ -424,6 +427,7 @@ def draw(func, left = 0, top = 0, width = None, height = None):
   :param int top: top position of the panel
   :param int width: panel width, uses all available space if **None**
   :param int height: panel height, uses all available space if **None**
+  :param nyx.curses.Color background: background color, unset if **None**
   """
 
   with CURSES_LOCK:
@@ -439,6 +443,10 @@ def draw(func, left = 0, top = 0, width = None, height = None):
 
     curses_subwindow = CURSES_SCREEN.subwin(subwindow_height, subwindow_width, top, left)
     curses_subwindow.erase()
+
+    if background:
+      curses_subwindow.bkgd(' ', curses_attr(background, HIGHLIGHT))
+
     func(_Subwindow(subwindow_width, subwindow_height, curses_subwindow))
     curses_subwindow.refresh()
 
@@ -464,6 +472,8 @@ class _Subwindow(object):
     :param int y: vertical location
     :param str msg: string to be written
     :param list attr: text attributes to apply
+
+    :returns: **int** with the horizontal position we drew to
     """
 
     if self.width > x and self.height > y:
@@ -486,6 +496,8 @@ class _Subwindow(object):
     :param int width: width avaialble to render the string
     :param int min_x: horizontal position to wrap to on new lines
     :param list attr: text attributes to apply
+
+    :returns: **tuple** of the (x, y) position we drew to
     """
 
     orig_y = y
@@ -523,10 +535,10 @@ class _Subwindow(object):
     width = max_width if width is None else min(width, max_width)
     height = max_height if height is None else min(height, max_height)
 
-    self._hline(left + 1, top, width - 2, *attr)  # top
-    self._hline(left + 1, top + height - 1, width - 2, *attr)  # bottom
-    self._vline(left, top + 1, height - 2, *attr)  # left
-    self._vline(left + width - 1, top + 1, height - 2, *attr)  # right
+    self.hline(left + 1, top, width - 2, *attr)  # top
+    self.hline(left + 1, top + height - 1, width - 2, *attr)  # bottom
+    self.vline(left, top + 1, height - 2, *attr)  # left
+    self.vline(left + width - 1, top + 1, height - 2, *attr)  # right
 
     self._addch(left, top, curses.ACS_ULCORNER, *attr)  # upper left corner
     self._addch(left, top + height - 1, curses.ACS_LLCORNER, *attr)  # lower left corner
@@ -543,14 +555,14 @@ class _Subwindow(object):
 
     return x
 
-  def _hline(self, x, y, length, *attr):
+  def hline(self, x, y, length, *attr):
     if self.width > x and self.height > y:
       try:
         self._curses_subwindow.hline(y, x, curses.ACS_HLINE | curses_attr(*attr), min(length, self.width - x))
       except:
         pass
 
-  def _vline(self, x, y, length, *attr):
+  def vline(self, x, y, length, *attr):
     if self.width > x and self.height > y:
       try:
         self._curses_subwindow.vline(y, x, curses.ACS_VLINE | curses_attr(*attr), min(length, self.height - y))
diff --git a/nyx/menu/menu.py b/nyx/menu/menu.py
index 5b719bb..01aa25e 100644
--- a/nyx/menu/menu.py
+++ b/nyx/menu/menu.py
@@ -11,7 +11,7 @@ import nyx.controller
 import nyx.menu.item
 import nyx.menu.actions
 
-from nyx.curses import RED, WHITE, NORMAL, BOLD, UNDERLINE, HIGHLIGHT
+from nyx.curses import RED, WHITE, NORMAL, BOLD, UNDERLINE
 
 
 class MenuCursor:
@@ -78,54 +78,43 @@ class MenuCursor:
 
 
 def show_menu():
-  with nyx.popups.popup_window(1, below_static = False) as (popup, width, height):
-    if popup:
-      # generates the menu and uses the initial selection of the first item in
-      # the file menu
+  selection_left = [0]
 
-      menu = nyx.menu.actions.make_menu()
-      cursor = MenuCursor(menu.get_children()[0].get_children()[0])
+  def _render(subwindow):
+    x = 0
 
-      while not cursor.is_done():
-        # sets the background color
-
-        popup.win.clear()
-        popup.win.bkgd(' ', nyx.curses.curses_attr(RED, HIGHLIGHT))
-        selection_hierarchy = cursor.get_selection().get_hierarchy()
-
-        # provide a message saying how to close the menu
-
-        nyx.controller.show_message('Press m or esc to close the menu.', BOLD)
-
-        # renders the menu bar, noting where the open submenu is positioned
-
-        draw_left, selection_left = 0, 0
-
-        for top_level_item in menu.get_children():
-          if top_level_item == selection_hierarchy[1]:
-            attr = UNDERLINE
-            selection_left = draw_left
-          else:
-            attr = NORMAL
+    for top_level_item in menu.get_children():
+      if top_level_item == selection_hierarchy[1]:
+        selection_left[0] = x
+        attr = UNDERLINE
+      else:
+        attr = NORMAL
 
-          draw_label = ' %s ' % top_level_item.get_label()[1]
-          popup.addstr(0, draw_left, draw_label, BOLD, attr)
-          popup.vline(0, draw_left + len(draw_label), 1)
+      x = subwindow.addstr(x, 0, ' %s ' % top_level_item.get_label()[1], BOLD, attr)
+      subwindow.vline(x, 0, 1)
+      x += 1
 
-          draw_left += len(draw_label) + 1
+  with nyx.curses.CURSES_LOCK:
+    # generates the menu and uses the initial selection of the first item in
+    # the file menu
 
-        # recursively shows opened submenus
+    menu = nyx.menu.actions.make_menu()
+    cursor = MenuCursor(menu.get_children()[0].get_children()[0])
 
-        _draw_submenu(cursor, 1, 1, selection_left)
+    while not cursor.is_done():
+      selection_hierarchy = cursor.get_selection().get_hierarchy()
 
-        popup.win.refresh()
+      # provide a message saying how to close the menu
 
-        cursor.handle_key(nyx.curses.key_input())
+      nyx.controller.show_message('Press m or esc to close the menu.', BOLD)
+      nyx.curses.draw(_render, height = 1, background = RED)
+      _draw_submenu(cursor, 1, 1, selection_left[0])
+      cursor.handle_key(nyx.curses.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():
-          nyx.controller.get_controller().redraw()
+      if not cursor.is_done():
+        nyx.controller.get_controller().redraw()
 
   nyx.controller.show_message()
 
@@ -154,29 +143,15 @@ def _draw_submenu(cursor, level, top, left):
 
   label_format = ' %%-%is%%-%is%%-%is ' % (prefix_col_size, middle_col_size, suffix_col_size)
   menu_width = len(label_format % ('', '', ''))
+  selection_top = submenu.get_children().index(selection) if selection in submenu.get_children() else 0
 
-  with nyx.popups.popup_window(len(submenu.get_children()), menu_width, top, left, below_static = False) as (popup, _, _):
-    if not popup:
-      return
-
-    # sets the background color
-
-    popup.win.bkgd(' ', nyx.curses.curses_attr(RED, HIGHLIGHT))
-
-    draw_top, selection_top = 0, 0
-
-    for menu_item in submenu.get_children():
+  def _render(subwindow):
+    for y, menu_item in enumerate(submenu.get_children()):
       if menu_item == selection:
-        draw_format = (WHITE, BOLD)
-        selection_top = draw_top
+        subwindow.addstr(0, y, label_format % menu_item.get_label(), WHITE, BOLD)
       else:
-        draw_format = (NORMAL,)
-
-      popup.addstr(draw_top, 0, label_format % menu_item.get_label(), *draw_format)
-      draw_top += 1
-
-    popup.win.refresh()
-
-    # shows the next submenu
+        subwindow.addstr(0, y, label_format % menu_item.get_label())
 
+  with nyx.curses.CURSES_LOCK:
+    nyx.curses.draw(_render, top = top, left = left, width = menu_width, height = len(submenu.get_children()), background = RED)
     _draw_submenu(cursor, level + 1, top + selection_top, left + menu_width)
diff --git a/nyx/popups.py b/nyx/popups.py
index b7ad7b1..70d996a 100644
--- a/nyx/popups.py
+++ b/nyx/popups.py
@@ -47,57 +47,6 @@ CONFIG = stem.util.conf.config_dict('nyx', {
 })
 
 
-def popup_window(height = -1, width = -1, top = 0, left = 0, below_static = True):
-  """
-  Provides a popup dialog you can use in a 'with' block...
-
-    with popup_window(5, 10) as (popup, width, height):
-      if popup:
-        ... do stuff...
-
-  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**.
-
-  :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
-  """
-
-  class _Popup(object):
-    def __enter__(self):
-      control = nyx.controller.get_controller()
-
-      if below_static:
-        sticky_height = control.header_panel().get_height()
-      else:
-        sticky_height = 0
-
-      popup = nyx.panel.Panel('popup', top + sticky_height, left, height, width)
-      popup.set_visible(True)
-
-      # 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)
-
-      if popup.win is not None:
-        nyx.curses.CURSES_LOCK.acquire()
-        return (popup, popup.max_x - 1, popup.max_y)
-      else:
-        return (None, 0, 0)
-
-    def __exit__(self, exit_type, value, traceback):
-      nyx.curses.CURSES_LOCK.release()
-      nyx.controller.get_controller().redraw(False)
-
-  return _Popup()
-
-
 def show_help():
   """
   Presents a popup with the current page's hotkeys.



More information about the tor-commits mailing list