Browse Source

add config frontend

add config frontend for configuring the firmware. type "make config" to configure.
build system does not use it yet
fertito
Daniel Poelzleithner 12 years ago
parent
commit
635ba91f73
  1. 3
      .gitignore
  2. 175
      tools/config.py
  3. 52
      tools/npyscreen/__init__.py
  4. 27
      tools/npyscreen/apNPSApplication.py
  5. 140
      tools/npyscreen/apNPSApplicationManaged.py
  6. 84
      tools/npyscreen/fmActionForm.py
  7. 366
      tools/npyscreen/fmForm.py
  8. 40
      tools/npyscreen/fmFormMutt.py
  9. 66
      tools/npyscreen/fmFormWithMenus.py
  10. 31
      tools/npyscreen/fmPopup.py
  11. 100
      tools/npyscreen/fm_form_edit_loop.py
  12. 70
      tools/npyscreen/muMenu.py
  13. 63
      tools/npyscreen/muNewMenu.py
  14. 2
      tools/npyscreen/npysGlobalOptions.py
  15. 68
      tools/npyscreen/npysNPSTree.py
  16. 91
      tools/npyscreen/npysThemeManagers.py
  17. 25
      tools/npyscreen/npysThemes.py
  18. 34
      tools/npyscreen/npyspmfuncs.py
  19. 106
      tools/npyscreen/npyssafewrapper.py
  20. 148
      tools/npyscreen/proto_fm_screen_area.py
  21. 58
      tools/npyscreen/wgFormControlCheckbox.py
  22. 138
      tools/npyscreen/wgNMenuDisplay.py
  23. 115
      tools/npyscreen/wgautocomplete.py
  24. 51
      tools/npyscreen/wgbutton.py
  25. 100
      tools/npyscreen/wgcheckbox.py
  26. 89
      tools/npyscreen/wgcombobox.py
  27. 88
      tools/npyscreen/wgdatecombo.py
  28. 270
      tools/npyscreen/wgeditmultiline.py
  29. 235
      tools/npyscreen/wggrid.py
  30. 45
      tools/npyscreen/wggridcoltitles.py
  31. 206
      tools/npyscreen/wgmonthbox.py
  32. 564
      tools/npyscreen/wgmultiline.py
  33. 114
      tools/npyscreen/wgmultilinetree.py
  34. 69
      tools/npyscreen/wgmultiselect.py
  35. 44
      tools/npyscreen/wgmultiselecttree.py
  36. 24
      tools/npyscreen/wgpassword.py
  37. 50
      tools/npyscreen/wgselectone.py
  38. 131
      tools/npyscreen/wgslider.py
  39. 301
      tools/npyscreen/wgtextbox.py
  40. 28
      tools/npyscreen/wgtextbox_controlchrs.py
  41. 121
      tools/npyscreen/wgtitlefield.py
  42. 401
      tools/npyscreen/wgwidget.py

3
.gitignore vendored

@ -0,0 +1,3 @@
*.[oa]
*.pyc
*.*~

175
tools/config.py

@ -0,0 +1,175 @@
#!/usr/bin/env python
# encoding: utf-8
import npyscreen
import re, sys
#npyscreen.disableColor()
DATA = {
"CONFIG_FREQUENCY": {
"name": "Frequency",
"depends": [],
"default": 911,
"type": "choices",
"values": [911, 868, 433]},
"CONFIG_ACCEL": {
"name": "Accleration",
"depends": [],
"default": True},
"CONFIG_ALARM": {
"name": "Alarm",
"depends": [],
"default": True},
"CONFIG_ALTITUDE": {
"name": "Altitude",
"depends": [],
"default": True},
"CONFIG_BATTERY": {
"name": "Battery",
"depends": [],
"default": True},
"CONFIG_CLOCK": {
"name": "Clock",
"depends": [],
"default": True},
"CONFIG_DATE": {
"name": "Date",
"depends": [],
"default": True},
"CONFIG_PHASE_CLOCK": {
"name": "Phase Clock",
"depends": [],
"default": False},
"CONFIG_RFBSL": {
"name": "Wireless Update",
"depends": [],
"default": True},
"CONFIG_STOP_WATCH": {
"name": "Stop Watch",
"depends": [],
"default": True},
"CONFIG_STOP_TEMP": {
"name": "Temperature",
"depends": [],
"default": True},
}
#load_config()
#print DATA
#sys.exit(1)
class OpenChronosApp(npyscreen.NPSApp):
def main(self):
self.fields = {}
# These lines create the form and populate it with widgets.
# A fairly complex screen in only 8 or so lines of code - a line for each control.
F = npyscreen.Form(name = "Config Chronos Firmware",)
# ms2= F.add(npyscreen.TitleMultiSelect, max_height =-2, value = [1,], name="Frequency",
# values = ["911","868","Option3"], scroll_exit=True)
# ms2= F.add(npyscreen.TitleMultiSelect, max_height =-2, value = [1,], name="Pick Several",
# values = ["Option1","Option2","Option3"], scroll_exit=True)
# fn = F.add(npyscreen.TitleFilename, name = "Filename:")
# dt = F.add(npyscreen.TitleDateCombo, name = "Date:")
# s = F.add(npyscreen.TitleSlider, out_of=12, name = "Slider")
# ml= F.add(npyscreen.MultiLineEdit,
# value = """try typing here!\nMutiline text, press ^R to reformat.\n""",
# max_height=5, rely=9)
# ms2= F.add(npyscreen.TitleMultiSelect, max_height =-2, value = [1,], name="Pick Several",
# values = ["Option1","Option2","Option3"], scroll_exit=True)
#t = F.add(npyscreen.TitleText, name = "Modules:",)
for key,field in DATA.iteritems():
if field.get("type", "bool") == "bool":
#f=F.add(npyscreen.TitleMultiSelect, max_height = 1, value = ["ENABLED",], name=field["name"],
# values = [""], scroll_exit=True)
f = F.add(npyscreen.Checkbox, name=field["name"], value=field["value"])
f._key = key
self.fields[key] = f
elif field["type"] == "choices":
try:
value = field["values"].index(field["value"])
except ValueError:
value = field["values"].index(field["default"])
f = F.add(npyscreen.TitleSelectOne, max_height=4, value=value, name="Frequency",
values = field["values"], scroll_exit=True)
f._key = key
self.fields[key] = f
# This lets the user play with the Form.
F.edit()
print "done", F
def save_config(self):
for key,field in self.fields.iteritems():
value = field.value
if hasattr(field, "values"):
value = field.values[value[0]]
DATA[key]["value"] = value
fp = open("config.h", "w")
for key,dat in DATA.iteritems():
if isinstance(dat["value"], bool):
if dat["value"]:
fp.write("#define %s\n" %key)
else:
fp.write("// %s is not set\n" %key)
else:
fp.write("#define %s %s\n" %(key, dat["value"]))
def load_config(self):
def set_default():
for key,dat in DATA.iteritems():
print dat
if not "value" in dat:
dat["value"] = dat["default"]
try:
fp = open("config.h")
except (OSError, IOError):
set_default()
return
match = re.compile('^[\t ]*#[\t ]*define[\t ]+([a-zA-Z0-9_]+)[\t ]*(.*)$')
match2 = re.compile('^// ([a-zA-Z0-9_]+) is not set$')
for line in fp:
print line
m = match.search(line)
print m
if m:
m = m.groups()
if not m[0] in DATA:
continue
if m[1] == "":
DATA[m[0]]["value"] = True
else:
try:
value = int(m[1])
except ValueError:
value = m[1]
DATA[m[0]]["value"] = value
else:
m = match2.search(line)
if m:
m = m.groups()
DATA[m[0]]["value"] = False
#print DATA
#sys.exit(0)
set_default()
if __name__ == "__main__":
App = OpenChronosApp()
App.load_config()
App.run()
App.save_config()

