[tor-commits] [nyx/master] Revise sort order dialog

atagar at torproject.org atagar at torproject.org
Sun Apr 3 22:36:37 UTC 2016


commit f9cf4bbc821356f7918860166d23f682ece39846
Author: Damian Johnson <atagar at torproject.org>
Date:   Sun Apr 3 12:45:31 2016 -0700

    Revise sort order dialog
    
    Rewriting this sucker. Quite a bit shorter, cleaner, and now tested.
---
 nyx/popups.py    | 145 ++++++++++++++++++++-----------------------------------
 test/__init__.py |   2 +-
 test/popups.py   |  62 ++++++++++++++++++++++++
 3 files changed, 116 insertions(+), 93 deletions(-)

diff --git a/nyx/popups.py b/nyx/popups.py
index 4a51e0c..b0cd48e 100644
--- a/nyx/popups.py
+++ b/nyx/popups.py
@@ -199,114 +199,75 @@ def show_counts(title, counts, fill_char = ' '):
     nyx.curses.key_input()
 
 
-def show_sort_dialog(title, options, old_selection, option_colors):
+def show_sort_dialog(title, options, previous_order, option_colors):
   """
-  Displays a sorting dialog of the form:
+  Provides sorting dialog of the form...
 
-    Current Order: <previous selection>
-    New Order: <selections made>
+    Current Order: <previous order>
+    New Order: <selected options>
 
     <option 1>    <option 2>    <option 3>   Cancel
 
-  Options are colored when among the "Current Order" or "New Order", but not
-  when an option below them. If cancel is selected or the user presses escape
-  then this returns None. Otherwise, the new ordering is provided.
+  :param str title: dialog title
+  :param list options: sort options to be provided
+  :param list previous_order: previous ordering
+  :param dict optoin_colors: mapping of options to their color
 
-  Arguments:
-    title   - title displayed for the popup window
-    options      - ordered listing of option labels
-    old_selection - current ordering
-    option_colors - mappings of options to their color
+  :returns: **list** of the new sort order or **None** if dialog is canceled
   """
 
-  with popup_window(9, 80) as (popup, _, _):
-    if popup:
-      new_selections = []  # new ordering
-      cursor_location = 0     # index of highlighted option
-
-      selection_options = list(options)
-      selection_options.append('Cancel')
-
-      while len(new_selections) < len(old_selection):
-        popup.win.erase()
-        popup.draw_box()
-        popup.addstr(0, 0, title, HIGHLIGHT)
-
-        _draw_sort_selection(popup, 1, 2, 'Current Order: ', old_selection, option_colors)
-        _draw_sort_selection(popup, 2, 2, 'New Order: ', new_selections, option_colors)
-
-        # presents remaining options, each row having up to four options with
-        # spacing of nineteen cells
-
-        row, col = 4, 0
-
-        for i in range(len(selection_options)):
-          option_format = HIGHLIGHT if cursor_location == i else NORMAL
-          popup.addstr(row, col * 19 + 2, selection_options[i], option_format)
-          col += 1
-
-          if col == 4:
-            row, col = row + 1, 0
-
-        popup.win.refresh()
-
-        key = nyx.curses.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.match('esc'):
-          break  # esc - cancel
+  new_order = []
+  cursor_index = 0
+  shown_options = list(options) + ['Cancel']
 
-  if len(new_selections) == len(old_selection):
-    return new_selections
-  else:
-    return None
+  def _draw_selection(subwindow, y, label, selection):
+    x = subwindow.addstr(2, y, label, BOLD)
 
+    for i, option in enumerate(selection):
+      x = subwindow.addstr(x, y, option, option_colors.get(option, WHITE), BOLD)
 
-def _draw_sort_selection(popup, y, x, prefix, options, option_colors):
-  """
-  Draws a series of comma separated sort selections. The whole line is bold
-  and sort options also have their specified color. Example:
+      if i < len(selection) - 1:
+        x = subwindow.addstr(x, y, ', ', BOLD)
 
-    Current Order: Man Page Entry, Option Name, Is Default
-
-  Arguments:
-    popup        - panel in which to draw sort selection
-    y            - vertical location
-    x            - horizontal location
-    prefix       - initial string description
-    options      - sort options to be shown
-    option_colors - mappings of options to their color
-  """
+  def _render(subwindow):
+    subwindow.box()
+    subwindow.addstr(0, 0, title, HIGHLIGHT)
 
-  popup.addstr(y, x, prefix, BOLD)
-  x += len(prefix)
+    _draw_selection(subwindow, 1, 'Current Order: ', previous_order)
+    _draw_selection(subwindow, 2, 'New Order: ', new_order)
 
-  for i in range(len(options)):
-    sort_type = options[i]
-    popup.addstr(y, x, sort_type, option_colors.get(sort_type, WHITE), BOLD)
-    x += len(sort_type)
+    # presents remaining options, each row having up to four options
 
-    # comma divider between options, if this isn't the last
+    for i, option in enumerate(shown_options):
+      attr = HIGHLIGHT if i == cursor_index else NORMAL
+      subwindow.addstr((i % 4) * 19 + 2, (i / 4) + 4, option, attr)
 
