Fixing sizing of
[watersofshiloah] / src / hildonize.py
1 #!/usr/bin/env python
2
3 """
4 Open Issues
5         @bug not all of a message is shown
6         @bug Buttons are too small
7 """
8
9
10 import gobject
11 import gtk
12 import dbus
13
14
15 class _NullHildonModule(object):
16         pass
17
18
19 try:
20         import hildon as _hildon
21         hildon  = _hildon # Dumb but gets around pyflakiness
22 except (ImportError, OSError):
23         hildon = _NullHildonModule
24
25
26 IS_HILDON_SUPPORTED = hildon is not _NullHildonModule
27
28
29 class _NullHildonProgram(object):
30
31         def add_window(self, window):
32                 pass
33
34
35 def _hildon_get_app_class():
36         return hildon.Program
37
38
39 def _null_get_app_class():
40         return _NullHildonProgram
41
42
43 try:
44         hildon.Program
45         get_app_class = _hildon_get_app_class
46 except AttributeError:
47         get_app_class = _null_get_app_class
48
49
50 def _hildon_set_application_title(title):
51         gtk.set_application_name(title)
52
53
54 def _null_set_application_title(title):
55         pass
56
57
58 if IS_HILDON_SUPPORTED:
59         set_application_title = _hildon_set_application_title
60 else:
61         set_application_title = _null_set_application_title
62
63
64 def _fremantle_hildonize_window(app, window):
65         oldWindow = window
66         newWindow = hildon.StackableWindow()
67         oldWindow.get_child().reparent(newWindow)
68         app.add_window(newWindow)
69         return newWindow
70
71
72 def _hildon_hildonize_window(app, window):
73         oldWindow = window
74         newWindow = hildon.Window()
75         oldWindow.get_child().reparent(newWindow)
76         app.add_window(newWindow)
77         return newWindow
78
79
80 def _null_hildonize_window(app, window):
81         return window
82
83
84 try:
85         hildon.StackableWindow
86         hildonize_window = _fremantle_hildonize_window
87 except AttributeError:
88         try:
89                 hildon.Window
90                 hildonize_window = _hildon_hildonize_window
91         except AttributeError:
92                 hildonize_window = _null_hildonize_window
93
94
95 def _fremantle_hildonize_menu(window, gtkMenu):
96         appMenu = hildon.AppMenu()
97         window.set_app_menu(appMenu)
98         gtkMenu.get_parent().remove(gtkMenu)
99         return appMenu
100
101
102 def _hildon_hildonize_menu(window, gtkMenu):
103         hildonMenu = gtk.Menu()
104         for child in gtkMenu.get_children():
105                 child.reparent(hildonMenu)
106         window.set_menu(hildonMenu)
107         gtkMenu.destroy()
108         return hildonMenu
109
110
111 def _null_hildonize_menu(window, gtkMenu):
112         return gtkMenu
113
114
115 try:
116         hildon.AppMenu
117         GTK_MENU_USED = False
118         IS_FREMANTLE_SUPPORTED = True
119         hildonize_menu = _fremantle_hildonize_menu
120 except AttributeError:
121         GTK_MENU_USED = True
122         IS_FREMANTLE_SUPPORTED = False
123         if IS_HILDON_SUPPORTED:
124                 hildonize_menu = _hildon_hildonize_menu
125         else:
126                 hildonize_menu = _null_hildonize_menu
127
128
129 def _hildon_set_button_auto_selectable(button):
130         button.set_theme_size(hildon.HILDON_SIZE_AUTO_HEIGHT)
131
132
133 def _null_set_button_auto_selectable(button):
134         pass
135
136
137 try:
138         hildon.HILDON_SIZE_AUTO_HEIGHT
139         gtk.Button.set_theme_size
140         set_button_auto_selectable = _hildon_set_button_auto_selectable
141 except AttributeError:
142         set_button_auto_selectable = _null_set_button_auto_selectable
143
144
145 def _hildon_set_button_finger_selectable(button):
146         button.set_theme_size(hildon.HILDON_SIZE_FINGER_HEIGHT)
147
148
149 def _null_set_button_finger_selectable(button):
150         pass
151
152
153 try:
154         hildon.HILDON_SIZE_FINGER_HEIGHT
155         gtk.Button.set_theme_size
156         set_button_finger_selectable = _hildon_set_button_finger_selectable
157 except AttributeError:
158         set_button_finger_selectable = _null_set_button_finger_selectable
159
160
161 def _hildon_set_button_thumb_selectable(button):
162         button.set_theme_size(hildon.HILDON_SIZE_THUMB_HEIGHT)
163
164
165 def _null_set_button_thumb_selectable(button):
166         pass
167
168
169 try:
170         hildon.HILDON_SIZE_THUMB_HEIGHT
171         gtk.Button.set_theme_size
172         set_button_thumb_selectable = _hildon_set_button_thumb_selectable
173 except AttributeError:
174         set_button_thumb_selectable = _null_set_button_thumb_selectable
175
176
177 def _hildon_set_cell_thumb_selectable(renderer):
178         renderer.set_property("scale", 1.5)
179
180
181 def _null_set_cell_thumb_selectable(renderer):
182         renderer.set_property("scale", 1.5)
183
184
185 if IS_HILDON_SUPPORTED:
186         set_cell_thumb_selectable = _hildon_set_cell_thumb_selectable
187 else:
188         set_cell_thumb_selectable = _null_set_cell_thumb_selectable
189
190
191 def _hildon_set_pix_cell_thumb_selectable(renderer):
192         renderer.set_property("stock-size", 48)
193
194
195 def _null_set_pix_cell_thumb_selectable(renderer):
196         pass
197
198
199 if IS_HILDON_SUPPORTED:
200         set_pix_cell_thumb_selectable = _hildon_set_pix_cell_thumb_selectable
201 else:
202         set_pix_cell_thumb_selectable = _null_set_pix_cell_thumb_selectable
203
204
205 def _fremantle_show_information_banner(parent, message):
206         hildon.hildon_banner_show_information(parent, "", message)
207
208
209 def _hildon_show_information_banner(parent, message):
210         hildon.hildon_banner_show_information(parent, None, message)
211
212
213 def _null_show_information_banner(parent, message):
214         pass
215
216
217 if IS_FREMANTLE_SUPPORTED:
218         show_information_banner = _fremantle_show_information_banner
219 else:
220         try:
221                 hildon.hildon_banner_show_information
222                 show_information_banner = _hildon_show_information_banner
223         except AttributeError:
224                 show_information_banner = _null_show_information_banner
225
226
227 def _fremantle_show_busy_banner_start(parent, message):
228         hildon.hildon_gtk_window_set_progress_indicator(parent, True)
229         return parent
230
231
232 def _fremantle_show_busy_banner_end(banner):
233         hildon.hildon_gtk_window_set_progress_indicator(banner, False)
234
235
236 def _hildon_show_busy_banner_start(parent, message):
237         return hildon.hildon_banner_show_animation(parent, None, message)
238
239
240 def _hildon_show_busy_banner_end(banner):
241         banner.destroy()
242
243
244 def _null_show_busy_banner_start(parent, message):
245         return None
246
247
248 def _null_show_busy_banner_end(banner):
249         assert banner is None
250
251
252 try:
253         hildon.hildon_gtk_window_set_progress_indicator
254         show_busy_banner_start = _fremantle_show_busy_banner_start
255         show_busy_banner_end = _fremantle_show_busy_banner_end
256 except AttributeError:
257         try:
258                 hildon.hildon_banner_show_animation
259                 show_busy_banner_start = _hildon_show_busy_banner_start
260                 show_busy_banner_end = _hildon_show_busy_banner_end
261         except AttributeError:
262                 show_busy_banner_start = _null_show_busy_banner_start
263                 show_busy_banner_end = _null_show_busy_banner_end
264
265
266 def _hildon_hildonize_text_entry(textEntry):
267         textEntry.set_property('hildon-input-mode', 7)
268
269
270 def _null_hildonize_text_entry(textEntry):
271         pass
272
273
274 if IS_HILDON_SUPPORTED:
275         hildonize_text_entry = _hildon_hildonize_text_entry
276 else:
277         hildonize_text_entry = _null_hildonize_text_entry
278
279
280 def _hildon_window_to_portrait(window):
281         # gtk documentation is unclear whether this does a "=" or a "|="
282         flags = hildon.PORTRAIT_MODE_SUPPORT | hildon.PORTRAIT_MODE_REQUEST
283         hildon.hildon_gtk_window_set_portrait_flags(window, flags)
284
285
286 def _hildon_window_to_landscape(window):
287         # gtk documentation is unclear whether this does a "=" or a "&= ~"
288         flags = hildon.PORTRAIT_MODE_SUPPORT
289         hildon.hildon_gtk_window_set_portrait_flags(window, flags)
290
291
292 def _null_window_to_portrait(window):
293         pass
294
295
296 def _null_window_to_landscape(window):
297         pass
298
299
300 try:
301         hildon.PORTRAIT_MODE_SUPPORT
302         hildon.PORTRAIT_MODE_REQUEST
303         hildon.hildon_gtk_window_set_portrait_flags
304
305         window_to_portrait = _hildon_window_to_portrait
306         window_to_landscape = _hildon_window_to_landscape
307 except AttributeError:
308         window_to_portrait = _null_window_to_portrait
309         window_to_landscape = _null_window_to_landscape
310
311
312 def get_device_orientation():
313         bus = dbus.SystemBus()
314         try:
315                 rawMceRequest = bus.get_object("com.nokia.mce", "/com/nokia/mce/request")
316                 mceRequest = dbus.Interface(rawMceRequest, dbus_interface="com.nokia.mce.request")
317                 orientation, standState, faceState, xAxis, yAxis, zAxis = mceRequest.get_device_orientation()
318         except dbus.exception.DBusException:
319                 # catching for documentation purposes that when a system doesn't
320                 # support this, this is what to expect
321                 raise
322
323         if orientation == "":
324                 return gtk.ORIENTATION_HORIZONTAL
325         elif orientation == "":
326                 return gtk.ORIENTATION_VERTICAL
327         else:
328                 raise RuntimeError("Unknown orientation: %s" % orientation)
329
330
331 def _hildon_hildonize_password_entry(textEntry):
332         textEntry.set_property('hildon-input-mode', 7 | (1 << 29))
333
334
335 def _null_hildonize_password_entry(textEntry):
336         pass
337
338
339 if IS_HILDON_SUPPORTED:
340         hildonize_password_entry = _hildon_hildonize_password_entry
341 else:
342         hildonize_password_entry = _null_hildonize_password_entry
343
344
345 def _hildon_hildonize_combo_entry(comboEntry):
346         comboEntry.set_property('hildon-input-mode', 1 << 4)
347
348
349 def _null_hildonize_combo_entry(textEntry):
350         pass
351
352
353 if IS_HILDON_SUPPORTED:
354         hildonize_combo_entry = _hildon_hildonize_combo_entry
355 else:
356         hildonize_combo_entry = _null_hildonize_combo_entry
357
358
359 def _null_create_seekbar():
360         adjustment = gtk.Adjustment(0, 0, 101, 1, 5, 1)
361         seek = gtk.HScale(adjustment)
362         seek.set_draw_value(False)
363         return seek
364
365
366 def _fremantle_create_seekbar():
367         seek = hildon.Seekbar()
368         seek.set_range(0.0, 100)
369         seek.set_draw_value(False)
370         seek.set_update_policy(gtk.UPDATE_DISCONTINUOUS)
371         return seek
372
373
374 try:
375         hildon.Seekbar
376         create_seekbar = _fremantle_create_seekbar
377 except AttributeError:
378         create_seekbar = _null_create_seekbar
379
380
381 def _fremantle_hildonize_scrollwindow(scrolledWindow):
382         pannableWindow = hildon.PannableArea()
383
384         child = scrolledWindow.get_child()
385         scrolledWindow.remove(child)
386         pannableWindow.add(child)
387
388         parent = scrolledWindow.get_parent()
389         if parent is not None:
390                 parent.remove(scrolledWindow)
391                 parent.add(pannableWindow)
392
393         return pannableWindow
394
395
396 def _hildon_hildonize_scrollwindow(scrolledWindow):
397         hildon.hildon_helper_set_thumb_scrollbar(scrolledWindow, True)
398         return scrolledWindow
399
400
401 def _null_hildonize_scrollwindow(scrolledWindow):
402         return scrolledWindow
403
404
405 try:
406         hildon.PannableArea
407         hildonize_scrollwindow = _fremantle_hildonize_scrollwindow
408         hildonize_scrollwindow_with_viewport = _hildon_hildonize_scrollwindow
409 except AttributeError:
410         try:
411                 hildon.hildon_helper_set_thumb_scrollbar
412                 hildonize_scrollwindow = _hildon_hildonize_scrollwindow
413                 hildonize_scrollwindow_with_viewport = _hildon_hildonize_scrollwindow
414         except AttributeError:
415                 hildonize_scrollwindow = _null_hildonize_scrollwindow
416                 hildonize_scrollwindow_with_viewport = _null_hildonize_scrollwindow
417
418
419 def _hildon_request_number(parent, title, range, default):
420         spinner = hildon.NumberEditor(*range)
421         spinner.set_value(default)
422
423         dialog = gtk.Dialog(
424                 title,
425                 parent,
426                 gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
427                 (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
428         )
429         dialog.set_default_response(gtk.RESPONSE_CANCEL)
430         dialog.get_child().add(spinner)
431
432         try:
433                 dialog.show_all()
434                 response = dialog.run()
435
436                 if response == gtk.RESPONSE_OK:
437                         return spinner.get_value()
438                 elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
439                         raise RuntimeError("User cancelled request")
440                 else:
441                         raise RuntimeError("Unrecognized response %r", response)
442         finally:
443                 dialog.hide()
444                 dialog.destroy()
445
446
447 def _null_request_number(parent, title, range, default):
448         adjustment = gtk.Adjustment(default, range[0], range[1], 1, 5, 0)
449         spinner = gtk.SpinButton(adjustment, 0, 0)
450         spinner.set_wrap(False)
451
452         dialog = gtk.Dialog(
453                 title,
454                 parent,
455                 gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
456                 (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
457         )
458         dialog.set_default_response(gtk.RESPONSE_CANCEL)
459         dialog.get_child().add(spinner)
460
461         try:
462                 dialog.show_all()
463                 response = dialog.run()
464
465                 if response == gtk.RESPONSE_OK:
466                         return spinner.get_value_as_int()
467                 elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
468                         raise RuntimeError("User cancelled request")
469                 else:
470                         raise RuntimeError("Unrecognized response %r", response)
471         finally:
472                 dialog.hide()
473                 dialog.destroy()
474
475
476 try:
477         hildon.NumberEditor # TODO deprecated in fremantle
478         request_number = _hildon_request_number
479 except AttributeError:
480         request_number = _null_request_number
481
482
483 def _hildon_touch_selector(parent, title, items, defaultIndex):
484         model = gtk.ListStore(gobject.TYPE_STRING)
485         for item in items:
486                 model.append((item, ))
487
488         selector = hildon.TouchSelector()
489         selector.append_text_column(model, True)
490         selector.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
491         selector.set_active(0, defaultIndex)
492
493         dialog = hildon.PickerDialog(parent)
494         dialog.set_selector(selector)
495
496         try:
497                 dialog.show_all()
498                 response = dialog.run()
499
500                 if response == gtk.RESPONSE_OK:
501                         return selector.get_active(0)
502                 elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
503                         raise RuntimeError("User cancelled request")
504                 else:
505                         raise RuntimeError("Unrecognized response %r", response)
506         finally:
507                 dialog.hide()
508                 dialog.destroy()
509
510
511 def _on_null_touch_selector_activated(treeView, path, column, dialog, pathData):
512         dialog.response(gtk.RESPONSE_OK)
513         pathData[0] = path
514
515
516 def _null_touch_selector(parent, title, items, defaultIndex = -1):
517         parentSize = parent.get_size()
518
519         model = gtk.ListStore(gobject.TYPE_STRING)
520         for item in items:
521                 model.append((item, ))
522
523         cell = gtk.CellRendererText()
524         set_cell_thumb_selectable(cell)
525         column = gtk.TreeViewColumn(title)
526         column.pack_start(cell, expand=True)
527         column.add_attribute(cell, "text", 0)
528
529         treeView = gtk.TreeView()
530         treeView.set_model(model)
531         treeView.append_column(column)
532         selection = treeView.get_selection()
533         selection.set_mode(gtk.SELECTION_SINGLE)
534         if 0 < defaultIndex:
535                 selection.select_path((defaultIndex, ))
536
537         scrolledWin = gtk.ScrolledWindow()
538         scrolledWin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
539         scrolledWin.add(treeView)
540
541         dialog = gtk.Dialog(
542                 title,
543                 parent,
544                 gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
545                 (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
546         )
547         dialog.set_default_response(gtk.RESPONSE_CANCEL)
548         dialog.get_child().add(scrolledWin)
549         dialog.resize(parentSize[0], max(parentSize[1]-100, 100))
550
551         scrolledWin = hildonize_scrollwindow(scrolledWin)
552         pathData = [None]
553         treeView.connect("row-activated", _on_null_touch_selector_activated, dialog, pathData)
554
555         try:
556                 dialog.show_all()
557                 response = dialog.run()
558
559                 if response == gtk.RESPONSE_OK:
560                         if pathData[0] is None:
561                                 raise RuntimeError("No selection made")
562                         return pathData[0][0]
563                 elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
564                         raise RuntimeError("User cancelled request")
565                 else:
566                         raise RuntimeError("Unrecognized response %r", response)
567         finally:
568                 dialog.hide()
569                 dialog.destroy()
570
571
572 try:
573         hildon.PickerDialog
574         hildon.TouchSelector
575         touch_selector = _hildon_touch_selector
576 except AttributeError:
577         touch_selector = _null_touch_selector
578
579
580 def _hildon_touch_selector_entry(parent, title, items, defaultItem):
581         # Got a segfault when using append_text_column with TouchSelectorEntry, so using this way
582         try:
583                 selector = hildon.TouchSelectorEntry(text=True)
584         except TypeError:
585                 selector = hildon.hildon_touch_selector_entry_new_text()
586         defaultIndex = -1
587         for i, item in enumerate(items):
588                 selector.append_text(item)
589                 if item == defaultItem:
590                         defaultIndex = i
591
592         dialog = hildon.PickerDialog(parent)
593         dialog.set_selector(selector)
594
595         if 0 < defaultIndex:
596                 selector.set_active(0, defaultIndex)
597         else:
598                 selector.get_entry().set_text(defaultItem)
599
600         try:
601                 dialog.show_all()
602                 response = dialog.run()
603         finally:
604                 dialog.hide()
605
606         if response == gtk.RESPONSE_OK:
607                 return selector.get_entry().get_text()
608         elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
609                 raise RuntimeError("User cancelled request")
610         else:
611                 raise RuntimeError("Unrecognized response %r", response)
612
613
614 def _on_null_touch_selector_entry_entry_changed(entry, result, selection, defaultIndex):
615         custom = entry.get_text().strip()
616         if custom:
617                 result[0] = custom
618                 selection.unselect_all()
619         else:
620                 result[0] = None
621                 selection.select_path((defaultIndex, ))
622
623
624 def _on_null_touch_selector_entry_entry_activated(customEntry, dialog, result):
625         dialog.response(gtk.RESPONSE_OK)
626         result[0] = customEntry.get_text()
627
628
629 def _on_null_touch_selector_entry_tree_activated(treeView, path, column, dialog, result):
630         dialog.response(gtk.RESPONSE_OK)
631         model = treeView.get_model()
632         itr = model.get_iter(path)
633         if itr is not None:
634                 result[0] = model.get_value(itr, 0)
635
636
637 def _null_touch_selector_entry(parent, title, items, defaultItem):
638         parentSize = parent.get_size()
639
640         model = gtk.ListStore(gobject.TYPE_STRING)
641         defaultIndex = -1
642         for i, item in enumerate(items):
643                 model.append((item, ))
644                 if item == defaultItem:
645                         defaultIndex = i
646
647         cell = gtk.CellRendererText()
648         set_cell_thumb_selectable(cell)
649         column = gtk.TreeViewColumn(title)
650         column.pack_start(cell, expand=True)
651         column.add_attribute(cell, "text", 0)
652
653         treeView = gtk.TreeView()
654         treeView.set_model(model)
655         treeView.append_column(column)
656         selection = treeView.get_selection()
657         selection.set_mode(gtk.SELECTION_SINGLE)
658
659         scrolledWin = gtk.ScrolledWindow()
660         scrolledWin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
661         scrolledWin.add(treeView)
662
663         customEntry = gtk.Entry()
664
665         layout = gtk.VBox()
666         layout.pack_start(customEntry, expand=False)
667         layout.pack_start(scrolledWin)
668
669         dialog = gtk.Dialog(
670                 title,
671                 parent,
672                 gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
673                 (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
674         )
675         dialog.set_default_response(gtk.RESPONSE_CANCEL)
676         dialog.get_child().add(layout)
677         dialog.resize(parentSize[0], max(parentSize[1]-100, 100))
678
679         scrolledWin = hildonize_scrollwindow(scrolledWin)
680
681         result = [None]
682         if 0 < defaultIndex:
683                 selection.select_path((defaultIndex, ))
684                 result[0] = defaultItem
685         else:
686                 customEntry.set_text(defaultItem)
687
688         customEntry.connect("activate", _on_null_touch_selector_entry_entry_activated, dialog, result)
689         customEntry.connect("changed", _on_null_touch_selector_entry_entry_changed, result, selection, defaultIndex)
690         treeView.connect("row-activated", _on_null_touch_selector_entry_tree_activated, dialog, result)
691
692         try:
693                 dialog.show_all()
694                 response = dialog.run()
695
696                 if response == gtk.RESPONSE_OK:
697                         _, itr = selection.get_selected()
698                         if itr is not None:
699                                 return model.get_value(itr, 0)
700                         else:
701                                 enteredText = customEntry.get_text().strip()
702                                 if enteredText:
703                                         return enteredText
704                                 elif result[0] is not None:
705                                         return result[0]
706                                 else:
707                                         raise RuntimeError("No selection made")
708                 elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
709                         raise RuntimeError("User cancelled request")
710                 else:
711                         raise RuntimeError("Unrecognized response %r", response)
712         finally:
713                 dialog.hide()
714                 dialog.destroy()
715
716
717 try:
718         hildon.PickerDialog
719         hildon.TouchSelectorEntry
720         touch_selector_entry = _hildon_touch_selector_entry
721 except AttributeError:
722         touch_selector_entry = _null_touch_selector_entry
723
724
725 if __name__ == "__main__":
726         app = get_app_class()()
727
728         label = gtk.Label("Hello World from a Label!")
729
730         win = gtk.Window()
731         win.add(label)
732         win = hildonize_window(app, win)
733         if False and IS_FREMANTLE_SUPPORTED:
734                 appMenu = hildon.AppMenu()
735                 for i in xrange(5):
736                         b = gtk.Button(str(i))
737                         appMenu.append(b)
738                 win.set_app_menu(appMenu)
739                 win.show_all()
740                 appMenu.show_all()
741                 gtk.main()
742         elif False:
743                 print touch_selector(win, "Test", ["A", "B", "C", "D"], 2)
744         elif False:
745                 print touch_selector_entry(win, "Test", ["A", "B", "C", "D"], "C")
746                 print touch_selector_entry(win, "Test", ["A", "B", "C", "D"], "Blah")
747         elif False:
748                 import pprint
749                 name, value = "", ""
750                 goodLocals = [
751                         (name, value) for (name, value) in locals().iteritems()
752                         if not name.startswith("_")
753                 ]
754                 pprint.pprint(goodLocals)
755         elif False:
756                 import time
757                 show_information_banner(win, "Hello World")
758                 time.sleep(5)
759         elif False:
760                 import time
761                 banner = show_busy_banner_start(win, "Hello World")
762                 time.sleep(5)
763                 show_busy_banner_end(banner)