[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [nyx/master] Merge LabelPanel into the header
commit e79ebcca7f975e4539196a4c4c1150e7179f9335
Author: Damian Johnson <atagar@xxxxxxxxxxxxxx>
Date: Tue Mar 22 10:09:51 2016 -0700
Merge LabelPanel into the header
The LabelPanel was a one-line panel that usually shows...
page 1 / 4 - m: menu, p: pause, h: page help, q: quit
... and provides custom messages or prompts for user input. Functionality for
this was spread across the LabelPanel, Controller, Panel, and popups module.
Needless to say this can be simplified.
This has always been part of the header so merging a nicer version of it there.
This is a pretty big overhaul with some unintended consequences - some good,
some bad...
* Good ones are that our interface now continues to update while awaiting
keypresses. For example, our graph continues to update when awaiting
confirmation of something.
* Step back is that we don't quickly redraw overlapped components as we
previously did, but this is pretty easily fixable.
---
nyx/controller.py | 80 +++++++++--------------------------------------------
nyx/menu/item.py | 2 +-
nyx/menu/menu.py | 8 ++----
nyx/panel/config.py | 8 +++---
nyx/panel/graph.py | 9 ++----
nyx/panel/header.py | 65 ++++++++++++++++++++++++++++++++++++++-----
nyx/panel/log.py | 15 +++++-----
nyx/popups.py | 41 ---------------------------
8 files changed, 90 insertions(+), 138 deletions(-)
diff --git a/nyx/controller.py b/nyx/controller.py
index e469358..5bef1dd 100644
--- a/nyx/controller.py
+++ b/nyx/controller.py
@@ -22,7 +22,7 @@ import stem
from stem.util import conf, log
-from nyx.curses import NORMAL, BOLD, HIGHLIGHT
+from nyx.curses import BOLD
from nyx import tor_controller
@@ -58,36 +58,17 @@ def get_controller():
return NYX_CONTROLLER
-class LabelPanel(nyx.panel.Panel):
- """
- Panel that just displays a single line of text.
- """
+def show_message(message = None, *attr, **kwargs):
+ header_panel = get_controller().get_panel('header')
+ return header_panel.show_message(message, *attr, **kwargs)
- def __init__(self):
- nyx.panel.Panel.__init__(self, 'msg', height = 1)
- self.msg_text = ''
- self.msg_attr = NORMAL
- def set_message(self, msg, attr = None):
- """
- Sets the message being displayed by the panel.
+def input_prompt(msg, initial_value = ''):
+ header_panel = get_controller().get_panel('header')
+ return header_panel.input_prompt(msg, initial_value)
- Arguments:
- msg - string to be displayed
- attr - attribute for the label, normal text if undefined
- """
- if attr is None:
- attr = NORMAL
-
- self.msg_text = msg
- self.msg_attr = attr
-
- def draw(self, width, height):
- self.addstr(0, 0, self.msg_text, self.msg_attr)
-
-
-class Controller:
+class Controller(object):
"""
Tracks the global state of the interface
"""
@@ -98,10 +79,7 @@ class Controller:
top to bottom on the page.
"""
- self._sticky_panels = [
- nyx.panel.header.HeaderPanel(),
- LabelPanel(),
- ]
+ self._sticky_panels = [nyx.panel.header.HeaderPanel()]
self._page_panels, first_page_panels = [], []
@@ -128,7 +106,6 @@ class Controller:
self._is_paused = False
self._force_redraw = False
self._last_drawn = 0
- self.set_msg() # initializes our control message
def get_page_count(self):
"""
@@ -159,7 +136,7 @@ class Controller:
if page_number != self._page:
self._page = page_number
self._force_redraw = True
- self.set_msg()
+ self.get_panel('header').redraw(True)
def next_page(self):
"""
@@ -190,7 +167,7 @@ class Controller:
if is_pause != self._is_paused:
self._is_paused = is_pause
self._force_redraw = True
- self.set_msg()
+ self.get_panel('header').redraw(True)
for panel_impl in self.get_all_panels():
panel_impl.set_paused(is_pause)
@@ -303,37 +280,6 @@ class Controller:
if force:
self._last_drawn = current_time
- def set_msg(self, msg = None, attr = None, redraw = False):
- """
- Sets the message displayed in the interfaces control panel. This uses our
- default prompt if no arguments are provided.
-
- Arguments:
- msg - string to be displayed
- attr - attribute for the label, normal text if undefined
- redraw - redraws right away if true, otherwise redraws when display
- content is next normally drawn
- """
-
- if msg is None:
- msg = ''
-
- if attr is None:
- if not self._is_paused:
- msg = 'page %i / %i - m: menu, p: pause, h: page help, q: quit' % (self._page + 1, len(self._page_panels))
- attr = NORMAL
- else:
- msg = 'Paused'
- attr = HIGHLIGHT
-
- control_panel = self.get_panel('msg')
- control_panel.set_message(msg, attr)
-
- if redraw:
- control_panel.redraw(True)
- else:
- self._force_redraw = True
-
def quit(self):
self.quit_signal = True
@@ -421,7 +367,7 @@ def start_nyx():
if CONFIG['features.confirmQuit']:
msg = 'Are you sure (q again to confirm)?'
- confirmation_key = nyx.popups.show_msg(msg, attr = BOLD)
+ confirmation_key = show_message(msg, BOLD, max_wait = 30)
quit_confirmed = confirmation_key.match('q')
else:
quit_confirmed = True
@@ -432,7 +378,7 @@ def start_nyx():
# provides prompt to confirm that nyx should issue a sighup
msg = "This will reset Tor's internal state. Are you sure (x again to confirm)?"
- confirmation_key = nyx.popups.show_msg(msg, attr = BOLD)
+ confirmation_key = show_message(msg, BOLD, max_wait = 30)
if confirmation_key in (ord('x'), ord('X')):
try:
diff --git a/nyx/menu/item.py b/nyx/menu/item.py
index 8efcaf9..026f14a 100644
--- a/nyx/menu/item.py
+++ b/nyx/menu/item.py
@@ -60,9 +60,9 @@ class MenuItem():
if self._callback:
control = nyx.controller.get_controller()
- control.set_msg()
control.redraw()
self._callback()
+
return True
def next(self):
diff --git a/nyx/menu/menu.py b/nyx/menu/menu.py
index da22362..9b0dc20 100644
--- a/nyx/menu/menu.py
+++ b/nyx/menu/menu.py
@@ -77,8 +77,6 @@ class MenuCursor:
def show_menu():
with nyx.popups.popup_window(1, below_static = False) as (popup, width, height):
if popup:
- control = nyx.controller.get_controller()
-
# generates the menu and uses the initial selection of the first item in
# the file menu
@@ -94,7 +92,7 @@ def show_menu():
# provide a message saying how to close the menu
- control.set_msg('Press m or esc to close the menu.', BOLD, True)
+ nyx.controller.show_message('Press m or esc to close the menu.', BOLD)
# renders the menu bar, noting where the open submenu is positioned
@@ -124,9 +122,9 @@ def show_menu():
# redraws the rest of the interface if we're rendering on it again
if not cursor.is_done():
- control.redraw()
+ nyx.controller.get_controller().redraw()
- control.set_msg()
+ nyx.controller.show_message()
def _draw_submenu(cursor, level, top, left):
diff --git a/nyx/panel/config.py b/nyx/panel/config.py
index 2ad6f8f..4b2881d 100644
--- a/nyx/panel/config.py
+++ b/nyx/panel/config.py
@@ -223,9 +223,9 @@ class ConfigPanel(nyx.panel.Panel):
if selection == 0:
try:
controller.save_conf()
- nyx.popups.show_msg('Saved configuration to %s' % controller.get_info('config-file', '<unknown>'), 2)
+ nyx.controller.show_message('Saved configuration to %s' % controller.get_info('config-file', '<unknown>'), HIGHLIGHT, max_wait = 2)
except IOError as exc:
- nyx.popups.show_msg('Unable to save configuration (%s)' % exc.strerror, 2)
+ nyx.controller.show_message('Unable to save configuration (%s)' % exc.strerror, HIGHLIGHT, max_wait = 2)
break
elif key.match('esc'):
@@ -243,7 +243,7 @@ class ConfigPanel(nyx.panel.Panel):
elif key.is_selection():
selected = self._scroller.selection(self._get_config_options())
initial_value = selected.value() if selected.is_set() else ''
- new_value = nyx.popups.input_prompt('%s Value (esc to cancel): ' % selected.name, initial_value)
+ new_value = nyx.controller.input_prompt('%s Value (esc to cancel): ' % selected.name, initial_value)
if new_value != initial_value:
try:
@@ -260,7 +260,7 @@ class ConfigPanel(nyx.panel.Panel):
tor_controller().set_conf(selected.name, new_value)
self.redraw(True)
except Exception as exc:
- nyx.popups.show_msg('%s (press any key)' % exc)
+ nyx.controller.show_message('%s (press any key)' % exc, HIGHLIGHT, max_wait = 30)
elif key.match('a'):
self._show_all = not self._show_all
self.redraw(True)
diff --git a/nyx/panel/graph.py b/nyx/panel/graph.py
index 7315bea..212ee85 100644
--- a/nyx/panel/graph.py
+++ b/nyx/panel/graph.py
@@ -474,13 +474,10 @@ class GraphPanel(nyx.panel.Panel):
* enter / space - set size
"""
- control = nyx.controller.get_controller()
-
with nyx.curses.CURSES_LOCK:
try:
while True:
- msg = 'press the down/up to resize the graph, and enter when done'
- control.set_msg(msg, BOLD, True)
+ nyx.controller.show_message('press the down/up to resize the graph, and enter when done', BOLD)
key = nyx.curses.key_input()
if key.match('down'):
@@ -497,9 +494,9 @@ class GraphPanel(nyx.panel.Panel):
elif key.is_selection():
break
- control.redraw()
+ nyx.controller.get_controller().redraw()
finally:
- control.set_msg()
+ nyx.controller.show_message()
def handle_key(self, key):
if key.match('r'):
diff --git a/nyx/panel/header.py b/nyx/panel/header.py
index 0c7aa1b..00d3ff2 100644
--- a/nyx/panel/header.py
+++ b/nyx/panel/header.py
@@ -20,7 +20,7 @@ from stem.control import Listener, State
from stem.util import conf, log, proc, str_tools, system
from nyx import msg, tor_controller
-from nyx.curses import RED, GREEN, YELLOW, CYAN, WHITE, BOLD
+from nyx.curses import RED, GREEN, YELLOW, CYAN, WHITE, BOLD, HIGHLIGHT
MIN_DUAL_COL_WIDTH = 141 # minimum width where we'll show two columns
SHOW_FD_THRESHOLD = 60 # show file descriptor usage if usage is over this percentage
@@ -49,8 +49,51 @@ class HeaderPanel(nyx.panel.Panel, threading.Thread):
self._halt = False # terminates thread if true
self._reported_inactive = False
+ self._message = None
+ self._message_attr = None
+
tor_controller().add_status_listener(self.reset_listener)
+ def show_message(self, message = None, *attr, **kwargs):
+ """
+ Sets the message displayed at the bottom of the header. If not called with
+ anything it clears the override.
+
+ :param str message: message to be displayed
+ :param list attr: text attributes to apply
+ :param int max_wait: seconds to wait for user input, no limit if **None**
+
+ :returns: :class:`~nyx.curses.KeyInput` user pressed if provided a
+ **max_wait**, **None** otherwise or if prompt was canceled
+ """
+
+ self._message = message
+ self._message_attr = attr
+ self.redraw(True)
+
+ if 'max_wait' in kwargs:
+ user_input = nyx.curses.key_input(kwargs['max_wait'])
+ self.show_message() # clear override
+ return user_input
+
+ def input_prompt(self, message, initial_value = ''):
+ """
+ Prompts the user for input.
+
+ :param str message: prompt for user input
+ :param str initial_value: initial value of the prompt
+
+ :returns: **str** with the user input, this is **None** if the prompt is
+ canceled
+ """
+
+ self.show_message(message)
+ self.redraw(True)
+ user_input = self.getstr(self.get_height() - 1, len(message), initial_value)
+ self.show_message()
+
+ return user_input
+
def is_wide(self):
"""
True if we should show two columns of information, False otherwise.
@@ -65,9 +108,9 @@ class HeaderPanel(nyx.panel.Panel, threading.Thread):
"""
if self._vals.is_relay:
- return 4 if self.is_wide() else 6
+ return 5 if self.is_wide() else 7
else:
- return 3 if self.is_wide() else 4
+ return 4 if self.is_wide() else 5
def send_newnym(self):
"""
@@ -85,7 +128,7 @@ class HeaderPanel(nyx.panel.Panel, threading.Thread):
# indication that the signal was sent. Otherwise use a msg.
if not self.is_wide():
- nyx.popups.show_msg('Requesting a new identity', 1)
+ self.show_message('Requesting a new identity', HIGHLIGHT, max_wait = 1)
def handle_key(self, key):
if key.match('n'):
@@ -108,15 +151,15 @@ class HeaderPanel(nyx.panel.Panel, threading.Thread):
try:
controller.authenticate() # TODO: should account for our chroot
except stem.connection.MissingPassword:
- password = nyx.popups.input_prompt('Controller Password: ')
+ password = self.input_prompt('Controller Password: ')
if password:
controller.authenticate(password)
log.notice("Reconnected to Tor's control port")
- nyx.popups.show_msg('Tor reconnected', 1)
+ self.show_message('Tor reconnected', HIGHLIGHT, max_wait = 1)
except Exception as exc:
- nyx.popups.show_msg('Unable to reconnect (%s)' % exc, 3)
+ self.show_message('Unable to reconnect (%s)' % exc, HIGHLIGHT, max_wait = 3)
controller.close()
else:
return False
@@ -156,6 +199,14 @@ class HeaderPanel(nyx.panel.Panel, threading.Thread):
self._draw_fingerprint_and_fd_usage(0, 3, left_width, vals)
self._draw_flags(0, 4, left_width, vals)
+ if self._message:
+ self.addstr(height - 1, 0, self._message, *self._message_attr)
+ elif not self.is_paused():
+ controller = nyx.controller.get_controller()
+ self.addstr(height - 1, 0, 'page %i / %i - m: menu, p: pause, h: page help, q: quit' % (controller.get_page() + 1, controller.get_page_count()))
+ else:
+ self.addstr(height - 1, 0, 'Paused', HIGHLIGHT)
+
def _draw_platform_section(self, x, y, width, vals):
"""
Section providing the user's hostname, platform, and version information...
diff --git a/nyx/panel/log.py b/nyx/panel/log.py
index 094ad06..c16eaec 100644
--- a/nyx/panel/log.py
+++ b/nyx/panel/log.py
@@ -11,6 +11,7 @@ import threading
import stem.response.events
import nyx.arguments
+import nyx.controller
import nyx.curses
import nyx.panel
import nyx.popups
@@ -128,7 +129,7 @@ class LogPanel(nyx.panel.Panel, threading.Thread):
Prompts the user to add a new regex filter.
"""
- regex_input = nyx.popups.input_prompt('Regular expression: ')
+ regex_input = nyx.controller.input_prompt('Regular expression: ')
if regex_input:
self._filter.select(regex_input)
@@ -153,7 +154,7 @@ class LogPanel(nyx.panel.Panel, threading.Thread):
popup.win.refresh()
- user_input = nyx.popups.input_prompt('Events to log: ')
+ user_input = nyx.controller.input_prompt('Events to log: ')
if user_input:
try:
@@ -164,21 +165,21 @@ class LogPanel(nyx.panel.Panel, threading.Thread):
self._event_types = nyx.log.listen_for_events(self._register_tor_event, event_types)
self.redraw(True)
except ValueError as exc:
- nyx.popups.show_msg('Invalid flags: %s' % str(exc), 2)
+ nyx.controller.show_message('Invalid flags: %s' % exc, HIGHLIGHT, max_wait = 2)
def show_snapshot_prompt(self):
"""
Lets user enter a path to take a snapshot, canceling if left blank.
"""
- path_input = nyx.popups.input_prompt('Path to save log snapshot: ')
+ path_input = nyx.controller.input_prompt('Path to save log snapshot: ')
if path_input:
try:
self.save_snapshot(path_input)
- nyx.popups.show_msg('Saved: %s' % path_input, 2)
+ nyx.controller.show_message('Saved: %s' % path_input, HIGHLIGHT, max_wait = 2)
except IOError as exc:
- nyx.popups.show_msg('Unable to save snapshot: %s' % exc, 2)
+ nyx.controller.show_message('Unable to save snapshot: %s' % exc, HIGHLIGHT, max_wait = 2)
def clear(self):
"""
@@ -233,7 +234,7 @@ class LogPanel(nyx.panel.Panel, threading.Thread):
self.redraw(True)
elif key.match('c'):
msg = 'This will clear the log. Are you sure (c again to confirm)?'
- key_press = nyx.popups.show_msg(msg, attr = BOLD)
+ key_press = nyx.controller.show_message(msg, BOLD, max_wait = 30)
if key_press.match('c'):
self.clear()
diff --git a/nyx/popups.py b/nyx/popups.py
index bf40e4c..1f19189 100644
--- a/nyx/popups.py
+++ b/nyx/popups.py
@@ -75,47 +75,6 @@ def popup_window(height = -1, width = -1, top = 0, left = 0, below_static = True
return _Popup()
-def input_prompt(msg, initial_value = ''):
- """
- Prompts the user to enter a string on the control line (which usually
- displays the page number and basic controls).
-
- Arguments:
- msg - message to prompt the user for input with
- initial_value - initial value of the field
- """
-
- with nyx.curses.CURSES_LOCK:
- control = nyx.controller.get_controller()
- msg_panel = control.get_panel('msg')
- msg_panel.set_message(msg)
- msg_panel.redraw(True)
- user_input = msg_panel.getstr(0, len(msg), initial_value)
- control.set_msg()
-
- return user_input
-
-
-def show_msg(msg, max_wait = None, attr = HIGHLIGHT):
- """
- Displays a single line message on the control line for a set time. Pressing
- any key will end the message. This returns the key pressed.
-
- Arguments:
- msg - message to be displayed to the user
- max_wait - time to show the message, indefinite if None
- attr - attributes with which to draw the message
- """
-
- with nyx.curses.CURSES_LOCK:
- control = nyx.controller.get_controller()
- control.set_msg(msg, attr, True)
-
- key_press = nyx.curses.key_input(max_wait)
- control.set_msg()
- return key_press
-
-
def show_help_popup():
"""
Presents a popup with instructions for the current page's hotkeys. This
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits