Browse Source

reworked config script

new config script uses the very good urwid library.
works on non ncurses platforms like windows, too.
works with small screens
master
Daniel Poelzleithner 13 years ago
parent
commit
d6e436e92f
  1. 263
      tools/config.py
  2. 52
      tools/npyscreen/__init__.py
  3. 27
      tools/npyscreen/apNPSApplication.py
  4. 140
      tools/npyscreen/apNPSApplicationManaged.py
  5. 84
      tools/npyscreen/fmActionForm.py
  6. 366
      tools/npyscreen/fmForm.py
  7. 40
      tools/npyscreen/fmFormMutt.py
  8. 66
      tools/npyscreen/fmFormWithMenus.py
  9. 31
      tools/npyscreen/fmPopup.py
  10. 100
      tools/npyscreen/fm_form_edit_loop.py
  11. 70
      tools/npyscreen/muMenu.py
  12. 63
      tools/npyscreen/muNewMenu.py
  13. 2
      tools/npyscreen/npysGlobalOptions.py
  14. 68
      tools/npyscreen/npysNPSTree.py
  15. 91
      tools/npyscreen/npysThemeManagers.py
  16. 25
      tools/npyscreen/npysThemes.py
  17. 34
      tools/npyscreen/npyspmfuncs.py
  18. 106
      tools/npyscreen/npyssafewrapper.py
  19. 148
      tools/npyscreen/proto_fm_screen_area.py
  20. 58
      tools/npyscreen/wgFormControlCheckbox.py
  21. 138
      tools/npyscreen/wgNMenuDisplay.py
  22. 115
      tools/npyscreen/wgautocomplete.py
  23. 51
      tools/npyscreen/wgbutton.py
  24. 100
      tools/npyscreen/wgcheckbox.py
  25. 89
      tools/npyscreen/wgcombobox.py
  26. 88
      tools/npyscreen/wgdatecombo.py
  27. 270
      tools/npyscreen/wgeditmultiline.py
  28. 235
      tools/npyscreen/wggrid.py
  29. 45
      tools/npyscreen/wggridcoltitles.py
  30. 206
      tools/npyscreen/wgmonthbox.py
  31. 564
      tools/npyscreen/wgmultiline.py
  32. 114
      tools/npyscreen/wgmultilinetree.py
  33. 69
      tools/npyscreen/wgmultiselect.py
  34. 44
      tools/npyscreen/wgmultiselecttree.py
  35. 24
      tools/npyscreen/wgpassword.py
  36. 50
      tools/npyscreen/wgselectone.py
  37. 131
      tools/npyscreen/wgslider.py
  38. 301
      tools/npyscreen/wgtextbox.py
  39. 28
      tools/npyscreen/wgtextbox_controlchrs.py
  40. 121
      tools/npyscreen/wgtitlefield.py
  41. 401
      tools/npyscreen/wgwidget.py
  42. 63
      tools/urwid/__init__.py
  43. 1265
      tools/urwid/canvas.py
  44. 63
      tools/urwid/command_map.py
  45. 1366
      tools/urwid/container.py
  46. 658
      tools/urwid/curses_display.py
  47. 1092
      tools/urwid/decoration.py
  48. 813
      tools/urwid/display_common.py
  49. 404
      tools/urwid/escape.py
  50. 456
      tools/urwid/font.py
  51. 853
      tools/urwid/graphics.py
  52. 255
      tools/urwid/html_fragment.py
  53. 1350
      tools/urwid/listbox.py
  54. 926
      tools/urwid/main_loop.py
  55. 394
      tools/urwid/monitored_list.py
  56. 341
      tools/urwid/old_str_util.py
  57. 861
      tools/urwid/raw_display.py
  58. 134
      tools/urwid/signals.py
  59. 129
      tools/urwid/split_repr.py
  60. 491
      tools/urwid/text_layout.py
  61. 455
      tools/urwid/util.py
  62. 1085
      tools/urwid/web_display.py
  63. 1320
      tools/urwid/widget.py
  64. 534
      tools/urwid/wimp.py

263
tools/config.py

