From be05b434519887d3e8c1634120d52e052b0530c1 Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Wed, 1 Nov 2006 22:36:23 +0000 Subject: [PATCH] Added the sample code from wxPython In Action to the samples dir git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@42925 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- .../samples/wxPIA_book/Chapter-01/bare.py | 11 + .../samples/wxPIA_book/Chapter-01/hello.py | 36 + .../wxPIA_book/Chapter-01/python_compare.py | 36 + .../samples/wxPIA_book/Chapter-01/sample.py | 21 + .../samples/wxPIA_book/Chapter-01/spare.py | 20 + .../wxPIA_book/Chapter-01/wxPython.jpg | Bin 0 -> 14557 bytes .../wxPIA_book/Chapter-02/dialog_scratch.py | 36 + .../samples/wxPIA_book/Chapter-02/images.py | 24 + .../samples/wxPIA_book/Chapter-02/insert.py | 27 + .../samples/wxPIA_book/Chapter-02/startup.py | 35 + .../samples/wxPIA_book/Chapter-02/toolbar.py | 41 + .../wxPIA_book/Chapter-03/customEvent.py | 64 + .../wxPIA_book/Chapter-03/double_event_one.py | 28 + .../wxPIA_book/Chapter-03/menu_event.py | 24 + .../wxPIA_book/Chapter-03/mouse_event.py | 34 + .../samples/wxPIA_book/Chapter-04/PyWrap.py | 48 + .../samples/wxPIA_book/Chapter-04/images.py | 24 + .../Chapter-04/pycrust-foundation.py | 60 + wxPython/samples/wxPIA_book/Chapter-04/pywrap | 4 + .../samples/wxPIA_book/Chapter-04/spare.py | 20 + .../wxPIA_book/Chapter-05/abstractmodel.py | 15 + .../wxPIA_book/Chapter-05/badExample.py | 77 + .../wxPIA_book/Chapter-05/generictable.py | 34 + .../wxPIA_book/Chapter-05/goodExample.py | 96 ++ .../wxPIA_book/Chapter-05/gridGeneric.py | 34 + .../wxPIA_book/Chapter-05/gridModel.py | 54 + .../wxPIA_book/Chapter-05/gridNoModel.py | 49 + .../wxPIA_book/Chapter-05/lineuptable.py | 41 + .../wxPIA_book/Chapter-05/modelExample.py | 89 ++ .../wxPIA_book/Chapter-05/testEventExample.py | 37 + .../wxPIA_book/Chapter-05/testExample.py | 26 + .../samples/wxPIA_book/Chapter-06/example1.py | 106 ++ .../samples/wxPIA_book/Chapter-06/example2.py | 21 + .../samples/wxPIA_book/Chapter-06/example3.py | 27 + .../samples/wxPIA_book/Chapter-06/example4.py | 92 ++ .../samples/wxPIA_book/Chapter-06/example5.py | 132 ++ .../samples/wxPIA_book/Chapter-06/example6.py | 192 +++ .../samples/wxPIA_book/Chapter-06/example7.py | 331 ++++ .../samples/wxPIA_book/Chapter-06/new.bmp | Bin 0 -> 238 bytes .../samples/wxPIA_book/Chapter-06/open.bmp | Bin 0 -> 238 bytes .../samples/wxPIA_book/Chapter-06/save.bmp | Bin 0 -> 1318 bytes .../samples/wxPIA_book/Chapter-06/splash.png | Bin 0 -> 3923 bytes .../samples/wxPIA_book/Chapter-07/bitmap.bmp | Bin 0 -> 13054 bytes .../wxPIA_book/Chapter-07/bitmap_button.py | 25 + .../samples/wxPIA_book/Chapter-07/button.py | 21 + .../samples/wxPIA_book/Chapter-07/checkbox.py | 16 + .../samples/wxPIA_book/Chapter-07/choice.py | 16 + .../wxPIA_book/Chapter-07/combo_box.py | 19 + .../samples/wxPIA_book/Chapter-07/gauge.py | 23 + .../wxPIA_book/Chapter-07/generic_button.py | 56 + .../samples/wxPIA_book/Chapter-07/list_box.py | 21 + .../samples/wxPIA_book/Chapter-07/radio.py | 32 + .../wxPIA_book/Chapter-07/radio_box.py | 19 + .../samples/wxPIA_book/Chapter-07/slider.py | 22 + .../samples/wxPIA_book/Chapter-07/spinner.py | 15 + .../wxPIA_book/Chapter-07/static_text.py | 38 + .../wxPIA_book/Chapter-07/text_ctrl.py | 25 + .../Chapter-07/text_ctrl_multiple.py | 33 + .../wxPIA_book/Chapter-08/frame_subclass.py | 21 + .../wxPIA_book/Chapter-08/help_context.py | 16 + .../samples/wxPIA_book/Chapter-08/images.py | 1424 +++++++++++++++++ wxPython/samples/wxPIA_book/Chapter-08/mdi.py | 29 + .../wxPIA_book/Chapter-08/miniframe.py | 21 + .../wxPIA_book/Chapter-08/scroll_window.py | 26 + .../wxPIA_book/Chapter-08/shaped_frame.py | 43 + .../Chapter-08/shaped_frame_mobile.py | 64 + .../wxPIA_book/Chapter-08/simple_frame.py | 8 + .../samples/wxPIA_book/Chapter-08/splitter.py | 101 ++ .../wxPIA_book/Chapter-09/choice_box.py | 12 + .../wxPIA_book/Chapter-09/color_box.py | 10 + .../samples/wxPIA_book/Chapter-09/dir_box.py | 12 + .../samples/wxPIA_book/Chapter-09/file_box.py | 17 + .../samples/wxPIA_book/Chapter-09/font_box.py | 16 + .../wxPIA_book/Chapter-09/image_box.py | 11 + .../wxPIA_book/Chapter-09/message_box.py | 16 + .../wxPIA_book/Chapter-09/modal_dialog.py | 21 + .../wxPIA_book/Chapter-09/progress_box.py | 33 + .../wxPIA_book/Chapter-09/startup_tip.py | 8 + .../samples/wxPIA_book/Chapter-09/text_box.py | 11 + .../samples/wxPIA_book/Chapter-09/tips.txt | 2 + .../wxPIA_book/Chapter-09/validator1.py | 93 ++ .../wxPIA_book/Chapter-09/validator2.py | 91 ++ .../wxPIA_book/Chapter-09/validator3.py | 92 ++ .../samples/wxPIA_book/Chapter-09/wizard.py | 39 + .../wxPIA_book/Chapter-10/add_items.py | 50 + .../wxPIA_book/Chapter-10/create_just_menu.py | 22 + .../Chapter-10/create_simple_menu.py | 29 + .../wxPIA_book/Chapter-10/disable_item.py | 46 + .../wxPIA_book/Chapter-10/fancy_items.py | 47 + .../wxPIA_book/Chapter-10/find_item.py | 52 + .../samples/wxPIA_book/Chapter-10/open.png | Bin 0 -> 281 bytes .../wxPIA_book/Chapter-10/popupmenu.py | 49 + .../samples/wxPIA_book/Chapter-10/sub_menu.py | 34 + .../wxPIA_book/Chapter-10/toggle_items.py | 36 + .../wxPIA_book/Chapter-10/update_ui.py | 49 + .../wxPIA_book/Chapter-10/with_accelerator.py | 47 + .../Chapter-11/basicflexgridsizer.py | 20 + .../wxPIA_book/Chapter-11/basicgridsizer.py | 18 + .../wxPIA_book/Chapter-11/blockwindow.py | 20 + .../wxPIA_book/Chapter-11/bordergridsizer.py | 23 + .../samples/wxPIA_book/Chapter-11/boxsizer.py | 78 + .../wxPIA_book/Chapter-11/gridbagsizer.py | 34 + .../wxPIA_book/Chapter-11/mingridsizer.py | 19 + .../wxPIA_book/Chapter-11/prependgridsizer.py | 18 + .../wxPIA_book/Chapter-11/realworld.py | 95 ++ .../Chapter-11/resizeflexgridsizer.py | 26 + .../wxPIA_book/Chapter-11/resizegridsizer.py | 22 + .../wxPIA_book/Chapter-11/staticboxsizer.py | 45 + .../wxPIA_book/Chapter-12/draw_image.py | 46 + .../samples/wxPIA_book/Chapter-12/image.bmp | Bin 0 -> 57138 bytes .../samples/wxPIA_book/Chapter-12/image.gif | Bin 0 -> 7116 bytes .../samples/wxPIA_book/Chapter-12/image.jpg | Bin 0 -> 8087 bytes .../samples/wxPIA_book/Chapter-12/image.png | Bin 0 -> 17905 bytes .../samples/wxPIA_book/Chapter-12/images.py | 35 + .../wxPIA_book/Chapter-12/masked-portrait.png | Bin 0 -> 76142 bytes .../wxPIA_book/Chapter-12/radargraph.py | 170 ++ .../samples/wxPIA_book/Chapter-13/data.py | 41 + .../samples/wxPIA_book/Chapter-13/icon01.png | Bin 0 -> 359 bytes .../samples/wxPIA_book/Chapter-13/icon02.png | Bin 0 -> 351 bytes .../samples/wxPIA_book/Chapter-13/icon03.png | Bin 0 -> 454 bytes .../samples/wxPIA_book/Chapter-13/icon04.png | Bin 0 -> 337 bytes .../samples/wxPIA_book/Chapter-13/icon05.png | Bin 0 -> 435 bytes .../samples/wxPIA_book/Chapter-13/icon06.png | Bin 0 -> 478 bytes .../samples/wxPIA_book/Chapter-13/icon07.png | Bin 0 -> 382 bytes .../samples/wxPIA_book/Chapter-13/icon08.png | Bin 0 -> 445 bytes .../wxPIA_book/Chapter-13/list_icon.py | 32 + .../wxPIA_book/Chapter-13/list_list.py | 34 + .../wxPIA_book/Chapter-13/list_report.py | 42 + .../Chapter-13/list_report_colsort.py | 70 + .../wxPIA_book/Chapter-13/list_report_etc.py | 210 +++ .../Chapter-13/list_report_virtual.py | 66 + .../wxPIA_book/Chapter-13/list_smicon.py | 35 + .../samples/wxPIA_book/Chapter-13/sm_down.bmp | Bin 0 -> 246 bytes .../samples/wxPIA_book/Chapter-13/sm_up.bmp | Bin 0 -> 246 bytes .../wxPIA_book/Chapter-13/smicon01.png | Bin 0 -> 266 bytes .../wxPIA_book/Chapter-13/smicon02.png | Bin 0 -> 212 bytes .../wxPIA_book/Chapter-13/smicon03.png | Bin 0 -> 205 bytes .../wxPIA_book/Chapter-13/smicon04.png | Bin 0 -> 249 bytes .../wxPIA_book/Chapter-13/smicon05.png | Bin 0 -> 257 bytes .../wxPIA_book/Chapter-13/smicon06.png | Bin 0 -> 226 bytes .../wxPIA_book/Chapter-14/grid_attr.py | 33 + .../wxPIA_book/Chapter-14/grid_basic.py | 18 + .../wxPIA_book/Chapter-14/grid_editor.py | 111 ++ .../wxPIA_book/Chapter-14/grid_headers.py | 24 + .../wxPIA_book/Chapter-14/grid_renderer.py | 59 + .../wxPIA_book/Chapter-14/grid_size.py | 23 + .../wxPIA_book/Chapter-14/grid_table.py | 65 + .../wxPIA_book/Chapter-14/grid_table_basic.py | 42 + .../Chapter-14/grid_table_header.py | 64 + .../samples/wxPIA_book/Chapter-15/data.py | 403 +++++ .../wxPIA_book/Chapter-15/tree_icons.py | 65 + .../wxPIA_book/Chapter-15/tree_misc.py | 155 ++ .../wxPIA_book/Chapter-15/tree_simple.py | 62 + .../wxPIA_book/Chapter-15/tree_treelist.py | 104 ++ .../wxPIA_book/Chapter-15/tree_virtual.py | 92 ++ .../wxPIA_book/Chapter-16/helpfiles/Index.hhk | 71 + .../Chapter-16/helpfiles/another.hhc | 18 + .../Chapter-16/helpfiles/another.hhp | 6 + .../Chapter-16/helpfiles/another.htm | 24 + .../wxPIA_book/Chapter-16/helpfiles/book1.htm | 4 + .../wxPIA_book/Chapter-16/helpfiles/book2.htm | 5 + .../Chapter-16/helpfiles/contents.hhc | 28 + .../wxPIA_book/Chapter-16/helpfiles/main.htm | 5 + .../Chapter-16/helpfiles/page2-b.htm | 5 + .../Chapter-16/helpfiles/testing.hhp | 16 + .../wxPIA_book/Chapter-16/html_help.py | 59 + .../samples/wxPIA_book/Chapter-16/html_tag.py | 71 + .../wxPIA_book/Chapter-16/html_window.py | 19 + .../Chapter-16/html_window_loadpage.py | 17 + .../Chapter-16/html_window_related.py | 21 + .../samples/wxPIA_book/Chapter-17/printing.py | 236 +++ .../wxPIA_book/Chapter-17/sample-text.txt | 213 +++ .../wxPIA_book/Chapter-18/clipboard.py | 77 + .../wxPIA_book/Chapter-18/customcomposite.py | 152 ++ .../wxPIA_book/Chapter-18/drop_source.py | 70 + .../wxPIA_book/Chapter-18/drop_target.py | 40 + .../samples/wxPIA_book/Chapter-18/sound.py | 38 + .../samples/wxPIA_book/Chapter-18/sound1.wav | Bin 0 -> 6160 bytes .../samples/wxPIA_book/Chapter-18/sound2.wav | Bin 0 -> 8536 bytes .../samples/wxPIA_book/Chapter-18/timer.py | 39 + .../wxPIA_book/Chapter-18/worker_threads.py | 101 ++ .../wxPIA_book/Chapter-18/xrcsample.py | 43 + .../wxPIA_book/Chapter-18/xrcsample.xrc | 94 ++ wxPython/samples/wxPIA_book/README.txt | 6 + 184 files changed, 9122 insertions(+) create mode 100644 wxPython/samples/wxPIA_book/Chapter-01/bare.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-01/hello.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-01/python_compare.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-01/sample.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-01/spare.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-01/wxPython.jpg create mode 100644 wxPython/samples/wxPIA_book/Chapter-02/dialog_scratch.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-02/images.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-02/insert.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-02/startup.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-02/toolbar.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-03/customEvent.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-03/double_event_one.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-03/menu_event.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-03/mouse_event.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-04/PyWrap.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-04/images.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-04/pycrust-foundation.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-04/pywrap create mode 100644 wxPython/samples/wxPIA_book/Chapter-04/spare.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-05/abstractmodel.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-05/badExample.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-05/generictable.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-05/goodExample.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-05/gridGeneric.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-05/gridModel.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-05/gridNoModel.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-05/lineuptable.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-05/modelExample.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-05/testEventExample.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-05/testExample.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-06/example1.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-06/example2.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-06/example3.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-06/example4.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-06/example5.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-06/example6.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-06/example7.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-06/new.bmp create mode 100644 wxPython/samples/wxPIA_book/Chapter-06/open.bmp create mode 100644 wxPython/samples/wxPIA_book/Chapter-06/save.bmp create mode 100644 wxPython/samples/wxPIA_book/Chapter-06/splash.png create mode 100644 wxPython/samples/wxPIA_book/Chapter-07/bitmap.bmp create mode 100644 wxPython/samples/wxPIA_book/Chapter-07/bitmap_button.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-07/button.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-07/checkbox.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-07/choice.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-07/combo_box.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-07/gauge.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-07/generic_button.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-07/list_box.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-07/radio.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-07/radio_box.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-07/slider.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-07/spinner.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-07/static_text.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-07/text_ctrl.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-07/text_ctrl_multiple.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-08/frame_subclass.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-08/help_context.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-08/images.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-08/mdi.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-08/miniframe.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-08/scroll_window.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-08/shaped_frame.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-08/shaped_frame_mobile.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-08/simple_frame.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-08/splitter.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-09/choice_box.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-09/color_box.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-09/dir_box.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-09/file_box.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-09/font_box.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-09/image_box.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-09/message_box.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-09/modal_dialog.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-09/progress_box.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-09/startup_tip.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-09/text_box.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-09/tips.txt create mode 100644 wxPython/samples/wxPIA_book/Chapter-09/validator1.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-09/validator2.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-09/validator3.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-09/wizard.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-10/add_items.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-10/create_just_menu.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-10/create_simple_menu.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-10/disable_item.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-10/fancy_items.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-10/find_item.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-10/open.png create mode 100644 wxPython/samples/wxPIA_book/Chapter-10/popupmenu.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-10/sub_menu.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-10/toggle_items.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-10/update_ui.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-10/with_accelerator.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-11/basicflexgridsizer.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-11/basicgridsizer.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-11/blockwindow.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-11/bordergridsizer.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-11/boxsizer.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-11/gridbagsizer.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-11/mingridsizer.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-11/prependgridsizer.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-11/realworld.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-11/resizeflexgridsizer.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-11/resizegridsizer.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-11/staticboxsizer.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-12/draw_image.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-12/image.bmp create mode 100644 wxPython/samples/wxPIA_book/Chapter-12/image.gif create mode 100644 wxPython/samples/wxPIA_book/Chapter-12/image.jpg create mode 100644 wxPython/samples/wxPIA_book/Chapter-12/image.png create mode 100644 wxPython/samples/wxPIA_book/Chapter-12/images.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-12/masked-portrait.png create mode 100644 wxPython/samples/wxPIA_book/Chapter-12/radargraph.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/data.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/icon01.png create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/icon02.png create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/icon03.png create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/icon04.png create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/icon05.png create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/icon06.png create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/icon07.png create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/icon08.png create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/list_icon.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/list_list.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/list_report.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/list_report_colsort.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/list_report_etc.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/list_report_virtual.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/list_smicon.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/sm_down.bmp create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/sm_up.bmp create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/smicon01.png create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/smicon02.png create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/smicon03.png create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/smicon04.png create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/smicon05.png create mode 100644 wxPython/samples/wxPIA_book/Chapter-13/smicon06.png create mode 100644 wxPython/samples/wxPIA_book/Chapter-14/grid_attr.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-14/grid_basic.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-14/grid_editor.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-14/grid_headers.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-14/grid_renderer.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-14/grid_size.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-14/grid_table.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-14/grid_table_basic.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-14/grid_table_header.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-15/data.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-15/tree_icons.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-15/tree_misc.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-15/tree_simple.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-15/tree_treelist.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-15/tree_virtual.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-16/helpfiles/Index.hhk create mode 100644 wxPython/samples/wxPIA_book/Chapter-16/helpfiles/another.hhc create mode 100644 wxPython/samples/wxPIA_book/Chapter-16/helpfiles/another.hhp create mode 100644 wxPython/samples/wxPIA_book/Chapter-16/helpfiles/another.htm create mode 100644 wxPython/samples/wxPIA_book/Chapter-16/helpfiles/book1.htm create mode 100644 wxPython/samples/wxPIA_book/Chapter-16/helpfiles/book2.htm create mode 100644 wxPython/samples/wxPIA_book/Chapter-16/helpfiles/contents.hhc create mode 100644 wxPython/samples/wxPIA_book/Chapter-16/helpfiles/main.htm create mode 100644 wxPython/samples/wxPIA_book/Chapter-16/helpfiles/page2-b.htm create mode 100644 wxPython/samples/wxPIA_book/Chapter-16/helpfiles/testing.hhp create mode 100644 wxPython/samples/wxPIA_book/Chapter-16/html_help.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-16/html_tag.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-16/html_window.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-16/html_window_loadpage.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-16/html_window_related.py create mode 100755 wxPython/samples/wxPIA_book/Chapter-17/printing.py create mode 100755 wxPython/samples/wxPIA_book/Chapter-17/sample-text.txt create mode 100644 wxPython/samples/wxPIA_book/Chapter-18/clipboard.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-18/customcomposite.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-18/drop_source.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-18/drop_target.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-18/sound.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-18/sound1.wav create mode 100644 wxPython/samples/wxPIA_book/Chapter-18/sound2.wav create mode 100644 wxPython/samples/wxPIA_book/Chapter-18/timer.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-18/worker_threads.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-18/xrcsample.py create mode 100644 wxPython/samples/wxPIA_book/Chapter-18/xrcsample.xrc create mode 100644 wxPython/samples/wxPIA_book/README.txt diff --git a/wxPython/samples/wxPIA_book/Chapter-01/bare.py b/wxPython/samples/wxPIA_book/Chapter-01/bare.py new file mode 100644 index 0000000000..b9417f956f --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-01/bare.py @@ -0,0 +1,11 @@ +import wx + +class App(wx.App): + + def OnInit(self): + frame = wx.Frame(parent=None, title='Bare') + frame.Show() + return True + +app = App() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-01/hello.py b/wxPython/samples/wxPIA_book/Chapter-01/hello.py new file mode 100644 index 0000000000..d2cef839b5 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-01/hello.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +"""Hello, wxPython! program.""" + +import wx + +class Frame(wx.Frame): + """Frame class that displays an image.""" + + def __init__(self, image, parent=None, id=-1, + pos=wx.DefaultPosition, title='Hello, wxPython!'): + """Create a Frame instance and display image.""" + temp = image.ConvertToBitmap() + size = temp.GetWidth(), temp.GetHeight() + wx.Frame.__init__(self, parent, id, title, pos, size) + panel = wx.Panel(self) + self.bmp = wx.StaticBitmap(parent=panel, bitmap=temp) + self.SetClientSize(size) + +class App(wx.App): + """Application class.""" + + def OnInit(self): + image = wx.Image('wxPython.jpg', wx.BITMAP_TYPE_JPEG) + self.frame = Frame(image) + self.frame.Show() + self.SetTopWindow(self.frame) + return True + +def main(): + app = App() + app.MainLoop() + +if __name__ == '__main__': + main() + diff --git a/wxPython/samples/wxPIA_book/Chapter-01/python_compare.py b/wxPython/samples/wxPIA_book/Chapter-01/python_compare.py new file mode 100644 index 0000000000..ed21258edd --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-01/python_compare.py @@ -0,0 +1,36 @@ +import wx + +class MyApp(wx.App): + + def OnInit(self): + frame = MyFrame("Hello World", (50, 60), (450, 340)) + frame.Show() + self.SetTopWindow(frame) + return True + +class MyFrame(wx.Frame): + + def __init__(self, title, pos, size): + wx.Frame.__init__(self, None, -1, title, pos, size) + menuFile = wx.Menu() + menuFile.Append(1, "&About...") + menuFile.AppendSeparator() + menuFile.Append(2, "E&xit") + menuBar = wx.MenuBar() + menuBar.Append(menuFile, "&File") + self.SetMenuBar(menuBar) + self.CreateStatusBar() + self.SetStatusText("Welcome to wxPython!") + self.Bind(wx.EVT_MENU, self.OnAbout, id=1) + self.Bind(wx.EVT_MENU, self.OnQuit, id=2) + + def OnQuit(self, event): + self.Close() + + def OnAbout(self, event): + wx.MessageBox("This is a wxPython Hello world sample", + "About Hello World", wx.OK | wx.ICON_INFORMATION, self) + +if __name__ == '__main__': + app = MyApp(False) + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-01/sample.py b/wxPython/samples/wxPIA_book/Chapter-01/sample.py new file mode 100644 index 0000000000..95032945fb --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-01/sample.py @@ -0,0 +1,21 @@ +#!/bin/env python +import wx + +class MyFrame(wx.Frame): + + def __init__(self): + wx.Frame.__init__(self, None, -1, "My Frame", size=(300, 300)) + panel = wx.Panel(self, -1) + panel.Bind(wx.EVT_MOTION, self.OnMove) + wx.StaticText(panel, -1, "Pos:", pos=(10, 12)) + self.posCtrl = wx.TextCtrl(panel, -1, "", pos=(40, 10)) + + def OnMove(self, event): + pos = event.GetPosition() + self.posCtrl.SetValue("%s, %s" % (pos.x, pos.y)) + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = MyFrame() + frame.Show(True) + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-01/spare.py b/wxPython/samples/wxPIA_book/Chapter-01/spare.py new file mode 100644 index 0000000000..756e5c5df2 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-01/spare.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +"""Spare.py is a starting point for simple wxPython programs.""" + +import wx + +class Frame(wx.Frame): + pass + +class App(wx.App): + + def OnInit(self): + self.frame = Frame(parent=None, title='Spare') + self.frame.Show() + self.SetTopWindow(self.frame) + return True + +if __name__ == '__main__': + app = App() + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-01/wxPython.jpg b/wxPython/samples/wxPIA_book/Chapter-01/wxPython.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9770d4e9b875606a97d3e6cb023b21f1ff85df95 GIT binary patch literal 14557 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 Bis=9V literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-02/dialog_scratch.py b/wxPython/samples/wxPIA_book/Chapter-02/dialog_scratch.py new file mode 100644 index 0000000000..d96c38f388 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-02/dialog_scratch.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +import wx +import images + +class App(wx.App): + + def __init__(self, redirect=True, filename=None): + wx.App.__init__(self, redirect, filename) + + def OnInit(self): + dlg = wx.MessageDialog(None, 'Is this the coolest thing ever!', + 'MessageDialog', wx.YES_NO | wx.ICON_QUESTION) + result = dlg.ShowModal() + dlg.Destroy() + + dlg = wx.TextEntryDialog(None, "Who is buried in Grant's tomb?", + 'A Question', 'Cary Grant') + if dlg.ShowModal() == wx.ID_OK: + response = dlg.GetValue() + dlg.Destroy() + + dlg = wx.SingleChoiceDialog(None, + 'What version of Python are you using?', 'Single Choice', + ['1.5.2', '2.0', '2.1.3', '2.2', '2.3.1']) + if dlg.ShowModal() == wx.ID_OK: + response = dlg.GetStringSelection() + dlg.Destroy() + + return True + + +if __name__ == '__main__': + app = App(False, "output") + fred = app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-02/images.py b/wxPython/samples/wxPIA_book/Chapter-02/images.py new file mode 100644 index 0000000000..63e5c8f1d6 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-02/images.py @@ -0,0 +1,24 @@ +#---------------------------------------------------------------------- +# This file was generated by encode_bitmaps.py +# +from wx import ImageFromStream, BitmapFromImage +from wx import EmptyIcon +import cStringIO + +def getNewData(): + return \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0f\x08\x06\ +\x00\x00\x00\xedsO/\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ +\x00YIDATx\x9c\xed\xd31\n@!\x0c\x03\xd0\xa4\xfe\xfb\xdfX\xe3\xf0\x97R\xa5(.\ +\x0ef\x13\xe45\xa2\x92Vp\x92\xcf/\xd4\xaa\xb2\xcd\xb4\xc2\x14\x00\x00in\x90\ +\x84ZUDl\xa9\xa7\xc3c\xcb-\x80\xfc\x87{d8B6=B\xdb\rfy\xc0\r\xc0\xf0\x0e\xfc\ +\x1d\xaf\x84\xa7\xbf\xb1\x03\xe1,\x19&\x93\x9a\xd2\x97\x00\x00\x00\x00IEND\ +\xaeB`\x82' + +def getNewBitmap(): + return BitmapFromImage(getNewImage()) + +def getNewImage(): + stream = cStringIO.StringIO(getNewData()) + return ImageFromStream(stream) + diff --git a/wxPython/samples/wxPIA_book/Chapter-02/insert.py b/wxPython/samples/wxPIA_book/Chapter-02/insert.py new file mode 100644 index 0000000000..313945a96b --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-02/insert.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +import wx + +class InsertFrame(wx.Frame): + + def __init__(self, parent, id): + wx.Frame.__init__(self, parent, id, 'Frame With Button', + size=(300, 100)) + panel = wx.Panel(self) + button = wx.Button(panel, label="Close", pos=(125, 10), + size=(50, 50)) + self.Bind(wx.EVT_BUTTON, self.OnCloseMe, button) + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + + def OnCloseMe(self, event): + self.Close(True) + + def OnCloseWindow(self, event): + self.Destroy() + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = InsertFrame(parent=None, id=-1) + frame.Show() + app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-02/startup.py b/wxPython/samples/wxPIA_book/Chapter-02/startup.py new file mode 100644 index 0000000000..41d1a07537 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-02/startup.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python + +import wx +import sys + +class Frame(wx.Frame): + + def __init__(self, parent, id, title): + print "Frame __init__" + wx.Frame.__init__(self, parent, id, title) + +class App(wx.App): + + def __init__(self, redirect=True, filename=None): + print "App __init__" + wx.App.__init__(self, redirect, filename) + + def OnInit(self): + print "OnInit" + self.frame = Frame(parent=None, id=-1, title='Startup') + self.frame.Show() + self.SetTopWindow(self.frame) + print >> sys.stderr, "A pretend error message" + print "app name: <", self.GetVendorName(), ">" + return True + + def OnExit(self): + print "OnExit" + +if __name__ == '__main__': + app = App(redirect=True) + print "before MainLoop" + fred = app.MainLoop() + print "after MainLoop", fred + diff --git a/wxPython/samples/wxPIA_book/Chapter-02/toolbar.py b/wxPython/samples/wxPIA_book/Chapter-02/toolbar.py new file mode 100644 index 0000000000..9a9619d580 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-02/toolbar.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +import wx +import images + +class ToolbarFrame(wx.Frame): + + def __init__(self, parent, id): + wx.Frame.__init__(self, parent, id, 'Toolbars', + size=(300, 200)) + panel = wx.Panel(self) + panel.SetBackgroundColour('White') + statusBar = self.CreateStatusBar() + toolbar = self.CreateToolBar() + toolbar.AddSimpleTool(wx.NewId(), images.getNewBitmap(), + "New", "Long help for 'New'") + toolbar.Realize() + menuBar = wx.MenuBar() + menu1 = wx.Menu() + menuBar.Append(menu1, "&File") + menu2 = wx.Menu() + menu2.Append(wx.NewId(), "&Copy", "Copy in status bar") + menu2.Append(wx.NewId(), "C&ut", "") + menu2.Append(wx.NewId(), "Paste", "") + menu2.AppendSeparator() + menu2.Append(wx.NewId(), "&Options...", "Display Options") + menuBar.Append(menu2, "&Edit") + self.SetMenuBar(menuBar) + + def OnCloseMe(self, event): + self.Close(True) + + def OnCloseWindow(self, event): + self.Destroy() + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = ToolbarFrame(parent=None, id=-1) + frame.Show() + app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-03/customEvent.py b/wxPython/samples/wxPIA_book/Chapter-03/customEvent.py new file mode 100644 index 0000000000..15923328b2 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-03/customEvent.py @@ -0,0 +1,64 @@ +import wx + +class TwoButtonEvent(wx.PyCommandEvent): + def __init__(self, evtType, id): + wx.PyCommandEvent.__init__(self, evtType, id) + self.clickCount = 0 + + def GetClickCount(self): + return self.clickCount + + def SetClickCount(self, count): + self.clickCount = count + +myEVT_TWO_BUTTON = wx.NewEventType() +EVT_TWO_BUTTON = wx.PyEventBinder(myEVT_TWO_BUTTON, 1) + +class TwoButtonPanel(wx.Panel): + def __init__(self, parent, id=-1, leftText="Left", + rightText="Right"): + wx.Panel.__init__(self, parent, id) + self.leftButton = wx.Button(self, label=leftText) + self.rightButton = wx.Button(self, label=rightText, + pos=(100,0)) + self.leftClick = False + self.rightClick = False + self.clickCount = 0 + self.leftButton.Bind(wx.EVT_LEFT_DOWN, self.OnLeftClick) + self.rightButton.Bind(wx.EVT_LEFT_DOWN, self.OnRightClick) + + def OnLeftClick(self, event): + self.leftClick = True + self.OnClick() + event.Skip() + + def OnRightClick(self, event): + self.rightClick = True + self.OnClick() + event.Skip() + + def OnClick(self): + self.clickCount += 1 + if self.leftClick and self.rightClick: + self.leftClick = False + self.rightClick = False + evt = TwoButtonEvent(myEVT_TWO_BUTTON, self.GetId()) + evt.SetClickCount(self.clickCount) + self.GetEventHandler().ProcessEvent(evt) + + +class CustomEventFrame(wx.Frame): + def __init__(self, parent, id): + wx.Frame.__init__(self, parent, id, 'Click Count: 0', + size=(300, 100)) + panel = TwoButtonPanel(self) + self.Bind(EVT_TWO_BUTTON, self.OnTwoClick, panel) + + def OnTwoClick(self, event): + self.SetTitle("Click Count: %s" % event.GetClickCount()) + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = CustomEventFrame(parent=None, id=-1) + frame.Show() + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-03/double_event_one.py b/wxPython/samples/wxPIA_book/Chapter-03/double_event_one.py new file mode 100644 index 0000000000..4cf5955c7e --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-03/double_event_one.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +import wx + +class DoubleEventFrame(wx.Frame): + + def __init__(self, parent, id): + wx.Frame.__init__(self, parent, id, 'Frame With Button', + size=(300, 100)) + self.panel = wx.Panel(self, -1) + self.button = wx.Button(self.panel, -1, "Click Me", pos=(100, 15)) + self.Bind(wx.EVT_BUTTON, self.OnButtonClick, self.button) + self.button.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown) + + def OnButtonClick(self, event): + self.panel.SetBackgroundColour('Green') + self.panel.Refresh() + + def OnMouseDown(self, event): + self.button.SetLabel("Again!") + event.Skip() + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = DoubleEventFrame(parent=None, id=-1) + frame.Show() + app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-03/menu_event.py b/wxPython/samples/wxPIA_book/Chapter-03/menu_event.py new file mode 100644 index 0000000000..da133f6e68 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-03/menu_event.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +import wx + +class MenuEventFrame(wx.Frame): + + def __init__(self, parent, id): + wx.Frame.__init__(self, parent, id, 'Menus', size=(300, 200)) + menuBar = wx.MenuBar() + menu1 = wx.Menu() + menuItem = menu1.Append(-1, "&Exit...") + menuBar.Append(menu1, "&File") + self.SetMenuBar(menuBar) + self.Bind(wx.EVT_MENU, self.OnCloseMe, menuItem) + + def OnCloseMe(self, event): + self.Close(True) + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = MenuEventFrame(parent=None, id=-1) + frame.Show() + app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-03/mouse_event.py b/wxPython/samples/wxPIA_book/Chapter-03/mouse_event.py new file mode 100644 index 0000000000..9d319831ae --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-03/mouse_event.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +import wx + +class MouseEventFrame(wx.Frame): + + def __init__(self, parent, id): + wx.Frame.__init__(self, parent, id, 'Frame With Button', + size=(300, 100)) + self.panel = wx.Panel(self) + self.button = wx.Button(self.panel, label="Not Over", pos=(100, 15)) + self.Bind(wx.EVT_BUTTON, self.OnButtonClick, self.button) + self.button.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow) + self.button.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) + + def OnButtonClick(self, event): + self.panel.SetBackgroundColour('Green') + self.panel.Refresh() + + def OnEnterWindow(self, event): + self.button.SetLabel("Over Me!") + event.Skip() + + def OnLeaveWindow(self, event): + self.button.SetLabel("Not Over") + event.Skip() + + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = MouseEventFrame(parent=None, id=-1) + frame.Show() + app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-04/PyWrap.py b/wxPython/samples/wxPIA_book/Chapter-04/PyWrap.py new file mode 100644 index 0000000000..99a91f1833 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-04/PyWrap.py @@ -0,0 +1,48 @@ +"""PyWrap is a command line utility that runs a wxPython program with +additional runtime-tools, such as PyCrust.""" + +__author__ = "Patrick K. O'Brien " +__cvsid__ = "$Id$" +__revision__ = "$Revision$"[11:-2] + +import wx +from wx import py + +import os +import sys + +def wrap(app): + wx.InitAllImageHandlers() + frame = py.crust.CrustFrame() + frame.SetSize((750, 525)) + frame.Show(True) + frame.shell.interp.locals['app'] = app + app.MainLoop() + +def main(modulename=None): + sys.path.insert(0, os.curdir) + if not modulename: + if len(sys.argv) < 2: + print "Please specify a module name." + raise SystemExit + modulename = sys.argv[1] + if modulename.endswith('.py'): + modulename = modulename[:-3] + module = __import__(modulename) + # Find the App class. + App = None + d = module.__dict__ + for item in d.keys(): + try: + if issubclass(d[item], wx.App): + App = d[item] + except (NameError, TypeError): + pass + if App is None: + print "No App class was found." + raise SystemExit + app = App() + wrap(app) + +if __name__ == '__main__': + main() diff --git a/wxPython/samples/wxPIA_book/Chapter-04/images.py b/wxPython/samples/wxPIA_book/Chapter-04/images.py new file mode 100644 index 0000000000..63e5c8f1d6 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-04/images.py @@ -0,0 +1,24 @@ +#---------------------------------------------------------------------- +# This file was generated by encode_bitmaps.py +# +from wx import ImageFromStream, BitmapFromImage +from wx import EmptyIcon +import cStringIO + +def getNewData(): + return \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0f\x08\x06\ +\x00\x00\x00\xedsO/\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ +\x00YIDATx\x9c\xed\xd31\n@!\x0c\x03\xd0\xa4\xfe\xfb\xdfX\xe3\xf0\x97R\xa5(.\ +\x0ef\x13\xe45\xa2\x92Vp\x92\xcf/\xd4\xaa\xb2\xcd\xb4\xc2\x14\x00\x00in\x90\ +\x84ZUDl\xa9\xa7\xc3c\xcb-\x80\xfc\x87{d8B6=B\xdb\rfy\xc0\r\xc0\xf0\x0e\xfc\ +\x1d\xaf\x84\xa7\xbf\xb1\x03\xe1,\x19&\x93\x9a\xd2\x97\x00\x00\x00\x00IEND\ +\xaeB`\x82' + +def getNewBitmap(): + return BitmapFromImage(getNewImage()) + +def getNewImage(): + stream = cStringIO.StringIO(getNewData()) + return ImageFromStream(stream) + diff --git a/wxPython/samples/wxPIA_book/Chapter-04/pycrust-foundation.py b/wxPython/samples/wxPIA_book/Chapter-04/pycrust-foundation.py new file mode 100644 index 0000000000..f9a5db6e11 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-04/pycrust-foundation.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python + +import wx +from wx.py.shell import ShellFrame +from wx.py.filling import FillingFrame +import images + +class ToolbarFrame(wx.Frame): + + def __init__(self, parent, id): + wx.Frame.__init__(self, parent, id, 'Toolbars', + size=(300, 200)) + panel = wx.Panel(self, -1) + panel.SetBackgroundColour('White') + statusBar = self.CreateStatusBar() + toolbar = self.CreateToolBar() + toolbar.AddSimpleTool(wx.NewId(), images.getNewBitmap(), + "New", "Long help for 'New'") + toolbar.Realize() + menuBar = wx.MenuBar() + menu1 = wx.Menu() + menuBar.Append(menu1, "&File") + menu2 = wx.Menu() + menu2.Append(wx.NewId(), "&Copy", "Copy in status bar") + menu2.Append(wx.NewId(), "C&ut", "") + menu2.Append(wx.NewId(), "Paste", "") + menu2.AppendSeparator() + menu2.Append(wx.NewId(), "&Options...", "Display Options") + menuBar.Append(menu2, "&Edit") + + menu3 = wx.Menu() + shell = menu3.Append(-1, "&Python shell", + "Open Python shell frame") + filling = menu3.Append(-1, "&Namespace viewer", + "Open namespace viewer frame") + menuBar.Append(menu3, "&Debug") + self.Bind(wx.EVT_MENU, self.OnShell, shell) + self.Bind(wx.EVT_MENU, self.OnFilling, filling) + + self.SetMenuBar(menuBar) + + def OnCloseMe(self, event): + self.Close(True) + + def OnCloseWindow(self, event): + self.Destroy() + + def OnShell(self, event): + frame = ShellFrame(parent=self) + frame.Show() + + def OnFilling(self, event): + frame = FillingFrame(parent=self) + frame.Show() + +if __name__ == '__main__': + app = wx.PySimpleApp() + app.frame = ToolbarFrame(parent=None, id=-1) + app.frame.Show() + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-04/pywrap b/wxPython/samples/wxPIA_book/Chapter-04/pywrap new file mode 100644 index 0000000000..3bd7ef1f84 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-04/pywrap @@ -0,0 +1,4 @@ +#!/usr/bin/env python + +from wx.py.PyWrap import main +main() diff --git a/wxPython/samples/wxPIA_book/Chapter-04/spare.py b/wxPython/samples/wxPIA_book/Chapter-04/spare.py new file mode 100644 index 0000000000..7cb63b12dd --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-04/spare.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +"""Spare.py is a starting point for simple wxPython programs.""" + +import wx + +class Frame(wx.Frame): + pass + +class App(wx.App): + + def OnInit(self): + self.frame = Frame(parent=None, id=-1, title='Spare') + self.frame.Show() + self.SetTopWindow(self.frame) + return True + +if __name__ == '__main__': + app = App() + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-05/abstractmodel.py b/wxPython/samples/wxPIA_book/Chapter-05/abstractmodel.py new file mode 100644 index 0000000000..80c8176d49 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-05/abstractmodel.py @@ -0,0 +1,15 @@ +class AbstractModel(object): + + def __init__(self): + self.listeners = [] + + def addListener(self, listenerFunc): + self.listeners.append(listenerFunc) + + def removeListener(self, listenerFunc): + self.listeners.remove(listenerFunc) + + def update(self): + for eachFunc in self.listeners: + eachFunc(self) + diff --git a/wxPython/samples/wxPIA_book/Chapter-05/badExample.py b/wxPython/samples/wxPIA_book/Chapter-05/badExample.py new file mode 100644 index 0000000000..6a57f5bcd0 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-05/badExample.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python + +import wx + +class RefactorExample(wx.Frame): + + def __init__(self, parent, id): + wx.Frame.__init__(self, parent, id, 'Refactor Example', + size=(340, 200)) + panel = wx.Panel(self, -1) + panel.SetBackgroundColour("White") + prevButton = wx.Button(panel, -1, "<< PREV", pos=(80, 0)) + self.Bind(wx.EVT_BUTTON, self.OnPrev, prevButton) + nextButton = wx.Button(panel, -1, "NEXT >>", pos=(160, 0)) + self.Bind(wx.EVT_BUTTON, self.OnNext, nextButton) + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + + menuBar = wx.MenuBar() + menu1 = wx.Menu() + openMenuItem = menu1.Append(-1, "&Open", "Copy in status bar") + self.Bind(wx.EVT_MENU, self.OnOpen, openMenuItem) + quitMenuItem = menu1.Append(-1, "&Quit", "Quit") + self.Bind(wx.EVT_MENU, self.OnCloseWindow, quitMenuItem) + menuBar.Append(menu1, "&File") + menu2 = wx.Menu() + copyItem = menu2.Append(-1, "&Copy", "Copy") + self.Bind(wx.EVT_MENU, self.OnCopy, copyItem) + cutItem = menu2.Append(-1, "C&ut", "Cut") + self.Bind(wx.EVT_MENU, self.OnCut, cutItem) + pasteItem = menu2.Append(-1, "Paste", "Paste") + self.Bind(wx.EVT_MENU, self.OnPaste, pasteItem) + menuBar.Append(menu2, "&Edit") + self.SetMenuBar(menuBar) + + static = wx.StaticText(panel, wx.NewId(), "First Name", + pos=(10, 50)) + static.SetBackgroundColour("White") + text = wx.TextCtrl(panel, wx.NewId(), "", size=(100, -1), + pos=(80, 50)) + + static2 = wx.StaticText(panel, wx.NewId(), "Last Name", + pos=(10, 80)) + static2.SetBackgroundColour("White") + text2 = wx.TextCtrl(panel, wx.NewId(), "", size=(100, -1), + pos=(80, 80)) + + firstButton = wx.Button(panel, -1, "FIRST") + self.Bind(wx.EVT_BUTTON, self.OnFirst, firstButton) + + menu2.AppendSeparator() + optItem = menu2.Append(-1, "&Options...", "Display Options") + self.Bind(wx.EVT_MENU, self.OnOptions, optItem) + + lastButton = wx.Button(panel, -1, "LAST", pos=(240, 0)) + self.Bind(wx.EVT_BUTTON, self.OnLast, lastButton) + + + # Just grouping the empty event handlers together + def OnPrev(self, event): pass + def OnNext(self, event): pass + def OnLast(self, event): pass + def OnFirst(self, event): pass + def OnOpen(self, event): pass + def OnCopy(self, event): pass + def OnCut(self, event): pass + def OnPaste(self, event): pass + def OnOptions(self, event): pass + + def OnCloseWindow(self, event): + self.Destroy() + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = RefactorExample(parent=None, id=-1) + frame.Show() + app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-05/generictable.py b/wxPython/samples/wxPIA_book/Chapter-05/generictable.py new file mode 100644 index 0000000000..88643bd286 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-05/generictable.py @@ -0,0 +1,34 @@ +import wx +import wx.grid + +class GenericTable(wx.grid.PyGridTableBase): + + def __init__(self, data, rowLabels=None, colLabels=None): + wx.grid.PyGridTableBase.__init__(self) + self.data = data + self.rowLabels = rowLabels + self.colLabels = colLabels + + def GetNumberRows(self): + return len(self.data) + + def GetNumberCols(self): + return len(self.data[0]) + + def GetColLabelValue(self, col): + if self.colLabels: + return self.colLabels[col] + + def GetRowLabelValue(self, row): + if self.rowLabels: + return self.rowLabels[row] + + def IsEmptyCell(self, row, col): + return False + + def GetValue(self, row, col): + return self.data[row][col] + + def SetValue(self, row, col, value): + pass + diff --git a/wxPython/samples/wxPIA_book/Chapter-05/goodExample.py b/wxPython/samples/wxPIA_book/Chapter-05/goodExample.py new file mode 100644 index 0000000000..adb7e54e4f --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-05/goodExample.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python + +import wx + +class RefactorExample(wx.Frame): + + def __init__(self, parent, id): + wx.Frame.__init__(self, parent, id, 'Refactor Example', + size=(340, 200)) + panel = wx.Panel(self, -1) + panel.SetBackgroundColour("White") + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + self.createMenuBar() + self.createButtonBar(panel) + self.createTextFields(panel) + + def menuData(self): + return (("&File", + ("&Open", "Open in status bar", self.OnOpen), + ("&Quit", "Quit", self.OnCloseWindow)), + ("&Edit", + ("&Copy", "Copy", self.OnCopy), + ("C&ut", "Cut", self.OnCut), + ("&Paste", "Paste", self.OnPaste), + ("", "", ""), + ("&Options...", "DisplayOptions", self.OnOptions))) + + def createMenuBar(self): + menuBar = wx.MenuBar() + for eachMenuData in self.menuData(): + menuLabel = eachMenuData[0] + menuItems = eachMenuData[1:] + menuBar.Append(self.createMenu(menuItems), menuLabel) + self.SetMenuBar(menuBar) + + def createMenu(self, menuData): + menu = wx.Menu() + for eachLabel, eachStatus, eachHandler in menuData: + if not eachLabel: + menu.AppendSeparator() + continue + menuItem = menu.Append(-1, eachLabel, eachStatus) + self.Bind(wx.EVT_MENU, eachHandler, menuItem) + return menu + + def buttonData(self): + return (("First", self.OnFirst), + ("<< PREV", self.OnPrev), + ("NEXT >>", self.OnNext), + ("Last", self.OnLast)) + + def createButtonBar(self, panel, yPos = 0): + xPos = 0 + for eachLabel, eachHandler in self.buttonData(): + pos = (xPos, yPos) + button = self.buildOneButton(panel, eachLabel, eachHandler, pos) + xPos += button.GetSize().width + + def buildOneButton(self, parent, label, handler, pos=(0,0)): + button = wx.Button(parent, -1, label, pos) + self.Bind(wx.EVT_BUTTON, handler, button) + return button + + def textFieldData(self): + return (("First Name", (10, 50)), + ("Last Name", (10, 80))) + + def createTextFields(self, panel): + for eachLabel, eachPos in self.textFieldData(): + self.createCaptionedText(panel, eachLabel, eachPos) + + def createCaptionedText(self, panel, label, pos): + static = wx.StaticText(panel, wx.NewId(), label, pos) + static.SetBackgroundColour("White") + textPos = (pos[0] + 75, pos[1]) + wx.TextCtrl(panel, wx.NewId(), "", size=(100, -1), pos=textPos) + + # Just grouping the empty event handlers together + def OnPrev(self, event): pass + def OnNext(self, event): pass + def OnLast(self, event): pass + def OnFirst(self, event): pass + def OnOpen(self, event): pass + def OnCopy(self, event): pass + def OnCut(self, event): pass + def OnPaste(self, event): pass + def OnOptions(self, event): pass + def OnCloseWindow(self, event): + self.Destroy() + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = RefactorExample(parent=None, id=-1) + frame.Show() + app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-05/gridGeneric.py b/wxPython/samples/wxPIA_book/Chapter-05/gridGeneric.py new file mode 100644 index 0000000000..73c7940cb2 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-05/gridGeneric.py @@ -0,0 +1,34 @@ +import wx +import wx.grid +import generictable + + +data = (("Bob", "Dernier"), ("Ryne", "Sandberg"), + ("Gary", "Matthews"), ("Leon", "Durham"), + ("Keith", "Moreland"), ("Ron", "Cey"), + ("Jody", "Davis"), ("Larry", "Bowa"), + ("Rick", "Sutcliffe")) + +colLabels = ("Last", "First") +rowLabels = ("CF", "2B", "LF", "1B", "RF", "3B", "C", "SS", "P") + + +class SimpleGrid(wx.grid.Grid): + def __init__(self, parent): + wx.grid.Grid.__init__(self, parent, -1) + tableBase = generictable.GenericTable(data, rowLabels, + colLabels) + self.SetTable(tableBase) + +class TestFrame(wx.Frame): + def __init__(self, parent): + wx.Frame.__init__(self, parent, -1, "A Grid", + size=(275, 275)) + grid = SimpleGrid(self) + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = TestFrame(None) + frame.Show(True) + app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-05/gridModel.py b/wxPython/samples/wxPIA_book/Chapter-05/gridModel.py new file mode 100644 index 0000000000..d8a990b64f --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-05/gridModel.py @@ -0,0 +1,54 @@ +import wx +import wx.grid + +class LineupTable(wx.grid.PyGridTableBase): + + data = (("CF", "Bob", "Dernier"), ("2B", "Ryne", "Sandberg"), + ("LF", "Gary", "Matthews"), ("1B", "Leon", "Durham"), + ("RF", "Keith", "Moreland"), ("3B", "Ron", "Cey"), + ("C", "Jody", "Davis"), ("SS", "Larry", "Bowa"), + ("P", "Rick", "Sutcliffe")) + + colLabels = ("Last", "First") + + def __init__(self): + wx.grid.PyGridTableBase.__init__(self) + + def GetNumberRows(self): + return len(self.data) + + def GetNumberCols(self): + return len(self.data[0]) - 1 + + def GetColLabelValue(self, col): + return self.colLabels[col] + + def GetRowLabelValue(self, row): + return self.data[row][0] + + def IsEmptyCell(self, row, col): + return False + + def GetValue(self, row, col): + return self.data[row][col + 1] + + def SetValue(self, row, col, value): + pass + +class SimpleGrid(wx.grid.Grid): + def __init__(self, parent): + wx.grid.Grid.__init__(self, parent, -1) + self.SetTable(LineupTable()) + +class TestFrame(wx.Frame): + def __init__(self, parent): + wx.Frame.__init__(self, parent, -1, "A Grid", + size=(275, 275)) + grid = SimpleGrid(self) + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = TestFrame(None) + frame.Show(True) + app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-05/gridNoModel.py b/wxPython/samples/wxPIA_book/Chapter-05/gridNoModel.py new file mode 100644 index 0000000000..faf411c9a6 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-05/gridNoModel.py @@ -0,0 +1,49 @@ +import wx +import wx.grid + +class SimpleGrid(wx.grid.Grid): + def __init__(self, parent): + wx.grid.Grid.__init__(self, parent, -1) + self.CreateGrid(9, 2) + self.SetColLabelValue(0, "First") + self.SetColLabelValue(1, "Last") + self.SetRowLabelValue(0, "CF") + self.SetCellValue(0, 0, "Bob") + self.SetCellValue(0, 1, "Dernier") + self.SetRowLabelValue(1, "2B") + self.SetCellValue(1, 0, "Ryne") + self.SetCellValue(1, 1, "Sandberg") + self.SetRowLabelValue(2, "LF") + self.SetCellValue(2, 0, "Gary") + self.SetCellValue(2, 1, "Matthews") + self.SetRowLabelValue(3, "1B") + self.SetCellValue(3, 0, "Leon") + self.SetCellValue(3, 1, "Durham") + self.SetRowLabelValue(4, "RF") + self.SetCellValue(4, 0, "Keith") + self.SetCellValue(4, 1, "Moreland") + self.SetRowLabelValue(5, "3B") + self.SetCellValue(5, 0, "Ron") + self.SetCellValue(5, 1, "Cey") + self.SetRowLabelValue(6, "C") + self.SetCellValue(6, 0, "Jody") + self.SetCellValue(6, 1, "Davis") + self.SetRowLabelValue(7, "SS") + self.SetCellValue(7, 0, "Larry") + self.SetCellValue(7, 1, "Bowa") + self.SetRowLabelValue(8, "P") + self.SetCellValue(8, 0, "Rick") + self.SetCellValue(8, 1, "Sutcliffe") + +class TestFrame(wx.Frame): + def __init__(self, parent): + wx.Frame.__init__(self, parent, -1, "A Grid", + size=(275, 275)) + grid = SimpleGrid(self) + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = TestFrame(None) + frame.Show(True) + app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-05/lineuptable.py b/wxPython/samples/wxPIA_book/Chapter-05/lineuptable.py new file mode 100644 index 0000000000..f0925e978e --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-05/lineuptable.py @@ -0,0 +1,41 @@ +import wx +import wx.grid + +class LineupEntry: + + def __init__(self, pos, first, last): + self.pos = pos + self.first = first + self.last = last + +class LineupTable(wx.grid.PyGridTableBase): + + colLabels = ("First", "Last") + colAttrs = ("first", "last") + + def __init__(self, entries): + wx.grid.PyGridTableBase.__init__(self) + self.entries = entries + + def GetNumberRows(self): + return len(self.entries) + + def GetNumberCols(self): + return 2 + + def GetColLabelValue(self, col): + return self.colLabels[col] + + def GetRowLabelValue(self, col): + return self.entries[row].pos + + def IsEmptyCell(self, row, col): + return False + + def GetValue(self, row, col): + entry = self.entries[row] + return getattr(entry, self.colAttrs[col]) + + def SetValue(self, row, col, value): + pass + diff --git a/wxPython/samples/wxPIA_book/Chapter-05/modelExample.py b/wxPython/samples/wxPIA_book/Chapter-05/modelExample.py new file mode 100644 index 0000000000..be3c6878d5 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-05/modelExample.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python + +import wx +import abstractmodel + +class SimpleName(abstractmodel.AbstractModel): + + def __init__(self, first="", last=""): + abstractmodel.AbstractModel.__init__(self) + self.set(first, last) + + def set(self, first, last): + self.first = first + self.last = last + self.update() + +class ModelExample(wx.Frame): + + def __init__(self, parent, id): + wx.Frame.__init__(self, parent, id, 'Flintstones', + size=(340, 200)) + panel = wx.Panel(self) + panel.SetBackgroundColour("White") + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + self.textFields = {} + self.createTextFields(panel) + self.model = SimpleName() + self.model.addListener(self.OnUpdate) + self.createButtonBar(panel) + + def buttonData(self): + return (("Fredify", self.OnFred), + ("Wilmafy", self.OnWilma), + ("Barnify", self.OnBarney), + ("Bettify", self.OnBetty)) + + def createButtonBar(self, panel, yPos = 0): + xPos = 0 + for eachLabel, eachHandler in self.buttonData(): + pos = (xPos, yPos) + button = self.buildOneButton(panel, eachLabel, eachHandler, pos) + xPos += button.GetSize().width + + def buildOneButton(self, parent, label, handler, pos=(0,0)): + button = wx.Button(parent, -1, label, pos) + self.Bind(wx.EVT_BUTTON, handler, button) + return button + + def textFieldData(self): + return (("First Name", (10, 50)), + ("Last Name", (10, 80))) + + def createTextFields(self, panel): + for eachLabel, eachPos in self.textFieldData(): + self.createCaptionedText(panel, eachLabel, eachPos) + + def createCaptionedText(self, panel, label, pos): + static = wx.StaticText(panel, wx.NewId(), label, pos) + static.SetBackgroundColour("White") + textPos = (pos[0] + 75, pos[1]) + self.textFields[label] = wx.TextCtrl(panel, wx.NewId(), + "", size=(100, -1), pos=textPos, + style=wx.TE_READONLY) + + def OnUpdate(self, model): + self.textFields["First Name"].SetValue(model.first) + self.textFields["Last Name"].SetValue(model.last) + + def OnFred(self, event): + self.model.set("Fred", "Flintstone") + + def OnBarney(self, event): + self.model.set("Barney", "Rubble") + + def OnWilma(self, event): + self.model.set("Wilma", "Flintstone") + + def OnBetty(self, event): + self.model.set("Betty", "Rubble") + + def OnCloseWindow(self, event): + self.Destroy() + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = ModelExample(parent=None, id=-1) + frame.Show() + app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-05/testEventExample.py b/wxPython/samples/wxPIA_book/Chapter-05/testEventExample.py new file mode 100644 index 0000000000..321a4b4af1 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-05/testEventExample.py @@ -0,0 +1,37 @@ +import unittest +import modelExample +import wx + +class TestExample(unittest.TestCase): + + def setUp(self): + self.app = wx.PySimpleApp() + self.frame = modelExample.ModelExample(parent=None, id=-1) + + def tearDown(self): + self.frame.Destroy() + + def testModel(self): + self.frame.OnBarney(None) + self.assertEqual("Barney", self.frame.model.first, + msg="First is wrong") + self.assertEqual("Rubble", self.frame.model.last) + + def testEvent(self): + panel = self.frame.GetChildren()[0] + for each in panel.GetChildren(): + if each.GetLabel() == "Wilmafy": + wilma = each + break + event = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, wilma.GetId()) + wilma.GetEventHandler().ProcessEvent(event) + self.assertEqual("Wilma", self.frame.model.first) + self.assertEqual("Flintstone", self.frame.model.last) + +def suite(): + suite = unittest.makeSuite(TestExample, 'test') + return suite + +if __name__ == '__main__': + unittest.main(defaultTest='suite') + diff --git a/wxPython/samples/wxPIA_book/Chapter-05/testExample.py b/wxPython/samples/wxPIA_book/Chapter-05/testExample.py new file mode 100644 index 0000000000..9015cebc71 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-05/testExample.py @@ -0,0 +1,26 @@ +import unittest +import modelExample +import wx + +class TestExample(unittest.TestCase): + + def setUp(self): + self.app = wx.PySimpleApp() + self.frame = modelExample.ModelExample(parent=None, id=-1) + + def tearDown(self): + self.frame.Destroy() + + def testModel(self): + self.frame.OnBarney(None) + self.assertEqual("Barney", self.frame.model.first, + msg="First is wrong") + self.assertEqual("Rubble", self.frame.model.last) + +def suite(): + suite = unittest.makeSuite(TestExample, 'test') + return suite + +if __name__ == '__main__': + unittest.main(defaultTest='suite') + diff --git a/wxPython/samples/wxPIA_book/Chapter-06/example1.py b/wxPython/samples/wxPIA_book/Chapter-06/example1.py new file mode 100644 index 0000000000..9ff11652e1 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-06/example1.py @@ -0,0 +1,106 @@ +import wx + + +class SketchWindow(wx.Window): + def __init__(self, parent, ID): + wx.Window.__init__(self, parent, ID) + self.SetBackgroundColour("White") + self.color = "Black" + self.thickness = 1 + self.pen = wx.Pen(self.color, self.thickness, wx.SOLID) + self.lines = [] + self.curLine = [] + self.pos = (0, 0) + self.InitBuffer() + + self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) + self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) + self.Bind(wx.EVT_MOTION, self.OnMotion) + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_IDLE, self.OnIdle) + self.Bind(wx.EVT_PAINT, self.OnPaint) + + def InitBuffer(self): + size = self.GetClientSize() + #self.buffer = wx.EmptyBitmap(max(1, size.width), max(1, size.height)) + self.buffer = wx.EmptyBitmap(size.width, size.height) + if self.buffer.Ok(): + dc = wx.BufferedDC(None, self.buffer) + dc.SetBackground(wx.Brush(self.GetBackgroundColour())) + dc.Clear() + self.DrawLines(dc) + self.reInitBuffer = False + + def GetLinesData(self): + return self.lines[:] + + def SetLinesData(self, lines): + self.lines = lines[:] + self.InitBuffer() + self.Refresh() + + def OnLeftDown(self, event): + self.curLine = [] + self.pos = event.GetPositionTuple() + self.CaptureMouse() + + def OnLeftUp(self, event): + if self.HasCapture(): + self.lines.append((self.color, + self.thickness, + self.curLine)) + self.curLine = [] + self.ReleaseMouse() + + def OnMotion(self, event): + if event.Dragging() and event.LeftIsDown(): + dc = wx.BufferedDC(wx.ClientDC(self), self.buffer) + self.drawMotion(dc, event) + event.Skip() + + def drawMotion(self, dc, event): + dc.SetPen(self.pen) + newPos = event.GetPositionTuple() + coords = self.pos + newPos + self.curLine.append(coords) + dc.DrawLine(*coords) + self.pos = newPos + + def OnSize(self, event): + self.reInitBuffer = True + + def OnIdle(self, event): + if self.reInitBuffer: + self.InitBuffer() + self.Refresh(False) + + def OnPaint(self, event): + dc = wx.BufferedPaintDC(self, self.buffer) + + def DrawLines(self, dc): + for colour, thickness, line in self.lines: + pen = wx.Pen(colour, thickness, wx.SOLID) + dc.SetPen(pen) + for coords in line: + dc.DrawLine(*coords) + + def SetColor(self, color): + self.color = color + self.pen = wx.Pen(self.color, self.thickness, wx.SOLID) + + def SetThickness(self, num): + self.thickness = num + self.pen = wx.Pen(self.color, self.thickness, wx.SOLID) + + +class SketchFrame(wx.Frame): + def __init__(self, parent): + wx.Frame.__init__(self, parent, -1, "Sketch Frame", + size=(800,600)) + self.sketch = SketchWindow(self, -1) + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = SketchFrame(None) + frame.Show(True) + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-06/example2.py b/wxPython/samples/wxPIA_book/Chapter-06/example2.py new file mode 100644 index 0000000000..9b0ddeadc1 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-06/example2.py @@ -0,0 +1,21 @@ +import wx +from example1 import SketchWindow + + +class SketchFrame(wx.Frame): + def __init__(self, parent): + wx.Frame.__init__(self, parent, -1, "Sketch Frame", + size=(800,600)) + self.sketch = SketchWindow(self, -1) + self.sketch.Bind(wx.EVT_MOTION, self.OnSketchMotion) + self.statusbar = self.CreateStatusBar() + + def OnSketchMotion(self, event): + self.statusbar.SetStatusText(str(event.GetPositionTuple())) + event.Skip() + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = SketchFrame(None) + frame.Show(True) + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-06/example3.py b/wxPython/samples/wxPIA_book/Chapter-06/example3.py new file mode 100644 index 0000000000..240fa380b7 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-06/example3.py @@ -0,0 +1,27 @@ +import wx +from example1 import SketchWindow + +class SketchFrame(wx.Frame): + def __init__(self, parent): + wx.Frame.__init__(self, parent, -1, "Sketch Frame", + size=(800,600)) + self.sketch = SketchWindow(self, -1) + self.sketch.Bind(wx.EVT_MOTION, self.OnSketchMotion) + self.statusbar = self.CreateStatusBar() + self.statusbar.SetFieldsCount(3) + self.statusbar.SetStatusWidths([-1, -2, -3]) + + def OnSketchMotion(self, event): + self.statusbar.SetStatusText("Pos: %s" % + str(event.GetPositionTuple()), 0) + self.statusbar.SetStatusText("Current Pts: %s" % + len(self.sketch.curLine), 1) + self.statusbar.SetStatusText("Line Count: %s" % + len(self.sketch.lines), 2) + event.Skip() + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = SketchFrame(None) + frame.Show(True) + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-06/example4.py b/wxPython/samples/wxPIA_book/Chapter-06/example4.py new file mode 100644 index 0000000000..05bc7d7e53 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-06/example4.py @@ -0,0 +1,92 @@ +import wx +from example1 import SketchWindow + + +class SketchFrame(wx.Frame): + def __init__(self, parent): + wx.Frame.__init__(self, parent, -1, "Sketch Frame", + size=(800,600)) + self.sketch = SketchWindow(self, -1) + self.sketch.Bind(wx.EVT_MOTION, self.OnSketchMotion) + self.initStatusBar() + self.createMenuBar() + + def initStatusBar(self): + self.statusbar = self.CreateStatusBar() + self.statusbar.SetFieldsCount(3) + self.statusbar.SetStatusWidths([-1, -2, -3]) + + def OnSketchMotion(self, event): + self.statusbar.SetStatusText("Pos: %s" % + str(event.GetPositionTuple()), 0) + self.statusbar.SetStatusText("Current Pts: %s" % + len(self.sketch.curLine), 1) + self.statusbar.SetStatusText("Line Count: %s" % + len(self.sketch.lines), 2) + event.Skip() + + def menuData(self): + return [("&File", ( + ("&New", "New Sketch file", self.OnNew), + ("&Open", "Open sketch file", self.OnOpen), + ("&Save", "Save sketch file", self.OnSave), + ("", "", ""), + ("&Color", ( + ("&Black", "", self.OnColor, + wx.ITEM_RADIO), + ("&Red", "", self.OnColor, + wx.ITEM_RADIO), + ("&Green", "", self.OnColor, + wx.ITEM_RADIO), + ("&Blue", "", self.OnColor, + wx.ITEM_RADIO))), + ("", "", ""), + ("&Quit", "Quit", self.OnCloseWindow)))] + + def createMenuBar(self): + menuBar = wx.MenuBar() + for eachMenuData in self.menuData(): + menuLabel = eachMenuData[0] + menuItems = eachMenuData[1] + menuBar.Append(self.createMenu(menuItems), menuLabel) + self.SetMenuBar(menuBar) + + def createMenu(self, menuData): + menu = wx.Menu() + for eachItem in menuData: + if len(eachItem) == 2: + label = eachItem[0] + subMenu = self.createMenu(eachItem[1]) + menu.AppendMenu(wx.NewId(), label, subMenu) + else: + self.createMenuItem(menu, *eachItem) + return menu + + def createMenuItem(self, menu, label, status, handler, + kind=wx.ITEM_NORMAL): + if not label: + menu.AppendSeparator() + return + menuItem = menu.Append(-1, label, status, kind) + self.Bind(wx.EVT_MENU, handler, menuItem) + + def OnNew(self, event): pass + def OnOpen(self, event): pass + def OnSave(self, event): pass + + def OnColor(self, event): + menubar = self.GetMenuBar() + itemId = event.GetId() + item = menubar.FindItemById(itemId) + color = item.GetLabel() + self.sketch.SetColor(color) + + def OnCloseWindow(self, event): + self.Destroy() + + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = SketchFrame(None) + frame.Show(True) + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-06/example5.py b/wxPython/samples/wxPIA_book/Chapter-06/example5.py new file mode 100644 index 0000000000..cbe02138fa --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-06/example5.py @@ -0,0 +1,132 @@ +import wx +from example1 import SketchWindow + + +class SketchFrame(wx.Frame): + def __init__(self, parent): + wx.Frame.__init__(self, parent, -1, "Sketch Frame", + size=(800,600)) + self.sketch = SketchWindow(self, -1) + self.sketch.Bind(wx.EVT_MOTION, self.OnSketchMotion) + self.initStatusBar() + self.createMenuBar() + self.createToolBar() + + def initStatusBar(self): + self.statusbar = self.CreateStatusBar() + self.statusbar.SetFieldsCount(3) + self.statusbar.SetStatusWidths([-1, -2, -3]) + + def OnSketchMotion(self, event): + self.statusbar.SetStatusText("Pos: %s" % + str(event.GetPositionTuple()), 0) + self.statusbar.SetStatusText("Current Pts: %s" % + len(self.sketch.curLine), 1) + self.statusbar.SetStatusText("Line Count: %s" % + len(self.sketch.lines), 2) + event.Skip() + + def menuData(self): + return [("&File", ( + ("&New", "New Sketch file", self.OnNew), + ("&Open", "Open sketch file", self.OnOpen), + ("&Save", "Save sketch file", self.OnSave), + ("", "", ""), + ("&Color", ( + ("&Black", "", self.OnColor, wx.ITEM_RADIO), + ("&Red", "", self.OnColor, wx.ITEM_RADIO), + ("&Green", "", self.OnColor, wx.ITEM_RADIO), + ("&Blue", "", self.OnColor, wx.ITEM_RADIO))), + ("", "", ""), + ("&Quit", "Quit", self.OnCloseWindow)))] + + def createMenuBar(self): + menuBar = wx.MenuBar() + for eachMenuData in self.menuData(): + menuLabel = eachMenuData[0] + menuItems = eachMenuData[1] + menuBar.Append(self.createMenu(menuItems), menuLabel) + self.SetMenuBar(menuBar) + + def createMenu(self, menuData): + menu = wx.Menu() + for eachItem in menuData: + if len(eachItem) == 2: + label = eachItem[0] + subMenu = self.createMenu(eachItem[1]) + menu.AppendMenu(wx.NewId(), label, subMenu) + else: + self.createMenuItem(menu, *eachItem) + return menu + + def createMenuItem(self, menu, label, status, handler, kind=wx.ITEM_NORMAL): + if not label: + menu.AppendSeparator() + return + menuItem = menu.Append(-1, label, status, kind) + self.Bind(wx.EVT_MENU, handler, menuItem) + + def createToolBar(self): + toolbar = self.CreateToolBar() + for each in self.toolbarData(): + self.createSimpleTool(toolbar, *each) + toolbar.AddSeparator() + for each in self.toolbarColorData(): + self.createColorTool(toolbar, each) + toolbar.Realize() + + def createSimpleTool(self, toolbar, label, filename, help, handler): + if not label: + toolbar.AddSeparator() + return + bmp = wx.Image(filename, wx.BITMAP_TYPE_BMP).ConvertToBitmap() + tool = toolbar.AddSimpleTool(-1, bmp, label, help) + self.Bind(wx.EVT_MENU, handler, tool) + + def toolbarData(self): + return (("New", "new.bmp", "Create new sketch", self.OnNew), + ("", "", "", ""), + ("Open", "open.bmp", "Open existing sketch", self.OnOpen), + ("Save", "save.bmp", "Save existing sketch", self.OnSave)) + + def createColorTool(self, toolbar, color): + bmp = self.MakeBitmap(color) + tool = toolbar.AddRadioTool(-1, bmp, shortHelp=color) + self.Bind(wx.EVT_MENU, self.OnColor, tool) + + def MakeBitmap(self, color): + bmp = wx.EmptyBitmap(16, 15) + dc = wx.MemoryDC() + dc.SelectObject(bmp) + dc.SetBackground(wx.Brush(color)) + dc.Clear() + dc.SelectObject(wx.NullBitmap) + return bmp + + def toolbarColorData(self): + return ("Black", "Red", "Green", "Blue") + + def OnNew(self, event): pass + def OnOpen(self, event): pass + def OnSave(self, event): pass + + def OnColor(self, event): + menubar = self.GetMenuBar() + itemId = event.GetId() + item = menubar.FindItemById(itemId) + if not item: + toolbar = self.GetToolBar() + item = toolbar.FindById(itemId) + color = item.GetShortHelp() + else: + color = item.GetLabel() + self.sketch.SetColor(color) + + def OnCloseWindow(self, event): + self.Destroy() + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = SketchFrame(None) + frame.Show(True) + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-06/example6.py b/wxPython/samples/wxPIA_book/Chapter-06/example6.py new file mode 100644 index 0000000000..9d58f06517 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-06/example6.py @@ -0,0 +1,192 @@ +import wx +import cPickle +import os + +from example1 import SketchWindow + + +class SketchFrame(wx.Frame): + def __init__(self, parent): + self.title = "Sketch Frame" + wx.Frame.__init__(self, parent, -1, self.title, + size=(800,600)) + self.filename = "" + self.sketch = SketchWindow(self, -1) + self.sketch.Bind(wx.EVT_MOTION, self.OnSketchMotion) + self.initStatusBar() + self.createMenuBar() + self.createToolBar() + + def initStatusBar(self): + self.statusbar = self.CreateStatusBar() + self.statusbar.SetFieldsCount(3) + self.statusbar.SetStatusWidths([-1, -2, -3]) + + def OnSketchMotion(self, event): + self.statusbar.SetStatusText("Pos: %s" % + str(event.GetPositionTuple()), 0) + self.statusbar.SetStatusText("Current Pts: %s" % + len(self.sketch.curLine), 1) + self.statusbar.SetStatusText("Line Count: %s" % + len(self.sketch.lines), 2) + event.Skip() + + def menuData(self): + return [("&File", ( + ("&New", "New Sketch file", self.OnNew), + ("&Open", "Open sketch file", self.OnOpen), + ("&Save", "Save sketch file", self.OnSave), + ("", "", ""), + ("&Color", ( + ("&Black", "", self.OnColor, wx.ITEM_RADIO), + ("&Red", "", self.OnColor, wx.ITEM_RADIO), + ("&Green", "", self.OnColor, wx.ITEM_RADIO), + ("&Blue", "", self.OnColor, wx.ITEM_RADIO), + ("&Other...", "", self.OnOtherColor, wx.ITEM_RADIO))), + ("", "", ""), + ("&Quit", "Quit", self.OnCloseWindow)))] + + def createMenuBar(self): + menuBar = wx.MenuBar() + for eachMenuData in self.menuData(): + menuLabel = eachMenuData[0] + menuItems = eachMenuData[1] + menuBar.Append(self.createMenu(menuItems), menuLabel) + self.SetMenuBar(menuBar) + + def createMenu(self, menuData): + menu = wx.Menu() + for eachItem in menuData: + if len(eachItem) == 2: + label = eachItem[0] + subMenu = self.createMenu(eachItem[1]) + menu.AppendMenu(wx.NewId(), label, subMenu) + else: + self.createMenuItem(menu, *eachItem) + return menu + + def createMenuItem(self, menu, label, status, handler, kind=wx.ITEM_NORMAL): + if not label: + menu.AppendSeparator() + return + menuItem = menu.Append(-1, label, status, kind) + self.Bind(wx.EVT_MENU, handler, menuItem) + + def createToolBar(self): + toolbar = self.CreateToolBar() + for each in self.toolbarData(): + self.createSimpleTool(toolbar, *each) + toolbar.AddSeparator() + for each in self.toolbarColorData(): + self.createColorTool(toolbar, each) + toolbar.Realize() + + def createSimpleTool(self, toolbar, label, filename, help, handler): + if not label: + toolbar.AddSeparator() + return + bmp = wx.Image(filename, wx.BITMAP_TYPE_BMP).ConvertToBitmap() + tool = toolbar.AddSimpleTool(-1, bmp, label, help) + self.Bind(wx.EVT_MENU, handler, tool) + + def toolbarData(self): + return (("New", "new.bmp", "Create new sketch", self.OnNew), + ("", "", "", ""), + ("Open", "open.bmp", "Open existing sketch", self.OnOpen), + ("Save", "save.bmp", "Save existing sketch", self.OnSave)) + + def createColorTool(self, toolbar, color): + bmp = self.MakeBitmap(color) + tool = toolbar.AddRadioTool(-1, bmp, shortHelp=color) + self.Bind(wx.EVT_MENU, self.OnColor, tool) + + def MakeBitmap(self, color): + bmp = wx.EmptyBitmap(16, 15) + dc = wx.MemoryDC() + dc.SelectObject(bmp) + dc.SetBackground(wx.Brush(color)) + dc.Clear() + dc.SelectObject(wx.NullBitmap) + return bmp + + def toolbarColorData(self): + return ("Black", "Red", "Green", "Blue") + + def OnNew(self, event): pass + + def OnColor(self, event): + menubar = self.GetMenuBar() + itemId = event.GetId() + item = menubar.FindItemById(itemId) + if not item: + toolbar = self.GetToolBar() + item = toolbar.FindById(itemId) + color = item.GetShortHelp() + else: + color = item.GetLabel() + self.sketch.SetColor(color) + + def OnCloseWindow(self, event): + self.Destroy() + + def SaveFile(self): + if self.filename: + data = self.sketch.GetLinesData() + f = open(self.filename, 'w') + cPickle.dump(data, f) + f.close() + + def ReadFile(self): + if self.filename: + try: + f = open(self.filename, 'r') + data = cPickle.load(f) + f.close() + self.sketch.SetLinesData(data) + except cPickle.UnpicklingError: + wx.MessageBox("%s is not a sketch file." % self.filename, + "oops!", style=wx.OK|wx.ICON_EXCLAMATION) + + wildcard = "Sketch files (*.sketch)|*.sketch|All files (*.*)|*.*" + + def OnOpen(self, event): + dlg = wx.FileDialog(self, "Open sketch file...", os.getcwd(), + style=wx.OPEN, wildcard=self.wildcard) + if dlg.ShowModal() == wx.ID_OK: + self.filename = dlg.GetPath() + self.ReadFile() + self.SetTitle(self.title + ' -- ' + self.filename) + dlg.Destroy() + + def OnSave(self, event): + if not self.filename: + self.OnSaveAs(event) + else: + self.SaveFile() + + def OnSaveAs(self, event): + dlg = wx.FileDialog(self, "Save sketch as...", os.getcwd(), + style=wx.SAVE | wx.OVERWRITE_PROMPT, + wildcard = self.wildcard) + if dlg.ShowModal() == wx.ID_OK: + filename = dlg.GetPath() + if not os.path.splitext(filename)[1]: + filename = filename + '.sketch' + self.filename = filename + self.SaveFile() + self.SetTitle(self.title + ' -- ' + self.filename) + dlg.Destroy() + + def OnOtherColor(self, event): + dlg = wx.ColourDialog(frame) + dlg.GetColourData().SetChooseFull(True) + if dlg.ShowModal() == wx.ID_OK: + self.sketch.SetColor(dlg.GetColourData().GetColour()) + dlg.Destroy() + + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = SketchFrame(None) + frame.Show(True) + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-06/example7.py b/wxPython/samples/wxPIA_book/Chapter-06/example7.py new file mode 100644 index 0000000000..626827fbe0 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-06/example7.py @@ -0,0 +1,331 @@ +import wx +import wx.html +import cPickle +import os +from wx.lib import buttons + +from example1 import SketchWindow + +class SketchFrame(wx.Frame): + def __init__(self, parent): + self.title = "Sketch Frame" + wx.Frame.__init__(self, parent, -1, self.title, + size=(800,600)) + self.filename = "" + self.sketch = SketchWindow(self, -1) + wx.EVT_MOTION(self.sketch, self.OnSketchMotion) + self.initStatusBar() + self.createMenuBar() + self.createToolBar() + self.createPanel() + + def createPanel(self): + controlPanel = ControlPanel(self, -1, self.sketch) + box = wx.BoxSizer(wx.HORIZONTAL) + box.Add(controlPanel, 0, wx.EXPAND) + box.Add(self.sketch, 1, wx.EXPAND) + self.SetSizer(box) + + def initStatusBar(self): + self.statusbar = self.CreateStatusBar() + self.statusbar.SetFieldsCount(3) + self.statusbar.SetStatusWidths([-1, -2, -3]) + + def OnSketchMotion(self, event): + self.statusbar.SetStatusText("Pos: %s" % + str(event.GetPositionTuple()), 0) + self.statusbar.SetStatusText("Current Pts: %s" % + len(self.sketch.curLine), 1) + self.statusbar.SetStatusText("Line Count: %s" % + len(self.sketch.lines), 2) + event.Skip() + + def menuData(self): + return [("&File", ( + ("&New", "New Sketch file", self.OnNew), + ("&Open", "Open sketch file", self.OnOpen), + ("&Save", "Save sketch file", self.OnSave), + ("", "", ""), + ("&Color", ( + ("&Black", "", self.OnColor, wx.ITEM_RADIO), + ("&Red", "", self.OnColor, wx.ITEM_RADIO), + ("&Green", "", self.OnColor, wx.ITEM_RADIO), + ("&Blue", "", self.OnColor, wx.ITEM_RADIO), + ("&Other...", "", self.OnOtherColor, wx.ITEM_RADIO))), + ("", "", ""), + ("About...", "Show about window", self.OnAbout), + ("&Quit", "Quit", self.OnCloseWindow)))] + + def createMenuBar(self): + menuBar = wx.MenuBar() + for eachMenuData in self.menuData(): + menuLabel = eachMenuData[0] + menuItems = eachMenuData[1] + menuBar.Append(self.createMenu(menuItems), menuLabel) + self.SetMenuBar(menuBar) + + def createMenu(self, menuData): + menu = wx.Menu() + for eachItem in menuData: + if len(eachItem) == 2: + label = eachItem[0] + subMenu = self.createMenu(eachItem[1]) + menu.AppendMenu(wx.NewId(), label, subMenu) + else: + self.createMenuItem(menu, *eachItem) + return menu + + def createMenuItem(self, menu, label, status, handler, kind=wx.ITEM_NORMAL): + if not label: + menu.AppendSeparator() + return + menuItem = menu.Append(-1, label, status, kind) + self.Bind(wx.EVT_MENU, handler, menuItem) + + def createToolBar(self): + toolbar = self.CreateToolBar() + for each in self.toolbarData(): + self.createSimpleTool(toolbar, *each) + toolbar.AddSeparator() + for each in self.toolbarColorData(): + self.createColorTool(toolbar, each) + toolbar.Realize() + + def createSimpleTool(self, toolbar, label, filename, help, handler): + if not label: + toolbar.AddSeparator() + return + bmp = wx.Image(filename, wx.BITMAP_TYPE_BMP).ConvertToBitmap() + tool = toolbar.AddSimpleTool(-1, bmp, label, help) + self.Bind(wx.EVT_MENU, handler, tool) + + def toolbarData(self): + return (("New", "new.bmp", "Create new sketch", self.OnNew), + ("", "", "", ""), + ("Open", "open.bmp", "Open existing sketch", self.OnOpen), + ("Save", "save.bmp", "Save existing sketch", self.OnSave)) + + def createColorTool(self, toolbar, color): + bmp = self.MakeBitmap(color) + tool = toolbar.AddRadioTool(-1, bmp, shortHelp=color) + self.Bind(wx.EVT_MENU, self.OnColor, tool) + + def MakeBitmap(self, color): + bmp = wx.EmptyBitmap(16, 15) + dc = wx.MemoryDC() + dc.SelectObject(bmp) + dc.SetBackground(wx.Brush(color)) + dc.Clear() + dc.SelectObject(wx.NullBitmap) + return bmp + + def toolbarColorData(self): + return ("Black", "Red", "Green", "Blue") + + def OnNew(self, event): pass + + def OnColor(self, event): + menubar = self.GetMenuBar() + itemId = event.GetId() + item = menubar.FindItemById(itemId) + if not item: + toolbar = self.GetToolBar() + item = toolbar.FindById(itemId) + color = item.GetShortHelp() + else: + color = item.GetLabel() + self.sketch.SetColor(color) + + def OnCloseWindow(self, event): + self.Destroy() + + def SaveFile(self): + if self.filename: + data = self.sketch.GetLinesData() + f = open(self.filename, 'w') + cPickle.dump(data, f) + f.close() + + def ReadFile(self): + if self.filename: + try: + f = open(self.filename, 'r') + data = cPickle.load(f) + f.close() + self.sketch.SetLinesData(data) + except cPickle.UnpicklingError: + wx.MessageBox("%s is not a sketch file." % self.filename, + "oops!", style=wx.OK|wx.ICON_EXCLAMATION) + + wildcard = "Sketch files (*.sketch)|*.sketch|All files (*.*)|*.*" + + def OnOpen(self, event): + dlg = wx.FileDialog(self, "Open sketch file...", os.getcwd(), + style=wx.OPEN, wildcard=self.wildcard) + if dlg.ShowModal() == wx.ID_OK: + self.filename = dlg.GetPath() + self.ReadFile() + self.SetTitle(self.title + ' -- ' + self.filename) + dlg.Destroy() + + def OnSave(self, event): + if not self.filename: + self.OnSaveAs(event) + else: + self.SaveFile() + + def OnSaveAs(self, event): + dlg = wx.FileDialog(self, "Save sketch as...", os.getcwd(), + style=wx.SAVE | wx.OVERWRITE_PROMPT, + wildcard = self.wildcard) + if dlg.ShowModal() == wx.ID_OK: + filename = dlg.GetPath() + if not os.path.splitext(filename)[1]: + filename = filename + '.sketch' + self.filename = filename + self.SaveFile() + self.SetTitle(self.title + ' -- ' + self.filename) + dlg.Destroy() + + def OnOtherColor(self, event): + dlg = wx.ColourDialog(frame) + dlg.GetColourData().SetChooseFull(True) + if dlg.ShowModal() == wx.ID_OK: + self.sketch.SetColor(dlg.GetColourData().GetColour()) + dlg.Destroy() + + def OnAbout(self, event): + dlg = SketchAbout(self) + dlg.ShowModal() + dlg.Destroy() + + +class SketchAbout(wx.Dialog): + text = ''' + + +
+ + + +

Sketch!

+
+

Sketch is a demonstration program for wxPython In Action +Chapter 7. It is based on the SuperDoodle demo included with wxPython, +available at http://www.wxpython.org/ +

+ +

SuperDoodle and wxPython are brought to you by +Robin Dunn and Total Control Software, Copyright +© 1997-2006.

+ + +''' + + def __init__(self, parent): + wx.Dialog.__init__(self, parent, -1, 'About Sketch', + size=(440, 400) ) + + html = wx.html.HtmlWindow(self) + html.SetPage(self.text) + button = wx.Button(self, wx.ID_OK, "Okay") + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(html, 1, wx.EXPAND|wx.ALL, 5) + sizer.Add(button, 0, wx.ALIGN_CENTER|wx.ALL, 5) + + self.SetSizer(sizer) + self.Layout() + + + +class ControlPanel(wx.Panel): + + BMP_SIZE = 16 + BMP_BORDER = 3 + NUM_COLS = 4 + SPACING = 4 + + colorList = ('Black', 'Yellow', 'Red', 'Green', 'Blue', 'Purple', + 'Brown', 'Aquamarine', 'Forest Green', 'Light Blue', + 'Goldenrod', 'Cyan', 'Orange', 'Navy', 'Dark Grey', + 'Light Grey') + maxThickness = 16 + + def __init__(self, parent, ID, sketch): + wx.Panel.__init__(self, parent, ID, style=wx.RAISED_BORDER) + self.sketch = sketch + buttonSize = (self.BMP_SIZE + 2 * self.BMP_BORDER, + self.BMP_SIZE + 2 * self.BMP_BORDER) + colorGrid = self.createColorGrid(parent, buttonSize) + thicknessGrid = self.createThicknessGrid(buttonSize) + self.layout(colorGrid, thicknessGrid) + + def createColorGrid(self, parent, buttonSize): + self.colorMap = {} + self.colorButtons = {} + colorGrid = wx.GridSizer(cols=self.NUM_COLS, hgap=2, vgap=2) + for eachColor in self.colorList: + bmp = parent.MakeBitmap(eachColor) + b = buttons.GenBitmapToggleButton(self, -1, bmp, size=buttonSize) + b.SetBezelWidth(1) + b.SetUseFocusIndicator(False) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, b) + colorGrid.Add(b, 0) + self.colorMap[b.GetId()] = eachColor + self.colorButtons[eachColor] = b + self.colorButtons[self.colorList[0]].SetToggle(True) + return colorGrid + + def createThicknessGrid(self, buttonSize): + self.thicknessIdMap = {} + self.thicknessButtons = {} + thicknessGrid = wx.GridSizer(cols=self.NUM_COLS, hgap=2, vgap=2) + for x in range(1, self.maxThickness + 1): + b = buttons.GenToggleButton(self, -1, str(x), size=buttonSize) + b.SetBezelWidth(1) + b.SetUseFocusIndicator(False) + self.Bind(wx.EVT_BUTTON, self.OnSetThickness, b) + thicknessGrid.Add(b, 0) + self.thicknessIdMap[b.GetId()] = x + self.thicknessButtons[x] = b + self.thicknessButtons[1].SetToggle(True) + return thicknessGrid + + def layout(self, colorGrid, thicknessGrid): + box = wx.BoxSizer(wx.VERTICAL) + box.Add(colorGrid, 0, wx.ALL, self.SPACING) + box.Add(thicknessGrid, 0, wx.ALL, self.SPACING) + self.SetSizer(box) + box.Fit(self) + + def OnSetColour(self, event): + color = self.colorMap[event.GetId()] + if color != self.sketch.color: + self.colorButtons[self.sketch.color].SetToggle(False) + self.sketch.SetColor(color) + + def OnSetThickness(self, event): + thickness = self.thicknessIdMap[event.GetId()] + if thickness != self.sketch.thickness: + self.thicknessButtons[self.sketch.thickness].SetToggle(False) + self.sketch.SetThickness(thickness) + + +class SketchApp(wx.App): + + def OnInit(self): + bmp = wx.Image("splash.png").ConvertToBitmap() + wx.SplashScreen(bmp, wx.SPLASH_CENTRE_ON_SCREEN | wx.SPLASH_TIMEOUT, + 1000, None, -1) + wx.Yield() + + frame = SketchFrame(None) + frame.Show(True) + self.SetTopWindow(frame) + return True + +if __name__ == '__main__': + app = SketchApp(False) + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-06/new.bmp b/wxPython/samples/wxPIA_book/Chapter-06/new.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d66feb2384ad4c626a078c995c1a3e49af78ec3c GIT binary patch literal 238 zcmbu2yA6Oa5JQcGL>b0l4tjP;1(ew=nJ8j|<6WY3bU0`GK9aK^RUId`!4(ELX-1{H u>6c`QQqJ8_T9s0iQsQ8(Wab^@`3kuPA_p->w)Xt4Pkz>06 literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-06/open.bmp b/wxPython/samples/wxPIA_book/Chapter-06/open.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1c38e97b59dac5b7dcb3d4ac14a31fe36d3fbc6e GIT binary patch literal 238 zcmZvVF%m){3`Ez_nP2KLES>QN_TFVHvE)eH08ZrCQ{W?L=aStGNg%iTOA8O|3{UU~ zcRHZbGxVQiiBQhVP*Szl@Yxs<8e?XVGfPPN!qmmh`zzRz%k)d~SOwQraPKkc3JUWb WyzyG%ebUB{{{0*7WXGE5t%V;V>_w>n literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-06/save.bmp b/wxPython/samples/wxPIA_book/Chapter-06/save.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9217b496c3b11ebde140c0ab78bb6e8c3462261e GIT binary patch literal 1318 zcmZ?rRbyoU12Yx|1`Qxf0Eqd4n2~`4ERLIKU|;|uhK2?R1tft?h64uFu(PB12*_n-hKPWe pAZcRxKwVJv%y59LA1Dox2MR&}R6Y582C(@E{p=t<3V>M!rvbtTA}s&_ literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-06/splash.png b/wxPython/samples/wxPIA_book/Chapter-06/splash.png new file mode 100644 index 0000000000000000000000000000000000000000..a2ae34cdb10410b1a52146a8c68bd2962ef74379 GIT binary patch literal 3923 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 AmH+?% literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-07/bitmap.bmp b/wxPython/samples/wxPIA_book/Chapter-07/bitmap.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b7eb51c9666682eff763ba7042365beb7de3a75c GIT binary patch literal 13054 zcmds-e@IqW7{|Z+cXJhuk*ykowtkI;77P}HoS|vxl2%Z>1~y{-B|$4=RNN|o^$U#_r3RhRodbt&%O7Y=RTkF zJkR-c-_q(28<76@Bmb`9|5E<{h5tW6A^!qBeE!d;>VNtM|GXO?cNP4N9EwZZoZfeH zJ;7?$BI;s>lfn{kkRAUb;}i{E^rhB#5@%_4Lbn6gGNHoxOlb6NH#Mj+_ZhvPCsmoWhcZ zR-hBmG}tg1A0;1un6~6EFRV%d4S=G-+CHp*jt%dFD50U18%O?DJ2X@QiUup%vFZi~ zf*{IlaX3uKF+~E}%DBc@ScNa@u&f2&U5|;9)E|M@&X)O>p3h6MpaP5cV%dpMl%Puz zam){ddP^iqJ{+5!7;|1J8coPS-vwW;_g3iY!kIHTc@h^d;^9N~yM9DLZXQ35=4PqG znncl{0S?_TqmvEIRs|&>3J2pQ4OrQU^}}>YjJOi>m1g$~#Zta%|9;fgioLgQGr+Vt zO2D2ysHu@UtT{L+0TximJN{OzzjG%J9KgAA(mikAN-IGrljY0uR;=x%OJZ|GJ3}~V z{;plvu|qnY@e|}A#Fj0B;#G*nL7m&S3H{l#HizYsDLW(VD-$y7JEfP|Yb;)Ohx9BV z=oQaladi@+r3E)`SkY*>glkFeS}bd=E9*&E4A78F%rM>=^>jUp5&k9$PM^k+BRF~# z7cNNJJK`!tCp|%kp&@H@FtUWpVy^H_m)KOABedgYZhrWHH*fIdi40aO6nM#-8l5B0 zvuC(>4_B_>(j@_X`V{Zp%~a4eO@S3?dvCAkeEb+ABbb=5nxtJ)3$z0R>0RWE!QuX} zTAQy@GDn`5FVWvG2C`7#r7;{y_K@t+BV4_T^XGB-vY1A)=+T#x$BP%}>l2;b-MD|> z8qWFZf)bu&)d0=u?edu61Vhwp6kHru*r<_}vG0w$s+Cpe)F~W1h{K1`-X0PvUJqGK z9BQe&1YqIXz7gnx906#X4N>2V%RvI>u${)HMM_3h6{@RIS0|}^{klKu(jPhIO>AfYZC*3pj|l~icCIYLofFEsB*%Q9!^b)t77Vm1lq2y=$&`&s2+$C=RVX)&D8(d&seZE z;zMB)e~`n6B8KRxn+I&Z?;lABEGGToggUt>pq>Tg(GbZwLQquXgnp088O77N6q|*^ z{mC|`xKb_&LCM+P$cA5`bU7-7!|~l&Lqz+-o6@!UreH-vq&d0OT!yl*QMC$n(%kVo z0L>9tC+a5|VOnw`wB%-8%vL1$7OC}U*u*n+a)kXZ!!$L(!5ijtkt0!v7}Kl@T4A1Hzy=&i-@K7MebX49U4 z9Fv3X94N|m9d$X=e2@AfG;T!mCbZE9njoVvV7Q58LPYyRsd1p_xH4(jiR{W~4;7<{ zMcH1Cj%sw(pl2ugl@Cau6h=71N1!ev;!1Z%I&!qV5yA`sKh+nFNS5-)l-z)>?pBX} zMYk%-_7sNdFhcs@F|G-yUqghN9C|YjhvyiocR^$bG`bS_!@S~g`T2n^v6Cs(*od3) zIXoH@C1ZZJgf!zis~ll$#3O@)wX(iMDwuuhb3lHV5oTt6l!POwEEabRxS-~wcWjQN Yt$p>AV)>fqb2+OV`52OC+y4*8zX}S|l>h($ literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-07/bitmap_button.py b/wxPython/samples/wxPIA_book/Chapter-07/bitmap_button.py new file mode 100644 index 0000000000..15a17773bd --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-07/bitmap_button.py @@ -0,0 +1,25 @@ +import wx + +class BitmapButtonFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, 'Bitmap Button Example', + size=(200, 150)) + panel = wx.Panel(self, -1) + bmp = wx.Image("bitmap.bmp", wx.BITMAP_TYPE_BMP).ConvertToBitmap() + self.button = wx.BitmapButton(panel, -1, bmp, pos=(10, 20)) + self.Bind(wx.EVT_BUTTON, self.OnClick, self.button) + self.button.SetDefault() + self.button2 = wx.BitmapButton(panel, -1, bmp, pos=(100, 20), + style=0) + self.Bind(wx.EVT_BUTTON, self.OnClick, self.button2) + + def OnClick(self, event): + self.Destroy() + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = BitmapButtonFrame() + frame.Show() + app.MainLoop() + + diff --git a/wxPython/samples/wxPIA_book/Chapter-07/button.py b/wxPython/samples/wxPIA_book/Chapter-07/button.py new file mode 100644 index 0000000000..009789af65 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-07/button.py @@ -0,0 +1,21 @@ +import wx + +class ButtonFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, 'Button Example', + size=(300, 100)) + panel = wx.Panel(self, -1) + self.button = wx.Button(panel, -1, "Hello", pos=(50, 20)) + self.Bind(wx.EVT_BUTTON, self.OnClick, self.button) + self.button.SetDefault() + + def OnClick(self, event): + self.button.SetLabel("Clicked") + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = ButtonFrame() + frame.Show() + app.MainLoop() + + diff --git a/wxPython/samples/wxPIA_book/Chapter-07/checkbox.py b/wxPython/samples/wxPIA_book/Chapter-07/checkbox.py new file mode 100644 index 0000000000..d03ab83c87 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-07/checkbox.py @@ -0,0 +1,16 @@ +import wx + +class CheckBoxFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, 'Checkbox Example', + size=(150, 200)) + panel = wx.Panel(self, -1) + wx.CheckBox(panel, -1, "Alpha", (35, 40), (150, 20)) + wx.CheckBox(panel, -1, "Beta", (35, 60), (150, 20)) + wx.CheckBox(panel, -1, "Gamma", (35, 80), (150, 20)) + +if __name__ == '__main__': + app = wx.PySimpleApp() + CheckBoxFrame().Show() + app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-07/choice.py b/wxPython/samples/wxPIA_book/Chapter-07/choice.py new file mode 100644 index 0000000000..704fd3b74b --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-07/choice.py @@ -0,0 +1,16 @@ +import wx + +class ChoiceFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, 'Choice Example', + size=(250, 200)) + panel = wx.Panel(self, -1) + sampleList = ['zero', 'one', 'two', 'three', 'four', 'five', + 'six', 'seven', 'eight'] + wx.StaticText(panel, -1, "Select one:", (15, 20)) + wx.Choice(panel, -1, (85, 18), choices=sampleList) + +if __name__ == '__main__': + app = wx.PySimpleApp() + ChoiceFrame().Show() + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-07/combo_box.py b/wxPython/samples/wxPIA_book/Chapter-07/combo_box.py new file mode 100644 index 0000000000..3e36f2517c --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-07/combo_box.py @@ -0,0 +1,19 @@ +import wx + +class ComboBoxFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, 'Combo Box Example', + size=(350, 300)) + panel = wx.Panel(self, -1) + sampleList = ['zero', 'one', 'two', 'three', 'four', 'five', + 'six', 'seven', 'eight'] + wx.StaticText(panel, -1, "Select one:", (15, 15)) + wx.ComboBox(panel, -1, "default value", (15, 30), wx.DefaultSize, + sampleList, wx.CB_DROPDOWN) + wx.ComboBox(panel, -1, "default value", (150, 30), wx.DefaultSize, + sampleList, wx.CB_SIMPLE) + +if __name__ == '__main__': + app = wx.PySimpleApp() + ComboBoxFrame().Show() + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-07/gauge.py b/wxPython/samples/wxPIA_book/Chapter-07/gauge.py new file mode 100644 index 0000000000..9a3b5cf91d --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-07/gauge.py @@ -0,0 +1,23 @@ +import wx + +class GaugeFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, 'Gauge Example', + size=(350, 150)) + panel = wx.Panel(self, -1) + self.count = 0 + self.gauge = wx.Gauge(panel, -1, 50, (20, 50), (250, 25)) + self.gauge.SetBezelFace(3) + self.gauge.SetShadowWidth(3) + self.Bind(wx.EVT_IDLE, self.OnIdle) + + def OnIdle(self, event): + self.count = self.count + 1 + if self.count >= 50: + self.count = 0 + self.gauge.SetValue(self.count) + +if __name__ == '__main__': + app = wx.PySimpleApp() + GaugeFrame().Show() + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-07/generic_button.py b/wxPython/samples/wxPIA_book/Chapter-07/generic_button.py new file mode 100644 index 0000000000..49c9d51fbd --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-07/generic_button.py @@ -0,0 +1,56 @@ +import wx +import wx.lib.buttons as buttons + +class GenericButtonFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, 'Generic Button Example', + size=(500, 350)) + panel = wx.Panel(self, -1) + + sizer = wx.FlexGridSizer(1, 3, 20, 20) + b = wx.Button(panel, -1, "A wx.Button") + b.SetDefault() + sizer.Add(b) + + b = wx.Button(panel, -1, "non-default wx.Button") + sizer.Add(b) + sizer.Add((10,10)) + + b = buttons.GenButton(panel, -1, 'Generic Button') + sizer.Add(b) + + b = buttons.GenButton(panel, -1, 'disabled Generic') + b.Enable(False) + sizer.Add(b) + + b = buttons.GenButton(panel, -1, 'bigger') + b.SetFont(wx.Font(20, wx.SWISS, wx.NORMAL, wx.BOLD, False)) + b.SetBezelWidth(5) + b.SetBackgroundColour("Navy") + b.SetForegroundColour("white") + b.SetToolTipString("This is a BIG button...") + sizer.Add(b) + + bmp = wx.Image("bitmap.bmp", wx.BITMAP_TYPE_BMP).ConvertToBitmap() + b = buttons.GenBitmapButton(panel, -1, bmp) + sizer.Add(b) + + b = buttons.GenBitmapToggleButton(panel, -1, bmp) + sizer.Add(b) + + b = buttons.GenBitmapTextButton(panel, -1, bmp, "Bitmapped Text", + size=(175, 75)) + b.SetUseFocusIndicator(False) + sizer.Add(b) + + b = buttons.GenToggleButton(panel, -1, "Toggle Button") + sizer.Add(b) + + panel.SetSizer(sizer) + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = GenericButtonFrame() + frame.Show() + app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-07/list_box.py b/wxPython/samples/wxPIA_book/Chapter-07/list_box.py new file mode 100644 index 0000000000..e7438d7d3a --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-07/list_box.py @@ -0,0 +1,21 @@ +import wx + +class ListBoxFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, 'List Box Example', + size=(250, 200)) + panel = wx.Panel(self, -1) + + sampleList = ['zero', 'one', 'two', 'three', 'four', 'five', + 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', + 'twelve', 'thirteen', 'fourteen'] + + listBox = wx.ListBox(panel, -1, (20, 20), (80, 120), sampleList, + wx.LB_SINGLE) + listBox.SetSelection(3) + +if __name__ == '__main__': + app = wx.PySimpleApp() + ListBoxFrame().Show() + app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-07/radio.py b/wxPython/samples/wxPIA_book/Chapter-07/radio.py new file mode 100644 index 0000000000..beb0efdd2d --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-07/radio.py @@ -0,0 +1,32 @@ +import wx + +class RadioButtonFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, 'Radio Example', + size=(200, 200)) + panel = wx.Panel(self, -1) + radio1 = wx.RadioButton(panel, -1, "Elmo", pos=(20, 50), style=wx.RB_GROUP) + radio2 = wx.RadioButton(panel, -1, "Ernie", pos=(20, 80)) + radio3 = wx.RadioButton(panel, -1, "Bert", pos=(20, 110)) + text1 = wx.TextCtrl(panel, -1, "", pos=(80, 50)) + text2 = wx.TextCtrl(panel, -1, "", pos=(80, 80)) + text3 = wx.TextCtrl(panel, -1, "", pos=(80, 110)) + self.texts = {"Elmo": text1, "Ernie": text2, "Bert": text3} + for eachText in [text2, text3]: + eachText.Enable(False) + for eachRadio in [radio1, radio2, radio3]: + self.Bind(wx.EVT_RADIOBUTTON, self.OnRadio, eachRadio) + self.selectedText = text1 + + def OnRadio(self, event): + if self.selectedText: + self.selectedText.Enable(False) + radioSelected = event.GetEventObject() + text = self.texts[radioSelected.GetLabel()] + text.Enable(True) + self.selectedText = text + +if __name__ == '__main__': + app = wx.PySimpleApp() + RadioButtonFrame().Show() + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-07/radio_box.py b/wxPython/samples/wxPIA_book/Chapter-07/radio_box.py new file mode 100644 index 0000000000..c7ae037b91 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-07/radio_box.py @@ -0,0 +1,19 @@ +import wx + +class RadioBoxFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, 'Radio Box Example', + size=(350, 200)) + panel = wx.Panel(self, -1) + sampleList = ['zero', 'one', 'two', 'three', 'four', 'five', + 'six', 'seven', 'eight'] + wx.RadioBox(panel, -1, "A Radio Box", (10, 10), wx.DefaultSize, + sampleList, 2, wx.RA_SPECIFY_COLS) + + wx.RadioBox(panel, -1, "", (150, 10), wx.DefaultSize, + sampleList, 3, wx.RA_SPECIFY_COLS | wx.NO_BORDER) + +if __name__ == '__main__': + app = wx.PySimpleApp() + RadioBoxFrame().Show() + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-07/slider.py b/wxPython/samples/wxPIA_book/Chapter-07/slider.py new file mode 100644 index 0000000000..65945b9d3e --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-07/slider.py @@ -0,0 +1,22 @@ +import wx + +class SliderFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, 'Slider Example', + size=(300, 350)) + panel = wx.Panel(self, -1) + self.count = 0 + slider = wx.Slider(panel, 100, 25, 1, 100, pos=(10, 10), + size=(250, -1), + style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS ) + slider.SetTickFreq(5, 1) + slider = wx.Slider(panel, 100, 25, 1, 100, pos=(125, 70), + size=(-1, 250), + style=wx.SL_VERTICAL | wx.SL_AUTOTICKS | wx.SL_LABELS ) + slider.SetTickFreq(20, 1) + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = SliderFrame() + frame.Show() + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-07/spinner.py b/wxPython/samples/wxPIA_book/Chapter-07/spinner.py new file mode 100644 index 0000000000..92995fa0ef --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-07/spinner.py @@ -0,0 +1,15 @@ +import wx + +class SpinnerFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, 'Spinner Example', + size=(100, 100)) + panel = wx.Panel(self, -1) + sc = wx.SpinCtrl(panel, -1, "", (30, 20), (80, -1)) + sc.SetRange(1,100) + sc.SetValue(5) + +if __name__ == '__main__': + app = wx.PySimpleApp() + SpinnerFrame().Show() + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-07/static_text.py b/wxPython/samples/wxPIA_book/Chapter-07/static_text.py new file mode 100644 index 0000000000..66ae3df849 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-07/static_text.py @@ -0,0 +1,38 @@ +import wx + +class StaticTextFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, 'Static Text Example', + size=(400, 300)) + panel = wx.Panel(self, -1) + wx.StaticText(panel, -1, "This is an example of static text", + (100, 10)) + rev = wx.StaticText(panel, -1, "Static Text With Reversed Colors", + (100, 30)) + rev.SetForegroundColour('white') + rev.SetBackgroundColour('black') + center = wx.StaticText(panel, -1, "align center", (100, 50), + (160, -1), wx.ALIGN_CENTER) + center.SetForegroundColour('white') + center.SetBackgroundColour('black') + right = wx.StaticText(panel, -1, "align right", (100, 70), + (160, -1), wx.ALIGN_RIGHT) + right.SetForegroundColour('white') + right.SetBackgroundColour('black') + str = "You can also change the font." + text = wx.StaticText(panel, -1, str, (20, 100)) + font = wx.Font(18, wx.DECORATIVE, wx.ITALIC, wx.NORMAL) + text.SetFont(font) + wx.StaticText(panel, -1, "Your text\ncan be split\n" + "over multiple lines\n\neven blank ones", (20,150)) + wx.StaticText(panel, -1, "Multi-line text\ncan also\n" + "be right aligned\n\neven with a blank", (220,150), + style=wx.ALIGN_RIGHT) + + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = StaticTextFrame() + frame.Show() + app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-07/text_ctrl.py b/wxPython/samples/wxPIA_book/Chapter-07/text_ctrl.py new file mode 100644 index 0000000000..ada733b200 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-07/text_ctrl.py @@ -0,0 +1,25 @@ +import wx + +class TextFrame(wx.Frame): + + def __init__(self): + wx.Frame.__init__(self, None, -1, 'Text Entry Example', + size=(300, 100)) + panel = wx.Panel(self, -1) + basicLabel = wx.StaticText(panel, -1, "Basic Control:") + basicText = wx.TextCtrl(panel, -1, "I've entered some text!", + size=(175, -1)) + basicText.SetInsertionPoint(0) + + pwdLabel = wx.StaticText(panel, -1, "Password:") + pwdText = wx.TextCtrl(panel, -1, "password", size=(175, -1), + style=wx.TE_PASSWORD) + sizer = wx.FlexGridSizer(cols=2, hgap=6, vgap=6) + sizer.AddMany([basicLabel, basicText, pwdLabel, pwdText]) + panel.SetSizer(sizer) + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = TextFrame() + frame.Show() + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-07/text_ctrl_multiple.py b/wxPython/samples/wxPIA_book/Chapter-07/text_ctrl_multiple.py new file mode 100644 index 0000000000..04abf7f7cc --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-07/text_ctrl_multiple.py @@ -0,0 +1,33 @@ +import wx + +class TextFrame(wx.Frame): + + def __init__(self): + wx.Frame.__init__(self, None, -1, 'Text Entry Example', + size=(300, 250)) + panel = wx.Panel(self, -1) + multiLabel = wx.StaticText(panel, -1, "Multi-line") + multiText = wx.TextCtrl(panel, -1, + "Here is a looooooooooooooong line of text set in the control.\n\n" + "See that it wrapped, and that this line is after a blank", + size=(200, 100), style=wx.TE_MULTILINE) + multiText.SetInsertionPoint(0) + + richLabel = wx.StaticText(panel, -1, "Rich Text") + richText = wx.TextCtrl(panel, -1, + "If supported by the native control, this is reversed, and this is a different font.", + size=(200, 100), style=wx.TE_MULTILINE|wx.TE_RICH2) + richText.SetInsertionPoint(0) + richText.SetStyle(44, 52, wx.TextAttr("white", "black")) + points = richText.GetFont().GetPointSize() + f = wx.Font(points + 3, wx.ROMAN, wx.ITALIC, wx.BOLD, True) + richText.SetStyle(68, 82, wx.TextAttr("blue", wx.NullColour, f)) + sizer = wx.FlexGridSizer(cols=2, hgap=6, vgap=6) + sizer.AddMany([multiLabel, multiText, richLabel, richText]) + panel.SetSizer(sizer) + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = TextFrame() + frame.Show() + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-08/frame_subclass.py b/wxPython/samples/wxPIA_book/Chapter-08/frame_subclass.py new file mode 100644 index 0000000000..66627208ac --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-08/frame_subclass.py @@ -0,0 +1,21 @@ +import wx + +class SubclassFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, 'Frame Subclass', + size=(300, 100)) + panel = wx.Panel(self, -1) + button = wx.Button(panel, -1, "Close Me", pos=(15, 15)) + self.Bind(wx.EVT_BUTTON, self.OnCloseMe, button) + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + + def OnCloseMe(self, event): + self.Close(True) + + def OnCloseWindow(self, event): + self.Destroy() + +if __name__ == '__main__': + app = wx.PySimpleApp() + SubclassFrame().Show() + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-08/help_context.py b/wxPython/samples/wxPIA_book/Chapter-08/help_context.py new file mode 100644 index 0000000000..3a7aed9b7a --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-08/help_context.py @@ -0,0 +1,16 @@ +import wx + +class HelpFrame(wx.Frame): + + def __init__(self): + pre = wx.PreFrame() + pre.SetExtraStyle(wx.FRAME_EX_CONTEXTHELP) + pre.Create(None, -1, "Help Context", size=(300, 100), + style=wx.DEFAULT_FRAME_STYLE ^ + (wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX)) + self.PostCreate(pre) + +if __name__ == '__main__': + app = wx.PySimpleApp() + HelpFrame().Show() + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-08/images.py b/wxPython/samples/wxPIA_book/Chapter-08/images.py new file mode 100644 index 0000000000..19d7806586 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-08/images.py @@ -0,0 +1,1424 @@ +#---------------------------------------------------------------------- +# This file was generated by encode_bitmaps.py +# +from wx import ImageFromStream, BitmapFromImage +from wx import EmptyIcon +import cStringIO + + +def getVippiData(): + return \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x01^\x00\x00\x01O\x08\x06\x00\ +\x00\x00\x05\xa1\xa6$\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00 \ +\x00IDATx\x9c\xec\x9dy`T\xd5\xd9\xff?\xe7\xced%!\x0b\x81@ \x10@\xf6M\x84\x80\ +"(\xae\x05\x14\x85\xba\xaf\xa8m\xad\xbb\xb5\xaf\xbe\xb6\xda\xfe\xaa]\xb4X\ +\xdf\xd6\xd6\xd6\x05\xad\xadR\xb7\x96\x8a\xe2\x8e; \n\x02\x82 \n\xc8\x1e aMH\ +B\x96\x99{\xcf\xef\x8fsg\xcdd\x9b\xcc\x96\xe4|tH\xe6n\xe7\xdc\x9b\xb9\xdfy\ +\xees\x9e\xe79B\x18\x0e:\x13\xd22\xa5\xff{a8D\xac\xda\x8cE[\x1a\x8d&\xf1q\ +\xc6\xbb\x03\xb1"Xp!\xf6B\xa8\x05X\xa3\xd1@\'\x10\xdeD\x10\xdc`\xb4\x00k4\ +\x9d\x1b\xd1Q]\r\x89,\xb8\xfe\xc4\xbbO\x1a\x8d&\xf6t8\xe1\r%n\x908\x02\xa7\ +\xc5W\xa3\xd1t\x18\xe1Mt\xc1\r&\x1e\x83|\x1a\x8d&1\xe8\x10\xc2\xdb^\xadH-\ +\xbe\x1aM\xe7\xa4]\x0bo{\xb3rC\xa1\xc5W\xa3\xe9|\xb4[\xe1m\xafVn(:\xd2\xb9h4\ +\x9a\xe6iw\xc2\xdb\x11\xac\xdc\xc6\xd0\xd6\xafF\xd390\xe2\xdd\x81\xd6\xd0\ +\x91E\x17\x1a\x9eGc\xe7\xab\xd1h\xda7\xedFx;\xba\xe8z\xd0\xe2\xab\xd1t|\xda\ +\x8d\xf0\x06#\x0c\x87\xe8h\xa2\xeb\xa1\xa3\x9e\x97F\xa3Q\xb4\x0b\xe1\xed\x8c\ +\xbeO\xffs\xd4V\xafF\xd3\xb1hW\xb5\x1a:\x83\xe0\xfa\xe39_-\xbc\x1aM\xc7\xa2\ +\xddE5h4\x1aM{\xa7]Y\xbc\xe1\xd2\x1a\x8b1ZVug\x19\x1c\xd4h4\xcd\xd3\xa1-\xde\ +\xb6>\xa2\x87#\x8a\x91v\x0bha\xd6h:\x1e\x1dNx\xa3\xe5\x0fmJ\x00c\xe9\x83\xd5\ +B\xac\xd1\xb4\x7f:\x8c\xf0\xb6D\xfcrss\xb9\xf8\xe2\x8b9\xfd\xf4\xd3\xc9\xc9\ +\xc9\x01\xa0\xb6\xb6\x96g\x9f}\x96\xf7\xde{\x8f\x8a\x8a\x8a&\xf7O\xb4\x18[-\ +\xc2\x1aM\xfb\xa4\xdd\x0bos\xe2\x97\x9b\x9b\xcb\xe5\x97_\xce\xa9\xa7\x9e\xca\ +I\'\x9dDAA\x01\x00B(\xcd\x92R\xed~\xe8\xd0!^~\xf9e^x\xe1\x05V\xacX\x81i\x9a\ +\x11\xebcff&III\x8c\x1e=\x9a^\xbdz1b\xc4\x08\x00\n\n\n(**b\xd7\xae]\x94\x94\ +\x94\xb0y\xf3fv\xed\xda\xc5\xa1C\x87\xd8\xb2e\x0b\xb5\xb5\xb5-:\xbe\x16`\x8d\ +\xa6}\xd1n\x85\xb7)\xc1\x15B0f\xcc\x18\xae\xbb\xee:\xe6\xcc\x99Cff\xa6wy\xa3\ +\xc7\xb3\x05\xd8\xb2,\xbe\xf9\xe6\x1b\x96.]\xca\xd2\xa5Ky\xff\xfd\xf79p\xe0@\ +\x8b\xfb\x95\x9c\x9cLZZ\x1a\x93&Mb\xca\x94)\x9cz\xea\xa9\x1c\x7f\xfc\xf1\x18\ +\x86AJJJ@\x1f\xa5\x94\r~\x02\x98\xa6Iii)\x1b7nd\xd1\xa2E,[\xb6\x8c\r\x1b6\ +\xb4\xe8\xcb@\x8b\xb0F\x93\xf8\xb4;\xe1mNp\xc7\x8f\x1f\xcf/~\xf1\x0b\xa6O\ +\x9f\x8e\xd3\xe9lRl\x9bl\xc7\x16\xc1\xd2\xd2R\xa6O\x9f\xce\xbau\xeb\x9a\xdc>\ +%%\x85K.\xb9\x84{\xee\xb9\x87\xa2\xa2"\x92\x93\x93\xbd}j\x0bRJL\xd3d\xd5\xaa\ +U,]\xba\x94\xf9\xf3\xe7\xb3~\xfd\xfa&\xf7\xd1\xe2\xab\xd1$6\xedFx\x9b\x13\ +\xdc\xe2\xe2b\x1e|\xf0AN9\xe5\x14\x1c\x0eG\x9b\x05\xcf\xdb\xae\x94\xbc\xf0\ +\xc2\x0b\\y\xe5\x95!\xd7\xf7\xef\xdf\x9f\x193fp\xf3\xcd73t\xe8Po\x7f\xa2\x81\ +\x94\x12\x97\xcb\xc5\x92%Kx\xe3\x8d7\xf8\xe4\x93O\xd8\xb0a\x03n\xb7\xbb\xc1\ +\xb6Z|5\x9a\xc4\xa5]\x08oS\xa2[TT\xc4}\xf7\xdd\xc7\xe5\x97_\xde&\x0b\xb7)v\ +\xef\xde\xcd\xa8Q\xa3\x1a\x0c\xbe\x15\x17\x17\xf3\xe6\x9bo\x92\x97\x97\x07DO\ +p\x83\xf1wI,^\xbc\x98\x9f\xfc\xe4\'l\xd9\xb2\xa5\xc1vZ|5\x9a\xc4$\xe1k54&\ +\xbaIII\xfc\xf0\x87?d\xe5\xca\x95\\}\xf5\xd5$%%EM\xf8\xfa\xf4\xe9\xc3\x85\ +\x17^\xd8`\xf9\x19g\x9cA^^\x1eB\x88\x98\x89.\xe0m\xcf\xe9t2}\xfat>\xff\xfcsf\ +\xcd\x9a\xd5`;i\x992\xde\x91\x17\x1a\x8d\xa6!\t+\xbcM\x89FQQ\x11\x0b\x17.\ +\xe4\xc9\'\x9f\xf4\n_\xb49\xfb\xec\xb3\x1b,[\xbdzuL\x057\x14B\x08rrrx\xfe\ +\xf9\xe7\x99={v\\\xfb\xa2\xd1hZFB\no\xa3\xe9\xb5Bp\xe5\x95W\xb2b\xc5\nf\xcc\ +\x98\x81a\x181\x11>!\x8472!xy" \x84 --\x8d\x7f\xfd\xeb_\x8dZ\xbeq\xe8\x96F\ +\xa3i\x84\x84\x13\xde\xc6D\xc20\x0c\xfe\xfa\xd7\xbf\xf2\xcc3\xcf\xd0\xbd{\ +\xf7\x98\x8b^QQ\x11\x85\x85\x85\x01\xcb,\xcb\xf2\xfa[\xe3\x8dG|\x9f\x7f\xfey\ +-\xbe\x1aM\x82\x93P\xc2\xdb\x988\xe4\xe4\xe4\xb0h\xd1"n\xbc\xf1\xc6\x88\xf9r\ +\x83\x05SJ\xd9\xa4\x88\x86\x8a\x94X\xb9re\x8b\x93\x1cb\x81\xbf\xf8N\x9d:5\ +\xde\xdd\xd1h4\x8d\x900\xd5\xc9\x1a\x13\xdd\xdc\xdc\\^\x7f\xfduN:\xe9\xa46\t\ +\xae\x94\x12\xb7\xdb\xcd\x8a\x15+8z\xf4(G\x8e\x1c\xe1\x9bo\xbe\xf1\xaeOKKc\ +\xec\xd8\xb1\x0c\x1e<\x98\xfe\xfd\xfb{\xdd\nM\xb5\x99H\x16\xaf\x07\x8f\xf8>\ +\xf9\xe4\x93L\x980! \x12CZ\xa6\xd4\x91\x0e\x1aM\xfcI\x08\xe1mLt\xfb\xf4\xe9\ +\xc3\xe2\xc5\x8b\x19:th\x9bE\xf7\xe0\xc1\x83\xdcu\xd7]\xcc\x9f?\x1f\xcb\xb2\ +\x1a\xdd6%%\x85Q\xa3F1c\xc6\x0cf\xcd\x9a\xc5\x88\x11#HJJ\xc20\x0cF\x8e\x1c\ +\xc9\x8e\x1d;\xc2\xeeG\xac\x10B0h\xd0 ~\xf3\x9b\xdfp\xdbm\xb7\x05\xac\xd3\ +\xe2\xab\xd1\xc4\x9f\xb8\xbb\x1a\x1a\x13\xdd!C\x86\xb0p\xe1\xc26\x8b.@EE\x05\ +3f\xcc\xe0\xd9g\x9fmRt\x01\xea\xea\xeaX\xb5j\x15\xbf\xfe\xf5\xaf\x19?~k\xd6\xac\tXo\x9a\ +&\x87\x0f\x1f\xe6\x1f\xff\xf8\x07\xcf=\xf7\x1c\xb3f\xcd\xe2\x81\x07\x1e`\xd0\ +\xa0A1\x13_\x8f\xcb!Xx5\x1aM\xfc\x88\x8b\xc5\xdb\x98\xb5{\xd5UW\xf1\xf4\xd3O\ +{+{\xb5\xa9\r\xfb\xb1\x7f\xc8\x90!\xec\xdf\xbf\x1f\x00Gf&C\x9e~\x9a\xbc\x0b/\ +\x84f\xd2|\xa5\x94`Y\x1c]\xbe\x9cm?\xfb\x19G\x97/o]\x07\xec\xf03\t\xe0W\xc4&\ +55\x95\xb9s\xe7r\xeb\xad\xb7\x02\xb1I\xc2X\xb3f\r\xe3\xc6\x8d\x0bX\xa6-^\x8d\ +&~\xc4\xdc\xe2mLt\xc7\x8d\x1b\xc7\xbcy\xf3""\xba\x1e\xe6\xcd\x9b\xe7\x15]\ +\x84`\xc8\xbcy\xe4]tQ\x80\xd8I)\xc1\xed\xa6f\xebV\xac\xba:\xd2\x07\x0eD\xa4\ +\xa6*\xe1t8\xe8:y2c>\xfc\x90\x83\x0b\x16\xb0\xf5\xee\xbb\xa9\xdf\xb3\'d[\x8e\ +\xae]\xe9>{6\xa9\x03\x07\x929v,\xe9\xc3\x86\xe1\xcc\xcd\x05\xb7\x9b\xc3\xef\ +\xbe\xcb\x81\x05\x0b8\xf4\xd6[\xd4\xd6\xd6r\xc7\x1dw\x00p\xcb-\xb7\xc4\xcd\ +\xf7\xab\xa3\x1b4\x9a\xf8\x11s\x8b7\x94\xf0&\'\'\xb3d\xc9\x12&L\x98\x101!\ +\xaa\xad\xade\xd4\xa8Q|\xf7\xddw\x00\xa4\r\x1aD\xf1\x86\r\x08?a\x97Rb\x1e9\ +\xc27W\\\xc1\x91\x0f>@\x9a&\x8e\xccL\xba\x0c\x1dJ\xc1\x8d7\xd2\xfd\x92K\x10)\ +)\xde"\xe5\xdf^~9\xfb_z\xa9A[\xd9\xa7\x9f\xce\xf0\xe7\x9f\xc7\x99\x9f\xdfh\ +\xff\xa5eq\xe4\xed\xb7\xf9\xfa\xd2K\xb1\xaa\xaap8\x1c<\xf2\xc8#\xdc|\xf3\xcd\ +Q\x17\xdf\x92\x92\x12\x06\x0f\x1eLMMM\xc0r-\xbc\x1aM|\x88i8Yc\xd6\xee\x9dw\ +\xde\x19Q\xd1\x95R\xf2\xdf\xff\xfe7 \x02!\xb9\xa0\x00\x91\x94\x14\xb0\x9du\ +\xec\x18\xdf^s\r\x87\xdfy\x07\xe9r\x81eaVTpt\xc5\n\xbe\xbd\xe6\x1a\xd6\x9dy&\ +\xa6\x9d\x80`VTP\xb9zu\xc0\xfe"%\x85\x01\x0f=\xc4\xa8\xb7\xdejRt\x01\x84a\ +\x903c\x06\xc3\xff\xf5/\x10\x02\xd34\xb9\xf7\xde{\xd9\xb0aC\xd4\x930z\xf4\ +\xe8\xe1\x8d\xbc\xd0h4\xf1\'\xeeq\xbc\xc7\x1dw\x9c\xf7\xd1;\x12H)\xd9\xb3g\ +\x0fw\xdduW\x80\xa0\xf5\xb8\xf0Bd\xd0v{\xff\xfaW\x0e\xbd\xfez\xa3\xc7:\xfa\ +\xe9\xa7\x1cy\xfbm\xa4\xdb\xcd\xf6{\xee\xa1&\xa8\xe6m\xf6\x94)\x14\xdey\'\ +\x86m\x157\x87\x10\x82n3g\xd2e\xe4Hu\xfc\xa3G\x993gN\xd4\xd3\x8e\x1d\x0eG\ +\x83:\x13\x1a\x8d&~\xc4=\xaa\xe1\xfa\xeb\xaf\xa7[\xb7n\x11}\xdc\xbe\xf7\xde{\ +\xd9\xb7o\x9fo\x81\xc3A\xde\xf9\xe7\x07\xb6Q_\xcf\xde\xa7\x9ej\xf6X{\x9fx\ +\x02wy9{\x9fx\xa2\xc1\xba\xa4\xee\xdd\x01;\x1d\xb9\xac\x8c\n\xbf\xc8\x01##\ +\x83\xec\xd3N\xf3\xba*\x1d\xe1WR\xb2\xf0\xa7?\xe5\xe0+\xaf\ +P\xb5v-\x96e\xf1\xd5W_Q\\\\\xdc\x8a3\xd4h4\xed\x99\xb8\xba\x1a\xee\xbc\xf3N\ +\xd2\xd3\xd3#n\xe9\xf5\xe8\xd1#\xe0}r\xcf\x9e8sr\xbc\xef\x05\xb0\xff\xe5\x97\ +\x1b\x8d\xcf\r\xc0\xed\xc6\n\xe1\nH\xee\xdd\x9b\xdc\x193\xd8q\xcf=l\xb9\xe9\ +\xa6\x06\xa2\x0bP\xbd~=\xeb\xcf?\x9f\xefn\xbe\x19\xeb\xd81\xefl\xc2"=\x9d\ +\xc1\x8f?\xae\xa2\'\x80\x8f>\xfa\xa8u\'\xa8\xd1h\xda5q\x13\xde\xc2\xc2B\xae\ +\xb8\xe2\x8a\x88\x8b\xae\x10\x82\x81\x03\x07\x06,\xeb:a\x02\x86\xdf\xe0\x924\ +M\xdcA\xf3\xa7\xb5\xb2\x11\x06>\xf4\x10\xae\xfd\xfb\xd9\xf3\xb7\xbf5\xbd\xad\ +i\xb2\xf7\x89\'\xd8v\xcf=\xde\x04\r!\x04\x19c\xc7\xe2\xb4k?\x94\x95\x95\x85\ +\xdf\x17\x8dF\xd3\xee\x88\x89\xf0\x86r3\\u\xd5UQ\x19i\x97R2j\xd4\xa8\x80e\ +\x8e\xf4\xf4\x80\x815WY\x19\xd5\x1b7\x86\xddF\xd6\xe4\xc9\xf4\xb8\xf4R\xf6\ +\xbf\xf4\x122\xc4\x0c\xbf\xa1\xa8\xdf\xb3\'\xc0\xdd\xe1:t\x083(\xbcK\xa3\xd1\ +t\x0e\xe2b\xf1\x1a\x86\xc1Yg\x9d\x15\x95c\x0b!\xc8\xcf\xcf\x0fXV\xb1|9\xd4\ +\xd7\xfb\xdaOM\xc5\x91\x99\x19^\x03\x0e\x07\xfd~\xf1\x0b\x10\x82\xaa\xb5k[\ +\xbc[\xfa\xb0a^\xd7\x86\x94\x92#\xef\xbf\x8fU]\xad\xfac\xc4=\xb8D\xa3\xd1\ +\xc4\x90\xb8\xdc\xf13f\xcc`\xca\x94)Q\x1b\xc5?\xf1\xc4\x13)((\xf0\xbe\xaf\ +\xdd\xbe\x9dC\xaf\xbf\xee\r/s\xe4\xe62p\xee\\p\xb4>y\xa4\xf7\r7\x90}\xe6\x99\ +\x00-\xb6v\x01\x92\xf2\xf2\xc0N\xc4\xb0\xaa\xab\xd9\xf3\xe8\xa3\x01\xfd\x8d&\ +\x96eQYY\x19\xb0L\'Oh4\xf1#.\xc2{\xc6\x19g\xe0\x08C\xf4ZJVV\x16\x17]tQ\xc0\ +\xb2\x9d\x0f>\x88\xb4\x1f\xed\x85\x10\xe4_s\r\x03\xff\xf0\x07h\x85\xb5\xe9\ +\xc8\xca\xa2\xdf/\x7f\xa9\x04\x14\xe89gN\x8b\xf6K\xe9\xd3\x87<\xbfy\xd0\xca?\ +\xfc\x90\xcaU\xab\xd41\x1d\x8e\xa8\xd7\xcc\xad\xa8\xa8`\xbd\x1d\xbe\xa6\xd1h\ +\xe2O\xd4\x857\xd8\xbfk\x18\x06\xe7\x9e{nT\xdb\x14Bp\xcb-\xb7\x04\xd4}\xa8Z\ +\xb3\x86]\x0f>\x88\xb4\x0b\xa1\x0b\xc3\xa0\xf7\xed\xb7\xb7J|\xb3&M\xc2iO\xb4\ +)\x84 w\xe6L\xf2\x9a\x99R=\xb9woF\xbd\xf5\x16\xc9v\x02\x83\x00\xb6\xfd\xfc\ +\xe7\xde\xf5\xf9\xf9\xf9L\x9c81j\xd6\xbf\x94\x92\xc5\x8b\x17s\xf4\xe8\xd1\ +\xa8\x1c_\xa3\xd1\xb4\x9e\x98[\xbc\x85\x85\x85\x14\x15\x15E\xbd\x9d\x01\x03\ +\x060c\xc6\x8c\x80e\xbb\xe6\xce\xa5|\xf1b\xaf\xcbA\x08A\xef\x9f\xfc\xa4\xc5\ +\xe2\x9b\x92\x9f\x1f0@&\x92\x92\x18\xfc\xe4\x93dM\x9e\xdc\xc0m\xe1\xc8\xca"o\ +\xf6lN\xf8\xec3\xd2G\x8e\xf4\xd6{\xa8\\\xb5\x8a\x9a\xcd\x9b\xbd\xdb\xfd\xe2\ +\x17\xbf\x88j:\xaf\xcb\xe5\xe2\xf7\xbf\xff}\xd4\x8e\xaf\xd1hZO\xd4\x8b\xe4\ +\x04[\xbcW_}5\xff\xfc\xe7?\xa3^\x18FJ\xc9\xae]\xbb\x18=zt\x80\xb5\xe7\xc8\ +\xc8`\xf8\xcb/\x933m\x9a\xb74\xa4\x94\x92\x8d\xb3gs\xf0\xb5\xd7\x9a\x9c\xd5\xabW\x93j\xc7\xf3F\x1a)%O?\xfd4\ +\xd7_\x7f}\xc0r\xed\xdf\xd5h\xe2K\xcc-\xdeh\x0f$y\x10B\xd0\xb7o_n\xbc\xf1\ +\xc6\x80\xe5fU\x15\xeb\xcf;\x8f\xefn\xbd\x15\xf3\xf0a\xafp\x1aii\xcd\x1e\xb3\ +f\xdb6\xca?\xfe8\xa0\x06\x84\x10\x02\x84 m\xc8\x10\xba\x8c\x1e\xed}9\xb2\xb2\ +\xbc\xeb<\xa2\xbb\xfdg?\xf3\x8anAA\x01/\xbd\xf4\x12)))\x11=o\x0f\x9ez\xc4\ +\xf7\xdf\x7f\x7fT\x8e\xaf\xd1h\xc2\'\xe6\xc2\x9b\x96\x96\x16\xd3\xd9\x17~\ +\xfb\xdb\xdfr\xce9\xe7\x04\xae0M\xf6>\xf6\x18+G\x8c`\xef_\xfeB\xe9\xd3OS\xbe\ +dI\xb3\xc7\x93uul\xbb\xfbn\xcc#GZ\\QLJI\xf5\x9a5|5m\x9a7\xd9"55\x95\xc7\x1e{\ +\x8c\x91\xb6\x0b"\x1a\xb8\\.\xee\xb8\xe3\x0e\xf6\x04\xd5\x0f\xd6\xd6\xaeF\ +\x13\x7fb\xeejX\xb7n\x1d\xa3G\x8f\x8ej\x9b\x01\xedK\xc9\x81\x03\x07\xb8\xf9\ +\xe6\x9bY\xb0`AD\x8e\x99;c\x06\xc3\x9e}\x16G#\xc5}\xa4\x94 %\xf5{\xf6P\xfa\ +\xcc3\xec\xfc\xfd\xef\x91v\xdaqrr2\xf3\xe7\xcf\xe7\xa2\xa0\x82\xec\x91\xc44M\ +\x1e{\xec1n\xbf\xfd\xf6@\xeb\\\x8b\xaeF\x93\x10tx\xe1\x05%\x84\xc7\x8e\x1d\ +\xe3o\x7f\xfb\x1b\xf7\xde{/\xeeV\xc4\xdf\xa6w\x07\xc3\x01U\xa5\x81\xcbS\xfa\ +\xf4\xa1\xe8W\xbf"\xef\x82\x0bpfg\x83\x94X\xf5\xf5X\xb5\xb5\x1cz\xf5U*>\xfd\ +\x94\xb2\x17_\xf4&I\x00\xa4\xa4\xa4\xf0\xec\xb3\xcfr\xf1\xc5\x17GEt\xa5\x94H\ +)y\xf8\xe1\x87\xb9\xe7\x9e{\x1aN\xf0\xa9\x85W\xa3I\x08b.\xbcK\x97.e\xf2\xe4\ +\xc9Qm3d?lQ\x9a7o\x1e\xb7\xdezk\x8b\xc4\xf7\xb8\xb3`\xf6\xb3p\xec \xcc\x9b\ +\x08\xae\x10\x19\xbe)}\xfb\xd2e\xe8P,\x97\x8b\xaa\xf5\xeb\x91n7fyy\x83\xed\n\ +\n\nx\xfc\xf1\xc7\x999sf\xd4D\xf7\xf0\xe1\xc3\xdcw\xdf}<\xf1\xc4\x13\r\xceO\ +\x8b\xaeF\x9388\x84\x88\xb2\x9bW\xca\xfb\xfc\xdf\x16\x17\x17\xc7\xa5\x04\xa2\ +\'\xf6\xf6\x84\x13N\xa0[\xb7n\xbc\xfb\xee\xbb\x8d\xfai\r\'L\xfb?\xf8\xde#\ +\x90\xd4UY\xbd\xd9\x05\xf0m\x88\x9a\xe9fE\x055[\xb7R\xbbc\x87\xaa@\x16\xa2\ +\x92\xd9\xa4I\x93x\xf1\xc5\x17\xa3\x96\xad\'\xa5d\xcb\x96-\xcc\x9e=\x9b\xd7^\ +{\r\xcb\x8eU\xf6\xa0EW\xa3I,b>\xb8\xb6}\xfb\xf6\xa8Ou\x13\n)%\x96e\xf1\xe9\ +\xa7\x9f\xf2\xa7?\xfd\xa9\x818yH\xef\x0eW\xbf\x03\xc5\xb7\x83\x91\xa4\xc2v\ +\x85\x01\xa3\xae\x81\xd3~\x89o\x0e\xf8\x16\xe0p8\xb8\xf5\xd6[\xf9\xe4\x93O\ +\x185jTDE\xd7c\xc1\x97\x96\x96r\xc7\x1dw0q\xe2DV\x07MM\x04Zt5\x9aD$\xe6\xae\ +\x86\xd1\xa3G\xb3l\xd922\xc3-R\xd3\xda\xf6m\x91?x\xf0 \xf3\xe6\xcd\xe3\xfe\ +\xfb\xef\xc7\xe5r\x85\xdc\xb6\xe0\x04\xb8\xe8e\xc8\x1a\x18\x90\'\xe1;\x96\ +\x1b\xde\xff_X\xfeg \xb4n{),,d\xfe\xfc\xf9L\x992%\xa2Ep<\x82\xbbw\xef^\xfe\ +\xf0\x87?\xf0\xc2\x0b/p0D-`\x0fZx5\x9a\xc4#\xe6\xc2\x0b\xf0\xcb_\xfe\x92\xfb\ +\xef\xbf?\xaaae\x1e\xc1\xdd\xb7o\x1f\x0f?\xfc0\x0b\x17.d\xc7\x8e\x1d\x8dn?h:\ +\xccz\x06\xd2\xf2C\x8b\xae\xf7\xb8\x16|\xbb\x00\x16^\x07\xae\xea\xc6\xb7\x1b\ +0`\x00\'\x9ex"c\xc6\x8ca\xea\xd4\xa9\x8c\x1f?\xde\xeb\xeeh\xedy\xf8[\xb7\xaf\ +\xbe\xfa*\x8b\x16-b\xe9\xd2\xa5\rf\r\x0e\x85\x16^\x8d&\xf1\x88\x8b\xf0&\'\'\ +\xf3\xd4SOq\xe5\x95W\x86%FM\xb6g\x0b\xee\x17_|\xc1\x03\x0f<\xc0\x92%K8r\xe4H\ +\xa3\xdb\'g\xc0\xe4\xbb\xe0\xe4\x9f\x81HjZt}\x8d\xc0\x81\xaf\xe0?\x97\xc1\ +\x81o\x9a\xdf<))\x89\xef\x7f\xff\xfbL\x9b6\x8d\xc9\x93\'\x93\x94\x94D\x9f>}\ +\x1a\x9cwUU\x15\xfb\xf7\xef\x07`\xcb\x96-\x1c:t\x88\xca\xcaJ^}\xf5Uv\xed\xda\ +EII\tUUU-\xe8\xa0\x0f-\xbc\x1aM\xe2\x11\x17\xe1\x05%Fs\xe6\xcc\xe1\xc6\x1bod\ +\xec\xd8\xb1vg\xc2\xd7\x08\xcb\xb2p\xb9\\|\xf8\xe1\x87<\xf1\xc4\x13\xbc\xfb\ +\xee\xbb\xd4\xf9\xa5\xf0\x86\xa2\xc7\x08\x98\xf9$\xf4\x9e\xd4B\xc1\xf5CJpU\ +\xc2;\xb7\xc1\xfa\x7f\x83\xbb\x855\xcd\r\xc3\xf0\no0\xd5\xd5\xd5\xde\xd9(\ +\xc2\xf5\x83\x0f<\x13z\x8d\x85e\x7f\xf0-\xd3\xe2\xab\xd1$\x16a\x0b\xaf\xbf\ +\xa06uc7&\xbc\x1eRSS\xb9\xfc\xf2\xcb9\xed\xb4\xd38\xf3\xcc3\xbdE\xcc\x9b\x12\ +a\x8f(Y\x96EII\t\x1b7n\xe4\xa5\x97^\xe2\xfd\xf7\xdf\xa7\xb4\xb4\xb4\xd1\x813\ +o\x7f\x9d0\xf5^8\xf1\x0e\x15\xb5\x10\xae\xdeK\tB\xc2\xfe\xaf\xe0\xb5\x1f\xc0\ +\xde/\x81\xd8\x8f\x1b\x02\x90\xdc\x05&\xdd\x01\'\xdf\x03X\xf0\xe4x8\xf8\xado\ +}c\x7f\xa3\xe0\xbf\x8f\x16i\x8d&\xfa\x84%\xbc\xa1\xc44\xd4\r\xdb\x9c\xe8\x06\ +\x93\x95\x95\xc5)\xa7\x9c\xc2\xc4\x89\x139\xfe\xf8\xe3\x1b\xcc$\x01\xb0c\xc7\ +\x0e\xb6o\xdf\xce\xb2e\xcb\xf8\xf2\xcb/9p\xe0\x00\xb5!B\xb8B!\x9c\xd0o2\x9c\ +\xf7\x04d\x0fR\xd1\n\x91@J\xc0\r\xbb>\x81O\x1e\x80\xed\x1f\x133\x016\x9cp\ +\xf2\xff\xc0\xb8\x1fC\xd7"\xf5%"%|\xf5\x0c\xbc\xfaC\xdfv\xad\xfd\xfbh\x01\ +\xd6h\xa2G\xab\x84\xb757jkE7\x9a\x08\x07\xf4;\x19\xa6\xfe\n\xfaM\x05)\xc2\ +\xb7rC\x11\xe0\x150a\xdfJX\xf5$|\xfb\x06\xd4\x1c\x8e\\;\x1e\x8c$\xe81\x0c\ +\xc6^\x0b\x83\xcfQQ\x18\x04\x9dS\xdda\xf8\xcb`8v\xc8\xb7,\x9c\xbf\x91\x16`\ +\x8d&\xf2\xb4Hx[{\x83\x86\xda\xbe\xd7\tP\xba\x0e\xa4\x19\xbc&z\x08\x07\x14\ +\x9d\x02\xa7\xfc\x1c\x8a\xce\x88\xbc\xe0z0k\xa1t\x15\xe4\x1f\x0f\xce.\xca\ +\xd8\x15\xc0\xb1\xfd\xb0\xf2/\xb0}\t\x94\xae\x05\xd71\x15\x15\xd1\x1a\x8c$p$\ +A\xd7B\xe8{\x12\xf4?\x15\n\xa7\xa8\xf7M\r\x06J\tK\xfe\x1f|\xfc[\xdf\xb2\xb6|\ +9j\x01\xd6h"G\x93\xc2\x1b\x8eE\x14j\x9f\xa2S\xe0\xaaw`\xf5S\xf0\xfe\xbdP\xdf\ +\xba\x81\xf9\xd6! \xbb\x1f\x8c\xbd\x1a\x86_\x08y#\xa2\'\xb8^$\xb8\x8e\xc2\ +\xaeeP\xf2\x19d\xf6\x86>\'A\xee p\xa6\xab\xf5f\r\xec\xdf\x08\xbb\x96\xc2\xbe\ +5P\xd5\xc4\x8c\xee\xdd\x87BFOu\x9c\xc2\x93\xd4O#Y\x89pk\x128\x0e}\rO\x8c\x07\ +\xb7\xed\x89\x89\x84;H\x0b\xb0F\xd3vB\noKo\xc6\x96\xdc\xc8\xce4\xb8i\xad\xf2\ +\xa9\x02T\xee\x84\xb7o\x87-\xef\x80Y\x1f\xbcw\xf8\xa4d\xc3\x90\xe90\xf6:(<\ +\x19\x8c\xd4(\x8bm\x08<\xbe\xde\xef\xde\x86es\xe1\xe8^8\xeeL\xe8w\n\xf4\x9d\ +\xa2\x04\x14\xa7\xad\x9dM\xf5M6\xb3\xbe\xc5\x1d\x82E\xd7\xc0\x97\xcf\xf9\x16\ +\xb5t\x90\xad%h\x11\xd6h\xc2#@x\xdb\xfa\xe8\xd9`\x7f\x013\xff\x06co\xf0\x89\ +\xa0\'\x12`\xcfr\xf8\xf4a5\x10U[\x11^\xe73\xf2!o(\x8c\xba\x04\x86_\x0c\xa9\ +\xb9\xb6f\xc5Y\x0e<\x02\xbc\xf5\x1d\xf8\xf2\x9f\xb0\xe9\r\xb5,w\x00\x8c\xb9\ +\x12\xc6^\x03\xe9\xf9j\xb0/\xda\xfd=\xfc\r<6\x16L\xbf\xc8:-\xbe\x1aM|\x11\ +\xc2pD\xec\x86\x0b>\xce\x84\x1b\xe0{\x7f\xb1\x1f\x91\x830\xeb\xd4\xe3\xb94\ +\x95\xf8~\xf5/(\xdd\x00\x08\xa8\xdc\x03VPVoJ\x16\xa4f\xabQ\xfc!\xd3a\xc8\xf9\ +\xd0\xe7Dp\xa4\xa9\xe8\x04O\xc3\x06P{\x18\xea* %WY\xc2\xb1FJe\xb0J\xd4?G6\ +\xc3\xf6\x8f\xe0\xdb\x85\xb0\xed#\xd5\xc9\x9c\xfe\xd0s\x84\x8a\xb9\xcd\x1f\ +\x0b=\x867u@H\xef\xa5\x9e\x1eZ\xdf\x19\x95\xe6\xfc\xe9\xc3\xbeE\x91\x12^-\ +\xba\x1aMxx\xf5\xa1U;\xb5@t3{\xc3u\x1fC\xf6q\xa1\x8fa\xd6\xc2\xe2\x9fB\xd9\ +\x06(\x18\xab\x92\x19\x0c\xa1\x1e\xc9\xabJ\xc1rC\xd7\xdeJh\x01R\xba*\xe1\x05\ +\x90\x0e\xf5\x18o\xd5+\x9f\xaa\xbbNe\x90\xd5\x1c\x84\x9d\x9f\x82#YY\x95\'\ +\xfc\x08RrZ{v\x11@\xc2\xe2\x9f\xc0\xa0\x19jP\x0f\xfb\xa1BH\xa8,\x81\xfd\xeba\ +\xdfZ([\x07{\xbe\x80\x8a=\xca\xea\xb5\x9a\x18x\xbc\xe6}\xe8;5\xbc\xee\x1c\ +\xda\x00\x7f\x1b\xe3\x1b\xd8k\xad\xf0\n\xc3!Z\x1aB\xa8\xd1h\x9a\'j\xc2{\xe9\ +\x02\x18\xfc\xfd\xa6G\xdd\xad:\xf8t.|\xfck\x7fQ\xf0m\x93\xd1SE&\x04\x93\x92\ +\xa5\xc4\xd5r\xa9\xe3\x14\x8eW#\xff\x00\xbd\xc6\xc3\xf0\x8b 9;\x8e.\x07\t/\ +\x9d\x0b\x9b\xdeVq\xc3g\xfe\x0e\xfaL\x0er+x\xae\x96\x05\x95\xf6\x97\xc8\x9e/\ +\xa0\xba\x14\x0el\x84\xca28\xb4U}\x99T\x95\xc1\xb5\x1fB\xdf\xd3\xc2\xec\x8e\ +\t\xf3\xcfRV\xb7\x87\xd6D8x\xb6mi\xd2\x8cF\xa3i\x9aF]\r\xad\xb1r\x82\xb7\xeb\ +9\x16~\xfc\x05^K\xafI,\xd8\xf91\xd4\x1e\x81\xd4\x1c\xe8\xde\xd4#\xb7\x8d3%\ +\xd0\x85 \xc1;\x18%eb\xf8x\xb7\xbd\xa5"8<\xb5\x1cF^\x08\x13o\x87\x9e\'\xd8_&\ +M|!\t\xfb\xebP\xa0\n\xf1\xd4W)\xcb\xdd\x11\xe6\xbc\x98R\xc2\x9a\'\xe0\x8d\ +\x9b|\xcbZ*\xbcZ`5\x9a\xc8\xe3\x1d\\\xf3\xdcx\xcd\xdd\x90\xcd\xde\xb0\xc2\ +\xb6vg\xc7V\x00=I\x0c\xf1\x16]\x0fR*\x7f\xf3\x91m\xb0\xe4\xb7\xb0\xf5}\xe5\ +\x1e\xe9S\x0c=G\xc3\xe8+\xa0\xdb\x90\xe6\xab\xa1E\x8a}+`^\xd0\x04\xcf\xcd\ +\xc5^\x07o\xa3\xd1h"C\xb3\t\x14\xad\x15\xde\xfcQp\xc3\x97\xb4\xcc\xda\r\x13\ +\xaf\xc8\x02\xeej(\xf9\x1c\xa4\x0b\xfaO#2aX\x11\xc43\xd0V\x7f\x14>\xfb?\x15\ +\xe5P\xb1[\xadK\xee\n#fCA1\x8c\xb8\x10\xd2z\xf8<\x10\x91\x16c\xab\x16\x9e\ +\x1c\xa7b\x89=4\'\xbcZt5\x9a\xe8\xd0j\xe1\x85\xd0>?\x0f\x97\xfe7\xf2\xd6\xae\ +G\xbc\xdc5P]\xa6\x8a\xbf\xec\xfe\x14\xf6\xaeV)\xb1\x13o\x81\x91\x97\xab\xf0\ +\xac\x84F*\x01\xde\xf2&\xec\\\x02_>\xebKnH\xce\x80>\x13a\xd8L\x188\x1dr\x06\ +\x824"w\x1d\xa5\x84O\x7f\x03\x1f\xfc*pyc.%\xcf\xba\xc8\xb4\xae\xd1h\xfc\x89\ +\xa8\xf0\xe6\r\x85\x1f\xafRi\xb3\x91BZ\xb0\xeb#8\xf05\x1c\xfa\x0e*K\x95\x00\ +\xa7w\x87\xa2)0\xecBpf$\x8e\x8b\xa1\xc5H8\xf4\x8d\xf2m\xef^\xae&\xd4\xf4X\ +\xa3\xceT(\x18\x07C\xce\x83\xdca\x9197)a\xcf\xa7\xf0\xf7)\x81\xcbu\xc4\x82F\ +\x13{\xc2\xaa\xd5\xd0\xd8\xcdz\xea=0\xf5\xb7D\xf4q\xdfc\xed\x86\\\xe7\xe9O;\ +\x96\x08\xff\xc1\xb4\x90\xeb\x89\xdc\xf9\xb9*\xe0\x8f\xfd\x95\xd87\x85\x16]\ +\x8d&\xbaDl20\xe1\x80\xa1\xb3\x89\xb8\x8fU\x08\xfb\x98!^"\xda5\x18b\x80\xb7\ +\xffM\x9cc\xa4H\xea\xaab\xa65\x1aM|\tKxCY\xbb=F\xa8\xea\\\x9a\xc4E\x02\xfd\ +\x9b\x89\x05\xd6\xd6\xaeF\x13}Z$\xbc-\xb9\x19O\xb86t\xb2\x83&q\x10\x02z\x8f\ +\x8fw/4\x1aMD\\\r]z\xc0\xa8+H\xb8P.MCz\x8e\x0b\xb3\xe6\x83F\xa3\x89\x18-\x16\ +\xde\xa6\xac\xde\xe1\xb3!-/2\x1d\xd2D\x97\xb4nj\xf6\x8aPh7\x83F\x13\x1b\xdal\ +\xf1:S\xe1\xc4\xdb\xe36\xc7\xa3\xa6\xb5\x08U\x11M\xa3\xd1\xc4\x8f6\x0bo\xd1\ +\x14\xc8\x19\xd4\xfe\xa3\x0b:\x0b\x12-\xbc\x1aM\xbci\xb3\xf0\x1e?\x87\xa8\ +\xa6\x07k"\x8b\x10\x90= \xc4r\xedf\xd0hbF\x9b\x84\xb7\xdb`\x959\xa6\xad\xdd\ +\xf6E\xaf\xe3UYM\x8dF\x13\x1f\xda$\xbc\xc7_\xad&a\xd4\xb4/\xd2\xf2 7\xa8@}8\ +\xb3\x90h4\x9a\xf0\x08[x\xbb\xf4\x80\xf17\xe8A\xb5\xf6\x88\x91\xa4\x06E5\x1a\ +M|\x08[xO\xbcU\xcdi\xa6\xdd\x0c\xed\x0f)\xb5\xf0j4\xf1$,\xe1M\xef\x0e\xc57i\ +\xd1m\xafH\xa0\xf7\t\xf1\xee\x85F\xd3y\tKxG\xcc\x86\xe4xL"\xa9\x89\x08\xfa\ +\x0bS\xa3\x89/a\to\xd1\xe9\x91\xee\x86F\xa3\xd1t\x1eZ/\xbc\x86\x9a\xdeG[M\ +\x1a\x8dF\x13\x1e\xad\x16^\x01\xa4fE\xa1\'\x1a\x8dF\xd3Ih\xb1\xf0\xea8O\x8dF\ +\xa3\x89\x0c\xad\xb6x\xa5T\x13Lj4\x1a\x8d&\xac{&\xf6\xedw\x14\x0c\x01\xbbV\xc4\xbb\x17\ +\x1aM\xe7%,\xe1\xdd\xb5"B\xb3d\xb6\x02)a\xd7\x12(\xdf\x0e\xd2\x82\xc2I\r\xd7\ +K\x89*D\x10\xeb/\x06\xbf6\xdb\x835)-\xb0\\\xf1\xee\x85F\xd3yq\x86\xb3\x93\ +\xb4"\xdd\x8d\xe6\xb1\\\xb0n\xbe\xaa\xaau\xfe<\xc8\x1d\xee\xd7\x1f\t\xfb\xd7\ +\xc2\xc6\x97a\xf7J\xc8\x1f\x01\x03\xcf\x86\xfeg\x82\x91\x1a\xfd,;\xb3\x0e\ +\xde\xff\x19$\xa7\xc1\xf1\xd7A\xf6q\x89\x9d\xd9Ws\x00\x0e~\xeb{\xaf#\x1a4\ +\x9a\xd8"\x84\xd1\xf2y{@BW\x88\xdf\xb7\ +\xce\'\xba\x1a\x8d&\xf6\x84\xe5j\x80\xd8\xdd\xb8R\xc2\x8e\x0fa\xdfZH\xea\x02\ +\xdd\x87\x05\xae\xdb\xf0\xa2\x12\xd8F\xf7\xb7\xe0\xd0f\xb5m8\x8f\xff\x9eH\ +\x8a\x0f\xee\x86\r\x0b\xa0\xaa\x14,\xb7Z\x97\x92\x05\xe3\xae\x85\xd3\x1f\x04\ +#E\x89\xef\x0f\x96\xc1k\xd7\xaa\x81\xc0\xb4\xfc\xd6\xb7\x17m\xa4\x84\xea\xb2\ +x\xf7B\xa3\xe9\xdc\x84\x17\xd5`AI\x8cF\xc5\x05\xb0\xe9U\xf5{\xc1\t\x90\x92\ +\x1d\xb8n\xcf\x17\xcd\x1f\xa3\xe4\x8b\xb6\r\x06.{\x00\x96?\x02GK|\xa2\x0bPW\ +\xa1\x96\xbfx\x1eT\xefU\xcb\x1c\xe9p\xf6\xff\xc1\x91mmh0\x8a\x08\xa0\xf4K\ +\xbf\xf7\xda\xcd\xa0\xd1\xc4\x9c\xb0\xf5(fi\xc3\x02*\xf7\xa9_\xfbM&0~\xd8\ +\x82\xdd\x9f7\x7f\x08w\x98q\xc7R\xc2\xce\xf7\xe1\x93\x07\x9a\xden\xeb{\xf0\ +\xaf\xe9P_\xae\xdeg\xf4\x81\xae\x85\xado/&H(Y\x19\xefNh4\x9d\x9bV\t\xaf\xbfu\ +T\xbe\x9d\xd8\xf81%t\xed\xa3~u\xa6\xd0@@\xcd\xba\xe85m\xd6\xc0\xe2\xbb[\x16z\ +U\xb6\x1e\xde\xbc\x19\xacz\xdb\xe7\xdb\'z\xfdj\x0b\xd5eP\xd6\x84kF\xa3\xd1D\ +\x9f\xb0-\xde\x92\x151J^\x13\xd0\xd3\x9e\x1f\xac\xf0\xe4\x86\xeb\xba\xb6@\ +\xe0\xba\xf6n}|\xad\xc7\x7f\xbc\xef\xcb\xe6\xb7\xf5\xb0\xfe%8V\xa6\xf6-\xdfJ\ +B\x0e\xb0\x95~\t\xaej\xf5\xbbv3h4\xf1!l\xe1=\xb2\x13\xea\xab"\xd9\x95\xc6\ +\xe9;I\x85\x839\x92\x82V\x08(:\xa5\x99\x9d\x05\x8c\xb9\xaa\xf5\x1a(\xeba\xed\ +?[\xb7O\xff\xa9\x90Q\xa0~\xff\xfa\xc5\xe8Z\xe3aa\xc1\xd7\xff\x8ew\'4\x1aM\ +\xd8\xc2[W\x01\x15;c\x93\xa9\x957\x1c\xfaLP\xd6Z@{\x02\x8ao\x86\xe3\xce\x06#\ +D|\x86\xe1\x84\xa9\xbf\x80QW\xb6>\xa2\xa1\xae\n\x8c`\xa1o\x02a\xc0)?\x07\x1c\ +*\xa6w\xf9\x9f\x13Kx\xa5\x84\xbd+a\xfd\xcb\xf1\xee\x89F\xa3i\xfd\xd4?\xf6\ +\xe3\xa9\xe5\x86o\x17F\xbeC!\xb1\xe7y\xfb\xe6u (k.\xa3\x0f\\\xf6:\xfc`\t\x14\ +_\xafB\xbc\x8c$\x18\xfe}\xf8\xd1r8\xe5W\x84\xf5\xf5\x92\x9a\x0bW\xbe\r\xa7\ +\xdc\xd3\x82\xe4\x0b\x01\'\\\x0b\xfdNW\xee\x97\xcf\xfe\x0f\xea\xab[\xdff4\ +\x11\x12\xbex\xcc\x1ehD\xbb\x194\x9ax\xd2\xaa\xcc5\x0f\x9e\x0c\xb6~\xa7\xc2\ +\xb5\x1f\x81\x8c\xf2-,%\xacy\x0c\xde\xbc\r\xae|\x03\xfaOkh\xc1J\xa9D\xaf\xee\ +\xb0J\xa6\xc8\x19\x02\x88\xb6\xa5\xeezj?\x94\xad\x86\xa5sa\xd3\x1b\xa1\xad\ +\xd8a\xb3\xe0\xa2\x7f\x03N\xd8\xfb\x19<3U\r\x04\xfe\xcf\x1eH\xee\x1a~\xfb\ +\x91BJ\xd8\xfe.\xfc\xeb\\_U7-\xbc\x1aM\xfchS\xad\x9b\xf2\x1d\xb1y\x9c\x16\ +\x02F_\xad\x92\'^\xbf\x11J\x96\x02V\xa0\xdbA\x08@@J7\xc8\x1d\xa6\x1e\xfd\xfd\ +E\xd7#\xa2\xadq\x8dx\x8e\xd9s<\\\xf82\xdc\xf4%\x8c\x9d\x03\x8e\x14\xdf6\x85\ +\'\xc19\x8f\x01NpW\xc2\x7f.SQ\x10\xdd\x87AJf\x9bN;"H\xa92\xec\xde\xbcE\x8b\ +\xaeF\x93(\xb4\xc9\xe2E\xc0e\xaf\xc0\xa0\xf3\xa3_\x14FJ8\xb2\x19^\xb9\x12\ +\xf6~\tc\xae\x84\xf1?\x86^\'\xd8\xbe\xd8\xe0\xaf\x10\x89\xd7-ql\xbf\xca|\x93\ +.8n&\xad\n\xc70ka\xf9\x83\x907\x12\x86\x9c\xaf\xda\xaa*\x81\x83\x9bTB\xc5\ +\xf0\x8b\xc1\x91\x06\xd2\ro\xdf\x02\xab\xe6\xa9\xfdz\x17\xc3\x8fV\xc6?\xb0\ +\xc1\xaa\x83\xe7g\xc0\xb6\x0f}\xcb\xb4\xf0j4\xf1%\xac\x94aa8\x84\xb4L\x89\ +\x84\r/\xc3\xe0\xf3#\xdd\xad\x10m\n\xc8\x19\x0c\xd7|\x0c\xab\x1e\x83/\xe6\ +\xc1\xda\xe7 \xabP\xbdr\xfa\x07no\xb9\xa0d\x15 \x95?z\xfc\x8f`\xe2O\x94\x10\ +\xb6Fu\x8c\x14\xe83\t\x9e?\x1f\x06}\x0ff<\n\x99\x85*=\xd8\x83\x94\xb0\xf1EX\ +\xf5\x94oYf/\xdb\xba\x8e\xa3\xc4I\t_>\x15(\xba\x1a\x8d&\xfe\x84e\xf1\x82\xcf\ +\xeaM\xeb\x06\xb7m\x82\xd4n\x11\xedW\xd3mK0\x8f\xc1\x96\xd7a\xd9\xc3*yA\xa2\ +\x92\x17@E3\x08\x03\xb2\xfa\xc2\xc4\x9ba\xe4\xa5\x90\x9eo\x8bn8B(\xe1\xc3\ +\x9f+?oF>\x9c\xf5\x00\x8c\xba\n\xef\xd7VM\x19\x84M\xaf\xb5\x8f\xc9\x1e;*R\xc2\xc6\x97\xe0\xab\x17\x03\x97kkW\xa3I,":\ +Y\xf0\xc7\xf7A\xed!-\xbe\xf1@J\xd8\xff%\xbc\xf6c\x02\x82\x87\xb5\xe8j4\x89GD\ +\x84\xd7ss\x97m\x80\xa5\xbf\x8dk\xe8j\xa7\xc5U\t\x0b.\x8b]\xc58\x8dF\x13>\ +\x11\xb5x\x01V<\x06[\xdf\xd2Vo,q\x1f\x83\x0f~\x06\x077\x07.\xd7\xd6\xaeF\x93\ +\x98D\\x-\x17\xbcr\r\x94~\xa1\xc57\x16HK\xcd\t\xb7\xf2\xf1\xc0\xe5Zt5\x9a\ +\xc4%\xe2\xc2\x0bp\xec \xfc\xeb\x1c8\xbcQ\x8boT\xb1S\x95\x97>\x14\xb8X\x8b\ +\xaeF\x93\xd8\xb4)\x8e\xd7\x83\x7f<\xaf?\x99\xbd\xe0\xf2E\x90?\xae\xf3\xc4\ +\xf7\xc6\n)a\xcf2xn\xbao*\x1f\x0f\x1dMx/\xbau\xa1\xdc\xb9\xe7(i\xe9\xc9`\x97\ +\xff\x94\xc2\x1eK\x90~\xa9\xe0R"\x85\xb0\x17H\x04\xeawO\xd9R\x81\xdf\xb8\xa3\ +\xf4[\xd0\x8e\xaf\x96\x90 \x85D\n\x89a\t\x84pP~\xa0\x84\xe21\xb9\xcc{\xe8\ +\xdav|f\x1d\x9b\xb0\x8a\xe4\xb4\x94\xca}\xf0\x9fK\xe0\xc2\x17\xa1g\xb1Z\xa6\ +\x058\x02H8\xb4^\xd5\xd7\xed\xe8\xa2\x0b\xf0\xedw\x87\xd8\xbc\xed0)\x19\xaa\ +\x1e\xa7\x12\\\x89D \x84\x92Ri\xab\xa7\xf0\x08\xa9\x00\x89\xaa\x05*,\xb5@z\ +\xfe\xf5\\!)}\x01\xd9\xed\xf9\xc9\xcc>Wa\x810\x9cT\xee\xddKN\xd7\xfax\xf7J\ +\xd3\x04Q\x15^\x80\xc3\xdb\xe0\xf9sa\xe6\x130dv\xb4[\xeb\xf8H\t\x876\xc2\xfc\ +s\xa0\xeeh\xe0\xba\x8e(\xba\x00i\x19\xc9\xa4uM%3C\xcd\xc5$\x10H\x0b\xdb\xaa\ +\xb5\x0b-\xe3\x00\x0c\x90\x16RX\x08\xfb\x1b\xdeS _Y\x86\xc2+\xc6\x08\xe1\x95\ +b\x84\x9f\xc7\xad\xddY\x06\x96:})@Z\x08\xc3I]u\x1a\xe9]R\xe3\xdd1M\x13D\xd4\ +\xc7\xdb\xb3gO\xfe\xfb\xdf\xffr\xddu\xd7\x91\x93\x93\xe3]^}\x00^\xfd\x01\xac\ +{F\r\xbei\xbfoxH\t\x15[\xe1\x85\xf3\xfc\x8a\xf2\xd8tT\xd1\xf5G\xd8\xff\x81\ +\xd2G\x03\x10\x9e\x0f\x93\x04,\x894l+W\x82\x90\x06\x02\xbb"\xbe\x90\x08\xbb@\ +\xb3\x94\x1e\x0b\xd7@\x99\x8b\xaaB~P"b;y\x19\x08a\xa8Sl\xcf>\x93NFD\x85799\ +\x99\x993g\xf2\xf4\xd3O\xb3~\xfdzn\xb9\xe5\x16\xaf\xe5Q[\x0e\xaf]\x0fo\xdd\ +\xa8\xa6\xe7\xd1\xb4\x0e)a\xffjx\xee{pd[\xe0\xba\xce \xba\r\x91\x08)\x10\xc2\ +\xc0\xb2\x0c\xea]\x165\xaez\xea\xea\xdd\xb8\xdc M\xa1\xdc\x0e\xb6\x85+\xa5\ +\xb0\xbf\xf0%\xc2P\xeb\xa4E\x03\x17C\xfc\x854\xfc\x97\xa6\xfd\xd0f\xe1\xf5\ +\x1fX\x1b=z4N\xa7\x13!\x04\xbd{\xf7\xe6\x91G\x1e\xe1\x7f\xff\xf7\x7f\xfd\xb6\ +\x85\xd5\x7f\x87\xe7\xceVs\x80\xc9VN\xc5\xd3Y\x91\x12v}\xa0\x06\xd2\x82E\xb7\ +s\xa2T\xd3\x14\x92:\x0b\x10\x82\xf44\']\xbb\xa4\x90\x99\x9aLJ\xb2\x03SH\\\ +\xd2Bb!\xa5\xc7\xf5`\xd8\n\xa5,_C\x80D\xa9\xafhw.\x06M{&\xa2\x16\xef\x80\x01\ +\x03\x02\xde;\x1c\x0e\xee\xba\xeb.\xbat\xe9\x12\xb0|\xdf\x1ax\xfe\xbc\x1fv,\x83s\x1eU\xb3\x02k\ +\xa3\xc3\x87\x94 ,X\xfd\x18\xbc\xf5\x13\xfb\xb1X\xe3\x8b\xfe2\x05\x96e2\xeb\ +\xb4\xbe\\z\xd6@\xc6\x0c\xce!;;\x15i\xc1\x81\xc3\xf9\x9cQ\xdc\x87\xff,\xfe\ +\x8ew>\xdd\x8d\xc4\x890,\xe5U\x90\xf6\x83\xb9@]T)\xf4\x07O\x13s"*\xbc\x83\ +\x07\x0f\x0exd\x93R\xb2r\xe5J\x8e\x1d;\x16z\x07\t\xdb\xde\x87\x7f\x9c\x0e\ +\xdf{\x08F\\\xa2z\xd4\xd9\xef\x03\xcf\xd4F\x0b\xaf\x86\x8d\x0bi\xdf\xa1NQ\ +\xc02%N\x03\x86\r\xe8\xc6\x0fg\rc\xd2\x84B\x844\xc1TB\xda\xb7o\x1a\x85}\xbb\ +\x93\x9e\xe2d\xdf\xfe\x1a\xd6o+\xc74M\x1c\x0e\x03p\xa8\xc8\x06\xff\xb83\xf4g\ +N\x13["\xe6j\x10B\xd0\xad[\xe0\xc4k\xa6i\xf2\xf8\xe3\x8f7\xb2\x87\x8f\xaa}\ +\xf0\xdf\xab\xe0\xef\x93\xa0l\x95m\x88tR\xb1\x91\x12*w\xc0\xbf/\x84\x8d\xaf\ +\x10 \xba\xc9\xc9\xc9\x0c\x1a4(^]K\x08\x04\xe02-\x9c\xc9\x823N\xea\xcd\x90\ +\xbeY\x08\xcb\xc4\xacuc\xd5K\xa4\xcbB\xd6\xba\x11f=\xc7\x0f\xcbc\xe6\xe9\x03\ +\x11\x02\xdcn%\xb4\x86m\xec\xaap^\x87WqC=\x95i4\xd1"b\xc2\xdb\xa3G\x8f\x00Q\ +\x90R\xf2\xe7?\xff\x997\xdex\xa3\xc5\xc7\xd8\xb3\n\x9e:\x19\x16\\d\x0bp\'*\ +\xac\x0e*\xd4\xee\xabg\xe0\xf1q\xb0\xe5\x9d\xc0u\xa7\x9ez*K\x97.\xe5\xb9\xe7\ +\x9e\x8bO\xe7\x12\x08K\x82\xc3\xe9\xa4o~\x172\xbb8\xc1\x94\x18R\x00\x12)\xd4\ +`\x99\xe52I\xcfLe\xd8\xc0\xae\xb6uk\xd8\xf37Y\xbe\xfc\t\xcf\xb7\x9a@\x0f\xae\ +ibJ\x9b\x84\xd7?\xa2!;;\x1b\xa7Sy.\xa4\x94|\xf5\xd5W\xfc\xeaW\xbfj\xf51-\x97\ +\xb2\xf4\x9e:\x19\xde\xbd\r\x8e\xeeD\rbw`\x83DJ\xa8\xdc\r/\xcf\x86W\x7f\x04\ +\xb5G\x02\xd7\xff\xf4\xa7?e\xf1\xe2\xc5\x14\x17\x173|\xf8p\xf2\xf3\xf3\xe3\ +\xd3\xd1\x04B\xc5(x\xc4R%M\xe0\xcdb\xb3\xecm\x0c\x1c~\xb1\xbf``\x19\xc2\x9bB\ +\xec{\xb4\xf2\xb8\x1b\xb4\xf8jbC\xc4,\xde\xe1\xc3\x87\xe3t:\x91RRRR\xc2\x8c\ +\x193\xa8\xae\xaent\xfb\xff\x9d<\x99\xc5s\xe6P\x94\x1dz\x86L\xcb\xa5JL>6\x06\ +\xde\xfb\xa9J\x1c\xb0\xea;\x98\x00\xdb\xb1\xa4\xbb?\x86\xf9\xd3`\xf3\x9b4\ +\xf0\xe7\x9ew\xdey<\xf8\xe0\x83$\'\'#\x84 33\x93\xf1\xe3\xc7\xc7\xa3\xb7\t\ +\x83\xc7U`y\x92\xd6<\x0b\r?_\xad\xfd\xd3\xf2/\n/|\x1bx2\xdet\x1c\xac&\x1eDLx\ +\xfb\xf7\xef\x0f@yy9W\\q\x05{\xf7\xee\xf5\xae\x0b\x0e\xf0\xef\x99\x91\xc1\ +\xcf&O\xe6\xcc~\xfdX\xfa\x83\x1fp\xf1\xc8\x91\x8d\x1e\xb7\xae\x02\x96?\x02\ +\x8f\x0e\x87gOW.\x08wU\x07\x10`\t\xc7\xca\xe0\xbd;\xe0\xd9\xef\xc1\x81\x8d\ +\xa17+..&99\xd9\xfb^\x08AAAA\x8c:\xd9~Pv\xad\x01\xc2\xc00\x8c\x16dq\x89\x80\ +\x1f\x1aM,\x89XTCAA\x01\xe5\xe5\xe5\x9c\x7f\xfe\xf9,]\xba\xd4\xbbuuu\xdcr\xcb-\ +\x14\x17\x17SPP@\xbf~\xfd\xd8\xb6M\x97*\xd3h\xda#\x11\x15\xde\xc6Ds\xee\xd9g\ +3(;\xbb\x81\xb5[Y_\xcf\xcf>\xf8\x80\xc7W\xaeTO\xf8m\xf0S\x86\xda\xb75b\x1c\ +\x0b\xba\x0f\x87\x11\x17\xc0\x88\x8b w\x08\x88$\xdb\xefl)\x9ft\xc9g\xbem=~[\ +\x7f\xabw\xef\xde\xbd\xfc\xf4\xa7?\xe5\xe5\x97_f\xc0\x80\x01|\xf4\xd1Gq:\x13\ +\x8dF\xd3\x16"&\xbc\x8dY\xa0C\xf3\xf2\xb8t\xc4\x88\x06\xa2\xeb\x96\x92{?\xfa\ +\x88\xc7V\xae\x0c\xb9\x7f\xa4\xfa\x14o\xf1u\xa6B\xe1D\x18u\x19\x8c\xbc\x1c\ +\x9c\x19v\xdf\xfc\xceV\n\x18:=Px\x1b\xe3\xb5\xd7^c\xf5\xea\xd5\xba\xb6\x80F\ +\xd3\x8e\x89\xea\x9ckI\x86\xc1o\xce8\x83\xd4\xa0\x015\t<\xfa\xc5\x17<\xfa\ +\xf9\xe7\xd1l\xbeQ\x84\x80\xd1\xa3\xbb\xb0m[-\x95\x95*2 )\x03\x1cI-?Fj\x16\ +\xf4\n\xf2\x0fw\x1b\x04]z\xf8m\xd3\x15\x06N\x83\x8c>\xd8\xf5\x00\x1a?\xde\ +\xe8\xab\xe1\xe3\x07B\x0f\xca\xf9\x7f\x81\xd4\xd7\xd7\xf3\xfb\xdf\xff\x9e\ +\xd1\xa3G\xb7\xbc\xb3\x1a\x8d&\xa1\x88\x88\xf06f\xed\x9eu\xdcq\\0th`\xd0\x80\ +\x94\xfcg\xd3&\xee~\xf7\xddF\xf7\x8f$\xa1\xac^!\xe0\xef\x7f\x1fJ~~2#G\xae\ +\xa4\xa2\xc2\xe4\xfc\xc7\xed\xb2\x94->0j~\xc5F""Z\xd5G\x01\x99}a\xc8\xb9\xf0\ +\xf5\x82F\xb6\xf1;\x8fO>\xf9\x84\t\x13&\xb4\xbe!\x8dF\x93\x10\xb49e\xb81\xd1\ +4\x84\xe0\x8e\x93Nj \xba\x9b\x8e\x1c\xe1\xf67\xdf\xc4eYx|\x98m\xedCk\xfbhY\ +\xb0~}5\xbd{\'SX\xa8\xa6\x0cw\xd7\x83t\x02I-|9i(\xb2m9\x13\x01\xbd\xc6\x06.j\ +\xccMr\xf0\xe0A\x1e}\xf4\xd164\xa6\xd1h\xe2IX\xc2\xeb\x11\x84\xa6\x06\xb4N-*\ +\xe2\xb4~\xfd\x02\xd6\x1d\xae\xab\xe3\xbaW_\xa5\xb4\xaa*x\xb7\x98\xb3`\xc1\ +\x81\x80z\x0f%\x9f\xc5?\xe5x\xccUM\xaf\xf7\xbf\xde%%%Mm\xaa\xd1h\x12\x98\xb0\ +-\xde\xe6,\xd5[&N\x0c8\xb8KJnx\xe3\r>\xdb\xbd\xbbE\xfbG\x9b\xcf>\xab\xa0\xce\ +/|\xab\xb2\x94\xb8\xcf\xf4\x90\xde]\xf9\x895\x1aM\xc7&,\xe1mL4\xfd#\x19\xa6\ +\x1fw\\@a\x97\xdf/[\xc6\x02\xbb\x06C\xbcE\x17\xd4\x8c\x04\xb5\xb5\xbeJ\xeb\ +\x87\xb7\x11w\xe1\x15)0\xe0\xb4f\xb6I\x80k\xa7\xd1h\xdaFDg\x19\xf6p\xc3\x84\ +\t\xdeH\x06)%+KKy`\xc9\x12 ~\xc2\x11\xdc\xee\xd1\xa3&;v\xd4&T\xf1k!\xec\x01\ +\xbef\xba\xa4\xc5W\xa3i\xdfD\\x\x05pB\xcf\x9e>A\x13\x82\xbf\xae\\I\xad\xdb\ +\x1d\xe9\xa6\xda\x8c\x10\x92\t\x13\xba\xc6\xbb\x1b\x01t\x1f\x06Ii\xad\xdf/\ +\xde\xf1\xca\x1a\x8d\xa6\xe5DLx=7\xfe\xe9\x03\x06pra\xa1Z&%\xefm\xdf\xceK_}\ +\x05$\xa6\xa5\xe6H\xb0.\xa5\xe7CVa\xbc{\xa1\xd1h\xa2I\xc4-\xde\x9f\x9fr\n\ +\xc2\x0e\x17pI\xc9\x1d\xef\xbc\x83\xdb\x0e\x1d\x8bt[m\xc5\xe5J@#Q\xc0\xe0\ +\x19\xbe\xb7\x8dY\xb2\x89x=5\x1aM\xcb\x88\xa8\xf0\xa69\x9d\x0c\xcb\xcbC\x08\ +\x81\x94\x92\xa5\xbbw\xb3\xe9\xc0\x81H6\x11Q>\xfd\xf4h\xbc\xbb\xd0\x00\t\x14\ +\x9d\x1a\xef^h4\x9ah\x12\x11\xe1\xf5XeW\x8c\x19C\xcf.]\xd4B!\xf8\xdb\xca\x95\ +\x98R&\xacu&\xa5\xa4\xb883\xce\x9dP\xb3jH\xb7za\xaab:-I\xc6H\xd4\xeb\xaa\xd1\ +h\x9a&\xa2\xb5\x1a\xa6\x0f\x1a\xa4\xdc\x0cBp\xa0\xa6\x86\xf7\xbe\xfb.\x92\ +\x87\x8f\n\x19\x19\x8e\x98\xb6\xe7I\xda\xb0j\xa1d\xb9\x9aG\xee\x9b\xd7\xa0\ +\xce\xcf\xf8\xb6\\\xc4=\xb4M\xa3\xd1D\x8f\x88\tozR\x12\xe3\n\n\xbcn\x86\x0f\ +\xb6o\xa7\xca\x9e\x91B\xe3\x9b\xcd\xa2\xfe0,\xfb=\xac\xff7T\xec\xa6\xcd\x02\ +\x9b\x08\x15\xd84\x1aM\xeb\x88\x98\xf0vMI\xa1\x97\x9f\x9b\xe1\xa5\xf5\xeb\ +\xd5\xaf\xfaq\x18)\xa1f?,\xfd\x1dl\xf8w\xd0\xcc\xc2)@\x010\x04\xb0\x80\x15@+\ +\xe7g\xd3\xd7X\xa3i_\xb4Yx=\xd6VA\xd7\xae\x18v\xec\xee\xc1\x9a\x1a>\xde\xde\ +\x8a\xa9t\xe3\xc8\xd1\xa3*\xbe89\x83\xa8\xccL,%l~\x05\xde\xbf\x07\x0en\xb6\ +\x17\n`$0\x1e\xe8\t$\xfb\xed0\x04x\x1a\xa8\x89|_4\x89\x81r7\xb5\xfe!\xa5\xa9\ +d\x1f\xfd\xc8\xd3\xbe\x88\x98\xc5{r\xdf\xbe8\xec\x0f\xc6\xfec\xc78Z\xd7\xc4<\ +6\t\xc4\xaaU\xaa`O\xaf\xd1aWu\x0c\x89\x94 ]\xb0\xfa\tx\xe7\x7f\xc0\xf2\xe4\ +\x8f\xf4\x02f\xda?C5\x98\x03L\x00>\x89PG4\x89\x85\x04\xa4D\n\xcf\x1bT%|\xfb\ +\xbd\xe7\xe3 \xfd?\x1b\xb2)\xd1\x95\xde\x9f\xd2o\x7fMb\x131\xe1\xed\x97\x9d\ +\xed\xfd\xa3\xaf/+kr\xdbDAJ\xc1\xee\xdd\xbe\xca\xe3\x91\xca\x1e\x96R\r\x9e\ +\xbd};\xac~\xca^\xe8\x04\xce\x03F\xe0\xbb\xa1\xfcn\xac\x80e\xb9\x91\xe9\x87&\ +\xf1\x90\xf6+\xa04\x1e\xd2\xa7\xc1A\x1bK)\xfcD\xb8)\xbbV\x80%\x10\x18HK \xa5\ +\x96\xe0D&b\xc2;0\'\x07P!Z;\xca\xcb\x81\xf6\xe1{,)\xb1\x857\x82\xcfj\xd2\x05\ +\xf3\xcf\x86\x9d\xcb\xec\x05N\xe0B\x94\x1b!`C\xc0\r\xec\x06\xf6\x02\xf5@\x17\ +\xa0[\xe4\xfa\xa2I0\x84\xb4\x7f\xa8Ah\x89\x85\x10\x12\xa4\x01\x18 L\xdbru\ +\xe2\x90\x82c\xf5I\xd4[\x0eD\xb3\x1fP\x89\xb0\x04\xc2pb\x1eK\xa2\xbe.5\xea\ +\xa7\xa2\t\x9f\xc8Y\xbcYY\x80z$Z\xbf\x7f\x7f\xa4\x0e\x1bU\x06\r\xf2\x15E((\ +\xb6#\x0f\xda\xf0U!%\xb8*\xe1\xdd\xdb\xfdD7\x19\xb8\x14(\xf2\xdf\x10e\xc1|\ +\x07\xbc\x05\x94\x03\xd9(q>\x0f(\x04^@;\xee:,\xb6\xf8\x02\x12\x03\xa4\xa5\ +\xdc\x0fH\x04\x02!\xc0m\x9a\xb8j+8e\xf4&\x8a\n\x0eSW\x9f\x14\xda\x0f&\x95\ +\x93\x01a!L\x03!\x04U\xd5G\xe9\xdb3\x8d\x87>\xbfG\xa6\xa4\xa5\xe02-\x84\xc7\ +\r\x91\xf0\xa6P\xdb\xb0\xccZ\x92\x92\xb2\x19>\xe6\x9e\x84>\xd3\x88\x08o\x97\ +\xa4$\xf232"q\xa8\x98\xd2\xa7O\x8a\xf7\xf7\xe4\xcc\xb6\x8b\xaet\xc3\xe2\xff\ +\x815\xff\xb4\x17:\x81\xef\x03\xfd\xfd7DE/\xbc\x03\xacAE5<\n\\\x04\xf4@\xdd\ +\x18/\x12 \xba\x9e\x19\x87\xc3\xef\x9d&\xb1\x10J,m\xa4-\xb6\xea\x0fl \x10\ +\x98\xee:\xcc\xba\x83\xcc:i\x153F\x97QS\x99\xd2\xd8\xc1\x1a\xe0\x90\x0e\\\ +\x98\xec?\xfa!UU\x16\x864pZ\x06\xf5N\x17)\xeedD\x07V\xdfzj \xb5w\xbc\xbb\xd1\ +,\x11\x11\xdeT\xa7\x93\x9c\xb40Jj\xc5\x90\xe0X\xd7\xe4dAr\xb2Ay\xb9\x1b\xe1h\ +8\xedN\xab\x8e-\xa1\xf6\x10,\xfa!|\xfb\x9a\xdf\x8aSh\xe8^\x10(\xc1]\x85\x8aj\ +x\x08\x98J\xa0%R\x1d~_4\x89\x8e\xf0\xca\xae\xf4z|\xa5_\xedj\xd4`\x9b%0\x04\ +\xe4d\xa4\x93v\xb4+\xa94\x1d\xd5\x10\xd4\x04R:\xe9\xe6\xc8\xf7\xbe\xf7\xe6\ +\xa8:\xe9\xd0\xc2+\x85\x05\xddz\x02\xdb\xe2\xdd\x95&i\x93\xf06\x17\xb8\x9f\ +\xc8\x96ZF\x86\x83\x8c\x0c\x07%%\xf58R\xecp\xb20\x11\x12\xde\xba9Ht\x8f\x03N\ +\x0e\xdaP\x02\xfb\x80\xf7\x80\xd3\x80\x85@W:\xfc\xe3\x9f\xc6\x1fi\x0b\xae\ +\xb0\x9f\xb0\xa4zZ\xb2$R(W\x03\xc2P.\x08\xcb\x89e)\xc5lm\xdd\xe8D\xaa3\x1dK\ +\x04\x06X\xb1\xcdF\r\x87\xb0k5\xf8\x8b\xee\xc5\xa3F\x91\xe2\xf9\xc6F\xb9\x1e\ +\x12\x9d\xf1\xe3\xbb\xe2v[\x00t\xed\x05]\xfb\x84w\x1c)\xa1b\x87J\xfb\xf5\x92\ +\x8d\xf2\xd5\xfa_]\tT\x02\xff\x02n\x03\xdeD\x8bn\'FH\xc0\xf2H\xb0C\xcd\xb4*\ +\x1d |n\x07)eP\xf4\x83\xa6%\xb4\x87+\xd6\xa6\xc9.\x01r\xd3\xd2\xf8\xe9I\'y\ +\x93\'\x90\x92\xe2\x82\x82\xc8\xf4.\x8a\xf4\xef\x9f\xca\x9a5*\x867\xabP\xb9]\ +\xc3e\xdd\xb3`\xfa\x87-\x9f\x01\x04[\xd0\x02\xf8\x0c\x95\xa5\xf6\x1b \r-\xba\ +\x9d\x12\x81gX\xcd\x8e\x17C\x19\xb9\xc2+\xb6\x16\xca\xfa\xc5\x90\xde(\x08MkH\ +\xfck\xd6jWC\xb0\xe8\xbe~\xc5\x15\x0c\xb4#\x1a@=\xe2\xf4\xee\x9aX\xb3:\x84b\ +\xe0\xc0T\x96/W\xb9\xb9E\xa7\x86\x9fq\xfc\ +\xf1\x99t\xe9\xe2\xa0\xa6\xc6"\xab/\xf4\x18\x15\xdeq\x84\x80\x92\xcf\xfd\x16\ +d\xa2\\\r\xfeT\xa2\xc2\xc7r\x81\xd14/\x18\x02\xe5\x96\xd0x1IB`I\xc9\x1fW\xac`h^\x1e\xd3\x06\x0e\xc4\x19\xf4G\x1d\ +\x98\x9bKvj*\xe5\xb5\xb5\x8d\x1c)>L\x98\xa0B\xdd\xde{\xef\x08)]\xa1\xd7\t\ +\x112\x08\x04\xa1-^Od\xddJ\xc0E`\xd1\xf3PT\x02A\x93\x1f\x87\x93\xfd\xb7\xeb\ +\xc1\x07\xa9\xdd[\x86\xd3ax\xbb\x17\xd1\x82\xc3Q\xc2\xa33I@\x95e\xb1\xd2\x99\ +M\xed\xe8;02\xfb\x81\xbbF}\x81XV{\x0elh9\x1e\xc38\xe4:\x81\xcc\x1c\x88t\xf6C\ +Xuv\x9a\xb1\x81\x14\x02\x84\x85!M\xa4\x14\x08\xe38DfOd\xd9\xaeX\xf6\\\xd3\ +\x0c\xad\x16\xde\xc9\xfd\xfa\x01\xf0eY\x19?\x7f\xef=L\xcb\xe2\xee)S\xf8\xedi\ +\xa7a\xe0KUt\x1a\x86\xb70z\xac\xd3\xb4I\x15K\xfc\xfc0\xd2\x81\x10\xe04 \ +YZ$\x1b\x867\x99@\x08\x81%\xa4\xb7\xdaA\x87\xc6\x9b\x08\xda\xf8\xdfGH\x07\ +\x86%\xec\x1a\xe8n\x84a }RX\xb6\xac\x1c\xc3\t\xc7Mo\x9b\ +\xc6U\x97\xfa\xcd\xa3\x06\xb0\x9f\x86\x07\xec\x85O|\x97\x00\x1f\x87\xd8\xc6\ +\x9fO\x9aY\xdfB,!pKpK\x81\x89\xaa\xb7nJ\xc3N\x8d\xf6\xccx [\xf1\x8a&\xc2O{\r\ +,\x04nia\xaa2\xe1\xde\xae\n\t\x0e\x8f\x9b:H\x8f<\xf1\xb1\xbeW\xa8v\x1a.\x94\ +\x01?\x13L\x9e\x9a\xb9\xf4*\xa3\xd8.\xa6\x0e\xca\xb7k\x00\x9e\xf8`\xe99L\x82\ +\x9d\x97\xa6u\xc2\x9b\x95\x9aJfJ\n\x0f\xfaY\xbb\xfel?r\x845\xfb\xf6%l\xf0\ +\xf6\xb9\xe7v\xc30\xa0\xbc\xdcMV_\xc8\x1d\xd86\xff\xee\xd1\x12\xbf\xb9\xd4@E\ +0\x04\x1fO\xa0\xcaC\x1a(\xab\xf7\x87\xa8\x8au\xa1.\x91D\xc5\xfcF\x08K\xd89\ +\xffvM\x00)\xecY\x0e\xbc\xb1\xa3 \xf1Y\x90\xb2\xd1\xffZ\'\xd1a\xbd\xecLY\xcf\ +\x85\t\x1c\x03\x14HCb\tK\xb9M\x84\xbf\xa8\xf8]>?\xe1\rP-\x8f\xf5h_\x87\x80\ +\xfd\xbc\xd6`cb\x1d\'\xec\x07\x80&?\x9f\xc2\xb2\xaf\x99@H\xc3\xbe^R\x85\xdfy\ +N\xda\x90m(\x85\xa5\x89\x16\xad\xfa\x938\r\x83\xd5\xa5\xa5\xbc\xe1g\xed\n\ +\xc3!\xfc\xfd\xb7Kv\xeeL\x98\xf0\x15\x7f\xff\xae\xd3)\xb8\xec\xb2\x1el\xd9R\ +\xcb\xd7_W3\xe4\x1c\x10\xcd\rt5C\xaf\xf10|\xb6\xdf\x82#!6\x12\xc0@T*1\xc0\ +\x0eT\xe5\xb2P\xe2[\x8f\x9a\xde=\x12\xf8\xdd\xb8\x06\x86\xfaC\xdb\xb5\x00$ \ +\xa5\x05.7\xb2\xd6\x85U\xe3\xc2\xaaw\xa9p-a\x8b\xb2\x90>q\x16\xb1{y\n\xc4\ +\x18\x08e\xd1y\xaf\xa3\xf0\xaeo\xf0\x95\xef\xd9\xc8\x16Q\xff\xcb*\xa4DX\x9e\ +\x8d\xfc\x0f\xe8\xc9\x80\xb3\xbf\x94\xda\xe1\x1ce\xde/+\xf5\x07\xf5~Y\t\xa4J\ +\xc4\xb0\x97k\x12\x8fV\t\xef\x84\xc2B\x1eZ\xb2\x84z\xdb\xda\xf5\x17\\\xcf\ +\xef\x1f\xd9\xd3\xba\x07|\xf8\x13\xa0&\xef\xc4\x89\xca\xcd\xf0\xee\xbb\x87\ +\xa9\xaf\x97\xf4;\x85\xb6\xbb7\x1d0\xfd/~\xb1\xc0e4\xfeh8\r8\xc1ns#0\x06x\ +\x15\xa8\x00L\xd4\xf4?\xabQ\xf3\xafE\x00ik\x8aa)+\xd7\x12\x80t\x83e\x82i\x82\ +\xcb\xc4HI\xc6\xd1\xbd\x07\x8e\xfc\x1e\x88\xae]\x90\xa6\x84z\x0bC\xaa\xfc0\ +\x7f\x83Q\x88(\xbe\x90\x08)\x94hx\x85\x10{\x84^\x89\x88\x90\x02\x03\x87\xaa\ +\xb7\xea\xb1Z\x85e\xfb\xae=\x16\xb0\xf0\xfc\x1f\x80\xd2 \xdb\x92\x0e\xf8`z\ +\xd5)2\x17=\x92\xb4\xa4k\xb6\xfbEY\xbe\xbe\xa7\x13\x95Zm\xf9.K\x02\x9e^g\xa7\ +U\x83k\xfb++y\x7f\xeb\xd6&\xb7\xd9|\xf0 Un7\xa9\x0e\x07\xdf\x1d>\xdc\xa6\xce\ +E\x92i\xd3\xba\xe1p\xc0\xe2\xc5\x87I\xcf\x83\xfeg\xb4\xfd\x98B@z/\x98\xfd\ +\x0c\xcc?\x07%\x9ee@>\xa1\xef\xfe\x99\xa8\xb2\x90o\xa1f\x99\xb8\x00\xc8\x03\ +\xba\xa3\xfc\xc3\x11\xbc\\\x12\x15\x0b+\x84i\xfbJ%\x06j0Fb r\xb31F\x8f\xc69f\ +,"\xc9\x89\xb9{\x07\xf5+V\xc2\xce\xdd\x08S"\x1dN\xfc\x8beF\xf5\x9b\xd3\xef\t\ +\xc9\xa3\x9fM\x89\x85\xf0l)P\x96\xaa\xe5\xb4\xad?\x13\xc32T&\x18\x00\x06\xd2\ +0\x94\x15\x8d\x89\x90\x86\xaa\x93\x80z\n\xb0\x0c\xec\xba\t\t\xf3\x90\x16\x82\ +\xa6;\xa6\xbc.\rS/\xbc\x0f\x01Zt\x13\x92\x16\x0boVj*\x0e\x87\xc3{?4f\xc5\x1e\ +\xed\x0c\ +\xe8\x92\x81\xac\xad\x81\xdaZ\xa8\xab\x85\xdaZ\xa4\xe5&i\xc2\xc9\xa4\\r\x15"\ ++[\x99\x81V\xe2=\xab:\x1c\x82\x1a\x97\xc9\xd2/K)=T\x0b\x8e\x14\x8c$\xc3v\x19\ +Hp\x1a\x88\x94T\xf6\xec\xad\xe0\x9d\xa5;\xb1\xa4\xc4\xe1TWCH\xdfu\xf1\x0b\ +\xa5\xd0hbJX\xc2\xdb\xdc\xe3\xef\xee\x8a\n\xde\xb5\x07\xd9\xe2Mv\xb6\x83\x99\ +3s\xd9\xb6\xad\x8e\xd5\xab+\xc9\xea\x07\xd9\x03#\xdf\x8e\x10\x903\x14\xae\ +\xfd\x102\xcaQ1\xbbqDY\xf4\x12\xb0\xd4\xcc\xab\xa6\x84\xd4t\x1c\xa3\x8fG\xa4\ +\xa5#,K\r\xbcIC\r\xca\x18\x12Q\xefB\x18\x0e\x8c\xc2B\x1c\x85\xf9\xe00Tzn\x02\ +!\x00\x87\xc3\xa0\xce4\xf9\xf0\x8b\xbd\xbc\xf2\xfevv\xee<\x8c\xcbeB\x92\x81p\ +&Q_\x0f%{+\xf8\xcf\xe2\xad\xbc\xff\xd9\x1e\xa4\x00\xc3\x93:-\x85\x8at@\xda\ +\xa2\xeb\xf5\x86\xc6\xeb\x944\x9d\x90\x16\xb9\x1a<.\x84\x96\x1e\xb4\xda\xe5b\ +\xc3\x9e\xf8\x14\x95\r\xee\xe7\x15W\xf4$/\xcf\xc9\xdbo\xabh\x86\xe3\xbf\x07\ +\x8e\x94\xe8\xb4-\x04\xf48\x01\xae~\x07\x9e\x9e\x02\xf5\xe9\xa8)\xdc\xfd\xef\ +\xef\x18a\xa1J\x93:\xd4\xfc2*\xaa\xc1\x92Xu\x12\xe9\xb1b\r\x8f\xa1m`Y\x12\ +\xc3[\x92\xd0B\xa4$\xc7\xde\xe9\x19\xe0hm\xfc\xe3f\x08\xf5\xaaw\x99<\xf5\xea\ +\xb7l\xd9y\x94YS\xfb\xd1\xbf(\x8b\xa4$\'\xdbvU\xf0\xca\x07\xdbY\xb2j/5\xf5\ +\x12G\x92\xfd8a\x1b\xb8\x9e8s\x87!\xb0\xec\t\'\r?\xf7\xb2\x7f\x0f\xfc\xaf\ +\x80\x7f|z\xdb\x0b\xceh\xa1\xef\xcc\xb4iz\xf7\xc6\xb0\xa4\xf4\x86\x95\xc5\ +\x93\xd4T\x83\x1bnP\x13o.\\x\x10\xe1\x801WE\xd6\xbf\x1b\x8c\x10\x907\n~\xb8\ +\x04\x16]\x0f%\xaf\xa0|\xbe=h\xf5\xd5n[\x18\x9e\xb4\xbd\x04\xca\xc7\xeb\t\ +\x11sX.<\x05\xc5-$`\xaa\x9c~\xe1\'z\x16j\xa0*\x1e\x8e\xcff,l{\xe8\x0c\x90\ +\x18\x86\xc1\xb1z7\x1f\xac)\xe1\x8bo\xf7\x93\x92\xec@ \xa8s\xb99ZUG]\xbd\x85\ +\xd3)\xfc4Nz\x13\x0e\xc0\xf2M*\xe9u\xfe\xfa\x92E\x02\xdb\x94\xfeo"*\xba\x9ec\ +\xcb\xe0\xd8\x04\xad\xcb\x1d\x9a\xa8\x08/\x10\x97\x81\xb5`kw\xc8\x904\x86\rK\ +\xe3\xe8Q\x8be\xcb\xca\xc9\xec\t\xdd\x87G\xdf\x90\x13\x02\xf2F\xc3\x15o\xc2\ +\xab\xd7\xc0\xa6\xa7Q\xf5x\x8f\x03\xfa\x01\x83\x81t\xa2\xfb\r\x80\xaa\xad!\ +\xd4<\xe2 $\x96\x10H\xe17\x9f\x83}!\x84\xb0\xb3\xc1\xbcaX1\xce\xed\xf7\xc4\ +\xe5J\x19\xb2]\xd9\xe0\x17O\xbfUM\x90\xdaZ\x93\xa3U\xd5\x98\xa6\n\x19\x13\ +\x0eIr\x92\x83$\x87C\x15\x8b\x91\x02\x95,-T\x88\x87\xb2q\xbdS\xf0x\xdan\xd0\ +\xa0\x08\xeaOD/\x8ag\xce\t\xdf4=>\xf7\x90o P\xd31\x89\x9a\xf0z\x88g\xf2\xc4m\ +\xb7\xf5\xc10\xe0\x83\x0f\x8ep\xf0\xa0\x9bS~\x0e\xce\x18\x95\t\xf6\x0c\xb8]\ +\xbc\x10\xbe\xfa\'|x\x1fT\xae\x05\xd6\xa2JC\xf6GM\x07$\x80B\xfb\xe7\xde\x08\ +\xf7\xc1\xfb\x9b\x9d\xed%|b\xeb\x95\x14i\xf8\xa2\xb8<\xbe\xcf\x18\xdf\xf4R\ +\x08\xb0,;\xd4\xcb\x1bv\x80O\x9c\xf0%s\x08\xec\x08\x05[|\x11$;\x1d$%\x19\xa8\ +\x8f\xb3g\x94\xd2>\t\xe1\x8b\xf7\xf5/;\xee\xfb\x17oz\xad@\x82\xe5\xab{\x80\ +\x9f\xd5\xef\x9d9\xa2\xad\xe7\xea7\xa6\x03\xab\x9d\x00\x00 \x00IDAT\xe7\x9aD\ +\x15wG\xa8A?<\xa7\x06\xeazxS\x9f5\x1d\x8d\x16\x0bok\xfd\xbc\xb1&\xb8o\xa9\ +\xa9\x06g\x9c\x91\x83\x94\x82\xb9sw!\x1c0\xf2\xd2\xd8\xba-\x85\x00\x91\x04\ +\xc7\xff\x10\x86]\x08K\x1f\x80\xcf\xfe\x0cV=\xb0)\xcam#\xb0\xa4\xcf\x87\x0b\ +\x96\xa7J\x83\xbd^\xda\x05V\x14\xc1\xa2\x12\xeb\xa2\xd9^#\x13\x8f\x10\xfa\ +\xd5\x8f\xb03\xd9L!1\xf0I\xab\xaf\x9f\xd2\x8e\xe9\xf5\x1c\xc9c\xd5J\x8fk\x17\ +5s\x9b\x0c\xb2\xe5=\xd6\xae\xe5{/\x95\xe8z\x8e*\xed\xf40\xe1\x11\xfb\x08\\\ +\x16!\x84_L\xb1\xf0\xa6\xf9J{\xc0\xcf\xdf\xc2O\xd8\x1bN\xd3&\xa2n\xf1\xc6\ +\x8bK.\xe9Aaa2{\xf7\xaah\x86n\x83\x95\x9b!.\x08U\xf7\xf7\xcc\x87\xa0\xf8\x06\ +\xd8\xfd\x19\xec\xf8\x08\xccz\xb5\xbat\x1d\x94\xae\x0f\xda\xa5\xcdO\nJq<7y\ +\xe8~\x85\x9al&\xf6\x0f(\xc2\x13`\xa04N\t\x8ea\xf8"\xbd<\xc6\xa7\xb4ly20\xa4\ +\xc7\x12\r\xees\xa0U\xeb\xaf\xe8\r\xceVz\x9d\x0e*\xd1\x04\x810\x04>C\xd3\xd7\ +!\xf5\xcc\xe0\xa0\xcd\x11\x98B\xf8\xd2\xc9\xec\xac9i\xff\x1e\xe0\xda\x10\x0e\ +\xedj\xe8\xc0\xb4Jx[b\xf5\xfao\x13O7\xc3\r7\xa8\xd8\xddw\xde9\x82i\xc2\xa8\ +\x8bi\xdb\xa4\x96m\xc4c@f\r\x84\xae\x03`\xe4\x95\xf6\n\t\xef\xdf\xd9Px\xa3E\ +\xf0\x1f\xcf\xdf\xb2\x8dWU9\x9fCA\xda\xb5\x83\xd5#\xbe\x9d\x12\x81\x1a \xb4p\ +X\xa6\x8a\xd0\xf0\x96k\x10~\x83e\x8d\xd0\xd4\'P`\x1fHxS\x89\x85\x10*$D\xa8\ +\xb6\x0cK\rBZ\xc2\x81\xd1P\xba\xc3<[\xdf\xd4\xedRJ\x0c\xc3\xa1\xeadH\xcbv\ +\x8dXHa\x92\xc8S4i\xdaF\xab\xbf\xbe\x13\xa1\xe0M0\xc1_\x06C\x87\xa63zt\x06 X\ +\xb0\xe0\x00\xce4\x18qI\xe2<\xb6\x05<\xc5[\xb0#\xce1\xbf\xf1F\xf8U\xccQ\x95$\ +L\x04\xa6]8L\xd8\x95,\x05R8\x91\xd2iW\x1b\xc3+\xaam)\xd0\xe3\xf1[\x08!0\x0c\ +\x81\xe1\xf1\xcf\x08\x81\x90\x0e\x10\x06"\xe4\x93A\x9b\xcf\xda\xfe)\x91\x16\ +\xb6\xaf\xdd\xe1k\xcb\x12:\xb9\xc3\xc6[\xea\xd3\x90|\xbd\xab\x0e\x97)\xe3f$D\ +\x02i\x99\xed`\x02\xfa0\xb8\xfb\xee\xbe\xa4\xa5\tV\xac\xa8\xe4\xfd\xf7\x0f\ +\x93?\x12\xf2\x86\xc6\xd6\xbf\xdbR\xea\xab\x82\x8a\xa9wJ|\x83HB*\x83\xd3\xf7\ +\xb8\xaf|\xa0\x86\xf2\x9b4\xd0"\x11\x81\x97\xc7\xba\xb6\xa4\xb2\xb8=cr \xb1\ +\x84\xc4\x14>\xdf\xb0\xd7\'.\xc3\x7f\xd9\xa3}>\x0b\x1bSY\xd8\x98\xb6\x87\xc8\ +P\xb6\xbe\x16^\xa4\x94\xd4\x9b\x92G\x17\x1ea\xf4U;\x187g\x07\xcf\xbc]\x1e\ +\xefn\x85\x8d\xc7H\x8c\x8a\x8f7\x96Vq\xb0\xb5\x9b\x96f0yr\x16\x00\x8b\x16\ +\x1d\xc44a\xec\xd5x\x82\x89\x12\x8e\xfd\xeb\xa0.\x02\x93[\xb6k\xa4\x00,{`\ +\xcb\xf0\x8a\x9ba\x1b}\xfeC\x80\xca\x0f\xaa\x12=\x84\x9dp\xd1f\xebGH\xb0\xa4\ +\xb7\x0c\xa5\xea\x87\xb2~\x85\xf4\x84\xe5\xf9\x15L\x0f\x18\xde\x0b\x0f\xcf\ +\x10\'\xa8\x88b\x87]\xff\x18\xe9\xf1#\xbb\xc10\xdb\xdcN\xbbG\xc0\x9c\xdf\xee\ +c\xe1\xc7U\xdeE\x7fz\xe1\x08W\x9d\x9dEzr\xfb\xbdM:\xdc\xe0\xdae\x97\xe53p`*\ +\xe5\xe5n\xfe\xfb\xdf\x03\xa4f\xc3\xc8\xcb\x13\xd3\xda\x95R\r\xacuzl\xdd\xf5\ +\xfc.,\xa1\xe6\x0b\x13\x127Pc\xa4p\xcc\x91nOr\xd9 \xd5\xa0\xcdH,\x8c$\x01u.\ +\\G\xab\xb0\xecd\x12C\n\x84\xa5DX\x1aQ\x10@\xe9\xb3\xf5\r\xe5\xefP~^\xe9\xc6\ +U_G\xaai6[\xf2\xa3c#\xf9h\xdd1\xdeXZ\x15\xb0t\xfb^\x17o}^\xc5\x05S2c\x1e}\ +\xd3\x16\xfc\xc7\xbe\xda\xb5\xf0\x06[\xbb\x86\x017\xddT\x80\x10\xb0x\xf1\x11\ +6o\xaea\xf8\x05\x90\x92\x13\xaf\x1e6\x8d\x00v|\x12\xef^\xc4\x1f\xdf\xd0\x9a_\ +\x94\x01\x80\x10d\xe2\xa6\xf7\xb1=8\xa5\x8b4\xcb\xa5\x02\xe3\xa4\x8c\xec\xe3\ +\x8b\x90\xb8\xdcn\x9c\x19Yd\r\xed\x830\xdc\xca\xef*\x8c\x80v"9\xd6%\xedA=o|\ +\xb0\'\xb6\xd7\xd6\xdfc5uT\x94\x1e\xc4i\xb4\x1fa\x89\x06+6\xd4\xe22\x1b.\x9f\ +\xfb\xdca\xa6M\xcc #\xa5}\\\x9f\xe0\x80\x83v-\xbc\xc1\x9cyf\x0ec\xc6tAJx\xe1\ +\x852\x00\xc6\\\xe9\xbb\xb1\x13\r\xab\x1e\xca\xbe\x0e\\\xd6\xe9\xdc\x0c\xf8\ +\\\x06H\xe9\x15U\x13\x13\x87!\x18aVs\xf3\xb6g\xa9\x16\x02\x87\x1d\x91\x1c\ +\xd1\x04\x0f\tN\t[+k\xc9=g:7\xbd\xb0 a\xae\xff_\xfe4O\xf6\xc9\xfc(a?\xbf\xd1\ +FJ\x98:6\x1d\xa7\x03\xdcA\xe2\xfb\xd5wu,\xfe\xa2\x9a\xd9\'g\xb4\x1b\xab\xd7\ +\xff\xde\xeeP\xc2{\xfd\xf5\x058\x1cp\xf8\xb0\x9b\x95+U%\xb2\x81g\'\xa6\x9b\ +\x01\xa0\xe6\x10TDh\xaa\x9f\xf6\x8c/\x9bN\x89\xb0\x85J\xf70\x84\xa0\x07.\xba\ +\x99\x07\x03\x12,"\xecg \t\xe8\xe9\xb6p\xa4\xd4D\xf0\xc0m\xe7\xb6;\xae\x17\ +\xe5\x9b.\x93\xec\xd9o[\xc2\t\xfaA\x8e\x12B\x08N\x1c\x9e\xca_\xee\xcc\xe7\ +\xb6\x87\xcb\x1a\x88\xef?^/g\xd6\xe4\x8c\x84\xffR\x92\x96)\x83\r\xaav+\xbc\ +\xc1n\x86\x1e=\x92\x98:UM+\xf1\xdak\x87(-\xadg\xea/\xc1h\xaa y\x9c\xd9\xbb\n\ +\\\xd5\xf1\xeeE\xfc\xf1\x1f\xaa\x12\x9e\x18]\xbb\xa6\x82\xd3\x80d\x873(\xc97\ +x\xef6 !\tI\x86QG}\x02N\xc7\x9b\x9e\x91\x8d;\xc9\x85\xa8o\xe3\xcc\xac\xed\ +\x14\x81\xe0\xba\xe9Y\xac\xdd\\\xc7\xbc\x85\x81\xd1\x0cK\xbf\xaca\xefa\x93>\ +\xb9\x89-c\xa1\x9eb\x13\xbb\xc7\xad\xe0\xf6\xdb\xfb\x90\x9b\xeb\xa0\xaeN\xf2\ +\xc8#\xbb\x11\x0e\x18pVl\xad]\xaf\xeb\xd1\x84#\xdb`\xd72\x90~\xdf\xd2}N\x84\ +\xbc\xe1\xb6\xa6\x00\x077\xc6\xaeo\x89\x8e\'\xb4J\xe2\xff7S\xefC\xb8\xf8"\ +\x8e\x0b\xb0\x120|\xcb\xb2\xdc\x9dVt\xbdH\xf8\xd3\xad=p\x9b\x92g\x16Ux\x17\ +\xd7\xd4K\xfe\xba\xe00\x0f^\xdf=\xc2\xc3\xad\x91#\x94\xb5\x0b\xedTxCe\xcf\ +\x9du\x96\x1aA\xdb\xb1\xa3\x8eo\xbf=F\xcfQPxR\x83]\xa3\xd3\x1f\tXP\xb2L\xcd\ +\xbb\xb6s\x19\x94~E\x83H \xe1\x80\x9ec`\xe4E0x\x06\xecY\x15\xb4\xbe\x13\xfaw\ +\x83\xf1\xde@1\xba\x12\xd2\xdf\xdcND\xbcI"\x9d\xf7\xa3!\x84\xc0)\xe0\x0f7\ +\xf7`\xed\xe6Z\xd6|[\xe7]\xb7\xf0\xe3*~1\'\xaf\xdd\x0c\xb2yh\x97\xc2\x1b\xcc\ +\xb4i\xb9\x8c\x1b\xf7\xff\xd9;\xef8)\xaa\xac\r?\xb7\xbb\'\x07`\x98!\xe7\x9cs\ +\x10\x04\x04\x13( *\x86UQW\x17\xd6\x0c\xba\xba\xabkZPw\xd7\xb4&\xf4\x13P\x8c\ +\xa0\xae\x19Ae1\xa1\x02*9J\xce0C\x9c\x1c;\xdd\xef\x8fS5\xd3\xdd\xd3=\x01&t\ +\x0f\xfd\xfel\x99\xae\xae\xae\xbaU}\xef[\xe7\x9e{\xce{\xe2\x01x\xf3\xcd#8\ +\x1c\x9a^\xd7JHdu\xff\x1cZC^*,\xbe\x1b~\xff\xcc\xdb\xc2-\xb5\xaf\x0b\xd2\xd6\ +\xca\xeb\x9b\x07\t\xee\x01\x1fF\x18A\x86\xb8H\xc5\x9c\x07\x9a2\xe6\xee\x83\ +\x9c\xc8\x94\x81\xb6/\xd5\xc1\xbc%Y\xdc2\xae\xbe\x87\xc4gm\xb6\xd2\x1b\x81\ +\x8c\xa9\xe0sj\x9d\x02n\xba\xa9\t\x16\x8b\xa2\xb0P3o\xde\x11\xa2\xeaA\xaf\ +\xeb\xaa\xdf\xcd\xa05l\xff\x08f\x0f\x84-\x1f{\x90\xae\xcd\xe7\x15\x0ft\x01F\ +\x02\x7f\x00\x86!%\xdd\xc3\x08#\x8c\nC)E\x8f6\x91<;\xb5\x116\x0f\xdd\x95\xe7\ +\xdfK\'\xcf\x1e|i\xc4e\xe9\xda\x84\x9c\xc5\xeb{1M\x9aDr\xfe\xf9\r\xd0Z\xf3\ +\xeb\xaf\xd9\x1c=j\xa7\xc3\x18\x88\xf1Wb\xbd\n\xe1\xb6\xc3\xaa\x97a\xc9\xfd\ +\xe0v\x1a\x1b\x9b\x02\xe7\x01\xcd\xf0~\xa4Y\x90\xa5s\xb3\xe5\x9d\x80Q\xc0;\ +\xc0\xfe\xeamg\x18a\xd4%(\x14W\x8dJ\xe0\x8d\x85\x99\xfc\xb4N\xa2P\xf6\xa59\ +\x99\xf9I\x06\x0f\\\x93t\xda\xc7\x0f\xe4\x93\xadj\x84\xbc\xc5{\xe9\xa5\xc94h\ +`\x05\x14\xaf\xbe\x9a\x8a\xcb\r}\xfeH\xb5^\x99\xdb\x01_\xde\x0e\x8b\xef5H7\ +\x02!\xd2\x9b\x80vHi\xf7(\x8fW\x84\xf1EO\x81\x00\x0b\x10]r\xcc\xb0\x7f7\x8c0\ +*\x06\x0b0\xfb\xfe&\xc4z\xf8u_\xfd8\x03\x8a\x87PpY\xbe\xfe\x10\xd2\xc4\x1b\ +\x17g\xe1\xe6\x9b\x9b\x00p\xfc\xb8\x83\xa5K3\x89I\xaa\xfa\xf2\xed\x9e\xd0\ +\x1a\x96\xff\x1b\xd6\xce564\x01n\x06F \x04[\xd1\xf3\xba\x81\xd0\xd5\xfa\x08#\ +\x8cZ\x83R\x8a\xb6M"\x18;,\xbex\xdb\xd1t\x17s\xbe\xc8\xc0\xad\\`\xa9\xfdD\ +\xeb\xf2\xe4sC\x8ax}/\xa6{\xf78\xfa\xf5\x93|\xed\x15+\xb29~\xdc\xc1\x80\x9b\ +\xc1\x16WM\xe7\xd7pl-\xfc\xf4ocC=\xe0J\xc0\xd7\xada\xb6\xd2\xac4\x91\x01\x14\ +\xe1M\xcak\x80\xa3\xd5\xd3\xce0\xc2\xa8\xf3\xd0\xf0\xe2=\x8di\xd2\xb0\xc4\ +\xd9\xbb\xe0\xa7\\\\\x16\xd7i\xe9nWe\xa5\x9d\xb2f\xb1!\xe7\xe3\xf5\xc4\x88\ +\x11\xf5\xb1X\xa4z\xc0\xff\xfd_*\xca\n]&R-\xa1\x0cZ\x83=\x13\x16L\x01g!r\xe7\ +\xae\x06\x1a\xf89\x9f\x1b\xf8\x0e\xd8\x08\xe4\x19\x9fG\x02\x89\x94\x90rz\xd5\ +\xb71\x8c0\xce\x14(\xa5H\x8a\xb70nX<\xaf/\x90\xd8\xde\xefV\xe6\xb3tC>\xe7\ +\x9e\x1fv5T\x1b\x92\x93#\xb8\xe7\x9e\x16\x00\x14\x15\xc1o\xbfe\xd1\xb474\xe9\ +[M\'\xd4\xf0\xe3\x0cH[g\xbc?\x07YLS\xde\xfb\xe0\x02~\x04~AH\xd7\xdc^\x04\x1c\ +\x07N\x18/\x8f\xd9P\xd8\xbf\x1bF\x18\x95\x87B\xf1\xa7K\xeac\xf5`\xb1\xe5\x1b\ +\x0b\xaa\xa6NH5\xd7\x97\x0c\x19\xe2\xf5\xbd\x11C\x87&\xd2\xa4\x89\xacZ}\xf6\ +\xd9q\xb2\xb3]\xf4\xbb\tT\x84\xdf\xaf\x9f\xde\xb95\xa4\xfe\x02\xbf\xbdbl\xe8\ +\x0f\x9c\xed\xbb\x13B\xa6\x0b\x80\x9f\x8dm6\xa4\x9apo\xe0\xcf\xc0\xad\xc0uU\ +\xdf\xbe0\xc28S\xd1\xbb]\x14\xe7\r*\xf1-~\xbf:\xbf\xd6\xc5Y*B\xda!\xe9jP\n\ +\xee\xbe\xbbEq\xdd\xc0\xaf\xbeJG\xd9\xa0\xe5\xb0\xea\xb9\xe7\nX\xff\xb6\x11\ +\xc1`\x01\xce\r\xb0\xe3\x97\xc0& \x16\xb8\x0b\xb8\x01\x89r\x880\xbe\xa7\x10\ +\xf7\xc3\xfc\xaaoc\x18a\x9c\x89\xb0\x00\x93\xc6$\xf2\xcd\xafyh`\xcdF\'k\x7f\ +\xb7\xd7v\xb3\xcaEH\x12o\x83\x066\xfa\xf4\x119\xb8\xbc<\x17_\x7f}\x92f}!\xb9\ +{\xf5\x9c/\xe7\x10l[d\xbc\xe9\x86\x84\x8b\xf9\xba\x18V\x02\xeb\x81^\xc0k\xc0\ +@J\xfb~5\xb0\xaaz\xda\x18F\x18g"\x94R\x8c\x1d\x12O\xe3\x86V\x8e\x9ct\xe1t\ +\xc2\xdb_\xe6T\xc9\xb1\xab3\xa67$\\\r\xbe\xa6\xfbu\xd75\xa6~}+Zk6m\xca#=\xdd\ +I\x9f\xeb\xa1Zd\xdd5\xecX\x08\xb9i@\x1cpA\xe9\xcf\xd9\x0f,\x01\x92\x80\xcf\ +\xf0O\xba&VTC\x1b\xc3\x08\xe3\x0cF\\\xa4\xe2\xb2\x91\t\xc5\xef\x7f\xf8\xb1\ +\xf6\xc3\x85\xca#\xec\x90 ^_\xdcxc\x93\xe2\xbf\xdf~\xfb(ZC\xa7q\xd5\xe7\xda\ +\xd9o\xfal\xdb#\x91\t\x9eq\xdaN\xe0s\xe3\xefg\x10\x9fnY\xed\xf0)\xf5\x13^X\ +\x0b#\x8c\xd3\x83R\x8a\x8b\x87\x96\xc4\xf4\xee\xdd\x9bQ\x8b\xad\xa9\x18B\x8e\ +x\x1b7\x8e\xa0{\xf7X\x94R8\x9d\xf0\xd5W\'I\xee\n\t-\xab\xe7|\x19\xbb`\xdb\ +\x17\x08\x99\x0e\xa2tR\xcc\xaf@\x160\t\xb8\x91\xb2I7\x03\xd8[\x1d\xad\x0c\ +\xa3\xce\xa2"k\xeb\xba\xa4\x04\xba\xf7\x0b\xcf\x02\xceu\x1ag\xf7\x8a!\xb9\ +\xbe\x04\xf0:\x9dU\x97@Q]\xd1\rAO\xbc\xbe\x17>hP"QQ\x16\xb4\xd6\xec\xdcY\xc0\ +\xe1\xc3E\xf4\xbc\x8a\xd3\n\x9a.\x0b\xc76\x83#\x1fH\x06\x9a\xe3M\xac.\xc4u\ +\x10\r\xfc\x8d\xf2\xe3\x87O"\xe4\x1bF\x18U\x82\x92\xea\xcbf\xdd6\x8d\x0f\xf1\ +\xc2\x19Q7(.\xd2B\xff.Q\xb5\xdd\x8c\n#\xe8\x89\xd7\x17\xe7\x9e\xdb\x00\xb3\ +\xc3\xcd\x9f\x7f\x0c\xb7\x866#\xab\xc7\xcd\xa05\xe4\x99\xee\xa2N\x94\xb6\x1c\ +\xd2\x80B$\xa6\xb7;ewp\r,\xf7s\x8c0\xc2(\x0bF\x9f\xf2\xa7\xbce\xc6\xabj\xad\ +\xc0m\x88\xc8k\xd9.\xe3\xc1\xa8\xd6v\x06\xf49\xed\xd6L\x18\x91\xe0\xf1\xbez\ +\xe3pO\x17!E\xbc\x16\x0b\x0c\x1bV\xcf\xa8\xc6\xaa\xf8\xe9\xa7L\x12\x9aB\xb3\ +\x01\xd5s>\x05l\xfb\xdcx\xe3O\xc6\xd1T%\x1bU\xc1\x83\xfdV\x15\xad\n\xe3\xcc\ +\x82F\xc7\x14\x96\xf1\xb9\xa8.\x15W\xad\xd3%\x95@\x15b<\xe83\x80y\x95R\x8c\ +\xe8\x13KD\x88\xc4i\x055\xf1\xfa>\xb5\xda\xb5\x8b\xa1gO\t\x96>q\xc2\xc1\xe6\ +\xcdyt\xb8\x10\xac\xd5\xa4\xcd\xa0\x80\xdcc>\x1b\xfc\xe1\xec2>3\xe1\xa7\xef\ +\x87\x17\xd6\xc2\xa8\x10\x02\x94$2\xdd\n(\x8dV\x86_S\x95X\xc1Z[\x82B0\xa6\ +\xa6\xd0\xa1y\x04\x1d[V}\x99\xa4S\xb1\x9e\xeb\x94H\xce\xd0\xa1\x89DF*\xb4\ +\xd6\xac[\x97KV\x96S\x94\xc8j\xaa\x01\xbe\xb7\xb2)\xe2[\xde\xe4\xe73\x7f\xd8\ +R\xfe.a\x84\xe1\x05\xad\xc0\xea\xbfs)\x14\xf2\x9fa\xe5j#KG\x99i\x94\xa0\xdc\ +\x16Th\r\xf3S\x87\x86\x8b\xcf\x8e/\x7f\xbf @H\xfd"#F\xd4\xc7\xf4[-[\x96\x855\ +\x1aZ\x8f\xa0\xda\x98\xd7\xed\x00{\xae\xf1\xe6\x98\x9f\xf3D!\xb2\x90\xdfW\ +\xe0`\x1a\xd1j\x08#\x8c\xca@iT^\x80E#mA\x19\xae\x05\xa5-(e\xae0k)\x83\xa34\ +\xfaLXY3\xa1\xe1\x12\x0f\xa9\xc8`\xf6\xf3\x86\x88GD\xd0\xa1C\x8c\xe1\xdf\xd5\ +\xec\xd9S@bs\x88kT}\xe7\xb3D@\xa4\xf9;\xe6\xfb\xd9A!q\xbb\xdf\x00G\x10\x12\ +\x0e\xd4\xcf\x1d\xc8B\\\x18\xb5\x02\xadK(\xc8\xd42\xd2@\xa1\xd6\xecpj\x0eip\ +\x9d\x0cF\xc98\x83X\xfd\xac\x1ek\xe5F+-\x06\xae\x92\xb81\x8d\x1b\xb92\xb1\ +\xa9\x94r\xe3\xa5\xc8T\x87\xa1\x94\xa2[\xdb(\x92\xebY8\x91U{\xd7\\\x11\x17b\ +\xd0\x12\xaf\xef\xd3\xcaf\x83\xe6\xcd\xc5\x7fST\xa4Y\xb1"\x9bN\xe3\xa89\x9b}\ +/\xb2\x98\xe6y\xc74\xd0\x11X\x06\xfc\x15)\xe5\x13\xe8\x96g\x00\x87J\xde\x86\ +\xfd\xbb\xd5\x0f\xe1#\xa1\xa2\xbd.\xcd*\x87\x9bT\x97f\xadS\xb3\xd2\xe1\xa6H\ +\x0b%\x15?\x0f\xbf\xfd\xd1\xfcZ\xb9\xa8\xb1\xdfO\x03\x167\xdam)E\xbeJic\x01M\ +\x1b\xe1\x0cN\xa3\xf5\xb2\xf8\xac\xb42|\xbegNW\x8b\x8fR\x9c;(\x8e\x0f\xbf\ +\xa9\x9a\xb4\xe1\xeaB\xd0\x12\xaf/Z\xb5\x8a\xa6uk\xa9\x95s\xfc\xb8\x83\xc3\ +\x87\x8b\x18r^q\xc0L\xb5@\x03\xcd\xfa\x19R\x90Y@*\xd0\xd2\xe3\x84\nh\x01\xb4\ +\x06\x16\x02;\x91\xb0\xb3@\r:s\xfa\x7f\xadAk\x8d\x05\xc8\xd3\xb0\xde\xe9fq\ +\x91\x9b\xe5\x0e7\xbf;uq\x10J\x95\x9c\xc7\xc70\xa8>"vCL\x11\xe4\xc5\x94\xfaD\ +i\x9b\xf7\xc2\x9b\xd9"\xb7EB\xca\xcc(\x07\x1dR\x1e\xc5\xd3\x83\x86\x8b\x87\ +\xd5;e\xe2\xad)\xf7D\xc8\xfc"\xc3\x86\xd5\xc7f<&V\xad\xca\xc1\xe9\xd64\xea^\ +\xbd\np\x1a\x18p+%\x84\xb9\x8d\xd2\xe4\xa9\x80\xb1\x88\xde\xee\xb3\x1e_\x0c\ +\xa3\xc6\xa0\xb5$\x0f\xb8\xb5f\xb7K\xf3\xa7l\x07\x03O\x161!\xd3\xc1\xab\x05.\ +6V1\xe9\xfam\x83\xdb\xa5\xcdW\x95\x1f;`T\x83\x1b\xb46,_\x0bJY(\x91\xc13}\xbc\ +\x85\xa0\x1cU\xdd\xa4\xa0\x85R\x8a\xb3\x06\xa5\x10\x1dm\xab\xd2\x87aU\xff\ +\xaeAi\xf1\xfa\xbb\xc8V\xad\xa2\x8a\xa7Z;v\x88\x7f\xb7^\xeb\xeam\x87R\xd0\ +\xa8\x17\xb4\x19\x01\xfb~\x04V\x03C\x80\x04\xcf\x9d\x90\x18\xdf\x11\xc0\xbbH\ +\xa4\xc3 D:\xd2W\xc5,\x8c*\x87\xd2\x9al\xad\x99\x99\xef\xe2\x7fEnv\xba\xaa\ +\x9fd\xcb\x83g\xff=\xed\xc1\xaf\xac\xa8\xfch?\x1fh\xdc:\x17e)\xc0\xe2\xb6\ +\xa1\x95<|\xe4;n\x14\x16\xb4v\xe2\xb4\xa4\x81\xf3\xcc*\xee\xd7\xbaE"E\xf6\ +\x00O\xab A\xc8X\xbc\xed\xdb\xcbTKk\xcd\xbe}\x85\xb4\x1aR=\xa2\xe7\xbeP\x110\ +\xfa?`\x8dD\x16\xc8\xd6\x06\xd8q0\xd0\x05x\x1c\x18\x0f\x0c\x00\xfe\x89D2\xb8\ +\x91\xa8\x883c\x8d\xa3\xdaa\xa6\xc4\xeer\xba\xb9%\xdb\xc1\xe0\x93v^\xc8w\xb1\ +5\x08H\xd7\x17\xa7o\t\xcb\xd7J\xf9w5\x90\xb1\x0e\xad\xd7\x81%\x02\xad\xac`\ +\xb8z\xb5\xd2\xb8\xb1\x89\xff\xd7\xf93\x1c\xdduz\x17\x11b\xa8e\x1d\xf4\n!$\ +\x887"B1th" \x1dp\xf5\xealZ\x0f\xaf\x99\x19\xbdR\xd0\xb8/\xf4\x9edlXO\xc9\ +\x92\xb8\',\xc0\x85@3\xe3\xfdV\xe0\x11\xc4\xe7{>0\xd5\xf8^\x18\xa7\x0c\xad5\ +\xb9n\xcd\xec|\'C\xd2\x8b\x18\x96n\xe7\x93"7\'B\xc4\xb5S\xa5\xae\x08\xa5\xe0\ +\xd0.\xdc9\xf3p\xebu\xa0\xdd(b\x80\x18\xf9W\x15\xe2\xd4+Pi_B~\x81\xdf\xa8\ +\x880j\x0fA\xe9j\xf0E\xbbv\xd1\xb4i#\xd3-m\xac\xa6%w\xab\xc1\'\x9b\x82\x91\ +\xd3a\xfb\x97\x86v\xc3/\xc0\xb0\xd2\xfb\x10\x83\xa8\x94\xbdNI1\xcbL\xe0\x87\ +\x1ajg\x1d\x84\x06\xd0\x9a|\r\xef\x168y\xa5\xc0\xc5\x91\xea\x9a9\x98\x01\x00\ +V\xa0s\x80}N \xb3\x17\xcf\x06V\x92JM\xf2\xad\xb0\x1b\xc2H\xfb-m\xf5j\xf4\x8e\ +\xe5\xb8\xda\xe4a\xab\x7f)X\xda\xa1u\x04\xb8\n\x81M\xb8S?A\x1d\xd9\x17\xf6v\ +\x05!B\x82x\x87\x0c\xa9GD\x84t\x9f\x93\'\x9d\xec\xda\x97\xcf\xc8N5w~\xa5 \ +\xbe\x05\x9c\xf3 |5\r!\xde\xb3(}\xf7\x14\xa2Tv#\xa2\xcb\x10\x85\xa8\x9a}\x8a\ +\x97\xb5\x1b\x0e%\xab \xb4\xe6\xb0[\xf3j\xbe\x93\xf7\x0b\xdd\xe4T\x90\xe0,\ +\x11\x90\xd2\t\xdcn8\xbe\xd5\xd8\xd8\x07\x89>\xf9\x1a\xb0#i\xde\x93\x003\x0e\ +\\#\xb5\xf1\xea#\xbfc\x12\xfe\xfd\xf3y@\x81\xc7\xfb\x1dH\x0c\xb7Y]\xe4\x17\ +\xe0\xa7\n^^E*\x1ch\x8d\x8e)B\x15\xfaI\xa2PJ\xc8w\xefZ\x9c\xd1[QQ\xf1\x10\ +\x19\x8d.\xca\x83\xc2\\T\x91\xddH\xa4\x08w\xb7`C\xd0\x11\xaf\xbf\xa9\xd8\xa5\ +\x97&c\x06\x8e\xb9\xdd`\x8d\xd1\xc4\xf9\x13\xad\xa9F(\x05\xfdo\x85\r\xf3\xe0\ +\xf0*`)\xe2B(\xb5#"\x96nV\xaa\xb0\x13^`\xab\x04L\x15\xae\xc3n\xcd\xac|\'\xf3\ +\n\xdc\xc5\xc5\x9a\xfd\xc1\x1a%!\x7f\r\xda@\x93\xde\xd0\xb8\x97,\xba6\xec\ +\x04[?\x82\x0f\xafEb\xad/A~\x87c\x089Z\x91\x02\xa4\x95u\xb6\xc5\x19/\x13\xc9\ +\x1e\x7f_\x0e\x87\x0f.5\xc8\x17D\xc7!\x03\xa9\xc1\x06%\ +\x16Y-\xd5\xbc\xd2~\xfe\x02o\x8e\x11\xce\xd5^\x1f\xaab&\xaa\xe6A\xae5\x07\\\ +\x9a\xeb\xb2\x1cl\xf7ch\xf4\xbd\x01F\xcc\xf0&\xdbJ\xb5\xc8\r\xb9\xa6\x1a\x9c\ +g\x18\x9f\x06z"\xbf\xd3A\xc4J-\xafzHE\x90\x01|d\xfc=\x04!\\\x13\xf9\xa0\xacp\ +\xc3\x97pd\x13\xac\x9a\r\xe9\xe5\x84\xd6j\xb7K\x0f\x18\xd0\x83\xc2B\x07\x91\ +\xd1\x01\x16\xd7\xc2\x08Y\x04u\x1c\xaf\xd5\n\xc3\x87\xd7\xf3\xb0xa\xd7\xae\ +\x02"\xabI\xf8\xbc\xa2P\n"\x0c\xf2\xed0\xc6H\xae\xf0\x85\xa6\xd6HW N\xcf\xd2\ +\x06\xad\x17\xf5z\x7fd\x08\xac\xc8\x03\xa3z\xcct\xad5\xa9.7\x0f\xe48\x18\x91\ +n\xf7K\xba\x00??\x0b\xbb\xbf>\xf5\xf3(\x1b\xb4\x1cd\xbcI\xc5\xc3\x01\x8c\xcc\ +F: i\xde\xff>\xf5s\x14C\x03K\x8c\xf3\xa4 \xc93\x9e\x9f\x1d\x85\xb8\x14h>\x14\ +\x06\xdf\x0b\xb7\xad\x87\xd1OCR\xfb\xb2\x0f\xbbz\xf5fn\xbec!En\x17"|#\x17a\ +\xd6S\x93\x97\xc7\xfd\x93r\x13\x1eo\xb5\xd7>\xbe\xef\xeb\x1a\xb4\xd6h\x8b\ +\x13l\xf6\xdanJ\xb9\x08j\x8b\xb7I\x93(:w\xf6\x16\x07\xc9\xc8\xb7\xd3\xb1E-5\ +\xc8\x03&\xf9N\xfa\n2\xf7\xc2\x81e\xbe;@\x8b\xc1\xb0\xfb\x7f\xf0\xe5\xd4Zh\ +\x1fP\xcc\xfcfD\x91[\xa3\xedE\xf2\xafR\xb8\r\x11m\xd1tu\xa3\xb4\x96\xfd\xec\ +\x0e\xdc\'\xd3\xc1\xed\xaa2\x1f\xa3\xe9\xc7\x9dW\xe0\xe4\xd9|\x17\xd9\xfe\ +\x12P\x86\x00}\x81\xfd\xe0\xfc\x06\x16\xde\x0e7,\x86\x06\x9dO\xa1\x19\x9eF\ +\xfbAJ?o\x06!\xa2F_!B\xf6=95\xabW\x03\xbb\x81;\x8c\xef_\x01Dx\x1c+\x0f\xc8\ +\x80\xa8\xf6\x10a\xac\x01\xd8\xe2`\xf0}0\xe0\x0e\xd8\xff#\xfc\xf0\x08\x1c^\ +\xe3\xff\xf0\x9f|}\x9c\x84$\x0b/\xdc\xd5\x8ehWt\xb1&\x8e\x8e-\x04\x87\x15e\ +\x8f,~^buI\xea\x9a\xd3VL\xc0:\xd2!\xfb(\x8f\xf7\x0e\x9bT\xa7\xa8\x83\xd0\t\ +\x19\xa0\n\xca\xdf\xd1\xf7{5\xac\xdd\x1bT\xc4\xeb{\xf1\x89\x89VbbJ\xca\x07\ +\xdb\xedn2s\x1dD7\xa8\xf1\xa6\xf9\x852V\xd2\xeb\xb5\x83\x9e\xed\xfc\xef\xd3\ +\xd1\n\x96\xfb\xc0]\x1b\x0fa%\xa4\xaaP\xb8m\x1a\nrp\xae\xfa\r\x9d\x9e\x8ej\ +\xd7\x1e\x8b\xd5\x06\x0e\x17\xe0F+\x85\x8a\x89\xc1\x9d\x93\x8d}\xd5\xaf\xb8\ +\x8e\x9eD\xbb5\xcazz\x03\xd4\xb4\xae\xd69\xdc\xfc1\xdb\xe1\xe5\xc7-i\'\x12\ +\x8a\xd5\xcdx\x9f\x04\xd4\x87\xacy\xf0\xf1\xb50\xf9\x17P\x95\x9cik\r\xcd\x07\ +\xc1\xc6\xf7\x11K\xd4S\xd2S\x01\xed\x80\xe1\xc0\x8f\xc0\x18$\xc9\xa5,e9\xbf\ +\'A|\xc5W"\xbe\xfchJ\xfbs\xa3\x81xh{\x0e^\xf3K\xa5$B\xa3\xdd\x18h5\x02v.\x84\ +\xc5\xf7BNj\xe9\xd3\xbc5\xdfMna\x0co\xbe~7\xd11\x1ey\xf2\x9eV|\xa0\xf6\x9din\ +a\x97\x1dT(t\x13\xd0\x0ei\x84\ +\x90\xae\xe7\xa9\xda\x02\xed\xe0\xe8&\xd8\xf1\x05t\xbe\xa2rMQ\n\xda_ \xc9\ +\x14n;\x12:\xe6\xe9\xcb\xd5\x88\xb0\xd1\x01Dky4\xf0\np1\x15#+\x8d\xb8*\xa6!i\ +\xe4\x18\xef\xb7R\xe2j\xd0`\xea\x92\xb7\x1f\xed\x9f\x07\x95\x82\x888\xe8z\ +\xb5\xb8\xad\xb6\xfc\x17\xbe\x9f\x0e\xb9G\xbc\xf7\xfb\xf8\x93M|\xf2\xd9\x9f\ +\xcf4\x1a\xad\x15\xd4k\rY\xfb\xab\xf7\x1cA=\xdf\x18>\xbc^\xf1\xdfZk\x96/\xcf\ +"\xb1\xb5F\x05\xf5\xe3\xc2\x1b\x96\x08H\xac%\xd7H\xb1`\x8a\xc5\x18\xfdV\x1b\ +\xb8\x0b)\xfc`>\xf9O=N\xd1g\x1f\xe2X\xb9\x0c\xe7\xba\xd58\x97\xfdH\xe1k\xb3(\ +|}6\xee-\xbbQ\x11V)\xeb|\nC\xdd\x14\xb1\xf9\xb0\xd0\xc5\xf0t;o\x96E\xba Z\ +\xc7\x19\x94\xf6\x87\x8f\x10o\xc7\xe2\xfb@\x9f\xc2\xf3\xb6a7\xe84\xc6x\xf3\ +\xb3\xcf\xf1MW\xc4U\x88\xc6\xf2~`"\xa2\xa9\xb1\x87\xf2\xfd\xf3v`2\xf0\xa1\ +\xf1>\nI\xa8\xe9\x8f\xb7%\xfa\rD[\xa5DUY\x0f\x0e\xa5 \xb2>\xf4\xf93\xdc\xba\ +\x06\x06\xdd\x06\x16\x9f~\x1e\xcc\xa5lB\x19\xa5\x8a.\xf8\x13\x83\xabb\x045\ +\x85%%\xd9\xbcBh\xf6\xec)$\xba\x9e\xac\x10\x87\n4\xd0\xb4\x17\xec\xfe\xa6f\ +\xcf\xeb\xc6-\xdc\xa2\xadh\xa5\r\xd9@\x0bX\xa2\xd0\xf6"\x9c_\x7f\x8d\xf3\xa7\ +\x9f\xa1YC,\t\xf5q\xa7\x1e\xc1}2\x13\xe5(\xc0\x12g\xc5\x8d\x0b\xb0\x80V\x95"\ +_\xad5\xbf;\xdd<\x9e\xebd\xa9C\x97\xd6\x05R\x88/\xf7\x1c\xc4\xda\xfc\x10)\ +\x01\xf15p\xad\xcf~-\x81f\x90u\x00\x8em\x86\xc6\x03*g\xf5j\xa0\xef\xcd\xb0m!\ +\x92\xb1\xf6\x03"\xd7i\x1eC!\x84y\x050\x17\xc8\x06^Fb{G\x00\x03\x81\xa1\x88\ +\xbb\xc0\x17s\x80\xf9H\x06\xdc\x10c\xdf\x04\xbc\xef\xd5j`\r4\x19\x011\xc9\ +\xa5\x0f\xe1\x0fJAlS\xb8\xe8eh\xd2\x0b\xbe\xbe\x17\x1c\x1ee\xa7*\x94f\x1c\ +\xc6)#\xaa\x1e\x14\x9c\xac\xfe\xf3\x04-\xf1Z\xad\xd0\xbd\xbb\xa7\xc3L\xb1|y\ +\x96\xffA\x10\xe4\xa8\xdf\xb6v\xce\xabQ(m\xc5\xa2\xdd\xc2\xa1\x16\xc0\xedFk\ +\x85\x1b\ryY\xb0+\x03m\xb1\x81\xcbm\xac\n\x83\xc5\xaa\xb0\xa0*\x15~\xac\xb5\ +\x90\xec{\x05.\x1e\xcau\xfa//\xa7\x80\x7f\x01\xf7\x177P\x08\xee\x0e`\x172\ +\xe5o\x8b71\x1a\xbfw\xeaj!\xde\xca@)\xe8p1\xb4\x1e\x0e\xfb\x7f\x06\x96#q\xb6\ +\xa3}\xce\x91\x00\xdc\x8a$:\xec\x00r\x91E\xb7\xaf\xca8x"\xa2\xd7a\xea3\xfb.\ +\xde\x19\xb1\xddJ\xc1\x05\xff\xae\xdc\xf3\xcb\xac\xd6\xd3\xe7\x16\xe8p\x11|p\ +\x85\\\x7f\xf1\xe1\xc3\xe4[mh\xd2\x0bNl\xab\xfe\xf3\x04\xad\xab!&\xc6Jl\xacw\ +\xf3\xdcA\x9c\x88P\x16Z\x0e+=m\xacnX\x8c\x88\\\xb1v\xc1\xed\xd6\xf2\xb2\xb8\ +\xd1\x16\r\x11\ne\xb5b\xd5\n\x8b\xcb\x89\xb2\x80\xc5f5\x16\xd3L\x96F\xfc\x15\ +e@\x1b\x95\x1fV:\xdc\x8cJ\xb7so \xd2\x8dDH\xf7o\xc6{%\xa7a\x8a\xb1\x1d`\x9f\ +\x9f\xef5\x91\x7f\xb6/\xac\xf8\xb5{BE\xc0\xf8W\xc1\x16\x83\x10\xe2o\x08\xa1\ +\x16\xe1\xed\x12\x88\x06\xaeF\xa2\x1d\xa2}^fbLg\x84l\'#\x0f\x8b\xd1\xf8\'\ +\xdd\xc3\xc0\xdbr\x8eVgC\xd3JZ\xea\xc5mW\x10\xdf\nn\xfe\tz\xfd\xc1\xfb\xb3\ +\xb0\xdb\xa1j\xe0{\x1f\x1b\xb4\x81\xfc\x8c\xd2\xfbU\xf5\x83.h-\xde\xc6\x8d#h\ +\xdc\xd8_\x80lhA)\xd1\x13H\xe9\x06G7\xca\xb6\x9a\xb3X4\x1a\x17n\xa5\x01\xabD\ +8h\x85.\xae<\xab\xd0V+XTq2\x852\n%VD\xbf\xdf\xcc<\xfbw\x9e\x839\x05e<\x15;#S\ +\xf9\xa1\xf8Y]\x02n\x07f#\x0bS\xe7\xe1\xed[5\xa2\x19\x0e\xae\x04\xe5\xa2\xd2\ +=V)H\xea\x06\x17\xfc\x13\xbe\xfe\x8b\xb1q5\xe2z\xb8\x140#d\xccv\x8dA\xd2}}a\ +\xae\x8c\xf9\xae\x90\xf9#\xdd\xf9\x80K\xe2\xbb\xcf\xffg\xe5\xdb\\|8\x89\x04$\ +c\x0fd\x1d\xf2\xf3y\xd8\xf2\xadR(\x0b$4\x01]\x03j\xfaAk\xf1B\x1dJS\xb7A\xef\ +\x1a\x8enQ\xc6\xff4R\xfe\xdb\x02R\x9bK\x83\xc2\x82\x05)\x88\xe8V\xe06\xe2\ +\x1a\xc0\x0c?\xc3(\x13\x8e\xdf\x05&\xb3\xc6\xd9*\x87\x9b\xd1\x19\xf6\xc0\xa4\ +\xab\x10\x12[\x8c\x7f\xd25\x11\x0b\xdc\x80,X\x05\x80#\x0fr\x0e\x97w\xd5\x811\ +\xe0vh\xef\xa9&w\x00\xf1\xd3\xae\xc6\xdb\xf2\r\xd4F\xe5\xf3\xaf/4\xe2*y\x17(\ +\x94\x05\x9a\x91\x0fC\xf3a\xa7\xd1\x8f\xdd\xb0\xec\x9f0g\x10\xec\xf7\x8d\x13\ +7O\x1b\xb6|\xab\x0cq)\xe2j\xa8\t\x045\xf1zBk(,\x0cM_\x83R0\xf0N\xe8ws\xc9\ +\xb6j\x1f0\xda$_+\n+\xca\xb0~\xb5\xc5\x83e\x94l\xd5\xb8\xb1\xa0\x8dD\n\x0b\ +\xaa8u\x18/\xd60\xa3\x15~w\xba\x99\x9a\xe3\xe0\xf2L\x07;\x02]F\n\xf0\x01\xf0\ +1\xa2\x0eV\x1e\xf9t/\xfbcg!\x14\xa4\x97\xbdO (\x05*\x12\xae\xfa\x18:\x8d\xf5\ +hK!\xa2&\xf6-\xa7\x9eahF?l@R\x86\r\x19\xd0\xf3\x1e\x83a\x0f\x9f\x06\xe9jX\ +\xf7\x1a|\xf7\xa8\xf7\xe2\x9a\xdf]\xc3\xe4[%hq\x16\xa4\x06Hd\xa9j\x84\x0c\ +\xf1\x16\x15i6n\xcc\xad\xedf\x9c2\xac10v\x16\x0c\xba\xbdd[u\x0e\x18\xad\x0c\ +\xd5\x05mP\xab\x02\xb0\xa0\xdc\x92\xf5\xe1\xd6n#\xf2A\xa1\xb4\x057\xe0Vn\xdc\ +\xca%\x0boX\x0cn6\x18\xdc\xa8\xe0{w\x8e\x83\xf32\x1c\xbc_\xe8\xa6\xc8\xdf\ +\x89-\xc8\x14\xfew$\xb1\xc0Tl\xabe\x14\xa7y\x7f\x06c_\x02\x9bgB\xc6\n\x84\ +\x80\x0f\x03\'\x91\xe8\x86\x8a\xc2\x0e,\x02\x16\x02\x85\x10\x19/\xd2\xa1\x83\ +\xef\xe5\xb4\xae\xdb\x9e\x05??\x89\xff\x108?\x08\x93o\xe5\xe1y\xcf\xac\x910\ +\xfc\xaf\x90\xb6\xb1f\xce\x1d\xb4>^_X\xad\x18>\xdf\xd0J\xa00\xa1\x14`\x85\ +\xb6#a\xe5\xff\xd5\xc0\xf9\xb4\x067X\xdcF,\xaf\x06\x0b\x16\xdc\xda\xed?\xe3\ +\xc9s\x9b\x87?S\xf2\x044\xef\x14\xbay*\xdf\x15\xb8\n\x84B\x08\xf7.$R\xc1\xac\ +2^Q\x04\x98JW%\x94\x02"\xa0\xff\x1d\x90\xd8\x1c\xbe\xf9;\x9c\xdci\xc8R\xac1^\ +\xc6\xef\x84\x99\xa9nE\xa4?\x03\xe1(R\x0e\x08\x89\x9e\x18\xff\xaa\xc4\x0f\ +\x9f\x0e\x0bj\r?>\x06\x99\xfb\x81\x86@+$\xda\xc3\xd0\x1d&\r\x89}^\x82\x97\ +\xf2]\xd8\xe7{\xeah\xda\x07\x1a\xf5\x94\xfeP\x13\x08\x19\xe2\x8d\x88P\xb4n\ +\x1dMZ\x88\x12\xaf\xab\x08V\xbe\x08\xdf<\xe8\xbd\xbd\xba\x06\x8b\xbb\xb0\x08\ +\xb7]\xa3\x9c\x0eSJ\xdb\x88\xcd\xd5~y\xb74\x14\x0e4\xffqj\xde\xd6\x92\xdf\ +\x10\x10]\x81\x07\x908\\k\xb9\x07\xf6w*\t\xf3\xf2\x85\x99\x1d\x86D\x85\xd8b\ +\xfc\xecs\nP\n:^\n\xedF\xc3\xd1u\xf0\xcb\x0b\xf0\xfbg\xa0\xcd"\xa6N \xc7\xe3\ +\x0beTGW\x16H\xea n\xa4\x81w\x82-^\xae\xe7\x94=\x0c\x1a\xf2Sa\xcd\xbbHB\xc6Y\ +\xc8=\xf5\\\xdc\x8bE\xdc8~\xc87\xc8-2\x0eR\xba\xc8>\xb6\x18$\xdc\x99\xaa\ +\x8d\xbeQ\xdapE\x99U\x8e\xcdc\x9b\x0f\xa7\xd7\x81|Dt=\t\xc9\xba\xf3C\xde\xa9\ +({\x00\x00 \x00IDAT\x16a\xf2\xad8.|\x12\xb0y\x08\xe7\xd7\x00B\x8ax\xadVEQ.\ +\xa7\xe7@\xab\x01\x98|\x95\xba\x02\xe6_\xe2\xb3\x1a\x1f\x85\x0c\x14\x9f\\\ +\xda`\x18(\xe6\xf4\xab\xb0\xa8T\xa2\xaf\xa0;\xb2r\xdf\xc5x_\x15\xad\xd5H\xe2\ +\xc4^\x84\xc8\xcdm\xd9\xc0w%\xbb\xf5\xbe\xb1z\':^b\xeb6\xc3e\x00$\xf7(\xe7{U\ +\xdc\x8e\xcc\xdd\x90\xb6\x01\xef\xf2\xf2\x1a\xb1p\xdfFH\xb7\x15\xa2+\x11\x87\ +\x14\xec\x0c\xb0f\x10\x0c}*\x18\xe1\xe9fh\xd8I\xc4\x89\xb4\x03v\x9e\x86\xfes\ +e\x112Q\r\xa0\x196,\x11W\x11\x14e\xd5v[\xca\xc7\x96y\x1e\xa4\xab\x10?\xe8-\ +\xc0}Hz\xaa\x9fism\xaeLW\xe8\xdc\x99\x80Yv\xa9\xaa\x86\xb3\x06f e\x92\xccr9\ +\n\x8940\xc2\xa8\x9a\xf5\x87N\x97\xd4\xa1\xb8\xee\x00\xd0\x1a\x8em\x91\x19])\ +\xac\xa1\xc4\xd1\xfe\x18\x921gE\x84\xdc\xef$\xa0\t\x15\x8ev(\x1b\x03&\x83\ +\x8a\x82\x03?\xc1\x89\x1d5w\xde\xa0"^\xcf\xa7\xb3\xcb\x05\x1b6x\x86\x8f)\xa2\ +\xa2,\x14eC\xf6\x81Zh\\E\xa1a\xdd,\xf8\xf4&\x0fKw\x0c\x12Z\xd5\x18\x19 \r\ +\x11\xbf\xa8\x1f\xdd\x89\x9a\x1c(\xda\xed\xd2\xe6\xabB_HE\xc2\xae\xaa\xaa\ +\x85\x1aI\xdf\xfd\x18\x11"7\xc9\xe3\x00\x92\xd8\x00\xa0`\xf8\x03\x04\xf1\xdc\ +\xac\xea\xa0\x08\x90\x1a\xad(^d\xa4%\x12=b\x8e\x94D\xe0\x05D\xd8\'\xc5\xffq\ +\xc3\xe4[\x02_k\xb7\xcf\x9f\xe4Vn\xfe\x80\x1a\x9dI\x07\x15\xf1\xfa"#\xc3\xe9\ +Q\xa6D3`@\x02Ps!\x1f\x95\x85\xd6\xb0\xf6U\xa98\xa1\xcd\xd9\xba\xa9reZ\x89\ +\xe6\xe5\x1c\xc2\xafo\x0e\xaa\x7f\xa0T\x8al\x13\x90\xf6_\x8cXX\xffB\xa6\xbd\ +\xa7\xdbB\x8d(\x92]\x83X\xbb\xe6B\x92\x19\x17k,h5\xeb\x0b\x9d\xc6\xd7}k\xd7\ +\x84\xa3\xbcP\xf5\xf1\x08\xd9z\xc2\x8aD\x94|\r\x04\xc8\xbc\n\x93oi\\\xf0/\ +\x88j \xfe\xfc\x9d\x8b\xfd\xefS]\xae\x9a\xa0&\xdeU\xab\xb21\x1f\xedJ)\xda\ +\xb7\x8f!"B\x91{\xb4\xc4\x8f\x1a,\xd0\x1av.\x80/\xa7y\xac\x8c6\xa4\x84t\x8bw\ +\x04\xbeARK\xcb\xc8\t\xaf\x8e\x81R)\xc2\x05\x11\xa8\xb9\x05!\xdd\x01H<\xeb&\ +\xe0\xe9\xd3i\x04P\x80,\x0e]\x8d\x84\x91\x8dC,Z\r\xfc\x0f0\x8aT\xc67\x81+\ +\xde+\x89\x18\xa8\xf3p\xc3\xa1\xd5~\xb6{:\xb7\x87\xe3\xdf\xcd\xa3\x80~H\x16\ +\xde=\xf8\x9d!\x9c\xe9\xe4\xeby\xfd-\x06A\xfb\x8b\xe4\x81\x9e\xb6\x06\xb2O#\ +\x1d\xfdT\x10\xd4\xc4\xfb\xfb\xef\xf9^\x85\xf9\x9a4\x89 >\xde\xca\xa1\xdf\ +\x82+\x9aLk\xc8\xd9\x0f\x0b&\xfb\x84\xa3\\\x80w)\x18\x8dL\xd7\x7fAb1gP"\xd2\ +\xe2\xef\xb8U0P*\xeaN\x88\x88\x85^\xd7\xc2\xe5o#\xa5\x95b\x80\x9b\x8cv\x9a8\ +\x1f\xa9\'\xf6\x1f\xe0U\xc0\x8c{\xadPC\x8c\xd7\xaf\x88\xdbe2R\x8f\xec<$\xa5X\ +\x03\x9b\x81u%\xed\x99\xf0\x1a4\xe8t\xe6X\xbbhp\xfaK\x07\xb4 B\xed\t\xc8o\ +\x10\x08\nHF~\x9f\xcf\x8d\xbf}Oq\x86\x93/\x805\n.xZ\xb2I\xd15\xbb\xa8f"\xa8\ +\x89w\xe7\xce\x02rsK\xa2\xc4\xe3\xe2\xact\xee\x1c\xcb\x91\r5\xa3 TQ(\r?\xfc\ +\xa3$\xec\x08\x80f\x94\xae\xe1\xe5F\xa6\x83 \x19^\x8f Ds#\xd0\xd4\xff\xb1+m\ +\xa5Rq\xb2\x05);3`\n\xdc\xbe\x1e.\x9b\x07\xbd\xae\x87\xc6]\x11k\xdc\xe1\xd1~\ +\x85X\xbc\xd7#\xbe\xe9;\x10\x01\x9c\x1d\x14\x97\xb7\xf1K\xc2\x9e\x84{#0\n\ +\xf1\x13+\xe0BdF`>\x90\xcc\xe9\x9e\x82\xf1\xff\x07\x1d\x03\x07\xc6\x17W\xa2\ +\xe8\xd93\x8e\xdf\xde\xc8&}\xa7\xa4f\x06\x054\x1c^\xe9\xb3\xcd\xb7t\xb7F\xa6\ +\xe9f\t\xf0\xbf"\x03\xa45\xf0&\xe27}\x14\x99\x82\xe7P\n\xde\x996\xa5\xfdN\ +\x95\x19L\xca\x02\xc9]\xa0\xff\xcd\xd0s\x12\xc46\xc2;^\xd4\x82\x90n.\xdeZ\ +\x0b\n\x89j\xb8\x03X\t\xacB\xa6\xb7\x03\x10\xcb\xfd,\xfc\x13\xe5N$\x0c\xcdL\ +\x92\x88D|\xbb\xa6\xa5\x9b\x8bH)\x16\xc8\xf7G=\n=\xae\x0fp\xac3\x19G\x10\xe9\ +\xcc>\x94\x7fo\x14\xa2-\xfc+\xf2\x80\\\xe7\xfd\xf1\x99\x1ajf\x8b\x81\xb3\xff\ +f\xd8\x08\x1a\xd6\xbfQ3\xc2\xe7\xa5\xdaQ\xf3\xa7\xac8\xdcn\xf8\xf1\xc7,\x06\ +\x0eL0\xb6h\xc6\x8fo\xc8k\xaf\xa7\x91\xb9W\x82\xde\x83a\x1a\x9aw\x0c\xd2\xf7\ +xlPx\x17V4\xb7\x99\xfb\\\x80\xb7\x8bA!\x0b&\xcf#\xfe\xb9\xe7(\t\x94\xf7\x83S\ +\xb5X"\x13\xa0\xdb\xa5\xd0\xf7&hq6\xa8\x88\xd2\xf7\xcf\r\xf4\xba\xce\x90!\ +\xdcH\xe9\xa9\xadBz\xcdP\x84hw \x95z\x8f\x03\x15\xc9\xccK\x06&P\xa2\x7f\x90\ +\x81\x94\xff1\x8a\xb2\x8d|\x18\x86?*\x0f\x870\xfc\xe0\x01Jf\x06\xe5A!\x85D\ +\x17#\xbf\xe3&\xef\x8f\xcf\x14\xf2\xf5\x1c/=&B\xb2YXU\xc3\xd6\xcf\x02\x7f\ +\xaf:\xefM\xd0w\xef\x9f\x7f.I\x94WJ\xd1\xa3G\x1cQ\x91\x8am\x0b\x82\xc8 \xd2>\ +\x8b}\x8d\x8d\x97\'\xdcH\x98\x14\x08\xf1\x06Z i\x8d\x84\x07}`\xfc]\x05\x88K\ +\x81Q\xd3a\xdav\x98\xf06\xb4\x1c)\x99\x7f\xfe\x1eZJA\x97\t\x10\xd3\x10\t\xe9\ +\xca+\xe3\xc0\x16$\xd0\xff\xcf\xc0mH\nq\x1b\xc4\x15\xe1\xd9\xb3l\xc84y8\xf0G\ +JH7\x1f\t%;*o;\x8d\x85\xb3\xff\x1e&]@\x84pJ\x02z$K\r\xe47\xd9\x85\x7f\xb7\ +\x8e?(d\x865\x973\xd2\xe7\xeby}\r\xda\xc1\xc8\x19\x14\x8b\xfc\x17\x9e\x84\ +\xfd+j\xa7]Am\xf1\x02\xacZ\x95Cn\xae\x8b\x84\x04\xc9\x17m\xdd:\x8a\xe1\xc3\ +\xeb\xb3}s\x06\xdaMP\x14\xbe\x8cL\x80\xb8\x86\x90c\x96\xe4n\xe6g\xa7\xdc\xf05$\ +\xb65|\xbb\x1a\xf6~\x07v?n\xbd\x9a@\xd0\xdb\x16G\x8f\x8a\x9f\xd7\x8cnP\n\xfa\ +\xf4\x89\xe7\xd8f8\xb9\xb5\x96\x1bg "\xce\x88\x040\xe1\xcfRM\xa5DM\xaa"*\xf7\ +\n\x19lS\x11?\xdd\x0fH\x04\x80\xe7\xe2\x8a\x8d2I<\xae\x11L\xfa\x12b=H\xb7"\ +\xd0\xc0\x85\xff\x81\x16\x83\x11\x0b\xab\xb2\xbd\xc4\x8a\x10qS\xe3\x15o\x1c\ +\xc3\x0c\x8b:\x88\xf8t\r\xd2\x8dn\x00c\xff\x0flq\xc1\xe1:\xaa-h\x0bt\x1ek\ +\xbc9\x82\xf8\xc4\xcd\xc5I\xcf\xe8\x98e\xc0,*\x17K\xad\x90\xf0\xbd\xce\xfe?\ +\xae\x8b\x96\xaf\xe75\x9d\xf3 \xd4\xefX\xd2\xbf\xdcvX3\xb7\xb6Z\x16\x84\xc4\ +\xeb\xfb\xe4\xd5\x1a\x16,(\t\x17PJ1n\\C\xec\xb9\xb0i^\xf0\xc4\xf3\x16\x0bk+\ +\x8a\x0b4z\xc1lg2%\xd6KE`\xfaT\x87 \xfa\xab;\x81\xed\xc6k\x07\xb2r\xedy\xc7\ +\xceF\xace\x84\xd0\xe2\x9aT\x9e\xcc\x94\x82\xe8d\x98\xf8.\xb4\xee\r\xbc\x88D\ +clF\xdc%\xa6\xefY{\xbc|\xe1\xfbY!2E~\x13\xd1\x1c(\x00,\xd0u\x02\\\xb7\x00\ +\xea\xb5;\xb3I\xd7D\xdf\x9b\rW\x8b\x13y\xe0\x9a\xf7d\x00\x92vn\xbe\x7f\x10Y\ +\x07pRq\x02\xb6Q\xa6\x95\\\x97\xc8\xd7\xf3ZzO*-L\x7f\xf0\'\xd8\xfdM\xe0\xefW\ +\xf7\x0c \xe8]\r\x00\xdf~\x9b\xce\x8c\x19\xad\xb1\x1an\x85!C\x12\xe9\xd0!\ +\x86\xad\x8b\n\x18\xf5O\xaaE\xb5\xaaRP\xd0r\x08\xa4\x99\xeaF\xfeB~\xcc\x00\ +\xed\x04\xbc\xad\x97J\x9c\xa3\x98\xd4=\x89\xddS\xb7\xa2\x0f\xb2\x88\xb2\xeb\ +\x14\x8e\xef{:\x05\xf5:\xc0\r\xdf\xc2\xe6y\xb0\xf2U8\xfc\x89\xf1\xa1\r\xf1\ +\x1b6F\xae%@\xaa*\x99\xc6+\x1d\xf1\xe3\x9a1\xaa\n\xda\x9c#\x0bi\xadF!\xc5.\ +\xc2\xa4\x8bR\xd0\xb8/\xb4\x1d\x05{\xbe\x03\xd6"\xe1v\xf5\x11\xc2\xbc\nq\xfd\ +,F\x1e\\\xb7 \x95/\xfe\r\x98\x0bF\x81`JJ\x96S>\xa9.\xb8\x1d\x08E\xb7\x83?\xd2-\xb5n\xa0a\xf7b8\xba\xa5\ +\x16\x1a\xe8\x01\xa5,\xb5=O\xf7\x0f\xdf\x1f>%%\x82\xfd\xfb\xcf"&F\x9e\x15Zkn\ +\xbcq;Kw\x1d\xe5\xe6\x9f\xa9uw\xc3\xb1u0k\xa0!\x8e\xf3GJ/\xb0-AR\x85\x93\x90\ +\xe9\xa2Y?\xebtP\x84H)\x1eD\x92\x1a\xccp\xa1\\\xe0yh\xda\x17\xfe\xbc\x92j{\ +\xbcj-\x97\xe0\xc8\x01g\x81\xff}\xa2\x1bH\xbcp\xf0\xc4\xfe\x95<\xa8\xcbk\x92\ +\xa6\xf6\x1e\x0e\xda\t\xf3F\xc3\x9e\xef\x8d\r]\x10W\x03\x944\xdc\x05\xfc\x86\ +\xff*\xc9\xc9\x88_8\n\xd1\xefm@\xe9\x0b^\x8dd\x11\x96\x83P\xb0~}Iw\xe2{\xfe\ +\x17k\xb5\x0b\xe6]\x08\'V[\xc9\xce\xf6?\r\xad\x89\xeb\r\tW\x03\xc0\xf1\xe3\ +\x0e\xbe\xfb.\x93\xb1c\x1b\x14g\xb1M\x9e\xdc\x94\x8f/:\xc6\xf6\xcf5\x9d\'\ +\xd6n\xfb\x92:Iy\x9a\xac\xfd\x88\xb0\xb7/\xf1\x9a\x8bo\xe9\x88\x06\xc2B\xbcu\ +\x10*\x0b\r|\x82\xa8\x9c\xd5\xa3$\xceSSl\xed4\xe9!S\xd7\xea\xeaEf\xa7\x8eH\ +\x94W0\xa3\xf8!\x91+\xe5}v/\x81\xcc=px\xad\xff\xfd\x9b\xf6\x91\x07W\xfd\xb6\ +\x92\xe5\x17\x99\x08\xa8\x1a$c+\\>\x0f\xe6\x8d\x81#\x1b\x81m\xc0\x7f\x91\x85\ +\xd38i\x0bV$\x91%\n!_\xb3\x1ca\x14\xd2\':!\x84\xeb)\xb2c\xc2\x14+\xaa\x00\ +\x82\xd9\xf5\xe0e\xa0)\xe8u\r\x8c\x9fS\xda\xbd\x00\xd2\x07Nn\x85\x83\xbfB\ +\x97\xf6\xd1l\xdaT:H\xbd\xa6\xae3d\x88\x17`\xee\xdc4\xc6\x8e\x95\xb8-\xa5\ +\x14g\x9f]\x8f\x8e\x1dbY\xf7v\x1e\x9d/\xa7V\xad*k,t\xbb\x04~\x99\x89\x7f\xdf\ +g\x1bJ\xdc\x00\xdf\x03\xd3\x80\x97)!\xe4\xca@#YbS\x8c\xbf[\xe2m\xd5n\'p\xb4\ +\xc1\x99\x06-d\xbb\xef\x1bP\xdb\xe3\xe8\x18\x91D\xefv\xf1\\\xde-J\xa6\xdc\ +\xe3Jv\xdd\xbb\xb7\x90={d\x05\xf0\xe4I;\x8b\xff\x91\xce\xfe\x03\x85\xa8hM\ +\xa3.\x12\x80\xdf\xe52hw>D\xd5\xaf^\x12VJ\xe2\xa9/\x99\x03\xef\x8e\x95\x87\ +\x05\xdb\x91\x0c\xc1K\xf0~\xb0\xf7G\xfa\xd7\xefH\xa6Z;\xbcGv \x9f\xafG\xf2@r\ +\'\x99\x9d\x1c^EI\x8d9\xcf\xaf\x18\x04\x17L\x04\xec;+\x1e\xf5\x88d=\x06Z;P\ +\xc0\xd2\xc7 \xb9~$\x19\x19\xfe\xd4\xe6k\x0eA\xebj\x80\xd276:Z\xb1i\xd3 :t\ +\x90\x98\x18\xad5\x0b\x16\xa4\xf3\x87\xeb7s\xcf~\x88J\xf2{\x98\x1a\x81\xd6\ +\x90\xb1\x1df\x0f\x02{.B\x8a\xbe~\xdf/(\xc9\x99WH\xaa\xecD*\xf7\xc00I\xf7ZJ,\ +\x96K\xf0\xce\xdf\xff\x0c\xd8\x08\xe7N\x87a\x8f\x9ey\xbeT\xad\x01\x17\xec\\\ +\x08\xe9?Gr\xe5\xc0\xd6\x0c\xeeY\x9f\xce\x9dc\xb0\x19\x84\xa4\xfc\xdc\x14\ +\xadu\xf1v\xad5\x0e\x87\x90\xf1g\x9f\x9d`\xce\x9cT\xf6\xee\x15\x932"VJ\xb9\ +\xf7\x9f"\xd1\x19\xd1\r\xa9\xb6\x87\xbe\xd6\x90\xf6\x1b\xbcw\x19\xe4\x99\t:\ +\x11\x88F\xc6PJ\xb4yM\xab\xd6\x9fu\xebu@\xc4E\xf5!Rn\th\xd8\x11&\xaf\x10m\ +\xda\xfd\xdf\xc1\'7B\xee\x91\xc0\x87\xa8m\xf2\xf5\xe5\x05k$\x8cx\x00F\xfc\ +\xc3\x98\xe1\x05h\x9d+\x1f^\xea\x02c\x86\xa4\xb0`\xc1\t\x8a\x8aJ[&5umV\x15\ +\xcc\xf9\x99ZO\xf7|\xebtJ\xdd\xb5\xd1\xa3\xc5\xdd\xa0\x94\xa2c\xc7\x18\xd6\ +\xac\xcce\xf3\xda\x02:\\D\xadY\xbdJ\x19\x03\xd0\x01{\x97"\x99j\x9e\xf5\xba4\ +\xe2\x8f-\xa2$\xb4l=B\x9a\xf5\xa8X\xbb5B\xde\x9e\xa4\xdb\x00\xb1\xda\xcc\x12\ +\xe0vD\xd3\xd6\x0e}n\x80&}\xfd\x1d\xa8nBk\xf17ox\x03\xd6S\x802HWkX\xf3*\xec\xff\xda\xca\xc0\x81\x89\ +\xac\\Y:e\xad&\x1f(!e\xf1\x82,\xb2m\xde<\x90F\x8d\xa4\xce\xb6\xd6\x9aU\xabr9\ +\x7f\xc2Z\xa6\xfc\x06\t\xadj\xbc\x99^(<\t\xaf\r6Ds\xaeET\xca\xcc\x9f\xd3\x1c\ +\x18{\x90E\x8dt$\x06\xf6]D"\x11\x02\x13\xb0\x06\xb6 \xab\xd2f\x02\x83\x15I\ +\x1fmJ\x89\xb5\xf3\x03\xf0\xb3\x10\xc0m\xeb!\xb9{\x15^\\\x90\xc2\xd3\xc2]\ +\xf6\x14t\x8ao\xc0\xec\xd9\x9dh\xd7.* \xc9\x06>\x96\xfcH\xe6\xd7\xb4\xf6\tE\ +\xd2\x1a\xad\x15\xfb\xf7\x17\xb2iS\x1e\xaf\xbd\x96\xc6\x0f?d\x90\x97\xef\xa6\ +\xe5Yp\xf6}"\xb0m\x8d\xae\xda\x99\x86\xd6\xa0\x1d\xf0\xf3\x13\xf0\xe3\xbf|\ +\x08Q!\x8bim\xf1v/e\x03\'\x90\xd01?\xee\x83\xc6=\xe0\xf2w \xa5\x8f\xef5\xca!\ +\x8f\xae\x81/n\x81\xd4\x00~\xf0\xe2\xd3W3a\xf9\xe3\x01e\x914\xf3\x8b_\xaeX\ +\xf2\x8d=K\xc6\xe5E\x83\x9a\xb0kW>\xbf\xfc\x92]j\x9f0\xf1\x1a\x08\x14\xd22}z\ +\x1b\x1e}\xb4\xb5\xd7\xe0\x189r=jX\x16\xe7\xd7\x06D\xa3F\x11\ +\xdcyg\x0b\xae\xbe:\x85\x8e\x1d\xa3\x8b\tx\xf7\xee"f\xcfN\xe5\xf9\xe7\x0f\ +\x12\xddP\xaa\xda\xf6\x98\x14X\x0b\xb9*P\x9c\x1c\xa2\xfc\xbf\xaf\x8a\xe3\xbb\ +s\xe1\xe5^\x90\xb9\xafj\x8eY."\x11\r\xeb_(\xd6\x9a\xb8\xf4u\xe8us\xf9\xd7\ +\xe5.\x84Wz\xc2u\x175g\xec\xd8\x86\x8c\x19\xb3\xb1\xd4>\xb5\x11\xa5\x11\xb2\ +\xc4\x0b\x92@1gNG\xaf\xe9\xde\xfc\xf9\xc7y\xf4\xf5\xad\xfc\xe1\x0b#\xe8\xbd\ +\x96\xa15d\xef\x85E\xb7\xc3\xae\xff\x19\x1b\xa3\x10\xab\xb5\x0b%.\x85\xf2B\ +\x81\xca\xfal=\xc5\xd5\x1f:\x8f\x87\xab?\xab\x98\xef+d\xa0!\xff(,\xbe\x076\ +\x7f\x08\xb11\x16f\xcf\xee\xcc\x95W&\x13\x11\xa1\x8a\x89NkX\xbd:\x97\xf7\xdf\ +?\xc6\xec\xd9\xa9\x14\x14T#\xdb\xfaA\x83\x066\xa6Nm\xc1\xf8\xf1\r\xe9\xd3\'\ +\x0e\x8bE~\xff\r\x1b\xf2x\xf0\xc1\xbd\xfc\xef\x7f\xe9\xb49\x07\xc6\xbd\n\r:\ +\x87\xe6\x83Qk\xd8\xf46|v3\xd5k\xf1Z\x90Yb\x1fd\x9cD \x95N~\x94\x8f\x9b\xf6\ +\x85)+\xcb\x9e\xd9j\r\xab^\x84uOE\xb2a\xc3\x00\xa6L\xd9\xce\x17_\x9c,\xb5_\ +\x98x\xcb\x80?\xf2\x8d\x89\xb1\xb0jU\x7f\xbau\x8b)&_\x87C3q\xe2\x16\xec\xc3O\ +r\xd6}\x04M\xaa\xaa3_\\\x0f?\xfe\x0b\x1cf\xc2\x8cB\x02\xdfG I\x10\x95\xf9)\ +\xcc\xbb\xf1;\x12\xb7\xeb\x12\xcd\x84)\xbf@B\xeb\xd0\x1c\xd4\xbe0}\x99kg\xc3\ +\xb7\x0fK\x12\xc1y\xe75\xe0\xc9\'\xdb\xd2\xbf\x7f|1\xe1\x82b\xc5\x8alf\xce<\ +\xccG\x1f\x1d;%\xeb6\xd0\xe0;\x15\xcd\x02\xab\x15&Nl\xc4c\x8f\xb5\xa1S\'\x89\ +9\xb7\xdb5O=u\x90W_M\xa50\xd2\xce\x95\x1f@\xd3\xb3B\xefw\xca9\x08\xaf\xf6\ +\x85\x82\x91\x94\xc4\x10\x83\xd4\x82\xfb\x15IS~\x10)\x1be7\xb6\x81\x08\xfa\ +\xecCB\xdb|}\xc4Q\x08\xb9\x0e\x03v#\xeakC\x90H\x1fO\x83#\r\x98#\x7fZ#\xc5\ +\xddPV\xdd\xc5\x8c\xed\xf0\x7f}\xe1\xf1G\xdbq\xc5\x15\xc9t\xeb\xb6\n\x87\xc3\ +\xfb\xe7\xac\xad\x98\xe4\x90&^\x80+\xaeH\xe1\x83\x0f\xbab\xb5\x96X\xbd\xbbv\ +\x15r\xd55[\x1883/h:\xb79\xe5;\xbcL\\\x0f\xa5\n\xec\xc5"\xa1b\x1d\x91\xc5\ +\xb3\xb2|\xd4\x99H\x16\xd3Z\xa4C#.\x86k>\x81\xf6\xe3\x82\xe3zO\x17ZC\x81i\ +\xe5~\x04\xd1\x91\x16\x1e~\xb85\x7f\xfb[\xcbbyP\x80%K2y\xe1\x85C|\xfbm\x06Ng\ +\xc59\xf2T\x07\\e\x8882R\xf1\xc0\x03\xad\xb9\xf3\xcef$\'\xcb\x0f\xbacG\x01S\ +\xa6\xec`\xf9/Y\x0c\xfb\x1b\x9c\xf3\x8fS\xf3\xb9\xd6\x06\xb4\x865/\xc3\x97w\ +\x03\xb7#i\xeaf\xbb\x17#\xba\x11\x0f\x03\x8fQ2\x833\xe1F\x08w;\xdeR\xa6 \xc6\ +\x87\xa9\xa8\xf7
+ diff --git a/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/another.hhc b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/another.hhc new file mode 100644 index 0000000000..f9dd604508 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/another.hhc @@ -0,0 +1,18 @@ + + + + + + + +
    +
  • + + + +
  • + + + +
+ diff --git a/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/another.hhp b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/another.hhp new file mode 100644 index 0000000000..017ed2427c --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/another.hhp @@ -0,0 +1,6 @@ +[OPTIONS] +Compatibility=1.1 +Contents file=another.hhc +Display compile progress=No +Title=Another book +Default topic=another.htm diff --git a/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/another.htm b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/another.htm new file mode 100644 index 0000000000..4532dc8c40 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/another.htm @@ -0,0 +1,24 @@ + + + + Another HTML Help book + + + +

Another book...

+ Here's another book to demonstrate that +
+ You can also view the project file for this book. + + diff --git a/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/book1.htm b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/book1.htm new file mode 100644 index 0000000000..fa470e3ec5 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/book1.htm @@ -0,0 +1,4 @@ +Book 1 +

Book 1.

+How do you enjoy book one?? + diff --git a/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/book2.htm b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/book2.htm new file mode 100644 index 0000000000..828723fc65 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/book2.htm @@ -0,0 +1,5 @@ +Book 1 +

Book 2.

+How do you enjoy book two?? +

Please click HERE + diff --git a/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/contents.hhc b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/contents.hhc new file mode 100644 index 0000000000..9ecf3537b6 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/contents.hhc @@ -0,0 +1,28 @@ + + + + + + + + + +

    +
  • + + + +
  • + + + + +
      +
    • + + + +
    +
+ + diff --git a/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/main.htm b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/main.htm new file mode 100644 index 0000000000..ca5275bfd7 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/main.htm @@ -0,0 +1,5 @@ + +

This is main page.

+Book 1
+Book 2
+ diff --git a/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/page2-b.htm b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/page2-b.htm new file mode 100644 index 0000000000..f51dd6d6d6 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/page2-b.htm @@ -0,0 +1,5 @@ + + +Hello, you're on sub page of page 2 !!! + + diff --git a/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/testing.hhp b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/testing.hhp new file mode 100644 index 0000000000..5f8eb34468 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/testing.hhp @@ -0,0 +1,16 @@ +[OPTIONS] +Compatibility=1.1 +Compiled file=testing.chm +Contents file=contents.hhc +Display compile progress=No +Index file=Index.hhk +Language=0x405 Èesky +Title=Test HELPFILE +Default topic=main.htm + +[FILES] +main.htm +book1.htm +book2.htm +page2-b.htm + diff --git a/wxPython/samples/wxPIA_book/Chapter-16/html_help.py b/wxPython/samples/wxPIA_book/Chapter-16/html_help.py new file mode 100644 index 0000000000..ae212aa91d --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-16/html_help.py @@ -0,0 +1,59 @@ +""" +wxPython can use html files for online help or other forms of +documentation for your application. The help can be organized as a +collection of books, and there is a help viewer available that enables +the user to browse by book, via an index or full text search. The +format of the contents and index files are similar to Microsoft +HtmlHelp. +""" + +import wx +import wx.html + +class MyHtmlFrame(wx.Frame): + def __init__(self, parent, title): + wx.Frame.__init__(self, parent, -1, title) + p = wx.Panel(self) + b1 = wx.Button(p, -1, "Show Help Contents") + b2 = wx.Button(p, -1, "Show Help Index") + b3 = wx.Button(p, -1, "Show Specific Help") + self.Bind(wx.EVT_BUTTON, self.OnShowHelpContents, b1) + self.Bind(wx.EVT_BUTTON, self.OnShowHelpIndex, b2) + self.Bind(wx.EVT_BUTTON, self.OnShowSpecificHelp, b3) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add((10,10)) + sizer.Add(b1, 0, wx.ALL, 10) + sizer.Add(b2, 0, wx.ALL, 10) + sizer.Add(b3, 0, wx.ALL, 10) + p.SetSizer(sizer) + + self.InitHelp() + + + def InitHelp(self): + def _addBook(filename): + if not self.help.AddBook(filename): + wx.MessageBox("Unable to open: " + filename, + "Error", wx.OK|wx.ICON_EXCLAMATION) + + self.help = wx.html.HtmlHelpController() + + _addBook("helpfiles/testing.hhp") + _addBook("helpfiles/another.hhp") + + + def OnShowHelpContents(self, evt): + self.help.DisplayContents() + + def OnShowHelpIndex(self, evt): + self.help.DisplayIndex() + + def OnShowSpecificHelp(self, evt): + self.help.Display("sub book") + + +app = wx.PySimpleApp() +frm = MyHtmlFrame(None, "HTML Help") +frm.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-16/html_tag.py b/wxPython/samples/wxPIA_book/Chapter-16/html_tag.py new file mode 100644 index 0000000000..771bb2a3cb --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-16/html_tag.py @@ -0,0 +1,71 @@ +import wx +import wx.html + +page = """ + +This silly example shows how custom tags can be defined and used in a +wx.HtmlWindow. We've defined a new tag, <blue> that will change +the foreground color of the portions of the document that +it encloses to some shade of blue. The tag handler can also use +parameters specifed in the tag, for example: + +
    +
  • Sky Blue +
  • Midnight Blue +
  • Dark Blue +
  • Navy Blue +
+ + +""" + + +class BlueTagHandler(wx.html.HtmlWinTagHandler): + def __init__(self): + wx.html.HtmlWinTagHandler.__init__(self) + + def GetSupportedTags(self): + return "BLUE" + + def HandleTag(self, tag): + old = self.GetParser().GetActualColor() + clr = "#0000FF" + if tag.HasParam("SHADE"): + shade = tag.GetParam("SHADE") + if shade.upper() == "SKY": + clr = "#3299CC" + if shade.upper() == "MIDNIGHT": + clr = "#2F2F4F" + elif shade.upper() == "DARK": + clr = "#00008B" + elif shade.upper == "NAVY": + clr = "#23238E" + + self.GetParser().SetActualColor(clr) + self.GetParser().GetContainer().InsertCell(wx.html.HtmlColourCell(clr)) + + self.ParseInner(tag) + + self.GetParser().SetActualColor(old) + self.GetParser().GetContainer().InsertCell(wx.html.HtmlColourCell(old)) + + return True + + +wx.html.HtmlWinParser_AddTagHandler(BlueTagHandler) + + + +class MyHtmlFrame(wx.Frame): + def __init__(self, parent, title): + wx.Frame.__init__(self, parent, -1, title) + html = wx.html.HtmlWindow(self) + if "gtk2" in wx.PlatformInfo: + html.SetStandardFonts() + html.SetPage(page) + + +app = wx.PySimpleApp() +frm = MyHtmlFrame(None, "Custom HTML Tag Handler") +frm.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-16/html_window.py b/wxPython/samples/wxPIA_book/Chapter-16/html_window.py new file mode 100644 index 0000000000..9f73b68122 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-16/html_window.py @@ -0,0 +1,19 @@ +import wx +import wx.html + +class MyHtmlFrame(wx.Frame): + def __init__(self, parent, title): + wx.Frame.__init__(self, parent, -1, title) + html = wx.html.HtmlWindow(self) + if "gtk2" in wx.PlatformInfo: + html.SetStandardFonts() + + html.SetPage( + "Here is some formatted text " + "loaded from a string.") + + +app = wx.PySimpleApp() +frm = MyHtmlFrame(None, "Simple HTML") +frm.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-16/html_window_loadpage.py b/wxPython/samples/wxPIA_book/Chapter-16/html_window_loadpage.py new file mode 100644 index 0000000000..5789ce4e9b --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-16/html_window_loadpage.py @@ -0,0 +1,17 @@ +import wx +import wx.html + +class MyHtmlFrame(wx.Frame): + def __init__(self, parent, title): + wx.Frame.__init__(self, parent, -1, title, size=(600,400)) + html = wx.html.HtmlWindow(self) + if "gtk2" in wx.PlatformInfo: + html.SetStandardFonts() + + wx.CallAfter( + html.LoadPage, "http://wxwidgets.org/manuals/2.6.2/wx_wxbutton.html") + +app = wx.PySimpleApp() +frm = MyHtmlFrame(None, "Simple HTML Browser") +frm.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-16/html_window_related.py b/wxPython/samples/wxPIA_book/Chapter-16/html_window_related.py new file mode 100644 index 0000000000..4887b71368 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-16/html_window_related.py @@ -0,0 +1,21 @@ +import wx +import wx.html + +class MyHtmlFrame(wx.Frame): + def __init__(self, parent, title): + wx.Frame.__init__(self, parent, -1, title, size=(600,400)) + self.CreateStatusBar() + + html = wx.html.HtmlWindow(self) + if "gtk2" in wx.PlatformInfo: + html.SetStandardFonts() + html.SetRelatedFrame(self, self.GetTitle() + " -- %s") + html.SetRelatedStatusBar(0) + + wx.CallAfter( + html.LoadPage, "http://wxwidgets.org/manuals/2.6.2/wx_wxbutton.html") + +app = wx.PySimpleApp() +frm = MyHtmlFrame(None, "Simple HTML Browser") +frm.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-17/printing.py b/wxPython/samples/wxPIA_book/Chapter-17/printing.py new file mode 100755 index 0000000000..a0481491be --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-17/printing.py @@ -0,0 +1,236 @@ +import wx +import os + +FONTSIZE = 10 + +class TextDocPrintout(wx.Printout): + """ + A printout class that is able to print simple text documents. + Does not handle page numbers or titles, and it assumes that no + lines are longer than what will fit within the page width. Those + features are left as an exercise for the reader. ;-) + """ + def __init__(self, text, title, margins): + wx.Printout.__init__(self, title) + self.lines = text.split('\n') + self.margins = margins + + + def HasPage(self, page): + return page <= self.numPages + + def GetPageInfo(self): + return (1, self.numPages, 1, self.numPages) + + + def CalculateScale(self, dc): + # Scale the DC such that the printout is roughly the same as + # the screen scaling. + ppiPrinterX, ppiPrinterY = self.GetPPIPrinter() + ppiScreenX, ppiScreenY = self.GetPPIScreen() + logScale = float(ppiPrinterX)/float(ppiScreenX) + + # Now adjust if the real page size is reduced (such as when + # drawing on a scaled wx.MemoryDC in the Print Preview.) If + # page width == DC width then nothing changes, otherwise we + # scale down for the DC. + pw, ph = self.GetPageSizePixels() + dw, dh = dc.GetSize() + scale = logScale * float(dw)/float(pw) + + # Set the DC's scale. + dc.SetUserScale(scale, scale) + + # Find the logical units per millimeter (for calculating the + # margins) + self.logUnitsMM = float(ppiPrinterX)/(logScale*25.4) + + + def CalculateLayout(self, dc): + # Determine the position of the margins and the + # page/line height + topLeft, bottomRight = self.margins + dw, dh = dc.GetSize() + self.x1 = topLeft.x * self.logUnitsMM + self.y1 = topLeft.y * self.logUnitsMM + self.x2 = dc.DeviceToLogicalXRel(dw) - bottomRight.x * self.logUnitsMM + self.y2 = dc.DeviceToLogicalYRel(dh) - bottomRight.y * self.logUnitsMM + + # use a 1mm buffer around the inside of the box, and a few + # pixels between each line + self.pageHeight = self.y2 - self.y1 - 2*self.logUnitsMM + font = wx.Font(FONTSIZE, wx.TELETYPE, wx.NORMAL, wx.NORMAL) + dc.SetFont(font) + self.lineHeight = dc.GetCharHeight() + self.linesPerPage = int(self.pageHeight/self.lineHeight) + + + def OnPreparePrinting(self): + # calculate the number of pages + dc = self.GetDC() + self.CalculateScale(dc) + self.CalculateLayout(dc) + self.numPages = len(self.lines) / self.linesPerPage + if len(self.lines) % self.linesPerPage != 0: + self.numPages += 1 + + + def OnPrintPage(self, page): + dc = self.GetDC() + self.CalculateScale(dc) + self.CalculateLayout(dc) + + # draw a page outline at the margin points + dc.SetPen(wx.Pen("black", 0)) + dc.SetBrush(wx.TRANSPARENT_BRUSH) + r = wx.RectPP((self.x1, self.y1), + (self.x2, self.y2)) + dc.DrawRectangleRect(r) + dc.SetClippingRect(r) + + # Draw the text lines for this page + line = (page-1) * self.linesPerPage + x = self.x1 + self.logUnitsMM + y = self.y1 + self.logUnitsMM + while line < (page * self.linesPerPage): + dc.DrawText(self.lines[line], x, y) + y += self.lineHeight + line += 1 + if line >= len(self.lines): + break + return True + + +class PrintFrameworkSample(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, size=(640, 480), + title="Print Framework Sample") + self.CreateStatusBar() + + # A text widget to display the doc and let it be edited + self.tc = wx.TextCtrl(self, -1, "", + style=wx.TE_MULTILINE|wx.TE_DONTWRAP) + self.tc.SetFont(wx.Font(FONTSIZE, wx.TELETYPE, wx.NORMAL, wx.NORMAL)) + filename = os.path.join(os.path.dirname(__file__), "sample-text.txt") + self.tc.SetValue(open(filename).read()) + self.tc.Bind(wx.EVT_SET_FOCUS, self.OnClearSelection) + wx.CallAfter(self.tc.SetInsertionPoint, 0) + + # Create the menu and menubar + menu = wx.Menu() + item = menu.Append(-1, "Page Setup...\tF5", + "Set up page margins and etc.") + self.Bind(wx.EVT_MENU, self.OnPageSetup, item) + item = menu.Append(-1, "Print Preview...\tF6", + "View the printout on-screen") + self.Bind(wx.EVT_MENU, self.OnPrintPreview, item) + item = menu.Append(-1, "Print...\tF7", "Print the document") + self.Bind(wx.EVT_MENU, self.OnPrint, item) + menu.AppendSeparator() +## item = menu.Append(-1, "Test other stuff...\tF9", "") +## self.Bind(wx.EVT_MENU, self.OnPrintTest, item) +## menu.AppendSeparator() + item = menu.Append(wx.ID_EXIT, "E&xit\tCtrl-Q", "Close this application") + self.Bind(wx.EVT_MENU, self.OnExit, item) + + menubar = wx.MenuBar() + menubar.Append(menu, "&File") + self.SetMenuBar(menubar) + + # initialize the print data and set some default values + self.pdata = wx.PrintData() + self.pdata.SetPaperId(wx.PAPER_LETTER) + self.pdata.SetOrientation(wx.PORTRAIT) + self.margins = (wx.Point(15,15), wx.Point(15,15)) + + + def OnExit(self, evt): + self.Close() + + + def OnClearSelection(self, evt): + evt.Skip() + wx.CallAfter(self.tc.SetInsertionPoint, + self.tc.GetInsertionPoint()) + + + def OnPageSetup(self, evt): + data = wx.PageSetupDialogData() + data.SetPrintData(self.pdata) + + data.SetDefaultMinMargins(True) + data.SetMarginTopLeft(self.margins[0]) + data.SetMarginBottomRight(self.margins[1]) + + dlg = wx.PageSetupDialog(self, data) + if dlg.ShowModal() == wx.ID_OK: + data = dlg.GetPageSetupData() + self.pdata = wx.PrintData(data.GetPrintData()) # force a copy + self.pdata.SetPaperId(data.GetPaperId()) + self.margins = (data.GetMarginTopLeft(), + data.GetMarginBottomRight()) + dlg.Destroy() + + + def OnPrintPreview(self, evt): + data = wx.PrintDialogData(self.pdata) + text = self.tc.GetValue() + printout1 = TextDocPrintout(text, "title", self.margins) + printout2 = None #TextDocPrintout(text, "title", self.margins) + preview = wx.PrintPreview(printout1, printout2, data) + if not preview.Ok(): + wx.MessageBox("Unable to create PrintPreview!", "Error") + else: + # create the preview frame such that it overlays the app frame + frame = wx.PreviewFrame(preview, self, "Print Preview", + pos=self.GetPosition(), + size=self.GetSize()) + frame.Initialize() + frame.Show() + + + def OnPrint(self, evt): + data = wx.PrintDialogData(self.pdata) + printer = wx.Printer(data) + text = self.tc.GetValue() + printout = TextDocPrintout(text, "title", self.margins) + useSetupDialog = True + if not printer.Print(self, printout, useSetupDialog) \ + and printer.GetLastError() == wx.PRINTER_ERROR: + wx.MessageBox( + "There was a problem printing.\n" + "Perhaps your current printer is not set correctly?", + "Printing Error", wx.OK) + else: + data = printer.GetPrintDialogData() + self.pdata = wx.PrintData(data.GetPrintData()) # force a copy + printout.Destroy() + + + def OnPrintTest(self, evt): + data = wx.PrintDialogData(self.pdata) + dlg = wx.PrintDialog(self, data) + if dlg.ShowModal() == wx.ID_OK: + data = dlg.GetPrintDialogData() + print + print "GetFromPage:", data.GetFromPage() + print "GetToPage:", data.GetToPage() + print "GetMinPage:", data.GetMinPage() + print "GetMaxPage:", data.GetMaxPage() + print "GetNoCopies:", data.GetNoCopies() + print "GetAllPages:", data.GetAllPages() + print "GetSelection:", data.GetSelection() + print "GetCollate:", data.GetCollate() + print "GetPrintToFile:", data.GetPrintToFile() + + self.pdata = wx.PrintData(data.GetPrintData()) + print + print "GetPrinterName:", self.pdata.GetPrinterName() + + dlg.Destroy() + + +app = wx.PySimpleApp() +frm = PrintFrameworkSample() +frm.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-17/sample-text.txt b/wxPython/samples/wxPIA_book/Chapter-17/sample-text.txt new file mode 100755 index 0000000000..8e902f3399 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-17/sample-text.txt @@ -0,0 +1,213 @@ +THE BROTHERS GRIMM +FAIRY TALES + + + +THE GOLDEN BIRD + +A certain king had a beautiful garden, and in the garden stood a tree +which bore golden apples. These apples were always counted, and about +the time when they began to grow ripe it was found that every night +one of them was gone. The king became very angry at this, and ordered +the gardener to keep watch all night under the tree. The gardener set +his eldest son to watch; but about twelve o'clock he fell asleep, and +in the morning another of the apples was missing. Then the second son +was ordered to watch; and at midnight he too fell asleep, and in the +morning another apple was gone. Then the third son offered to keep +watch; but the gardener at first would not let him, for fear some harm +should come to him: however, at last he consented, and the young man +laid himself under the tree to watch. As the clock struck twelve he +heard a rustling noise in the air, and a bird came flying that was of +pure gold; and as it was snapping at one of the apples with its beak, +the gardener's son jumped up and shot an arrow at it. But the arrow +did the bird no harm; only it dropped a golden feather from its tail, +and then flew away. The golden feather was brought to the king in the +morning, and all the council was called together. Everyone agreed that +it was worth more than all the wealth of the kingdom: but the king +said, 'One feather is of no use to me, I must have the whole bird.' + +Then the gardener's eldest son set out and thought to find the golden +bird very easily; and when he had gone but a little way, he came to a +wood, and by the side of the wood he saw a fox sitting; so he took his +bow and made ready to shoot at it. Then the fox said, 'Do not shoot +me, for I will give you good counsel; I know what your business is, +and that you want to find the golden bird. You will reach a village in +the evening; and when you get there, you will see two inns opposite to +each other, one of which is very pleasant and beautiful to look at: go +not in there, but rest for the night in the other, though it may +appear to you to be very poor and mean.' But the son thought to +himself, 'What can such a beast as this know about the matter?' So he +shot his arrow at the fox; but he missed it, and it set up its tail +above its back and ran into the wood. Then he went his way, and in the +evening came to the village where the two inns were; and in one of +these were people singing, and dancing, and feasting; but the other +looked very dirty, and poor. 'I should be very silly,' said he, 'if I +went to that shabby house, and left this charming place'; so he went +into the smart house, and ate and drank at his ease, and forgot the +bird, and his country too. + +Time passed on; and as the eldest son did not come back, and no +tidings were heard of him, the second son set out, and the same thing +happened to him. He met the fox, who gave him the good advice: but +when he came to the two inns, his eldest brother was standing at the +window where the merrymaking was, and called to him to come in; and he +could not withstand the temptation, but went in, and forgot the golden +bird and his country in the same manner. + +Time passed on again, and the youngest son too wished to set out into +the wide world to seek for the golden bird; but his father would not +listen to it for a long while, for he was very fond of his son, and +was afraid that some ill luck might happen to him also, and prevent +his coming back. However, at last it was agreed he should go, for he +would not rest at home; and as he came to the wood, he met the fox, +and heard the same good counsel. But he was thankful to the fox, and +did not attempt his life as his brothers had done; so the fox said, +'Sit upon my tail, and you will travel faster.' So he sat down, and +the fox began to run, and away they went over stock and stone so quick +that their hair whistled in the wind. + +When they came to the village, the son followed the fox's counsel, and +without looking about him went to the shabby inn and rested there all +night at his ease. In the morning came the fox again and met him as he +was beginning his journey, and said, 'Go straight forward, till you +come to a castle, before which lie a whole troop of soldiers fast +asleep and snoring: take no notice of them, but go into the castle and +pass on and on till you come to a room, where the golden bird sits in +a wooden cage; close by it stands a beautiful golden cage; but do not +try to take the bird out of the shabby cage and put it into the +handsome one, otherwise you will repent it.' Then the fox stretched +out his tail again, and the young man sat himself down, and away they +went over stock and stone till their hair whistled in the wind. + +Before the castle gate all was as the fox had said: so the son went in +and found the chamber where the golden bird hung in a wooden cage, and +below stood the golden cage, and the three golden apples that had been +lost were lying close by it. Then thought he to himself, 'It will be a +very droll thing to bring away such a fine bird in this shabby cage'; +so he opened the door and took hold of it and put it into the golden +cage. But the bird set up such a loud scream that all the soldiers +awoke, and they took him prisoner and carried him before the king. The +next morning the court sat to judge him; and when all was heard, it +sentenced him to die, unless he should bring the king the golden horse +which could run as swiftly as the wind; and if he did this, he was to +have the golden bird given him for his own. + +So he set out once more on his journey, sighing, and in great despair, +when on a sudden his friend the fox met him, and said, 'You see now +what has happened on account of your not listening to my counsel. I +will still, however, tell you how to find the golden horse, if you +will do as I bid you. You must go straight on till you come to the +castle where the horse stands in his stall: by his side will lie the +groom fast asleep and snoring: take away the horse quietly, but be +sure to put the old leathern saddle upon him, and not the golden one +that is close by it.' Then the son sat down on the fox's tail, and +away they went over stock and stone till their hair whistled in the +wind. + +All went right, and the groom lay snoring with his hand upon the +golden saddle. But when the son looked at the horse, he thought it a +great pity to put the leathern saddle upon it. 'I will give him the +good one,' said he; 'I am sure he deserves it.' As he took up the +golden saddle the groom awoke and cried out so loud, that all the +guards ran in and took him prisoner, and in the morning he was again +brought before the court to be judged, and was sentenced to die. But +it was agreed, that, if he could bring thither the beautiful princess, +he should live, and have the bird and the horse given him for his own. + +Then he went his way very sorrowful; but the old fox came and said, +'Why did not you listen to me? If you had, you would have carried away +both the bird and the horse; yet will I once more give you counsel. Go +straight on, and in the evening you will arrive at a castle. At twelve +o'clock at night the princess goes to the bathing-house: go up to her +and give her a kiss, and she will let you lead her away; but take care +you do not suffer her to go and take leave of her father and mother.' +Then the fox stretched out his tail, and so away they went over stock +and stone till their hair whistled again. + +As they came to the castle, all was as the fox had said, and at twelve +o'clock the young man met the princes going to the bath and gave her +the kiss, and she agreed to run away with him, but begged with many +tears that he would let her take leave of her father. At first he +refused, but she wept still more and more, and fell at his feet, till +at last he consented; but the moment she came to her father's house +the guards awoke and he was taken prisoner again. + +Then he was brought before the king, and the king said, 'You shall +never have my daughter unless in eight days you dig away the hill that +stops the view from my window.' Now this hill was so big that the +whole world could not take it away: and when he had worked for seven +days, and had done very little, the fox came and said. 'Lie down and +go to sleep; I will work for you.' And in the morning he awoke and the +hill was gone; so he went merrily to the king, and told him that now +that it was removed he must give him the princess. + +Then the king was obliged to keep his word, and away went the young +man and the princess; and the fox came and said to him, 'We will have +all three, the princess, the horse, and the bird.' 'Ah!' said the +young man, 'that would be a great thing, but how can you contrive it?' + +'If you will only listen,' said the fox, 'it can be done. When you +come to the king, and he asks for the beautiful princess, you must +say, "Here she is!" Then he will be very joyful; and you will mount +the golden horse that they are to give you, and put out your hand to +take leave of them; but shake hands with the princess last. Then lift +her quickly on to the horse behind you; clap your spurs to his side, +and gallop away as fast as you can.' + +All went right: then the fox said, 'When you come to the castle where +the bird is, I will stay with the princess at the door, and you will +ride in and speak to the king; and when he sees that it is the right +horse, he will bring out the bird; but you must sit still, and say +that you want to look at it, to see whether it is the true golden +bird; and when you get it into your hand, ride away.' + +This, too, happened as the fox said; they carried off the bird, the +princess mounted again, and they rode on to a great wood. Then the fox +came, and said, 'Pray kill me, and cut off my head and my feet.' But +the young man refused to do it: so the fox said, 'I will at any rate +give you good counsel: beware of two things; ransom no one from the +gallows, and sit down by the side of no river.' Then away he went. +'Well,' thought the young man, 'it is no hard matter to keep that +advice.' + +He rode on with the princess, till at last he came to the village +where he had left his two brothers. And there he heard a great noise +and uproar; and when he asked what was the matter, the people said, +'Two men are going to be hanged.' As he came nearer, he saw that the +two men were his brothers, who had turned robbers; so he said, 'Cannot +they in any way be saved?' But the people said 'No,' unless he would +bestow all his money upon the rascals and buy their liberty. Then he +did not stay to think about the matter, but paid what was asked, and +his brothers were given up, and went on with him towards their home. + +And as they came to the wood where the fox first met them, it was so +cool and pleasant that the two brothers said, 'Let us sit down by the +side of the river, and rest a while, to eat and drink.' So he said, +'Yes,' and forgot the fox's counsel, and sat down on the side of the +river; and while he suspected nothing, they came behind, and threw him +down the bank, and took the princess, the horse, and the bird, and +went home to the king their master, and said. 'All this have we won by +our labour.' Then there was great rejoicing made; but the horse would +not eat, the bird would not sing, and the princess wept. + +The youngest son fell to the bottom of the river's bed: luckily it was +nearly dry, but his bones were almost broken, and the bank was so +steep that he could find no way to get out. Then the old fox came once +more, and scolded him for not following his advice; otherwise no evil +would have befallen him: 'Yet,' said he, 'I cannot leave you here, so +lay hold of my tail and hold fast.' Then he pulled him out of the +river, and said to him, as he got upon the bank, 'Your brothers have +set watch to kill you, if they find you in the kingdom.' So he dressed +himself as a poor man, and came secretly to the king's court, and was +scarcely within the doors when the horse began to eat, and the bird to +sing, and princess left off weeping. Then he went to the king, and +told him all his brothers' roguery; and they were seized and punished, +and he had the princess given to him again; and after the king's death +he was heir to his kingdom. + +A long while after, he went to walk one day in the wood, and the old +fox met him, and besought him with tears in his eyes to kill him, and +cut off his head and feet. And at last he did so, and in a moment the +fox was changed into a man, and turned out to be the brother of the +princess, who had been lost a great many many years. + diff --git a/wxPython/samples/wxPIA_book/Chapter-18/clipboard.py b/wxPython/samples/wxPIA_book/Chapter-18/clipboard.py new file mode 100644 index 0000000000..3ddf43cfd9 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-18/clipboard.py @@ -0,0 +1,77 @@ +import wx + +t1_text = """\ +The whole contents of this control +will be placed in the system's +clipboard when you click the copy +button below. +""" + +t2_text = """\ +If the clipboard contains a text +data object then it will be placed +in this control when you click +the paste button below. Try +copying to and pasting from +other applications too! +""" + +class MyFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, title="Clipboard", + size=(500,300)) + p = wx.Panel(self) + + # create the controls + self.t1 = wx.TextCtrl(p, -1, t1_text, + style=wx.TE_MULTILINE|wx.HSCROLL) + self.t2 = wx.TextCtrl(p, -1, t2_text, + style=wx.TE_MULTILINE|wx.HSCROLL) + copy = wx.Button(p, -1, "Copy") + paste = wx.Button(p, -1, "Paste") + + # setup the layout with sizers + fgs = wx.FlexGridSizer(2, 2, 5, 5) + fgs.AddGrowableRow(0) + fgs.AddGrowableCol(0) + fgs.AddGrowableCol(1) + fgs.Add(self.t1, 0, wx.EXPAND) + fgs.Add(self.t2, 0, wx.EXPAND) + fgs.Add(copy, 0, wx.EXPAND) + fgs.Add(paste, 0, wx.EXPAND) + border = wx.BoxSizer() + border.Add(fgs, 1, wx.EXPAND|wx.ALL, 5) + p.SetSizer(border) + + # Bind events + self.Bind(wx.EVT_BUTTON, self.OnDoCopy, copy) + self.Bind(wx.EVT_BUTTON, self.OnDoPaste, paste) + + def OnDoCopy(self, evt): + data = wx.TextDataObject() + data.SetText(self.t1.GetValue()) + if wx.TheClipboard.Open(): + wx.TheClipboard.SetData(data) + wx.TheClipboard.Close() + else: + wx.MessageBox("Unable to open the clipboard", "Error") + + def OnDoPaste(self, evt): + success = False + data = wx.TextDataObject() + if wx.TheClipboard.Open(): + success = wx.TheClipboard.GetData(data) + wx.TheClipboard.Close() + + if success: + self.t2.SetValue(data.GetText()) + else: + wx.MessageBox( + "There is no data in the clipboard in the required format", + "Error") + + +app = wx.PySimpleApp() +frm = MyFrame() +frm.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-18/customcomposite.py b/wxPython/samples/wxPIA_book/Chapter-18/customcomposite.py new file mode 100644 index 0000000000..c396322c5a --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-18/customcomposite.py @@ -0,0 +1,152 @@ +""" +This sample shows how to put multiple objects in the clipboard, one of +which uses a custom data format. In this case we use a Python +dictionary of values for our custom format, and we also put a textual +representation of the dictionary. To test this, run two instances of +this program, enter data in one and click the copy button. Then click +the paste button in the other instance. Also paste into a text editor +to see the data in the standard text format. +""" + + +import wx +import cPickle +import pprint + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "Copy/Paste Test") + panel = wx.Panel(self) + + # First create the controls + topLbl = wx.StaticText(panel, -1, "Account Information") + topLbl.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD)) + + nameLbl = wx.StaticText(panel, -1, "Name:") + self.name = wx.TextCtrl(panel, -1, ""); + + addrLbl = wx.StaticText(panel, -1, "Address:") + self.addr1 = wx.TextCtrl(panel, -1, ""); + self.addr2 = wx.TextCtrl(panel, -1, ""); + + cstLbl = wx.StaticText(panel, -1, "City, State, Zip:") + self.city = wx.TextCtrl(panel, -1, "", size=(150,-1)); + self.state = wx.TextCtrl(panel, -1, "", size=(50,-1)); + self.zip = wx.TextCtrl(panel, -1, "", size=(70,-1)); + + phoneLbl = wx.StaticText(panel, -1, "Phone:") + self.phone = wx.TextCtrl(panel, -1, ""); + + emailLbl = wx.StaticText(panel, -1, "Email:") + self.email = wx.TextCtrl(panel, -1, ""); + + copyBtn = wx.Button(panel, -1, "Copy") + pasteBtn = wx.Button(panel, -1, "Paste") + self.Bind(wx.EVT_BUTTON, self.OnCopy, copyBtn) + self.Bind(wx.EVT_BUTTON, self.OnPaste, pasteBtn) + + # Now do the layout. + + # mainSizer is the top-level one that manages everything + mainSizer = wx.BoxSizer(wx.VERTICAL) + mainSizer.Add(topLbl, 0, wx.ALL, 5) + mainSizer.Add(wx.StaticLine(panel), 0, + wx.EXPAND|wx.TOP|wx.BOTTOM, 5) + + # addrSizer is a grid that holds all of the address info + addrSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5) + addrSizer.AddGrowableCol(1) + addrSizer.Add(nameLbl, 0, + wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + addrSizer.Add(self.name, 0, wx.EXPAND) + addrSizer.Add(addrLbl, 0, + wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + addrSizer.Add(self.addr1, 0, wx.EXPAND) + addrSizer.Add((10,10)) # some empty space + addrSizer.Add(self.addr2, 0, wx.EXPAND) + + addrSizer.Add(cstLbl, 0, + wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + + # the city, state, zip fields are in a sub-sizer + cstSizer = wx.BoxSizer(wx.HORIZONTAL) + cstSizer.Add(self.city, 1) + cstSizer.Add(self.state, 0, wx.LEFT|wx.RIGHT, 5) + cstSizer.Add(self.zip) + addrSizer.Add(cstSizer, 0, wx.EXPAND) + + addrSizer.Add(phoneLbl, 0, + wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + addrSizer.Add(self.phone, 0, wx.EXPAND) + addrSizer.Add(emailLbl, 0, + wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + addrSizer.Add(self.email, 0, wx.EXPAND) + + # now add the addrSizer to the mainSizer + mainSizer.Add(addrSizer, 0, wx.EXPAND|wx.ALL, 10) + + # The buttons sizer will put them in a row with resizeable + # gaps between and on either side of the buttons + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + btnSizer.Add((20,20), 1) + btnSizer.Add(copyBtn) + btnSizer.Add((20,20), 1) + btnSizer.Add(pasteBtn) + btnSizer.Add((20,20), 1) + + mainSizer.Add(btnSizer, 0, wx.EXPAND|wx.BOTTOM, 10) + + panel.SetSizer(mainSizer) + + # Fit the frame to the needs of the sizer. The frame will + # automatically resize the panel as needed. Also prevent the + # frame from getting smaller than this size. + mainSizer.Fit(self) + self.SetMinSize(self.GetSize()) + + + fieldNames = ["name", "addr1", "addr2", + "city", "state", "zip", "phone", "email"] + + def OnCopy(self, evt): + # make a dictionary of values + fieldData = {} + for name in self.fieldNames: + tc = getattr(self, name) + fieldData[name] = tc.GetValue() + + # pickle it and put in a custom data object + cdo = wx.CustomDataObject("ContactDictFormat") + cdo.SetData(cPickle.dumps(fieldData)) + + # also make a text representaion + tdo = wx.TextDataObject(pprint.pformat(fieldData)) + + # and put them both in the clipboard + dataobj = wx.DataObjectComposite() + dataobj.Add(cdo) + dataobj.Add(tdo) + if wx.TheClipboard.Open(): + wx.TheClipboard.SetData(dataobj) + wx.TheClipboard.Close() + + + def OnPaste(self, evt): + # Get the custom format object and put it into + # the entry fields + cdo = wx.CustomDataObject("ContactDictFormat") + if wx.TheClipboard.Open(): + success = wx.TheClipboard.GetData(cdo) + wx.TheClipboard.Close() + if success: + data = cdo.GetData() + fieldData = cPickle.loads(data) + for name in self.fieldNames: + tc = getattr(self, name) + tc.SetValue(fieldData[name]) + + + +app = wx.PySimpleApp() +TestFrame().Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-18/drop_source.py b/wxPython/samples/wxPIA_book/Chapter-18/drop_source.py new file mode 100644 index 0000000000..d854947a69 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-18/drop_source.py @@ -0,0 +1,70 @@ +import wx + +class DragController(wx.Control): + """ + Just a little control to handle dragging the text from a text + control. We use a separate control so as to not interfere with + the native drag-select functionality of the native text control. + """ + def __init__(self, parent, source, size=(25,25)): + wx.Control.__init__(self, parent, -1, size=size, + style=wx.SIMPLE_BORDER) + self.source = source + self.SetMinSize(size) + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) + + def OnPaint(self, evt): + # draw a simple arrow + dc = wx.BufferedPaintDC(self) + dc.SetBackground(wx.Brush(self.GetBackgroundColour())) + dc.Clear() + w, h = dc.GetSize() + y = h/2 + dc.SetPen(wx.Pen("dark blue", 2)) + dc.DrawLine(w/8, y, w-w/8, y) + dc.DrawLine(w-w/8, y, w/2, h/4) + dc.DrawLine(w-w/8, y, w/2, 3*h/4) + + def OnLeftDown(self, evt): + text = self.source.GetValue() + data = wx.TextDataObject(text) + dropSource = wx.DropSource(self) + dropSource.SetData(data) + result = dropSource.DoDragDrop(wx.Drag_AllowMove) + + # if the user wants to move the data then we should delete it + # from the source + if result == wx.DragMove: + self.source.SetValue("") + +class MyFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, title="Drop Source") + p = wx.Panel(self) + + # create the controls + label1 = wx.StaticText(p, -1, "Put some text in this control:") + label2 = wx.StaticText(p, -1, + "Then drag from the neighboring bitmap and\n" + "drop in an application that accepts dropped\n" + "text, such as MS Word.") + text = wx.TextCtrl(p, -1, "Some text") + dragctl = DragController(p, text) + + # setup the layout with sizers + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(label1, 0, wx.ALL, 5) + hrow = wx.BoxSizer(wx.HORIZONTAL) + hrow.Add(text, 1, wx.RIGHT, 5) + hrow.Add(dragctl, 0) + sizer.Add(hrow, 0, wx.EXPAND|wx.ALL, 5) + sizer.Add(label2, 0, wx.ALL, 5) + p.SetSizer(sizer) + sizer.Fit(self) + + +app = wx.PySimpleApp() +frm = MyFrame() +frm.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-18/drop_target.py b/wxPython/samples/wxPIA_book/Chapter-18/drop_target.py new file mode 100644 index 0000000000..bec7653449 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-18/drop_target.py @@ -0,0 +1,40 @@ +import wx + +class MyFileDropTarget(wx.FileDropTarget): + def __init__(self, window): + wx.FileDropTarget.__init__(self) + self.window = window + + def OnDropFiles(self, x, y, filenames): + self.window.AppendText("\n%d file(s) dropped at (%d,%d):\n" % + (len(filenames), x, y)) + for file in filenames: + self.window.AppendText("\t%s\n" % file) + + +class MyFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, title="Drop Target", + size=(500,300)) + p = wx.Panel(self) + + # create the controls + label = wx.StaticText(p, -1, "Drop some files here:") + text = wx.TextCtrl(p, -1, "", + style=wx.TE_MULTILINE|wx.HSCROLL) + + # setup the layout with sizers + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(label, 0, wx.ALL, 5) + sizer.Add(text, 1, wx.EXPAND|wx.ALL, 5) + p.SetSizer(sizer) + + # make the text control be a drop target + dt = MyFileDropTarget(text) + text.SetDropTarget(dt) + + +app = wx.PySimpleApp() +frm = MyFrame() +frm.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-18/sound.py b/wxPython/samples/wxPIA_book/Chapter-18/sound.py new file mode 100644 index 0000000000..9242fc97ee --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-18/sound.py @@ -0,0 +1,38 @@ +import wx +from wx.lib.filebrowsebutton import FileBrowseButton + +class MyFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, title="wx.Sound", + size=(500,100)) + p = wx.Panel(self) + + # create the controls + self.fbb = FileBrowseButton(p, + labelText="Select WAV file:", + fileMask="*.wav") + btn = wx.Button(p, -1, "Play") + self.Bind(wx.EVT_BUTTON, self.OnPlaySound, btn) + + # setup the layout with sizers + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(self.fbb, 1, wx.ALIGN_CENTER_VERTICAL) + sizer.Add(btn, 0, wx.ALIGN_CENTER_VERTICAL) + border = wx.BoxSizer(wx.VERTICAL) + border.Add(sizer, 0, wx.EXPAND|wx.ALL, 15) + p.SetSizer(border) + + + def OnPlaySound(self, evt): + filename = self.fbb.GetValue() + self.sound = wx.Sound(filename) + if self.sound.IsOk(): + self.sound.Play(wx.SOUND_ASYNC) + else: + wx.MessageBox("Invalid sound file", "Error") + + +app = wx.PySimpleApp() +frm = MyFrame() +frm.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-18/sound1.wav b/wxPython/samples/wxPIA_book/Chapter-18/sound1.wav new file mode 100644 index 0000000000000000000000000000000000000000..c8bdd59f2e4fee0089bf731c5c29391e3c01422a GIT binary patch literal 6160 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

0bj zd6ytWkJ2SFs6~81EV&$X$%h&Wi;=VjHfp;f!Ge<0KpTFJ=I-*u>^opL&&(09^9t0R zMKY%8L`)h5*7VJ)ds>X1W$0oV%M(O)S_Ztv*UK7on7HxiE2KkiaXX5WIxT;liW3sB z7dSeDGSLjVi)txz7L$T*8pFsE6ob9OOhZ2%Dw2y8+|v6B1nefh_WmkiIKRO$8*R1} z1@lyVL5yx%p+*J)IM-C$HQsivwH>QP$7+FJ&2!gJ+|?)ij$LnzwbsX4gQM!;syeWG zYxx5VZkw~0rMB9vu*ZsXKK$DhTpAl$l|p)7X5;{iouk5fG;_x$K>CnbQ5Zps z)g>%PvX@NnsGvy6^af(&nh_%LG^5yKIu452SueOIg)gM>tatWelE=v?PxXvs?^xa7 zQ?LpfD^*FCD1ig0B$G>j-U_9xkM~XRYu>i#gAEo zm#@~1%7+iDtE+2kYac(Z + + + + + + + + wxALIGN_RIGHT + 1,1 + + 5 + 5 + + + 200,-1 + + wxEXPAND + 1,2 + + + + + + wxALIGN_RIGHT + 2,1 + + + + wxEXPAND + 2,2 + + + + + + wxALIGN_RIGHT + 3,1 + + + + wxEXPAND + 3,2 + + 2 + + + wxVERTICAL + + + + + wxEXPAND|wxALIGN_CENTRE_VERTICAL + + + wxEXPAND + 5,0 + 1,4 + + + + wxHORIZONTAL + + 10,10 + + + + + + 1 + + + + 10,10 + + + + + + + + + + 10,10 + + + + wxEXPAND + 6,0 + 1,4 + + + + diff --git a/wxPython/samples/wxPIA_book/README.txt b/wxPython/samples/wxPIA_book/README.txt new file mode 100644 index 0000000000..3b7799b608 --- /dev/null +++ b/wxPython/samples/wxPIA_book/README.txt @@ -0,0 +1,6 @@ +This directory contains the sample programs that were printed in the +wxPython In Action book. For details and explainations of each, +please see the coresponding chapter in the book. + +http://www.manning.com/affiliate/idevaffiliate.php?id=189_23 + -- 2.45.2

-\xdcS\x80R\xa2\x9a\xd4\xefv\x98\xb6S\xea\xa1\ +\xf5\xbfI2\x88\x8a\x93\x08\xf3\x90iU\x1a\xd2\x99W \xa1b\xe66\x0f\xd2\x8dL\ +\x80\xcb\xde\xa8;\xa4[x\x12\xbe{\x00\x16\xdd\t\x99\xfb\xe1\xc2\x0b\x1b\xb0dI\ +\xefb\xd2\xcd\xcbs3}\xfa~z\xf6\\\xc5\x9c9\xa9\x15"]e\xb1*\xf3U\x95\xed\xad\ +\xe81\x0f\x1d*\xe2\xaa\xab\xb6p\xe3\x8d\xdb\xc8\xcar\x11\x1fo\xe1\xde{\x9b\ +\xb3`AO\xec\x9b\xa2y\xed,\xd8\xfa>\x94*\x9a\x1adp\x16A\xf6!?\x1f\xd8\x91\xac\ +8\x85\x7f\x15\xb4S\xc1\t?\xdb\xf2\xa8P\xddAw!|\xfaG\x98|cs\x86\x0eM\xe4\xc9\ +\'\x0f\x96"\xdd\xdaFm\x07]U\n\xcabU\xfe\xac\x8c\x83\x07\x8b\xb8\xe5\x96\x1d|\ +\xf0A7/\xab\xe1\xfe\xfb[\xf2\xe5\x88\x13\xacz\xa9\x80A\xf7\x10T\xc4\xa4\x94(\ +z\xb5\xbbX^\xa3s 7\x15R\xd7\xc8j\xf1\t\xa3\x8a\x84=\x1b\xd2\x02)h\xf5\x87Q3\ +\x0c?W\x10]\xdb)A\xc3\xd1\xb5\xb0\xe0fQ\xe3\x8a\x8cT\xdcs_K\x9ex\xa2M\xb1ka\ +\xdd\xba<\xa6N\xdd\xc9\xf2\xe5\xa5\xb3\x8e\xfc\xa1\xa6,\x1a\xcf\xf3\x04\xb2\ +\x82\xddnx\xef\xbdc\xacY\x93\xc3\xacY\x9d\x191"\x91\x0b/\xac\xcf\xaaU\xfd\ +\xb9\xf4\xd2\xcd|\xf2\xc7,\x8em\x11\xbd\x01\x82\xd4\xf5`\xcf\x81\xbc\xe3\xc6\ +\x9b\x86\x94\xf8_#\x90\x99\x99\x85\xd2V\xea\xa9\xc2\xdf\xf5\x17"\xba\xc4\x06\ +l~\xca\x18i\r[?\x06\xc7\xde\x08\xfe\xf1Ekv\xee,\xe0\xa3\x8fJO+k[o"\xa4\x88\ +\x17\x02\x93\xef\x82\x05\'x\xe9\xa5\xc3L\x9b\xd6\xac8\x1f?%\xc5\xc6\x92%\xbd\ +\x19B\xeeZC\xd6n\ +\xf8\xfa\x1e\x98~\x7fK\xa2\xa3-L\x9a\xb4\xb58\x0b\xb1\xe4\xbb\xb5\xaf\xb0V\'\ +\\\r \xab\xc6O?}\x80\x8c\x8c\x92\x9b\xac\x94\xa2e\xcbH\x9ey\xb2\x03\x0bnV\ +\x14\xf9\x9b\xbe\x04#<\xbb\x85\xc5\xc80\xf2\xf7\n\xf1\xd29ZK\xb5\xd7%\xf7\ +\xc0W\xd3\xa0\xe0\x04\\}u#6o\x1e\xc8\xd5W\x0b\xe9\x1e>l\xe7\xce;wr\xcf=\xbb\ +\xca%\xdd\xeap\'\x9c\x0e\x02\xb5\xa7\xa8H\xf3\xef\x7f\x1f\xa0\x7f\xff5\xec\ +\xdcYH|\xbc\x85\x17^h\xcf=w\xb7\xe0\xd0r\xc5\xcb=a\xc3\xeb\xf2@\n&D$@\x9cY_\ +\xcf\xacpa\xa2*\xb2E]H\xb8\x98\x05\x89\xf2\xf1\x84\x9b\x92\x08\t\xa0^+h\xda\ +\xcfg\x97"\xf8\xe6~\x18\xda\xb7\x01\xf7\xdc\xd3\x82\xaf\xbeJg\xed\xdaS\xc9\ +\xa9\xae~\x84$\xf1\x06\x1a\\iiv\xe6\xcc))\x11\x04B\xbe\xd7]\x97\xc2\xdd7\xb4\ +e\xd1\xed\xd2\x99\x83\xd9\x8fv&@kI;M\xdf"U\x16~{\x05\xfa\xf5\x8bg\xf1\xe2^\ +\xcc\x9b\xd7\x85&M$\x15\xfc\xd7_s\x18:t\x1d\xef\xbcS\xb6H@\xb0\x11\xae/\xfc\ +\xb5Mk\xd8\xb81\x8f\x8b.\xda\xc8\xa2E\x19X,\xf0\xec\xb3\xedX\xb4\xa8\'\xcd\ +\x93\xa3Yp\x0b\xfc4C\\M\xc1\xd2_\xadQ\xd0\xe1\x02\xe3\xcdJ\xbc\r\x84\x9e\x88\ +\x15\xbc\xf7\x14\x0f\xae\x91\xea\xd3\xab\x90\xd8\xddd\x9f\xcfR\x91P3\x03C\ +\xa6\x81%\xc6c\x17\r+_\x82\xb4\x1fl\xcc\x9c\xd9\x91\xdd\xbb\x0b\xb8\xff~\x8f\ +/\x18\x08\x96~\x12\x92\xc4\x0b\x81o\xe0\x0b/\x1cd\xd3\xa6\xfcR\xe4{\xef\xbd-\ +\xe8\x15\xd1\x88\xef\xfe\x86L\xdf\x83\xa43\x9fI0\xb3\xf92\xb6\xc3;\xe7I\x8c\ +\xe5\xde\xa50zt\x03\x96,\xe9\xc5\xf9\xe7\xd7\xc7j\x15\x7f\xe8\xcb/\xa7r\xd9e\ +[8x\xb0\xa8\xccc\x06\xcb@*\x0f\x81\x1e\x0e{\xf6\x142a\xc2&\x1e\x7f\xfc\x00.\ +\x17\\pA}V\xae\xec\xc7\x9dw4g\xc5\xd3\x8ayc }+\xb5\x96\x9e\xeb\t\r\xb4=\xd7x\ +\xb3\x1dY\xf85\xdb\x15\x85h\x92\xa4R\xf9\xb6j`\x130\xd5\xf8\xbb\x0b\xde\xe9\ +\xf0\xb9\x14k\x90\x00$\xb6\x84\xbe\x7f\xf2\xce\xce\xcb;\x04\xcb\x9f\x83;\xef\ +lN\xb3f\x91\\s\xcd\xd6b\xd1\xa3`D\xc8\x12/\xf8\x1ftG\x8f:\xb8\xe8\xa2\x8d\ +\x1c\x00G\x8e8\xb8\xfc\xf2-\xfc\xfa[6\xdd\'\ +\xc2\xf8\xd7E\x87\xa4\xb6\x16V]E\xf0\xc5M\xb0\xf1}Dk\xfa\x06J\xc7\xef\xba\ +\x90*\xc6?"\x84\xda\x1b\xc9\xc8\xf4\xc5\x02\x84X\x1b\x03\x93(\x89f\xc8B\xe4R\ +w\x95\xec\xda\xb8\'\\\xbf\x18b\x9b\xca\xb5k\r\x8e,\x11\xc19\x7fP2\x1f}\xd4\ +\x9d\xc7\x1e\xdb\xcf\x8c\x19\xfbJ\x9d&\xd8\xfaN\x9d&^\x80\x9bnj\xc2\x9c9\x9d\ +\xb0\xd9\xbc\xe5\x02\xd7\xad\xcbc\xec\xd8\x8d\xf4\xbc\xdb\xc1\xd0\xbfRf\xad\ +\xa60N\rZC\xea\n\xf8\xe4z\xc80\x16]\x9a7\x8f\xe4\xbb\xef\xfa\xd0\xa9S\x89\ +\x8a\xd7\xe6\xcd\xf9L\x98\xb0\xb9\xb8\xa6\x99?\x04\xdb\xc0\xa9J\xf8\xeb\xbfq\ +q\x16\x1ey\xa4\rw\xdf\xdd\x9c\xc8HEa\xa1\xe6\xd6[w\xf0\xce;Gi9\x04.\x7f\xb7b\ +\x95\x17\xaa\x0b\xb9\x86fC\xfeI\x84|/F\x8alZ\xf1\xf6\xcfn\x03\xbeB\xfc\xb4\ +\x81\xd0\xd5\xf8\xbeI\xba\xb9\xc0\x9bH\xe5\x0c\x03\x8d{\xc2\xa4\xaf!\xaeY\ +\xc95\xbb\xed0\xef"\xb0\x1d\x8ca\xd9\xb2\xbel\xd8\x90\xcb\xf8\xf1\x9bJ\xd5R\ +\x0b\xc6\xbeS\'\x88\x17\xca&\xdf;\xefl\xce\xf3\xcf\xb7\xc7j\xc5+\xad\xf8\xdb\ +o3\xb9\xe4\xd2M\xf4\xfe\xa3\xe6\xc2\x17\xa8\xb00t\x18\xe5C\xbb`\xe3\xdb\xf0\ +\xe5]\xe00R^\x9fd\x91\ +\xa8z0a\x16t\xbe\xdc[\xbdMk\xd8\xbb\x18\xde\xbb\x14.87\x89\x0f?\xec&Y\x7f\ +\xaf\x1c\xc6\x17\xc1\xdc\x8f\xea\x1c\xf1B\xd9\xe4\xfb\xc4\x13my\xf0\xc1\x96\ +\xa5J\xc4l\xdf^\xc8\x95Wn\xe1\xa8;\x8f\x91\x0fA\xb7k\x8c\xcc\xdd\xa0\xfd\xe9\ +\x82\x07f\x95\xdfU/\x8bn\xae#\x0f\x12\x12\xac\xdc\x7f\x7f+\xee\xbb\xaf\x05\ +\x91\x91\xaax\xbf\xa7\x9e:\xc8\xf4\xe9\xfb\xfc\x16\x1b\x84\xe0\x1e,5\t\xff\ +\x8bn\x16\x1e{\xac-w\xdf\xdd\x1c\x90\x0c\xb8\x9bo\xde\xceG\x9f\x1f\xe3\xaa\ +\xf7\xa0\xc3%\x1eBK5\r\r\xc77\xc2\xd2\xc7a\xebge\xa4\xb9W\x00\xcd\x07\xc2\ +\x95\xefC\xa2\x8f\x0f[k\x91U}\xe7"\xe8\xd0*\x96E\x8bz\xf2\xdcs\x87B\x8et\x01\ +\xac\xaa\xd6~\xa9\xea\x83R\x96\x19h=\xdd\xdfg\xcb\x96e\xd1\xb6m,={\xc6\x16\ +\x93\xafR\x8a\x86\rm\x9cuV=\xfe\xfb\xe6IV\xbd\xe7\xc2]\x08\xcd\xfaW}\x99\xee\ +\xba\x06\xad\xe1\xe4fY\xe4\xd8\xf0.\xb8\xecR\x89\xe1\x8b/z2iRc\xa3*\xaf\xc2\ +\xe9\x84\xa7\x9f>\xc8#\x8f\xec\xc5\xe9\xf4\x7f\xac`\x1f,5\t\x7f}\xd8n\xd7|\ +\xf3M\x06QQV\x06\x0eL :\xda\xc2\xd8\xb1\r\xc9\xcbv\xf3\xceC9D\xc4@\xf3A\xb5D\ +\xbe\n\xe2\x9a@\xf7+\xa0\xddy\x90\xd4V\xb6\xc57\x82\x888\x11\xd8)\xabH\xa6-\ +\x06:]\x04c_\x81\x913 :\xb94\xe9\x9e\xd8\x04\x1f]\x03\x11v+K\x97\xf6\xe5\xeb\ +\xaf\xd3C"\x82\xc1\x1f\xea\xa4\xc5k"\x90\xe5\x1b\x19\xa9x\xe1\x85\x8eL\x9e\ +\xdc\x04\x9b\xcd\xdb\xedp\xe4\x88\x83?\xfeq\x1bK\x96d\xd0z\xb8T\x89M\xe9\x1d\ +&__\x98E\x16\x7f{\x01~z\n\x8a\xb2\xc0b\x81\xa9S[\xf0\x97\xbf\xb4(\xae\xf6\ +\xab\xb5f\xcf\x9e"\xee\xbak\'\x8b\x17\xa7\xfb\x8d\x9b\x0e\x85\x81R[\x08\xd4\ +\x87\xaf\xb9\xa6\x11s\xe7v&:Zn\xdd\xf7\xdfgq\xf3\x9f\xb6\xd1xL\x11\x17>\x07\ +\xd6\x98\xda\xed\xb3Z\x1bI\x02J\x1e\xc6Y\xfb s\xaf\xc8Jf\xfa\x88\xe94\xeb\ +\x0b-\x86BL\xb2\xff\xe8"\xd3\x97\xfc\xe6\xb9\xa03\xac|\xf2I\x0f\xb2\xb3]\xfc\ +\xe1\x0f[J\xcd\x9cB\xa5/\xd5i\xe2\x85\xb2\xdd\x0ew\xdd\xd5\x9c\xe7\x9e+\xed\ +\xf3u8`\xea\xd4\x9d\xbc\xf5\xd6\x11\x9ch\x86\xde\x03\xc3\xee\x87\xc8z\x9c\ +\xf1\xbe_sE\xf9\xd02\xf8\xe6\x018\xb0B\xb6\'&Z\x99>\xbd-\xd3\xa65+\xf6\xe5:\ +\x1c\xf0\xca+\x87y\xfc\xf1\xfddd\xf87sCe\xa0\xd46\xfc\xf5\xe3\xb3\xcf\xae\ +\xc7\xb3\xcf\xb6c\xf0\xe0\x04\x00\x0e\x1c\xb03\xe9\xfa\xadd7\xcbb\xdck\x92\ +\xdd\x15\xf2\x06\x83\x86\xcc=\xf0\xc5d\xd8\xff\x13\xcc\x9a\xd5\x89\xf3\xcek\ +\xc0\xd9g\xaf\xe5\xc8\x91\xd2*B\xa1\xd2\x9f\xea<\xf1B\xf9\xe4\xfb\xe4\x93\ +\xed\x88\x89Q^\xe4\xebv\xc3\xaaU9\xdcx\xe36v\xec( \xa9\x83T\x89\xed8\x0e,g\ +\xa8\xfbAk\xc8;\x0c\xbf\xbe\x00+^\x90\xa9\xa3\xc5"\x04\xf0\xf2\xcb\x1d\xe9\ +\xd9\xd3\\E\x81\xb5k\xf3\x986m\'+Vd\x07\xcc\x0e\x0c\x95A\x12,\xf0\xd7\x8fM\ +\xb7\xce\xd9g\x0b\xf9\xba\\\xf0\xec\xb3\x07\xf9\xef\xe6\xbd\\\xfcjh\x93\xaf\ +\xd6\xb0\xff[\x115\xcfI\x85\'\x9fl\xc7\xb4i\xcd\xb9\xf0\xc2\x8d\xfc\xfcs\xe8\ +D0\xf8\xc3\x19A\xbcP6\xf9\x9esN=>\xff\xbc\'\xf5\xeaYJ-\xba\x1d;\xe6\xe0\xce;\ +w\xf1\xf1\xc7\xc7QVh\xd4\x1d\xce\xff\'\xb4\xbb\x00T5\x96\xe9\x0e&\x04*W\xd4\ +\xaaU\x14\xcf=WR\xd2\x06\xa4B\xc4\x8b/\x1ef\xfa\xf4}\x01\xabC\x84\xd2\x00\tF\ +\xf8\xf6\xe5\xa4$\x1b\x8f>\xda\x86\xdboo\x86\xcd&\xf1\xd1O?s\x909\x0b\xf6q\ +\xd5\x02MtJ\x08\xf6S\r\xe9\xdb$N8}\x0f\\ye\no\xbe\xd9\x85{\xee\xd9\xc5k\xaf\ +\x05\x7fJpy8c\x88\x17\xca&\xdf\x8e\x1dcx\xff\xfdn\xf4\xeb\x17W\x8a|\x1d\x0eI\ +\xb6\x98\xf8\xe0\x18\ +o\xbf}\x84c\xc7\x1c(\x0b4\xe9\r].\x81\xde\xd7K\x0e}(\xc6\x00k\r\xda\x0e\xfb\ +\xbe\x87\xe5\xcf\xc2\x9e\xefe{\xf3\xe6QL\x98\xd0\x90)S\x9a\xd2\xa3G\\\xb1[\ +\xe1\xe4I\'O\xbc>S\ +\xa64e\xec\xd8\x86\xc4\xc5\x954\xb6\xb0P\xf3\xfe\xfb\xc7x\xea\xa9\x03\xec\ +\xd8QP\xc6\xc1C\x7f`\x84\x1a\x02\xf5\xe3A\x83\x12x\xe4\x916\x8c\x1d\xdb\x80\ +\xbd{\x8b\x183f#\x873\n\x18\xfd\x0c\xf4\xbc\xa1\x163\xdd(\x89\x92Y\xf6$\xac\ +\x9c%Q2\xf1\xf1V\xfe\xf3\x9f\x0e\xec\xdbW\xc8\xcc\x99\x07\xfd\xce\xa4\xeaB\ +\xdf:\xe3\x89\x17\xca&_\x90\'\xf0\xf9\xe77\xe0\x81\x07Z1lX=\xaf\xa4\x8b\xe2c\ +\x18!h\xbbv\x15\xf2\xe5\x97\xe9|\xf4\xd1Q\xd6\xaf\xcf\x93\x02\x8d\n\xa2\xeb\ +\x89r\x7f\xeba\xd0\xf9\x12\xb1\x86#\xe2\xc0\x12I\x8d\x10\xb1i\xd9\xba\xed\ +\x12\x17\xb9q\x1e\xec\\\x0cG7C\x84E\xd1\xaf_\x02\xc3\x86\xd5\xe3\xfa\xeb\x9b\ +\xd0\xad[,J\xe9b\x0b77\xd7\xcd\xfc\xf9\xc7x\xfe\xf9\x83\xec\xdcYP\xaex|]\x18\ +\x18\xa1\n\x7f}9"Bq\xef\xbd-\xb9\xef\xbe\x16de\xb9\x183f#\xbbv\x170\xf4\x1e\ +\x18\xf1\x88h\xfb\xd6\xb41\xa05\xa4\xfd\n\x0b\xfe\x0c\xc76\xcb\xb6\x0b.h\xc0\ +\xfd\xf7\xb7\xe6\xc5\x17\x0f\xb2pai\xd7\x02\xd4\x9d\xbe\x15&^\x03\xe5\x91/\ +\x885\xd8\xbf\x7f\x02O=\xd5\x8e\x81\x03\x13\x88\x8aR\xa5\x08\x18\x84\x84].)C\ +\xb4xq:\xf3\xe6\x1de\xd5\xaal/Q\x98\xc8\x04\x88o\x0c-\x07C\x83\xb6\xd0l \xb4\ +\x1e\x01\xd6\x08\xb0\xc5\x1a\xc7\x81S\x1e\x10\x9eD\x9b\xb5\x0f\x0e\xae\x80\ +\xbd?\xc0\xc1_%s(&\xc2\xc2\xa0A\xf58\xe7\x9cz\xdcpC\x13Z\xb5\x8a\xf4\xb0\xe8\ +5ZCf\xa6\x8b\xcf>;\xc1\xb3\xcf\x1ed\xeb\xd6\xfcr\xcfYW\x06E(\xa3\xac~|\xd6Y\ +\x89<\xf4P+\xbav\x8d\xe3\x96[v\xf0\xddw\x19\xc45\x82K_\x87\x0e\xe3jf]\xc2\\\ +\xb8\xdd\xf2>|9\r\n3d\r\xe1\xbe\xfbZR\xaf\x9e\x8d\x87\x1f\xdeCjj\xdd\x97\x08\ +\r\x13\xaf\x07*B\xbe \x9d\xb3M\x9bh\x9ex\xa2-\xa3G\'\x19\xf5\xc2t@\x12\xd6\ +\x1a\x8e\x1ds\xf0\xd1G\xc7Y\xba4\x8bM\x9br\xd9\xb7\xaf\x10\x87\xc3\xfbt\xd6H\ +\x88I\x82\x06\xed\xe4}J\x17\x88K\x86\x96C\xc1b\x93\x92\xd6\xf1\xcd\x02\xb7\ +\xab(\x0bNl\x85\xfc\xe3pl\x0b\x9c\xdc%\xff\xa6\xef\x81\xa8\x08E\xbf~\x89\xf4\ +\xe9\x13G\x9f>\xf1\x8c\x19\x93D\x8b\x16Qf+\x8b\xad[\xad\x15\xfb\xf7\x172s\ +\xe6a\xdex#\x8d\xac\xac2\x12\xec=\xefI\x1d\x1a\x14u\x01eE\xee\\\x7f}\x13\x1e\ +~\xb85S\xa7\xee\x14\xcb\xd2\x02\xed\xcf\x83s\x1e\x86\xe6g\x01\xd5\xa0K\xad5\ +\xe0\x84\xdf?\x84eFhb\x84M1aB2\xe3\xc6%\xf3\xfe\xfbG\xf9\xe6\x9b\xf43F"4L\ +\xbc~PQ\x02\x06\x88\x89\xb10th=.\xbb,\x99+\xaeH\xa1Q#)\xda\x18\x88\x84A\xe1t\ +j\x0e\x1c(b\xf3\xe6<\xd6\xac\xc9a\xcb\x96<\xd6\xaf\xcf%\'\xc7Ez\xba\x03W\x00\ +\xaeSV\x08\xf8s)\xc0\r\tq6l6\xc5\x80\x01\t\xf4\xea\x15G\xa3F\x91\xf4\xec\x19\ +G\xd7\xae\xb14k\x16\x89\xc5\xf0\xe9yf\xe9\x81X\xb7_}\x95\xcek\xaf\xa5\xf1\ +\xcb/Y\x01\xd5\xc3J\x9d\xb6\x8e\r\x88\xba\x86@}9%%\x82\xc7\x1fo\xc7\xde\xbd\ +\x85<\xf7\xdc\x01\x1c\x0e\x8d\xb2BJW8\xe7A\xe8\xdeJ\xaf^R7\xa5m\xdb\x18bb,X,r\xdc\xb2\x1e\ +\x00\xb9\xb9.V\xaf\xce\xe1\xbd\xf7\x8e\xf1\xd1G\xc7*l\xddB\xdd\x1c\x0cu\x15e\ +\xf5\xe3n\xddb\x998\xb11\xef\xbf\x7f\x84]\xbbJ\x16L\x13\x9aC\xd7\xf1\xd0\xe3\ +\x0f\xd0\xb4?\xd8\xe2\xca\'a\xd3\xbd\x85\x1brSa\xefR\xf8\xf5EH]\x8b\x99INT\ +\x94\xe2\xd2KS\x88\x8f\xb7\xf1\xfe\xfbG\xc8\xcf?3\xc3\x10\xc3\xc4[\x0e*K\xbe\ +&,\x16\xa9\x1c0~|2\x13&4\xa4A\x03\x1b-ZDa\xb1\xa8Z\xaa\x16 \x97\x91\x9e\xeed\ +\xed\xda<\x16-:\xc1\xa2E\'\xd9\xb3\'p\x9d3\x7f\xa8\xcb\x83\xa1.\xa3\xac~\x1c\ +\x13ca\xf0\xe0D\x92\x93#\xf8\xf6\xdb\x0c23\xbd\x1f\xf6\x89-\xa0\xeb\x04h\xd6\ +\x0f\xea\xb7\x83\xc4V\x12\xb1\x13\x97,\x9fg\x1f\x06\xb7\x0b\xb2\x0f\x88e\xbb\ +\xffg\xb1l\x9d\x1e\x81/\xf1\xf1\x16:t\x88!3\xd3\xc9\xf1\xe3\x8e\x80"\xf8&\ +\xeaz?\x0b\x13o\x05q\xaa\x04\x0cB\xc2V\xab\xa2W\xafx&LhH\x93&\x91\x0c\x1c\ +\x98HB\x82\x95V\xad\xa2\x0c\xab\xb8l\xcb\xb8Rm5H\xd6\xe5\x82\x8c\x0c\'\x1b6\ +\xe4\xb2aC\x1eK\x97f\xb2lY\x16YY\xceJ\x97\xb5\xaf\xeb\x03\xe1LAY\xfd8!\xc1\ +\xca\x88\x11\xf5IM-b\xf7\xee\x02\xb2\xb3\xfd\xcc\x80\x8c\xe4\x8b\x88X\x88m(\ +\x9b\xb2S%\x14Lk\xf0,\xe3\x1e\x15\xa5\x185\xaa\x01n\xb7f\xe7\xce|\xf6\xed+\ +\xaaP\xbf;\x13\xfaZ\x98x+\x81\xd3!_\x7f\x88\x8cT4n\x1cI\xd7\xae\xb1\x8c\x18Q\ +\x9f\x86\r#\x182$\x11\xad\xe5\xb3\xf6\xedc\xd0Zc\xb1(\xfe\xbf\x9d\xbbWM\x18\ +\x8c\xc28\xfe\x18\x89\xa6Z\x89kwQ\x10\x15\x17\xaf\xc7\xdb\x14\\3(^\x80 \xf8\ +\xb5k\xd1P\x8d%\x89\xe9\x10\n\xd6Z\x13\xbfj\xce{\xce\x7f\x16\xcc\xf0\xf3\xe1\ +%\t\xea\xfa\xef\x93r\x10\x00\x9e\x17\xc0\xf7\x038\xce\x1e\xf3\xf9\'f3\x07\ +\xe3\xf1\x0e\xbd\x9e\x8d\xc9\xc4\xc1t\xba\xfb\xf3/\x19\xa3\xe2\xf0\x03\xe0X\ +\x1c\xc7\x95\xca\x0b\x0cC\x83\xe3\xec\xb1X\xb8\xb1nye\xb3)\x94J94\x9b\x05T\ +\xab9x\x1e`Y+t\xbb\xef\xb1\xaf\x8d\x8b9\x19\xde+\xba\xf7\x00\x1f\xf6=\xae\ +\xe9t\n\xc5b\xf8\xa0\xce4\xd3\xa8\xd7_O~~8\xdcb\xb9t\xe1\xba{\xd8\xb6\x7f\ +\xf1I\xf6\xc7w3A/\xc57\\.\xe7\xd0h\xe4aY+\xd4jy\xac\xd7\x1e\x06\x83\x0f\xe8z\ +\n\xed\xf6\x1b\x0cC\x83ah\xc8d4\xb4Z\x05\x8cF[t:K\xf4\xfb\xf6\xd9\xfb\xb7\ +\xc7q\xb3\'\xc3{\xd0#\x075\xe9q\x83\xcf\xbd[\xadk\x1a`\x9a\xe1\xc1`\xb3\xf1c\ +\xbf\x05\x13\x15\x17\x87\xac\x87\x97\xf3\xd0\x1e\xc7\x05<\xd7([W\xd1&\xbb\ +\xe1\xa5\x0c\xf0?S\x11;\xa7TwN\xdd\xa7\x0c\xaftU\xd4\xe1\xab\x94\x98\x0e\xa3\ +d\x92\xdd\xf0\x02\x02\xf5\x91Q\xc2O=q|\xbe$[d9\xbc\xe7\x12\xcc\xb7\x95d\xec\ +\x9c\xe2\xee8\xe9\x0eex/\x88;\xe6\xa8\x92\x8e]\nS\xd91\x15\x832\xbcwLU\xd0T0\ +K\xf7\x8d\x82g\xaa6ex\x9f\xdc3pS\xc5*\xd1\xe9V\xd7\xaa\x1b\xfd\x028\xc0\xaeS\ +5\x9dLZ\x00\x00\x00\x00IEND\xaeB`\x82' + +def getVippiBitmap(): + return BitmapFromImage(getVippiImage()) + +def getVippiImage(): + stream = cStringIO.StringIO(getVippiData()) + return ImageFromStream(stream) + diff --git a/wxPython/samples/wxPIA_book/Chapter-08/mdi.py b/wxPython/samples/wxPIA_book/Chapter-08/mdi.py new file mode 100644 index 0000000000..5d15900313 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-08/mdi.py @@ -0,0 +1,29 @@ +import wx + +class MDIFrame(wx.MDIParentFrame): + def __init__(self): + wx.MDIParentFrame.__init__(self, None, -1, "MDI Parent", + size=(600,400)) + menu = wx.Menu() + menu.Append(5000, "&New Window") + menu.Append(5001, "E&xit") + menubar = wx.MenuBar() + menubar.Append(menu, "&File") + self.SetMenuBar(menubar) + self.Bind(wx.EVT_MENU, self.OnNewWindow, id=5000) + self.Bind(wx.EVT_MENU, self.OnExit, id=5001) + + def OnExit(self, evt): + self.Close(True) + + def OnNewWindow(self, evt): + win = wx.MDIChildFrame(self, -1, "Child Window") + win.Show(True) + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = MDIFrame() + frame.Show() + app.MainLoop() + + diff --git a/wxPython/samples/wxPIA_book/Chapter-08/miniframe.py b/wxPython/samples/wxPIA_book/Chapter-08/miniframe.py new file mode 100644 index 0000000000..91080f452c --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-08/miniframe.py @@ -0,0 +1,21 @@ +import wx + +class MiniFrame(wx.MiniFrame): + def __init__(self): + wx.MiniFrame.__init__(self, None, -1, 'Mini Frame', + size=(300, 100)) + panel = wx.Panel(self, -1, size=(300, 100)) + button = wx.Button(panel, -1, "Close Me", pos=(15, 15)) + self.Bind(wx.EVT_BUTTON, self.OnCloseMe, button) + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + + def OnCloseMe(self, event): + self.Close(True) + + def OnCloseWindow(self, event): + self.Destroy() + +if __name__ == '__main__': + app = wx.PySimpleApp() + MiniFrame().Show() + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-08/scroll_window.py b/wxPython/samples/wxPIA_book/Chapter-08/scroll_window.py new file mode 100644 index 0000000000..2ea57a77bf --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-08/scroll_window.py @@ -0,0 +1,26 @@ +import wx + +class ScrollbarFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, 'Scrollbar Example', + size=(300, 200)) + self.scroll = wx.ScrolledWindow(self, -1) + self.scroll.SetScrollbars(1, 1, 600, 400) + self.button = wx.Button(self.scroll, -1, "Scroll Me", pos=(50, 20)) + self.Bind(wx.EVT_BUTTON, self.OnClickTop, self.button) + self.button2 = wx.Button(self.scroll, -1, "Scroll Back", pos=(500, 350)) + self.Bind(wx.EVT_BUTTON, self.OnClickBottom, self.button2) + + def OnClickTop(self, event): + self.scroll.Scroll(600, 400) + + def OnClickBottom(self, event): + self.scroll.Scroll(1, 1) + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = ScrollbarFrame() + frame.Show() + app.MainLoop() + + diff --git a/wxPython/samples/wxPIA_book/Chapter-08/shaped_frame.py b/wxPython/samples/wxPIA_book/Chapter-08/shaped_frame.py new file mode 100644 index 0000000000..513ab464a9 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-08/shaped_frame.py @@ -0,0 +1,43 @@ +import wx +import images + +class ShapedFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "Shaped Window", + style = wx.FRAME_SHAPED | wx.SIMPLE_BORDER | + wx.FRAME_NO_TASKBAR) + self.hasShape = False + self.bmp = images.getVippiBitmap() + self.SetClientSize((self.bmp.GetWidth(), self.bmp.GetHeight())) + dc = wx.ClientDC(self) + dc.DrawBitmap(self.bmp, 0,0, True) + self.SetWindowShape() + self.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) + self.Bind(wx.EVT_RIGHT_UP, self.OnExit) + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_WINDOW_CREATE, self.SetWindowShape) + + def SetWindowShape(self, evt=None): + r = wx.RegionFromBitmap(self.bmp) + self.hasShape = self.SetShape(r) + + def OnDoubleClick(self, evt): + if self.hasShape: + self.SetShape(wx.Region()) + self.hasShape = False + else: + self.SetWindowShape() + + def OnPaint(self, evt): + dc = wx.PaintDC(self) + dc.DrawBitmap(self.bmp, 0,0, True) + + def OnExit(self, evt): + self.Close() + +if __name__ == '__main__': + app = wx.PySimpleApp() + ShapedFrame().Show() + app.MainLoop() + + diff --git a/wxPython/samples/wxPIA_book/Chapter-08/shaped_frame_mobile.py b/wxPython/samples/wxPIA_book/Chapter-08/shaped_frame_mobile.py new file mode 100644 index 0000000000..9e592ed460 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-08/shaped_frame_mobile.py @@ -0,0 +1,64 @@ +import wx +import images + +class ShapedFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "Shaped Window", + style = wx.FRAME_SHAPED | wx.SIMPLE_BORDER ) + self.hasShape = False + self.delta = wx.Point(0,0) + self.bmp = images.getVippiBitmap() + self.SetClientSize((self.bmp.GetWidth(), self.bmp.GetHeight())) + dc = wx.ClientDC(self) + dc.DrawBitmap(self.bmp, 0,0, True) + self.SetWindowShape() + self.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) + self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) + self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) + self.Bind(wx.EVT_MOTION, self.OnMouseMove) + self.Bind(wx.EVT_RIGHT_UP, self.OnExit) + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_WINDOW_CREATE, self.SetWindowShape) + + def SetWindowShape(self, evt=None): + r = wx.RegionFromBitmap(self.bmp) + self.hasShape = self.SetShape(r) + + def OnDoubleClick(self, evt): + if self.hasShape: + self.SetShape(wx.Region()) + self.hasShape = False + else: + self.SetWindowShape() + + def OnPaint(self, evt): + dc = wx.PaintDC(self) + dc.DrawBitmap(self.bmp, 0,0, True) + + def OnExit(self, evt): + self.Close() + + def OnLeftDown(self, evt): + self.CaptureMouse() + pos = self.ClientToScreen(evt.GetPosition()) + origin = self.GetPosition() + self.delta = wx.Point(pos.x - origin.x, pos.y - origin.y) + + def OnMouseMove(self, evt): + if evt.Dragging() and evt.LeftIsDown(): + pos = self.ClientToScreen(evt.GetPosition()) + newPos = (pos.x - self.delta.x, pos.y - self.delta.y) + self.Move(newPos) + + def OnLeftUp(self, evt): + if self.HasCapture(): + self.ReleaseMouse() + + + +if __name__ == '__main__': + app = wx.PySimpleApp() + ShapedFrame().Show() + app.MainLoop() + + diff --git a/wxPython/samples/wxPIA_book/Chapter-08/simple_frame.py b/wxPython/samples/wxPIA_book/Chapter-08/simple_frame.py new file mode 100644 index 0000000000..acea15b7ec --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-08/simple_frame.py @@ -0,0 +1,8 @@ +import wx + +if __name__ == '__main__': + app = wx.PySimpleApp() + frame = wx.Frame(None, -1, "A Frame", style=wx.DEFAULT_FRAME_STYLE, + size=(200, 100)) + frame.Show() + app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-08/splitter.py b/wxPython/samples/wxPIA_book/Chapter-08/splitter.py new file mode 100644 index 0000000000..8699db640e --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-08/splitter.py @@ -0,0 +1,101 @@ +import wx + +class SplitterExampleFrame(wx.Frame): + def __init__(self, parent, title): + wx.Frame.__init__(self, parent, title=title) + self.MakeMenuBar() + self.minpane = 0 + self.initpos = 0 + self.sp = wx.SplitterWindow(self) + self.p1 = wx.Panel(self.sp, style=wx.SUNKEN_BORDER) + self.p2 = wx.Panel(self.sp, style=wx.SUNKEN_BORDER) + self.p1.SetBackgroundColour("pink") + self.p2.SetBackgroundColour("sky blue") + self.p1.Hide() + self.p2.Hide() + + self.sp.Initialize(self.p1) + + self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, + self.OnSashChanging, self.sp) + self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, + self.OnSashChanged, self.sp) + + + def MakeMenuBar(self): + menu = wx.Menu() + item = menu.Append(-1, "Split horizontally") + self.Bind(wx.EVT_MENU, self.OnSplitH, item) + self.Bind(wx.EVT_UPDATE_UI, self.OnCheckCanSplit, item) + item = menu.Append(-1, "Split vertically") + self.Bind(wx.EVT_MENU, self.OnSplitV, item) + self.Bind(wx.EVT_UPDATE_UI, self.OnCheckCanSplit, item) + item = menu.Append(-1, "Unsplit") + self.Bind(wx.EVT_MENU, self.OnUnsplit, item) + self.Bind(wx.EVT_UPDATE_UI, self.OnCheckCanUnsplit, item) + + menu.AppendSeparator() + item = menu.Append(-1, "Set initial sash position") + self.Bind(wx.EVT_MENU, self.OnSetPos, item) + item = menu.Append(-1, "Set minimum pane size") + self.Bind(wx.EVT_MENU, self.OnSetMin, item) + + menu.AppendSeparator() + item = menu.Append(wx.ID_EXIT, "E&xit") + self.Bind(wx.EVT_MENU, self.OnExit, item) + + mbar = wx.MenuBar() + mbar.Append(menu, "Splitter") + self.SetMenuBar(mbar) + + + def OnSashChanging(self, evt): + print "OnSashChanging:", evt.GetSashPosition() + + def OnSashChanged(self, evt): + print "OnSashChanged:", evt.GetSashPosition() + + + def OnSplitH(self, evt): + self.sp.SplitHorizontally(self.p1, self.p2, self.initpos) + + def OnSplitV(self, evt): + self.sp.SplitVertically(self.p1, self.p2, self.initpos) + + def OnCheckCanSplit(self, evt): + evt.Enable(not self.sp.IsSplit()) + + def OnCheckCanUnsplit(self, evt): + evt.Enable(self.sp.IsSplit()) + + def OnUnsplit(self, evt): + self.sp.Unsplit() + + def OnSetMin(self, evt): + minpane = wx.GetNumberFromUser( + "Enter the minimum pane size", + "", "Minimum Pane Size", self.minpane, + 0, 1000, self) + if minpane != -1: + self.minpane = minpane + self.sp.SetMinimumPaneSize(self.minpane) + + def OnSetPos(self, evt): + initpos = wx.GetNumberFromUser( + "Enter the initial sash position (to be used in the Split call)", + "", "Initial Sash Position", self.initpos, + -1000, 1000, self) + if initpos != -1: + self.initpos = initpos + + + def OnExit(self, evt): + self.Close() + + +app = wx.PySimpleApp(redirect=True) +frm = SplitterExampleFrame(None, "Splitter Example") +frm.SetSize((600,500)) +frm.Show() +app.SetTopWindow(frm) +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-09/choice_box.py b/wxPython/samples/wxPIA_book/Chapter-09/choice_box.py new file mode 100644 index 0000000000..17693fc0d1 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-09/choice_box.py @@ -0,0 +1,12 @@ +import wx + +if __name__ == "__main__": + app = wx.PySimpleApp() + choices = ["Alpha", "Baker", "Charlie", "Delta"] + dialog = wx.SingleChoiceDialog(None, "Pick A Word", "Choices", + choices) + if dialog.ShowModal() == wx.ID_OK: + print "You selected: %s\n" % dialog.GetStringSelection() + + dialog.Destroy() + diff --git a/wxPython/samples/wxPIA_book/Chapter-09/color_box.py b/wxPython/samples/wxPIA_book/Chapter-09/color_box.py new file mode 100644 index 0000000000..94e709e484 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-09/color_box.py @@ -0,0 +1,10 @@ +import wx + +if __name__ == "__main__": + app = wx.PySimpleApp() + dialog = wx.ColourDialog(None) + dialog.GetColourData().SetChooseFull(True) + if dialog.ShowModal() == wx.ID_OK: + data = dialog.GetColourData() + print 'You selected: %s\n' % str(data.GetColour().Get()) + dialog.Destroy() diff --git a/wxPython/samples/wxPIA_book/Chapter-09/dir_box.py b/wxPython/samples/wxPIA_book/Chapter-09/dir_box.py new file mode 100644 index 0000000000..36cc79b00e --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-09/dir_box.py @@ -0,0 +1,12 @@ +import wx + +if __name__ == "__main__": + app = wx.PySimpleApp() + dialog = wx.DirDialog(None, "Choose a directory:", + style=wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON) + if dialog.ShowModal() == wx.ID_OK: + print dialog.GetPath() + dialog.Destroy() + + + diff --git a/wxPython/samples/wxPIA_book/Chapter-09/file_box.py b/wxPython/samples/wxPIA_book/Chapter-09/file_box.py new file mode 100644 index 0000000000..ff46e39701 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-09/file_box.py @@ -0,0 +1,17 @@ +import wx +import os + +if __name__ == "__main__": + app = wx.PySimpleApp() + wildcard = "Python source (*.py)|*.py|" \ + "Compiled Python (*.pyc)|*.pyc|" \ + "All files (*.*)|*.*" + dialog = wx.FileDialog(None, "Choose a file", os.getcwd(), + "", wildcard, wx.OPEN) + if dialog.ShowModal() == wx.ID_OK: + print dialog.GetPath() + + dialog.Destroy() + + + diff --git a/wxPython/samples/wxPIA_book/Chapter-09/font_box.py b/wxPython/samples/wxPIA_book/Chapter-09/font_box.py new file mode 100644 index 0000000000..969e596b9e --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-09/font_box.py @@ -0,0 +1,16 @@ +import wx + +if __name__ == "__main__": + app = wx.PySimpleApp() + dialog = wx.FontDialog(None, wx.FontData()) + if dialog.ShowModal() == wx.ID_OK: + data = dialog.GetFontData() + font = data.GetChosenFont() + colour = data.GetColour() + print 'You selected: "%s", %d points\n' % ( + font.GetFaceName(), font.GetPointSize()) + dialog.Destroy() + + + + diff --git a/wxPython/samples/wxPIA_book/Chapter-09/image_box.py b/wxPython/samples/wxPIA_book/Chapter-09/image_box.py new file mode 100644 index 0000000000..b425400056 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-09/image_box.py @@ -0,0 +1,11 @@ +import wx +import wx.lib.imagebrowser as imagebrowser + +if __name__ == "__main__": + app = wx.PySimpleApp() + dialog = imagebrowser.ImageDialog(None) + if dialog.ShowModal() == wx.ID_OK: + print "You Selected File: " + dialog.GetFile() + dialog.Destroy() + + diff --git a/wxPython/samples/wxPIA_book/Chapter-09/message_box.py b/wxPython/samples/wxPIA_book/Chapter-09/message_box.py new file mode 100644 index 0000000000..db9828eee6 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-09/message_box.py @@ -0,0 +1,16 @@ +import wx + +if __name__ == "__main__": + app = wx.PySimpleApp() + dlg = wx.MessageDialog(None, "Is this explanation OK?", + 'A Message Box', + wx.YES_NO | wx.ICON_QUESTION) + retCode = dlg.ShowModal() + if (retCode == wx.ID_YES): + print "yes" + else: + print "no" + dlg.Destroy() + + retCode = wx.MessageBox("Is this way easier?", "Via Function", + wx.YES_NO | wx.ICON_QUESTION) diff --git a/wxPython/samples/wxPIA_book/Chapter-09/modal_dialog.py b/wxPython/samples/wxPIA_book/Chapter-09/modal_dialog.py new file mode 100644 index 0000000000..f4dcd71428 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-09/modal_dialog.py @@ -0,0 +1,21 @@ +import wx + +class SubclassDialog(wx.Dialog): + def __init__(self): + wx.Dialog.__init__(self, None, -1, 'Dialog Subclass', + size=(300, 100)) + okButton = wx.Button(self, wx.ID_OK, "OK", pos=(15, 15)) + okButton.SetDefault() + cancelButton = wx.Button(self, wx.ID_CANCEL, "Cancel", + pos=(115, 15)) + +if __name__ == '__main__': + app = wx.PySimpleApp() + app.MainLoop() + dialog = SubclassDialog() + result = dialog.ShowModal() + if result == wx.ID_OK: + print "OK" + else: + print "Cancel" + dialog.Destroy() diff --git a/wxPython/samples/wxPIA_book/Chapter-09/progress_box.py b/wxPython/samples/wxPIA_book/Chapter-09/progress_box.py new file mode 100644 index 0000000000..f5e0253e11 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-09/progress_box.py @@ -0,0 +1,33 @@ +import wx + +class Frame(wx.Frame): + def __init__(self, parent): + wx.Frame.__init__(self, parent, title="ProgressDialog sample") + self.progressMax = 100 + self.count = 0 + self.dialog = None + self.timer = wx.Timer(self) + self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer) + self.timer.Start(1000) + + def OnTimer(self, evt): + if not self.dialog: + self.dialog = wx.ProgressDialog("A progress box", "Time remaining", + self.progressMax, + style=wx.PD_CAN_ABORT + | wx.PD_ELAPSED_TIME + | wx.PD_REMAINING_TIME) + + self.count += 1 + keepGoing = self.dialog.Update(self.count) + if not keepGoing or self.count == self.progressMax: + self.dialog.Destroy() + self.timer.Stop() + + +if __name__ == "__main__": + app = wx.PySimpleApp() + frame = Frame(None) + frame.Show() + app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-09/startup_tip.py b/wxPython/samples/wxPIA_book/Chapter-09/startup_tip.py new file mode 100644 index 0000000000..8341060c9b --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-09/startup_tip.py @@ -0,0 +1,8 @@ +import wx + +if __name__ == "__main__": + app = wx.PySimpleApp() + provider = wx.CreateFileTipProvider("tips.txt", 0) + wx.ShowTip(None, provider, True) + + diff --git a/wxPython/samples/wxPIA_book/Chapter-09/text_box.py b/wxPython/samples/wxPIA_book/Chapter-09/text_box.py new file mode 100644 index 0000000000..ebad419c90 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-09/text_box.py @@ -0,0 +1,11 @@ +import wx + +if __name__ == "__main__": + app = wx.PySimpleApp() + dialog = wx.TextEntryDialog(None, + "What kind of text would you like to enter?", + "Text Entry", "Default Value", style=wx.OK|wx.CANCEL) + if dialog.ShowModal() == wx.ID_OK: + print "You entered: %s" % dialog.GetValue() + + dialog.Destroy() diff --git a/wxPython/samples/wxPIA_book/Chapter-09/tips.txt b/wxPython/samples/wxPIA_book/Chapter-09/tips.txt new file mode 100644 index 0000000000..a3c442529b --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-09/tips.txt @@ -0,0 +1,2 @@ +You can do startup tips very easily. +Feel the force, Luke. diff --git a/wxPython/samples/wxPIA_book/Chapter-09/validator1.py b/wxPython/samples/wxPIA_book/Chapter-09/validator1.py new file mode 100644 index 0000000000..af49ad0bd8 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-09/validator1.py @@ -0,0 +1,93 @@ +import wx + +about_txt = """\ +The validator used in this example will ensure that the text +controls are not empty when you press the Ok button, and +will not let you leave if any of the Validations fail.""" + + +class NotEmptyValidator(wx.PyValidator): + def __init__(self): + wx.PyValidator.__init__(self) + + def Clone(self): + """ + Note that every validator must implement the Clone() method. + """ + return NotEmptyValidator() + + def Validate(self, win): + textCtrl = self.GetWindow() + text = textCtrl.GetValue() + + if len(text) == 0: + wx.MessageBox("This field must contain some text!", "Error") + textCtrl.SetBackgroundColour("pink") + textCtrl.SetFocus() + textCtrl.Refresh() + return False + else: + textCtrl.SetBackgroundColour( + wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) + textCtrl.Refresh() + return True + + def TransferToWindow(self): + return True + + def TransferFromWindow(self): + return True + + + +class MyDialog(wx.Dialog): + def __init__(self): + wx.Dialog.__init__(self, None, -1, "Validators: validating") + + # Create the text controls + about = wx.StaticText(self, -1, about_txt) + name_l = wx.StaticText(self, -1, "Name:") + email_l = wx.StaticText(self, -1, "Email:") + phone_l = wx.StaticText(self, -1, "Phone:") + + name_t = wx.TextCtrl(self, validator=NotEmptyValidator()) + email_t = wx.TextCtrl(self, validator=NotEmptyValidator()) + phone_t = wx.TextCtrl(self, validator=NotEmptyValidator()) + + # Use standard button IDs + okay = wx.Button(self, wx.ID_OK) + okay.SetDefault() + cancel = wx.Button(self, wx.ID_CANCEL) + + # Layout with sizers + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(about, 0, wx.ALL, 5) + sizer.Add(wx.StaticLine(self), 0, wx.EXPAND|wx.ALL, 5) + + fgs = wx.FlexGridSizer(3, 2, 5, 5) + fgs.Add(name_l, 0, wx.ALIGN_RIGHT) + fgs.Add(name_t, 0, wx.EXPAND) + fgs.Add(email_l, 0, wx.ALIGN_RIGHT) + fgs.Add(email_t, 0, wx.EXPAND) + fgs.Add(phone_l, 0, wx.ALIGN_RIGHT) + fgs.Add(phone_t, 0, wx.EXPAND) + fgs.AddGrowableCol(1) + sizer.Add(fgs, 0, wx.EXPAND|wx.ALL, 5) + + btns = wx.StdDialogButtonSizer() + btns.AddButton(okay) + btns.AddButton(cancel) + btns.Realize() + sizer.Add(btns, 0, wx.EXPAND|wx.ALL, 5) + + self.SetSizer(sizer) + sizer.Fit(self) + + +app = wx.PySimpleApp() + +dlg = MyDialog() +dlg.ShowModal() +dlg.Destroy() + +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-09/validator2.py b/wxPython/samples/wxPIA_book/Chapter-09/validator2.py new file mode 100644 index 0000000000..e14d76045b --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-09/validator2.py @@ -0,0 +1,91 @@ +import wx +import pprint + +about_txt = """\ +The validator used in this example shows how the validator +can be used to transfer data to and from each text control +automatically when the dialog is shown and dismissed.""" + + +class DataXferValidator(wx.PyValidator): + def __init__(self, data, key): + wx.PyValidator.__init__(self) + self.data = data + self.key = key + + def Clone(self): + """ + Note that every validator must implement the Clone() method. + """ + return DataXferValidator(self.data, self.key) + + def Validate(self, win): + return True + + def TransferToWindow(self): + textCtrl = self.GetWindow() + textCtrl.SetValue(self.data.get(self.key, "")) + return True + + def TransferFromWindow(self): + textCtrl = self.GetWindow() + self.data[self.key] = textCtrl.GetValue() + return True + + + +class MyDialog(wx.Dialog): + def __init__(self, data): + wx.Dialog.__init__(self, None, -1, "Validators: data transfer") + + # Create the text controls + about = wx.StaticText(self, -1, about_txt) + name_l = wx.StaticText(self, -1, "Name:") + email_l = wx.StaticText(self, -1, "Email:") + phone_l = wx.StaticText(self, -1, "Phone:") + + name_t = wx.TextCtrl(self, validator=DataXferValidator(data, "name")) + email_t = wx.TextCtrl(self, validator=DataXferValidator(data, "email")) + phone_t = wx.TextCtrl(self, validator=DataXferValidator(data, "phone")) + + # Use standard button IDs + okay = wx.Button(self, wx.ID_OK) + okay.SetDefault() + cancel = wx.Button(self, wx.ID_CANCEL) + + # Layout with sizers + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(about, 0, wx.ALL, 5) + sizer.Add(wx.StaticLine(self), 0, wx.EXPAND|wx.ALL, 5) + + fgs = wx.FlexGridSizer(3, 2, 5, 5) + fgs.Add(name_l, 0, wx.ALIGN_RIGHT) + fgs.Add(name_t, 0, wx.EXPAND) + fgs.Add(email_l, 0, wx.ALIGN_RIGHT) + fgs.Add(email_t, 0, wx.EXPAND) + fgs.Add(phone_l, 0, wx.ALIGN_RIGHT) + fgs.Add(phone_t, 0, wx.EXPAND) + fgs.AddGrowableCol(1) + sizer.Add(fgs, 0, wx.EXPAND|wx.ALL, 5) + + btns = wx.StdDialogButtonSizer() + btns.AddButton(okay) + btns.AddButton(cancel) + btns.Realize() + sizer.Add(btns, 0, wx.EXPAND|wx.ALL, 5) + + self.SetSizer(sizer) + sizer.Fit(self) + + +app = wx.PySimpleApp() + +data = { "name" : "Jordyn Dunn" } +dlg = MyDialog(data) +dlg.ShowModal() +dlg.Destroy() + +wx.MessageBox("You entered these values:\n\n" + + pprint.pformat(data)) + +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-09/validator3.py b/wxPython/samples/wxPIA_book/Chapter-09/validator3.py new file mode 100644 index 0000000000..12a4a8ea34 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-09/validator3.py @@ -0,0 +1,92 @@ +import wx +import string + +about_txt = """\ +The validator used in this example will validate the input on the fly +instead of waiting until the okay button is pressed. The first field +will not allow digits to be typed, the second will allow anything +and the third will not allow alphabetic characters to be entered. +""" + + +class CharValidator(wx.PyValidator): + def __init__(self, flag): + wx.PyValidator.__init__(self) + self.flag = flag + self.Bind(wx.EVT_CHAR, self.OnChar) + + def Clone(self): + """ + Note that every validator must implement the Clone() method. + """ + return CharValidator(self.flag) + + def Validate(self, win): + return True + + def TransferToWindow(self): + return True + + def TransferFromWindow(self): + return True + + def OnChar(self, evt): + key = chr(evt.GetKeyCode()) + if self.flag == "no-alpha" and key in string.letters: + return + if self.flag == "no-digit" and key in string.digits: + return + evt.Skip() + + +class MyDialog(wx.Dialog): + def __init__(self): + wx.Dialog.__init__(self, None, -1, "Validators: behavior modification") + + # Create the text controls + about = wx.StaticText(self, -1, about_txt) + name_l = wx.StaticText(self, -1, "Name:") + email_l = wx.StaticText(self, -1, "Email:") + phone_l = wx.StaticText(self, -1, "Phone:") + + name_t = wx.TextCtrl(self, validator=CharValidator("no-digit")) + email_t = wx.TextCtrl(self, validator=CharValidator("any")) + phone_t = wx.TextCtrl(self, validator=CharValidator("no-alpha")) + + # Use standard button IDs + okay = wx.Button(self, wx.ID_OK) + okay.SetDefault() + cancel = wx.Button(self, wx.ID_CANCEL) + + # Layout with sizers + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(about, 0, wx.ALL, 5) + sizer.Add(wx.StaticLine(self), 0, wx.EXPAND|wx.ALL, 5) + + fgs = wx.FlexGridSizer(3, 2, 5, 5) + fgs.Add(name_l, 0, wx.ALIGN_RIGHT) + fgs.Add(name_t, 0, wx.EXPAND) + fgs.Add(email_l, 0, wx.ALIGN_RIGHT) + fgs.Add(email_t, 0, wx.EXPAND) + fgs.Add(phone_l, 0, wx.ALIGN_RIGHT) + fgs.Add(phone_t, 0, wx.EXPAND) + fgs.AddGrowableCol(1) + sizer.Add(fgs, 0, wx.EXPAND|wx.ALL, 5) + + btns = wx.StdDialogButtonSizer() + btns.AddButton(okay) + btns.AddButton(cancel) + btns.Realize() + sizer.Add(btns, 0, wx.EXPAND|wx.ALL, 5) + + self.SetSizer(sizer) + sizer.Fit(self) + + +app = wx.PySimpleApp() + +dlg = MyDialog() +dlg.ShowModal() +dlg.Destroy() + +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-09/wizard.py b/wxPython/samples/wxPIA_book/Chapter-09/wizard.py new file mode 100644 index 0000000000..6c7562104f --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-09/wizard.py @@ -0,0 +1,39 @@ +import wx +import wx.wizard + +class TitledPage(wx.wizard.WizardPageSimple): + def __init__(self, parent, title): + wx.wizard.WizardPageSimple.__init__(self, parent) + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.SetSizer(self.sizer) + titleText = wx.StaticText(self, -1, title) + titleText.SetFont( + wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD)) + self.sizer.Add(titleText, 0, + wx.ALIGN_CENTRE | wx.ALL, 5) + self.sizer.Add(wx.StaticLine(self, -1), 0, + wx.EXPAND | wx.ALL, 5) + +if __name__ == "__main__": + app = wx.PySimpleApp() + wizard = wx.wizard.Wizard(None, -1, "Simple Wizard") + page1 = TitledPage(wizard, "Page 1") + page2 = TitledPage(wizard, "Page 2") + page3 = TitledPage(wizard, "Page 3") + page4 = TitledPage(wizard, "Page 4") + page1.sizer.Add(wx.StaticText(page1, -1, + "Testing the wizard")) + page4.sizer.Add(wx.StaticText(page4, -1, + "This is the last page.")) + wx.wizard.WizardPageSimple_Chain(page1, page2) + wx.wizard.WizardPageSimple_Chain(page2, page3) + wx.wizard.WizardPageSimple_Chain(page3, page4) + wizard.FitToPage(page1) + + if wizard.RunWizard(page1): + print "Success" + + wizard.Destroy() + + + diff --git a/wxPython/samples/wxPIA_book/Chapter-10/add_items.py b/wxPython/samples/wxPIA_book/Chapter-10/add_items.py new file mode 100644 index 0000000000..2c5efe6ce1 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-10/add_items.py @@ -0,0 +1,50 @@ +import wx + +class MyFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, + "Add Menu Items") + p = wx.Panel(self) + self.txt = wx.TextCtrl(p, -1, "new item") + btn = wx.Button(p, -1, "Add Menu Item") + self.Bind(wx.EVT_BUTTON, self.OnAddItem, btn) + + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(self.txt, 0, wx.ALL, 20) + sizer.Add(btn, 0, wx.TOP|wx.RIGHT, 20) + p.SetSizer(sizer) + + self.menu = menu = wx.Menu() + simple = menu.Append(-1, "Simple menu item") + menu.AppendSeparator() + exit = menu.Append(-1, "Exit") + self.Bind(wx.EVT_MENU, self.OnSimple, simple) + self.Bind(wx.EVT_MENU, self.OnExit, exit) + + menuBar = wx.MenuBar() + menuBar.Append(menu, "Menu") + self.SetMenuBar(menuBar) + + + def OnSimple(self, event): + wx.MessageBox("You selected the simple menu item") + + def OnExit(self, event): + self.Close() + + def OnAddItem(self, event): + item = self.menu.Append(-1, self.txt.GetValue()) + self.Bind(wx.EVT_MENU, self.OnNewItemSelected, item) + + def OnNewItemSelected(self, event): + wx.MessageBox("You selected a new item") + + + +if __name__ == "__main__": + app = wx.PySimpleApp() + frame = MyFrame() + frame.Show() + app.MainLoop() + + diff --git a/wxPython/samples/wxPIA_book/Chapter-10/create_just_menu.py b/wxPython/samples/wxPIA_book/Chapter-10/create_just_menu.py new file mode 100644 index 0000000000..dd9f207bfc --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-10/create_just_menu.py @@ -0,0 +1,22 @@ +import wx + +class MyFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "Simple Menu Example") + p = wx.Panel(self) + menuBar = wx.MenuBar() + menu = wx.Menu() + menuBar.Append(menu, "Left Menu") + menu2 = wx.Menu() + menuBar.Append(menu2, "Middle Menu") + menu3 = wx.Menu() + menuBar.Append(menu3, "Right Menu") + self.SetMenuBar(menuBar) + +if __name__ == "__main__": + app = wx.PySimpleApp() + frame = MyFrame() + frame.Show() + app.MainLoop() + + diff --git a/wxPython/samples/wxPIA_book/Chapter-10/create_simple_menu.py b/wxPython/samples/wxPIA_book/Chapter-10/create_simple_menu.py new file mode 100644 index 0000000000..24e3592c5b --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-10/create_simple_menu.py @@ -0,0 +1,29 @@ +import wx + +class MyFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "Simple Menu Example") + p = wx.Panel(self) + menu = wx.Menu() + simple = menu.Append(-1, "Simple menu item") + menu.AppendSeparator() + exit = menu.Append(-1, "Exit") + self.Bind(wx.EVT_MENU, self.OnSimple, simple) + self.Bind(wx.EVT_MENU, self.OnExit, exit) + menuBar = wx.MenuBar() + menuBar.Append(menu, "Simple Menu") + self.SetMenuBar(menuBar) + + def OnSimple(self, event): + wx.MessageBox("You selected the simple menu item") + + def OnExit(self, event): + self.Close() + +if __name__ == "__main__": + app = wx.PySimpleApp() + frame = MyFrame() + frame.Show() + app.MainLoop() + + diff --git a/wxPython/samples/wxPIA_book/Chapter-10/disable_item.py b/wxPython/samples/wxPIA_book/Chapter-10/disable_item.py new file mode 100644 index 0000000000..78c753494f --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-10/disable_item.py @@ -0,0 +1,46 @@ +import wx + +ID_SIMPLE = wx.NewId() + +class MyFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, + "Enable/Disable Menu Example") + p = wx.Panel(self) + self.btn = wx.Button(p, -1, "Disable Item", (20,20)) + self.Bind(wx.EVT_BUTTON, self.OnToggleItem, self.btn) + + menu = wx.Menu() + menu.Append(ID_SIMPLE, "Simple menu item") + self.Bind(wx.EVT_MENU, self.OnSimple, id=ID_SIMPLE) + + menu.AppendSeparator() + menu.Append(wx.ID_EXIT, "Exit") + self.Bind(wx.EVT_MENU, self.OnExit, id=wx.ID_EXIT) + + menuBar = wx.MenuBar() + menuBar.Append(menu, "Menu") + self.SetMenuBar(menuBar) + + + def OnSimple(self, event): + wx.MessageBox("You selected the simple menu item") + + def OnExit(self, event): + self.Close() + + def OnToggleItem(self, event): + menubar = self.GetMenuBar() + enabled = menubar.IsEnabled(ID_SIMPLE) + menubar.Enable(ID_SIMPLE, not enabled) + self.btn.SetLabel( + (enabled and "Enable" or "Disable") + " Item") + + +if __name__ == "__main__": + app = wx.PySimpleApp() + frame = MyFrame() + frame.Show() + app.MainLoop() + + diff --git a/wxPython/samples/wxPIA_book/Chapter-10/fancy_items.py b/wxPython/samples/wxPIA_book/Chapter-10/fancy_items.py new file mode 100644 index 0000000000..8a42df8698 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-10/fancy_items.py @@ -0,0 +1,47 @@ +import wx + +class MyFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, + "Fancier Menu Example") + p = wx.Panel(self) + menu = wx.Menu() + + bmp = wx.Bitmap("open.png", wx.BITMAP_TYPE_PNG) + item = wx.MenuItem(menu, -1, "Has Open Bitmap") + item.SetBitmap(bmp) + menu.AppendItem(item) + + if True or 'wxMSW' in wx.PlatformInfo: + font = wx.SystemSettings.GetFont( + wx.SYS_DEFAULT_GUI_FONT) + font.SetWeight(wx.BOLD) + item = wx.MenuItem(menu, -1, "Has Bold Font") + item.SetFont(font) + menu.AppendItem(item) + + item = wx.MenuItem(menu, -1, "Has Red Text") + item.SetTextColour("red") + menu.AppendItem(item) + + + menu.AppendSeparator() + exit = menu.Append(-1, "Exit") + self.Bind(wx.EVT_MENU, self.OnExit, exit) + + menuBar = wx.MenuBar() + menuBar.Append(menu, "Menu") + self.SetMenuBar(menuBar) + + + def OnExit(self, event): + self.Close() + + +if __name__ == "__main__": + app = wx.PySimpleApp() + frame = MyFrame() + frame.Show() + app.MainLoop() + + diff --git a/wxPython/samples/wxPIA_book/Chapter-10/find_item.py b/wxPython/samples/wxPIA_book/Chapter-10/find_item.py new file mode 100644 index 0000000000..cf58c359aa --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-10/find_item.py @@ -0,0 +1,52 @@ +import wx + +class MyFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, + "Find Item Example") + p = wx.Panel(self) + self.txt = wx.TextCtrl(p, -1, "new item") + btn = wx.Button(p, -1, "Add Menu Item") + self.Bind(wx.EVT_BUTTON, self.OnAddItem, btn) + + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(self.txt, 0, wx.ALL, 20) + sizer.Add(btn, 0, wx.TOP|wx.RIGHT, 20) + p.SetSizer(sizer) + + self.menu = menu = wx.Menu() + simple = menu.Append(-1, "Simple menu item") + menu.AppendSeparator() + exit = menu.Append(-1, "Exit") + self.Bind(wx.EVT_MENU, self.OnSimple, simple) + self.Bind(wx.EVT_MENU, self.OnExit, exit) + + menuBar = wx.MenuBar() + menuBar.Append(menu, "Menu") + self.SetMenuBar(menuBar) + + + def OnSimple(self, event): + wx.MessageBox("You selected the simple menu item") + + def OnExit(self, event): + self.Close() + + def OnAddItem(self, event): + item = self.menu.Append(-1, self.txt.GetValue()) + self.Bind(wx.EVT_MENU, self.OnNewItemSelected, item) + + def OnNewItemSelected(self, event): + item = self.GetMenuBar().FindItemById(event.GetId()) + text = item.GetText() + wx.MessageBox("You selected the '%s' item" % text) + + + +if __name__ == "__main__": + app = wx.PySimpleApp() + frame = MyFrame() + frame.Show() + app.MainLoop() + + diff --git a/wxPython/samples/wxPIA_book/Chapter-10/open.png b/wxPython/samples/wxPIA_book/Chapter-10/open.png new file mode 100644 index 0000000000000000000000000000000000000000..c1f11bc59ce05dff3aa07829fa442337c877c4a3 GIT binary patch literal 281 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~q!3HGX7W?Z1DeV&1h!W?b)Wnj^{5*w_%-mFl zkkV8I3k9#zJOv{I0}};9Ln{LdD+411T>}dP1KX_6sX%S)C7!;n>{r-0gt+x1ICez= zg*Xd5B8wRqIKO># zaBrn}dQaHhmXrK~zoZn}3M2|LeomhK;GggI%Nb1@6J#bXo{+Lu`GNHGypUjeESxU(R8#>0~bB-Hnp_es~z WQkQY)DZLN0oWax8&t;ucLK6T5d}43_ literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-10/popupmenu.py b/wxPython/samples/wxPIA_book/Chapter-10/popupmenu.py new file mode 100644 index 0000000000..d26ce9ad36 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-10/popupmenu.py @@ -0,0 +1,49 @@ +import wx + +class MyFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, + "Popup Menu Example") + self.panel = p = wx.Panel(self) + menu = wx.Menu() + exit = menu.Append(-1, "Exit") + self.Bind(wx.EVT_MENU, self.OnExit, exit) + + menuBar = wx.MenuBar() + menuBar.Append(menu, "Menu") + self.SetMenuBar(menuBar) + + wx.StaticText(p, -1, + "Right-click on the panel to show a popup menu", + (25,25)) + + self.popupmenu = wx.Menu() + for text in "one two three four five".split(): + item = self.popupmenu.Append(-1, text) + self.Bind(wx.EVT_MENU, self.OnPopupItemSelected, item) + p.Bind(wx.EVT_CONTEXT_MENU, self.OnShowPopup) + + + def OnShowPopup(self, event): + pos = event.GetPosition() + pos = self.panel.ScreenToClient(pos) + self.panel.PopupMenu(self.popupmenu, pos) + + + def OnPopupItemSelected(self, event): + item = self.popupmenu.FindItemById(event.GetId()) + text = item.GetText() + wx.MessageBox("You selected item '%s'" % text) + + + def OnExit(self, event): + self.Close() + + +if __name__ == "__main__": + app = wx.PySimpleApp() + frame = MyFrame() + frame.Show() + app.MainLoop() + + diff --git a/wxPython/samples/wxPIA_book/Chapter-10/sub_menu.py b/wxPython/samples/wxPIA_book/Chapter-10/sub_menu.py new file mode 100644 index 0000000000..6021508d84 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-10/sub_menu.py @@ -0,0 +1,34 @@ +import wx + +class MyFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, + "Sub-menu Example") + p = wx.Panel(self) + menu = wx.Menu() + + submenu = wx.Menu() + submenu.Append(-1, "Sub-item 1") + submenu.Append(-1, "Sub-item 2") + menu.AppendMenu(-1, "Sub-menu", submenu) + + menu.AppendSeparator() + exit = menu.Append(-1, "Exit") + self.Bind(wx.EVT_MENU, self.OnExit, exit) + + menuBar = wx.MenuBar() + menuBar.Append(menu, "Menu") + self.SetMenuBar(menuBar) + + + def OnExit(self, event): + self.Close() + + +if __name__ == "__main__": + app = wx.PySimpleApp() + frame = MyFrame() + frame.Show() + app.MainLoop() + + diff --git a/wxPython/samples/wxPIA_book/Chapter-10/toggle_items.py b/wxPython/samples/wxPIA_book/Chapter-10/toggle_items.py new file mode 100644 index 0000000000..216e4c17ca --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-10/toggle_items.py @@ -0,0 +1,36 @@ +import wx + +class MyFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, + "Toggle Items Example") + p = wx.Panel(self) + menuBar = wx.MenuBar() + menu = wx.Menu() + exit = menu.Append(-1, "Exit") + self.Bind(wx.EVT_MENU, self.OnExit, exit) + menuBar.Append(menu, "Menu") + + menu = wx.Menu() + menu.AppendCheckItem(-1, "Check Item 1") + menu.AppendCheckItem(-1, "Check Item 2") + menu.AppendCheckItem(-1, "Check Item 3") + menu.AppendSeparator() + menu.AppendRadioItem(-1, "Radio Item 1") + menu.AppendRadioItem(-1, "Radio Item 2") + menu.AppendRadioItem(-1, "Radio Item 3") + menuBar.Append(menu, "Toggle Items") + + self.SetMenuBar(menuBar) + + def OnExit(self, event): + self.Close() + + +if __name__ == "__main__": + app = wx.PySimpleApp() + frame = MyFrame() + frame.Show() + app.MainLoop() + + diff --git a/wxPython/samples/wxPIA_book/Chapter-10/update_ui.py b/wxPython/samples/wxPIA_book/Chapter-10/update_ui.py new file mode 100644 index 0000000000..a33a6fe629 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-10/update_ui.py @@ -0,0 +1,49 @@ +import wx + +ID_SIMPLE = wx.NewId() + +class MyFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, + "UPDATE_UI Menu Example") + p = wx.Panel(self) + self.btn = wx.Button(p, -1, "Disable Item", (20,20)) + self.Bind(wx.EVT_BUTTON, self.OnToggleItem, self.btn) + + menu = wx.Menu() + menu.Append(ID_SIMPLE, "Simple menu item") + self.enabled = True + self.Bind(wx.EVT_MENU, self.OnSimple, id=ID_SIMPLE) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateSimple, id=ID_SIMPLE) + + menu.AppendSeparator() + menu.Append(wx.ID_EXIT, "Exit") + self.Bind(wx.EVT_MENU, self.OnExit, id=wx.ID_EXIT) + + menuBar = wx.MenuBar() + menuBar.Append(menu, "Menu") + self.SetMenuBar(menuBar) + + + def OnSimple(self, event): + wx.MessageBox("You selected the simple menu item") + + def OnExit(self, event): + self.Close() + + def OnToggleItem(self, event): + self.btn.SetLabel( + (self.enabled and "Enable" or "Disable") + " Item") + self.enabled = not self.enabled + + def OnUpdateSimple(self, event): + event.Enable(self.enabled) + + +if __name__ == "__main__": + app = wx.PySimpleApp() + frame = MyFrame() + frame.Show() + app.MainLoop() + + diff --git a/wxPython/samples/wxPIA_book/Chapter-10/with_accelerator.py b/wxPython/samples/wxPIA_book/Chapter-10/with_accelerator.py new file mode 100644 index 0000000000..1e2b785f4e --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-10/with_accelerator.py @@ -0,0 +1,47 @@ +import wx + +class MyFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, + "Accelerator Example") + p = wx.Panel(self) + menu = wx.Menu() + simple = menu.Append(-1, "Simple &menu item") # with mnemonic + accel = menu.Append(-1, "&Accelerated\tCtrl-A") # with accelerator + + menu.AppendSeparator() + exit = menu.Append(-1, "E&xit") + + self.Bind(wx.EVT_MENU, self.OnSimple, simple) + self.Bind(wx.EVT_MENU, self.OnAccelerated, accel) + self.Bind(wx.EVT_MENU, self.OnExit, exit) + + menuBar = wx.MenuBar() + menuBar.Append(menu, "&Menu") + self.SetMenuBar(menuBar) + + # An alternate way to make accelerators + acceltbl = wx.AcceleratorTable( [ + (wx.ACCEL_CTRL, ord('Q'), exit.GetId()) + ]) + self.SetAcceleratorTable(acceltbl) + + + def OnSimple(self, event): + wx.MessageBox("You selected the simple menu item") + + def OnAccelerated(self, event): + wx.MessageBox("You selected the accelerated menu item") + + + def OnExit(self, event): + self.Close() + + +if __name__ == "__main__": + app = wx.PySimpleApp() + frame = MyFrame() + frame.Show() + app.MainLoop() + + diff --git a/wxPython/samples/wxPIA_book/Chapter-11/basicflexgridsizer.py b/wxPython/samples/wxPIA_book/Chapter-11/basicflexgridsizer.py new file mode 100644 index 0000000000..08204bb24c --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-11/basicflexgridsizer.py @@ -0,0 +1,20 @@ +import wx +from blockwindow import BlockWindow + +labels = "one two three four five six seven eight nine".split() + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "FlexGridSizer") + sizer = wx.FlexGridSizer(rows=3, cols=3, hgap=5, vgap=5) + for label in labels: + bw = BlockWindow(self, label=label) + sizer.Add(bw, 0, 0) + center = self.FindWindowByName("five") + center.SetMinSize((150,50)) + self.SetSizer(sizer) + self.Fit() + +app = wx.PySimpleApp() +TestFrame().Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-11/basicgridsizer.py b/wxPython/samples/wxPIA_book/Chapter-11/basicgridsizer.py new file mode 100644 index 0000000000..01e7e4cd75 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-11/basicgridsizer.py @@ -0,0 +1,18 @@ +import wx +from blockwindow import BlockWindow + +labels = "one two three four five six seven eight nine".split() + +class GridSizerFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "Basic Grid Sizer") + sizer = wx.GridSizer(rows=3, cols=3, hgap=5, vgap=5) + for label in labels: + bw = BlockWindow(self, label=label) + sizer.Add(bw, 0, 0) + self.SetSizer(sizer) + self.Fit() + +app = wx.PySimpleApp() +GridSizerFrame().Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-11/blockwindow.py b/wxPython/samples/wxPIA_book/Chapter-11/blockwindow.py new file mode 100644 index 0000000000..c506568c86 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-11/blockwindow.py @@ -0,0 +1,20 @@ +import wx + +class BlockWindow(wx.Panel): + def __init__(self, parent, ID=-1, label="", + pos=wx.DefaultPosition, size=(100, 25)): + wx.Panel.__init__(self, parent, ID, pos, size, + wx.RAISED_BORDER, label) + self.label = label + self.SetBackgroundColour("white") + self.SetMinSize(size) + self.Bind(wx.EVT_PAINT, self.OnPaint) + + def OnPaint(self, evt): + sz = self.GetClientSize() + dc = wx.PaintDC(self) + w,h = dc.GetTextExtent(self.label) + dc.SetFont(self.GetFont()) + dc.DrawText(self.label, (sz.width-w)/2, (sz.height-h)/2) + + diff --git a/wxPython/samples/wxPIA_book/Chapter-11/bordergridsizer.py b/wxPython/samples/wxPIA_book/Chapter-11/bordergridsizer.py new file mode 100644 index 0000000000..d03ba5badc --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-11/bordergridsizer.py @@ -0,0 +1,23 @@ +import wx +from blockwindow import BlockWindow + +labels = "one two three four five six seven eight nine".split() +flags = {"one": wx.BOTTOM, "two": wx.ALL, "three": wx.TOP, + "four": wx.LEFT, "five": wx.ALL, "six": wx.RIGHT, + "seven": wx.BOTTOM | wx.TOP, "eight": wx.ALL, + "nine": wx.LEFT | wx.RIGHT} + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "GridSizer Borders") + sizer = wx.GridSizer(rows=3, cols=3, hgap=5, vgap=5) + for label in labels: + bw = BlockWindow(self, label=label) + flag = flags.get(label, 0) + sizer.Add(bw, 0, flag, 10) + self.SetSizer(sizer) + self.Fit() + +app = wx.PySimpleApp() +TestFrame().Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-11/boxsizer.py b/wxPython/samples/wxPIA_book/Chapter-11/boxsizer.py new file mode 100644 index 0000000000..45b761cd26 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-11/boxsizer.py @@ -0,0 +1,78 @@ +import wx +from blockwindow import BlockWindow + +labels = "one two three four".split() + +class TestFrame(wx.Frame): + title = "none" + def __init__(self): + wx.Frame.__init__(self, None, -1, self.title) + sizer = self.CreateSizerAndWindows() + self.SetSizer(sizer) + self.Fit() + +class VBoxSizerFrame(TestFrame): + title = "Vertical BoxSizer" + + def CreateSizerAndWindows(self): + sizer = wx.BoxSizer(wx.VERTICAL) + for label in labels: + bw = BlockWindow(self, label=label, size=(200,30)) + sizer.Add(bw, flag=wx.EXPAND) + return sizer + + +class HBoxSizerFrame(TestFrame): + title = "Horizontal BoxSizer" + + def CreateSizerAndWindows(self): + sizer = wx.BoxSizer(wx.HORIZONTAL) + for label in labels: + bw = BlockWindow(self, label=label, size=(75,30)) + sizer.Add(bw, flag=wx.EXPAND) + return sizer + +class VBoxSizerStretchableFrame(TestFrame): + title = "Stretchable BoxSizer" + + def CreateSizerAndWindows(self): + sizer = wx.BoxSizer(wx.VERTICAL) + for label in labels: + bw = BlockWindow(self, label=label, size=(200,30)) + sizer.Add(bw, flag=wx.EXPAND) + + # Add an item that takes all the free space + bw = BlockWindow(self, label="gets all free space", size=(200,30)) + sizer.Add(bw, 1, flag=wx.EXPAND) + return sizer + +class VBoxSizerMultiProportionalFrame(TestFrame): + title = "Proportional BoxSizer" + + def CreateSizerAndWindows(self): + sizer = wx.BoxSizer(wx.VERTICAL) + for label in labels: + bw = BlockWindow(self, label=label, size=(200,30)) + sizer.Add(bw, flag=wx.EXPAND) + + # Add an item that takes one share of the free space + bw = BlockWindow(self, + label="gets 1/3 of the free space", + size=(200,30)) + sizer.Add(bw, 1, flag=wx.EXPAND) + + # Add an item that takes 2 shares of the free space + bw = BlockWindow(self, + label="gets 2/3 of the free space", + size=(200,30)) + sizer.Add(bw, 2, flag=wx.EXPAND) + return sizer + +app = wx.PySimpleApp() +frameList = [VBoxSizerFrame, HBoxSizerFrame, + VBoxSizerStretchableFrame, + VBoxSizerMultiProportionalFrame] +for klass in frameList: + frame = klass() + frame.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-11/gridbagsizer.py b/wxPython/samples/wxPIA_book/Chapter-11/gridbagsizer.py new file mode 100644 index 0000000000..32f5b7a6b9 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-11/gridbagsizer.py @@ -0,0 +1,34 @@ +import wx +from blockwindow import BlockWindow + +labels = "one two three four five six seven eight nine".split() + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "GridBagSizer Test") + sizer = wx.GridBagSizer(hgap=5, vgap=5) + for col in range(3): + for row in range(3): + bw = BlockWindow(self, label=labels[row*3 + col]) + sizer.Add(bw, pos=(row,col)) + + # add a window that spans several rows + bw = BlockWindow(self, label="span 3 rows") + sizer.Add(bw, pos=(0,3), span=(3,1), flag=wx.EXPAND) + + # add a window that spans all columns + bw = BlockWindow(self, label="span all columns") + sizer.Add(bw, pos=(3,0), span=(1,4), flag=wx.EXPAND) + + # make the last row and col be stretchable + sizer.AddGrowableCol(3) + sizer.AddGrowableRow(3) + + self.SetSizer(sizer) + self.Fit() + + +app = wx.PySimpleApp() +TestFrame().Show() + +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-11/mingridsizer.py b/wxPython/samples/wxPIA_book/Chapter-11/mingridsizer.py new file mode 100644 index 0000000000..dc97915cd9 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-11/mingridsizer.py @@ -0,0 +1,19 @@ +import wx +from blockwindow import BlockWindow + +labels = "one two three four five six seven eight nine".split() + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "GridSizer Test") + sizer = wx.GridSizer(rows=3, cols=3, hgap=5, vgap=5) + for label in labels: + bw = BlockWindow(self, label=label) + sizer.Add(bw, 0, 0) + center = self.FindWindowByName("five") + center.SetMinSize((150,50)) + self.SetSizer(sizer) + self.Fit() +app = wx.PySimpleApp() +TestFrame().Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-11/prependgridsizer.py b/wxPython/samples/wxPIA_book/Chapter-11/prependgridsizer.py new file mode 100644 index 0000000000..77b8c19dd2 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-11/prependgridsizer.py @@ -0,0 +1,18 @@ +import wx +from blockwindow import BlockWindow + +labels = "one two three four five six seven eight nine".split() + +class GridSizerFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "Prepend Grid Sizer") + sizer = wx.GridSizer(rows=3, cols=3, hgap=5, vgap=5) + for label in labels: + bw = BlockWindow(self, label=label) + sizer.Prepend(bw, 0, 0) + self.SetSizer(sizer) + self.Fit() + +app = wx.PySimpleApp() +GridSizerFrame().Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-11/realworld.py b/wxPython/samples/wxPIA_book/Chapter-11/realworld.py new file mode 100644 index 0000000000..0069afa996 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-11/realworld.py @@ -0,0 +1,95 @@ +import wx + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "Real World Test") + panel = wx.Panel(self) + + # First create the controls + topLbl = wx.StaticText(panel, -1, "Account Information") + topLbl.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD)) + + nameLbl = wx.StaticText(panel, -1, "Name:") + name = wx.TextCtrl(panel, -1, ""); + + addrLbl = wx.StaticText(panel, -1, "Address:") + addr1 = wx.TextCtrl(panel, -1, ""); + addr2 = wx.TextCtrl(panel, -1, ""); + + cstLbl = wx.StaticText(panel, -1, "City, State, Zip:") + city = wx.TextCtrl(panel, -1, "", size=(150,-1)); + state = wx.TextCtrl(panel, -1, "", size=(50,-1)); + zip = wx.TextCtrl(panel, -1, "", size=(70,-1)); + + phoneLbl = wx.StaticText(panel, -1, "Phone:") + phone = wx.TextCtrl(panel, -1, ""); + + emailLbl = wx.StaticText(panel, -1, "Email:") + email = wx.TextCtrl(panel, -1, ""); + + saveBtn = wx.Button(panel, -1, "Save") + cancelBtn = wx.Button(panel, -1, "Cancel") + + # Now do the layout. + + # mainSizer is the top-level one that manages everything + mainSizer = wx.BoxSizer(wx.VERTICAL) + mainSizer.Add(topLbl, 0, wx.ALL, 5) + mainSizer.Add(wx.StaticLine(panel), 0, + wx.EXPAND|wx.TOP|wx.BOTTOM, 5) + + # addrSizer is a grid that holds all of the address info + addrSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5) + addrSizer.AddGrowableCol(1) + addrSizer.Add(nameLbl, 0, + wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + addrSizer.Add(name, 0, wx.EXPAND) + addrSizer.Add(addrLbl, 0, + wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + addrSizer.Add(addr1, 0, wx.EXPAND) + addrSizer.Add((10,10)) # some empty space + addrSizer.Add(addr2, 0, wx.EXPAND) + + addrSizer.Add(cstLbl, 0, + wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + + # the city, state, zip fields are in a sub-sizer + cstSizer = wx.BoxSizer(wx.HORIZONTAL) + cstSizer.Add(city, 1) + cstSizer.Add(state, 0, wx.LEFT|wx.RIGHT, 5) + cstSizer.Add(zip) + addrSizer.Add(cstSizer, 0, wx.EXPAND) + + addrSizer.Add(phoneLbl, 0, + wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + addrSizer.Add(phone, 0, wx.EXPAND) + addrSizer.Add(emailLbl, 0, + wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + addrSizer.Add(email, 0, wx.EXPAND) + + # now add the addrSizer to the mainSizer + mainSizer.Add(addrSizer, 0, wx.EXPAND|wx.ALL, 10) + + # The buttons sizer will put them in a row with resizeable + # gaps between and on either side of the buttons + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + btnSizer.Add((20,20), 1) + btnSizer.Add(saveBtn) + btnSizer.Add((20,20), 1) + btnSizer.Add(cancelBtn) + btnSizer.Add((20,20), 1) + + mainSizer.Add(btnSizer, 0, wx.EXPAND|wx.BOTTOM, 10) + + panel.SetSizer(mainSizer) + + # Fit the frame to the needs of the sizer. The frame will + # automatically resize the panel as needed. Also prevent the + # frame from getting smaller than this size. + mainSizer.Fit(self) + mainSizer.SetSizeHints(self) + + +app = wx.PySimpleApp() +TestFrame().Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-11/resizeflexgridsizer.py b/wxPython/samples/wxPIA_book/Chapter-11/resizeflexgridsizer.py new file mode 100644 index 0000000000..caceae08f5 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-11/resizeflexgridsizer.py @@ -0,0 +1,26 @@ +import wx +from blockwindow import BlockWindow + +labels = "one two three four five six seven eight nine".split() + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "Resizing Flex Grid Sizer") + sizer = wx.FlexGridSizer(rows=3, cols=3, hgap=5, vgap=5) + for label in labels: + bw = BlockWindow(self, label=label) + sizer.Add(bw, 0, 0) + center = self.FindWindowByName("five") + center.SetMinSize((150,50)) + sizer.AddGrowableCol(0, 1) + sizer.AddGrowableCol(1, 2) + sizer.AddGrowableCol(2, 1) + sizer.AddGrowableRow(0, 1) + sizer.AddGrowableRow(1, 5) + sizer.AddGrowableRow(2, 1) + self.SetSizer(sizer) + self.Fit() + +app = wx.PySimpleApp() +TestFrame().Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-11/resizegridsizer.py b/wxPython/samples/wxPIA_book/Chapter-11/resizegridsizer.py new file mode 100644 index 0000000000..ca512bfccf --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-11/resizegridsizer.py @@ -0,0 +1,22 @@ +import wx +from blockwindow import BlockWindow + +labels = "one two three four five six seven eight nine".split() +flags = {"one": wx.ALIGN_BOTTOM, "two": wx.ALIGN_CENTER, + "four": wx.ALIGN_RIGHT, "six": wx.EXPAND, "seven": wx.EXPAND, + "eight": wx.SHAPED} + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "GridSizer Resizing") + sizer = wx.GridSizer(rows=3, cols=3, hgap=5, vgap=5) + for label in labels: + bw = BlockWindow(self, label=label) + flag = flags.get(label, 0) + sizer.Add(bw, 0, flag) + self.SetSizer(sizer) + self.Fit() + +app = wx.PySimpleApp() +TestFrame().Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-11/staticboxsizer.py b/wxPython/samples/wxPIA_book/Chapter-11/staticboxsizer.py new file mode 100644 index 0000000000..76cf4f74cc --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-11/staticboxsizer.py @@ -0,0 +1,45 @@ +import wx +from blockwindow import BlockWindow + +labels = "one two three four five six seven eight nine".split() + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "StaticBoxSizer Test") + self.panel = wx.Panel(self) + + # make three static boxes with windows positioned inside them + box1 = self.MakeStaticBoxSizer("Box 1", labels[0:3]) + box2 = self.MakeStaticBoxSizer("Box 2", labels[3:6]) + box3 = self.MakeStaticBoxSizer("Box 3", labels[6:9]) + + # We can also use a sizer to manage the placement of other + # sizers (and therefore the windows and sub-sizers that they + # manage as well.) + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(box1, 0, wx.ALL, 10) + sizer.Add(box2, 0, wx.ALL, 10) + sizer.Add(box3, 0, wx.ALL, 10) + + self.panel.SetSizer(sizer) + sizer.Fit(self) + + + def MakeStaticBoxSizer(self, boxlabel, itemlabels): + # first the static box + box = wx.StaticBox(self.panel, -1, boxlabel) + + # then the sizer + sizer = wx.StaticBoxSizer(box, wx.VERTICAL) + + # then add items to it like normal + for label in itemlabels: + bw = BlockWindow(self.panel, label=label) + sizer.Add(bw, 0, wx.ALL, 2) + + return sizer + + +app = wx.PySimpleApp() +TestFrame().Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-12/draw_image.py b/wxPython/samples/wxPIA_book/Chapter-12/draw_image.py new file mode 100644 index 0000000000..12ae522581 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-12/draw_image.py @@ -0,0 +1,46 @@ +# This one shows how to draw images on a DC. + +import wx +import random +random.seed() + +class RandomImagePlacementWindow(wx.Window): + def __init__(self, parent, image): + wx.Window.__init__(self, parent) + self.photo = image.ConvertToBitmap() + + # choose some random positions to draw the image at: + self.positions = [(10,10)] + for x in range(50): + x = random.randint(0, 1000) + y = random.randint(0, 1000) + self.positions.append( (x,y) ) + + # Bind the Paint event + self.Bind(wx.EVT_PAINT, self.OnPaint) + + + def OnPaint(self, evt): + # create and clear the DC + dc = wx.PaintDC(self) + brush = wx.Brush("sky blue") + dc.SetBackground(brush) + dc.Clear() + + # draw the image in random locations + for x,y in self.positions: + dc.DrawBitmap(self.photo, x, y, True) + + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, title="Loading Images", + size=(640,480)) + img = wx.Image("masked-portrait.png") + win = RandomImagePlacementWindow(self, img) + + +app = wx.PySimpleApp() +frm = TestFrame() +frm.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-12/image.bmp b/wxPython/samples/wxPIA_book/Chapter-12/image.bmp new file mode 100644 index 0000000000000000000000000000000000000000..bbab4cd3b08d22098ef8419a56eb3d3fd1a28c4f GIT binary patch literal 57138 zcmeIb2Y4OVdFMS~rzlY(DUp;|KoY(8-h1!8cU;^K;G#Ez015WqtJqYiLN&{FymnmT z*iP}LJIN-oMv-q?a_loUY@5I^OiPODfCwfPY z+J_HX2lrWKt~;i$^iN;zXTRq~$IK1K-j@dEUL82_#vnJd3>ew$W2S+$eCLk3n6n0xNnZ7con?6V5#P@HYLVW>@qHve zKMo`3oB%l^Ffw}FK62PLbifMdg9`x=Cq`y(4eWh+VE=1_2i_cl=}f&n=Dr@=u+cGN z;aBh;0AW9VQeb50%$f0clz8+7b>=N)x0{nlIKH*Rot;-!~hcu)Wq1VGN5Q2^WZI@G&&uYLD!+r)%oY!C#*0N0-P-oskMPGi64-FNwh3oIie#@=3GaY?PA zNCP;0uYS&ckzUmmi{p#XUI;&f5%a)+d2o=u(Qb!-T)YH2rY`ic37DMe#j_YaW*<2u z%q9gBm5Cle}9kN4wqtd^-Y<%Uj1rdRv1EP0azLihpSNs zLLG|nOf_;Qh6)su_kyFh*hBi6Ao%jhUBtuR#PVMGCB>Y{|n zc?pw~I!tiSaX|LHqWd6+-Wfi4cZff+yXb%G_&A)|W3yp&*+z_xJr=YH00A$YMGFYY zFAXghMqGO20gN~f9)!Jn_w0fB)yVR5VPd`a9tY?Yln#ms;GmVbKwxTmS~UQoKo)iy zUk)5Q##zuo!xrh)dr}I(#qmXeKc1fjMkXd;CsYYst$I)GMLbG5=9fiO3djg;B4L7W zP6&%V2HWBHhB-!|?71c`RfMbh8cqPEZF>UFckQljh2M!l{zxc|z#Q5Yfb?~1S~7YQ$kpZ8b{M!QI8 zf)q9&!#Co48RcH2cX50d!p~p?23GzxscMnDBkn58Kj=W^ECUmqVpvOXm(2#}V|VFJ z@$|I%{^32KAcDmAfQ4gp3Y$QR#WLR>(__oB)`g@z8%R+w;kScx0vf&@XZA?8w|vhL_o=D zWho&8Oz!EC?rxa;K8)XUbBUSQLX1tQOmG z5{?gI1c2Pbh*Bahj9lrzr$pWyB8iEuC1Y+%h3QFuj7c3JX7eJw%8FhbU)Xjb{46j6 zGfz%pey9o%ff0hPM~~u(D5rx1Wxt^jU~+6N;gS$p#ny6$Wap!VTZzj?N0lXp>bZvz zmEE)3X&W2AQdXAGAWn=3J#t34B%D=BVvW|!rkmulMF^t z7$Yzuogt+}7U^9aU)W=T{46lya8T)iL#_0P%5e*r96wI#jSaDbxg|^{oRQ&Sm6%id z1rRA#)EQEiwFrO=4RKF}AhZTQ6fluWM4W7v6E|-P zm|VF+*&zlS3I$i4J*Yt`2+l`?khz|nMNNxf*O4PCe~o_u?;)aLdoB~k*w~nGSez9g z!nm^8Tqc&dSY9t4inlIPlbBd8D+_?&XmECZPz$`^vr|iq&rV#6jSHxUA-|7tC5mBW zuAgt%P$ir-^mH4o!d1s@$9Wg#76F7sdKbs{qwq5rfy0e5NK5G~aV>!qS$Ru=R?S<(jl?$$)%3tehqQ74hdkhT$CEcl)7*RoH;iump(SnEhi1fV-Y6(9b z6N@6Ti+VVhv$_FBo!AjkDkj|aS>d(=6E-eDWuQdJ`0MHZm-Iq1RXK+GaK(OIQQt*+ z7svM_@w3n)7$K5-MTsDDF{m?q^;LlvrgF&H9Q+A4D)oWx!1Mwd#D~!@XdF(VILt#s z=HX$njf_~v#xS&0e3-Kz^y!kHsf)c+=f&(2Rbn?kmdg*p$jC99+N;WKJ^Twy_L#ZB z>`RWhI|By@WW7Di!OTs^p6ia8oBjJQDBrPJloW%KHF%l`>_IgLWUiGnRoF3-_75-M{x0 z$J`r^{cjF(Fmt0HdS`DtFfw_B5D3FP_6dkJvH#WS9hUSO3APLl>Kg++GGd16$w`}& zUKe!_9MIsY3qhVJI9sCSj~^*#na<5M8&#Wp$$MjoK+qy9-__$Zd>=;(0q#$)a?|0nAB zkr%7ms(U_gnL5R@=AU(4&zEh^PkVd2>zYSCW#M0{HawD2*D0RGhllfA^=ST7XBYmU zM_%coj@v$Pf10Eo;cA9!6!_+mcU#Dp>TZ&t4)suHr;2}F)TyUGd_&jI)s-J~*~344 z%s1SV`=}*8Ec(^Wpo)+--rUz=%*8H*Tnkbi5CA#L(%}{9Lz=3|R13@+RHg zz@So@LHPjMKvU_l=H}+c#>R$*2KGb8jbmr6LSkH!a~0)uMKK}kYCqSH9%Vqw;PPer*|ThYr%v${sCMi%4Ii}* z95mTyyUe>gjH7MF!S)wvE2>%J@q!jorF6L4mZKaj?Mgg;=_p zk)=!P>+7L{XH`~KR>)7!?k3}Ovw5b)wzs|SK>CQsbn@a=cs?TnF0yiNm@1j`s)x2)utmydS++4M@PE{ z2MrEKcV8b!9DeDg{!5o^r%zjt9<>}kY&(3o52pZ+;M6G^wh(?+eg426j9_9hI<#4@ zOTTmpBZ|xJbFoQh5T0_nFWGlr>7(Doc1=!u zzwY4rfqf?X?k>}KyJ4ugy|2zV+19_mXXJ!s@~oWgE&)PgMsC~~c=1Kc*|Qx74;qgi zH6Jj^zQB%IAF2v>F646YySw^ljY9`4n2wA-NMWNJl|X=Arsp#sQ%n|<6+vp|vbbQc zW#q73%7pHY!N%I|vht>)!iv0tl3YHm`}TDmK5RL0!hZCq3Cm|-ps};FvaYVWu8y`j zu3v|3fC)CUipB_}eAxJ6Ny3eEH2|SY%gO{5JS!(BCrf^+jfJ(AVhC&rA^_=qvlaeFLXXF`eO&^zvNCta!0gGlIL`10Qd?49d&>^C~*%>8>!eN!g<4wwyT&@weu-P>E(++0vy zod?gAm&1ECwKc%mc>H+h;ls_-)AUK*z(B*`VEgXfW-4-z9pkqKnYJd!@fdz~G4}ie zfswb~5*We!Adod*&H#{kQ?BO!%5}`6=@yy?tI(NgX=$mcsb!tHh|un-di%k4`fcKp zZ5oW+aNuykX}wcDhJn^*Q*A{{ab9IcReN!3Z=HFnec*tJyA6Pmix&Z`YC zW4Uc@#Rfw~PY?ZpY(z9U4)t`6HB=jlN?LMqtI}bc(#HIf+I)DU#9+v8ZcZsFiA+ok zkBJEj508$HN=S;&$WG7C&+nuN6XWFCwP6;NAjGX0#wAxDORozfunp`7rRsx#?VPCV z7^{U<>a4}!BBwSbsW3XVBrc;uFjY=zdP#kLZAW>Vt==@&j&vP5WJO3~lhBP=0zxLR ziiMn^&sd=55D`k1a{;Pn_?X2$*U>pzU(u1DR+NyC86A}v7M&QuC$qM;u&u4Kr>Cx` zr?RQ3w7fh!Co3r>F(oZIB_*Y1Xb3HACBQ<7(Sqp(APOT$B>EgOp&~RiG$bS>NPc3o z!xQo%lM13U$`f+yQp>yZn)=JTChKem+mIpF@hNt`9__#~tm`f>sLd*A$}MZn zhePV@_Kw}Vt<3tldUXP>yK@JCI4)c;@88eh!bKPct&SST*D%>+ooz=r^zSn{W=*#7 z9$?!wJ6mP77Bn>p0hp1Ikd%~}m040=TwaB2sA%7}uVwGv>cPRn?r!8{QAbCO-QGGr zZrr;UF75ibMd@G!3C5tPBs=`c=%{Lz4+RJ#23zu@secSNfia&cUtA&Sv}~0|Ntt<9wsigA?*2i`%o>$E)p!+r}?jcE8v=drQRYFdhuUEsdtC z+{%ool(5vo`24zzT2o2aD0I}@_U^^cf_u#<&9SkZ#>P-ILQ+yhLIT_fOuEMFhfWzf zCaR0uGgFFVL*oO2WBdXmeWQ}XqN1Xb3JQ|)^1|ceef<3yQ@;Sez+nHtkbuBo+7+19 z(o$-*HjIvT?%9J1#xPbv?1j*)h((kkT~SFfF)_$h9>Hysi=wk@l8Rb0^PAFg>XIQm zG|@jIB`_*IgtN%}nAC{GteE`jtU6Hwg_+|L<3b}s zynH-8JUw>p+7(+|oY~Y=H#}@Tas+#W2Mv)IK6h>*^db-tSx5sYg^C?JcDTE{Z{NP1 zytoG)aCrvyezfq>F1Xi87ZO=~bzcJwz|r#j7(9j3{)*8ZA`&VuZ!l-P{$ z;NalMPjc~wNNM%zpm zH>5pH{r$L^DS3IJ5fOfVex81w!4W~R2{EbZDL|}ccD8+PuDGWsp|CI_H8mhQIx;N{ zq!c47Dp9jduphnpQ9ob=!v=LvzhN7TwBYH}9DL|~y!*W4`r|sgM0kzH!`|o-xRm~+ z1L?iUw4mIEltxFXXBR6Ga^AjFlk7De~`bgpDzM1uB0Tjy1KBVquOTcpj3uZ z0dhSbMsKsBIrL;`i=l-+QJySrh%!I8r&q9-Z>2|IhfjLU|E zA`?R+lR}UN1@#$q=2F8%L;skgDk3%x#H>MUe zrxi4(qd;-NVzXm6++3GsO6?e^H;gx#rdv8k>zey23L7)xvmC~Kv>MUwYjvoggWC=eMBiZI`?aSITgU{re@ECOIilIe6_(ysLM0-Oi-B@ML@0_gZ zKi(O>FHn0^3$_R2vD)``b&oexbmk`)#w6xP#b$-2mc}6@{Tlq-Zn}96`?t;x;oLR! z^<`I9hQ`MFhlFg-*sQ&+t?gM`Fp)NP#b}(Xudx+mRVN1L`>i&w(uOtHwrptG&UUYu z#JGsah|utmz~BI1KOYZIPb6VbQc`GYYEp4=9{ttZD|8m7-2&)+@|#bt7+Mi&i)=PE zqw!Jem<=fU=PI9b8+3C$nuCoa8`9133~pLkTyjwif-yWH7?uu<@`*|bf!Knkj5>RX zd0)%;d8_cwW@glkdzt}YQ7hzXNnNS=Xt8~<%SV^F?!Rn!=~nymF*V^aY2mS{5n*9r zsYOL;HAQY;bzA0Gwyk_?U_^koub2Cd?K^kw^ziUVC@sxtZmu5~upT&IKX5?Jm3utB z9mbAab8bLyzy`;LCBsWxkLJK_$Zd7&>aA&8Q%Ymem{q3yMn_5ecvZ`A1v;+UTu{=U zh3ME|T<3PkZD;@Xy5SP@Y%|dtJW~wsgxp9ZzfVw5ctS#AK4Fc<8jGc>ySuEpIXNpU zFenIsprm{wJbc1;1;luTB=|;WhG5HKQSY#C)2?Z2``4ygi}Gt~64KK#q`iH-cY5r6 zrtul=iniADbX<8H{-*Kp;W99in+rO2VjqTt1V%?^5Zf#%L5zQFj9?D~4Wia!up~_Q z^FuMxY3f|@uPd}Wf;qSLZ7uC6MY>`R!4>Ecxp`xRly+v(ht`9wC7;gHexlLs%}1&n zM+}y|E%o-2?Am0mK`trFHpCF3{V#FDWy8yZ2V={Po$1BJ!I6;|PTSMAi&MwM*>S4EklimHl;DFtN)xxMSA-F)!T(73~}CAl;v zAx~)4u=v2B7(c&ouh4{mn5;0g4D4ju+eE|!NoH>)J zT|mvtZJrR|{_b7dQi|eXNX+|?xmfK_H0_{h#tO@d&8eG(wD8)1*oUVo4x)upceQ+;a^%#jSMVWz(KNSkGUvtdttV}BX(3JeLKVGlKk%ZHam zPlOou)msm=)L4rUgY<@PP*5;ol+@I;l9Iy4#=PokoXp7BSQs9~N6Y=AJp*IC!&3ud zvO}?2F{iUDQ#SwFM(wZlR&6qG4bP4f81WVu*=~`Hu}5>;Y3q&x+URK+uhq!Ibj>uX-3H;#(NGjJYV z9`R}M2shL*^a{Bh6vQ~6blSt@KTL1(+Zo~!pU|Ja+Oax1 zFWR@wSNoBCG^bvc+ov?`_cZPIHSJYxrFEr8iU*Pt>eT47=QunZ?&uM?IY47W8qwAh7dK%{%GKnf= zW@ZxbLD7Rp*PS0Ym``urWVfL7Z#3U;U^+9!ovge1D|VsZjEWp>Ymk4RX?>U zV$-&5+ZZ5*n?c9);u<_$sCfGGPisHcv{&?dE*)69sd$r@j~D9FKg@s0PnT%_sGq`$ z@NDypj*AWm2w>2;fNsaUf!PQVtA3bI?|goKpj%vjf)S)Bu@1h$DG@&qZ&G%M|dpd6zSnq=n_6?=ic0BXBwc^xY z=x0|9Er;2*zxRUplI`c3c0|+0v=vvDZ@u~a^Y3jGU3WoSVP3I4Z0nAl?)3jI1}KPt zOnO#L4fay+i4((@FE51N^1bEyQ=AR+uJsPh4PElHCHnVLjB97Lbr;rczrA(MA3Ool z0rJN3=X`@ay#hQue0TZ%s0bD5}D;2-(w zHwW_I0vH0)uW3Stz=40KEjzt5Zz6T+*OzL4sc9^B?rhtpd{5KZ;6@}BPduir7+jHLNU}_~lh3X0F3GJ-k4=m8 z4fcBe)FyEUfaYwH=ZJfGcTQGKVoXkGRAx|Evj1k|v#ztQgC|?p_$7D|en~4xEUe8= zPfu?gEUC2?KJ$lbF+#K--n$_`aSwC%^79Cf4SDA4Pm9MPot%#gZBGJXevy%W(a~%v zm6cV!y&bI5#w?E$Cn!khwpb8Q$PGU93?KMeOuic*pU>p#7>wX2k{01l5vad$g9s#% zE;bHavv(gT*(EGY4SeTZuTTv%k3n=cZ*%iz)CaNxj3{xDUz=ImQ)U=x4*lIgaq&fQ z@y=oQy6#G(Ty}MGR9Y|q@sILC!*2NUGvXRHdBd$u&-;dYcm?j<Ob@eOhD z`jT}3#M5tAV3;30lUtuklol^BXZ@J!yde(KNG2#g>Goot5xg~R3PvnxD0bmuj9y}@_&3p_2s z#H)ki;{)U3{9|I0D=J8~Hcw5Nj~=xhJJx&jXlq*=8W6QY5JnhaOi1kQ1t2(s06|n< zso5NIUO5;+O(={Ictog@!=gGxuK^~@bNe=tVSXrb?y|m}JBS;Ojd8=L|7pG6Jk+sl z|I?OdA|fNvm0$$(2~#SkGQGO9q;sIL=*?_#u~RL2^zT3e5-`L{CxnQPADtDl?T!0@ z@Qh)tPpF4y;Er8>?%vJP(B%$)=HA zZue5Yt0qp0d11H3gctGB3JDV`RZt~KUy0Sb7pHIX`Ht=miWY`Xm?;1=jJ8DX4sm-8`229stM1w_#3|ulAXWO7dxz{&7zvK|U;0xiwEw5G zD;hS2Ck6#X_#(SPq5`+qZ(Z(K{#4(S;^u6~z+cy$S^jj-+8IK>kwqvh%&D)}F>>wN zlq>@IPACw&Bx&5&kRGsVVAa}NYnKhkFcjhu&lfh3Em>oF zBAN_O1}1q-xgoE4sJ!=B+w3cS``;9kUntRGiA!oe>12>HA0}v%oG+v<`{gq2OWIRo zPo`K?+K<)M?ki83h<|oyy@3BU$!TBJAH?G}CT;{H;Smv81qImO-ON)sbcnPFH(%iR zc8}VZ{!;cc94_0xYH&3!WmHOvH`X%=_lSs?I0iZSg#RO=4%mTE{EMYHc{TPT(5xg&M-g`J6_8RQtMAg~(4S0GAFgDc_%m zoF6)7rZi>w_m*i4IvBa4-|d-(wRkT0?1U~8GUJ#0o73o(&ss6G5){Ye=7y!E1#nba znoj`DZU-ineSIY+6RuN6US4)VL4HX|WkW-Y$z)(^`GEtfqr{p&a%oT|q@!HGh?p=X z3nQs~6Dzu_W!Poykaz=vb4hkwb)X@pOORQZo#j_}F}YuB(mBW3pL9rcQ6lb^a#88j zw8F%a#=JIr9c38n{z2MBKhi1HPHJ2GHzyL<$O#Qg@lVK)@Vc}^^ad~?q$61|Fxe+C z+K0GMWJ>VUf8sQiWmi09dwOvgh$4)tC47jOHEv%9VX9 z5;9{*xbvwr<~0wO^&W4XdBr|+OB4X_mP;q`?g_Lr(&x&$m3> z{=tnFY`2ATA-HpuD^u?a$0OVs|p(wea!X{N1fOv6K3p z(_72QYxo2Q`-g=E;Y!EGB5Zt)`-sc_MZack`%^waUb}pD;F1JK2CVt3HTq3tcfGKC zWB2abtf54=&%22>1B(AHf*T^z@=1vl{`{6SsJQ1#+Om;l1w93W`&nn9)9w3iI#(Rl zpY?3{df}4q+7S{Kl9-gZ?i=g$XU*srL}y1QmX=24X)c*oCJ&xJkB6dy{7qyFhdkjIp z=Rd#S#PL<_8Qa?E;*hZ907B?HZf+I9qMu6TEBiLE%!hPjXktKIPQ(kJkB+Qd3K-s+bgDA{xouYPsyd!pAq_ca!w{zoC;BW6r`x z^$892V+#ohi;j+qkKc7_mvFm&CdHBLfgMTPJ$!crg!zWYhj^dy)Ng`HmEx{tx^nx? zEh6lIaflClUF!PF!bM$vd701buG~GTc{kHMzA62Sx3yJ6t2(BedL}#cKmpF+gx;P_ z1<#5oeF_;zDs|W)8-GT3`no5BYcS-iO9-Irk1Ip0gJ1|YAv={h?T`shnAks zmR3|$*w9eVay|R^_g}bxhk{5UV~7tzIE!iNV8k_HP}OGRfMB>1&caEdLR(m0@4N#> zNS)}*q#Qm>I-awFsos2DWJ%O`Ny$%dcy#$o>bt`_lTzf-X*}q~(;kL-!kS9O8hKP-TiPOLiGXxM1NiL2d$>{rrr_QKOotsb* z8(SXj_H#EeQeTmx^|v(bJI;U%p%q5tQ`&aJ_Qd4mgw)jdw6v7m+$@O^s;v93UL9m@ zZK~8hjNYNk=iPoL0~8p>k{`DBd83bBc-vi!AU%Lc|DKeD0Q0XUMj+(t+UmWlQyUX9 zOHwk6lfei!dGkn_abJVu7+u;kbl5UDCl=Lb>M=b`n2UMGOt@1p!R`VnY#d;cF$&Bs zEWcP1@wu>7-(Dp`zC7!%^!CsyuUt>cQ7CA{(PKJ5D|0Scqk~0kzJC&w% zskpPBBZ{gyf@OG^UI76lt)i3S*Sx<*Nd6z(6KI=iH+lzp;FUzDgs0aeE&Itb(KCOq zw=npopHL!b5N^w0feu2EQ`&0#s))iM()4X3)wccZ? zOerdg%gl^ON{Y?MNGdF(0J52+#)%VDsr7>qS-40|0y+hZU_{Z4^uKaIuv&3X01>ts z)|4pqmvePRB3P!|IN*C>+_D1vJMV1$6Q^GOqTalX))%6al03Y<$!=qDMJ0!26erhp zmD#4cI!-s}wEQ=5G2%UUB6;PHRtW1hHwU4MZE zt9>;P0qP~Z&zm#(FkF}M5xx(*rK9$zu zvZjKZ^0e&IREd$i`u^gs$y(dKc2WL4XX@WW?YCG`j}Z}XsQ@NUZGzneG{h!f^+I$} zEXV5TX&-A|{@!w-(GUVo$+@C`MM_3Wc7AqIX(2PBnp#>qO(ubnk3PQEn}>AIk=~Z$ zvU%7Y9`lci^2XDoN-ZM%*@@?bH}N}Cv0l(G+t9HNLn}NknBwI8s>~gq*r5-%youXc zH|?u3Nc$(62J7t;0Kpgt&G$u2*%-RgS!RQ+KtaX-k7+2mc5u56_`(%buxCO>VeIxG>Id%*gl3iU*+9o(QHkdlG z`1n+UXw)R{-%rgd@nJ9`wzFs9c`zcTW6L+-sP`QJ3Q;&jg$A`fXU-sCfddHAfphva zYDh#8Z`~pS2CO3AiPZZ6DJq+{dSFdlS{gABoLRt5kEP_sQv+`vZ|~h>cXw$hGtP`*{94#8)oXfM|Xyf`LFxh(;}RUns7$>d<f_HRi*Xy70t~Q z@YpY1qD~$Yl;Xz6&|7`P9JDt+@{5^*Az@2&glzee;icuK9!ifkeR_-D1OH2)-u(}@ z#m_~TOyoXsdv(f4JoVwtmTD%sQ1?qsQP*@$&rCh@P5KXYQvl42GbZMXx%T5GI+m3y zSl~sdlGg`?Z}O6GPxS5OfihdA$(t}{+&UC_jRZc0qymGi49z1dr;HzgKE<~61?^b_uD8$D+NAjpK-R~(za z`Melweu&F+zaH@^6$x1n&t3TJiOC5$x!F(s&3(S=(!r&rz4m8*{Wl^~VcAuK)&lmielceo@3tEmbGp`^AwzT%;Cl<))xTmKFb{eUsvkp_m7QD3lZB~um}73EhSxbi!z#GQ9*?ibt>3<>$B{Iy?R zs~y*fB?g)UtLv*t2b14tPfMuSLaVC8D{;}s^gxNJL`3^vmG(1!oi*PU`~^ zn-}Yu>M3F=XEg1c6jSJH82&e;)r4@v*vs$|(p|cuR9ukc-S8(H#C?dvFx*Hs0EH5n z(eJs!vdTX)B041{EjJelrZ_}3j1)u7fyO1jTp|P}X2$&(@yHZ43_Od#sjB7J{#j=v z&Dr1>>gBS7*G;Tj`cF%RMLH)W*k;q_+?HIb0*K2IiWflh@PJXtR*=&t-o+_KN+eC3 zTmeSJbm^nweT9Tp2+kwERL<8rWMo6Li>0LH0&XI=A}4b(A!zu@6{>U1v$Gx3gMtvn z+mh|+jez<%AIcKY%l`i4aiX)cnflZ?I0#51Z%G}>^%J6_)|u9+a+Iy!Ti1Nf842Mm z`a<5V;7Iz|Im^%)W6W#uD}OQ%M+8HLwGGw{r0p0E=nYGV@Op2@(qAmmKCS;&_z3W} zywB5)r;Uf3`wtkHN8dYZ=$kVR9konew6n4ba+`5^485k$9N+o30XmJY5g*nPJF=;V zi7zU`B@7=+UHcswT~VEY!v&)Eh^JGi6KRSBl6;U7DtpB!7_3&YSh4gql(G==^QH{{ zUh8K*-~()&HI?<`51$lO8E7>6hn66aG3jZ^-l(BtCKd-^KXTGSD1af}EnlnjF~%3~ zKL0CiI=wtXQWV%25uO~s{=)iIe>`uPXw2s{(cxFMjn=IsNhzkJ{)5QB;@SeQpp&<@ZZ6&046nnvwqcQ1zr6T;S4QEY&X<);60r zQ?Y;qKpBw~piVnyI(f@qNjm|TnVbAndbP-|3C;hsH?#l5Qe6i{C~1N8A{NLK5um90 zjP2PUZq^@--!ZIZ^pqnii7|o^w%pdHpu6!RBag@Q=kmEU01JFVa~pN5G1klGe$sAj5B^N>J)wkHKBPT2wE?h;C79%^kj0xR=G6(EhNk)otQR44lT zlgP_2$zT1?G8XqWsSX$jr*XKcw#5_1uq<==RXW z+$g5fL{d$i8r+Q$(5G(?YvL z$p%u|hc+Q{MJYZ7s7$Y}eY3>7vZjhs_Ck&-;kk_zto<-xz>KUT@-pbm+iWT zk#k~+l8;9(ro!rN1gg{#jA0zWap8>&ZcU()M&vZX99E9Viio z(`f}^x&(c~S=@rWLW#)h**{ydo?7U{yeMW#u#ybcFL77W6D~5lji1ZJE?rH002glCi`CS@nx6CJ8a)-|Mw)6)i;X2djI3iEYkGT;{QcwwaJ}X062J)PVDSw$4iGyG5PF~Hi5J{B#CA`Q7>z6h zYOvc`UBq_bLi3(IWmaouLxb0eFdf1_(x1MpcezJ!u)qk_8dQ6RhWbQA5ET(U?CZPq zAEbYc2$HlsoAa!y%N1r}xHq)dSxOs^m)G4X898fW0V0)6b9G%^PhEmFA4{rl{`&OiKrs z1t!G9{GK5p2tda4h21;ExH}ci3foF|FLy9P*dIGz`6JZDrJha|;qkwh5x*Pypf4F* z;u+x{ksOp-6jx^{={wMkmF02)=9648TOnlKw2KZVwo~{W5bfg=vdbq-RNe3N*s=Pn&g_!B3Ab98yMCvqCwWFPDH#n7OjB*1oHUak zXId!ry|-@B5->u1UM!+3-+qhv!BV0s6wf<5)Z1<5zuE?dVZA=|$iR&oEY!pFVRDx# z)3rKA<{{lDDV)g~Z1^K=!3hZ=iHZ2{eu05&e#>dl%BHSuT#Nh>o$u)x6z!K@n#k0% z?(s&_2cst~N-C~C#qGSki(anzpbw_6cpB1vRa(Um9@&tC#}Sf{K(Lg`d+*i|?LQ>zzOJ+G`pWgHper&e3a1z)%ed@(b*G5K z<2B<(jp$cC+qs?zq;Z)M40nUA+;PZ&68RuXH@b{@r+1k?mcWe8!p2Nymw+<#2%h`4 zFF6B@1QsM~`4{>yn>#Eq00#5%^U|1N%Dmm@#6>_-)3ool> z2@a~TWc3A25*T5jX}N-~Sjy?B9lpXa<`nkTJ&dSD*YRa2_Zl6=9~pV+rGAzIJ9)Bg z-@clW;pIPZW)dg$r+bwKGpCriwAgSN5xJm* z=tdH_7^shW&mCvQD#vo6W3lM*{LM+PqWaN$gW^ z@TRPdfv-NVKgheqgHm*Y!Rw?0NnYjLo7dwy7RnGRV|F$!nen)TKbMHUz z(-Ioo7#r4*6kVI1Qc;vvRz?XxTw>z$w_ng*lB4>?VM$^5-Fzr4FRagQv{V?znutLS z9W@J#@ESO|8WjzWJ`=s{=gw3Jv7Pgx1byY%mH9*YDC^xX+F65z;#e#+#HmmvQk!th zZy(Sj3#S)ngw6E!@vUEx)5;hHHe!s|#pZK0*t&1lx_`g@;K4rLAPGif7K!W<57n0` z`+!xLSn!rG!abx&X)vE&?(mq8Uf*@yX>0vz^p^M4#E+zAj2Bj2ax`Dt-SCA`y{f?( zWAqsnv$|N8B)%qlTaSmRI)>SZPLMWr%8mH^Bvxo)5}B|<8yXT1CW`nlc^q8nL;7Xw zhMq2O%g?Gvp-8*9Ij4P~mK7Zz_C#ES9s>fpdQUz6Q7&<2JnH`Cj+!ZQJ9E6E?lSNiTJFTBjl9A%v#!yYp*UN~pN4 zzt%L>>NwCdeAF_2$__x(YE-Jz>PG9f|B(!a|4;F(_2cV{OhxL{<9P-u;wLq?ktGr15j``b6thvNBWmHClby*usbvAwgaXyP zhxckx=zB1cYUKfXAO4l=oB!kVri^4Q`yb0(<+UP9s04y!s^udqm{+)BaHT%1$7N9K zH)X(Tk3Q~Mmd_WlOMin~qhCoHU0_252tzgc0?-_chqXe&XPOEO7dgWKmkqpM+J1mX@_P zcJAMAp^W76gHhY}7x1mkwil z@aIF8d~bq6F=AFf$(VnyRnqyFW?w#Pa7`cdhUa1E}pP$dhamv@(7 zBjJpoH-#PnCU@?Ld1o)Z)c3~Oz;DI5{gGSzAG6w7Hy5ayH-QxD;sDFRgJOMvLx)_g z{h$M(N7QRlmBsau^vHh>y)_p)p81Ik=3`>vBfla?>XE~JSXS-+k;KR~F_bLJKmrc+ zK@=CY4%^4P;Y^1y-0~){cl*9NF?(^Op?j>61=E-g!-B?-bl6?}=JT6QJBs_fCT{iY z#QM?Gmcb*Y>`x>w`^7TBOR^0bVR?Yye4Kiy*w4sWZy@@ca@xWtMD}Wj-Lu(j?!^aT z0Y+A{l%=g=YN{%8b^7dxM}R|PM8&&WZui9(g}RZtM(~EL*J9QQrgho=vJKynnN!+; z;@c;4tnbQJ{hn026wI)FOX^lc2TB%QOg91_)olLcz_q<7==E@TcbLtcW^jbZCgC7EgRVFfT!3uHO`v?2J)02q z^3_@-o;b_w8|H)(`Vi3%xxhFb>nay{JiYu}Q2L)wZ%c2B`yV(b_o)P_G%i1qhP2cF#x%uOa)A6 zF*0%~Yn=<@Ltx86)7HOoBJQBJWyD>K@ANcmX&x}JS%-QSIKHEA+)VxL z^40$;b5EdhbcN-`6KHk@y8n~cw*R9{%DY%g9nfId4{oHvAo_2m-2S?@?beQFM<+!{ zKtp|8qx``53XH%uZ@t9@*v~{PMX@3r_0BtRot_tvXQ7L!h?JwKTh)%&Zu!$KqObl@ zq{)O%`H{pad%Et2+Vbx&U-kE^R{rhE)!$#mw(9#UMI+g8BK}phdC9*oar+xLam+eh zBkSo*u~A?t0itFWizKGZ(Qp7#fCflm4=-W<(Gt}{(NvTO+3;JpC|B;?w@-hYHijii z^Y(2qAs1C50rm0db#)*I5A@+Zn8>Bz@2e`gA)ujhf`r=mE!f8}gUtUD^cEj3cK?0% zjeqy-3gVVZ9x`5R2;?7VZr^iT`}MVvUkq-)TjP=jA4G4)n*~q&%Np#Q=l^Cao$#xS zuj$BC)Mw(wq>Qg=p5F~|jqmiQ-;4QH;j=&9vhv5P6_1HM{DuIBEq|ab{m#;j-`F1g z<-Fp_;s^NoG2;tH2>yczu0e^g5DKP83XT{R6~HBItrDyR9uW$=vNf!7`5H?4!WdMq!sb-r3(^NEt$q1wo=Ca?SUhWHEV zVxA+M14ib(1503}Uxc7V0D-*!pg@YKkRgm<*D*p<1wh_;2O!XXR&t}Mn1wtVfG`Dy zy&&qXx0IFgtI(^cek4Zj>5+N#QjVo(_oQdUR9J!s*7IeLe#naIf+UuibnX*9gr zXuj1tdeQR0_&%Oq!^}YFZ$>}y+LMs4rnLMj<4a)@{@{w=TUq%<+r#7AVd^kl+t>ZZ zUc>tbjsNY0`3qqg%O1d>~=QMpYOh_FoM4+BAE|;T*ij$KnYcs4=ZNX zv9bYH$K`$;B7#cB~g9QX-4=(hrN{yFh*x{>a_C=nEK9O;JbW(t&W4 zu1D~NC4#Wu@Yx?3=W#*9bs&HsUn0T^wIH zXW{$|Mqn@%*J3Un>tiF3@AF4K`APm1_av?*Us28R10NSO)B#FF0ff8;SL!oQWm%Dq z5en2vQXCZ+A()2bM~MIsA^fSpXD42yE*?U@kGbCBm8lqAF8^J6D8PgZV0ao27EmI1 z>qN8^?Mjbu3Iyqq2N|G)*hP95#~037I6s3Ckuj0^5riv?h$*Ev9Owel$JkCPxP;@({6vJmvWvw1 zrGbPRqUeQuH(H5!GA58%Xz2EBrH>Hx7+1tU+4@-Uf8I(&+yHw|6wS)FlJQ$q8yBM% z2|KIyi#5Kcr%@KTFr+ovILn_ZmdG_|5Ntve6B`bc3UI04e$alAUNL2OaeP03pC5@4 z#Y@DXFpbzaV168dsRuBEU8G~=e&z!Uc*??w=Ji;-T z)DJ&&zew-m_&$=K7laWt=NdWlk|;nzkBBUuoS#SlR`}QIW5C}QibTZ~byafdlHmE9 zH*p6DBXd?I(S$l+{Xj5s^r(ubski~SAV(u&wxl+sCL;SUg2TIatB0U>bd)KW01)(u zgo(O9?12d@ct0wYbMKmmj_zS(k>17em0YCwc|jOq4yn?`w`H~7>w{F+sCcX}x8(FI z?j}}Ek#bv)BN39lb4SlmkiwJ2Ej(FRS(GA7PXiNdEu}|*0~d4l9!5x!gAr88sZ(Ov zRi~QZdV*K?veizD3#02HuK#FX+{4Hsy^G^JkDnin5vdNavV=>b{E@5DUcD`!YIzmI*zh6WMIKAC3`Hj)zl(uqJRh?w)`%Y>)+ zEruCZmQW=(Zs-`1>q)xY4QhHnNR@mvNX)-_k>17e{a}86Bt}$>SC8mEjFCHoL}Ep4 z;iw6VOXa)KAOHk68P>yU!fh8hdUS`%Zol^)Na0ITd!puKWJE7{1tz?s;m8r(5J16i z(HhiM3Yf?jF$=FBJtE(vshC=m$bdd_>%4K{rT9VMS59`MfmJW z1}=`TjQqIx`C*K(R1U8ufv4`nh||^*dgRU^)&7*J0~1meB9~{7(IolKM8G1_5V9g2 zA4C*9Q1>Ov?52jG$#Ou3Qk%F(SPZ zV8Vvor4Do)IJM*g{gFj_F*04Y^y2tF%+C*CgoqFTAxs3nQBR`Bex(mfF$r-GHGAmZ zJPuSze-Ghbpn(#>eFlBPOp?YD@m_F&S^+E^5ZaN&d4)udt;T z$JaG4=~4VVA0u#-;B)LB`BpfEk%xs0{)l)H0Ivg(#Z;ucaocg&)o+0SmJ&)qcPprv za=l&g_HC{qXQ6nQz0f8jBd8KkK$sV{<r0M=|u)Ej_-%^^L&iV7qB1i*riQido~K)g*=x_ z1S<(IbO$S$GnY!H{{V=Z+xYPw_kaCYi}e2gVSE)v5V`Q%;G8HR6l-nm5o&@eDZZhq zkagQQE8cGTx|pL4?l|U68Em`@fKzl7Ru;MdVJ=?l<9rJzp(-pN;aM=D{>l{sxx##s z+5s|F^Nvyw6CvfheO0#qL#5P(10qxHK!6ApY%iP?6{=E5IeQj63R{cc!m$Lq$dw3;@MaSdj?#GZeW^&adbc(9}Qb91?_hHJR YLLwNE-pwNc!k3HmE{^ZQ`5BD-Z_iK|A^-pY literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-12/image.gif b/wxPython/samples/wxPIA_book/Chapter-12/image.gif new file mode 100644 index 0000000000000000000000000000000000000000..34b3e035701d1dce9ee3691e970e30d71a9bb456 GIT binary patch literal 7116 zcmc(g_dnb1`~D-utTqX;>kc&|RT4pmR*e`{k{}3*AfZOB7}2UwyTfdSYVC+s)ULa? zQM1tsEv-(gHL6>6zVmtM_mB8qznzckypHpE9A{pS*x2Ds5BhxoS%J1e|L|D~YAQ}xsV}ocs5KXYt%f^D(G!UB&V)H<3!Ol}2 z7Q~~0cx(`l2jU3;C6E9M63{>bHb}q&34j972BZNk;4#oG*qO6)Xjm*8i{)Xlf}OEI zMWbP9Y%Gn3r3rQ@fJ-(F%VuNQJSCiWShX0yb8_!wP_@ z05u>6Km(Kj7H|g)2DAZbKnr***fF$I1BXqc@n|%`jz3^5P_fxGHjl;@?AQe;fJ+{m z#^cd=0>C{01@zJcY?^>a69D#rJOE7KH4q2jAAkTH0@Q#Q01Z$AtpEow7|;f!0WHB! zay!>R4ICbuE!YVX@CS?qDjtu`69Bmab^!|Dk}cq|1wf8K(m((J7tjs_4Y&oO1o8kd zf!9DB025#sa0pNXVgNMo62JmDfWd$^AT8Kg(M~sT4b;F902>2>1pEPGfr=*(>@4u_ z`gbV)Zggj#f0wia^*8sO_5O`=hw*PZJKO$icnA5fhn?mB#oBT3cM>2C{2YKS0pS6j zfKmUy4tnPc*!dPf;sQ{U`@(cu`SDbU3|wVjL^&eOyAcGI6`w-o$TW$NI$EjL=3rgw zJMp%P@my^u^&{diHA|M4s(PW$=SAz>y$7?=9tD*T3bjsv_dbczymxK4+H_+O*5C1p zq9$g`BT~n{!Tt8>7ZV+7V_ApqWbZv;yfT;d&;5GuhOJQd0udp^E+YfzHFJM(R)uo3 z4${o)Yk5bvY}HBbA=>jPFk7Dg`oPi4ek?phMa#E-CFewIxkbRvD`!~bGN8GUnc|jSs%62?zXS$H&?j5h1 ztO8&4^F^j;Qf*zhRO;n_!m8Dy5#Y21hXKt(d6K~zKTQ=}MD?;!+bZ^oEZ6Olbs>7B zy|lE(YhBNa=T>VJkWD@QDI8w0)x6^NUUu2evyu+=S=+1oCjaEoablqc-n6tR$nQt3 z-5=d?$Z^cmz&VA^Ke%Ex|wsSHTngM`x!Wjea3{T&Oq?9J3?;gq7T*GUa8yZx>z?{}ObAAZ&064>B; zC-vWF>UCBy%{c`xqi4Byp64xw`^VTNRNmX={D^CrVJy#2NH&;PZM`eH7|{<6S$~__ zEP8Qv*f8+-KclMKqESP8mI6NCgFXl~B>&5(Lo*+|)Wo0pFS}a3LtHei$(1+-%EI5Dy_ZZYzTBCcO#5oSXPj{Vp8xs2ZzSDgYX6nYAnuZ* z7xD5-QZw42o9q*hR9t?sToXi#5UpM%*Vcd4~m zYP^NI2~{kIlCKNQuAui5Wd}&q+Tb$c#X>Aa`l*ij4_NLoy}TvMWReXwT;!6{xc^vl z@tE=ZcUO*Vs3*cj3&6uxBn90xH6yld7aD%TK5?%`E13OdwaL7wJw=V&I_{ukQFtZa ziPEe&(NP$sc8Zi`PJU{ycDIdGa{CcF(&c_zH7Dt+gcb5zGDn^iP;j>*6SLhf8Dte2 zZeQrT?^+$ynoHLyF_J;n;nWAMTjHO8o)AA#d2fI07yVZv_Nku{nIsh|f*HU285%Fh zb8V@#Sw}xKUQj5ztF|kTw&%Xts0A zTxq%@FmdO?6hy5-8lrl>(iEcsJ@lAsC9lL!!~4sfDheXsURRE}yXT7V^S!nn-yfKN zed9@ku}i#4dY^z@+%~*TIDuRyARE0 z$5PV#y{Asd@6MYE8l&!+FoNjGmhew!Uqz&Jrz31jXUx4=c7rga0xKcST<|+L{_;UB zJC=p~RR75N4iEMOEwk^)AV+VdR72e5(N35Q+Bg3BG7;9Wb zn&eO%_5OXU)W88}Jr41&5j$=m+n|id+;zhjq7$SEon0;?<2@z+{Om&4`qm+C9QK_W z$?lgv-sEdyucha;pwtGvr`o*mvI1FLXw0GoII919_H_Hu2>g~gSmjcnWB>%?etg&Z z;SNYFt6lj04F%mA8`w$ifVNr_(r8h)p-F^zoJq|f>5jzcUmVG4AHS4Q>CQ!IXl)r~ z?P`Py|N1%7upUNA;4r1R;R*Mp`9pHW?P;H;G_IGP)x5mWHlH@%Dd;5B4HmjKE}Em; zhxEq2NZ#mALF~~W6CRw_Gnb;U(w%LB-yfjV4hLDy7D@@7LRY*{D!7Yl$cZR|64Kwj z{yHMEj~P0x1>5_e#)wI=O1E>YVd_Bcj=Ezqh05FrX`}k>jZT@zZ+Z|Q&Z~v`A)OXY zU%WO@vZZ#=Ihg= zppof@L793&81>eZC&F2hQAQpk1|=erN$*2F+{a8olUMQrdJPns9_z#_hACsHDSfQ>`%JFq@}ufBFi+LJ3L;yVu)T3>6~ve?WZ>8b!3iwX^7hOuF=`Q2?^T&vEL^DC8$d|eIC@23J5s-DsDA+ z-q**csxNc?P!X|@aqwZuW-M(r4b^QRkTa+QfVe= zun#QMXdc>@o%z3+H_p#B9@%Lm6)ejt?KZ|a&z^0?2cGW?gS@53*tlxjfW^w=q}<7Y zTk`e@aTMNX$!w^A`h2(gv{=6uWb<Sy$l zA%qri9RHkd1wk`5rDL1rjPnSWllH7LTe4CxrfNRPgO}kF+ukH67zZjv(zQk7*Sg$S zGSD$yr~O<)t_MoCRysIqV{%$$lE0)sG9r@%oz$iXX@@qklctQ_L^zA3U6NsPy$&|p zPnent{5+(nkQc4HC99f2ynzqwojnVNW#w!+C6hy#ApZpSD5-1C9SXtg+Q){B)qcpG zybU9%Z&PN-Q79TC7Z;^xPWexZ)luir1oajsLYUC3Sl6uksr%?~jk%Q+M+LpMHz7i^ zCK8BbT+LyjI&)I$UOqxRWy<;CmYE97vi0$$@j_SWt5npt(9Uh|+I|hp?T9gXJtmDw zsBw3IPW;yc7*A9OGX<%F1lTyqmD9FeOn3VDVg zPRQyT7zV}`Gi?;|lA*4aigkr)X6 zAQY^=?FH|m|7((ea#(VA4})3m+~^xei97$!IPsWCgq2nRtpLg$(JqG(y|0Fy=R^p` zdLGpJUJ<7z) zp~sILNpWF7AasaRe^#=nk%1820i5oA&{tMoShJk*KC);bF!!EK+#gLd!xpi6c8<$q zD8V2MB^Ls*P1#+c^eMnDC6bgp<=0}HTGfoEamW>`v_UGhmC#7K*!C##7tUkKUBKe(;SeT!;N~ zABB%R6>^P!H$AM)BMhaT9>yh^L&xNqbLWEn(p776Q-^h+PUYnh68@fc@=V$d zhkUw@P2Am2*S&O(-9p?fT4gk5*h{sG1++^(G>J+V58s4H3zjRGqEX~H3osr2?v3|9 z9zH1Jg!3a=%AFSQg_}>_6rs$0=84{N!xv}S&TBPv9w%G-YKl-fINq(gIVi)RLiq{VkL%hxfj`MST!-C#g-UKP9ZU@Q)YF_l4*pu?RU>$$ zky8Y>h%4$W%3z^n$o_VIkBUEMdc*Y)7}PPn{+iiu7u&ey(c2-9gQN6qS`4#vmb0&3 z?M}$EfO(B`>QSw(gaSWzAF=KF$+{fvH#HhRDd1jrvr_t7b_Nrl@@hF=Ye6IOdz(mB z;b1L8bEFkvv$q%_BcnyUKr4I{Ai2DD+fc$tQ;lobDp?D?QskCkX$><+`1FqEam-uW zwL>udSKUfVgcIvEiVdA_Ybbr*f0<0GF7JUng$mh6hH(fF@QJRaon<3e#9Dfkvs@1i zUr$m>SILUHM}`_{R%i{tTt_twlZh)e4v#fBOt%i%YdUy7O%Za%?Z+u+f$Pcj8u}Cp zC*fJBM06_JmN=(Nk?&9_uBVd^FDh`A|ew~oZN`#anTtDjs28(s~O|bKOijG}O8P7VrcEQZg-OYpE-);{)JiLh`LsVo>F$r44}1;_6l#D{#wYGBrxko0zcEgi)er zV!e0yt_?<%Bq|iXprM~;w)U8HSJy{uv|D z@qSxPm!y>Ld8T{;-Frzy;kSFusr36d{@l{pAprgbx$TP1(v0Fbs&XhR8+A(V4LmrFIctYG9NNhF+|N@LPti zTuBOZZ&R)P{vMd6mG^cf>_5Y9yHBd;jEl)O!{Tor7z$bw+tHPr-#H3dwYDy(_QZ%& zqy718I(<#Ev7xVLpz=5O(bfcb=m>r>GDfx-HZ(iTd6tc&XDrTJiEc;f4O|g(3o+!P z4}VuiOc<5%Et>oc|MLqKy<}KUn(>-z?t!(T@C~@h%BDKHKBwYTWKd8nVwH%PQZD!C zigmaYVbv;M@fn)vrzgzs`RUoknaDe!4XdI}CoYZ==b`k`fnSM95ed*{&J&u9Ow=33 z#1Wa%mDmR^c34>iH7*vNt|Qz-jX7!N`jKbw6oZ+fi|Ej~lhYnUuu_qu@F!*+a>6nu z2~jrpo4Qr6G^tv8u1#)VxoK9$uc z7LWWkhHpe8HrvBIMrocF#Q}#D-5YqD64#{tGD0||@$Y2ouOC<(uxP0fqlEcH$G%!W z86j;bUy3l=_SZvXJ%eP-eZ>WeH>Nwn9k=DqpXu&5Lobwywcj;cs8382)rp~5;({)W z8F7!rM0;tg&0?PXvj^o9z$E;5f!UvKvU%u;Axqe6j_E9yM>53h^Y>Uc4Lrt%8>}tm zH1)YHVa>D(gqoEpO-#0$nyt(Yu&{hcEu#;A+t6eA+=40R1vLsBLQZCErK*Wa$ygR; z8qw6sDh=Z-Yq^Fbmzn8TZI3_BF8B#*_ntV84{(V#XR++NvgV(m!Gn`%zCz^w<;Cf- zJT>_IZ>_!YR7t(%2v=FbiRKS}xY2eG|8>>yYw&-jS>OKn_#3Wx5p@aSE8dq!+rtkV zEgm*E+>m;XP*r)?Ipc;Bf&~T3E~?ktA6Y;g-CHT7f>5i+7|Z?1+jPGJ7q>JrVs+&% zq6_7mQZZ_+E30F!?322R=KGLGt-MX~P^VdW89pl|_5EeynuN^W`zdO78Z~5EH9A}6 zXEt?bhCS6`3S(w+7E9z(CGMR*nG{ynuV#}Q>Sw@_;;KX!ew)?J0{P!B;pK`dAH(4O za9k{VIrUwX{!` zJfwVdT{++!yuN(&pHJ`n^X?zjS~WYQVJ+vNmiM)BzyF5?PdjHha9Hq<&9|jLr|`A^ zY8zSFx10aKm^{}&)-E5OgmDK0EG?>_tuK6&X6y@=9Kq`H*%({a*Wf2c3(5UYyhQ>v zzdqXc5}{Bj`?Yp4^NZXdf3qh*-eX!`{f4Qh(fb+i28hIZPeK5VX%pPb(5A%QIh3Ij&C)bLD!ky)8H~lTI z9JM}h=)-6K3yNF1_gg?6)=0sJk8wFB0-=E0t=K5i|NgUc!D*tU4#i~S{3lBS^DghIC$AMZ`tJ%)yC3_>y51MtjFZR=p``onmFt8*fsPFveSA99^QZ4b zqqbj^uH=}yd;6gSXO;yGEhiRu<(rqijxYnsokc}$4pMEWE!&w6$9A=6yC5%`DJL17 zzy!_Tu92cWdOG~+^g8SN8;66XJ*XW1UgJU)=GVmUpH?1nd|v(U-0vS-AGWiIu6WS# z`OV%YDD#$4VXyoChHfKCtBd9%NS*HM%&3pYgan6!uH4)u8{7ci^Jwi(YCz&fMS+G@ zsAhi4#ye91hGK7!w~O-7EHBe}ll$2bbEVv}S3KXM9ep-a?ZxbuhPrX)%)~9e7U?vS z)0mrw;Xsx5)mTnrGAr}+Ni{>c?bJ&{<0=#$Z@XOSfm)9UTuQ5ew49$~m|g9xVcy>+ zZlsse%Ws~f!rM;@WUf_)8k_f$2p0>H=W^St%J+S#XfnN5KVmL@8grO~_J=ip?#0-) zii@ShJXE(nflZ=uy<3C3AFm!NvR|~0Rg!-$4*&vz0L8}(@GuLI1%N@IKlkH6 zdb}a15C{?y1PuiR85IK!0|Olm9UT)37mA66gN2R`C4}PO;S&%LU|RO=0MQ&?wy}S3y?Ub`Xy%RVIxY5Oo3=$Q z&(qv&P^m$XGo>ILnJLhk{X<*Ud)BobK`Q~awX*+dI-UNyz?08LW4)_6UU*@?-cZ02$W$D9Ge35)b_N57gw3cu_DJ|WlkFXn*&h34%~&Q zPYHtPrl+nAy0`OphEeY6^lQ%*Nx0HluJtxp*D3HB&cq_OUpMeMXX1N%Y93c^Hk*7z zj`}3=rFb8?CBbKxHNnLI=am-xNgmd)qf>JLH9@Z`)swif&+gLBs+TP?8aHXI+k6fj zs)(?T;1pdvDEclNR&5hJ2OZfto&u9M76UF+Gj0#`4|aDPUlSLwBWRKGqaPIFVjh{) zDR(mt_EGF^z!JZRT%?u&{ag)}Q7QK@==7gr(j&GoRn5&OO`oRMlk(8ii0*$cYM^gH z`%zAjpZ|+uMc__;9!UzlXLV(-oIqr}oxMeZF>w63JTHgho~=cE>Dx!f7@+_V2#5qk zdgSyU+8)_Of&g&w@NsBp>3ER|c(|n>*+YGVfe?_!Wg;R|jx00~WS;z< z&L@$q$GCRN(5Xs9c+O4|w~_}d_~Iu8|CF=o)H#Jv)$6R-E>ILT8`QJC=4DlOPjmZF zz*TVJH_Tm8%FZG}HoW1fKn)AXJFF>zG66o~i+U04MK1SA(`LB&l>18eyEmdxG`7G> z=~?7)tM9>-7bwyaKT0O#K94`{ow74%qFH7SK?EI5X<_TLfW6eaNoHT1{a)wB zOOQEoG$a%#9}u}Gd3;YsXvD}q#k3=yHcx)IcA8q6S2EEtn-l4(dxd7OmUvY4H@K(a zvvG_PE&@iKyssz)i8a#R<7DfukzHX4s58c$-#B{|<$l5%VSPJKW)}gP>yTA#_3E;qpm(WeflqHiBg<2tgU>rV;Me?Zp!I%RlQGY9(W{hT|Gi)eKD3;m2PVb$X1GuJmp zw@-xwTX#;eF{4_N*z#*v0uT){9)qs*|F4kx_+y-M;Q)YOFc29D0{J&i|D;+Z92y7| z7mt=(TEi4JjGvIRe8?jcRMmd;H)0<{S`wI6IF}=5^Ii8)9IbwuSG7SVayYtt=?www zi`7ThP=Y)X!?shFRf}@TYDVQI9SXx1(DS*8=~~RTGZvP#ozrb$xj8SnK#DIVrx9d^ z?OB5WXELgbX;Jmm>M@a@)*8N>qffr1m{PDtD0YzeP{OhnGR2)r`BtTtn+~7vE#-L; z^wlQYQTH@{2pyNxR>`tbBBcd&f|*WO3TX<3qhqprcRy}S zZb9w~?2!wFKOO;$Vizr@KUZA`TB7FLoG|^me<`ZLn2=aShOzkb!=5E$<*--{S!=OV zT>3|CYm`tm%D>fy&cKT-rP*U*KjunfWYBuk?TNj5f^P4Vw5CXfWxi#?nKPLbFhfw#@y`MO{SR@Ma;Z{(ZL^Mc;7OkAo=GmCKCJ+s zmvR~i{U3e|aX#`(hx3?+9|sr!{!>uE)6%WG#-yBKCi}KN|j;jJsZuYAXaMo*5eyk#TrO2Q+P)@Nv zW<~uWFP^&z<5gZ%D&iOvH_my>1zxV8qwxRzvE-w(c>WeG5E29gd8}K1{Po9KxL}$; zf$-=p*fO*oNyaQFhmKb>LH2#s@V^BNSrSyCK}NIKPo}t{P|dkWc= zu(P2Z-wsH*Xf$30m_=#5EyP>&G0GK?ZA}(P=!&z^Hm}Q9qweh2A=66$t?U@+6RcmQ z2QKA#9N%^m7Crz}m|Bh-o;kqZvN_U4P!1LMI4fpI!;?z|KGQ<%L_%xx2|d&G1!HAAq~r{p~)OKEWi<}Z%S!ffW*cV7v#UcVLEIg$ACeHG^-A}Va9IW8xntQf7}qyn~OrhPxE&ImUB*+Yoh zT1^}*e1Jt7-cxB4l*%a{ah5Dd9M_~`BuKF9kD=REN~z8-q*j>MK>Lfin4k1_vhR~* zg{hA?9)91Pn8Fe1ti$^ImcIk&E7CLf4w&<}SX-N_>bv|mFZAvgrFj`k)bD%lK;At$ zv6Hea4VV55&f8S{;hP=5JLA(9m5NcqgMcJZ2Q@qwxgqC{wXk0i#cTniDp_c+lvqo` zaZZoKijOY>El3(CN44zd_IPv-rvkLbp1Did&0btTxwPCNh&$0xuxu!ul(x0x=oS7j zVPku*Ioq=ta~jdgE%4;d5>{h(1kg*4a)Vb9mv>g{V zvDfjQi)5~>7fXvb%0a$>>HuMata7WlA4WPL~$WqG=wdw%6QkUW^%dG^6|EAy{__BU}W*J|&GyjG_)K~t< zhIA8q#id7W&lw@OV8_am1(l2QX)L&rHHewbFPDuEN;P(U75`x!Pi`-YqjS`@bUn@+ zIWWEG-mqAiLm@+zry5{i6H>X#Atjl__+S7M-!i+F^hZjz>bFFehfAgdSvE%1r zZ~kICbeS%HREMBhiubi$qw<73xasIjNMZd|)nNHvvz+5$y^AOE=lmag(>}7bOJkic z_VoBpuM9Q9YRKxI-~C#WXNj!2S3Lrz7(P!O2nf&&5CU`G~ z=GF&^EESM+ERT3mf%5CH$lUU`AN-`0X%=cj_w4uqlfO|;uNQ^Jvfby}ic}3A0D4_x ze1Z%Ooy9ujI65g^zW`{0tkF6I_TT*EIG1ZrScyCE!2y+T)e~A^B~sfBL2BtW_n#w* zyX7}ITpF}pNR~w`1pF`q&CQK?w6iLeKb;a0RsVB<4dM_mgjiszh5~zw8?qN#Z4tgD z*LEdyR#wTNT1gvSXS^9yz?!zvkh4kkg!tGUzxF;auQJe(s+v_WV((9~WQ0C;3Xi=5 zeeFI5gbSrW&x}poE;N_QT~P=zltVNgBU4(SnYWbIcmi6G9`SXwNt8dN|D! zS1Zt`HU^H15eg&B%8j%nh3E$+;o{Sd9PyZxvsEV|=NWVxzwZCllx0SpZj~ewWQ>QQ16(F=Zl(A8ZQTQH&gbLOCaagJxUjZeO8tW!)o!~} zi0CM?Ds{S?JzBg&&+@B>L%MTJAtknu~ILxFRjP|Wi4H0TzhCw5EsEOFms3f$lI}qOavws#T|^s*Xl_5Qb5t3f}ByzOp#j zti{X+uC@hHr6cneYqkD0uZkj`mSf!Vk?lxdk;Oz2Uz^vY*!E~{+gML^GV<)K!YOj9 zTdM3Sp|kM|qB4eJ9Jo<@%B%-D1&zks>ehzGaCJuvW_2z85q$KJt>N)BsXb2=Rde*E zjWb@)$+hpaAx2eth4CB!=JsO3n|9;(bpLr%!J8)9JXDeN;*6Ohe5!-g{%fJr6k)Mg z#xK2XGd7V)5pHN^oeV?~R(#3)GOXAb%$Apq|Qq4W3eo)Yw@p{5sSGvFe zuknwWRGy#gQ&B3~~JvZ#m$o*ZL@#`s)BaR)^+HFD!G-Msy{dh&agkqsozq+{J z46+r}+ZZ_b<7B%a6?nIa#@{7!2Q_w=48?=U1&imTbq3ea{+FRks>biILiJMXbv@jQ zhl?kg&WfAqac@*7ydT+X#$X0A? z&-g^R${wxaqIe^(^NB<^cr+ChJR!4m0Vg)i>GG zVeCs7+ZsAfo~y+bw>q9-LuZpSp)O%c5BJZ8Hn2nj8ml9}>uFRP1{on2#gihnIjOu* zwbH#O%rA%Zs)&_KImjw!M=)zi@fp4#F8it}GrD=Gr`+~fMRxqxY9zV`E&k-iJGlDkyF&4wyE0y%;{iEq06iaTy%U?q$2j{o}gf+pYTbXK2SU zM$B(!*YUEn)FS;tYEhX)M2GV1xHxL1K8kh3#|-zNLXHDG7ESJ&PV`9-8LYC!EgOr?l;_DY6)yU?a$>-^{vKka(dPZE}Bec=iyNz2oLAR|j-2 zpa>!9BBb6&Oc8vX*wPkfn;Ks5<-m-Y4})~p=lmyE$o1Qj$E^JK)aOJ}~#u8Zu>AXJnbqd4eGx^XM0^TsY@_+FCs} z0grWn7Uwbj|En?nkr+T6z+)YFRE|N=oP>Xy9?nv}_;vnd8V|#5IuLyY#3Rm3XPm--Sh>^w^l_O@8isX3Q89 z8*l)K!s2~(%rAoVp?B+paYu_|E7i^suxs92Pgd3UfZuySYYwL6A&G& zw6>KvhVmape?cMbv^s(J3n(-xNu0oit+A6G;=B|6H?dp?so16|kC<-;$=5GG{ndqk zNCP50p34147yhZ}&0#F^I7d!mLaT$9$-21Ss)7g2HKh<^3gxZg z1qlxTqT4`BLfhgl*Y;gycH~K3Y$Bh`JLL z@W-7D(EkR(zunN^AkdID4N8Fh>4k=ukN(>WL02rIgiNe`908?KT8{i4k! z(ph&_W4Ux`UB;IE1ezk*~C2j&Wi3unG(lz6sft!TP3aD zreCEKoPG$DA}QpM(a#4tp19yLvRK#mnOq)FP#huw`F*JY_u~SfmdU6lfHz zIO3ouSMvLob3$Q(PaWqvI?v?ZNvC@XSMnJ>5bSHqW^h0M!``(4)@gj!ku?V;Y)eT4-_Kr8xjAXgr3_Krb?Mx!re0q`3 z)o1sFSYhsa2!mE%(fR#XlZaoIO#5aU#s0{jMB+P;x*Z8fgP+wa?dK%fSDwH5h5s8x z`xa-l9Z_8;6HSAC*5@|cnRqioEK)>UTY5ZPTl#@nb08Wy5EuP;BksuzI8Y-q%bM8z z2atM($gtb~J1sm`HIs;40nlHCF7GO-#lBR_TIEaXXG!4G=f901t$q9c0Z_;A?uPbl zRk%heDZcZ`D%y2DM^WJI#wy$y89wm<(8pjY>^>w$M@d2@m~!Zpp{@#*^Z71BY8jj! z81=LaJCDO64Ic8_H?BPpF`S$zbBvu)bn;`NU)@lm60LTD9^4-grVs?nXOwj`K10V$ zF8*Bf{wM0$5fE#!bunm_$k_v+mP^f|8X0@}-A`})-B(ORO{4W~m=kRo zM{&bXn6NgqWgJkyq*q?^Y&=i(R;#POC8p4olA8VOfE@$ilahexZ7e7;?ZI-3yEyq) zX9JZ&Y*wfgdb7AirOi@M{hZNX4`G^g=VkdUw`G?)z*m`#CXimL>id&e8C5S%FbebO zMv`6lF9pSui*HF7kuA@exYVp>+H+LvkV}4;aF(rTpCNTgDd??BPX2sPTsDtr4D}?8 zDT@Z_I^eLxpV9=F#>_r(it(!%{2wXmpK3@9lvCCN3N*8cQ zQ1*fS>^I+xl&ZsR&7gdx6wcn3}e1*${75I)Y@tFCkGD69ZgdN#(>E2?Nm`f!yKzV)y^V)zs5OGiEyC#3{8eN_ z%gUVE53Q=hc%O?>EYYK7JN2A@?*yl!Hu-k-Fh&l`1{^dYbb5uQvcS)xYQg*7wd^(% zML%NHq)w_uyj+GUe=6@SaDT0z$Ge5ScfvQ|WcFRD?Ls0?S?a@S_Hpv;{6XZTIdkdT zhRIXyrM%!KwzLlN#>C~A!fsfZs>w6>#OTwDA}V`jw5?ykaDKo^CC0M*mU99WIc(FE za}ag!f(CVNk9cGLXRD&T0L_^@v1Qmx1JQy5;Vc)|ATjv}A_ocshUX=<8Ok%}X%!9Y z*mOeEir=UwOuE`wm)X zkY}p{bLD2AvZ$J~xpE}6AiKIP&|_(izIM7ZqP;&tN#mm2+U=y1)fdz!u%pCQQ<$EN z&_CL4@56^sN|IFQ9DLuPm>5xrt*q*8)V(D6@yk12SXnjb+nGz$O&6s_n{VD%j2O(< z^RIP^y~Ty8tY0yh_Y|QpzrgptwQA67B}?@(d`>CS(L=j!xMa;Fz9O~GE`WS6{%cVa zaKZ?lr%1K1u}A(5Dwl2F?!6H?Vx<%p5|#sjURYrdT8Y@AU%njjP=Qd$HH3m*`; zExES?w0^|5o^#24y-({HLk@tT??oxRy3z@jS>daqJS5fq?C}7|SoX9zQaJtpIrm-4 J4avjw{{jP`!K?rP literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-12/image.png b/wxPython/samples/wxPIA_book/Chapter-12/image.png new file mode 100644 index 0000000000000000000000000000000000000000..5a4ce74b8970c81980eea62df1c214d9ffdf3a40 GIT binary patch literal 17905 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 literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-12/radargraph.py b/wxPython/samples/wxPIA_book/Chapter-12/radargraph.py new file mode 100644 index 0000000000..89908fdf84 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-12/radargraph.py @@ -0,0 +1,170 @@ +import wx +import math +import random + +class RadarGraph(wx.Window): + """ + A simple radar graph that plots a collection of values in the + range of 0-100 onto a polar coordinate system designed to easily + show outliers, etc. You might use this kind of graph to monitor + some sort of resource allocation metrics, and a quick glance at + the graph can tell you when conditions are good (within some + accepted tolerance level) or approaching critical levels (total + resource consumption). + """ + def __init__(self, parent, title, labels): + wx.Window.__init__(self, parent) + self.title = title + self.labels = labels + self.data = [0.0] * len(labels) + self.titleFont = wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD) + self.labelFont = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL) + + self.InitBuffer() + + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_PAINT, self.OnPaint) + + + def OnSize(self, evt): + # When the window size changes we need a new buffer. + self.InitBuffer() + + + def OnPaint(self, evt): + # This automatically Blits self.buffer to a wx.PaintDC when + # the dc is destroyed, and so nothing else needs done. + dc = wx.BufferedPaintDC(self, self.buffer) + + + def InitBuffer(self): + # Create the buffer bitmap to be the same size as the window, + # then draw our graph to it. Since we use wx.BufferedDC + # whatever is drawn to the buffer is also drawn to the window. + w, h = self.GetClientSize() + self.buffer = wx.EmptyBitmap(w, h) + dc = wx.BufferedDC(wx.ClientDC(self), self.buffer) + self.DrawGraph(dc) + + + def GetData(self): + return self.data + + def SetData(self, newData): + assert len(newData) == len(self.data) + self.data = newData[:] + + # The data has changed, so update the buffer and the window + dc = wx.BufferedDC(wx.ClientDC(self), self.buffer) + self.DrawGraph(dc) + + + def PolarToCartesian(self, radius, angle, cx, cy): + x = radius * math.cos(math.radians(angle)) + y = radius * math.sin(math.radians(angle)) + return (cx+x, cy-y) + + + def DrawGraph(self, dc): + spacer = 10 + scaledmax = 150.0 + + dc.SetBackground(wx.Brush(self.GetBackgroundColour())) + dc.Clear() + dw, dh = dc.GetSize() + + # Find out where to draw the title and do it + dc.SetFont(self.titleFont) + tw, th = dc.GetTextExtent(self.title) + dc.DrawText(self.title, (dw-tw)/2, spacer) + + # find the center of the space below the title + th = th + 2*spacer + cx = dw/2 + cy = (dh-th)/2 + th + + # calculate a scale factor to use for drawing the graph based + # on the minimum available width or height + mindim = min(cx, (dh-th)/2) + scale = mindim/scaledmax + + # draw the graph axis and "bulls-eye" with rings at scaled 25, + # 50, 75 and 100 positions + dc.SetPen(wx.Pen("black", 1)) + dc.SetBrush(wx.TRANSPARENT_BRUSH) + dc.DrawCircle(cx,cy, 25*scale) + dc.DrawCircle(cx,cy, 50*scale) + dc.DrawCircle(cx,cy, 75*scale) + dc.DrawCircle(cx,cy, 100*scale) + + dc.SetPen(wx.Pen("black", 2)) + dc.DrawLine(cx-110*scale, cy, cx+110*scale, cy) + dc.DrawLine(cx, cy-110*scale, cx, cy+110*scale) + + # Now find the coordinates for each data point, draw the + # labels, and find the max data point + dc.SetFont(self.labelFont) + maxval = 0 + angle = 0 + polypoints = [] + for i, label in enumerate(self.labels): + val = self.data[i] + point = self.PolarToCartesian(val*scale, angle, cx, cy) + polypoints.append(point) + x, y = self.PolarToCartesian(125*scale, angle, cx,cy) + dc.DrawText(label, x, y) + if val > maxval: + maxval = val + angle = angle + 360/len(self.labels) + + # Set the brush color based on the max value (green is good, + # red is bad) + c = "forest green" + if maxval > 70: + c = "yellow" + if maxval > 95: + c = "red" + + # Finally, draw the plot data as a filled polygon + dc.SetBrush(wx.Brush(c)) + dc.SetPen(wx.Pen("navy", 3)) + dc.DrawPolygon(polypoints) + + + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, title="Double Buffered Drawing", + size=(480,480)) + self.plot = RadarGraph(self, "Sample 'Radar' Plot", + ["A", "B", "C", "D", "E", "F", "G", "H"]) + + # Set some random initial data values + data = [] + for d in self.plot.GetData(): + data.append(random.randint(0, 75)) + self.plot.SetData(data) + + # Create a timer to update the data values + self.Bind(wx.EVT_TIMER, self.OnTimeout) + self.timer = wx.Timer(self) + self.timer.Start(500) + + + def OnTimeout(self, evt): + # simulate the positive or negative growth of each data value + data = [] + for d in self.plot.GetData(): + val = d + random.uniform(-5, 5) + if val < 0: + val = 0 + if val > 110: + val = 110 + data.append(val) + self.plot.SetData(data) + + +app = wx.PySimpleApp() +frm = TestFrame() +frm.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-13/data.py b/wxPython/samples/wxPIA_book/Chapter-13/data.py new file mode 100644 index 0000000000..76d2231b20 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-13/data.py @@ -0,0 +1,41 @@ + +# Just some simple data structures for the report mode listctrl examples + +columns = ["Request ID", "Summary", "Date", "Submitted By"] + +rows = [ + ("987441", "additions to RTTI?", "2004-07-08 10:22", "g00fy"), + ("846368", "wxTextCtrl - disable auto-scrolling", "2003-11-20 21:25", "ryannpcs"), + ("846367", "Less flicker when resizing a window", "2003-11-20 21:24", "ryannpcs"), + ("846366", "Wishlist - wxDbGetConnection return value", "2003-11-20 21:23", "ryannpcs"), + ("846364", "wxPostscriptDC with floating point coordinates", "2003-11-20 21:22", "ryannpcs"), + ("846363", "Wishlist - Better wxString Formatting", "2003-11-20 21:22", "ryannpcs"), + ("846362", "Wishlist - Crossplatform wxRichText Widget", "2003-11-20 21:20", "ryannpcs"), + ("953341", "Support for paper trays when printing", "2004-05-13 08:01", "tonye"), + ("952466", "mac menu - Window menu", "2004-05-12 03:19", "pimbuur"), + ("928899", "FloatCanvas demo should work with numarray", "2004-04-03 08:30", "glchapman"), + ("912714", "wxGrid: Support for Search / Replace", "2004-03-09 05:46", "rclund"), + ("901061", "wxComboBox - add small icons as in MSW CComboBoxEx ", "2004-02-20 04:04", "tomash"), + ("900768", "Please add more codepages support to your source built", "2004-02-19 15:49", "jsat66"), + ("894921", "trigger on event-system creation", "2004-02-11 08:10", "g00fy"), + ("869808", "HitTest in wxCheckListBox", "2004-01-03 01:22", "dickkniep"), + ("863306", "wxGrid - Thaw/Freeze column/row", "2003-12-19 17:54", "zinit"), + ("975435", "wxMenu anchor right position in wxMenuBar", "2004-06-18 08:44", "jmt2715"), + ("969811", "wxColourEnumerator", "2004-06-09 11:41", "wyo"), + ("959849", "wx.Grid gridlines past max row/col", "2004-05-24 19:39", "dodywijaya"), + ("959158", "wxGrid: Arbitrary controls in the grid", "2004-05-23 16:56", "somecoder"), + ("953824", "mac menu - Window menu", "2004-05-14 02:06", "pimbuur"), + ("863301", "wxTextCtrl - edit mode", "2003-12-19 17:48", "zinit"), + ("855902", "virtual window classes", "2003-12-07 12:39", "cursorstar"), + ("852379", "wxGrid row/col size limits", "2003-12-01 15:47", "jbrouwers"), + ("846375", "wxGraphicsPath", "2003-11-20 21:30", "ryannpcs"), + ("846374", "wxToolBar - return tool at position", "2003-11-20 21:29", "ryannpcs"), + ("846373", "Scrolling improvements", "2003-11-20 21:28", "ryannpcs"), + ("846372", "Hooks for standard remote events", "2003-11-20 21:27", "ryannpcs"), + ("846370", "wxDial - dial widget", "2003-11-20 21:27", "ryannpcs"), + ("846369", "wxGird - auto-scrolling", "2003-11-20 21:26", "ryannpcs"), + ("846361", "Wishlist - wxStaticText that takes fonts, colors, etc.", "2003-11-20 21:19", "ryannpcs"), + ("819559", "wxListCtrl column widths in wxLC_ICON mode ", "2003-10-07 13:34", "nwmoriarty"), + ("817429", "OS X wheel mouse", "2003-10-03 14:05", "mdcowles"), +] + diff --git a/wxPython/samples/wxPIA_book/Chapter-13/icon01.png b/wxPython/samples/wxPIA_book/Chapter-13/icon01.png new file mode 100644 index 0000000000000000000000000000000000000000..0825ab7e3cbbdd88fc8033d5e56de10435793c6f GIT binary patch literal 359 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz_7YEDSN1C$>>|dxPVQSdfI^%F z9+AZi40=i+%(&{&-AO<}mUKs7M+SzC{oH>NS%Lg-o-U3d6}O&-Mf0^N@GNO-E-ntc zzTwp7%Rz^Z`z<;ao^F*J`23&j7PFd;-fT(r%y^d*i@AGyoW)La$MqBm+VHjfIaIs% z=@}U*$;4}kH|{XIsb0R37pLXv@Y_z1W!hx_D_0l!hiE_ay)$2AuE2~xDe2~(ntWdl zhThO~2v}Y4w(eTg*M{SA-cS4!UR}Sri&4L5-O794_b=vhPnTI?%+7Lob6n4n&4v@t zMDwNiZCHG3CX?^8M?7~O4(M3+h4W7_TlRUYQ;pK=zg=hlaAjx&RHwQ9pQhanK9FJU$ju*V`i6-4(=yahn@jLfWgz%&t;ucLK6Vo C*N%?> literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-13/icon02.png b/wxPython/samples/wxPIA_book/Chapter-13/icon02.png new file mode 100644 index 0000000000000000000000000000000000000000..171b8b3eaea8f579c352374007cb2153009ff2a7 GIT binary patch literal 351 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz_7YEDSN1C$>>_3ona!iqQ3KjQXYyHhAD*s4xKkLR?u5%0#f1hSwGd=%;!DEfx;(rDQ zew1!MviXVseun6~H-j%|CEQwBdgS$?aN)Dto}2hFZV}bH#hRkCMZ{fUkKvb~Gd{e+ z+>Bqmq8>$ly4YXVbFVLZ(j>--MW)G#H%`AS`^_lpoUapcZk)FyI z(_#OTnLCu!K-IGhAP+zasz;gt&hu;D{n~RiF~CI3f*|jF zngKiyV*oP|&!vp~4Fet<(TW!IJi-VSIcXQZK*V&jq5d69`a+$#-1&8vCLl$y@4H*q z)g8w{&Q$SH?;q6w=QjiJkl@ryq|}FXoTCj_bVm~d+_S56z#<6>1|ael18`0;0Fis* z7eAy1a5JhEpd|8)0d3?N16L9}8#xOA8{M|;K`ZQ0AOV2Y`J)D~BW_Qcb5RXw5%=W$ wg%tcfoMl9b#i?=rU;y`O%N(1m#`#ak8-lweR(Vh>^Z)<=07*qoM6N<$f(dH0^Z)<= literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-13/icon04.png b/wxPython/samples/wxPIA_book/Chapter-13/icon04.png new file mode 100644 index 0000000000000000000000000000000000000000..55bf370dcb07f9289b39ff8d12d1698ec5dcdfd1 GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz_7YEDSN1C$?4ryfhmR#50Sa*z zctjR6Fz6|PFypF6cP9Y_S<)SS9T^xl_H+M9WCijcc)B=-RNQ(y?KU5iA%{zMd|&*! zGG)%SsXM=ZdUS+cxYbhjMVhyz&V;&(*!lDAodch&W%g$FKAa(2F}r7$>uV_nf8l#N zQSSHU?chv{St>xp|kb&py3VzbG>B9?Fh0t!1})rpS;fZ&UpK*U=;Hf}M7}4g!*&S7}-cnEErn eshb+T$lNV8^pHWzDJP&`89ZJ6T-G@yGywqjwR$4} literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-13/icon05.png b/wxPython/samples/wxPIA_book/Chapter-13/icon05.png new file mode 100644 index 0000000000000000000000000000000000000000..e39b52f9ffb7b3d707059c4afe9ca353f99dbdd6 GIT binary patch literal 435 zcmV;k0ZjghP)?S3`Pdb(%6;$ zeTwN17D9$0gIUo(@ye$yWhccrR0qI(N)3R`r+6JeN*ogcq?$!i6p$0dgaG4+F9!zP z0VJgXoQ7a2BS=Y%|FL0c+W1ch!_?hZV}xT;^n*iS>ZPwJF3Q&9hO?FDvEg+2-6X;Z z`0Lc8IOVvrt%pe(00G5YL{}9k0F+R$>I5YsVk#hfiH#WjqXp5Z1E`h@z=jdoYC=x9 zWH|ucB4h)!6z%0*WT@A*h_#7J`$pOfg!vHdy96)jupj$ZUcPI)U zJ&1{N0J%X3vmBNN$Z1=GOG1zX4l_I9RcQNnA4({oTTU(@DGk6Zqn70$08azRJ|xBw d)B>ZG5de5!42J1k%%iC{)01@tsar}Z#hsW*W}6V>qx@fA!4N*w@F}5}CXVEwmro9~Bq{yRqo{lpm=Z%_`Wmza=f6g3o3#=UcndO&Z#)YN02C;1$ zJgdkrMiPyL!h*p{;zBr03XPR_)UNwh+q6o#t$&Z&%~$M55o#X U2KLB4RR91007*qoM6N<$f)^#rs{jB1 literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-13/icon07.png b/wxPython/samples/wxPIA_book/Chapter-13/icon07.png new file mode 100644 index 0000000000000000000000000000000000000000..1459cfbac578271700709c88efdbff506530d44d GIT binary patch literal 382 zcmV-^0fGLBP)!k;NW)0Z(Jl{5Maf0uZChsdAuJJ;yK%&vHN$oXBIZ8`WEigY%++ffGCD4gtJ1)CMRw z5|qjJ#Mat07bPL6h|gK_Qsq33o)c$A63`^?5#JIJS_6lOpvBa5L3BV{y%talHpHRh z2VK3ZlT{ZkZ^GCn$tBtkYQz~xN5bkv@mf3v+n#L^2=*dSa%cvm7f{4Fj`_3q97&0>!uB c84kSo0XFIQ0UTO)(f|Me07*qoM6N<$g3}V4#Q*>R literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-13/icon08.png b/wxPython/samples/wxPIA_book/Chapter-13/icon08.png new file mode 100644 index 0000000000000000000000000000000000000000..97b4fda643bf7db4fcae0f89db6066f900b77ce8 GIT binary patch literal 445 zcmV;u0Yd(XP)Dqqqlh*H;MmSI zEspMXv(5wV;rF{T6+vW~$Ciu>saNF$`Fdzo<(8RRrgkiJs#XU~M|Q2lIhVWXrZx8f zN4W=(Ij&_)Fv00000NkvXXu0mjfSo*q( literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-13/list_icon.py b/wxPython/samples/wxPIA_book/Chapter-13/list_icon.py new file mode 100644 index 0000000000..01a6f08a51 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-13/list_icon.py @@ -0,0 +1,32 @@ +import wx +import sys, glob + +class DemoFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, + "wx.ListCtrl in wx.LC_ICON mode", + size=(600,400)) + + # load some images into an image list + il = wx.ImageList(32,32, True) + for name in glob.glob("icon??.png"): + bmp = wx.Bitmap(name, wx.BITMAP_TYPE_PNG) + il_max = il.Add(bmp) + + # create the list control + self.list = wx.ListCtrl(self, -1, + style=wx.LC_ICON | wx.LC_AUTOARRANGE) + + # assign the image list to it + self.list.AssignImageList(il, wx.IMAGE_LIST_NORMAL) + + # create some items for the list + for x in range(25): + img = x % (il_max+1) + self.list.InsertImageStringItem(x, + "This is item %02d" % x, img) + +app = wx.PySimpleApp() +frame = DemoFrame() +frame.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-13/list_list.py b/wxPython/samples/wxPIA_book/Chapter-13/list_list.py new file mode 100644 index 0000000000..23210dceee --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-13/list_list.py @@ -0,0 +1,34 @@ +import wx +import sys, glob + +class DemoFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, + "wx.ListCtrl in wx.LC_LIST mode", + size=(600,400)) + + # load some images into an image list + il = wx.ImageList(16,16, True) + for name in glob.glob("smicon??.png"): + bmp = wx.Bitmap(name, wx.BITMAP_TYPE_PNG) + il_max = il.Add(bmp) + + # create the list control + self.list = wx.ListCtrl(self, -1, style=wx.LC_LIST) + + # assign the image list to it + self.list.AssignImageList(il, wx.IMAGE_LIST_SMALL) + + # create some items for the list + for x in range(25): + img = x % (il_max+1) + self.list.InsertImageStringItem(x, + "This is item %02d" % x, + img) + + + +app = wx.PySimpleApp() +frame = DemoFrame() +frame.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-13/list_report.py b/wxPython/samples/wxPIA_book/Chapter-13/list_report.py new file mode 100644 index 0000000000..0b20fe9822 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-13/list_report.py @@ -0,0 +1,42 @@ +import wx +import sys, glob, random +import data + +class DemoFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, + "wx.ListCtrl in wx.LC_REPORT mode", + size=(600,400)) + + il = wx.ImageList(16,16, True) + for name in glob.glob("smicon??.png"): + bmp = wx.Bitmap(name, wx.BITMAP_TYPE_PNG) + il_max = il.Add(bmp) + self.list = wx.ListCtrl(self, -1, style=wx.LC_REPORT) + self.list.AssignImageList(il, wx.IMAGE_LIST_SMALL) + + # Add some columns + for col, text in enumerate(data.columns): + self.list.InsertColumn(col, text) + + # add the rows + for item in data.rows: + index = self.list.InsertStringItem(sys.maxint, item[0]) + for col, text in enumerate(item[1:]): + self.list.SetStringItem(index, col+1, text) + + # give each item a random image + img = random.randint(0, il_max) + self.list.SetItemImage(index, img, img) + + # set the width of the columns in various ways + self.list.SetColumnWidth(0, 120) + self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE) + self.list.SetColumnWidth(2, wx.LIST_AUTOSIZE) + self.list.SetColumnWidth(3, wx.LIST_AUTOSIZE_USEHEADER) + + +app = wx.PySimpleApp() +frame = DemoFrame() +frame.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-13/list_report_colsort.py b/wxPython/samples/wxPIA_book/Chapter-13/list_report_colsort.py new file mode 100644 index 0000000000..fbf98e366d --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-13/list_report_colsort.py @@ -0,0 +1,70 @@ +import wx +import wx.lib.mixins.listctrl +import sys, glob, random +import data + +class DemoFrame(wx.Frame, wx.lib.mixins.listctrl.ColumnSorterMixin): + def __init__(self): + wx.Frame.__init__(self, None, -1, + "wx.ListCtrl with ColumnSorterMixin", + size=(600,400)) + + # load some images into an image list + il = wx.ImageList(16,16, True) + for name in glob.glob("smicon??.png"): + bmp = wx.Bitmap(name, wx.BITMAP_TYPE_PNG) + il_max = il.Add(bmp) + + # add some arrows for the column sorter + self.up = il.AddWithColourMask( + wx.Bitmap("sm_up.bmp", wx.BITMAP_TYPE_BMP), "blue") + self.dn = il.AddWithColourMask( + wx.Bitmap("sm_down.bmp", wx.BITMAP_TYPE_BMP), "blue") + + # create the list control + self.list = wx.ListCtrl(self, -1, style=wx.LC_REPORT) + + # assign the image list to it + self.list.AssignImageList(il, wx.IMAGE_LIST_SMALL) + + # Add some columns + for col, text in enumerate(data.columns): + self.list.InsertColumn(col, text) + + # add the rows + self.itemDataMap = {} + for item in data.rows: + index = self.list.InsertStringItem(sys.maxint, item[0]) + for col, text in enumerate(item[1:]): + self.list.SetStringItem(index, col+1, text) + + # give each item a data value, and map it back to the + # item values, for the column sorter + self.list.SetItemData(index, index) + self.itemDataMap[index] = item + + # give each item a random image + img = random.randint(0, il_max) + self.list.SetItemImage(index, img, img) + + # set the width of the columns in various ways + self.list.SetColumnWidth(0, 120) + self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE) + self.list.SetColumnWidth(2, wx.LIST_AUTOSIZE) + self.list.SetColumnWidth(3, wx.LIST_AUTOSIZE_USEHEADER) + + # initialize the column sorter + wx.lib.mixins.listctrl.ColumnSorterMixin.__init__(self, + len(data.columns)) + + def GetListCtrl(self): + return self.list + + def GetSortImages(self): + return (self.dn, self.up) + + +app = wx.PySimpleApp() +frame = DemoFrame() +frame.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-13/list_report_etc.py b/wxPython/samples/wxPIA_book/Chapter-13/list_report_etc.py new file mode 100644 index 0000000000..92d0529e20 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-13/list_report_etc.py @@ -0,0 +1,210 @@ +import wx +import sys, glob, random +import data + +class DemoFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, + "Other wx.ListCtrl Stuff", + size=(700,500)) + self.list = None + self.editable = False + self.MakeMenu() + self.MakeListCtrl() + + + def MakeListCtrl(self, otherflags=0): + # if we already have a listctrl then get rid of it + if self.list: + self.list.Destroy() + + if self.editable: + otherflags |= wx.LC_EDIT_LABELS + + # load some images into an image list + il = wx.ImageList(16,16, True) + for name in glob.glob("smicon??.png"): + bmp = wx.Bitmap(name, wx.BITMAP_TYPE_PNG) + il_max = il.Add(bmp) + + # create the list control + self.list = wx.ListCtrl(self, -1, style=wx.LC_REPORT|otherflags) + + # assign the image list to it + self.list.AssignImageList(il, wx.IMAGE_LIST_SMALL) + + # Add some columns + for col, text in enumerate(data.columns): + self.list.InsertColumn(col, text) + + # add the rows + for row, item in enumerate(data.rows): + index = self.list.InsertStringItem(sys.maxint, item[0]) + for col, text in enumerate(item[1:]): + self.list.SetStringItem(index, col+1, text) + + # give each item a random image + img = random.randint(0, il_max) + self.list.SetItemImage(index, img, img) + + # set the data value for each item to be its position in + # the data list + self.list.SetItemData(index, row) + + + # set the width of the columns in various ways + self.list.SetColumnWidth(0, 120) + self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE) + self.list.SetColumnWidth(2, wx.LIST_AUTOSIZE) + self.list.SetColumnWidth(3, wx.LIST_AUTOSIZE_USEHEADER) + + # bind some interesting events + self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.list) + self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected, self.list) + self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, self.list) + + # in case we are recreating the list tickle the frame a bit so + # it will redo the layout + self.SendSizeEvent() + + + def MakeMenu(self): + mbar = wx.MenuBar() + menu = wx.Menu() + item = menu.Append(-1, "E&xit\tAlt-X") + self.Bind(wx.EVT_MENU, self.OnExit, item) + mbar.Append(menu, "&File") + + menu = wx.Menu() + item = menu.Append(-1, "Sort ascending") + self.Bind(wx.EVT_MENU, self.OnSortAscending, item) + item = menu.Append(-1, "Sort descending") + self.Bind(wx.EVT_MENU, self.OnSortDescending, item) + item = menu.Append(-1, "Sort by submitter") + self.Bind(wx.EVT_MENU, self.OnSortBySubmitter, item) + + menu.AppendSeparator() + item = menu.Append(-1, "Show selected") + self.Bind(wx.EVT_MENU, self.OnShowSelected, item) + item = menu.Append(-1, "Select all") + self.Bind(wx.EVT_MENU, self.OnSelectAll, item) + item = menu.Append(-1, "Select none") + self.Bind(wx.EVT_MENU, self.OnSelectNone, item) + + menu.AppendSeparator() + item = menu.Append(-1, "Set item text colour") + self.Bind(wx.EVT_MENU, self.OnSetTextColour, item) + item = menu.Append(-1, "Set item background colour") + self.Bind(wx.EVT_MENU, self.OnSetBGColour, item) + + menu.AppendSeparator() + item = menu.Append(-1, "Enable item editing", kind=wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnEnableEditing, item) + item = menu.Append(-1, "Edit current item") + self.Bind(wx.EVT_MENU, self.OnEditItem, item) + mbar.Append(menu, "&Demo") + + self.SetMenuBar(mbar) + + + + def OnExit(self, evt): + self.Close() + + + def OnItemSelected(self, evt): + item = evt.GetItem() + print "Item selected:", item.GetText() + + def OnItemDeselected(self, evt): + item = evt.GetItem() + print "Item deselected:", item.GetText() + + def OnItemActivated(self, evt): + item = evt.GetItem() + print "Item activated:", item.GetText() + + def OnSortAscending(self, evt): + # recreate the listctrl with a sort style + self.MakeListCtrl(wx.LC_SORT_ASCENDING) + + def OnSortDescending(self, evt): + # recreate the listctrl with a sort style + self.MakeListCtrl(wx.LC_SORT_DESCENDING) + + def OnSortBySubmitter(self, evt): + def compare_func(row1, row2): + # compare the values in the 4th col of the data + val1 = data.rows[row1][3] + val2 = data.rows[row2][3] + if val1 < val2: return -1 + if val1 > val2: return 1 + return 0 + + self.list.SortItems(compare_func) + + + + def OnShowSelected(self, evt): + print "These items are selected:" + index = self.list.GetFirstSelected() + if index == -1: + print "\tNone" + return + while index != -1: + item = self.list.GetItem(index) + print "\t%s" % item.GetText() + index = self.list.GetNextSelected(index) + + def OnSelectAll(self, evt): + for index in range(self.list.GetItemCount()): + self.list.Select(index, True) + + def OnSelectNone(self, evt): + index = self.list.GetFirstSelected() + while index != -1: + self.list.Select(index, False) + index = self.list.GetNextSelected(index) + + + def OnSetTextColour(self, evt): + dlg = wx.ColourDialog(self) + if dlg.ShowModal() == wx.ID_OK: + colour = dlg.GetColourData().GetColour() + index = self.list.GetFirstSelected() + while index != -1: + self.list.SetItemTextColour(index, colour) + index = self.list.GetNextSelected(index) + dlg.Destroy() + + def OnSetBGColour(self, evt): + dlg = wx.ColourDialog(self) + if dlg.ShowModal() == wx.ID_OK: + colour = dlg.GetColourData().GetColour() + index = self.list.GetFirstSelected() + while index != -1: + self.list.SetItemBackgroundColour(index, colour) + index = self.list.GetNextSelected(index) + dlg.Destroy() + + + def OnEnableEditing(self, evt): + self.editable = evt.IsChecked() + self.MakeListCtrl() + + def OnEditItem(self, evt): + index = self.list.GetFirstSelected() + if index != -1: + self.list.EditLabel(index) + + +class DemoApp(wx.App): + def OnInit(self): + frame = DemoFrame() + self.SetTopWindow(frame) + print "Program output appears here..." + frame.Show() + return True + +app = DemoApp(redirect=True) +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-13/list_report_virtual.py b/wxPython/samples/wxPIA_book/Chapter-13/list_report_virtual.py new file mode 100644 index 0000000000..caeb26220c --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-13/list_report_virtual.py @@ -0,0 +1,66 @@ +import wx +import sys, glob, random +import data + +class DataSource: + """ + A simple data source class that just uses our sample data items. + A real data source class would manage fetching items from a + database or similar. + """ + def GetColumnHeaders(self): + return data.columns + + def GetCount(self): + return len(data.rows) + + def GetItem(self, index): + return data.rows[index] + + def UpdateCache(self, start, end): + pass + + +class VirtualListCtrl(wx.ListCtrl): + """ + A generic virtual listctrl that fetches data from a DataSource. + """ + def __init__(self, parent, dataSource): + wx.ListCtrl.__init__(self, parent, + style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VIRTUAL) + self.dataSource = dataSource + self.Bind(wx.EVT_LIST_CACHE_HINT, self.DoCacheItems) + self.SetItemCount(dataSource.GetCount()) + + columns = dataSource.GetColumnHeaders() + for col, text in enumerate(columns): + self.InsertColumn(col, text) + + + def DoCacheItems(self, evt): + self.dataSource.UpdateCache( + evt.GetCacheFrom(), evt.GetCacheTo()) + + def OnGetItemText(self, item, col): + data = self.dataSource.GetItem(item) + return data[col] + + def OnGetItemAttr(self, item): return None + def OnGetItemImage(self, item): return -1 + + + +class DemoFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, + "Virtual wx.ListCtrl", + size=(600,400)) + + self.list = VirtualListCtrl(self, DataSource()) + + + +app = wx.PySimpleApp() +frame = DemoFrame() +frame.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-13/list_smicon.py b/wxPython/samples/wxPIA_book/Chapter-13/list_smicon.py new file mode 100644 index 0000000000..9a81b0a606 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-13/list_smicon.py @@ -0,0 +1,35 @@ +import wx +import sys, glob + +class DemoFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, + "wx.ListCtrl in wx.LC_SMALL_ICON mode", + size=(600,400)) + + # load some images into an image list + il = wx.ImageList(16,16, True) + for name in glob.glob("smicon??.png"): + bmp = wx.Bitmap(name, wx.BITMAP_TYPE_PNG) + il_max = il.Add(bmp) + + # create the list control + self.list = wx.ListCtrl(self, -1, + style=wx.LC_SMALL_ICON + | wx.LC_AUTOARRANGE + ) + + # assign the image list to it + self.list.AssignImageList(il, wx.IMAGE_LIST_SMALL) + + # create some items for the list + for x in range(25): + img = x % (il_max+1) + self.list.InsertImageStringItem(x, + "This is item %02d" % x, + img) + +app = wx.PySimpleApp() +frame = DemoFrame() +frame.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-13/sm_down.bmp b/wxPython/samples/wxPIA_book/Chapter-13/sm_down.bmp new file mode 100644 index 0000000000000000000000000000000000000000..df9e6243d4c9ec857c068ef08214657fd0588817 GIT binary patch literal 246 zcma)!u?>Jg3?NMQuIyJh*u~U&lv$SL0);pW zJR*x37`TN&n2}-D90{NxOS+@4BLl<6e(pbstU&%uPZ!6Kid#!3Gx8k};BgHvG%!DW zw#r!fQr6OAkJPuCKKr?r(WNHu$!!5AjcX~bhxs17SUP3VBkmj~9n%YZk5ZW!_H1~* zvu~wSfTIBO^kp(0zaLA6e!0YU;VfUu8t-l%Ls<`XA)8NU{LaYnsD|>r)pOi06Y+HC zh`Ex+q@zRA1yZj$m6_%Gw}&LW$8L7)Ef{QSkcqhh}@g;ZDgsjRVW20D_#)78&q Iol`;+0ERMK-2eap literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-13/smicon02.png b/wxPython/samples/wxPIA_book/Chapter-13/smicon02.png new file mode 100644 index 0000000000000000000000000000000000000000..3c112b5dcd53ce54c14a69025105d424a8bf9fd0 GIT binary patch literal 212 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`>?NMQuIyJh*u~V0dn$Jc0);pW zJR*x37~~FtFk{|@Qahj^OS+@4BLl<6e(pbstU!LUr;B4q#jUrKFLE7F;BYNZ{{R1U zT5{8t)kkaII$dd&;|~;=xO&oUK8B!4d`?^y-5Hw?&1dAf6tVHX?VQLuhBU+578{l@ zq!}b^tCMz#lyWKGl)J&mitTc6-?9|Pujbo=wl8D8qVF%e;ihE=&^iWBS3j3^P6?NMQuIyJh*u~W3PA+?v0u!lvI6-ro-U3d6}R3__U2+x;Bb+C`7eB% zS>w$4Cvuq=di0)mFeqNVVm*t)3lr&st1g$FvFVdQ&MBb@09c?tIsgCw literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-13/smicon04.png b/wxPython/samples/wxPIA_book/Chapter-13/smicon04.png new file mode 100644 index 0000000000000000000000000000000000000000..5b734cd3f2f8730172f68ab71fbf3d0339753771 GIT binary patch literal 249 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`>?NMQuIyJh*u~ViF4q`I0);pW zJR*x37~~FtFk{|@Qahj^OS+@4BLl<6e(pbstU!K;r;B4q#jU5oxqJ-@9IemxzDj#= z_Ctz_nbz-FH_zWYCLr7Yea@m)hs0ZI1(R(y3JTg8&0ykA)AJTw`DxSo0`Y_D!iGy! z4Elnnb}p;on{L;=EBBXmM8Bj&mfxA+;NW%d4v5P9wNDK%*l^+6o9Wd`KUOkrdG(5O ryTW9KU+GRq^d?PRAbxoHyB?NMQuIyJh*u_-!js&%G1BEyX zJR*x37`TN&n2}-D90{NxOS+@4BLl<6e(pbstU&$*PZ!6Kid#>EA95X2;P~S9e(T#&)LDu7WGP=e@86;P@|?HGDlhGc@1_TNEkAaqBD8?LuISu5S67t>Gxy)?@ynWO znZ8PCi@dvonU0!?*1LC?&T_rwKf%07RFz>@tB%9gYnnW^JO17L`=592<1Y#Z-g#%= zvi!TkILA!t;Y;ot>kpxYQcUHx3vIVCg!0FO&u AjQ{`u literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-13/smicon06.png b/wxPython/samples/wxPIA_book/Chapter-13/smicon06.png new file mode 100644 index 0000000000000000000000000000000000000000..7b644d5bcdf7f0dd0586e660f45ac5467fe3903a GIT binary patch literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`>?NMQuIyJh*u_-Y+aAcK1BEyX zJR*x381$4tm~qvkyOV%|Ea{HEjtmSN`?>!lvI6;qo-U3d6}PqqGx9Yka7;P&f4|Rz zRf0;2dS<1MpIG?k<{CG!i)PJpnAuSz!(i~lfT{G%EScSM2@BhtnojU{pWIl>Dqk0q zlh2x$uAhG5<1{0IkFPji?qF(h$d9fKsgF}Wy<`o$pr^0nr~EH++e)rB3->Hl(VnBQ R_&?Bc22WQ%mvv4FO#qnFN&^4@ literal 0 HcmV?d00001 diff --git a/wxPython/samples/wxPIA_book/Chapter-14/grid_attr.py b/wxPython/samples/wxPIA_book/Chapter-14/grid_attr.py new file mode 100644 index 0000000000..ec4b5be0ca --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-14/grid_attr.py @@ -0,0 +1,33 @@ +import wx +import wx.grid + +class TestFrame(wx.Frame): + + + def __init__(self): + wx.Frame.__init__(self, None, title="Grid Attributes", + size=(600,300)) + grid = wx.grid.Grid(self) + grid.CreateGrid(10,6) + for row in range(10): + for col in range(6): + grid.SetCellValue(row, col, "(%s,%s)" % (row, col)) + + grid.SetCellTextColour(1, 1, "red") + grid.SetCellFont(1,1, wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD)) + grid.SetCellBackgroundColour(2, 2, "light blue") + + attr = wx.grid.GridCellAttr() + attr.SetTextColour("navyblue") + attr.SetBackgroundColour("pink") + attr.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD)) + + grid.SetAttr(4, 0, attr) + grid.SetAttr(5, 1, attr) + grid.SetRowAttr(8, attr) + + +app = wx.PySimpleApp() +frame = TestFrame() +frame.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-14/grid_basic.py b/wxPython/samples/wxPIA_book/Chapter-14/grid_basic.py new file mode 100644 index 0000000000..1f52aee0f8 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-14/grid_basic.py @@ -0,0 +1,18 @@ +import wx +import wx.grid + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, title="Simple Grid", + size=(640,480)) + grid = wx.grid.Grid(self) + grid.CreateGrid(50,50) + for row in range(20): + for col in range(6): + grid.SetCellValue(row, col, + "cell (%d,%d)" % (row, col)) + +app = wx.PySimpleApp() +frame = TestFrame() +frame.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-14/grid_editor.py b/wxPython/samples/wxPIA_book/Chapter-14/grid_editor.py new file mode 100644 index 0000000000..98d6296020 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-14/grid_editor.py @@ -0,0 +1,111 @@ +import wx +import wx.grid +import string + +class UpCaseCellEditor(wx.grid.PyGridCellEditor): + def __init__(self): + wx.grid.PyGridCellEditor.__init__(self) + + def Create(self, parent, id, evtHandler): + """ + Called to create the control, which must derive from wx.Control. + *Must Override* + """ + self._tc = wx.TextCtrl(parent, id, "") + self._tc.SetInsertionPoint(0) + self.SetControl(self._tc) + + if evtHandler: + self._tc.PushEventHandler(evtHandler) + + self._tc.Bind(wx.EVT_CHAR, self.OnChar) + + def SetSize(self, rect): + """ + Called to position/size the edit control within the cell rectangle. + If you don't fill the cell (the rect) then be sure to override + PaintBackground and do something meaningful there. + """ + self._tc.SetDimensions(rect.x, rect.y, rect.width+2, rect.height+2, + wx.SIZE_ALLOW_MINUS_ONE) + + def BeginEdit(self, row, col, grid): + """ + Fetch the value from the table and prepare the edit control + to begin editing. Set the focus to the edit control. + *Must Override* + """ + self.startValue = grid.GetTable().GetValue(row, col) + self._tc.SetValue(self.startValue) + self._tc.SetInsertionPointEnd() + self._tc.SetFocus() + self._tc.SetSelection(0, self._tc.GetLastPosition()) + + def EndEdit(self, row, col, grid): + """ + Complete the editing of the current cell. Returns True if the value + has changed. If necessary, the control may be destroyed. + *Must Override* + """ + changed = False + + val = self._tc.GetValue() + + if val != self.startValue: + changed = True + grid.GetTable().SetValue(row, col, val) # update the table + + self.startValue = '' + self._tc.SetValue('') + return changed + + def Reset(self): + """ + Reset the value in the control back to its starting value. + *Must Override* + """ + self._tc.SetValue(self.startValue) + self._tc.SetInsertionPointEnd() + + def Clone(self): + """ + Create a new object which is the copy of this one + *Must Override* + """ + return UpCaseCellEditor() + + def StartingKey(self, evt): + """ + If the editor is enabled by pressing keys on the grid, this will be + called to let the editor do something about that first key if desired. + """ + self.OnChar(evt) + if evt.GetSkipped(): + self._tc.EmulateKeyPress(evt) + + def OnChar(self, evt): + key = evt.GetKeyCode() + if key > 255: + evt.Skip() + return + char = chr(key) + if char in string.letters: + char = char.upper() + self._tc.WriteText(char) + else: + evt.Skip() + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, title="Grid Editor", + size=(640,480)) + + grid = wx.grid.Grid(self) + grid.CreateGrid(50,50) + grid.SetDefaultEditor(UpCaseCellEditor()) + + +app = wx.PySimpleApp() +frame = TestFrame() +frame.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-14/grid_headers.py b/wxPython/samples/wxPIA_book/Chapter-14/grid_headers.py new file mode 100644 index 0000000000..2c43171ddb --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-14/grid_headers.py @@ -0,0 +1,24 @@ +import wx +import wx.grid + +class TestFrame(wx.Frame): + + rowLabels = ["uno", "dos", "tres", "quatro", "cinco"] + colLabels = ["homer", "marge", "bart", "lisa", "maggie"] + + def __init__(self): + wx.Frame.__init__(self, None, title="Grid Headers", + size=(500,200)) + grid = wx.grid.Grid(self) + grid.CreateGrid(5,5) + for row in range(5): + grid.SetRowLabelValue(row, self.rowLabels[row]) + grid.SetColLabelValue(row, self.colLabels[row]) + for col in range(5): + grid.SetCellValue(row, col, + "(%s,%s)" % (self.rowLabels[row], self.colLabels[col])) + +app = wx.PySimpleApp() +frame = TestFrame() +frame.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-14/grid_renderer.py b/wxPython/samples/wxPIA_book/Chapter-14/grid_renderer.py new file mode 100644 index 0000000000..415fd50ee2 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-14/grid_renderer.py @@ -0,0 +1,59 @@ +import wx +import wx.grid +import random + +class RandomBackgroundRenderer(wx.grid.PyGridCellRenderer): + def __init__(self): + wx.grid.PyGridCellRenderer.__init__(self) + + + def Draw(self, grid, attr, dc, rect, row, col, isSelected): + text = grid.GetCellValue(row, col) + hAlign, vAlign = attr.GetAlignment() + dc.SetFont( attr.GetFont() ) + if isSelected: + bg = grid.GetSelectionBackground() + fg = grid.GetSelectionForeground() + else: + bg = random.choice(["pink", "sky blue", "cyan", "yellow", "plum"]) + fg = attr.GetTextColour() + + dc.SetTextBackground(bg) + dc.SetTextForeground(fg) + dc.SetBrush(wx.Brush(bg, wx.SOLID)) + dc.SetPen(wx.TRANSPARENT_PEN) + dc.DrawRectangleRect(rect) + grid.DrawTextRectangle(dc, text, rect, hAlign, vAlign) + + + def GetBestSize(self, grid, attr, dc, row, col): + text = grid.GetCellValue(row, col) + dc.SetFont(attr.GetFont()) + w, h = dc.GetTextExtent(text) + return wx.Size(w, h) + + def Clone(self): + return RandomBackgroundRenderer() + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, title="Grid Renderer", + size=(640,480)) + + grid = wx.grid.Grid(self) + grid.CreateGrid(50,50) + + # Set this custom renderer just for row 4 + attr = wx.grid.GridCellAttr() + attr.SetRenderer(RandomBackgroundRenderer()) + grid.SetRowAttr(4, attr) + + for row in range(10): + for col in range(10): + grid.SetCellValue(row, col, + "cell (%d,%d)" % (row, col)) + +app = wx.PySimpleApp() +frame = TestFrame() +frame.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-14/grid_size.py b/wxPython/samples/wxPIA_book/Chapter-14/grid_size.py new file mode 100644 index 0000000000..d23c21e54b --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-14/grid_size.py @@ -0,0 +1,23 @@ +import wx +import wx.grid + +class TestFrame(wx.Frame): + + + def __init__(self): + wx.Frame.__init__(self, None, title="Grid Sizes", + size=(600,300)) + grid = wx.grid.Grid(self) + grid.CreateGrid(5,5) + for row in range(5): + for col in range(5): + grid.SetCellValue(row, col, "(%s,%s)" % (row, col)) + + grid.SetCellSize(2, 2, 2, 3) + grid.SetColSize(1, 125) + grid.SetRowSize(1, 100) + +app = wx.PySimpleApp() +frame = TestFrame() +frame.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-14/grid_table.py b/wxPython/samples/wxPIA_book/Chapter-14/grid_table.py new file mode 100644 index 0000000000..ee1705c1a8 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-14/grid_table.py @@ -0,0 +1,65 @@ +import wx +import wx.grid + +class TestTable(wx.grid.PyGridTableBase): + def __init__(self): + wx.grid.PyGridTableBase.__init__(self) + self.data = { (1,1) : "Here", + (2,2) : "is", + (3,3) : "some", + (4,4) : "data", + } + + self.odd=wx.grid.GridCellAttr() + self.odd.SetBackgroundColour("sky blue") + self.odd.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD)) + + self.even=wx.grid.GridCellAttr() + self.even.SetBackgroundColour("sea green") + self.even.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD)) + + + # these five are the required methods + def GetNumberRows(self): + return 50 + + def GetNumberCols(self): + return 50 + + def IsEmptyCell(self, row, col): + return self.data.get((row, col)) is not None + + def GetValue(self, row, col): + value = self.data.get((row, col)) + if value is not None: + return value + else: + return '' + + def SetValue(self, row, col, value): + self.data[(row,col)] = value + + + # the table can also provide the attribute for each cell + def GetAttr(self, row, col, kind): + attr = [self.even, self.odd][row % 2] + attr.IncRef() + return attr + + + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, title="Grid Table", + size=(640,480)) + + grid = wx.grid.Grid(self) + + table = TestTable() + grid.SetTable(table, True) + + +app = wx.PySimpleApp() +frame = TestFrame() +frame.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-14/grid_table_basic.py b/wxPython/samples/wxPIA_book/Chapter-14/grid_table_basic.py new file mode 100644 index 0000000000..60f017907b --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-14/grid_table_basic.py @@ -0,0 +1,42 @@ +import wx +import wx.grid + +class TestTable(wx.grid.PyGridTableBase): + def __init__(self): + wx.grid.PyGridTableBase.__init__(self) + self.rowLabels = ["uno", "dos", "tres", "quatro", "cinco"] + self.colLabels = ["homer", "marge", "bart", "lisa", "maggie"] + + def GetNumberRows(self): + return 5 + + def GetNumberCols(self): + return 5 + + def IsEmptyCell(self, row, col): + return False + + def GetValue(self, row, col): + return "(%s,%s)" % (self.rowLabels[row], self.colLabels[col]) + + def SetValue(self, row, col, value): + pass + + def GetColLabelValue(self, col): + return self.colLabels[col] + + def GetRowLabelValue(self, row): + return self.rowLabels[row] + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, title="Grid Table", + size=(500,200)) + grid = wx.grid.Grid(self) + table = TestTable() + grid.SetTable(table, True) + +app = wx.PySimpleApp() +frame = TestFrame() +frame.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-14/grid_table_header.py b/wxPython/samples/wxPIA_book/Chapter-14/grid_table_header.py new file mode 100644 index 0000000000..8b2e29554c --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-14/grid_table_header.py @@ -0,0 +1,64 @@ +import wx +import wx.grid + +class TestTable(wx.grid.PyGridTableBase): + def __init__(self): + wx.grid.PyGridTableBase.__init__(self) + self.data = { (1,1) : "Here", + (2,2) : "is", + (3,3) : "some", + (4,4) : "data", + } + + self.odd=wx.grid.GridCellAttr() + self.odd.SetBackgroundColour("sky blue") + self.odd.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD)) + + self.even=wx.grid.GridCellAttr() + self.even.SetBackgroundColour("sea green") + self.even.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD)) + + + # these five are the required methods + def GetNumberRows(self): + return 50 + + def GetNumberCols(self): + return 50 + + def IsEmptyCell(self, row, col): + return self.data.get((row, col)) is not None + + def GetValue(self, row, col): + value = self.data.get((row, col)) + if value is not None: + return value + else: + return '' + + def SetValue(self, row, col, value): + self.data[(row,col)] = value + + + # the table can also provide the attribute for each cell + def GetAttr(self, row, col, kind): + attr = [self.even, self.odd][row % 2] + attr.IncRef() + return attr + + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, title="Grid Table", + size=(640,480)) + + grid = wx.grid.Grid(self) + + table = TestTable() + grid.SetTable(table, True) + + +app = wx.PySimpleApp() +frame = TestFrame() +frame.Show() +app.MainLoop() diff --git a/wxPython/samples/wxPIA_book/Chapter-15/data.py b/wxPython/samples/wxPIA_book/Chapter-15/data.py new file mode 100644 index 0000000000..ac5c0cab29 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-15/data.py @@ -0,0 +1,403 @@ + +# Some sample data for the treectrl samples + +tree = [ + "wx.AcceleratorTable", + "wx.BrushList", + "wx.BusyInfo", + "wx.Clipboard", + "wx.Colour", + "wx.ColourData", + "wx.ColourDatabase", + "wx.ContextHelp", + ["wx.DC", [ + "wx.ClientDC", + ["wx.MemoryDC", [ + "wx.lib.colourchooser.canvas.BitmapBuffer", + ["wx.BufferedDC", [ + "wx.BufferedPaintDC", ]]]], + + "wx.MetaFileDC", + "wx.MirrorDC", + "wx.PaintDC", + "wx.PostScriptDC", + "wx.PrinterDC", + "wx.ScreenDC", + "wx.WindowDC",]], + "wx.DragImage", + "wx.Effects", + "wx.EncodingConverter", + ["wx.Event", [ + "wx.ActivateEvent", + "wx.CalculateLayoutEvent", + "wx.CloseEvent", + ["wx.CommandEvent", [ + "wx.calendar.CalendarEvent", + "wx.ChildFocusEvent", + "wx.ContextMenuEvent", + "wx.gizmos.DynamicSashSplitEvent", + "wx.gizmos.DynamicSashUnifyEvent", + "wx.FindDialogEvent", + "wx.grid.GridEditorCreatedEvent", + "wx.HelpEvent", + ["wx.NotifyEvent",[ + ["wx.BookCtrlEvent", [ + "wx.ListbookEvent", + "wx.NotebookEvent ",]], + "wx.grid.GridEvent", + "wx.grid.GridRangeSelectEvent", + "wx.grid.GridSizeEvent", + "wx.ListEvent", + "wx.SpinEvent", + "wx.SplitterEvent", + "wx.TreeEvent", + "wx.wizard.WizardEvent ",]], + ["wx.PyCommandEvent", [ + "wx.lib.colourselect.ColourSelectEvent", + "wx.lib.buttons.GenButtonEvent", + "wx.lib.gridmovers.GridColMoveEvent", + "wx.lib.gridmovers.GridRowMoveEvent", + "wx.lib.intctrl.IntUpdatedEvent", + "wx.lib.masked.combobox.MaskedComboBoxSelectEvent", + "wx.lib.masked.numctrl.NumberUpdatedEvent", + "wx.lib.masked.timectrl.TimeUpdatedEvent ",]], + "wx.SashEvent", + "wx.ScrollEvent", + "wx.stc.StyledTextEvent", + "wx.TextUrlEvent", + "wx.UpdateUIEvent", + "wx.WindowCreateEvent", + "wx.WindowDestroyEvent ",]], + "wx.DisplayChangedEvent", + "wx.DropFilesEvent", + "wx.EraseEvent", + "wx.FocusEvent", + "wx.IconizeEvent", + "wx.IdleEvent", + "wx.InitDialogEvent", + "wx.JoystickEvent", + "wx.KeyEvent", + "wx.MaximizeEvent", + "wx.MenuEvent", + "wx.MouseCaptureChangedEvent", + "wx.MouseEvent", + "wx.MoveEvent", + "wx.NavigationKeyEvent", + "wx.NcPaintEvent", + "wx.PaintEvent", + "wx.PaletteChangedEvent", + "wx.ProcessEvent", + ["wx.PyEvent", [ + "wx.lib.throbber.UpdateThrobberEvent ",]], + "wx.QueryLayoutInfoEvent", + "wx.QueryNewPaletteEvent", + "wx.ScrollWinEvent", + "wx.SetCursorEvent", + "wx.ShowEvent", + "wx.SizeEvent", + "wx.SysColourChangedEvent", + "wx.TaskBarIconEvent", + "wx.TimerEvent ",]], + ["wx.EvtHandler", [ + "wx.lib.gridmovers.GridColMover", + "wx.lib.gridmovers.GridRowMover", + "wx.html.HtmlHelpController", + "wx.Menu", + "wx.Process", + ["wx.PyApp", [ + ["wx.App", [ + "wx.py.PyAlaCarte.App", + "wx.py.PyAlaMode.App", + "wx.py.PyAlaModeTest.App", + "wx.py.PyCrust.App", + "wx.py.PyShell.App", + ["wx.py.filling.App", [ + "wx.py.PyFilling.App ",]], + ["wx.PySimpleApp", [ + "wx.lib.masked.maskededit.test",]], + "wx.PyWidgetTester ",]]]], + + "wx.TaskBarIcon", + ["wx.Timer", [ + "wx.PyTimer ",]], + ["wx.Validator", [ + ["wx.PyValidator",[ + "wx.lib.intctrl.IntValidator",]]]], + ["wx.Window", [ + ["wx.lib.colourchooser.canvas.Canvas", [ + "wx.lib.colourchooser.pycolourslider.PyColourSlider", + "wx.lib.colourchooser.pypalette.PyPalette",]], + "wx.lib.gridmovers.ColDragWindow", + ["wx.Control",[ + ["wx.BookCtrl", [ + "wx.Listbook", + ["wx.Notebook",[ + "wx.py.editor.EditorNotebook", + "wx.py.editor.EditorShellNotebook",]] ]], + ["wx.Button", [ + ["wx.BitmapButton",[ + "wx.lib.colourselect.ColourSelect", + "wx.ContextHelpButton", + "wx.lib.foldmenu.FoldOutMenu ",]] ]], + "wx.calendar.CalendarCtrl", + "wx.CheckBox", + ["wx.ComboBox",[ + ["wx.lib.masked.combobox.BaseMaskedComboBox", [ + "wx.lib.masked.combobox.ComboBox", + "wx.lib.masked.combobox.PreMaskedComboBox",]] ]], + ["wx.ControlWithItems", [ + ["wx.Choice",[ + "wx.DirFilterListCtrl ",]], + "wx.ListBox", + "wx.CheckListBox ",]], + "wx.Gauge", + "wx.GenericDirCtrl", + "wx.gizmos.LEDNumberCtrl", + ["wx.ListCtrl",[ + "wx.ListView ",]], + ["wx.PyControl",[ + "wx.lib.calendar.Calendar", + ["wx.lib.buttons.GenButton",[ + ["wx.lib.buttons.GenBitmapButton",[ + ["wx.lib.buttons.GenBitmapTextButton",[ + "wx.lib.buttons.GenBitmapTextToggleButton ",]], + "wx.lib.buttons.GenBitmapToggleButton ",]], + "wx.lib.buttons.GenToggleButton ",]], + "wx.lib.statbmp.GenStaticBitmap", + "wx.lib.stattext.GenStaticText", + "wx.lib.popupctl.PopButton", + "wx.lib.popupctl.PopupControl", + "wx.lib.ticker.Ticker ",]], + "wx.RadioBox", + "wx.RadioButton", + "wx.ScrollBar", + "wx.Slider", + "wx.SpinButton", + "wx.SpinCtrl", + ["wx.StaticBitmap",[ + "wx.lib.fancytext.StaticFancyText ",]], + "wx.StaticBox", + "wx.StaticLine", + "wx.StaticText", + ["wx.stc.StyledTextCtrl",[ + ["wx.py.editwindow.EditWindow",[ + "wx.py.crust.Display", + "wx.py.editor.EditWindow", + "wx.py.filling.FillingText", + "wx.py.shell.Shell",]], + "wx.lib.pyshell.PyShellWindow ",]], + ["wx.TextCtrl", [ + ["wx.lib.masked.textctrl.BaseMaskedTextCtrl",[ + "wx.lib.masked.ipaddrctrl.IpAddrCtrl", + "wx.lib.masked.numctrl.NumCtrl", + "wx.lib.masked.textctrl.PreMaskedTextCtrl", + "wx.lib.masked.textctrl.TextCtrl", + "wx.lib.masked.timectrl.TimeCtrl ",]], + "wx.py.crust.Calltip", + "wx.lib.sheet.CTextCellEditor", + "wx.py.crust.DispatcherListing", + "wx.lib.intctrl.IntCtrl", + "wx.lib.rightalign.RightTextCtrl", + "wx.py.crust.SessionListing",]], + "wx.ToggleButton", + "wx.ToolBar", + ["wx.TreeCtrl",[ + "wx.py.filling.FillingTree", + "wx.gizmos.RemotelyScrolledTreeCtrl ",]], + "wx.gizmos.TreeListCtrl ",]], + "wx.gizmos.DynamicSashWindow", + "wx.lib.multisash.EmptyChild", + "wx.glcanvas.GLCanvas", + "wx.lib.imagebrowser.ImageView", + "wx.MDIClientWindow", + "wx.MenuBar", + "wx.lib.multisash.MultiClient", + "wx.lib.multisash.MultiCloser", + "wx.lib.multisash.MultiCreator", + "wx.lib.multisash.MultiSash", + "wx.lib.multisash.MultiSizer", + "wx.lib.multisash.MultiSplit", + "wx.lib.multisash.MultiViewLeaf", + ["wx.Panel",[ + "wx.gizmos.EditableListBox", + ["wx.lib.filebrowsebutton.FileBrowseButton",[ + "wx.lib.filebrowsebutton.DirBrowseButton", + "wx.lib.filebrowsebutton.FileBrowseButtonWithHistory",]], + "wx.lib.floatcanvas.FloatCanvas.FloatCanvas", + "wx.lib.floatcanvas.NavCanvas.NavCanvas", + "wx.NotebookPage", + ["wx.PreviewControlBar",[ + "wx.PyPreviewControlBar ",]], + "wx.lib.colourchooser.pycolourbox.PyColourBox", + "wx.lib.colourchooser.pycolourchooser.PyColourChooser", + ["wx.PyPanel",[ + "wx.lib.throbber.Throbber",]], + "wx.lib.shell.PyShell", + "wx.lib.shell.PyShellInput", + "wx.lib.shell.PyShellOutput", + ["wx.ScrolledWindow",[ + "wx.lib.editor.editor.Editor", + ["wx.grid.Grid",[ + "wx.lib.sheet.CSheet ",]], + ["wx.html.HtmlWindow",[ + "wx.lib.ClickableHtmlWindow.PyClickableHtmlWindow",]], + "wx.PreviewCanvas", + "wx.lib.printout.PrintTableDraw", + ["wx.PyScrolledWindow",[ + "wx.lib.scrolledpanel.ScrolledPanel",]], + "wx.lib.ogl.ShapeCanvas", + "wx.gizmos.SplitterScrolledWindow ",]], + ["wx.VScrolledWindow",[ + ["wx.VListBox", [ + "wx.HtmlListBox ",]] ]], + ["wx.wizard.WizardPage", [ + "wx.wizard.PyWizardPage", + "wx.wizard.WizardPageSimple ",]], + "wx.lib.plot.PlotCanvas", + "wx.lib.wxPlotCanvas.PlotCanvas", + ["wx.PopupWindow",[ + "wx.lib.foldmenu.FoldOutWindow", + ["wx.PopupTransientWindow",[ + "wx.TipWindow ",]] ]], + ["wx.PyWindow", [ + "wx.lib.analogclock.AnalogClockWindow",]], + "wx.lib.gridmovers.RowDragWindow", + ["wx.SashWindow",[ + "wx.SashLayoutWindow ",]], + "wx.SplashScreenWindow", + ["wx.SplitterWindow",[ + "wx.py.crust.Crust", + "wx.py.filling.Filling", + "wx.gizmos.ThinSplitterWindow ",]], + "wx.StatusBar", + ["wx.TopLevelWindow",[ + ["wx.Dialog",[ + "wx.lib.calendar.CalenDlg", + "wx.ColourDialog", + "wx.DirDialog", + "wx.FileDialog", + "wx.FindReplaceDialog", + "wx.FontDialog", + "wx.lib.imagebrowser.ImageDialog", + "wx.MessageDialog", + "wx.MultiChoiceDialog", + "wx.lib.dialogs.MultipleChoiceDialog", + "wx.PageSetupDialog", + "wx.lib.popupctl.PopupDialog", + "wx.PrintDialog", + "wx.lib.dialogs.ScrolledMessageDialog", + "wx.SingleChoiceDialog", + "wx.TextEntryDialog", + "wx.wizard.Wizard ",]], + ["wx.Frame", [ + "wx.lib.analogclockopts.ACCustomizationFrame", + "wx.py.filling.FillingFrame", + ["wx.py.frame.Frame",[ + "wx.py.crust.CrustFrame", + ["wx.py.editor.EditorFrame",[ + "wx.py.editor.EditorNotebookFrame",]], + "wx.py.shell.ShellFrame",]], + "wx.html.HtmlHelpFrame", + "wx.MDIChildFrame", + "wx.MDIParentFrame", + "wx.MiniFrame", + ["wx.PreviewFrame",[ + "wx.PyPreviewFrame ",]], + "wx.ProgressDialog", + "wx.SplashScreen", + "wx.lib.splashscreen.SplashScreen", + "wx.lib.masked.maskededit.test2", + "wx.lib.plot.TestFrame ",]] ]], + "wx.gizmos.TreeCompanionWindow ",]] ]] ]], + "wx.FileHistory", + "wx.FileSystem", + "wx.FindReplaceData", + "wx.FontData", + "wx.FontList", + "wx.FSFile", + ["wx.GDIObject",[ + "wx.Bitmap", + "wx.Brush", + "wx.Cursor", + "wx.Font", + "wx.Icon", + "wx.Palette", + "wx.Pen", + "wx.Region ",]], + "wx.glcanvas.GLContext", + ["wx.grid.GridTableBase", [ + "wx.grid.GridStringTable", + "wx.grid.PyGridTableBase ",]], + ["wx.html.HtmlCell", [ + "wx.html.HtmlColourCell", + "wx.html.HtmlContainerCell", + "wx.html.HtmlFontCell", + "wx.html.HtmlWidgetCell", + "wx.html.HtmlWordCell ",]], + "wx.html.HtmlDCRenderer", + "wx.html.HtmlEasyPrinting", + "wx.html.HtmlFilter", + "wx.html.HtmlLinkInfo", + ["wx.html.HtmlParser", [ + "wx.html.HtmlWinParser ",]], + "wx.html.HtmlTag", + ["wx.html.HtmlTagHandler", [ + ["wx.html.HtmlWinTagHandler", [ + "wx.lib.wxpTag.wxpTagHandler ",]] ]], + "wx.Image", + ["wx.ImageHandler", [ + ["wx.BMPHandler", [ + ["wx.ICOHandler", [ + ["wx.CURHandler", [ + "wx.ANIHandler ",]] ]] ]], + "wx.GIFHandler", + "wx.JPEGHandler", + "wx.PCXHandler", + "wx.PNGHandler", + "wx.PNMHandler", + "wx.TIFFHandler", + "wx.XPMHandler ",]], + "wx.ImageList", + "wx.IndividualLayoutConstraint", + "wx.LayoutAlgorithm", + ["wx.LayoutConstraints", [ + "wx.lib.anchors.LayoutAnchors", + "wx.lib.layoutf.Layoutf",]], + "wx.ListItem", + "wx.Mask", + "wx.MenuItem", + "wx.MetaFile", + "wx.PageSetupDialogData", + "wx.PenList", + "wx.PrintData", + "wx.PrintDialogData", + "wx.Printer", + ["wx.Printout", [ + "wx.html.HtmlPrintout", + "wx.lib.plot.PlotPrintout", + "wx.lib.printout.SetPrintout ",]], + ["wx.PrintPreview", [ + "wx.PyPrintPreview ",]], + "wx.RegionIterator", + ["wx.Sizer", [ + "wx.BookCtrlSizer", + ["wx.BoxSizer", [ + "wx.StaticBoxSizer", ]], + ["wx.GridSizer", [ + ["wx.FlexGridSizer", [ + "wx.GridBagSizer",]] ]], + "wx.NotebookSizer", + "wx.PySizer",]], + ["wx.SizerItem", [ + "wx.GBSizerItem",]], + "wx.SystemOptions", + "wx.ToolBarToolBase", + "wx.ToolTip", + "wx.gizmos.TreeListColumnInfo", + "wx.xrc.XmlDocument", + "wx.xrc.XmlResource", + "wx.xrc.XmlResourceHandler ", +] + + + diff --git a/wxPython/samples/wxPIA_book/Chapter-15/tree_icons.py b/wxPython/samples/wxPIA_book/Chapter-15/tree_icons.py new file mode 100644 index 0000000000..c7730b847f --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-15/tree_icons.py @@ -0,0 +1,65 @@ +import wx +import data + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, + title="simple tree with icons", size=(400,500)) + + # Create an image list + il = wx.ImageList(16,16) + + # Get some standard images from the art provider and add them + # to the image list + self.fldridx = il.Add( + wx.ArtProvider.GetBitmap(wx.ART_FOLDER, + wx.ART_OTHER, (16,16))) + self.fldropenidx = il.Add( + wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, + wx.ART_OTHER, (16,16))) + self.fileidx = il.Add( + wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, + wx.ART_OTHER, (16,16))) + + + # Create the tree + self.tree = wx.TreeCtrl(self) + # Give it the image list + self.tree.AssignImageList(il) + root = self.tree.AddRoot("wx.Object") + self.tree.SetItemImage(root, self.fldridx, + wx.TreeItemIcon_Normal) + self.tree.SetItemImage(root, self.fldropenidx, + wx.TreeItemIcon_Expanded) + + self.AddTreeNodes(root, data.tree) + self.tree.Expand(root) + + + def AddTreeNodes(self, parentItem, items): + for item in items: + if type(item) == str: + newItem = self.tree.AppendItem(parentItem, item) + self.tree.SetItemImage(newItem, self.fileidx, + wx.TreeItemIcon_Normal) + else: + newItem = self.tree.AppendItem(parentItem, item[0]) + self.tree.SetItemImage(newItem, self.fldridx, + wx.TreeItemIcon_Normal) + self.tree.SetItemImage(newItem, self.fldropenidx, + wx.TreeItemIcon_Expanded) + + self.AddTreeNodes(newItem, item[1]) + + + def GetItemText(self, item): + if item: + return self.tree.GetItemText(item) + else: + return "" + +app = wx.PySimpleApp(redirect=True) +frame = TestFrame() +frame.Show() +app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-15/tree_misc.py b/wxPython/samples/wxPIA_book/Chapter-15/tree_misc.py new file mode 100644 index 0000000000..2df8e00fdc --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-15/tree_misc.py @@ -0,0 +1,155 @@ +import wx +import data + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, title="tree: misc tests", size=(400,500)) + + # Create an image list + il = wx.ImageList(16,16) + + # Get some standard images from the art provider and add them + # to the image list + self.fldridx = il.Add( + wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, (16,16))) + self.fldropenidx = il.Add( + wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_OTHER, (16,16))) + self.fileidx = il.Add( + wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, (16,16))) + + + # Create the tree + self.tree = wx.TreeCtrl(self, style=wx.TR_DEFAULT_STYLE | wx.TR_EDIT_LABELS) + + # Give it the image list + self.tree.AssignImageList(il) + + + # Add a root node and assign it some images + root = self.tree.AddRoot("wx.Object") + self.tree.SetItemPyData(root, None) + self.tree.SetItemImage(root, self.fldridx, + wx.TreeItemIcon_Normal) + self.tree.SetItemImage(root, self.fldropenidx, + wx.TreeItemIcon_Expanded) + + # Add nodes from our data set + self.AddTreeNodes(root, data.tree) + + # Bind some interesting events + self.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.OnItemExpanded, self.tree) + self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed, self.tree) + self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged, self.tree) + self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnActivated, self.tree) + + self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnBeginEdit, self.tree) + + + # Expand the first level + self.tree.Expand(root) + + + menu = wx.Menu() + mi = menu.Append(-1, "Edit Item") + self.Bind(wx.EVT_MENU, self.OnEditItem, mi) + mi = menu.Append(-1, "Sort Children") + self.Bind(wx.EVT_MENU, self.OnSortChildren, mi) + mi = menu.Append(-1, "Delete Children") + self.Bind(wx.EVT_MENU, self.OnDeleteChildren, mi) + mi = menu.Append(-1, "Find all Children") + self.Bind(wx.EVT_MENU, self.OnFindChildren, mi) + mb = wx.MenuBar() + mb.Append(menu, "Tests") + self.SetMenuBar(mb) + + + def AddTreeNodes(self, parentItem, items): + """ + Recursively traverses the data structure, adding tree nodes to + match it. + """ + for item in items: + if type(item) == str: + newItem = self.tree.AppendItem(parentItem, item) + self.tree.SetItemPyData(newItem, None) + self.tree.SetItemImage(newItem, self.fileidx, + wx.TreeItemIcon_Normal) + else: + newItem = self.tree.AppendItem(parentItem, item[0]) + self.tree.SetItemPyData(newItem, None) + self.tree.SetItemImage(newItem, self.fldridx, + wx.TreeItemIcon_Normal) + self.tree.SetItemImage(newItem, self.fldropenidx, + wx.TreeItemIcon_Expanded) + + self.AddTreeNodes(newItem, item[1]) + + + def GetItemText(self, item): + if item: + return self.tree.GetItemText(item) + else: + return "" + + def OnItemExpanded(self, evt): + print "OnItemExpanded: ", self.GetItemText(evt.GetItem()) + + def OnItemCollapsed(self, evt): + print "OnItemCollapsed:", self.GetItemText(evt.GetItem()) + + def OnSelChanged(self, evt): + print "OnSelChanged: ", self.GetItemText(evt.GetItem()) + + def OnActivated(self, evt): + print "OnActivated: ", self.GetItemText(evt.GetItem()) + + + def OnBeginEdit(self, evt): + print "OnBeginEdit: ", self.GetItemText(evt.GetItem()) + # we can prevent nodes from being edited, for example let's + # not let the root node be edited... + item = evt.GetItem() + if item == self.tree.GetRootItem(): + evt.Veto() + print "*** Edit was vetoed!" + + + def OnEditItem(self, evt): + item = self.tree.GetSelection() + if item: + self.tree.EditLabel(item) + + def OnSortChildren(self, evt): + item = self.tree.GetSelection() + if item: + self.tree.SortChildren(item) + + def OnDeleteChildren(self, evt): + item = self.tree.GetSelection() + if item: + self.tree.DeleteChildren(item) + + def OnFindChildren(self, evt): + item = self.tree.GetSelection() + if item: + self.PrintAllItems(item) + + def PrintAllItems(self, parent, indent=0): + text = self.tree.GetItemText(parent) + print ' ' * indent, text + indent += 4 + item, cookie = self.tree.GetFirstChild(parent) + while item: + if self.tree.ItemHasChildren(item): + self.PrintAllItems(item, indent) + else: + text = self.tree.GetItemText(item) + print ' ' * indent, text + item, cookie = self.tree.GetNextChild(parent, cookie) + + +app = wx.PySimpleApp(redirect=True) +frame = TestFrame() +frame.Show() +app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-15/tree_simple.py b/wxPython/samples/wxPIA_book/Chapter-15/tree_simple.py new file mode 100644 index 0000000000..b04beabbf5 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-15/tree_simple.py @@ -0,0 +1,62 @@ +import wx +import data + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, title="simple tree", size=(400,500)) + + # Create the tree + self.tree = wx.TreeCtrl(self) + + # Add a root node + root = self.tree.AddRoot("wx.Object") + + # Add nodes from our data set + self.AddTreeNodes(root, data.tree) + + # Bind some interesting events + self.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.OnItemExpanded, self.tree) + self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed, self.tree) + self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged, self.tree) + self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnActivated, self.tree) + + # Expand the first level + self.tree.Expand(root) + + + def AddTreeNodes(self, parentItem, items): + """ + Recursively traverses the data structure, adding tree nodes to + match it. + """ + for item in items: + if type(item) == str: + self.tree.AppendItem(parentItem, item) + else: + newItem = self.tree.AppendItem(parentItem, item[0]) + self.AddTreeNodes(newItem, item[1]) + + def GetItemText(self, item): + if item: + return self.tree.GetItemText(item) + else: + return "" + + def OnItemExpanded(self, evt): + print "OnItemExpanded: ", self.GetItemText(evt.GetItem()) + + def OnItemCollapsed(self, evt): + print "OnItemCollapsed:", self.GetItemText(evt.GetItem()) + + def OnSelChanged(self, evt): + print "OnSelChanged: ", self.GetItemText(evt.GetItem()) + + def OnActivated(self, evt): + print "OnActivated: ", self.GetItemText(evt.GetItem()) + + +app = wx.PySimpleApp(redirect=True) +frame = TestFrame() +frame.Show() +app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-15/tree_treelist.py b/wxPython/samples/wxPIA_book/Chapter-15/tree_treelist.py new file mode 100644 index 0000000000..e35bfc1108 --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-15/tree_treelist.py @@ -0,0 +1,104 @@ +import wx +import wx.gizmos +import data + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, title="TreeListCtrl", size=(400,500)) + + # Create an image list + il = wx.ImageList(16,16) + + # Get some standard images from the art provider and add them + # to the image list + self.fldridx = il.Add( + wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, (16,16))) + self.fldropenidx = il.Add( + wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_OTHER, (16,16))) + self.fileidx = il.Add( + wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, (16,16))) + + + # Create the tree + self.tree = wx.gizmos.TreeListCtrl(self, style = + wx.TR_DEFAULT_STYLE + | wx.TR_FULL_ROW_HIGHLIGHT) + + # Give it the image list + self.tree.AssignImageList(il) + + + # create some columns + self.tree.AddColumn("Class Name") + self.tree.AddColumn("Description") + self.tree.SetMainColumn(0) # the one with the tree in it... + self.tree.SetColumnWidth(0, 200) + self.tree.SetColumnWidth(1, 200) + + # Add a root node and assign it some images + root = self.tree.AddRoot("wx.Object") + self.tree.SetItemText(root, "A description of wx.Object", 1) + self.tree.SetItemImage(root, self.fldridx, + wx.TreeItemIcon_Normal) + self.tree.SetItemImage(root, self.fldropenidx, + wx.TreeItemIcon_Expanded) + + # Add nodes from our data set + self.AddTreeNodes(root, data.tree) + + # Bind some interesting events + self.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.OnItemExpanded, self.tree) + self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed, self.tree) + self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged, self.tree) + self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnActivated, self.tree) + + # Expand the first level + self.tree.Expand(root) + + + def AddTreeNodes(self, parentItem, items): + """ + Recursively traverses the data structure, adding tree nodes to + match it. + """ + for item in items: + if type(item) == str: + newItem = self.tree.AppendItem(parentItem, item) + self.tree.SetItemText(newItem, "A description of %s" % item, 1) + self.tree.SetItemImage(newItem, self.fileidx, + wx.TreeItemIcon_Normal) + else: + newItem = self.tree.AppendItem(parentItem, item[0]) + self.tree.SetItemText(newItem, "A description of %s" % item[0], 1) + self.tree.SetItemImage(newItem, self.fldridx, + wx.TreeItemIcon_Normal) + self.tree.SetItemImage(newItem, self.fldropenidx, + wx.TreeItemIcon_Expanded) + + self.AddTreeNodes(newItem, item[1]) + + + def GetItemText(self, item): + if item: + return self.tree.GetItemText(item) + else: + return "" + + def OnItemExpanded(self, evt): + print "OnItemExpanded: ", self.GetItemText(evt.GetItem()) + + def OnItemCollapsed(self, evt): + print "OnItemCollapsed:", self.GetItemText(evt.GetItem()) + + def OnSelChanged(self, evt): + print "OnSelChanged: ", self.GetItemText(evt.GetItem()) + + def OnActivated(self, evt): + print "OnActivated: ", self.GetItemText(evt.GetItem()) + + +app = wx.PySimpleApp(redirect=True) +frame = TestFrame() +frame.Show() +app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-15/tree_virtual.py b/wxPython/samples/wxPIA_book/Chapter-15/tree_virtual.py new file mode 100644 index 0000000000..795596b93f --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-15/tree_virtual.py @@ -0,0 +1,92 @@ +import wx +import data + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, title="virtual tree with icons", size=(400,500)) + il = wx.ImageList(16,16) + self.fldridx = il.Add( + wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, (16,16))) + self.fldropenidx = il.Add( + wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_OTHER, (16,16))) + self.fileidx = il.Add( + wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, (16,16))) + self.tree = wx.TreeCtrl(self) + self.tree.AssignImageList(il) + root = self.tree.AddRoot("wx.Object") + self.tree.SetItemImage(root, self.fldridx, + wx.TreeItemIcon_Normal) + self.tree.SetItemImage(root, self.fldropenidx, + wx.TreeItemIcon_Expanded) + + # Instead of adding nodes for the whole tree, just attach some + # data to the root node so that it can find and add its child + # nodes when it is expanded, and mark it as having children so + # it will be expandable. + self.tree.SetItemPyData(root, data.tree) + self.tree.SetItemHasChildren(root, True) + + # Bind some interesting events + self.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.OnItemExpanded, self.tree) + self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed, self.tree) + self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged, self.tree) + self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnActivated, self.tree) + + self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.OnItemExpanding, self.tree) + self.tree.Expand(root) + + + def AddTreeNodes(self, parentItem): + """ + Add nodes for just the children of the parentItem + """ + items = self.tree.GetItemPyData(parentItem) + for item in items: + if type(item) == str: + # a leaf node + newItem = self.tree.AppendItem(parentItem, item) + self.tree.SetItemImage(newItem, self.fileidx, + wx.TreeItemIcon_Normal) + else: + # this item has children + newItem = self.tree.AppendItem(parentItem, item[0]) + self.tree.SetItemImage(newItem, self.fldridx, + wx.TreeItemIcon_Normal) + self.tree.SetItemImage(newItem, self.fldropenidx, + wx.TreeItemIcon_Expanded) + self.tree.SetItemPyData(newItem, item[1]) + self.tree.SetItemHasChildren(newItem, True) + + + + def GetItemText(self, item): + if item: + return self.tree.GetItemText(item) + else: + return "" + + def OnItemExpanded(self, evt): + print "OnItemExpanded: ", self.GetItemText(evt.GetItem()) + + def OnItemExpanding(self, evt): + # When the item is about to be expanded add the first level of child nodes + print "OnItemExpanding:", self.GetItemText(evt.GetItem()) + self.AddTreeNodes(evt.GetItem()) + + def OnItemCollapsed(self, evt): + print "OnItemCollapsed:", self.GetItemText(evt.GetItem()) + # And remove them when collapsed as we don't need them any longer + self.tree.DeleteChildren(evt.GetItem()) + + def OnSelChanged(self, evt): + print "OnSelChanged: ", self.GetItemText(evt.GetItem()) + + def OnActivated(self, evt): + print "OnActivated: ", self.GetItemText(evt.GetItem()) + + +app = wx.PySimpleApp(redirect=True) +frame = TestFrame() +frame.Show() +app.MainLoop() + diff --git a/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/Index.hhk b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/Index.hhk new file mode 100644 index 0000000000..1835a2ddcb --- /dev/null +++ b/wxPython/samples/wxPIA_book/Chapter-16/helpfiles/Index.hhk @@ -0,0 +1,71 @@ + + + + + + +