summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2012-06-18 00:18:13 +0000
committerIgor Pashev <pashev.igor@gmail.com>2012-06-18 00:18:13 +0000
commit70a2e7a5b5d28e6433060aede2b7c8bea3b407c0 (patch)
tree0fad3d0252e5d39fd3e840cefe9a7c91343fbecb
parentb4dd752476e86a4b7649e500c9171b21160e9d8d (diff)
downloadlive-70a2e7a5b5d28e6433060aede2b7c8bea3b407c0.tar.gz
Common dialogs
-rw-r--r--lib/__init__.py0
-rw-r--r--lib/dialog/__init__.py343
2 files changed, 343 insertions, 0 deletions
diff --git a/lib/__init__.py b/lib/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/__init__.py
diff --git a/lib/dialog/__init__.py b/lib/dialog/__init__.py
new file mode 100644
index 0000000..b5868c1
--- /dev/null
+++ b/lib/dialog/__init__.py
@@ -0,0 +1,343 @@
+#!/usr/bin/python
+#
+# Urwid example similar to dialog(1) program
+# Copyright (C) 2004-2009 Ian Ward
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# Urwid web site: http://excess.org/urwid/
+
+"""
+Urwid example similar to dialog(1) program
+
+"""
+
+import sys
+
+import urwid
+
+
+class DialogExit(Exception):
+ pass
+
+
+class DialogDisplay:
+ palette = [
+ ('body','black','light gray', 'standout'),
+ ('border','black','dark blue'),
+ ('shadow','white','black'),
+ ('selectable','black', 'dark cyan'),
+ ('focus','white','dark blue','bold'),
+ ('focustext','light gray','dark blue'),
+ ]
+
+ def __init__(self, text, height, width, body=None):
+ width = int(width)
+ if width <= 0:
+ width = ('relative', 80)
+ height = int(height)
+ if height <= 0:
+ height = ('relative', 80)
+
+ self.body = body
+ if body is None:
+ # fill space with nothing
+ body = urwid.Filler(urwid.Divider(),'top')
+
+ self.frame = urwid.Frame( body, focus_part='footer')
+ if text is not None:
+ self.frame.header = urwid.Pile( [urwid.Text(text),
+ urwid.Divider()] )
+ w = self.frame
+
+ # pad area around listbox
+ w = urwid.Padding(w, ('fixed left',2), ('fixed right',2))
+ w = urwid.Filler(w, ('fixed top',1), ('fixed bottom',1))
+ w = urwid.AttrWrap(w, 'body')
+
+ # "shadow" effect
+ w = urwid.Columns( [w,('fixed', 2, urwid.AttrWrap(
+ urwid.Filler(urwid.Text(('border',' ')), "top")
+ ,'shadow'))])
+ w = urwid.Frame( w, footer =
+ urwid.AttrWrap(urwid.Text(('border',' ')),'shadow'))
+
+ # outermost border area
+ w = urwid.Padding(w, 'center', width )
+ w = urwid.Filler(w, 'middle', height )
+ w = urwid.AttrWrap( w, 'border' )
+
+ self.view = w
+
+
+ def add_buttons(self, buttons):
+ l = []
+ for name, exitcode in buttons:
+ b = urwid.Button( name, self.button_press )
+ b.exitcode = exitcode
+ b = urwid.AttrWrap( b, 'selectable','focus' )
+ l.append( b )
+ self.buttons = urwid.GridFlow(l, 10, 3, 1, 'center')
+ self.frame.footer = urwid.Pile( [ urwid.Divider(),
+ self.buttons ], focus_item = 1)
+
+ def button_press(self, button):
+ raise DialogExit(button.exitcode)
+
+ def main(self):
+ self.loop = urwid.MainLoop(self.view, self.palette)
+ try:
+ self.loop.run()
+ except DialogExit as e:
+ return self.on_exit( e.args[0] )
+
+ def on_exit(self, exitcode):
+ return exitcode, ""
+
+
+
+class InputDialogDisplay(DialogDisplay):
+ def __init__(self, text, height, width):
+ self.edit = urwid.Edit()
+ body = urwid.ListBox([self.edit])
+ body = urwid.AttrWrap(body, 'selectable','focustext')
+
+ DialogDisplay.__init__(self, text, height, width, body)
+
+ self.frame.set_focus('body')
+
+ def unhandled_key(self, size, k):
+ if k in ('up','page up'):
+ self.frame.set_focus('body')
+ if k in ('down','page down'):
+ self.frame.set_focus('footer')
+ if k == 'enter':
+ # pass enter to the "ok" button
+ self.frame.set_focus('footer')
+ self.view.keypress( size, k )
+
+ def on_exit(self, exitcode):
+ return exitcode, self.edit.get_edit_text()
+
+
+class TextDialogDisplay(DialogDisplay):
+ def __init__(self, file, height, width):
+ l = []
+ # read the whole file (being slow, not lazy this time)
+ for line in open(file).readlines():
+ l.append( urwid.Text( line.rstrip() ))
+ body = urwid.ListBox(l)
+ body = urwid.AttrWrap(body, 'selectable','focustext')
+
+ DialogDisplay.__init__(self, None, height, width, body)
+
+
+ def unhandled_key(self, size, k):
+ if k in ('up','page up','down','page down'):
+ self.frame.set_focus('body')
+ self.view.keypress( size, k )
+ self.frame.set_focus('footer')
+
+
+class ListDialogDisplay(DialogDisplay):
+ def __init__(self, text, height, width, constr, items, has_default):
+ j = []
+ if has_default:
+ k, tail = 3, ()
+ else:
+ k, tail = 2, ("no",)
+ while items:
+ j.append( items[:k] + tail )
+ items = items[k:]
+
+ l = []
+ self.items = []
+ for tag, item, default in j:
+ w = constr( tag, default=="on" )
+ self.items.append(w)
+ w = urwid.Columns( [('fixed', 12, w),
+ urwid.Text(item)], 2 )
+ w = urwid.AttrWrap(w, 'selectable','focus')
+ l.append(w)
+
+ lb = urwid.ListBox(l)
+ lb = urwid.AttrWrap( lb, "selectable" )
+ DialogDisplay.__init__(self, text, height, width, lb )
+
+ self.frame.set_focus('body')
+
+ def unhandled_key(self, size, k):
+ if k in ('up','page up'):
+ self.frame.set_focus('body')
+ if k in ('down','page down'):
+ self.frame.set_focus('footer')
+ if k == 'enter':
+ # pass enter to the "ok" button
+ self.frame.set_focus('footer')
+ self.buttons.set_focus(0)
+ self.view.keypress( size, k )
+
+ def on_exit(self, exitcode):
+ """Print the tag of the item selected."""
+ if exitcode != 0:
+ return exitcode, ""
+ s = ""
+ for i in self.items:
+ if i.get_state():
+ s = i.get_label()
+ break
+ return exitcode, s
+
+
+
+
+class CheckListDialogDisplay(ListDialogDisplay):
+ def on_exit(self, exitcode):
+ """
+ Mimick dialog(1)'s --checklist exit.
+ Put each checked item in double quotes with a trailing space.
+ """
+ if exitcode != 0:
+ return exitcode, ""
+ l = []
+ for i in self.items:
+ if i.get_state():
+ l.append(i.get_label())
+ return exitcode, "".join(['"'+tag+'" ' for tag in l])
+
+
+
+
+class MenuItem(urwid.Text):
+ """A custom widget for the --menu option"""
+ def __init__(self, label):
+ urwid.Text.__init__(self, label)
+ self.state = False
+ def selectable(self):
+ return True
+ def keypress(self,size,key):
+ if key == "enter":
+ self.state = True
+ raise DialogExit(0)
+ return key
+ def mouse_event(self,size,event,button,col,row,focus):
+ if event=='mouse release':
+ self.state = True
+ raise DialogExit(0)
+ return False
+ def get_state(self):
+ return self.state
+ def get_label(self):
+ text, attr = self.get_text()
+ return text
+
+
+def do_checklist(text, height, width, list_height, *items):
+ def constr(tag, state):
+ return urwid.CheckBox(tag, state)
+ d = CheckListDialogDisplay( text, height, width, constr, items, True)
+ d.add_buttons([ ("OK", 0), ("Cancel", 1) ])
+ return d
+
+def do_inputbox(text, height, width):
+ d = InputDialogDisplay( text, height, width )
+ d.add_buttons([ ("Exit", 0) ])
+ return d
+
+def do_menu(text, height, width, menu_height, *items):
+ def constr(tag, state ):
+ return MenuItem(tag)
+ d = ListDialogDisplay(text, height, width, constr, items, False)
+ d.add_buttons([ ("OK", 0), ("Cancel", 1) ])
+ return d
+
+def do_msgbox(text, height, width):
+ d = DialogDisplay( text, height, width )
+ d.add_buttons([ ("OK", 0) ])
+ return d
+
+def do_radiolist(text, height, width, list_height, *items):
+ radiolist = []
+ def constr(tag, state, radiolist=radiolist):
+ return urwid.RadioButton(radiolist, tag, state)
+ d = ListDialogDisplay( text, height, width, constr, items, True )
+ d.add_buttons([ ("OK", 0), ("Cancel", 1) ])
+ return d
+
+def do_textbox(file, height, width):
+ d = TextDialogDisplay( file, height, width )
+ d.add_buttons([ ("Exit", 0) ])
+ return d
+
+def do_yesno(text, height, width):
+ d = DialogDisplay( text, height, width )
+ d.add_buttons([ ("Yes", 0), ("No", 1) ])
+ return d
+
+MODES={ '--checklist': (do_checklist,
+ "text height width list-height [ tag item status ] ..."),
+ '--inputbox': (do_inputbox,
+ "text height width"),
+ '--menu': (do_menu,
+ "text height width menu-height [ tag item ] ..."),
+ '--msgbox': (do_msgbox,
+ "text height width"),
+ '--radiolist': (do_radiolist,
+ "text height width list-height [ tag item status ] ..."),
+ '--textbox': (do_textbox,
+ "file height width"),
+ '--yesno': (do_yesno,
+ "text height width"),
+ }
+
+
+def show_usage():
+ """
+ Display a helpful usage message.
+ """
+ modelist = [(mode, help) for (mode, (fn, help)) in MODES.items()]
+ modelist.sort()
+ sys.stdout.write(
+ __doc__ +
+ "\n".join(["%-15s %s"%(mode,help) for (mode,help) in modelist])
+ + """
+
+height and width may be set to 0 to auto-size.
+list-height and menu-height are currently ignored.
+status may be either on or off.
+""" )
+
+
+def main():
+ if len(sys.argv) < 2 or not MODES.has_key(sys.argv[1]):
+ show_usage()
+ return
+
+ # Create a DialogDisplay instance
+ fn, help = MODES[sys.argv[1]]
+ d = fn( * sys.argv[2:] )
+
+ # Run it
+ exitcode, exitstring = d.main()
+
+ # Exit
+ if exitstring:
+ sys.stderr.write(exitstring+"\n")
+
+ sys.exit(exitcode)
+
+
+if __name__=="__main__":
+ main()