Source code for ui.number_input
from time import sleep
from copy import copy
import logging
def to_be_foreground(func): #A safety check wrapper so that certain checks don't get called if menu is not the one active
def wrapper(self, *args, **kwargs):
if self.in_foreground:
return func(self, *args, **kwargs)
else:
return False
return wrapper
[docs]class IntegerAdjustInput():
"""Implements a simple number input dialog which allows you to increment/decrement a number using which can be used to navigate through your application, output a list of values or select actions to perform. Is one of the most used elements, used both in system core and in most of the applications.
Attributes:
* ``number``: The number being changed.
* ``initial_number``: The number sent to the constructor. Used by reset() method.
* ``selected_number``: A flag variable to be returned by activate().
* ``in_foreground`` : a flag which indicates if UI element is currently displayed. If it's not active, inhibits any of element's actions which can interfere with other UI element being displayed.
"""
display_callback = None
in_foreground = False
name = ""
message = ""
initial_number = 0
number = 0
selected_number = None
[docs] def __init__(self, number, i, o, message="Pick a number:", interval=1, name="IntegerAdjustInput"):
"""Initialises the IntegerAdjustInput object.
Args:
* ``number``: number to be operated on
* ``i``, ``o``: input&output device objects
Kwargs:
* ``message``: Message to be shown on the first line of the screen when UI element is active.
* ``interval``: Value by which the number is incremented and decremented.
* ``name``: UI element name which can be used internally and for debugging.
"""
self.i = i
self.o = o
if type(number) != int:
raise ValueError("IntegerAdjustInput operates on integers!")
self.initial_number = number
self.number = number
self.message = message
self.name = name
self.interval = interval
self.set_display_callback(o.display_data)
self.generate_keymap()
def to_foreground(self):
""" Is called when ``activate()`` method is used, sets flags and performs all the actions so that UI element can display its contents and receive keypresses. Also, refreshes the screen."""
logging.info("{0} enabled".format(self.name))
self.in_foreground = True
self.refresh()
self.set_keymap()
[docs] def activate(self):
""" A method which is called when input element needs to start operating. Is blocking, sets up input&output devices, renders the UI element and waits until self.in_background is False, while callbacks are executed from the input device thread.
This method returns the selected number if KEY_ENTER was pressed, thus accepting the selection.
This method returns None when the UI element was exited by KEY_LEFT and thus it's assumed changes to the number were not accepted."""
logging.info("{0} activated".format(self.name))
self.to_foreground()
while self.in_foreground: #All the work is done in input callbacks
sleep(0.1)
logging.debug(self.name+" exited")
return self.selected_number
[docs] def deactivate(self):
""" Deactivates the UI element, exiting it and thus making activate() return."""
self.in_foreground = False
logging.info("{0} deactivated".format(self.name))
[docs] def print_number(self):
""" A debug method. Useful for hooking up to an input event so that you can see current number value. """
logging.info(self.number)
[docs] def print_name(self):
""" A debug method. Useful for hooking up to an input event so that you can see which UI element is currently processing input events. """
logging.info("{0} active".format(self.name))
@to_be_foreground
def decrement(self):
"""Decrements the number by selected ``interval``"""
self.number -= self.interval
self.refresh()
@to_be_foreground
def increment(self):
"""Increments the number by selected ``interval``"""
self.number += self.interval
self.refresh()
@to_be_foreground
def reset(self):
"""Resets the number, setting it to the number passed to the constructor."""
logging.debug("Number reset")
self.number = self.initial_number
self.refresh()
@to_be_foreground
def select_number(self):
"""Selects the currently active number value, making activate() return it."""
logging.debug("Number accepted")
self.selected_number = self.number
self.deactivate()
@to_be_foreground
def exit(self):
"""Exits discarding all the changes to the number."""
logging.debug("{} exited without changes".format(self.name))
self.deactivate()
def generate_keymap(self):
self.keymap = {
"KEY_RIGHT":lambda: self.reset(),
"KEY_UP":lambda: self.increment(),
"KEY_DOWN":lambda: self.decrement(),
"KEY_KPENTER":lambda: self.select_number(),
"KEY_ENTER":lambda: self.select_number(),
"KEY_LEFT":lambda: self.exit()
}
@to_be_foreground
def set_keymap(self):
self.generate_keymap()
self.i.stop_listen()
self.i.clear_keymap()
self.i.keymap = self.keymap
self.i.listen()
def get_displayed_data(self):
return [self.message, str(self.number).rjust(self.o.cols)]
@to_be_foreground
def refresh(self):
logging.debug("{0}: refreshed data on display".format(self.name))
self.display_callback(*self.get_displayed_data())
def set_display_callback(self, callback):
logging.debug("{0}: display callback set".format(self.name))
self.display_callback = callback