diff --git a/npyscreen/__init__.py b/npyscreen/__init__.py index e9cbde2..b401d01 100755 --- a/npyscreen/__init__.py +++ b/npyscreen/__init__.py @@ -90,7 +90,7 @@ from .npyspmfuncs import CallSubShell -from .utilNotify import notify, notify_confirm, notify_wait, notify_ok_cancel, notify_yes_no +from .utilNotify import notify, notify_confirm, notify_wait, notify_ok_cancel, notify_yes_no, notify_loading # Base classes for overriding: diff --git a/npyscreen/fmPopup.py b/npyscreen/fmPopup.py index e2bbb08..b64df77 100644 --- a/npyscreen/fmPopup.py +++ b/npyscreen/fmPopup.py @@ -11,28 +11,39 @@ class Popup(fmForm.Form): DEFAULT_COLUMNS = 60 SHOW_ATX = 10 SHOW_ATY = 2 - + + class ActionPopup(fmActionFormV2.ActionFormV2): DEFAULT_LINES = 12 DEFAULT_COLUMNS = 60 SHOW_ATX = 10 SHOW_ATY = 2 - - + + +class LoadingPopup(fmForm.Form): + DEFAULT_LINES = 7 + DEFAULT_COLUMNS = 12 + SHOW_ATX = 10 + SHOW_ATY = 2 + + class MessagePopup(Popup): def __init__(self, *args, **keywords): from . import wgmultiline as multiline super(MessagePopup, self).__init__(*args, **keywords) self.TextWidget = self.add(multiline.Pager, scroll_exit=True, max_height=self.widget_useable_space()[0]-2) - + + class PopupWide(Popup): DEFAULT_LINES = 14 DEFAULT_COLUMNS = None SHOW_ATX = 0 SHOW_ATY = 0 - + + class ActionPopupWide(fmActionFormV2.ActionFormV2): DEFAULT_LINES = 14 DEFAULT_COLUMNS = None SHOW_ATX = 0 SHOW_ATY = 0 + diff --git a/npyscreen/utilNotify.py b/npyscreen/utilNotify.py index 6cf8aae..d3289d8 100644 --- a/npyscreen/utilNotify.py +++ b/npyscreen/utilNotify.py @@ -3,6 +3,7 @@ from . import fmPopup import curses import textwrap +import threading class ConfirmCancelPopup(fmPopup.ActionPopup): def on_ok(self): @@ -115,4 +116,85 @@ def single_line_input(default_value="Input Text", title="Message", form_color='S if F.value is True: return tf.value else: - return None \ No newline at end of file + return None + +def notify_loading(routine, frames = None, title = "Loading", delay = 150, form_color='STANDOUT'): + ''' Convenience function for displaying an animation while a task is in progress. + + Args: + routine (func): The function we are waiting for. + frames ([str]): A list of string that are our animation's frames. + title (str): Title for the popup. + delay (int): The time between each frame. + form_color (str): Color scheme used (as defined by the theme used). + + Returns: + any: - Value returned by routine. + ''' + + global waiting + global result + + waiting = True + + if frames == None: + frames = [ + " |/\n" + " +\n", + + " \| \n" + " +\n", + + " \\ \n" + " --+ \n", + + " \n" + " --+ \n" + " /", + + " \n" + " + \n" + " /|", + + " \n" + " + \n" + " |\\", + + " \n" + " +--\n" + " \\", + + " /\n" + " +-- \n" + ] + + def display_frame(frame, title, + wrap=True, wide=False, + ): + F = fmPopup.LoadingPopup(name=title, color=form_color) + F.preserve_selected_widget = True + mlw = F.add(wgmultiline.Pager,) + mlw.values = frame.split('\n') + F.display() + + def capsule(): + ''' This function is intended to be ran inside a new thread. + I use global for avoiding shadowing waiting and result variables. + ''' + global waiting + global result + result = routine() + waiting = False + + thread = threading.Thread(target=capsule) + thread.start() + i = 0 + while waiting: + display_frame(frames[i], title) + i = i + 1 + if(i >= len(frames)): + i = 0 + curses.napms(150) + curses.flushinp() + thread.join() + return result \ No newline at end of file