-    if i < len(options) - 1:
-      popup.addstr(y, x, ', ', BOLD)
-      x += 2
+  with nyx.curses.CURSES_LOCK:
+    while len(new_order) < len(previous_order):
+      nyx.curses.draw(_render, top = nyx.controller.get_controller().header_panel().get_height(), width = 80, height = 9)
+      key = nyx.curses.key_input()
+
+      if key.match('left'):
+        cursor_index = max(0, cursor_index - 1)
+      elif key.match('right'):
+        cursor_index = min(len(shown_options) - 1, cursor_index + 1)
+      elif key.match('up'):
+        cursor_index = max(0, cursor_index - 4)
+      elif key.match('down'):
+        cursor_index = min(len(shown_options) - 1, cursor_index + 4)
+      elif key.is_selection():
+        selection = shown_options[cursor_index]
+
+        if selection == 'Cancel':
+          return None
+        else:
+          new_order.append(selection)
+          shown_options.remove(selection)
+          cursor_index = min(cursor_index, len(shown_options) - 1)
+      elif key.match('esc'):
+        return None
+
+  return new_order
 
 
 def show_menu(title, options, old_selection):
diff --git a/test/__init__.py b/test/__init__.py
index 0884866..705e9b1 100644
--- a/test/__init__.py
+++ b/test/__init__.py
@@ -51,7 +51,7 @@ def render(func, *args, **kwargs):
     if SHOW_RENDERED_CONTENT:
       time.sleep(SHOW_RENDERED_CONTENT)
 
-  with patch('nyx.curses.key_input', return_value = Mock()):
+  with patch('nyx.curses.key_input', return_value = nyx.curses.KeyInput(27)):
     nyx.curses.start(draw_func, transparent_background = True, cursor = False)
 
   return RenderResult(attr.get('content'), attr.get('return_value'), attr.get('runtime'))
diff --git a/test/popups.py b/test/popups.py
index b82c9a2..8a7e76b 100644
--- a/test/popups.py
+++ b/test/popups.py
@@ -2,6 +2,7 @@
 Unit tests for nyx.popups.
 """
 
+import curses
 import unittest
 
 import nyx.panel
@@ -52,6 +53,30 @@ Client Locales-----------------------------------------------------------------+
 +------------------------------------------------------------------------------+
 """.strip()
 
+EXPECTED_SORT_DIALOG_START = """
+Config Option Ordering:--------------------------------------------------------+
+| Current Order: Man Page Entry, Name, Is Set                                  |
+| New Order:                                                                   |
+|                                                                              |
+| Name               Value              Value Type         Category            |
+| Usage              Summary            Description        Man Page Entry      |
+| Is Set             Cancel                                                    |
+|                                                                              |
++------------------------------------------------------------------------------+
+""".strip()
+
+EXPECTED_SORT_DIALOG_END = """
+Config Option Ordering:--------------------------------------------------------+
+| Current Order: Man Page Entry, Name, Is Set                                  |
+| New Order: Name, Summary                                                     |
+|                                                                              |
+| Value              Value Type         Category           Usage               |
+| Description        Man Page Entry     Is Set             Cancel              |
+|                                                                              |
+|                                                                              |
++------------------------------------------------------------------------------+
+""".strip()
+
 
 class TestPopups(unittest.TestCase):
   @patch('nyx.controller.get_controller')
@@ -117,3 +142,40 @@ class TestPopups(unittest.TestCase):
 
     rendered = test.render(nyx.popups.show_counts, 'Client Locales', clients, fill_char = '*')
     self.assertEqual(EXPECTED_COUNTS, rendered.content)
+
+  @patch('nyx.controller.get_controller')
+  def test_sort_dialog(self, get_controller_mock):
+    get_controller_mock().header_panel().get_height.return_value = 0
+
+    previous_order = ['Man Page Entry', 'Name', 'Is Set']
+    options = ['Name', 'Value', 'Value Type', 'Category', 'Usage', 'Summary', 'Description', 'Man Page Entry', 'Is Set']
+
+    rendered = test.render(nyx.popups.show_sort_dialog, 'Config Option Ordering:', options, previous_order, {})
+    self.assertEqual(EXPECTED_SORT_DIALOG_START, rendered.content)
+    self.assertEqual(None, rendered.return_value)
+
+  @patch('nyx.controller.get_controller')
+  def test_sort_dialog_selecting(self, get_controller_mock):
+    # Use the dialog to make a selection. At the end we render two options as
+    # being selected (rather than three) because the act of selecing the third
+    # closed the popup.
+
+    keypresses = [
+      nyx.curses.KeyInput(curses.KEY_ENTER),
+      nyx.curses.KeyInput(curses.KEY_DOWN),
+      nyx.curses.KeyInput(curses.KEY_ENTER),
+      nyx.curses.KeyInput(curses.KEY_ENTER),
+    ]
+
+    def draw_func():
+      with patch('nyx.curses.key_input', side_effect = keypresses):
+        return nyx.popups.show_sort_dialog('Config Option Ordering:', options, previous_order, {})
+
+    get_controller_mock().header_panel().get_height.return_value = 0
+
+    previous_order = ['Man Page Entry', 'Name', 'Is Set']
+    options = ['Name', 'Value', 'Value Type', 'Category', 'Usage', 'Summary', 'Description', 'Man Page Entry', 'Is Set']
+
+    rendered = test.render(draw_func)
+    self.assertEqual(EXPECTED_SORT_DIALOG_END, rendered.content)
+    self.assertEqual(['Name', 'Summary', 'Description'], rendered.return_value)





More information about the tor-commits mailing list