52
tools/npyscreen/__init__.py

@ -0,0 +1,52 @@
#!/usr/bin/python
from .npyssafewrapper import wrapper, wrapper_basic
from .npysThemeManagers import ThemeManager, disableColor, enableColor
from . import npysThemes as Themes
from .apNPSApplication import NPSApp
from .apNPSApplicationManaged import NPSAppManaged
from .proto_fm_screen_area import setTheme
from .fmForm import FormBaseNew, Form, TitleForm, TitleFooterForm, SplitForm
from .fmActionForm import ActionForm
from .fmFormWithMenus import FormWithMenus, ActionFormWithMenus, FormBaseNewWithMenus
from .fmPopup import Popup, MessagePopup, ActionPopup
from .fmFormMutt import FormMutt
from .wgbutton import MiniButton
from .wgbutton import MiniButtonPress
from .wgbutton import MiniButton as Button
from .wgbutton import MiniButtonPress as ButtonPress
from .wgtextbox import Textfield, FixedText
from .wgtitlefield import TitleText, TitleFixedText
from .wgpassword import PasswordEntry, TitlePassword
from .wgslider import Slider, TitleSlider
from .wgwidget import DummyWidget
from .wgmultiline import MultiLine, Pager, TitleMultiLine
from .wgmultiselect import MultiSelect, TitleMultiSelect, MultiSelectFixed, TitleMultiSelectFixed
from .wgeditmultiline import MultiLineEdit
from .wgcombobox import ComboBox, TitleCombo
from .wgcheckbox import Checkbox, RoundCheckBox
from .wgFormControlCheckbox import FormControlCheckbox
from .wgautocomplete import TitleFilename, Filename, Autocomplete
from .muMenu import Menu
from .wgselectone import SelectOne, TitleSelectOne
from .wgdatecombo import DateCombo, TitleDateCombo
from .wgmonthbox import MonthBox
from .wggrid import SimpleGrid
from .wggridcoltitles import GridColTitles
from .muNewMenu import NewMenu, MenuItem
from .wgNMenuDisplay import MenuDisplay, MenuDisplayScreen
from .npyspmfuncs import CallSubShell

27
tools/npyscreen/apNPSApplication.py

@ -0,0 +1,27 @@
#!/usr/bin/env python
import curses
import locale
import _curses
from . import npyssafewrapper
class AlreadyOver(Exception):
pass
class NPSApp(object):
_run_called = 0
def main(self):
"""Overload this method to create your application"""
def __remove_argument_call_main(self, screen):
# screen disgarded.
del screen
return self.main()
def run(self, fork=None):
"""Run application. Calls Mainloop wrapped properly."""
if fork is None:
return npyssafewrapper.wrapper(self.__remove_argument_call_main)
else:
return npyssafewrapper.wrapper(self.__remove_argument_call_main, fork=fork)

140
tools/npyscreen/apNPSApplicationManaged.py

