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