@ -1,9 +1,12 @@
#!/usr/bin/env python
# encoding: utf-8
import npyscreen
import urwid
import urwid.raw_display
import sys
import re, sys, random
#npyscreen.disableColor()
from sorteddict import SortedDict
# {0x79, 0x56, 0x34, 0x12}
@ -22,15 +25,18 @@ DATA["CONFIG_FREQUENCY"] = {
"depends": [],
"default": 902,
"type": "choices",
"values": [902, 869, 433]}
"values": [902, 869, 433],
"help": "Frequency for the clock"
}
DATA["OPTION_TIME_DISPLAY"] = {
"name": "Time display options",
"depends": [],
"default": 0,
"type": "choices",
"values": [0, 1, 2],
"help": "Select how time should be displayed, in order of code size options are- 0 = 24hr, 1=12hr (AM/PM) or 2=selectable"
"values": [(0, "24hr"), (1, "12hr (AM/PM)"), (2, "selectable")],
"help": "Select how time should be displayed, in order of code size options are- 0 = 24hr, 1=12hr (AM/PM) or 2=selectable"
}
DATA["CONFIG_METRIC_ONLY"] = {
@ -179,129 +185,163 @@ FOOTER = """
"""
#load_config()
#print DATA
#sys.exit(1)
import curses, weakref
def wrap(text, width):
"""
A word-wrap function that preserves existing line breaks
and most spaces in the text. Expects that existing line
breaks are posix newlines (\n).
"""
return reduce(lambda line, word, width=width: '%s%s%s' %
(line,
' \n'[(len(line)-line.rfind('\n')-1
+ len(word.split('\n',1)[0]
) >= width)],
word),
text.split(' ')
)
class ConfigForm(npyscreen.TitleForm):
BLANK_LINES_BASE = 0
BLANK_COLUMNS_RIGHT = 0
DEFAULT_X_OFFSET = 2
FRAMED = False
#MAIN_WIDGET_CLASS = wgmultiline.MultiLine
STATUS_WIDGET_CLASS = npyscreen.Textfield
COMMAND_WIDGET_CLASS= npyscreen.Textfield
#MAIN_WIDGET_CLASS = grid.SimpleGrid
#MAIN_WIDGET_CLASS = editmultiline.MultiLineEdit
def __init__(self, *args, **keywords):
super(ConfigForm, self).__init__(cycle_widgets=False, *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.wStatus1.value = "Config Chronos Firmware"
#self.wMain = self.add(npyscreen.SimpleGrid, rely=1, relx=0, max_height = -2, )
#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-6, relx=0, max_heigh=3, heigth=3, editable=False, )
self.wStatus2.value = ""
#self.wCommand = self.add(self.__class__.COMMAND_WIDGET_CLASS, rely = MAXY-1, relx=0,)
self.wStatus1.important = True
self.wStatus2.important = False
self.nextrely = 2
def set_help(self):
if hasattr(self._widgets__[self.editw], "_datafield") and \
"help" in self._widgets__[self.editw]._datafield:
#print wrap(self._widgets__[self.editw]._datafield["help"], self.columns-40)
val = wrap(self._widgets__[self.editw]._datafield["help"], self.columns-5)+"\n\n\n"
# debugging functions
#FP = open("/tmp/log", "w")
#def flog(*args):
# FP.write(repr(args))
# FP.write("\n")
class HelpListWalker(urwid.SimpleListWalker):
def __init__(self, app, *args, **kwargs):
self.app = app
super(HelpListWalker, self).__init__(*args, **kwargs)
def set_focus(self, focus):
if hasattr(self[focus], "_datafield") and \
"help" in self[focus]._datafield:
self.app.help_widget.set_text(self[focus]._datafield["help"])
else:
val = ""
self.wStatus2.value = val + "\n"*(2-val.count("\n"))
self.wStatus2.display()
self.app.help_widget.set_text("")
return super(HelpListWalker, self).set_focus(focus)
def while_editing(self, *args, **kwargs):
self.set_help()
super(ConfigForm, self).while_editing(*args, **kwargs)
class HelpGridFlow(urwid.GridFlow):
def __init__(self, app, *args, **kwargs):
self.app = app
super(HelpGridFlow, self).__init__(*args, **kwargs)
class OpenChronosApp(npyscreen.NPSApp):
def set_focus(self, focus):
if hasattr(focus, "_datafield") and \
"help" in focus._datafield:
self.app.help_widget.set_text(focus._datafield["help"])
else:
self.app.help_widget.set_text("")
return super(HelpGridFlow, self).set_focus(focus)
class OpenChronosApp(object):
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 = ConfigForm(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:",)
text_header = (u"OpenChronos config \u2503 "
u"UP / DOWN / PAGE UP / PAGE DOWN scroll. F8 aborts.")
self.list_content = list_content = []
for key,field in DATA.iteritems():
# generate gui forms depending on type
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 = urwid.AttrWrap(urwid.CheckBox(field["name"], state=field["value"]),'buttn','buttnf')
f._datafield = field
self.fields[key] = f
list_content.append(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=field["name"],
values = field["values"], scroll_exit=True)
value = field["default"]
field["radio_button_group"] = []
f = urwid.Text(field["name"])
f._datafield = field
choice_items = [f]
for dat in field["values"]:
txt = value = dat
if isinstance(dat, tuple):
value, txt = dat
f = urwid.AttrWrap(urwid.RadioButton(field["radio_button_group"],
unicode(txt), state=value==field["value"]), 'buttn','buttnf')
f._datafield = field
f.value = value
choice_items.append(f)
hgf = HelpGridFlow(self, choice_items, 20, 3, 1, 'left')
self.fields[key] = choice_items
hgf.focus_cell = hgf.cells[1]
list_content.append(hgf)
elif field["type"] == "text":
f = F.add(npyscreen.TitleText, max_height=1, value=field["value"], name=field["name"],
values = field["value"])
elif field["type"] == "info":
f = F.add(npyscreen.TitleText, max_height=1, name=field["name"])
f._key = key
f._datafield = field
self.fields[key] = f
f = urwid.AttrWrap(urwid.Edit("%s: "%field["name"], field["value"]),
'editbx', 'editfc')
f._datafield = field
self.fields[key] = f
list_content.append(f)
elif field["type"] == "info":
f = urwid.Text(field["name"])
f._datafield = field
self.fields[key] = f
list_content.append(f)
def ok_pressed(*args, **kwargs):
raise urwid.ExitMainLoop()
def abort_pressed(*args, **kwargs):
sys.exit(0)
list_content.append(urwid.Divider(div_char=u"\u2550", top=1, bottom=1))
list_content.append(
urwid.Padding(urwid.GridFlow(
[urwid.AttrWrap(urwid.Button("Save", ok_pressed), 'buttn','buttnf'),
urwid.AttrWrap(urwid.Button("Abort", abort_pressed), 'buttn','buttnf')],
15, 4, 4, 'center'),
('fixed left',4), ('fixed right',3)))
header = urwid.AttrWrap(urwid.Text(text_header), 'header')
#header = urwid.Padding(urwid.BigText("OpenChronos", urwid.HalfBlock5x4Font()))
walker = HelpListWalker(self, list_content)
listbox = urwid.ListBox(walker)
self.help_widget = urwid.Text("")
footer = urwid.AttrWrap(self.help_widget, 'footer')
frame = urwid.Frame(urwid.AttrWrap(listbox, 'body'), header=header, footer=footer)
screen = urwid.raw_display.Screen()
palette = [
('body','black','light gray', 'standout'),
('reverse','light gray','black'),
('header','white','dark red', 'bold'),
('important','dark blue','light gray',('standout','underline')),
('editfc','white', 'dark blue', 'bold'),
('editbx','light gray', 'dark blue'),
('editcp','black','light gray', 'standout'),
('bright','dark gray','light gray', ('bold','standout')),
('buttn','black','dark cyan'),
('buttnf','white','dark blue','bold'),
]
def unhandled(key):
if key == 'f8':
#raise urwid.ExitMainLoop()
sys.exit(0)
urwid.MainLoop(frame, palette, screen,
unhandled_input=unhandled).run()
# This lets the user play with the Form.
F.edit()
def save_config(self):
print "save"
for key,field in self.fields.iteritems():
value = field.value
if hasattr(field, "values"):
value = field.values[value[0]]
DATA[key]["value"] = value
print key, field
if isinstance(field, (tuple, list)):
for item in field:
if hasattr(item, "get_state"):
print item.get_state()
if item.get_state():
# found the set radio button
DATA[key]["value"] = item.value
# look up the
elif isinstance(field, urwid.Text):
pass
elif isinstance(field, urwid.AttrMap):
wid = field.original_widget
if isinstance(wid, urwid.Edit):
DATA[key]["value"] = wid.get_edit_text()
else:
DATA[key]["value"] = wid.get_state()
else:
raise ValueError, "Unhandled type"
fp = open("config.h", "w")
fp.write("// !!!! DO NOT EDIT !!!, use: make config\n")
@ -357,14 +397,11 @@ class OpenChronosApp(npyscreen.NPSApp):
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.main()
App.save_config()

52
tools/npyscreen/__init__.py

@ -1,52 +0,0 @@
#!/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

@ -1,27 +0,0 @@
#!/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

@ -1,140 +0,0 @@
#!/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

@ -1,84 +0,0 @@
#!/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

@ -1,366 +0,0 @@
#!/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

@ -1,40 +0,0 @@
#/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

@ -1,66 +0,0 @@
#!/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

@ -1,31 +0,0 @@
#!/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

@ -1,100 +0,0 @@
#!/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

@ -1,70 +0,0 @@
#!/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<