@ -0,0 +1,140 @@
#!/usr/bin/env python
# encoding: utf-8
"""
NPSAppManaged.py
"""
from . import apNPSApplication
from . import fmForm
import weakref
class NPSAppManaged(apNPSApplication.NPSApp):
"""This class is intended to make it easier to program applications with many screens:
1. The programmer should not now select which 'Form' to display himself. Instead, he should set the NEXT_ACTIVE_FORM class variable.
See the registerForm method for details.
Doing this will avoid accidentally exceeding the maximum recursion depth. Forms themselves should be placed under the management
of the class using the 'addForm' or 'addFormClass' method.
2. Forms that are managed by this class can access a proxy to the parent application through their ".parentApp" attribute, which is
created by this class.
3. a Optionally, Forms managed by this class may be given an .activate method, which will be called instead of their .edit loop
b If not given an .activate method, any .afterEditing method which a form possesses will be called after .edit() has exited.
3b is the preferred method to change NEXT_ACTIVE_FORM
4. The method onInMainLoop is called after each screen has exited. This can be overridden.
5. This method should be able to see which screen was last active using the self._LAST_NEXT_ACTIVE_FORM attribute, which is only set
just before each screen is displayed.
6. Unless you override the attribute STARTING_FORM, the first form to be called should be named 'MAIN'
7. Do override the onStart and onCleanExit functions if you wish.
"""
STARTING_FORM = "MAIN"
def __init__(self):
super(NPSAppManaged, self).__init__()
self.NEXT_ACTIVE_FORM = self.__class__.STARTING_FORM
self._LAST_NEXT_ACTIVE_FORM = None
self._Forms = {}
def addFormClass(self, f_id, FormClass, *args, **keywords):
self._Forms[f_id] = [FormClass, args, keywords]
def addForm(self, f_id, FormClass, *args, **keywords):
"""Create a form of the given class. f_id should be a string which will uniquely identify the form. *args will be passed to the Form constructor.
Forms created in this way are handled entirely by the NPSAppManaged class."""
fm = FormClass( parentApp=self, *args, **keywords)
self.registerForm(f_id, fm)
return weakref.proxy(fm)
def registerForm(self, f_id, fm):
"""f_id should be a string which should uniquely identify the form. fm should be a Form."""
fm.parentApp = weakref.proxy(self)
self._Forms[f_id] = fm
def removeForm(self, f_id):
del self._Forms[f_id].parentApp
del self._Forms[f_id]
def getForm(self, name):
f = self._Forms[name]
try:
return weakref.proxy(f)
except:
return f
def setNextForm(self, fmid):
"""Set the form that will be selected when the current one exits."""
self.NEXT_ACTIVE_FORM = fmid
def switchForm(self, fmid):
"""Immediately switch to the form specified by fmid."""
self._THISFORM.editing = False
self.NEXT_ACTIVE_FORM = fmid
try:
self._THISFORM._widgets__[self._THISFORM.editw].editing = False
except:
pass
def main(self):
"""Call this function to start your application. You should not override this function, but override the onInMainLoop, onStart and
onCleanExit methods instead, if you need to modify the application's behaviour.
When this method is called, it will activate the form named by the class variable STARTING_FORM. By default this Form will be called
'MAIN'.
When that form exits (user selecting an ok button or the like), the form named by object variable NEXT_ACTIVE_FORM will be activated.
If NEXT_ACTIVE_FORM is None, the main() loop will exit.
The form selected will be edited using it's .edit() method UNLESS it has been provided with an .activate() method,
in which case that method will be called instead. This is done so that the same class of form can be made
NPSAppManaged aware and have the normal non-NPSAppManaged edit loop.
After a Form has been edited, if it has an .afterEditing method, this will be called, unless it was invoked with the activate() method.
A similar .beforeEditing method will be called if it exists before editing the form. Again, the presence of a .activate method
will override this behaviour.
Note that NEXT_ACTIVE_FORM is a string that is the name of the form that was specified when .addForm or .registerForm was called.
"""
self.onStart()
while self.NEXT_ACTIVE_FORM != "" and self.NEXT_ACTIVE_FORM != None:
self._LAST_NEXT_ACTIVE_FORM = self._Forms[self.NEXT_ACTIVE_FORM]
self.LAST_ACTIVE_FORM_NAME = self.NEXT_ACTIVE_FORM
try:
Fm, a, k = self._Forms[self.NEXT_ACTIVE_FORM]
self._THISFORM = Fm( parentApp = self, *a, **k )
except TypeError:
self._THISFORM = self._Forms[self.NEXT_ACTIVE_FORM]
if hasattr(self._THISFORM, "activate"):
self._THISFORM.activate()
else:
if hasattr(self._THISFORM, "beforeEditing"):
self._THISFORM.beforeEditing()
self._THISFORM.edit()
if hasattr(self._THISFORM, "afterEditing"):
self._THISFORM.afterEditing()
self.onInMainLoop()
self.onCleanExit()
def onInMainLoop(self):
"""Called between each screen while the application is running. Not called before the first screen. Override at will"""
def onStart(self):
"""Override this method to perform any initialisation."""
pass
def onCleanExit(self):
"""Override this method to perform any cleanup when application is exiting without error."""

84
tools/npyscreen/fmActionForm.py

@ -0,0 +1,84 @@
#!/usr/bin/python
from . import fmForm
from . import wgwidget as widget
class ActionForm(fmForm.Form):
"""A form with OK and Cancel buttons. Users should override the on_ok and on_cancel methods."""
CANCEL_BUTTON_BR_OFFSET = (2, 12)
def set_up_exit_condition_handlers(self):
super(ActionForm, self).set_up_exit_condition_handlers()
self.how_exited_handers.update({
widget.EXITED_ESCAPE: self.find_cancel_button
})
def find_cancel_button(self):
self.editw = len(self._widgets__)-2
def edit(self):
self.editing=True
if self.editw < 0: self.editw=0
if self.editw > len(self._widgets__)-1:
self.editw = len(self._widgets__)-1
if not self._widgets__[self.editw].editable: self.find_next_editable()
# Add ok and cancel buttons. Will remove later
tmp_rely, tmp_relx = self.nextrely, self.nextrelx
c_button_text = "Cancel"
cmy, cmx = self.curses_pad.getmaxyx()
cmy -= self.__class__.CANCEL_BUTTON_BR_OFFSET[0]
cmx -= len(c_button_text)+self.__class__.CANCEL_BUTTON_BR_OFFSET[1]
self.c_button = self.add_widget(self.__class__.OKBUTTON_TYPE, name=c_button_text, rely=cmy, relx=cmx, use_max_space=True)
c_button_postion = len(self._widgets__)-1
self.c_button.update()
my, mx = self.curses_pad.getmaxyx()
ok_button_text = "OK"
my -= self.__class__.OK_BUTTON_BR_OFFSET[0]
mx -= len(ok_button_text)+self.__class__.OK_BUTTON_BR_OFFSET[1]
self.ok_button = self.add_widget(self.__class__.OKBUTTON_TYPE, name=ok_button_text, rely=my, relx=mx, use_max_space=True)
ok_button_postion = len(self._widgets__)-1
self.ok_button.update()
self.display()
while not self._widgets__[self.editw].editable:
self.editw += 1
if self.editw > len(self._widgets__)-2:
self.editing = False
return False
while self.editing:
if not self.ALL_SHOWN: self.on_screen()
self.while_editing()
self._widgets__[self.editw].edit()
self._widgets__[self.editw].display()
self.handle_exiting_widgets(self._widgets__[self.editw].how_exited)
if self.editw > len(self._widgets__)-1: self.editw = len(self._widgets__)-1
if self.ok_button.value or self.c_button.value:
self.editing = False
if self.ok_button.value:
self.edit_return_value = self.on_ok()
elif self.c_button.value:
self.edit_return_value = self.on_cancel()
self.ok_button.destroy()
self.c_button.destroy()
del self._widgets__[ok_button_postion]
del self.ok_button
del self._widgets__[c_button_postion]
del self.c_button
self.nextrely, self.nextrelx = tmp_rely, tmp_relx
self.display()
self.editing = False
return self.edit_return_value
def on_cancel(self):
pass
def on_ok(self):
pass

366
tools/npyscreen/fmForm.py

@ -0,0 +1,366 @@
#!/usr/bin/python
from . import proto_fm_screen_area
from . import wgwidget as widget
from . import wgbutton as button
import weakref
from . import npyspmfuncs as pmfuncs
#import Menu
import curses
from . import npysGlobalOptions
from . import fm_form_edit_loop as form_edit_loop
class _FormBase(proto_fm_screen_area.ScreenArea, widget.InputHandler,):
BLANK_COLUMNS_RIGHT= 2
BLANK_LINES_BASE = 2
OK_BUTTON_BR_OFFSET = (2,6)
OKBUTTON_TYPE = button.MiniButton
DEFAULT_X_OFFSET = 2
PRESERVE_SELECTED_WIDGET_DEFAULT = False # Preserve cursor location between displays?
FRAMED = True
def __init__(self, name=None, parentApp=None, framed=FRAMED, help=None, color='FORMDEFAULT',
widget_list=None, cycle_widgets=False, *args, **keywords):
super(_FormBase, self).__init__(*args, **keywords)
self.preserve_selected_widget = self.__class__.PRESERVE_SELECTED_WIDGET_DEFAULT
if parentApp:
try:
self.parentApp = weakref.proxy(parentApp)
except:
self.parentApp = parentApp
self.framed = framed
self.name=name
self.editing = False
## OLD MENU CODE REMOVED self.__menus = []
self._clear_all_widgets()
self.help = help
self.color = color
self.cycle_widgets = cycle_widgets
self.set_up_handlers()
self.set_up_exit_condition_handlers()
if hasattr(self, 'initialWidgets'):
self.create_widgets_from_list(self.__class__.initialWidgets)
if widget_list:
self.create_widgets_from_list(widget_list)
self.create()
def _clear_all_widgets(self, ):
self._widgets__ = []
self._widgets_by_id = {}
self._next_w_id = 0
self.nextrely = self.DEFAULT_NEXTRELY
self.nextrelx = self.DEFAULT_X_OFFSET
self.editw = 0 # Index of widget to edit.
def create_widgets_from_list(self, widget_list):
# This code is currently experimental, and the API may change in future releases
# (npyscreen.TextBox, {'rely': 2, 'relx': 7, 'editable': False})
for line in widget_list:
w_type = line[0]
keywords = line[1]
self.add_widget(w_type, **keywords)
def set_value(self, value):
self.value = value
for _w in self._widgets__:
if hasattr(_w, 'when_parent_changes_value'):
_w.when_parent_changes_value()
def create(self):
"""Programmers should over-ride this in derived classes, creating widgets here"""
pass
def set_up_handlers(self):
self.complex_handlers = []
self.handlers = {
curses.KEY_F1: self.h_display_help,
"KEY_F(1)": self.h_display_help,
"!h": self.h_display_help,
"^L": self.h_display,
#curses.KEY_RESIZE: self.h_display,
}
def set_up_exit_condition_handlers(self):
# What happens when widgets exit?
# each widget will set it's how_exited value: this should
# be used to look up the following table.
self.how_exited_handers = {
widget.EXITED_DOWN: self.find_next_editable,
widget.EXITED_RIGHT: self.find_next_editable,
widget.EXITED_UP: self.find_previous_editable,
widget.EXITED_LEFT: self.find_previous_editable,
widget.EXITED_ESCAPE: self.do_nothing,
True: self.find_next_editable, # A default value
widget.EXITED_MOUSE: self.get_and_use_mouse_event,
False: self.do_nothing,
}
def handle_exiting_widgets(self, condition):
self.how_exited_handers[condition]()
def do_nothing(self, *args, **keywords):
pass
def exit_editing(self, *args, **keywords):
self.editing = False
def adjust_widgets(self):
"""This method can be overloaded by derived classes. It is called when editing any widget, as opposed to
the while_editing() method, which may only be called when moving between widgets. Since it is called for
every keypress, and perhaps more, be careful when selecting what should be done here."""
def while_editing(self, *args, **keywords):
"""This function gets called during the edit loop, on each iteration
of the loop. It does nothing: it is here to make customising the loop
as easy as overriding this function. A proxy to the currently selected widget is
passed to the function."""
def on_screen(self):
# is the widget in editw on sreen at the moment?
# if not, alter screen so that it is.
w = weakref.proxy(self._widgets__[self.editw])
max_y, max_x = self._max_physical()
w_my, w_mx = w.calculate_area_needed()
# always try to show the top of the screen.
self.show_from_y = 0
self.show_from_x = 0
while w.rely + w_my -1 > self.show_from_y + max_y:
self.show_from_y += 1
while w.rely < self.show_from_y:
self.show_from_y -= 1
while w.relx + w_mx -1 > self.show_from_x + max_x:
self.show_from_x += 1
while w.relx < self.show_from_x:
self.show_from_x -= 1
## REMOVING OLD MENU CODE def menuOfMenus(self, *args, **keywords):
## REMOVING OLD MENU CODE """DEPRICATED"""
## REMOVING OLD MENU CODE tmpmnu = Menu.Menu(name = "All Menus", show_aty=2, show_atx=2)
## REMOVING OLD MENU CODE #tmpmnu.before_item_select = self.display
## REMOVING OLD MENU CODE for mnu in self.__menus:
## REMOVING OLD MENU CODE text = ""
## REMOVING OLD MENU CODE if mnu.name: text += mnu.name
## REMOVING OLD MENU CODE for keypress in self.handlers.keys():
## REMOVING OLD MENU CODE if self.handlers[keypress] == mnu.edit:
## REMOVING OLD MENU CODE if keypress: text += " (%s)" % keypress
## REMOVING OLD MENU CODE text += " >"
## REMOVING OLD MENU CODE tmpmnu.add_item(text, mnu.edit)
## REMOVING OLD MENU CODE tmpmnu.edit()
## REMOVING OLD MENU CODE
## REMOVING OLD MENU CODE def add_menu(self, menu=None, key=None, *args, **keywords):
## REMOVING OLD MENU CODE """DEPRICATED"""
## REMOVING OLD MENU CODE if menu is None:
## REMOVING OLD MENU CODE mu = Menu.Menu(*args, **keywords)
## REMOVING OLD MENU CODE self.__menus.append(mu)
## REMOVING OLD MENU CODE else:
## REMOVING OLD MENU CODE mu = menu
## REMOVING OLD MENU CODE self.__menus.append(mu)
## REMOVING OLD MENU CODE self.add_handlers({key: mu.edit})
## REMOVING OLD MENU CODE return weakref.proxy(mu)
def h_display_help(self, input):
if self.help == None: return
if self.name:
help_name="%s Help" %(self.name)
else: help_name=None
curses.flushinp()
select.ViewText(self.help, name=help_name)
self.display()
return True
def h_display(self, input):
self.curses_pad.redrawwin()
self.display()
def get_and_use_mouse_event(self):
curses.beep()
def find_next_editable(self, *args):
if not self.editw == len(self._widgets__):
if not self.cycle_widgets:
r = list(range(self.editw+1, len(self._widgets__)))
else:
r = list(range(self.editw+1, len(self._widgets__))) + list(range(0, self.editw))
for n in r:
if self._widgets__[n].editable and not self._widgets__[n].hidden:
self.editw = n
break
self.display()
def find_previous_editable(self, *args):
if not self.editw == 0:
# remember that xrange does not return the 'last' value,
# so go to -1, not 0! (fence post error in reverse)
for n in range(self.editw-1, -1, -1 ):
if self._widgets__[n].editable and not self._widgets__[n].hidden:
self.editw = n
break
#def widget_useable_space(self, rely=0, relx=0):
# #Slightly misreports space available.
# mxy, mxx = self.lines-1, self.columns-1
# return (mxy-1-rely, mxx-1-relx)
def center_on_display(self):
my, mx = self._max_physical()
if self.lines < my:
self.show_aty = (my - self.lines) // 2
else:
self.show_aty = 0
if self.columns < mx:
self.show_atx = (mx - self.columns) // 2
else:
self.show_atx = 0
def display(self, clear=False):
#APPLICATION_THEME_MANAGER.setTheme(self)
if curses.has_colors() and not npysGlobalOptions.DISABLE_ALL_COLORS:
color_attribute = self.theme_manager.findPair(self)
self.curses_pad.bkgdset(' ', color_attribute)
self.curses_pad.attron(color_attribute)
self.curses_pad.erase()
self.draw_form()
for w in self._widgets__:
if w.hidden:
w.clear()
else:
w.update(clear=clear)
self.refresh()
def draw_form(self):
if self.framed:
self.curses_pad.border()
try:
if self.name:
_title = self.name[:(self.columns-4)]
self.curses_pad.addstr(0,1, ' '+str(_title)+' ')
except:
pass
if self.help and self.editing:
try:
help_advert = " Help: F1 or M-h "
self.curses_pad.addstr(
0, self.curses_pad.getmaxyx()[1]-len(help_advert)-2, help_advert
)
except:
pass
def add_widget(self, widgetClass, w_id=None, max_height=None, rely=None, relx=None, *args, **keywords):
"""Add a widget to the form. The form will do its best to decide on placing, unless you override it.
The form of this function is add_widget(WidgetClass, ....) with any arguments or keywords supplied to
the widget. The wigdet will be added to self._widgets__
It is safe to use the return value of this function to keep hold of the widget, since that is a weak
reference proxy, but it is not safe to keep hold of self._widgets__"""
if rely is None:
rely = self.nextrely
if relx is None:
relx = self.nextrelx
if max_height is False:
max_height = self.curses_pad.getmaxyx()[0] - rely - 1
_w = widgetClass(self,
rely=rely,
relx=relx,
max_height=max_height,
*args, **keywords)
self.nextrely = _w.height + _w.rely
self._widgets__.append(_w)
w_proxy = weakref.proxy(_w)
if not w_id:
w_id = self._next_w_id
self._next_w_id += 1
self._widgets_by_id[w_id] = w_proxy
return w_proxy
def get_widget(self, w_id):
return self._widgets_by_id[w_id]
add = add_widget
class FormBaseNew(form_edit_loop.FormNewEditLoop, _FormBase):
# use the new-style edit loop.
pass
class Form(form_edit_loop.FormDefaultEditLoop, _FormBase, ):
#use the old-style edit loop
pass
class TitleForm(Form):
"""A form without a box, just a title line"""
BLANK_LINES_BASE = 1
DEFAULT_X_OFFSET = 1
DEFAULT_NEXTRELY = 1
BLANK_COLUMNS_RIGHT = 0
OK_BUTTON_BR_OFFSET = (1,6)
#OKBUTTON_TYPE = button.MiniButton
#DEFAULT_X_OFFSET = 1
def draw_form(self):
MAXY, MAXX = self.curses_pad.getmaxyx()
self.curses_pad.hline(0, 0, curses.ACS_HLINE, MAXX)
try:
if self.name:
self.curses_pad.addstr(0,1, ' '+str(self.name)+' ')
except:
pass
if self.help and self.editing:
try:
help_advert = " Help: F1 or M-h "
self.curses_pad.addstr(
0, self.curses_pad.MAXX-len(help_advert)-2, help_advert
)
except:
pass
class TitleFooterForm(TitleForm):
BLANK_LINES_BASE=1
def draw_form(self):
MAXY, MAXX = self.curses_pad.getmaxyx()
if self.editing:
self.curses_pad.hline(MAXY-1, 0, curses.ACS_HLINE,
MAXX - self.__class__.OK_BUTTON_BR_OFFSET[1] - 1)
else:
self.curses_pad.hline(MAXY-1, 0, curses.ACS_HLINE, MAXX-1)
super(TitleFooterForm, self).draw_form()
class SplitForm(Form):
"""Just the same as the Title Form, but with a horizontal line"""
def draw_form(self):
MAXY, MAXX = self.curses_pad.getmaxyx()
super(SplitForm, self).draw_form()
self.curses_pad.hline(MAXY//2-1, 1, curses.ACS_HLINE, MAXX-2)
def get_half_way(self):
return self.curses_pad.getmaxyx()[0] // 2

40
tools/npyscreen/fmFormMutt.py

@ -0,0 +1,40 @@
#/usr/bin/env python
import curses
from . import fmForm
from . import fmFormWithMenus
from . import wgtextbox
from . import wgmultiline
#import grid
#import editmultiline
class FormMutt(fmForm.FormBaseNew):
BLANK_LINES_BASE = 0
BLANK_COLUMNS_RIGHT = 0
DEFAULT_X_OFFSET = 2
FRAMED = False
MAIN_WIDGET_CLASS = wgmultiline.MultiLine
STATUS_WIDGET_CLASS = wgtextbox.Textfield
COMMAND_WIDGET_CLASS= wgtextbox.Textfield
#MAIN_WIDGET_CLASS = grid.SimpleGrid
#MAIN_WIDGET_CLASS = editmultiline.MultiLineEdit
def __init__(self, cycle_widgets = True, *args, **keywords):
super(FormMutt, self).__init__(cycle_widgets=cycle_widgets, *args, **keywords)
def draw_form(self):
MAXY, MAXX = self.lines, self.columns #self.curses_pad.getmaxyx()
self.curses_pad.hline(0, 0, curses.ACS_HLINE, MAXX-1)
self.curses_pad.hline(MAXY-2, 0, curses.ACS_HLINE, MAXX-1)
def create(self):
MAXY, MAXX = self.lines, self.columns
self.wStatus1 = self.add(self.__class__.STATUS_WIDGET_CLASS, rely=0, relx=0, editable=False, )
self.wMain = self.add(self.__class__.MAIN_WIDGET_CLASS, rely=1, relx=0, max_height = -2, )
self.wStatus2 = self.add(self.__class__.STATUS_WIDGET_CLASS, rely=MAXY-2, relx=0, editable=False, )
self.wCommand = self.add(self.__class__.COMMAND_WIDGET_CLASS, rely = MAXY-1, relx=0,)
self.wStatus1.important = True
self.wStatus2.important = True
self.nextrely = 2

66
tools/npyscreen/fmFormWithMenus.py

@ -0,0 +1,66 @@
#!/usr/bin/env python
# encoding: utf-8
from . import fmForm
from . import fmActionForm
from . import wgNMenuDisplay
class FormBaseNewWithMenus(fmForm.FormBaseNew, wgNMenuDisplay.HasMenus):
"""The FormBaseNew class, but with a handling system for menus as well. See the HasMenus class for details."""
def __init__(self, *args, **keywords):
super(FormBaseNewWithMenus, self).__init__(*args, **keywords)
self.initialize_menus()
def display_menu_advert_at(self):
return self.lines-1, 1
def draw_form(self):
super(FormBaseNewWithMenus, self).draw_form()
menu_advert = " " + self.__class__.MENU_KEY + ": Menu "
y, x = self.display_menu_advert_at()
self.curses_pad.addnstr(y, x, menu_advert, self.columns - x - 1)
class FormWithMenus(fmForm.Form, wgNMenuDisplay.HasMenus):
"""The Form class, but with a handling system for menus as well. See the HasMenus class for details."""
def __init__(self, *args, **keywords):
super(FormWithMenus, self).__init__(*args, **keywords)
self.initialize_menus()
def display_menu_advert_at(self):
return self.lines-1, 1
def draw_form(self):
super(FormWithMenus, self).draw_form()
menu_advert = " " + self.__class__.MENU_KEY + ": Menu "
y, x = self.display_menu_advert_at()
self.curses_pad.addnstr(y, x, menu_advert, self.columns - x - 1)
# The following class does not inherit from FormWithMenus and so some code is duplicated.
# The pig is getting to inherit edit() from ActionForm, but draw_form from FormWithMenus
class ActionFormWithMenus(fmActionForm.ActionForm, wgNMenuDisplay.HasMenus):
def __init__(self, *args, **keywords):
super(ActionFormWithMenus, self).__init__(*args, **keywords)
self.initialize_menus()
def display_menu_advert_at(self):
return self.lines-1, 1
def draw_form(self):
super(ActionFormWithMenus, self).draw_form()
menu_advert = " " + self.__class__.MENU_KEY + ": Menu "
y, x = self.display_menu_advert_at()
self.curses_pad.addnstr(y, x, menu_advert, self.columns - x - 1)
class SplitFormWithMenus(FormWithMenus):
"""Just the same as the Title Form, but with a horizontal line"""
def draw_form(self):
MAXY, MAXX = self.curses_pad.getmaxyx()
super(SplitFormWithMenus, self).draw_form()
self.curses_pad.hline(MAXY//2-1, 1, curses.ACS_HLINE, MAXX-2)
def get_half_way(self):
return self.curses_pad.getmaxyx()[0] // 2

31
tools/npyscreen/fmPopup.py

@ -0,0 +1,31 @@
#!/usr/bin/python
# encoding: utf-8
from . import fmForm
from . import fmActionForm
import curses
class Popup(fmForm.Form):
def __init__(self,
lines = 12,
columns=60,
minimum_lines=None,
minimum_columns=None,
*args, **keywords):
super(Popup, self).__init__(lines = lines, columns=columns,
*args, **keywords)
self.show_atx = 10
self.show_aty = 2
class ActionPopup(fmActionForm.ActionForm, Popup):
def __init__(self, *args, **keywords):
Popup.__init__(self, *args, **keywords)
class MessagePopup(Popup):
def __init__(self, *args, **keywords):
import multiline
super(MessagePopup, self).__init__(*args, **keywords)
self.TextWidget = self.add(multiline.Pager, scroll_exit=True, max_height=self.widget_useable_space()[0]-2)

100
tools/npyscreen/fm_form_edit_loop.py

@ -0,0 +1,100 @@
#!/usr/bin/env python
# encoding: utf-8
"""
form_edit_loop.py
Created by Nicholas Cole on 2008-03-31.
Copyright (c) 2008 __MyCompanyName__. All rights reserved.
"""
import sys
import os
import weakref
class FormNewEditLoop(object):
"Edit Fields .editing = False"
def pre_edit_loop(self):
pass
def post_edit_loop(self):
pass
def _during_edit_loop(self):
pass
def edit_loop(self):
self.editing = True
self.display()
while not self._widgets__[self.editw].editable:
self.editw += 1
if self.editw > len(self._widgets__)-1:
self.editing = False
return False
while self.editing:
if not self.ALL_SHOWN: self.on_screen()
self.while_editing(weakref.proxy(self._widgets__[self.editw]))
self._during_edit_loop()
if not self.editing:
break
self._widgets__[self.editw].edit()
self._widgets__[self.editw].display()
self.handle_exiting_widgets(self._widgets__[self.editw].how_exited)
if self.editw > len(self._widgets__)-1: self.editw = len(self._widgets__)-1
def edit(self):
self.pre_edit_loop()
self.edit_loop()
self.post_edit_loop()
class FormDefaultEditLoop(object):
def edit(self):
"""Edit the fields until the user selects the ok button added in the lower right corner. Button will
be removed when editing finishes"""
self.editing=True
if self.editw < 0: self.editw=0
if self.editw > len(self._widgets__)-1:
self.editw = len(self._widgets__)-1
if not self.preserve_selected_widget:
self.editw = 0
# Add ok button. Will remove later
tmp_rely, tmp_relx = self.nextrely, self.nextrelx
my, mx = self.curses_pad.getmaxyx()
ok_button_text = "OK"
my -= self.__class__.OK_BUTTON_BR_OFFSET[0]
mx -= len(ok_button_text)+self.__class__.OK_BUTTON_BR_OFFSET[1]
self.ok_button = self.add_widget(self.__class__.OKBUTTON_TYPE, name=ok_button_text, rely=my, relx=mx, use_max_space=True)
ok_button_postion = len(self._widgets__)-1
self.ok_button.update()
if not self._widgets__[self.editw].editable: self.find_next_editable()
self.display()
while not self._widgets__[self.editw].editable:
self.editw += 1
if self.editw > len(self._widgets__)-1:
self.editing = False
return False
while self.editing:
if not self.ALL_SHOWN: self.on_screen()
self.while_editing(weakref.proxy(self._widgets__[self.editw]))
if not self.editing:
break
self._widgets__[self.editw].edit()
self._widgets__[self.editw].display()
self.handle_exiting_widgets(self._widgets__[self.editw].how_exited)
if self.editw > len(self._widgets__)-1: self.editw = len(self._widgets__)-1
if self.ok_button.value:
self.editing = False
self.ok_button.destroy()
del self._widgets__[ok_button_postion]
del self.ok_button
self.nextrely, self.nextrelx = tmp_rely, tmp_relx
self.display()
self.editing = False
self.erase()

70
tools/npyscreen/muMenu.py

@ -0,0 +1,70 @@
#!/usr/bin/python
# encoding: utf-8
import sys
import os
from . import wgmultiline
from . import fmForm
import weakref
class Menu(object):
"This class is obsolete and Depricated. Use NewMenu instead."
def __init__(self, name=None, show_atx=None, show_aty=None):
self.__menu_items = []
self.name = name
self.__show_atx = show_atx
self.__show_aty = show_aty
def before_item_select(self):
pass
def add_item(self, text, func):
self.__menu_items.append((text, func))
def set_menu(self, pairs):
"""Pass in a list of pairs of text labels and functions"""
self.__menu_items = []
for pair in pairs:
self.add_item(pair[0], pair[1])
def edit(self, *args, **keywords):
"""Display choice to user, execute function associated"""
menu_text = [x[0] for x in self.__menu_items]
longest_text = 0
#Slightly different layout if we are showing a title
if self.name: longest_text=len(self.name)+2
for item in menu_text:
if len(item) > longest_text:
longest_text = len(item)
height = len(menu_text)
if self.name:
height +=3
else:
height +=2
if height > 14:
height = 13
atx = self.__show_atx or 20
aty = self.__show_aty or 2
popup = fmForm.Form(name=self.name,
lines=height, columns=longest_text+4,
show_aty=aty, show_atx=atx, )
if not self.name: popup.nextrely = 1
l = popup.add(wgmultiline.MultiLine,
values=menu_text,
#exit_left=True,
return_exit=True)
popup.display()
l.edit()
if l.value is not None:
self.before_item_select()
self.__menu_items[l.value][1]()

63
tools/npyscreen/muNewMenu.py

@ -0,0 +1,63 @@
#!/usr/bin/env python
# encoding: utf-8
import weakref
class NewMenu(object):
"""docstring for NewMenu"""
def __init__(self, name=None):
self.name = name
self._menuList = []
def addItemsFromList(self, item_list):
for l in item_list:
if isinstance(l, MenuItem):
self.addNewSubmenu(l)
else:
self.addItem(*l)
def addItem(self, *args, **keywords):
_itm = MenuItem(*args, **keywords)
self._menuList.append(_itm)
def addSubmenu(self, submenu):
"Not recommended. Use addNewSubmenu instead"
_itm = submenu
self._menuList.append(submenu)
def addNewSubmenu(self, *args, **keywords):
_mnu = NewMenu(*args, **keywords)
self._menuList.append(_mnu)
return weakref.proxy(_mnu)
def getItemObjects(self):
return self._menuList
class MenuItem(object):
"""docstring for MenuItem"""
def __init__(self, text='', onSelect=None, document=None):
self.setText(text)
self.setOnSelect(onSelect)
self.setDocumentation(document)
def setText(self, text):
self._text = text
def getText(self):
return self._text
def setOnSelect(self, onSelect):
self.onSelectFunction = onSelect
def setDocumentation(self, document):
self._help = document
def getDocumentation(self):
return self._help
def getHelp(self):
return self._help
def do(self):
return self.onSelectFunction()

2
tools/npyscreen/npysGlobalOptions.py

@ -0,0 +1,2 @@
DISABLE_ALL_COLORS = False
ASCII_ONLY = False

68
tools/npyscreen/npysNPSTree.py

@ -0,0 +1,68 @@
#!/usr/bin/env python
import weakref
class NPSTreeData(object):
def __init__(self, content=None, parent=None, selected=False, hilight=False, expanded=True):
self.setParent(parent)
self.setContent(content)
self.selected = selected
self.hilight = hilight
self.expanded = expanded
self._children = []
def getContent(self):
return self.content
def getContentForDisplay(self):
return str(self.content)
def setContent(self, content):
self.content = content
def isSelected(self):
return self.selected
def isHighlighted(self):
return self.hilight
def setParent(self, parent):
if parent == None:
self.parent = None
else:
self.parent = weakref.proxy(parent)
def findDepth(self, d=0):
if self.parent == None:
return d
else:
return(self.parent.findDepth(d+1))
def hasChildren(self):
if len(self._children) > 0:
return True
else:
return False
def getChildren(self):
return self._children
def newChild(self, *args, **keywords):
c = NPSTreeData(parent=self, *args, **keywords)
self._children.append(c)
return weakref.proxy(c)
def walkTree(self, onlyExpanded=True, ignoreRoot=True):
#Iterate over Tree
if not ignoreRoot:
yield self
if (not onlyExpanded) or (self.expanded):
for child in self.getChildren():
for node in child.walkTree(onlyExpanded=onlyExpanded, ignoreRoot=False):
yield node
def getTreeAsList(self, onlyExpanded=True):
_a = []
for node in self.walkTree(onlyExpanded=onlyExpanded):
_a.append(weakref.proxy(node))
return _a

91
tools/npyscreen/npysThemeManagers.py

@ -0,0 +1,91 @@
#!/usr/bin/env python
# encoding: utf-8
"""IMPORTANT - COLOUR SUPPORT IS CURRENTLY EXTREMELY EXPERIMENTAL. THE API MAY CHANGE, AND NO DEFAULT
WIDGETS CURRENTLY TAKE ADVANTAGE OF THEME SUPPORT AT ALL."""
import curses
from . import npysGlobalOptions
def disableColor():
npysGlobalOptions.DISABLE_ALL_COLORS = True
def enableColor():
npysGlobalOptions.DISABLE_ALL_COLORS = False
class ThemeManager(object):
_colors_to_define = (
('BLACK_WHITE', curses.COLOR_BLACK, curses.COLOR_WHITE),
('BLUE_BLACK', curses.COLOR_BLUE, curses.COLOR_BLACK),
('CYAN_BLACK', curses.COLOR_CYAN, curses.COLOR_BLACK),
('GREEN_BLACK', curses.COLOR_GREEN, curses.COLOR_BLACK),
('MAGENTA_BLACK', curses.COLOR_MAGENTA, curses.COLOR_BLACK),
('RED_BLACK', curses.COLOR_RED, curses.COLOR_BLACK),
('YELLOW_BLACK', curses.COLOR_YELLOW, curses.COLOR_BLACK),
('BLACK_RED', curses.COLOR_BLACK, curses.COLOR_RED),
)
default_colors = {
'DEFAULT' : 'WHITE_BLACK',
'FORMDEFAULT' : 'WHITE_BLACK',
'NO_EDIT' : 'BLUE_BLACK',
'STANDOUT' : 'CYAN_BLACK',
'LABEL' : 'GREEN_BLACK',
'LABELBOLD' : 'WHITE_BLACK',
'CONTROL' : 'YELLOW_BLACK',
'IMPORTANT' : 'GREEN_BLACK',
'SAFE' : 'GREEN_BLACK',
'WARNING' : 'YELLOW_BLACK',
'DANGER' : 'RED_BLACK',
'CRITICAL' : 'BLACK_RED',