wxPython 4.3.2__cp315-cp315-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (472) hide show
  1. wx/WebView2Loader.dll +0 -0
  2. wx/__init__.py +22 -0
  3. wx/__init__.pyi +10 -0
  4. wx/__version__.py +9 -0
  5. wx/__version__.pyi +15 -0
  6. wx/_adv.cp315-win_amd64.pyd +0 -0
  7. wx/_aui.cp315-win_amd64.pyd +0 -0
  8. wx/_core.cp315-win_amd64.pyd +0 -0
  9. wx/_dataview.cp315-win_amd64.pyd +0 -0
  10. wx/_glcanvas.cp315-win_amd64.pyd +0 -0
  11. wx/_grid.cp315-win_amd64.pyd +0 -0
  12. wx/_html.cp315-win_amd64.pyd +0 -0
  13. wx/_html2.cp315-win_amd64.pyd +0 -0
  14. wx/_media.cp315-win_amd64.pyd +0 -0
  15. wx/_msw.cp315-win_amd64.pyd +0 -0
  16. wx/_propgrid.cp315-win_amd64.pyd +0 -0
  17. wx/_ribbon.cp315-win_amd64.pyd +0 -0
  18. wx/_richtext.cp315-win_amd64.pyd +0 -0
  19. wx/_stc.cp315-win_amd64.pyd +0 -0
  20. wx/_xml.cp315-win_amd64.pyd +0 -0
  21. wx/_xrc.cp315-win_amd64.pyd +0 -0
  22. wx/adv.py +127 -0
  23. wx/adv.pyi +5931 -0
  24. wx/aui.py +70 -0
  25. wx/aui.pyi +4805 -0
  26. wx/core.py +3417 -0
  27. wx/core.pyi +62949 -0
  28. wx/dataview.py +176 -0
  29. wx/dataview.pyi +3828 -0
  30. wx/gizmos.py +18 -0
  31. wx/glcanvas.py +13 -0
  32. wx/glcanvas.pyi +544 -0
  33. wx/grid.py +237 -0
  34. wx/grid.pyi +5678 -0
  35. wx/html.py +38 -0
  36. wx/html.pyi +3283 -0
  37. wx/html2.py +46 -0
  38. wx/html2.pyi +1301 -0
  39. wx/include/wxPython/sip.h +1938 -0
  40. wx/include/wxPython/wxpy_api.h +418 -0
  41. wx/lib/CDate.py +201 -0
  42. wx/lib/ClickableHtmlWindow.py +57 -0
  43. wx/lib/__init__.py +0 -0
  44. wx/lib/activex.py +178 -0
  45. wx/lib/activexwrapper.py +153 -0
  46. wx/lib/agw/__init__.py +128 -0
  47. wx/lib/agw/advancedsplash.py +563 -0
  48. wx/lib/agw/aquabutton.py +1127 -0
  49. wx/lib/agw/artmanager.py +2110 -0
  50. wx/lib/agw/aui/__init__.py +295 -0
  51. wx/lib/agw/aui/aui_constants.py +2616 -0
  52. wx/lib/agw/aui/aui_switcherdialog.py +1232 -0
  53. wx/lib/agw/aui/aui_utilities.py +648 -0
  54. wx/lib/agw/aui/auibar.py +4045 -0
  55. wx/lib/agw/aui/auibook.py +6288 -0
  56. wx/lib/agw/aui/dockart.py +1198 -0
  57. wx/lib/agw/aui/framemanager.py +10485 -0
  58. wx/lib/agw/aui/tabart.py +2749 -0
  59. wx/lib/agw/aui/tabmdi.py +679 -0
  60. wx/lib/agw/balloontip.py +1157 -0
  61. wx/lib/agw/buttonpanel.py +2787 -0
  62. wx/lib/agw/cubecolourdialog.py +3529 -0
  63. wx/lib/agw/customtreectrl.py +9908 -0
  64. wx/lib/agw/data/ShortcutEditor_1.png +0 -0
  65. wx/lib/agw/data/ShortcutEditor_1_thumb.png +0 -0
  66. wx/lib/agw/data/ShortcutEditor_2.png +0 -0
  67. wx/lib/agw/data/ShortcutEditor_2_thumb.png +0 -0
  68. wx/lib/agw/data/ShortcutEditor_3.png +0 -0
  69. wx/lib/agw/data/ShortcutEditor_3_thumb.png +0 -0
  70. wx/lib/agw/data/ShortcutEditor_4.png +0 -0
  71. wx/lib/agw/data/ShortcutEditor_4_thumb.png +0 -0
  72. wx/lib/agw/data/default_help_text.html +105 -0
  73. wx/lib/agw/flatmenu.py +7392 -0
  74. wx/lib/agw/flatnotebook.py +6669 -0
  75. wx/lib/agw/floatspin.py +1820 -0
  76. wx/lib/agw/fmcustomizedlg.py +535 -0
  77. wx/lib/agw/fmresources.py +407 -0
  78. wx/lib/agw/foldpanelbar.py +2282 -0
  79. wx/lib/agw/fourwaysplitter.py +1130 -0
  80. wx/lib/agw/genericmessagedialog.py +1549 -0
  81. wx/lib/agw/gradientbutton.py +731 -0
  82. wx/lib/agw/hyperlink.py +664 -0
  83. wx/lib/agw/hypertreelist.py +5756 -0
  84. wx/lib/agw/infobar.py +885 -0
  85. wx/lib/agw/knobctrl.py +944 -0
  86. wx/lib/agw/labelbook.py +3028 -0
  87. wx/lib/agw/multidirdialog.py +581 -0
  88. wx/lib/agw/peakmeter.py +1028 -0
  89. wx/lib/agw/persist/__init__.py +188 -0
  90. wx/lib/agw/persist/persist_constants.py +283 -0
  91. wx/lib/agw/persist/persist_handlers.py +2614 -0
  92. wx/lib/agw/persist/persistencemanager.py +863 -0
  93. wx/lib/agw/piectrl.py +1082 -0
  94. wx/lib/agw/pybusyinfo.py +399 -0
  95. wx/lib/agw/pycollapsiblepane.py +940 -0
  96. wx/lib/agw/pygauge.py +570 -0
  97. wx/lib/agw/pyprogress.py +916 -0
  98. wx/lib/agw/ribbon/__init__.py +198 -0
  99. wx/lib/agw/ribbon/art.py +219 -0
  100. wx/lib/agw/ribbon/art_aui.py +1283 -0
  101. wx/lib/agw/ribbon/art_default.py +81 -0
  102. wx/lib/agw/ribbon/art_internal.py +248 -0
  103. wx/lib/agw/ribbon/art_msw.py +2735 -0
  104. wx/lib/agw/ribbon/art_osx.py +52 -0
  105. wx/lib/agw/ribbon/bar.py +1259 -0
  106. wx/lib/agw/ribbon/buttonbar.py +1317 -0
  107. wx/lib/agw/ribbon/control.py +205 -0
  108. wx/lib/agw/ribbon/gallery.py +973 -0
  109. wx/lib/agw/ribbon/page.py +946 -0
  110. wx/lib/agw/ribbon/panel.py +1170 -0
  111. wx/lib/agw/ribbon/toolbar.py +1441 -0
  112. wx/lib/agw/rulerctrl.py +1885 -0
  113. wx/lib/agw/scrolledthumbnail.py +2116 -0
  114. wx/lib/agw/shapedbutton.py +1809 -0
  115. wx/lib/agw/shortcuteditor.py +2642 -0
  116. wx/lib/agw/speedmeter.py +1800 -0
  117. wx/lib/agw/supertooltip.py +1443 -0
  118. wx/lib/agw/thumbnailctrl.py +529 -0
  119. wx/lib/agw/toasterbox.py +1327 -0
  120. wx/lib/agw/ultimatelistctrl.py +13671 -0
  121. wx/lib/agw/xlsgrid.py +2111 -0
  122. wx/lib/agw/zoombar.py +1336 -0
  123. wx/lib/analogclock/__init__.py +140 -0
  124. wx/lib/analogclock/analogclock.py +630 -0
  125. wx/lib/analogclock/helpers.py +986 -0
  126. wx/lib/analogclock/lib_setup/__init__.py +0 -0
  127. wx/lib/analogclock/lib_setup/buttontreectrlpanel.py +297 -0
  128. wx/lib/analogclock/lib_setup/fontselect.py +57 -0
  129. wx/lib/analogclock/setup.py +490 -0
  130. wx/lib/analogclock/styles.py +47 -0
  131. wx/lib/anchors.py +103 -0
  132. wx/lib/art/__init__.py +4 -0
  133. wx/lib/art/flagart.py +1583 -0
  134. wx/lib/art/img2pyartprov.py +56 -0
  135. wx/lib/busy.py +152 -0
  136. wx/lib/buttons.py +1140 -0
  137. wx/lib/calendar.py +1596 -0
  138. wx/lib/checkbox.py +837 -0
  139. wx/lib/colourchooser/__init__.py +36 -0
  140. wx/lib/colourchooser/canvas.py +145 -0
  141. wx/lib/colourchooser/intl.py +24 -0
  142. wx/lib/colourchooser/pycolourbox.py +89 -0
  143. wx/lib/colourchooser/pycolourchooser.py +626 -0
  144. wx/lib/colourchooser/pycolourslider.py +98 -0
  145. wx/lib/colourchooser/pypalette.py +208 -0
  146. wx/lib/colourdb.py +740 -0
  147. wx/lib/colourselect.py +385 -0
  148. wx/lib/colourutils.py +118 -0
  149. wx/lib/combotreebox.py +944 -0
  150. wx/lib/delayedresult.py +420 -0
  151. wx/lib/dialogs.py +510 -0
  152. wx/lib/docview.py +3210 -0
  153. wx/lib/dragscroller.py +79 -0
  154. wx/lib/editor/README.txt +77 -0
  155. wx/lib/editor/__init__.py +24 -0
  156. wx/lib/editor/editor.py +974 -0
  157. wx/lib/editor/images.py +15 -0
  158. wx/lib/editor/selection.py +44 -0
  159. wx/lib/embeddedimage.py +76 -0
  160. wx/lib/eventStack.py +136 -0
  161. wx/lib/eventwatcher.py +440 -0
  162. wx/lib/evtmgr.py +521 -0
  163. wx/lib/expando.py +393 -0
  164. wx/lib/fancytext.py +494 -0
  165. wx/lib/filebrowsebutton.py +461 -0
  166. wx/lib/flashwin.py +262 -0
  167. wx/lib/flashwin_old.py +651 -0
  168. wx/lib/floatcanvas/FCEvents.py +53 -0
  169. wx/lib/floatcanvas/FCObjects.py +2910 -0
  170. wx/lib/floatcanvas/FloatCanvas.py +1025 -0
  171. wx/lib/floatcanvas/GUIMode.py +396 -0
  172. wx/lib/floatcanvas/NavCanvas.py +162 -0
  173. wx/lib/floatcanvas/Resources.py +319 -0
  174. wx/lib/floatcanvas/ScreenShot.py +1788 -0
  175. wx/lib/floatcanvas/Utilities/BBox.py +313 -0
  176. wx/lib/floatcanvas/Utilities/Colors.py +137 -0
  177. wx/lib/floatcanvas/Utilities/GUI.py +91 -0
  178. wx/lib/floatcanvas/Utilities/__init__.py +7 -0
  179. wx/lib/floatcanvas/__init__.py +124 -0
  180. wx/lib/foldmenu.py +89 -0
  181. wx/lib/gestures.py +310 -0
  182. wx/lib/gizmos/__init__.py +18 -0
  183. wx/lib/gizmos/dynamicsash.py +1202 -0
  184. wx/lib/gizmos/ledctrl.py +299 -0
  185. wx/lib/gizmos/treelistctrl.py +87 -0
  186. wx/lib/graphics.py +1942 -0
  187. wx/lib/gridmovers.py +516 -0
  188. wx/lib/iewin.py +249 -0
  189. wx/lib/iewin_old.py +894 -0
  190. wx/lib/imagebrowser.py +853 -0
  191. wx/lib/imageutils.py +163 -0
  192. wx/lib/infoframe.py +490 -0
  193. wx/lib/inspection.py +1254 -0
  194. wx/lib/intctrl.py +990 -0
  195. wx/lib/itemspicker.py +256 -0
  196. wx/lib/langlistctrl.py +480 -0
  197. wx/lib/layoutf.py +271 -0
  198. wx/lib/masked/__init__.py +27 -0
  199. wx/lib/masked/combobox.py +839 -0
  200. wx/lib/masked/ctrl.py +108 -0
  201. wx/lib/masked/ipaddrctrl.py +241 -0
  202. wx/lib/masked/maskededit.py +7262 -0
  203. wx/lib/masked/numctrl.py +2000 -0
  204. wx/lib/masked/textctrl.py +465 -0
  205. wx/lib/masked/timectrl.py +1465 -0
  206. wx/lib/mixins/__init__.py +17 -0
  207. wx/lib/mixins/grid.py +47 -0
  208. wx/lib/mixins/gridlabelrenderer.py +277 -0
  209. wx/lib/mixins/imagelist.py +77 -0
  210. wx/lib/mixins/inspection.py +184 -0
  211. wx/lib/mixins/listctrl.py +893 -0
  212. wx/lib/mixins/rubberband.py +403 -0
  213. wx/lib/mixins/treemixin.py +678 -0
  214. wx/lib/msgpanel.py +95 -0
  215. wx/lib/multisash.py +746 -0
  216. wx/lib/myole4ax.idl +178 -0
  217. wx/lib/myole4ax.tlb +0 -0
  218. wx/lib/newevent.py +229 -0
  219. wx/lib/newevent.pyi +25 -0
  220. wx/lib/nvdlg.py +156 -0
  221. wx/lib/ogl/__init__.py +13 -0
  222. wx/lib/ogl/basic.py +3989 -0
  223. wx/lib/ogl/bmpshape.py +86 -0
  224. wx/lib/ogl/canvas.py +467 -0
  225. wx/lib/ogl/composit.py +1576 -0
  226. wx/lib/ogl/diagram.py +230 -0
  227. wx/lib/ogl/divided.py +482 -0
  228. wx/lib/ogl/drawn.py +898 -0
  229. wx/lib/ogl/lines.py +1809 -0
  230. wx/lib/ogl/oglmisc.py +607 -0
  231. wx/lib/pdfviewer/__init__.py +113 -0
  232. wx/lib/pdfviewer/bitmaps/ArrowLeft.png +0 -0
  233. wx/lib/pdfviewer/bitmaps/ArrowRight.png +0 -0
  234. wx/lib/pdfviewer/bitmaps/DirectionH.png +0 -0
  235. wx/lib/pdfviewer/bitmaps/DirectionV.png +0 -0
  236. wx/lib/pdfviewer/bitmaps/PlayerFirst.png +0 -0
  237. wx/lib/pdfviewer/bitmaps/PlayerLast.png +0 -0
  238. wx/lib/pdfviewer/bitmaps/PlayerNext.png +0 -0
  239. wx/lib/pdfviewer/bitmaps/PlayerPrev.png +0 -0
  240. wx/lib/pdfviewer/bitmaps/Printer.png +0 -0
  241. wx/lib/pdfviewer/bitmaps/ReadMe.txt +28 -0
  242. wx/lib/pdfviewer/bitmaps/Save.png +0 -0
  243. wx/lib/pdfviewer/bitmaps/ZoomIn.png +0 -0
  244. wx/lib/pdfviewer/bitmaps/ZoomOut.png +0 -0
  245. wx/lib/pdfviewer/bitmaps/encode_bitmaps.py +37 -0
  246. wx/lib/pdfviewer/buttonpanel.py +285 -0
  247. wx/lib/pdfviewer/images.py +240 -0
  248. wx/lib/pdfviewer/viewer.py +1118 -0
  249. wx/lib/pdfwin.py +295 -0
  250. wx/lib/pdfwin_old.py +789 -0
  251. wx/lib/platebtn.py +789 -0
  252. wx/lib/plot/CHANGELOG.md +150 -0
  253. wx/lib/plot/README.md +16 -0
  254. wx/lib/plot/__init__.py +46 -0
  255. wx/lib/plot/__main__.py +5 -0
  256. wx/lib/plot/examples/__init__.py +0 -0
  257. wx/lib/plot/examples/demo.py +1010 -0
  258. wx/lib/plot/examples/simple_example.py +56 -0
  259. wx/lib/plot/plotcanvas.py +2985 -0
  260. wx/lib/plot/polyobjects.py +1524 -0
  261. wx/lib/plot/utils.py +334 -0
  262. wx/lib/popupctl.py +251 -0
  263. wx/lib/printout.py +1155 -0
  264. wx/lib/progressindicator.py +151 -0
  265. wx/lib/pubsub/LICENSE_BSD_Simple.txt +23 -0
  266. wx/lib/pubsub/README_WxPython.txt +22 -0
  267. wx/lib/pubsub/RELEASE_NOTES.txt +71 -0
  268. wx/lib/pubsub/__init__.py +25 -0
  269. wx/lib/pubsub/core/__init__.py +92 -0
  270. wx/lib/pubsub/core/arg1/__init__.py +16 -0
  271. wx/lib/pubsub/core/arg1/listenerimpl.py +97 -0
  272. wx/lib/pubsub/core/arg1/publisher.py +40 -0
  273. wx/lib/pubsub/core/arg1/publishermixin.py +34 -0
  274. wx/lib/pubsub/core/arg1/topicargspecimpl.py +66 -0
  275. wx/lib/pubsub/core/arg1/topicmgrimpl.py +19 -0
  276. wx/lib/pubsub/core/callables.py +198 -0
  277. wx/lib/pubsub/core/imp2.py +62 -0
  278. wx/lib/pubsub/core/itopicdefnprovider.py +0 -0
  279. wx/lib/pubsub/core/kwargs/__init__.py +16 -0
  280. wx/lib/pubsub/core/kwargs/datamsg.py +27 -0
  281. wx/lib/pubsub/core/kwargs/listenerimpl.py +93 -0
  282. wx/lib/pubsub/core/kwargs/publisher.py +77 -0
  283. wx/lib/pubsub/core/kwargs/publishermixin.py +65 -0
  284. wx/lib/pubsub/core/kwargs/topicargspecimpl.py +216 -0
  285. wx/lib/pubsub/core/kwargs/topicmgrimpl.py +13 -0
  286. wx/lib/pubsub/core/listener.py +40 -0
  287. wx/lib/pubsub/core/listenerbase.py +185 -0
  288. wx/lib/pubsub/core/notificationmgr.py +185 -0
  289. wx/lib/pubsub/core/publisherbase.py +189 -0
  290. wx/lib/pubsub/core/topicargspec.py +77 -0
  291. wx/lib/pubsub/core/topicdefnprovider.py +631 -0
  292. wx/lib/pubsub/core/topicexc.py +72 -0
  293. wx/lib/pubsub/core/topicmgr.py +454 -0
  294. wx/lib/pubsub/core/topicobj.py +472 -0
  295. wx/lib/pubsub/core/topictreetraverser.py +143 -0
  296. wx/lib/pubsub/core/topicutils.py +119 -0
  297. wx/lib/pubsub/core/treeconfig.py +21 -0
  298. wx/lib/pubsub/core/validatedefnargs.py +29 -0
  299. wx/lib/pubsub/core/weakmethod.py +102 -0
  300. wx/lib/pubsub/policies.py +24 -0
  301. wx/lib/pubsub/pub.py +199 -0
  302. wx/lib/pubsub/setuparg1.py +47 -0
  303. wx/lib/pubsub/setupkwargs.py +29 -0
  304. wx/lib/pubsub/utils/__init__.py +27 -0
  305. wx/lib/pubsub/utils/exchandling.py +100 -0
  306. wx/lib/pubsub/utils/misc.py +99 -0
  307. wx/lib/pubsub/utils/notification.py +331 -0
  308. wx/lib/pubsub/utils/topictreeprinter.py +195 -0
  309. wx/lib/pubsub/utils/xmltopicdefnprovider.py +286 -0
  310. wx/lib/pydocview.py +3300 -0
  311. wx/lib/rcsizer.py +227 -0
  312. wx/lib/resizewidget.py +357 -0
  313. wx/lib/scrolledpanel.py +243 -0
  314. wx/lib/sheet.py +350 -0
  315. wx/lib/sized_controls.py +691 -0
  316. wx/lib/softwareupdate.py +355 -0
  317. wx/lib/splitter.py +925 -0
  318. wx/lib/statbmp.py +199 -0
  319. wx/lib/stattext.py +321 -0
  320. wx/lib/throbber.py +424 -0
  321. wx/lib/ticker.py +306 -0
  322. wx/lib/ticker_xrc.py +48 -0
  323. wx/lib/utils.py +89 -0
  324. wx/lib/wordwrap.py +97 -0
  325. wx/lib/wxcairo/__init__.py +139 -0
  326. wx/lib/wxcairo/wx_cairocffi.py +200 -0
  327. wx/lib/wxcairo/wx_pycairo.py +455 -0
  328. wx/lib/wxpTag.py +274 -0
  329. wx/libcairo-2.dll +0 -0
  330. wx/locale/af/LC_MESSAGES/wxstd.mo +0 -0
  331. wx/locale/an/LC_MESSAGES/wxstd.mo +0 -0
  332. wx/locale/ar/LC_MESSAGES/wxstd.mo +0 -0
  333. wx/locale/ca/LC_MESSAGES/wxstd.mo +0 -0
  334. wx/locale/ca@valencia/LC_MESSAGES/wxstd.mo +0 -0
  335. wx/locale/co/LC_MESSAGES/wxstd.mo +0 -0
  336. wx/locale/cs/LC_MESSAGES/wxstd.mo +0 -0
  337. wx/locale/da/LC_MESSAGES/wxstd.mo +0 -0
  338. wx/locale/de/LC_MESSAGES/wxstd.mo +0 -0
  339. wx/locale/el/LC_MESSAGES/wxstd.mo +0 -0
  340. wx/locale/es/LC_MESSAGES/wxstd.mo +0 -0
  341. wx/locale/eu/LC_MESSAGES/wxstd.mo +0 -0
  342. wx/locale/fa_IR/LC_MESSAGES/wxstd.mo +0 -0
  343. wx/locale/fi/LC_MESSAGES/wxstd.mo +0 -0
  344. wx/locale/fr/LC_MESSAGES/wxstd.mo +0 -0
  345. wx/locale/gl_ES/LC_MESSAGES/wxstd.mo +0 -0
  346. wx/locale/hi/LC_MESSAGES/wxstd.mo +0 -0
  347. wx/locale/hr/LC_MESSAGES/wxstd.mo +0 -0
  348. wx/locale/hu/LC_MESSAGES/wxstd.mo +0 -0
  349. wx/locale/id/LC_MESSAGES/wxstd.mo +0 -0
  350. wx/locale/it/LC_MESSAGES/wxstd.mo +0 -0
  351. wx/locale/ja/LC_MESSAGES/wxstd.mo +0 -0
  352. wx/locale/ka/LC_MESSAGES/wxstd.mo +0 -0
  353. wx/locale/ko_KR/LC_MESSAGES/wxstd.mo +0 -0
  354. wx/locale/lt/LC_MESSAGES/wxstd.mo +0 -0
  355. wx/locale/lv/LC_MESSAGES/wxstd.mo +0 -0
  356. wx/locale/ms/LC_MESSAGES/wxstd.mo +0 -0
  357. wx/locale/nb/LC_MESSAGES/wxstd.mo +0 -0
  358. wx/locale/ne/LC_MESSAGES/wxstd.mo +0 -0
  359. wx/locale/nl/LC_MESSAGES/wxstd.mo +0 -0
  360. wx/locale/pl/LC_MESSAGES/wxstd.mo +0 -0
  361. wx/locale/pt/LC_MESSAGES/wxstd.mo +0 -0
  362. wx/locale/pt_BR/LC_MESSAGES/wxstd.mo +0 -0
  363. wx/locale/ro/LC_MESSAGES/wxstd.mo +0 -0
  364. wx/locale/ru/LC_MESSAGES/wxstd.mo +0 -0
  365. wx/locale/sk/LC_MESSAGES/wxstd.mo +0 -0
  366. wx/locale/sl/LC_MESSAGES/wxstd.mo +0 -0
  367. wx/locale/sq/LC_MESSAGES/wxstd.mo +0 -0
  368. wx/locale/sr/LC_MESSAGES/wxstd.mo +0 -0
  369. wx/locale/sv/LC_MESSAGES/wxstd.mo +0 -0
  370. wx/locale/ta/LC_MESSAGES/wxstd.mo +0 -0
  371. wx/locale/tr/LC_MESSAGES/wxstd.mo +0 -0
  372. wx/locale/uk/LC_MESSAGES/wxstd.mo +0 -0
  373. wx/locale/vi/LC_MESSAGES/wxstd.mo +0 -0
  374. wx/locale/zh_CN/LC_MESSAGES/wxstd.mo +0 -0
  375. wx/locale/zh_TW/LC_MESSAGES/wxstd.mo +0 -0
  376. wx/media.py +30 -0
  377. wx/media.pyi +272 -0
  378. wx/msw.py +16 -0
  379. wx/msw.pyi +91 -0
  380. wx/propgrid.py +498 -0
  381. wx/propgrid.pyi +7427 -0
  382. wx/py/CHANGES.txt +796 -0
  383. wx/py/Py.ico +0 -0
  384. wx/py/PyAlaCarte.py +34 -0
  385. wx/py/PyAlaMode.py +34 -0
  386. wx/py/PyAlaModeTest.py +33 -0
  387. wx/py/PyCrust.ico +0 -0
  388. wx/py/PyCrust.py +78 -0
  389. wx/py/PyCrust_16.png +0 -0
  390. wx/py/PyCrust_32.png +0 -0
  391. wx/py/PyFilling.py +35 -0
  392. wx/py/PyShell.py +78 -0
  393. wx/py/PySlices.ico +0 -0
  394. wx/py/PySlices.py +98 -0
  395. wx/py/PySlicesShell.py +94 -0
  396. wx/py/PySlices_16.png +0 -0
  397. wx/py/PySlices_32.png +0 -0
  398. wx/py/PyWrap.py +52 -0
  399. wx/py/README.txt +77 -0
  400. wx/py/__init__.py +20 -0
  401. wx/py/buffer.py +136 -0
  402. wx/py/crust.py +403 -0
  403. wx/py/crustslices.py +403 -0
  404. wx/py/dispatcher.py +259 -0
  405. wx/py/document.py +37 -0
  406. wx/py/editor.py +844 -0
  407. wx/py/editwindow.py +316 -0
  408. wx/py/filling.py +358 -0
  409. wx/py/frame.py +976 -0
  410. wx/py/images.py +212 -0
  411. wx/py/interpreter.py +161 -0
  412. wx/py/introspect.py +402 -0
  413. wx/py/magic.py +98 -0
  414. wx/py/parse.py +134 -0
  415. wx/py/path.py +36 -0
  416. wx/py/pseudo.py +99 -0
  417. wx/py/shell.py +1579 -0
  418. wx/py/sliceshell.py +3805 -0
  419. wx/py/tests/test_interpreter.py +71 -0
  420. wx/py/tests/test_introspect.py +810 -0
  421. wx/py/tests/test_pseudo.py +70 -0
  422. wx/py/tests/test_version.py +36 -0
  423. wx/py/tests/testall.py +22 -0
  424. wx/py/version.py +7 -0
  425. wx/py.typed +0 -0
  426. wx/ribbon.py +48 -0
  427. wx/ribbon.pyi +3099 -0
  428. wx/richtext.py +141 -0
  429. wx/richtext.pyi +13581 -0
  430. wx/siplib.cp315-win_amd64.pyd +0 -0
  431. wx/siplib.pyi +19 -0
  432. wx/stc.py +59 -0
  433. wx/stc.pyi +9918 -0
  434. wx/svg/__init__.py +363 -0
  435. wx/svg/_nanosvg.cp315-win_amd64.pyd +0 -0
  436. wx/tools/__init__.py +18 -0
  437. wx/tools/dbg.py +268 -0
  438. wx/tools/genaxmodule.py +50 -0
  439. wx/tools/helpviewer.py +92 -0
  440. wx/tools/img2img.py +85 -0
  441. wx/tools/img2png.py +54 -0
  442. wx/tools/img2py.py +306 -0
  443. wx/tools/img2xpm.py +54 -0
  444. wx/tools/pywxrc.py +951 -0
  445. wx/tools/wxget.py +254 -0
  446. wx/tools/wxget_docs_demo.py +183 -0
  447. wx/wxbase334u_net_vc140_x64.dll +0 -0
  448. wx/wxbase334u_vc140_x64.dll +0 -0
  449. wx/wxbase334u_xml_vc140_x64.dll +0 -0
  450. wx/wxmsw334u_adv_vc140_x64.dll +0 -0
  451. wx/wxmsw334u_aui_vc140_x64.dll +0 -0
  452. wx/wxmsw334u_core_vc140_x64.dll +0 -0
  453. wx/wxmsw334u_gl_vc140_x64.dll +0 -0
  454. wx/wxmsw334u_html_vc140_x64.dll +0 -0
  455. wx/wxmsw334u_media_vc140_x64.dll +0 -0
  456. wx/wxmsw334u_propgrid_vc140_x64.dll +0 -0
  457. wx/wxmsw334u_qa_vc140_x64.dll +0 -0
  458. wx/wxmsw334u_ribbon_vc140_x64.dll +0 -0
  459. wx/wxmsw334u_richtext_vc140_x64.dll +0 -0
  460. wx/wxmsw334u_stc_vc140_x64.dll +0 -0
  461. wx/wxmsw334u_webview_vc140_x64.dll +0 -0
  462. wx/wxmsw334u_xrc_vc140_x64.dll +0 -0
  463. wx/xml.py +18 -0
  464. wx/xml.pyi +728 -0
  465. wx/xrc.py +68 -0
  466. wx/xrc.pyi +896 -0
  467. wxpython-4.3.2.dist-info/METADATA +71 -0
  468. wxpython-4.3.2.dist-info/RECORD +472 -0
  469. wxpython-4.3.2.dist-info/WHEEL +5 -0
  470. wxpython-4.3.2.dist-info/entry_points.txt +13 -0
  471. wxpython-4.3.2.dist-info/licenses/LICENSE.txt +610 -0
  472. wxpython-4.3.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2642 @@
1
+ # --------------------------------------------------------------------------------- #
2
+ # SHORTCUTEDITOR wxPython IMPLEMENTATION
3
+ # Inspired By the GIMP Shortcut Editor.
4
+ #
5
+ # Andrea Gavana, @ 05 March 2012
6
+ # Latest Revision: 27 Dec 2012, 21.00 GMT
7
+ #
8
+ #
9
+ # TODO List
10
+ #
11
+ # 1. Check the various IDs in the KEYMAP dictionary to try and understand if all
12
+ # the possible shortcut combinations can be handled.
13
+ #
14
+ # 2. Verify that the current shortcut handling is working as advertised.
15
+ #
16
+ #
17
+ # For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
18
+ # Write To Me At:
19
+ #
20
+ # andrea.gavana@maerskoil.com
21
+ # andrea.gavana@gmail.com
22
+ #
23
+ # Or, Obviously, To The wxPython Mailing List!!!
24
+ #
25
+ # Tags: phoenix-port, unittest, documented, py3-port
26
+ #
27
+ # End Of Comments
28
+ # --------------------------------------------------------------------------------- #
29
+
30
+
31
+ """
32
+ :class:`~wx.lib.agw.shortcuteditor.ShortcutEditor` is a widget that allows the user to customize and change keyboard
33
+ shortcuts via a dialog. It can be used to edit :class:`wx.MenuItem` shortcuts or accelerators
34
+ defined in a :class:`AcceleratorTable`.
35
+
36
+ .. note::
37
+
38
+ :class:`ShortcutEditor` **requires** the minimum AGW version 0.9.3 or the current
39
+ SVN, for the various enhancements made to the :class:`~wx.lib.agw.hypertreelist.HyperTreeList`
40
+ and :class:`~wx.lib.agw.genericmessagedialog.GenericMessageDialog`
41
+ widgets.
42
+
43
+
44
+ Description
45
+ ===========
46
+
47
+ :class:`ShortcutEditor` is a widget that allows the user to customize and change keyboard
48
+ shortcuts via a dialog. It can be used to edit :class:`wx.MenuItem` shortcuts or accelerators
49
+ defined in a :class:`AcceleratorTable`.
50
+
51
+ The interface itself is very much inpired by the GIMP shortcut editor:
52
+
53
+ http://graphicssoft.about.com/od/gimptutorials/tp/keyboard-shortcut-editor.htm
54
+
55
+ There are very few minor UI differences between :class:`ShortcutEditor` and the GIMP one,
56
+ although the behaviour should be pretty much equivalent.
57
+
58
+ Various features:
59
+
60
+ * Shortcuts are listed in a tree-like structure, pretty much reflecting a menu
61
+ hierarchy (as most of the time :class:`ShortcutEditor` is used to edit :class:`wx.MenuItem`
62
+ shortcuts);
63
+ * Accelerators defined via :class:`AcceleratorTable` are handled in a similar way;
64
+ * Support for I18N;
65
+ * Ability to restore default shortcuts/accelerators via a UI button;
66
+ * Possibility to send back the new/updated shortcuts to the original :class:`wx.MenuBar` or
67
+ the original :class:`AcceleratorTable`;
68
+ * Filters on the shortcuts label (case-insensitive);
69
+ * Basic help window with instructions (customizable via :meth:`~ShortcutEditor.SetHTMLHelpFile`), via
70
+ the ``Help`` button.
71
+
72
+ And a lot more. Check the demo for an almost complete review of the functionalities.
73
+
74
+
75
+ UI Interactions
76
+ ===============
77
+
78
+ 1. In the :class:`ShortcutEditor` dialog you can open sub-sections by clicking the small box
79
+ with a + sign in it next to each section name. In the screen grab, you can see I've
80
+ opened the *Options* sub-section as I'm going to add a keyboard shortcut to the
81
+ *OptionsItem 1* item.
82
+
83
+ .. figure:: _static/images/sphinxdocs/ShortcutEditor_1_thumb.png
84
+ :alt: Open Subsections
85
+ :figclass: floatcenter
86
+ :target: _static/images/sphinxdocs/ShortcutEditor_1.png
87
+
88
+ **Figure 1**
89
+
90
+
91
+ 2. Now you need to scroll to the tool or command that you want to edit and click on it
92
+ to select it. When selected, the text for that tool in the *Shortcut* column changes
93
+ to read 'New accelerator...' and you can press the key or combination of keys you
94
+ want to assign as a shortcut.
95
+
96
+ .. figure:: _static/images/sphinxdocs/ShortcutEditor_2_thumb.png
97
+ :alt: Assign Shortcut
98
+ :figclass: floatcenter
99
+ :target: _static/images/sphinxdocs/ShortcutEditor_2.png
100
+
101
+ **Figure 2**
102
+
103
+
104
+ 3. I've changed the *OptionsItem 1*'s keyboard shortcut to ``Shift+Ctrl+F`` by pressing
105
+ the ``Shift``, ``Ctrl`` and ``F`` keys simultaneously. If you want to remove a keyboard
106
+ shortcut from any tool or command, just click on it to select it and then when the
107
+ 'New accelerator...' text displays, press the backspace key and the text will change
108
+ to 'Disabled'.
109
+
110
+ Once you're happy that your keyboard shortcuts are set up as you wish, simply click
111
+ the ``OK`` button.
112
+
113
+ .. figure:: _static/images/sphinxdocs/ShortcutEditor_3_thumb.png
114
+ :alt: Remove/Save Shortcuts
115
+ :figclass: floatcenter
116
+ :target: _static/images/sphinxdocs/ShortcutEditor_3.png
117
+
118
+ **Figure 3**
119
+
120
+
121
+ 4. If you thought my choice of ``Shift+Ctrl+F`` was an odd selection, I chose it because
122
+ it was a keyboard combination that hadn't already been assigned to any tool or command.
123
+ If you try to assign a keyboard shortcut that is already in use, an alert will open
124
+ telling you what the shortcut is currently being used for. If you want to keep the
125
+ original shortcut, just click the ``Cancel`` button, otherwise click ``Reassign shortcut``
126
+ to make the shortcut apply to your new selection.
127
+
128
+ .. figure:: _static/images/sphinxdocs/ShortcutEditor_4_thumb.png
129
+ :alt: Reassigning Shortcuts
130
+ :figclass: floatcenter
131
+ :target: _static/images/sphinxdocs/ShortcutEditor_4.png
132
+
133
+ **Figure 4**
134
+
135
+
136
+
137
+ Base Functionalities
138
+ ====================
139
+
140
+ There are basically three ways to populate the :class:`ShortcutEditor` dialog, depending on
141
+ your needs. These approaches can be combined if needed.
142
+
143
+ 1) Use the :meth:`~ShortcutEditor.FromMenuBar` method: if you need to give your user the ability to edit
144
+ the various :class:`wx.MenuItem` shortcuts in your application, you can create :class:`ShortcutEditor`
145
+ in this way::
146
+
147
+ # Build your wx.MenuBar first!!!
148
+ # "self" is an instance of wx.TopLevelWindow
149
+
150
+ dlg = ShortcutEditor(self)
151
+ dlg.FromMenuBar(self)
152
+
153
+ # Here the user will make all the various modifications
154
+ # to the shortcuts
155
+
156
+ if dlg.ShowModal() == wx.ID_OK:
157
+ # Changes accepted, send back the new shortcuts to
158
+ # the TLW wx.MenuBar
159
+ dlg.ToMenuBar(self)
160
+
161
+ dlg.Destroy()
162
+
163
+
164
+ 2) Use the :meth:`~ShortcutEditor.FromAcceleratorTable` method: if you need to give your user the ability to edit
165
+ the various accelerators you set via :class:`AcceleratorTable` in your application, you can
166
+ create :class:`ShortcutEditor` in this way::
167
+
168
+ # Build your wx.AcceleratorTable first!!!
169
+ # "accelTable" is a list of tuples (4 elements per tuple)
170
+
171
+ accelTable = []
172
+
173
+ # Every tuple is defined in this way:
174
+
175
+ for label, flags, keyCode, cmdID in my_accelerators:
176
+ # label: the string used to show the accelerator into the ShortcutEditor dialog
177
+ # flags: a bitmask of wx.ACCEL_ALT, wx.ACCEL_SHIFT, wx.ACCEL_CTRL, wx.ACCEL_CMD,
178
+ # or wx.ACCEL_NORMAL used to specify which modifier keys are held down
179
+ # keyCode: the keycode to be detected (i.e., ord('b'), wx.WXK_F10, etc...)
180
+ # cmdID: the menu or control command ID to use for the accelerator event.
181
+
182
+ accel_tuple = (label, flags, keyCode, cmdID)
183
+ accelTable.append(accel_tuple)
184
+
185
+ dlg = ShortcutEditor(self)
186
+ dlg.FromAcceleratorTable(accelTable)
187
+
188
+ # Here the user will make all the various modifications
189
+ # to the shortcuts
190
+
191
+ if dlg.ShowModal() == wx.ID_OK:
192
+ # Changes accepted, send back the new shortcuts to
193
+ # the window with the wx.AcceleratorTable:
194
+ dlg.ToAcceleratorTable(self)
195
+
196
+ dlg.Destroy()
197
+
198
+
199
+ 3) Build your own hierarchy of shortcuts using :meth:`~ShortcutEditor.GetShortcutManager`::
200
+
201
+ dlg = ShortcutEditor(self)
202
+ manager = dlg.GetShortcutManager()
203
+
204
+ for label, accelerator, bitmap, help, cmdID in my_list:
205
+ shortcut = Shortcut(label, accelerator, bitmap, help, accelId=cmdID)
206
+ manager.AppendItem(shortcut)
207
+
208
+ dlg.ShowModal()
209
+ dlg.Destroy()
210
+
211
+
212
+ Usage
213
+ =====
214
+
215
+ Usage example::
216
+
217
+ import wx
218
+ import wx.lib.agw.shortcuteditor as SE
219
+
220
+ class MyFrame(wx.Frame):
221
+
222
+ def __init__(self, parent):
223
+
224
+ wx.Frame.__init__(self, parent, -1, "ShortcutEditor Demo")
225
+
226
+ bar = wx.MenuBar()
227
+ menu = wx.Menu()
228
+
229
+ menu.Append(101, "&Mercury", "This the text in the Statusbar")
230
+ menu.Append(102, "&Venus", "")
231
+ menu.Append(103, "&Earth", "You may select Earth too")
232
+ menu.AppendSeparator()
233
+ menu.Append(104, "&Close", "Close this frame")
234
+
235
+ bar.Append(menu, 'File')
236
+ self.SetMenuBar(bar)
237
+
238
+ dlg = SE.ShortcutEditor(self)
239
+ dlg.FromMenuBar(self)
240
+
241
+ if dlg.ShowModal() == wx.ID_OK:
242
+ # Changes accepted, send back the new shortcuts to the TLW wx.MenuBar
243
+ dlg.ToMenuBar(self)
244
+
245
+ dlg.Destroy()
246
+
247
+
248
+ # our normal wxApp-derived class, as usual
249
+
250
+ app = wx.App(0)
251
+
252
+ frame = MyFrame(None)
253
+ app.SetTopWindow(frame)
254
+ frame.Show()
255
+
256
+ app.MainLoop()
257
+
258
+
259
+
260
+ Window Styles
261
+ =============
262
+
263
+ `No particular window styles are available for this class.`
264
+
265
+
266
+ Events Processing
267
+ =================
268
+
269
+ This class processes the following events:
270
+
271
+ ========================= ==================================================
272
+ Event Name Description
273
+ ========================= ==================================================
274
+ ``EVT_SHORTCUT_CHANGING`` Event emitted when the user is about to change a shortcut.
275
+ ``EVT_SHORTCUT_CHANGED`` Event emitted when the user has changed a shortcut.
276
+ ========================= ==================================================
277
+
278
+
279
+ Supported Platforms
280
+ ===================
281
+
282
+ :class:`ShortcutEditor` has been tested on the following platforms:
283
+ * Windows (Windows Vista/7);
284
+
285
+
286
+ License And Version
287
+ ===================
288
+
289
+ :class:`ShortcutEditor` is distributed under the wxPython license.
290
+
291
+ Latest Revision: Andrea Gavana @ 27 Dec 2012, 21.00 GMT
292
+
293
+ Version 0.1
294
+
295
+ .. versionadded:: 0.9.3
296
+
297
+ """
298
+
299
+ # Version Info
300
+ __version__ = "0.1"
301
+
302
+ import wx
303
+ import os
304
+ import sys
305
+
306
+ import wx.html
307
+
308
+ import wx.lib.buttons as buttons
309
+ from wx.lib.embeddedimage import PyEmbeddedImage
310
+ from wx.lib.mixins import treemixin
311
+
312
+ # AGW stuff
313
+ from . import hypertreelist as HTL
314
+ from . import genericmessagedialog as GMD
315
+
316
+ # add support for I18N
317
+ _ = wx.GetTranslation
318
+
319
+ try:
320
+ dirName = os.path.dirname(os.path.abspath(__file__))
321
+ except:
322
+ dirName = os.path.dirname(os.path.abspath(sys.argv[0]))
323
+
324
+
325
+ # ----------------------------------------------------------------------------
326
+ # Constants
327
+ # ----------------------------------------------------------------------------
328
+
329
+ DATA_DIR = os.path.join(dirName, 'data')
330
+ """ The folder where the default HTML help for :class:`ShortcutEditor` lives. """
331
+
332
+ # These commented out things need to be taken into account somehow, but I
333
+ # have no idea how to treat them and even if they could be valid accelerators
334
+
335
+ KEYMAP = {
336
+ wx.WXK_BACK : 'Back',
337
+ wx.WXK_TAB : 'Tab',
338
+ wx.WXK_RETURN : 'Enter',
339
+ wx.WXK_ESCAPE : 'Esc',
340
+ wx.WXK_SPACE : 'Space',
341
+ wx.WXK_DELETE : 'Delete',
342
+ wx.WXK_START : 'Start',
343
+ wx.WXK_CANCEL : 'Cancel',
344
+ wx.WXK_CLEAR : 'Clear',
345
+ wx.WXK_MENU : 'Menu',
346
+ wx.WXK_PAUSE : 'Pause',
347
+ wx.WXK_CAPITAL : 'Capital',
348
+
349
+ wx.WXK_END : 'End',
350
+ wx.WXK_HOME : 'Home',
351
+ wx.WXK_LEFT : 'Left',
352
+ wx.WXK_UP : 'Up',
353
+ wx.WXK_RIGHT : 'Right',
354
+ wx.WXK_DOWN : 'Down',
355
+ wx.WXK_SELECT : 'Select',
356
+ wx.WXK_PRINT : 'Print',
357
+ wx.WXK_EXECUTE : 'Execute',
358
+ wx.WXK_SNAPSHOT : 'Snapshot',
359
+ wx.WXK_INSERT : 'Insert',
360
+ wx.WXK_HELP : 'Help',
361
+ # wx.WXK_NUMPAD0 : 'WXK_NUMPAD0',
362
+ # wx.WXK_NUMPAD1 : 'WXK_NUMPAD1',
363
+ # wx.WXK_NUMPAD2 : 'WXK_NUMPAD2',
364
+ # wx.WXK_NUMPAD3 : 'WXK_NUMPAD3',
365
+ # wx.WXK_NUMPAD4 : 'WXK_NUMPAD4',
366
+ # wx.WXK_NUMPAD5 : 'WXK_NUMPAD5',
367
+ # wx.WXK_NUMPAD6 : 'WXK_NUMPAD6',
368
+ # wx.WXK_NUMPAD7 : 'WXK_NUMPAD7',
369
+ # wx.WXK_NUMPAD8 : 'WXK_NUMPAD8',
370
+ # wx.WXK_NUMPAD9 : 'WXK_NUMPAD9',
371
+ wx.WXK_MULTIPLY : '*',
372
+ wx.WXK_ADD : '+',
373
+ # wx.WXK_SEPARATOR : 'WXK_SEPARATOR',
374
+ wx.WXK_SUBTRACT : '-',
375
+ wx.WXK_DECIMAL : '.',
376
+ wx.WXK_DIVIDE : '/',
377
+ wx.WXK_F1 : 'F1',
378
+ wx.WXK_F2 : 'F2',
379
+ wx.WXK_F3 : 'F3',
380
+ wx.WXK_F4 : 'F4',
381
+ wx.WXK_F5 : 'F5',
382
+ wx.WXK_F6 : 'F6',
383
+ wx.WXK_F7 : 'F7',
384
+ wx.WXK_F8 : 'F8',
385
+ wx.WXK_F9 : 'F9',
386
+ wx.WXK_F10 : 'F10',
387
+ wx.WXK_F11 : 'F11',
388
+ wx.WXK_F12 : 'F12',
389
+ wx.WXK_F13 : 'F13',
390
+ wx.WXK_F14 : 'F14',
391
+ wx.WXK_F15 : 'F15',
392
+ wx.WXK_F16 : 'F16',
393
+ wx.WXK_F17 : 'F17',
394
+ wx.WXK_F18 : 'F18',
395
+ wx.WXK_F19 : 'F19',
396
+ wx.WXK_F20 : 'F20',
397
+ wx.WXK_F21 : 'F21',
398
+ wx.WXK_F22 : 'F22',
399
+ wx.WXK_F23 : 'F23',
400
+ wx.WXK_F24 : 'F24',
401
+ wx.WXK_NUMLOCK : 'NumLock',
402
+ wx.WXK_SCROLL : 'Scroll',
403
+ wx.WXK_PAGEUP : 'PgUp',
404
+ wx.WXK_PAGEDOWN : 'PgDn',
405
+ # wx.WXK_NUMPAD_SPACE : 'WXK_NUMPAD_SPACE',
406
+ # wx.WXK_NUMPAD_TAB : 'WXK_NUMPAD_TAB',
407
+ # wx.WXK_NUMPAD_ENTER : 'WXK_NUMPAD_ENTER',
408
+ # wx.WXK_NUMPAD_F1 : 'WXK_NUMPAD_F1',
409
+ # wx.WXK_NUMPAD_F2 : 'WXK_NUMPAD_F2',
410
+ # wx.WXK_NUMPAD_F3 : 'WXK_NUMPAD_F3',
411
+ # wx.WXK_NUMPAD_F4 : 'WXK_NUMPAD_F4',
412
+ # wx.WXK_NUMPAD_HOME : 'WXK_NUMPAD_HOME',
413
+ # wx.WXK_NUMPAD_LEFT : 'WXK_NUMPAD_LEFT',
414
+ # wx.WXK_NUMPAD_UP : 'WXK_NUMPAD_UP',
415
+ # wx.WXK_NUMPAD_RIGHT : 'WXK_NUMPAD_RIGHT',
416
+ # wx.WXK_NUMPAD_DOWN : 'WXK_NUMPAD_DOWN',
417
+ # wx.WXK_NUMPAD_PAGEUP : 'WXK_NUMPAD_PAGEUP',
418
+ # wx.WXK_NUMPAD_PAGEUP : 'WXK_NUMPAD_PAGEUP',
419
+ # wx.WXK_NUMPAD_PAGEDOWN : 'WXK_NUMPAD_PAGEDOWN',
420
+ # wx.WXK_NUMPAD_PAGEDOWN : 'WXK_NUMPAD_PAGEDOWN',
421
+ # wx.WXK_NUMPAD_END : 'WXK_NUMPAD_END',
422
+ # wx.WXK_NUMPAD_BEGIN : 'WXK_NUMPAD_BEGIN',
423
+ # wx.WXK_NUMPAD_INSERT : 'WXK_NUMPAD_INSERT',
424
+ # wx.WXK_NUMPAD_DELETE : 'WXK_NUMPAD_DELETE',
425
+ # wx.WXK_NUMPAD_EQUAL : 'WXK_NUMPAD_EQUAL',
426
+ # wx.WXK_NUMPAD_MULTIPLY : 'WXK_NUMPAD_MULTIPLY',
427
+ # wx.WXK_NUMPAD_ADD : 'WXK_NUMPAD_ADD',
428
+ # wx.WXK_NUMPAD_SEPARATOR : 'WXK_NUMPAD_SEPARATOR',
429
+ # wx.WXK_NUMPAD_SUBTRACT : 'WXK_NUMPAD_SUBTRACT',
430
+ # wx.WXK_NUMPAD_DECIMAL : 'WXK_NUMPAD_DECIMAL',
431
+ # wx.WXK_NUMPAD_DIVIDE : 'WXK_NUMPAD_DIVIDE',
432
+ #
433
+ # wx.WXK_WINDOWS_LEFT : 'WXK_WINDOWS_LEFT',
434
+ # wx.WXK_WINDOWS_RIGHT : 'WXK_WINDOWS_RIGHT',
435
+ # wx.WXK_WINDOWS_MENU : 'WXK_WINDOWS_MENU',
436
+
437
+ # wx.WXK_SPECIAL1 : 'WXK_SPECIAL1',
438
+ # wx.WXK_SPECIAL2 : 'WXK_SPECIAL2',
439
+ # wx.WXK_SPECIAL3 : 'WXK_SPECIAL3',
440
+ # wx.WXK_SPECIAL4 : 'WXK_SPECIAL4',
441
+ # wx.WXK_SPECIAL5 : 'WXK_SPECIAL5',
442
+ # wx.WXK_SPECIAL6 : 'WXK_SPECIAL6',
443
+ # wx.WXK_SPECIAL7 : 'WXK_SPECIAL7',
444
+ # wx.WXK_SPECIAL8 : 'WXK_SPECIAL8',
445
+ # wx.WXK_SPECIAL9 : 'WXK_SPECIAL9',
446
+ # wx.WXK_SPECIAL10 : 'WXK_SPECIAL10',
447
+ # wx.WXK_SPECIAL11 : 'WXK_SPECIAL11',
448
+ # wx.WXK_SPECIAL12 : 'WXK_SPECIAL12',
449
+ # wx.WXK_SPECIAL13 : 'WXK_SPECIAL13',
450
+ # wx.WXK_SPECIAL14 : 'WXK_SPECIAL14',
451
+ # wx.WXK_SPECIAL15 : 'WXK_SPECIAL15',
452
+ # wx.WXK_SPECIAL16 : 'WXK_SPECIAL16',
453
+ # wx.WXK_SPECIAL17 : 'WXK_SPECIAL17',
454
+ # wx.WXK_SPECIAL18 : 'WXK_SPECIAL18',
455
+ # wx.WXK_SPECIAL19 : 'WXK_SPECIAL19',
456
+ # wx.WXK_SPECIAL2 : 'WXK_SPECIAL2',
457
+ }
458
+
459
+ # Define a dictionary to hold the correspondence between wx.ACCEL_* and
460
+ # human-readable names
461
+ ACCELERATORS = {wx.ACCEL_ALT : 'Alt',
462
+ wx.ACCEL_CTRL : 'Ctrl',
463
+ wx.ACCEL_NORMAL: '',
464
+ wx.ACCEL_SHIFT : 'Shift'}
465
+
466
+ # Define a dictionary to hold the correspondence between wx.MOD_* and
467
+ # human-readable names (platform dependent)
468
+ if wx.Platform == '__WXMAC__':
469
+ MODIFIERS = [(wx.MOD_CONTROL, 'Cmd'), (wx.MOD_ALT, 'Alt'), (wx.MOD_SHIFT, 'Shift'), (wx.MOD_META, 'Meta')]
470
+ else:
471
+ MODIFIERS = [(wx.MOD_CONTROL, 'Ctrl'), (wx.MOD_ALT, 'Alt'), (wx.MOD_SHIFT, 'Shift'), (wx.MOD_WIN, 'Win')]
472
+
473
+ # Define a couple of standard, default accelerators
474
+ NEW_ACCEL_STRING = _('New accelerator...')
475
+ """ The string to display when the user wants to enter a new accelerator (by default is `New accelerator...`). """
476
+ DISABLED_STRING = _('Disabled')
477
+ """ The string to display when an accelerator is disabled (by default is `Disabled`). """
478
+
479
+ # Events handled by ShortcutEditor
480
+ wxEVT_SHORTCUT_CHANGING = wx.NewEventType()
481
+ wxEVT_SHORTCUT_CHANGED = wx.NewEventType()
482
+
483
+ EVT_SHORTCUT_CHANGING = wx.PyEventBinder(wxEVT_SHORTCUT_CHANGING, 1)
484
+ """ Event emitted when the user is about to change a shortcut. """
485
+ EVT_SHORTCUT_CHANGED = wx.PyEventBinder(wxEVT_SHORTCUT_CHANGED, 1)
486
+ """ Event emitted when the user has changed a shortcut. """
487
+
488
+
489
+ # Standard images for all the buttons we use in the dialog
490
+ #----------------------------------------------------------------------
491
+ _cancel = PyEmbeddedImage(
492
+ "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0"
493
+ "RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAQQSURBVHjaAEEAvv8BXTIyAAL9"
494
+ "/UEy6Oip+fn5BqAAAHX1/f2bBP7+ACMDAwA4BQUAB/z8AAH6+hQhCQm7FAsLKpPm5qfh/f1g"
495
+ "4QAAAAIAQQC+/wMtGBhBLufnr1w5ORI1JycI+traR9QBAev4/v7NFQICABsDAwAB/PwUFwAA"
496
+ "vDdJSTA0X18DIujoL9Lm5iLZAACyAgBBAL7/A2ADA8xhKSkREoaGAAQ9PQAm398DAeDgRtP/"
497
+ "/+gKAgLOHQEBDBr//782NDQwIGpqAP84OAAgFBQBKOXlLr3n5wcCAEEAvv8E9fn5CAcBAQD5"
498
+ "3NwA+A8PAA5aWgBY+PgG/cjIlMcCAhUUAQFSMScnMB1VVQD/AAAA99HRAAj4+AAFBQUBAf//"
499
+ "NAKI+TEf36uvT5546N+4wczMxcXwE2gYu6Qkg8T79yxCb986KUtKSiu7ujKwAA3/9ewZA/fN"
500
+ "mwxX1q5lyD979sXZ//9LAAKImZeL69w5oJ//v37tqvP4MQsj0IA/wEBjBWrg+fmTUVRZmYGD"
501
+ "lxesmePpU4Zbx44xFF269OLQ379xQAftBgggZgFOToYvf/+ePcPA8ILl0yc35RcvWP79+sXA"
502
+ "9PMnAxc3NwML0LA/L14w/H79muHarVsM5TduvDj6928UUPNeIGYACCBmbXFxBkFgVPEwM597"
503
+ "xcn5W/DXLxexp08Zf338yPDn/XuGX0CNPz5/ZvgGNLD93r13R37/DhBkYDjMA9QMChOAAGLR"
504
+ "FBEBpQOG/3/+8Mn+/Bmi8OkT40eg5ncfPjB8BXqHhZ2dgRvoHVFRUQYvMTHuN48fa/xgYDjG"
505
+ "C9R8H4gBAohZDxhgP///55H68eOg34sXxmJAze+BEh/+/2f4DqT/sLAwsAK9ycbGxmAhJcUi"
506
+ "yczscfrDh9dAQ85+BcoDBBCztoyMpMz37/vCnjwxkAY69QNQ8BsQswI18EtIMHACaRBgBbqE"
507
+ "CYiNZGRYRP//d738/v3rF0BDAAKI2U9A4EjMw4f6il+/MnwEKvwJxCBNT4SFGab/+PGem42N"
508
+ "WY+bm/kvMFWyAMWZga4xVVBgkfj3z23f27cPAQKISebzZ21toOa/QI3/gJgfGKCPgZq7v317"
509
+ "sfPdO7+Fr19nnv/585cIUCMTKMEBY4UFmF7M5eTYBJmZkwACiPk1F5cCPyengTYwzlmBtpwG"
510
+ "aq7//v3F+Y8fo9gYGQ+xMzCcv/7ly0sxFhY3HSEhFkFgmvgEjJ2ms2d/7Pz6dSpAADHIAkNX"
511
+ "R1x80SoxsX+bxMX/6/HzPwc6xBnkbw6gjWpAF6kDaUNGxoxFSko/7lpY/E/n5//ByMBQAlID"
512
+ "EEAMqmJiDNJAWxX4+dsluLh2A8XcGKAAZoA+MEdqAvn6jIwx+iwse5kZGAphagACDAAeLHBa"
513
+ "S9SUbwAAAABJRU5ErkJggg==")
514
+
515
+ #----------------------------------------------------------------------
516
+ _clear = PyEmbeddedImage(
517
+ "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAA"
518
+ "B3RJTUUH1wYeFCULmGdR+AAAAnpJREFUOI2V0ktIVFEcBvDv3jveufO4jk46ZVlGNUGRLTIp"
519
+ "K8OCoAdBIM2ioo2LCKFsI7QJCQoiiJ60nCDBTbUpsJSh0cxw42DImA2j1vhImXFmvPM493VO"
520
+ "izDS6WFn/X0/+H8cDv/xHpyzXuYs/FVdVT2iVbre/CTXxq+0fP+M9ZLNId/YVd+4+tTZFo5o"
521
+ "rBUAVgQ8PI9VsOBmTf1JR3+wE18igyCcHAUAy0oAysSLFeuqBJFMoW7nerwZ+JzLGFLLP4FP"
522
+ "70r7KOOeBzqMZpeYl+KxEPqiYlbVhHt3XnwN/PUEf5tfMg3Lfrmk+tYhn3VNWXUeUYXXFogQ"
523
+ "GhNi1xZzwp+AxiN7H01EjtaoxCt4KmvhLMvA6priqzaTjrxFDQSDYADALS+Ov4WkWzxPDWY7"
524
+ "np4/IY0Ob+RHQgrc5QnsafgIQx+CrqH1WJNyuwCI9DrLqeAI2GXvlrVVp22MmdDyMYyPJvDM"
525
+ "TxEJ21HXMNBeXjvU5PNBWwJEu0tdpk18L5ft9pa4a0ShSIapzUGZHwEvZKCTafR2ZzXOmfP4"
526
+ "LiTTiz0eAGL9lTbDLnY53dWbZNd2MZuegKnHoeYnkVuIQVdnoKszcDhTBVvxAJCj2iuH7N3h"
527
+ "kLfapsdewlFcAY1MITU7AmokoaSmAVDoKoDkbwBK1cOi6LZPjLbD6fJCV2cQDfeAZGdBzSSS"
528
+ "CQrGAMPgeJBkvgAAuIZvk0HoGiBKEsKhTj0VT4IaC+AFA/E5DprKATzSvrYf4y0Bth1M9RDT"
529
+ "soHSosfhwdcsq5AiajBqmgbyhEdGARJxRnmOdS/foOAfAECXv9hrmuwuIeyApqL4Z5jn9vmu"
530
+ "KB9+zX4H1k8cy/juDWsAAAAASUVORK5CYII=")
531
+
532
+ #----------------------------------------------------------------------
533
+ _default = PyEmbeddedImage(
534
+ "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw"
535
+ "SFlzAAAK8AAACvABQqw0mAAAACV0RVh0U29mdHdhcmUATWFjcm9tZWRpYSBGaXJld29ya3Mg"
536
+ "TVggMjAwNId2rM8AAAAWdEVYdENyZWF0aW9uIFRpbWUAMDIvMTEvMDeS+i0/AAACvklEQVR4"
537
+ "nKWSXUjVdxjHP7/f/+W8qdPqj5rRPAsryDM2FIRBjEQotjuHsV2NCIPqoqju6iqnuYu9ZKtw"
538
+ "N7mKujGqDXQ3o9UQEsl8mYl1OGp5lDRt5+h5+Z/j///rIgVfops98MDDw/N8+D4vQinF/zG5"
539
+ "NtHU2LDn8qWL1StS1q329khj43dPZ1/P578X8Mfvdw/W1Oy9Mzo21l5bW1vjy/XKCy0tZ4LB"
540
+ "YHBudq6s/uC3x9YCdADchIUMzHR13du/9cOyvEgkAspp7uvpMzs7/wz9dP5nno2GldBFIWAA"
541
+ "2dUKhMoODju1wZ11u65fu0o0GnW2lIbse38/CMXiMR739rF722fcbrr5iZ1JhFYqEG+XOCR+"
542
+ "aStr/W/erNfFDAG/oYpzXtrXrh7x9j4b52T5VxyvPMHAZA+bzlZt3Fxgza0egV0qmcy+TsRB"
543
+ "ahYTzxFf11327jtXxmSsku0l20hfuE9qmnSgwFp1tqUl9oFAahKkAE1X2Il5csxpthdPwNg/"
544
+ "QAqh68IF8Q5AaY6hu7arKaQXhAZCGiB1cAS4BkJqCEN6AmQ3rb8CnhJpZ/qHHjrkF9r4/Dmg"
545
+ "ZcFYAkhBMp3GNfMepTHC5nqAb2TqZWJrMu4wM5lkYTHKSO4gRVUpKC1CMwMMd00ytUNMV4H7"
546
+ "DgWQXURJAZqhkcnAq5EIsdlpjKJxuiMbyA7v58nGoY/vHD5QveWDwti55ubHgLv8SNLjdV3d"
547
+ "cFhcANcRxFIJpN+DtpDgxWiaT/MsOu9fKentCv+lS42Ojo6m/oGB08uv/NGhA/qjyqr5b8pD"
548
+ "dnd+QZxcv4lKJzGERkxPcjLRwr/OKHbaxvR4lGVZDwFQSi15dDk2w2MTX6Qe/Ppj+PsvpzIN"
549
+ "5W5zdZ5Cw/X5fcmKiorrbW2/7VjuWwFY73GlyrP9N9pbT9WNf16z94emxoaja2veALFzTWMO"
550
+ "z/GRAAAAAElFTkSuQmCC")
551
+
552
+ #----------------------------------------------------------------------
553
+ _help = PyEmbeddedImage(
554
+ "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAC+ElEQVR4nGWTP2xbVRjFf9+9"
555
+ "9/01TgwJCQkMbkMKqCkEKGoXBpiQEqkpZUL8y8BeRqYwMMBQRMWMGtQgJCSKYWCohARIVCCo"
556
+ "MJUgLbSipVERTuzYcexn+713L4OlirafdLZzznC+c4TbbnZxrSTIEkoeQ9S8iICob0WkevHM"
557
+ "C5Xb+XKLeOH08WIxXnloZqoUhSFRFDHIcmr1XerNDts7navWuTfWPz1SucNgduH0qfm58mt7"
558
+ "y/ezfq1LrZmR2SHFaAg9QTtLo1WnnybLv3+yuHrTYHZh7a1DT8ysFEfH+eVyh73TEa8vTvL0"
559
+ "o0WsdXzz6w6nzm5x5cYALdDtNMgG3aO/ffxcRWYX18pTE6W/Dj7+CN9daDM17lN5+2GsteS5"
560
+ "w1qLc44b9ZSXTlxHRHDOkrRqTWvzPXp837GVw0/OHl7fyOiljt2eJQ4U9VbGiTM1HLBn0iP2"
561
+ "hR8v92n1QGmNaB3m6eCS8QNvSZmI7XYXRECED76skTshs6C18OyBGOccm7uOTjrMLNQRottH"
562
+ "zOhIoVxrpsM0BPqpo9vJEa15YMLnzWNjWGs590efRg/8yABQUJB0dclYB71BjnWwvZORI3i+"
563
+ "RnuKd16ZIA6EK/9mnPy6QxB7KDV8XDFw1BsGM0hzBMfmdooTwfgKZRQLB+9iZtJgrePD7xNS"
564
+ "ZQgChdIKgJGCRZRGdZJBpd1OsM4hSlB6iKl7DM45nHNc2nQEoSGIPMLYY2TEIwxAtKkaRH3R"
565
+ "au8uFcNRulZQaojKzwn7pn22EjC+xgs0fuhhfE15DP5cbyFKf6Qufvb8atJPqpHOMQKIIEo4"
566
+ "+lTMoRmfhTmfuWmD9jReqJm+10ORs/FPv3L+/QNVBeBwy4O01QzE3uz2hesp3QFs7MDfTYdR"
567
+ "cN+oUPIyzv3QqIrSy7dsYf+LX82jzOe5GS3rsEgcGeKCR6FouLvkMVYybDV6XNtIqoNMnvnp"
568
+ "3Qebd6xx7uWzJZQ6Ltp71XhBOS7EhJEhzS27SV4VbU6ef2//6v81/wH6bjI8fK9HXAAAAABJ"
569
+ "RU5ErkJggg==")
570
+
571
+ #----------------------------------------------------------------------
572
+ _info = PyEmbeddedImage(
573
+ "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAALGPC/xhBQAAAAFz"
574
+ "UkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
575
+ "AAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAN1gAADdYBkG95nAAAEURJREFUeNrtmmlsXNd1"
576
+ "x//n3Hvfm53kcEiKpERSmy3LdmwlSrwVcZM4qdE6CVB0M4p8CBL0S9ECTb61/dD0cxq3KPKp"
577
+ "SIK2aZAWbeo2cd0kcJp4ixfZlmxHu0RJXGaG23D2mffevacf3oxEs/JObWgecPguhrPc87tn"
578
+ "uefcB/zy+uX1//qiq/2DrDT56cFsZmhyfPLme3ea7MB+ERkDABLUIpazpfOHTzUWTi+210or"
579
+ "UdAOIHLjA/DSg35h6rZbd33k0w8PbtvzK6lsfkcilR0wmn3FUADBibjIIeoGnVanWV9uri6c"
580
+ "WJp95dHZFx/7YW3lQlFsJDccAGV8tW3fPQf3P/CFL+VHpu/PZtKFoTSCiSETDWWMJH0FrQgE"
581
+ "wDkgsA7NjqXyesDlmvNrLRvVKiuzpZPPf/fYk9/5u/XFU0VAbgwA2cLU8J2//odfnth3z+cH"
582
+ "c6mRnSOmPTXiR+mEEgDodCOptQIbRBYAQTEhnTCcSRo2msla0FojpFOljlesOLW2XHz16E++"
583
+ "9ZWzhx573Iad6LoGMLb3I3s/9Jk/eWRk+95PzRRUcPNkMkz5LGu1jl2qtqN2N5LIOondWwAQ"
584
+ "iAAmgmIizyjKJj0ez6e17yleqgb82oVOsrTaqp89/uQjrz729a91VhZa79tCr4Ty4zfdfetd"
585
+ "v/Pn3xzfPvPRO6a81t6JVNRod+2ZxWqwtN6yndAKBDCaKelrTicMp3zDvlGsmMgJEFmHZieS"
586
+ "1XrbtruRjA4kaKrghw7iIzNz/8Do7oHl2SPPhu16cF0BGLv57l13/faffXPb+PiHP7Qz0RwZ"
587
+ "MO78Ui0srjajMHJQipFLeWrP5KB/5+6x1G07C4l9U/nETTvy/p7JIX96LOeNDqa0E0EYOTgn"
588
+ "0gmsVBpd6xtFM2MpYbHoqNG7/PHdpnT6hWdctxVdFwBSQ+MDdz/8F1+fmJz5xIEZv5lLaXum"
589
+ "WA1rza5jZiSMon1T+cS9t06m927P+/lcQqcShhOeZt8oTnhaZZKeKgwkzdRozisMpHSzE7pO"
590
+ "aMU5Qb0VOAFkejQNEYs2Dd+lWC8unXnpZRF3bQGw9ujAQ3/8pelb7vni7VOmU8iZaLZUDZud"
591
+ "0GnFlPAUH7x5PHXHntFUJmlU7PEAxQmAKBb0RSumwbSvtuXTptEOXasbOgBodkJhAk2NpNHs"
592
+ "RF6YmDxYWTzxZHNtoXhNAYztv3f/Bz75xa/uHktmdo35wcJyPaq3A2c0k1ZMt82MJD6waySl"
593
+ "mIkAYgIRgZggsfa0SWI4CU/zcC6pl9dbthtZIRC1upFL+prGh3xXrkmBMxP50olnHrdhJ3zX"
594
+ "C7cVymsvqfbf+3t/NJTL7tg5ajrrza6ttgKrFZNiQjbl8U3bhxJKUV8/EJEwkRCod21mQEQg"
595
+ "ECCDaV/tnRzyPK3Y9L6jvN6yvseyf0eqnZ/c82sjuz9813uy3K0AMDhx01R++75Pbc9z4Bty"
596
+ "K9V2xARSTKSYaTib1OmkYQLAhFjxWLsYBt5EqJcdiTA+nDaphCGlFBnFZK2TtXrH7igko+Fc"
597
+ "MjP94c9+3qQG/GsCYPrOBx/M5gYmxwZUUG12bRhZKGYoxVCKKJ3UrJkvLm0v5fc3IfRmV58B"
598
+ "IDBKkacVa0VQKnarRjtwxCI7xxLdbGHH/Zn8jumrDkD7KTM4sffBXJJUwpCrtQLHTBgbSpk7"
599
+ "d40mh7IJ1QmsOBHwhtXu692zBiGiTdK3lPiKrANRHBy1YlKKSQRodyO3vZCMMun0SG5s9/6r"
600
+ "DiCRzedTgyO7R7IcQODCyEkhl9R33TKe2j89nLh950iiGzlpdkJHGzTnS0pfCgtvkEuGQACW"
601
+ "qq3IySUAcXxhanZCl/SVy6aMGd518D5Whq4ygOGCn8wUsgm2nTASZqJbpoYTAylfCYDBtK8V"
602
+ "Ec4Wq0EYCTiO8D3FL6v5JYljBurtwC5V2pHmvuLUczGCdQImSCapJDEw9hGdyKTflQW/XwB+"
603
+ "aiivWKU8w64TBJLyDRcGkqqf4JkIWhEtrbeiM8X17t7JId83iqxzsFbIOkEYOXJOAAI0E7Rm"
604
+ "0YqhmNBoh/ZMsRZEzolWHKcFAICDCMOJCAjIJbVjZQqsdApA46oBKMzckTeerxWj60SQ9DX7"
605
+ "RnOv0iLrnAgApZjmlxtRcaXJg2nfHx5Isqf5YhHUt1sB4JxQvRXgxeMlFNeabmZigIdzSdGK"
606
+ "BGBAABGBUgSx8efSSe0ASYjAu6oWIAKIk55zA1oxmC/Gd1QaXWudoNYI1Msnyv65Ys0MZnz5"
607
+ "+IemwoP7tslwLsEJL07uIoJOYGW90XXF9ZbMrTTU8XOr6qUT5eTIUMo+cHC6M5DxrAjBCce/"
608
+ "Lf3QEkN510H8/QJYOXd4pXv3p0PrMmyUosg6RNaJpxUHkXXl9VbUCSz96PlzqXY34vsPbA/2"
609
+ "7sjbwawvzW5I3TVLWjGYiACBE4h1grF8Cg/dt9t+9M7t9NKxkvrpK3NeJ4h4WCWccwInBCcE"
610
+ "JSTMTJVaV0eRXYdI66oGwXZ1qdRutdebXaeyKY+7oZXF1UbUaAf21EIlaLZDlzAKzITxQtoe"
611
+ "uHksLAwkxTeKFDP1rKVXF8S9AKPjCG8001A2Ia1uxNmU5wqDSWEiYu4JEXyjCACXKm1urRef"
612
+ "jrqN9asKoLG2XKouV87MLbd9o5iNYpycr3RfPFlqlyutiAhIeBp7tg9GpdWWarZDVipWVCuC"
613
+ "ZiajYmWNVrGo+DWtmMLI8blilffuGHK5lC/UzwA9WNmUp1arHV1arTdLp5561IYdd1UBhO3V"
614
+ "ZmXh0L8urHRso21VLu0pARBGTojjLMBMdNNUPrLOobzWVIqZlGKoXlrTvYKpB5D7rxnFtF7v"
615
+ "cK0V0L7pYesZpr4FEBP5RpPRig+dXEmsluaeq51/9eVrsBUWzB15/NHV5fLJEwuNRNI3nPQU"
616
+ "9dpbFze1+VxCRgZTbq5cV0CvTlCx6J4FaH0Jho4h0bFzq0oxY7yQFgKBOc4aigkDaY/nyg1z"
617
+ "6sJao/jaDx/p1paq16QWqJfPLq6eee4bp+ZrslYL1GDGV0oxEai3/SX4RuGh+3Z377l9IlKK"
618
+ "er2/nhUwo2cBF91BK0ZkHZ24UOGd4wNuMONLXD7HRFO+YetEPf1aySufP/r95RNP/uyaVYPi"
619
+ "LGaf/7d/WinNv/LK6UqSQJz2NfdLun4NNJZPSWEg6WIwREwU7+p6VvAGC1BM9WZAzU6IAzeN"
620
+ "Os+oi30CrZjSvubDp5a9sxfKS4uv/OcjUbvWumYAAKC+Mr+yePTpr51ZqLYvLDd1JumxUUz9"
621
+ "GE8Xd3AbisJeFzgGcSnwcZwdaK5co1zKw46xXK9tHP9J+4Ya7ZCfP1pWK+ePfKs69+rh99zJ"
622
+ "2rqOoGD+5e89vjp/8qmXTqwmuqGllN8vTKg//0t3emO9TwRw7BJgAqxzmFuu08xEbP6Id8qk"
623
+ "FJFnmA6dKJuF4vJ8+bXH/8FFXXsdAADC1npj4dX/+tpcaX19tlhXSU+RVtxbe+lZQO8u8S6y"
624
+ "v60VAZwTOBf/v9WJYK3g1p3DYjSj/1ZPM1qdiI6cXuHK/Ov/0iifPvm+eplb3RZfPf38s5XS"
625
+ "mWePnFlLtANLnmF6g7L9YV9pEXEiYp2TyMbinEil3kEmaTA6lHZO5OI212im0mqTyyu1xurJ"
626
+ "p77voq67rgCEnXq7eOGFb8wv11pL623u7dR6Cl8U6SkOJwJrBZEVCa2LJbSyVmujMJh0SV/D"
627
+ "ORGR2HREgOMX1nS9Wi2210qn33c3+0qcDFWPPvPz6kp5dnaxZkTiQCeCWGnXM3URWCdirUjU"
628
+ "X/3IShRZ6YQWAGR8OCNMJP33EwFBaDFbrKtOrXQobC8vX5cAgvrKcnN17tCJuXXT6oQwmhGv"
629
+ "NuCciHMi1vXM3jmJrEjUX33rpBNEkkwYSSeNs86JlfgzRjHKay1eXK51188f+p57D23wqwLA"
630
+ "2dCtnH72u6WVau18ua7i4obgnBPrBHEzxJG1lmxkKYoihFFEYWQRRlYi6ySbNI6IJLJOrHVg"
631
+ "JkRW6H9envNWloqv1+YOP7slx/dX6nQ46jSWspN33tty/s07x3NhNuWxiFOQ0EBCj8lqgtMg"
632
+ "pyCxiDglzjLEKSYhK46cgyiO9wpPHVkwT75yobnw0r9/uXrh8KHrGoANWkHUbZ1yA3s+Ue9I"
633
+ "YfuwUYNp5Xs6roIvnXzEuwEBSAQkkN7uQFizsFFQrU7IP35xXv3o+XPB3MuPf6X82mPfFhe5"
634
+ "6xoAALQr8wsS1E4hO/rJ08VwwGimgbRHCd/A0xpGKxjF0IqhFaHfB2SOW02NVkhHTq/S9352"
635
+ "ls+cP+NWj/3gL88+/4O/lqgdbtUc9ZUEAHFwxZ/+/Pf3lOZnzcPbfvxCHU8eyWGikMauiSxG"
636
+ "B5PwPYX4qJQQWUE7iLC43MK5UgPltQaCoIYPzhTxwMEn+G9e/9n8L6Io2MopXlkAABKe8I70"
637
+ "Gfqtj/8Ui61pvHB6BM+d2oZnD2cQWg9ONAT9I2IHpgi+7mJiqIaH7y7hjulV7MhXUDp5LBQb"
638
+ "VbZ6flccwIP34TdG89jv6RB3zNRx23SI3713FtWWRr3toR0oRI5BEBjtkPYiZFMBcskQKS9C"
639
+ "t93EhZPHcfJY6eixs3jxhgJgNOjW3fjk0OhIMpUdgJUcOPMFZDMtZFv/Adhz+L+PKVHc7QXi"
640
+ "xqdjOCsw2hUyaYwAKG/lHPlKAiBACGgFnTbCIADcGlzrUbjuIThbgXUMJ5uFIBdPEAV+Oo3t"
641
+ "e2/BcD4xOT2OA1s9xysKIIiA/34O3yoX10qzrx9Gp1UH7FkgOAyRxjt4RC0uJINuG9bayDrU"
642
+ "brgYUKtDiBTlx8bhJQugzB+A9BRc8zuQ7iGQ4OIh+GVTaaOGuRNHUV4Ojx2b3foYcEUtQCvg"
643
+ "M/fjc+PbR8YKE5NgMwryPwgye0D+PSDSb/vMpwBQxsD3kc6kkLmhABABvockENf+sCuQ7kuQ"
644
+ "8Cyk+yxE7Nu6QSqbw/S+2zA85O+cmcDBGwpAGAFPvIh/XCouL184fhRRUIE0/x6u9lUgOHyJ"
645
+ "0luagMBGIax1zkZo31AAAKDaQMU5BIl0CqwHQZnPg3NfBrwPbuiLvZX+gspSGZ1O2O4EWLmh"
646
+ "ABgNPPRRfG5sfHhydMc02IyAvAMgsxvk3/2OYgARYWxqBoP5XO5T9+AzRm/tnK9UFugncqUZ"
647
+ "Y0prECnArQDdQxC9C9J95h3FgPhQIX7AymiME5AEEAJw6Hdb4/E1rwap9326J8Y5MAHujt3t"
648
+ "BxTZpPEUEL4K6T4F2LlLz8dsMnmIwFmLsNtBbWUZ86eOYqW8Xvn2Y/jq8XM42/v+/m9xT+i9"
649
+ "TnqrFOcN94tjz8B89mP4zYcfxJcmtvkzyZSvtfGgjA9WCswKrFTcLLUW1kZwNkIUdBF0u9Jo"
650
+ "dLqLZTf7zz/E3z7+NB7rhuhuWHXbu28cb3xNrjSAvqJqE4Q3AGGGntqGmdv34OB9B/CrU+P6"
651
+ "rnSKRn0DKJberjd+4CFyhFaHUKnaC8fPhj958XW8fOoCji2tYdEJQgBRT+wGcW8ytm8HgbZI"
652
+ "+c0gNooB4PVdw9NIj20b+NiuPdN/OjmWTQ1mfRARBIB1jEotwGK5Fpw6ee6vlsuVnzhB0FMk"
653
+ "7EmwQTaDeNcQ1Ps0fX4b6QPoQ0hYB11vhKuBTQw2w/SeastTzSCJasPD4nKIxaW2XVhYe6Jc"
654
+ "XHrCidhNmUouE/zkLQSbxlsO4L2JSNRs1H8RheGqE8k3Wx1Vqze61Wp1YalU/Nfl0uKjztn1"
655
+ "3gqHmyTaIO4tRDaMr0oMuKz/b84MG+4KgNLG5I3xCgAoDINKFIbVDWZrNykcbri/le+7qxED"
656
+ "NrvCm2aCy7jFxjtdxqJk02raNxm/VQa4Klngci6xWXG6zHizW2yey2b/lU1mLW9j/ld1H/BO"
657
+ "4sObKY93AUDeJPi9o5W+2gDe6rc2mzzeBgAuE9W37PpfnmQMHSrQKjcAAAAASUVORK5CYII=")
658
+
659
+ #----------------------------------------------------------------------
660
+ _ok = PyEmbeddedImage(
661
+ "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAANkE3LLaAgAAAjpJ"
662
+ "REFUeJy90k1IkwEcx/Hvs2evMt1KJ741Wy0zexMy0US6WHSKgii8pAUZKUEFubSgkjKRQgT1"
663
+ "kL0hZNChMpJCi/RQGQll0sBE09wWw5c2c5rbs+fptIgutQ59758//8MP/nNCcsWSm5ajS+8C"
664
+ "6qh1con5So+3W3ni6lTiS81XAe1f45QDsXV3JloVT2BC8c57lGZng6LZJVz8+Ub8fpVD0Mri"
665
+ "1DVqf8dpZYYLZ6pOOjJi1jDqHyIoS7xwdyMbla1qANNO7fHDx0rrZPV3WufbpOl26iM4/Yju"
666
+ "XEXlwdNWvZ3xuY9IssKDT23c6+0l3McjUVfEoe2Vm5vyEwuJ1yVgyRO3jflHfIFBXtvK1dUl"
667
+ "jt016ZpM/MFJZiUfTyfbed7/Ct9t6hmiRkzeR2Moddo6G5xBJYZJjEkiMUcoIvtrzo7iLeUp"
668
+ "Ohu+oJcpycPA3DPefXiP6zoN0gAOQBYRyLRslAqmtS7coSF8iguNQVFZs0yrtYIGb2iE0eBb"
669
+ "3OFBvMMzOBuk2oV+qgAZQFz8zMvwPGkrc3XZQlyIb4KfsNqPUYhFL6pRqWQMOjULEwJ9l3yX"
670
+ "Z/uojmAAEQgFhukKLsq2rLyE9XqTiiTtMuwxWaQb7Cw3ZjDjCtBx1tk41SNX/oojBwBCfidd"
671
+ "QUlalVtgX5tqsmHVrWCdKZfxL2M0nXrY4nksnQDCf9pL3IZy/f1m917ljXxD6fCeV+zF2ugW"
672
+ "B5gLHcbOFtceZVOZ4RagjwZHSrLkUwHE/guOqh90ld9+870vDgAAAABJRU5ErkJggg==")
673
+
674
+ #----------------------------------------------------------------------
675
+ _reassign = PyEmbeddedImage(
676
+ "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9i"
677
+ "ZSBJbWFnZVJlYWR5ccllPAAAAsZJREFUeNqck1lIVGEUx393thaXCm0qtdJrm4FlONGkWESb"
678
+ "tthDUA9F9dDyFhTRghI9WJpgPgSBD/UWQRvZrg6CSFk5FuJDD+nYTFCmmaDV2Cz3dr7LBEIv"
679
+ "0oE/937nfP/DOed/Pm1XPZMyU2AYNBom5TYNzWYDTXw2KyhRCVjff4iJWDwOv2OU1+5tYDyK"
680
+ "qc7qui1u8EACpnJGYtyVsxVQUP8Zs3QzHMH8JfDq0Nl3jIrycyqZKRWhldZiXt1XQSQeo6PP"
681
+ "j/9jP6HhgKbKm5+mmx5dx5tbKFVoAged/VXYpe7Zyfu45ruJQ93sDF4kHAXvovOkp6zmec9t"
682
+ "q5kdBfvJmeugI3AeK6Mq2SGQBCPhkHW2L97IoXchZqYmwc9oG0vmFZAydSHBbwE2r9LpDF0i"
683
+ "OAhdfeAUonuWkH/o3HvVTdNpPPZeH74+Hzdc+ZTNSGbGOG/IdS9jqtPNrVfXZdzwoptg40k2"
684
+ "TVnF0bSZTlreDtN8Bk95PV12kXFo6Va+PDtDiy2fw0nTscftPeS4c0hx5fL4dW+ktZL1O+vo"
685
+ "joYpDQ4ZWU2KfIUu1ZZNNdt4wmRzNfcPbNzuGh7RCQxA/+gTFmT8ZE9JkUtidx6elJtOvHUH"
686
+ "G9hUjf+vWjYjTuuWGs3cXVK8OCtzjOKiAP2SIPgVPofbUb7t3uV5G6o0c+1KGfiQyLhHZIwm"
687
+ "ZCy7jHn8QB7x2DSGwm8JfYIvId2a8NzMANlZkOpaRMwYs6Qc+z2AbCJuh8j4SGRU+zhivCcm"
688
+ "9QQ/w8sOBpsrA9tUgi0XeSJDnKNn92IkFktLyPg9IaNWWoVfc1GoVjYe5nXLBY7IYHuwZkN+"
689
+ "WQ2twktX5OI1IHvFyIDO07YAzWfxqPVYIkhJrP6okD9MfAuSZAVqfGLSrn9diYu29gjPEzJq"
690
+ "k32NysZHaXUmseHxKTzC6+I/LFdQONHxR4ABANuzKntCBWfVAAAAAElFTkSuQmCC")
691
+
692
+ #----------------------------------------------------------------------
693
+
694
+ _html_back = PyEmbeddedImage(
695
+ "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAAK/INwWK6QAAABl0"
696
+ "RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAavSURBVHjaYvz//z/DQAKAAGJi"
697
+ "GGAAEEAD7gCAAGJBF2Bk7IM6jRGIgTQzkGZG5wMxI0g3mNZh+PGnmoGbhZWBhSkXKPocbth/"
698
+ "qBd5mSFqQUJn0lDsAwgg0kMAlmQYGdgYvv3OZPr2e3dgoFqEsqJAIMOvf9YMf4EKQPgPVCE3"
699
+ "M8QROABAAJHuAJBH/v1XZnj/c620NO+0hbO9JNbN8WIQFmBnYPgNtPkf1AEgddxMEBoPAAgg"
700
+ "FhItZ2T48Tea4d+/1thEXbm6SgsGFQV+hr9//zH8+vUXET6gKAJZzoQUYjgAQAAR7wBGRh6G"
701
+ "Tz87BES5sjo67BjTE3XBpv/5/QfVDlBa4QD5nBFiOYEQAAggFuKCnEGN4du3OYamUrbTp7sx"
702
+ "mBtLAA3/y/D6838GHrb/DMzMYFv+AS3/y8AODXYiixeAAGIhaPnvvx6MDH+nxyYbKvR02DGI"
703
+ "inAy/Ab6evk1RobHn5gYik1/M/z/x8jw/dsfJoavv52Awc4B1McBzz2MUJqViYmBk+UskHUJ"
704
+ "2QqAAGIhYHksUP/Mtk5HzrISU3Dovvn6h2H6OWaG/Q8ZGSwlfjMw/vvLwMjMwqCnKcLEyciY"
705
+ "x8rNnAdPB8wQg5hZGYGx95vh5vMvt4ECasjWAAQQC07L//6J5uBknD1hoht7eqoeOISvv/7P"
706
+ "MOUMM8Ojj4wMXMDQZvz7lwFUkv8H0gt6HYA57z9S2IMkgJkCmCM42VkYjlx5wxCav0sc3SqA"
707
+ "AMLugP//XFlYGKdPnebBnpSgAzbs8MP/DLMuMAF9wsjAyfyH4dOPX8Co+Mvw5y8TEAMdAwyq"
708
+ "/wwgC/8BMwmQ/vcPaAwwkQL5jH9ZGNiY/4Ni4ze6VQABhM0BssCwn1BX78ALsfwfw9ZbjAxz"
709
+ "LjCDo5MD6PPfP/8wMP39w3Dr5R+Gks1/GP78ATrk1x9goAHZv3+Dc8ZfIP785ReDixY3Q5aH"
710
+ "ONhh2Oo9gADC4oBfma6uKlqlJWZg3r77DAxzLgLjEZi4mYHx/fPXb4a/QPwfaNlHYLw+f/0L"
711
+ "bPFvIPsPVO43CAP57z/9YFARYYJnCmw5EiCAsDiAMTA2VoeBg4OZ4dqrvwzzLjKDNTIBs92v"
712
+ "XxBLYPgf0Lcs//8AAwlYFgAxA5T9D0Qz/GFgBdJM//8x/AVFx///WHMmQABhcwAbOzs4+TJ8"
713
+ "/fWf4TvIXGBw/wYF769fSA6ABvcvSJCD2UBf//6NcCAoJEChAw97LEEAEEBY6oJ/O9atuwku"
714
+ "Xk2l/zOEqf5i+PztD8Ovn7+gFiHwb6Ajvn//DcS/oPg3Ev83sOz6BdT3G54gsQUBQABhcQDr"
715
+ "tJUrrz2ZM/cK0MWsDMHqfxlC1IDx/fU3w48fv8GJC+T738DQALqCgYf1LxD/A+L/DLxs/xh4"
716
+ "gWxetv9gzM/BwMAOrIaB9uMEAAGELQquAmO8qrR0/wI5OT4mTw8FhjiDr8CijYlhzrHfDD+B"
717
+ "IcEKTA9fvv5i0JdiZqjyEgPmAmDWA8Ux0JegkINkxX9gNsgB3378AacBRixRABBAOAoi5sWf"
718
+ "P/2Uio/f0jF/gTeDt6c8Q7TBPwYBVnaG3j3fGd5+/AlM7X8YmP8zMkjyMwPrAjZgomUFp3Ww"
719
+ "Q6COAcX9L5AjWJkZ2N//Bkkzo1sFEEC4i2Im1s7Xr76zRkdtapw+y50pMlSVwRtYAYpy8TG0"
720
+ "bXnDcPzmd4afEsBE+usfAzcPG0NV33mGOw8+MrBwAI1kBDqAEdqCAlKsbEwMrz78YPj8+993"
721
+ "dGsAAogFZ6sHFFysLC0fP/x+kZywvff69bd8ZSWGDBaq3Ax9Yf8Zujb/Y3gDCglwqfefYcue"
722
+ "h/9un3+5DJgYzgP1sqNURiBbWJhZgc22U+hWAQQQC8HmFwfLnO9//t9trj8y5/z5l0oT+u0Y"
723
+ "VGV5GBoCGRhuPPvO8Os3JIVzcQNTHzfragYulk3gWgvdAUzYGwYAAcREVBuQhXE/Aw+H45YN"
724
+ "d7a4eW1k2HHoJYOkFB+DvgI3uCL69/8fxKz/QKt+487z2ABAADGR0Bx7xMDPHnrvzoe6oPAt"
725
+ "Xxs6zzL8+s/MICTICY4GFAf//E9UawgEAAKIeAdAatofwDhu/vmPwaO16eQF/+gdDFdufWYQ"
726
+ "F+EG1xVwK0EO+v4PVI8RbB0BBBB5HRMWpiMM/GxO58687PMK2/qjqPkkMK8D62VmRhZIxcEA"
727
+ "KX6//SMYEgABxIjeNySqYwJjgzob//87M/z+V8PIw8L0n4kxGSh6B6NjAmohs0D0oXdMAAKI"
728
+ "caA7pwABNOB9Q4AAGnAHAAQYABaU9vBbRzekAAAAAElFTkSuQmCC")
729
+
730
+ #----------------------------------------------------------------------
731
+ _html_forward = PyEmbeddedImage(
732
+ "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAAK/INwWK6QAAABl0"
733
+ "RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAbWSURBVHjaYvz//z/DQAKAAGJi"
734
+ "GGAAEEAD7gCAAGJBF2A0mQVlAPGPfwwMv/9D2HAFDHwMf/9PZfjyR5CBnaWZ4f//kwx/geL/"
735
+ "gOqAyoFyDHD+XySxfxCx/78KUewDCCDcIQBKGqxAm9FV/P6nK8zHHuPqrODN/PvvHobvf6qB"
736
+ "ouzkhgBAAOGPAmagAziYUcX+/mfiYGJkmNHuyLB6jjePoix/C8P7H7uAIaFLjgMAAgi/A/5D"
737
+ "VXCgKvsDDNI/v/8xBLorMezbEMwQm6hnx/jlz25gaBQApdlIcQBAABGXCBmBIcHKhOY2cKQy"
738
+ "KEjzMCyY6Mowa5qbuIggRz/D518LgelElFgHAAQQcQ74D02ULODU+B2SFoEJCpjYnn8EEkBG"
739
+ "SrQ2w54tIQzG5pIRDG+/bwcmOG1ijAYIIBYsYqoMP//aMPwBJllGBkgpBfLsHyDz//8/DN/+"
740
+ "aPzhYGUAFWCMjP8Y5l9iYpDiZWCI1PnDoK8lwrBrfTBDec0h4znTL+wB5pJ8BhamVfgcABBA"
741
+ "LFh8u1pJhldfkJsNmN7+Qzz/D5q1gNTv738ZRPnYGdhYmBj+//vH8AuYTRdfYWV4+JGRIcXw"
742
+ "L4O0ABvDrMmuDEqKAhK1VYdW/P3zX4iBlXkGAwP2EhcggDDLgb//lDpLzBm8rKQYvn7/A8wI"
743
+ "jAyMTEyQogCUFoAsZmDEsQNzyM8fv4Ehw8TAARQ//ZyF4elnZoY8078MOuIMDJXFpgwS4lyM"
744
+ "mem7J//89YedgZl5IjYHAAQQtjTwix3ou38/fwN9+4vhN9CS30D2319/GP79AQbDXwj9/ecf"
745
+ "hr/AqPnz5w/Dn5+/GLiY/jC8+sbA0HaMmeHgfUZwcCXGaDNMmeLCws7C2Mfw+68fNgcABBC2"
746
+ "NAA09C/Q5/8Zdl34wLDsxEcGbk5WBlY2VgZmVhYghtCsrMwMLGwsQEuZGZiBOe/Xr98MbMAM"
747
+ "+PMPC8OEM0wMX4DZ1FvtH0NKog7Dly+/mArzdk9lYGa7DjT+NrJdAAHEgjPnAfHL978YTt36"
748
+ "yMDLA4xzdjYGFnaIQ1hY2cCWswDZXMAEycbByPDnFySNsAHLREYmFobZF5iA6e8fg7vKf4bc"
749
+ "LEOGzZvuyOzb8yAHqCof2R6AAMKaDf8BE98/UMIDJn9WIAYmRwYWYFZj+fcHin/D2f9AUQD0"
750
+ "PQyDoosJJAc0eR4wh1x79Q8Y/YwMWdmGIG85otsFEEA4Q+Df/3/A6P4DNPAnw282RqQCAZQb"
751
+ "EWn6P3JhAW1bgPIOCzA6vv1lYfj8EyLGzQ0qIBkxSkmAAGLBXfiAiltgYvv2m4EV6B1Q+mMB"
752
+ "hgorMOExQ9l/gGwOROaAF5ogKz//YmKI1PvHYC4JEV+8+AoodZ1BtwYggPCEwH9gNfCfgYv5"
753
+ "HwM7MC5ZgZgZRDMCowJoCwsjMI4ZQFHAyPCbEVpi/YfUwsBAYwjRY2KI1QFWZCycDBs332NY"
754
+ "tvj6F2CwzEC3ByCAWHAVvZ+//WFwNxJisNISAFrMyMDEwszABKKBZQIzEINoUMj07P7AcO7J"
755
+ "LwY+oM+/g0pLYLDEmrIyJBoDywpODoaDRx4zpKbtAJlay8DEeATdKoAAwuIARmZ2NiYGIQFO"
756
+ "Bk5gCmdnA1oMCldQgQRqHgAtBjF+AsuB37/+AhPoP3A6+Qh0NScnG0O+HTdDqBEbAycvJ8OJ"
757
+ "0y8YoqO3Mrx+8WUaAwfbBHDwoAGAAMJwwH9mhi89S64KrN7Lw/D7DyJRMf5jBIfvn1//GIR5"
758
+ "2BhKU3UZQOnqBzDVv/v0i0FXHijmxcvgqMEBtnzzjgcMSUk7Gd68+DaJgYu9BJxAmRkxHAAQ"
759
+ "QCxYqt7kg8eeOQOD8i+8KfYXXhkBU+VfWWEhzvjUCHUGHhF2hq/ffjG4AC2t8hdm0JDhYmBk"
760
+ "52DomXKBoa766O/v3/+0MfCyNgL14mx6AwQQtjSwC9gK2gUKCkSKhDoAFIRMzMYsPKzxoGQH"
761
+ "LOMZkh2EGXTlOBmkxHkYPn7/z1BavJ9h4dwrbxk4WDIZOFlWMxBo9QMEEAtJ7SdIUucCB8o/"
762
+ "SGFlpsLFICjCw3D64juGvPIjDOeOPTvPwM+WBFR7AdwYJQAAAog4B8BatshCQMt5uYHamVkZ"
763
+ "Jsy+ztDWc/rPxzc/FjEIsFcB1b8kxnIQAAgg/A5ghMX/PwxhEWFOhudvfjPkNRxm2Lf9wTNg"
764
+ "cOcx8LGtBVtMQmcLIIDwOwBcqqCZBsyT/4DlQe/cKwxr19358/LZlw0MvGxlQFfdBzuWRAAQ"
765
+ "QCx44/sHFq+wMt1+9fHn8Wmzr/ADi8NuBl72pcAE+htbHicGAAQQ40B3TgECaMD7hgABNOAO"
766
+ "AAgwANtDcqAqYx6xAAAAAElFTkSuQmCC")
767
+
768
+ #----------------------------------------------------------------------
769
+ _html_home = PyEmbeddedImage(
770
+ "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAAK/INwWK6QAAABl0"
771
+ "RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAmrSURBVHjaYvz//z/DQAKAAGJi"
772
+ "GGAAEECMDH5SqCL/oe76ywiWZvjHiJD7xwzEULnf/w0Yfv3tY/jPyMPAzFLOwMq2n+EfNDRB"
773
+ "NCMjBP9HNhjqX1CogzAjEwNAAJEXAj+++7Ax/N/QlV/pOLu205Sfk2sVw5fP8eQYBRBALGh8"
774
+ "biD2hdL/gBjoZYYrQHwCEmFAH335ksnLJ9QztbCFK9Y9ECwsJSImktZWNf/p40fyDDz8bUDv"
775
+ "/SHWAQABxMygzovMlwSG0lZg8IQBg8cfSPsBw+kPMCa2AuXYGT5+7FFX1Gxe2TyT1dfKieHb"
776
+ "vy8MP/5+Y9CRV2dws7RjPHP7uuOze3dUGNjYDwCD/zs4CtBiHJXLyAAQQMwMmkDPMv6HYT6g"
777
+ "cAKQwQtTAMS7GP79ucjw6eMCD1uvxGV10xn0lTUY3v15xTD9eQPDng8bGFTZ9BhUxVQYAh3d"
778
+ "GJ69f6N7+fI5awYW1pMMzMyvGf7jdwBAAAEdwAMRh2B+IE4Fsnjh6v/8+cDw80dMgl+C19yy"
779
+ "CQwSgiIMj3/dZZj2vJ7h0pczDK9/vmA4//k4gzSzIoOygAqDn70rw49//+ROXTjt8u/vvwsM"
780
+ "LCyP8DkAIICYGbS5kEOAHxh/qUB1vKAUCrQYyPyn3pRcq9ib2sDAwcrGcOHrMYYpz2sZHv+4"
781
+ "x8DByMXA9J+N4c2vVwyHP+wGahJg0ODRYXA1t2YQExUTOXDqeMDv71+fAUPjEi4HAAQQM4MW"
782
+ "F7IQMAQYgQ5g4mX49plBkE+QYV7xdIZs7wRwbOz+uJph7ssOhs+/PzGw/Odg+PPvL8NvIGb8"
783
+ "z8TwDZgWDr7bxfD91zcGI25LBjMdPQZDbR3OPaeOB319/46RgZ3jEAMDaoSADAUIIGYGQxZ4"
784
+ "+AMTIDBB/E9j+PKeV1VGlWF55SIGbxNnhr/ARL3m3QyGNW9mA9lAZf9YwJb/+fuX4e+/f2D6"
785
+ "P7C8+P+fkeHUx6MMj789ZNDjNAGmFU0GVwsbhtPXLzk8f3hfhoGNYz/Q0l/IDgAIIGYGI6AD"
786
+ "GP9BMtz//7JAy1OsDZy5lpTOZzBR0Wf4+vcTw5zXbQy7368FBzfDf2a45WAMdcBfsGP+A41i"
787
+ "Zjj38RTDxU/nGXTZjRm0ZNUZPG0cGO6+fG5089plfWB0HGdgYvoAKYgYGQACiJlBnx1oKND3"
788
+ "f/9qAYN9boRrgvrigtkM8qIykMT2so7h/JejDGzAwPkHtABm+W+opb+BBsFCAiwG5LMAVd/+"
789
+ "cpPhyLsDDApMygx64noMAY6uDB9+/VA9ff6MOzAizjMwMT8GOQAggCAO+PHNA2j6ivroJp0J"
790
+ "iR0MPOzcDNe/n2WY9qqO4dGPOwxsjNxgn4KD+88fYLz/A1uO7Hs4G0qzAIuN59+fMWx/uYVB"
791
+ "8L8Igw6vNoOvvRODsJCwyP7TR0P/fP/+BFh8XwIIIGYGHYZQCT7xhZNTJ4sXeGUDCztI6fzr"
792
+ "/0+G179eMDz4cZfh/18msM9hFoEtgWK45WD8HxEdQPz9z08GEwFLBh8xfwbO/1wMf3/9YbAz"
793
+ "MWPQVdVkP3nlos+HT5/eAwQQC+P/P01N0a0CCXYx8CoDlCSl2RQZlFh1GPb83cTADDT46+9v"
794
+ "wCD+A/cpPArAFkOj5Q9M7C8DKzAEfgIdoMGlyWAhYsXwg/EH2OCfP34y+Ns5geo4tqjyvDKA"
795
+ "AGL5z8JycNa+WRrbzm4GG/Drx2+GCNsQhiTHBAZOYD4HGSLOIsbgJxoHTIQsQMN/gy0BpQdQ"
796
+ "ovv3HxIKEBrIB3qBGQjXP1/DcPrbWaAZ3KBCnGH/qRMME1bOAUY9KwMLEzPD20+fGX4yMZwG"
797
+ "CCAWoEjFmTvHd535Awyj3wzfGL4y+EiJSiaCHcDMDXYUD4sAQ6RoBrDWZYLkFrw1Jaj0ZGA4"
798
+ "++4Mw6Hfpxn4WIBlGzCjnbxxnmHXno1bGNi55jMws3EyMLMCg4nrIEAAgQqBD8D8uY6BDWjy"
799
+ "X2B2ZPrG8vn3t0SQWSDXg3z98+8vhp//gXXLL2aG1SfWM3wEFlJMTCyQ+PoPKeH+A/WysbAx"
800
+ "BFh4MgiyCYDjHyQnwCoEpl9+eg8s4Dn3M3DwrWMA5hKw4F8GBoAAQlTHsKYZM8PXj9/eAeuf"
801
+ "/wzcwAIR5IA/wGBnZmZm+PjlC0P5wuqfL57e38bAxvkemH1ZIA0WYI356y8XMyefl5WmKZ+Y"
802
+ "hAiQ+xuYDpgYRNiEwRa9//IBZPYXYIIChhAQ/4ckdoAAQjgAVhgxMbz58vUjw8/fvxg4mbjA"
803
+ "raBfwMT3Hxi/oCKXi5PrCwM3VzEDM+d9cPkBw8x/Rbi4uQ0ZGRj5/oPLhD/AEOQBOkCU4d+v"
804
+ "fwwfgGYCwTuwPazAwvA3O7h1BRBATJBS+D8CMzF8+PT90++vv78C0wAXMLA4wCn+Pyy8mcBl"
805
+ "MRMD639EEQ4KvX+/mcH6wSr/g8sLbiAUYBUA6v/N8OUrOATegj3JAgwStp9ghwAEILIMVgCG"
806
+ "QRga3GGTUfb/H9lBy5DutkQPu0t8wYhaNf61NIK+7jli4Nwaml3pRqlPiAI1QlCEaWP6Oa+C"
807
+ "ort891irVXRz7HYgmIcnpsz1fAt12QThLz4BxASOIGTMxPjt/Y93H958ecPAAswyPEyCwJzw"
808
+ "G1GRMUJDAUSD4hOYPsDBCvMIVB0ou3IALedi5QQm2k8M779/BMY/w2eIWqh6oFqAAGICN9+Q"
809
+ "MdP/P79//fz06vMrsIE8THzgwuYf0GugPsR/uGX/EY6BYZAcOD3/B5cNnCycDFwsXAxvPr1l"
810
+ "eP/t00dgSv6GEtpADBBALOCGJioAppD/H958fQvmgNLA59+fGUAJC6wD3EyDWo7cxoCkH0hK"
811
+ "ATrg29/vDHzAKAQ54vWndwyfv3/+AHTAT0hbFwEAAoiFAaNhDqyvGf+/fvvlNZinAixK3/x4"
812
+ "DbQHVN//gzSWURzwH5GLGEGpBFQ0/2Ew4DVgEAXlAKDI2y9Az/z79ZGBhf03epsEIIBYwEGH"
813
+ "CkC2vPz84zOYEyuXxBAjlwhMDyzACuoPsOBkhFjGBPUJPASB2RQozgEs5FjYWRgmW0wChwQT"
814
+ "BxPD5x9fQOkLGAIMv+AOhgKAAGJhwNZyZmJ4dPnZZQYQBid4IASW9sAC4h3Dz3/A4pAJqb0N"
815
+ "YzGB1PxnuvniDlDNTwYmYO8JlG4ef3vJcP7+JZCZTxmYGX+j+xYggBgZMhmxlehqLAwss0RY"
816
+ "hbWAZvyG5D5GUDXM8u7np/dA2gPo3QeQsp8dFgKijIxMm4RYuFSBJeDPf/8h3Tqg41nf//jx"
817
+ "6Off/7lAU46jWwQQQIwD3TsGCKAB7x0DBBgAIYJYB6/AsBcAAAAASUVORK5CYII=")
818
+
819
+ #----------------------------------------------------------------------
820
+ _html_print = PyEmbeddedImage(
821
+ "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9i"
822
+ "ZSBJbWFnZVJlYWR5ccllPAAABwhJREFUeJytl99vVMcVxz9n7tx7d732esHYxmBTfgVRQmg3"
823
+ "OBH9IRGgjUBqoBKoapDIQ9NW4qH0oVL/hPahfegD6kvCcyM1b6nUNhJS0kpNSgW0VUQsEpvy"
824
+ "yxCDbdZe7957585MH3bXNhRcQBzp7OydOXe+59ecc0eOHfsRK5FzbtOOHdt+v3nzhl7nnHuU"
825
+ "3OnTv9oGcPHiRQCq1SqP8yyvvfbGigrkuR09deoHfz94cL9aSa5arS5u/rhUrVbRIrKikIhY"
826
+ "Y6wB4odLeMA/MTi0vNG2amUlHk2uzRZIn2oHtbSBRymNiDyUHw7uF5WoVvc8MXi1WkXn+TTe"
827
+ "e7wXoqibMCzj/RKg9w8LvV8G3vn/dKRBEAFrDc3mXZwzFItDiLCoWBAED4DbBxRwT50DeulR"
828
+ "UEqTZfPkuWX16k2IBEC2LAT3gy4PwdPS//hXqYA0rVGr/Yf5+RuAaSgVtn3slrG/77lzrp+E"
829
+ "qtXqcg8skUhAltURqessM99RSoVLCiyP/zPJgRZ573HO4j3rjMl2WRus7+oq7t21a8cJrTti"
830
+ "HcBnnAPee+WcO1YuV04MD4/s3rp1W19//9poeHgdE+MTOJO0X5E2YGeEZ+IB793Pjxw5+stX"
831
+ "XjlAX18/hUIMCKFWnPvHBRI9yMD1BUzeRPBYZxHpALc88ObRA09Xio0xz+3c+cLPjh8/0U7A"
832
+ "JknSIAg0SSNBFbvoHtnKzEKOtCMmEiIC0j7CatmGT9yMDh06+NOTJ3/ym/37v029Po+I4D1E"
833
+ "Ucjs9B3+eO5TvnHwIHgB33J1IKCkZXtiweRggMx6jAPrQMKAz879jT2DEeXeARpJwke1T+mh"
834
+ "i73DX+GTsX/x9pnTv9alUmnnyMgI3ju0Xio4QaBI04Ssdz2XZhU4hxYQgbqB6RRqiWc+B+Pa"
835
+ "unnfygYBJxDYNXxd1+kqhixkDTJnWVdZQxDC2qEhyuXeL+uenvJzfX19iLRAQbDWkTUT6onh"
836
+ "C7WKuTpEXriTwOVZuNnwJA6Ub4Wgjbn4i0AOhHM9HM3n2RAJfb1lvlf5Jg6LE0df32oGBgaH"
837
+ "daVSWdvT041SglKKLMtpNlPiAGqpZ9oVUXX4523h0jTUc1qy/6eBOgHVKHBlNmd0a0DmwOMQ"
838
+ "hEAp4riLSqW3or2X0txck8HBIkoJ1lq0VsSh4m7dMFMv8vEETN6jlW3ymMVXwCUlJmYErVs5"
839
+ "1TESIMtynJNQp6nhwoXPGBhYRV9fD+VyF4VCTKngmLhX4A8fl8gSIGx7WJYA7qMHy4IH0ojx"
840
+ "VRXiOMCokCTJmJurc+dOjXv3mtTrCVopZQCmpmpMTc0ShiHd3QUG+0tsW9vLD7+6wJyNuJdq"
841
+ "ZptCrelpGDBWcO1TIUCkoRhCTwyru6ASWypBxsvruxm/do+pu3Xq9YQ0NXjviaIYEXJtrZkN"
842
+ "w2BToVAgz3O89zSbGTdvwfpCysnna+goJohClI4QETInbQWWzI8DiALfKul5js0z8jSlkcLN"
843
+ "W5bMZAAUixEiCqUCnLN1nabJTaX8i8ViAWMMWmvm5mb54IP3McZgbatHdGqACCgRlOqU5HbS"
844
+ "OXDed8RABFEKHQQoJYyOfo21a4cxxhAEAcZkZFlzRue5ueq9oViM0VqI4wJTU9f48MM/kSQJ"
845
+ "pVIXQaDx/gnqfbtKWmtpNpuAY8uWzWzduo0kaaJ1RK3WoNGo39J5nl/JsialUpEkgTiOMCah"
846
+ "u7uboaEhXn/9OKtWrSbPzeMrAARBQJIkvPPO75icnMRaQxxrICaOY6anE7Isvarz3Jy/e/eL"
847
+ "rLu7EGndenFwcIBXXz1EFBV56aVRjLFY22q9znla1xOP9w7nWm5vtfNWY3IOnPNs2dLLgQMH"
848
+ "mZy8yebNGykUQsJQUSgUqdVmybL0ogbOX7586d+HDx8ZrVTKGJPz4ou7KZcHCMOA9euHMcYu"
849
+ "AjjnlgG69lyH7eJanlvK5RL79n2LiYnb7N69nYWFBkEQoFTA2NgnV73nL8Ho6Gg2Pz83myTJ"
850
+ "Xq3jYpYZtbDQYGxsgtHR7QSBxlqLtXYR0FqHc7Y9dtguKtjhLDP09/dy6dLn7XxYYGpqyn70"
851
+ "0V9nzp8/94sgCM5qEUEp9e7Zs3++eP78uRfCMFpnrd51+PB33+jpKRWbzbRtLcu84Bc9sHyu"
852
+ "M+99az5Nc6yFkZEB/9Zbb7+rVPMDa93t6em7Y1EUXRKRpU+yMNTjWsfjMzOzRNHA97dv3/xm"
853
+ "63j5+9ztPQ8Au4coxOL8zMw8GzYMSRh2f3779s3f9vevIQzDxS9t3Ro91sbcuZOTplHXyy8/"
854
+ "f2rjxmENUCoVHpnprXizeESXj8vXCgXNvn17fnzmzJUzN24sjMexJo5b3USnadi2KgAsWsvq"
855
+ "ZrNefu+9969Za91K98aV77VLiyLI9euTYaEQfslaN57nIZ129l9hzBKSSHX0vAAAAABJRU5E"
856
+ "rkJggg==")
857
+
858
+ #----------------------------------------------------------------------
859
+ _html_reload = PyEmbeddedImage(
860
+ "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAAK/INwWK6QAAABl0"
861
+ "RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAlZSURBVHjabIvBCYBAEAOT027t"
862
+ "xI/VWJA/i9DkonsfwYEhw8LSNh64EP/kroxbZKnRXzaIJ+62QpMj0qVm4BqN+vN+vNsFEBMD"
863
+ "JeAfIxJm0mf486+D4fvXtUDjlYg1AiCAKHMAAzRkQCH048evONtYhjiHpECGL5+PMPz9E0uM"
864
+ "doAAotwBoCD9Dwzi3//+KosoMizMmsswMXWWJAcjywKGH1/7GRgZ2fDpBgggFiJtEWH4/0+T"
865
+ "4c9/VYa/DNxAH/9j+A+NAnAIMP5m+MGg+PP7b4ZPjI8YorztGcyV9zPFTUwquPXgqjYDpzAo"
866
+ "NF5iMxgggPA74B+DIsOv//lA2pWHm19dVliWmZuVFxLksDTwH5IGfnz7yaAkpMrwluE5w+rf"
867
+ "3Qx+GvkMB1t3MoS2x7oeuXhoIwOnYABQxwt0KwACiBFrLmBkYGP4zVAG9G2lm7YHV5ZtNoOJ"
868
+ "ihEDOycjw1+gZ7EmBSBkYmRiuPLnGMPen4vBhrjxRTDof/dlCG6KZ9h3Zu8JBk4hL4b//98j"
869
+ "5wKAAMLmAE5gcM6SEZKNmRE1g8FOz4rh1I+dDBe+H2X48Oc1w+//v8HW4UoPf///Abr7L1jN"
870
+ "9/9fGOx4fBkcGWIYvCtjGM7dvtLEwMpeD3bAtgdgHQABhB4FzECfz1cSVw7fmbOT4R3/Q4by"
871
+ "h9EMH36/ZvgHdOgfIMRpNxSwMXEwcDJxgh3z5e83hqM/DjIEKqczaMnpMJy7ekGFgZkdRT1A"
872
+ "ALGgpOY//yNFOEXC1yavY7jOcpJhyo1WBmYmFoZ///4yyHEqMejxmjKIsUowIBIBamb4++c/"
873
+ "w9XPFxkufjnF8PPvdwZpDjmGasVJDDNXrmJYtnP5FwZOnuno2gACCDkEhIG+r2sMbGZgFfzL"
874
+ "0H6lloEJaCoT41+GLPlSBjtOL4aL964xPP/wAiQKDQlotAET4u8/vxksFSwYuPgEGFY9XcLg"
875
+ "IOTO0KE4nWHx+i0MBTMrfwB9ngRUfwTdAQABhHDAn/+eEgISKt46XgzVN/MY3n79DLagQbWD"
876
+ "QeOLKUPA9BCG03dPvmD48/cOpChmYmT4zwwJjH+M/xi+/NApiqgTNPVUZPAWDmcolW5iaF8w"
877
+ "k6Fn9cQvDGzc6QxMzKvh8fcXUfwABBDCAT8ZnJ11XRjv/r7FsPHhNnBiC5EOYTD4Z83gPNGZ"
878
+ "4fnrJwsZOHiLGZj+v4XEAFLZDqLZmbf/Yfzj4SsWyKD5w5QhuauEYceJbfcZOAXSgJbvAVv+"
879
+ "H6r2H8IBAAHEgpSPdC0VrRh+/vnBYM1nDwx6ZoZs+QKGlYdWgCw/DgzbFKBlwFQITOEsQIN+"
880
+ "MUJiAGTYP1aQFCMLIwvD5qP7GQpm1TK8fPV8MwOPcDYw2z0GBxO0vEAHAAGEcAAjo8zjj08Y"
881
+ "lN+pMOTwFUFS8YtfDLtu7AN6lnUHMMj/MDACfcH6H2IQB9DQ30DLv3BCkz8Pw9KDmxj61899"
882
+ "9x9UKXHzdTMw/0ZY/B97bQsQQIhyIIX9HPM/JgWmf8C8BilewcXsn79MHMAipgxo+QwG1t+Q"
883
+ "sP/HJAmknwHd+J/hnQDMqD0Mv/7yMTCxZDAw/z/HwAgOZ05oGoGGFDzt/Pm/7+YPkC6AAEKK"
884
+ "Akbrv//+s/wFlfL//kPSC4gGBg0Qf2dg/gsKFHGGv//6gW6QBXJswWoQPstiYGZ5BqS/AC0H"
885
+ "qfUEql3I8P3nH6DF/+AOYGRhYWDjBEYLgzFIE0AAIWfD7wzAohQY+ZAE9h9KM/+BZrdfnkDD"
886
+ "enl4xDS//vh5CF4egYIZ1OD4z3QLGqYQ9b9+i8iLyQpPymoHFkxcDKCAZmT5z3DuzlWG6um9"
887
+ "8FQIEEAsOCIGgln+gAKAi+H79zo2Zo6y1th+RkYmVoaS2YXAtMABzLrAUg3kW2DyAAczI6zV"
888
+ "BMyeXz/aOmpaM/hZ2jLs+r8EmKt+MFgyuTLwsFsy/P3x+z3MKoAAwu4AJnhJJ8vw5dscdUkt"
889
+ "txlpsxgctK0ZZu5ZALQYGDdAh4DTCpZqieHbl2wuTv7oLP8UhgM/NzCsfjMLWEf8Y1CSNmA4"
890
+ "fvEeMMv/fghTDRBACAdgtPP+mzJ8/rHE2yxAbWHmfIbLrPsYzv/Zz/DvF1Dq818tBo4vK4EO"
891
+ "YIImLFhC+wesLpWlhaWNJxX0M0hrsDO0PpnH8O8vG4MIsAiX/KfOsGrvJGC0sR+F2QIQQMiJ"
892
+ "EMnu/7oM335sjHVMlpyWOoFh7ceZDCsfzmQok+9mcFJ3YKiObxJlYeEIgzdSofgfMAUrSioy"
893
+ "2BuZMfwWec3QfC8fWIN+ZPjx7ztDnFQRw8njtxlOXzz3CVivr4dZBRBALFgqFRlgsbo2zS1H"
894
+ "sj+xg6H3cSXD4Xe7gbUcJ8OpV8cZbIR4GHxDbRDBjRxzwDTw5tdzhoUfWxkuXD3NAMrRP//+"
895
+ "ZPCTiGAw+uPBYD01AlixMcwFqrwA0wMQQIhyIIEbmnq/TzZTss7ZUbWBofF+PsPJD4cZ+FkE"
896
+ "wHI/gT75+e8HohLC2iz5D66sQJAFWJNGyCQwRAvmMcTXljOs37vjFAM3jwsoEv8fh7gBIIBQ"
897
+ "0wBE6P3nr58Yvn76ziDAIAoMjO/AopwdmBmAQQxMSH+BDVBGfI1MYOLkZeZlMBI0ZYiWTmb4"
898
+ "85yXwb02leH4aaCNvPwRQPd9RlYPEECYaYCZo/v6g8v2CdMz7JZlzGNg+cfJMPfRVHC7IEIs"
899
+ "nsFbJJDhN7BZxoie8oEiIEeyMbIz8PzjY/j0+hfD9BnbGZZuW8vw/hMwwfIKFADVYbQJAQII"
900
+ "Mw38//+ZgZM/fO+5HVsDeiKMFqbPYhCWF2WoulHKIMEqxfD25k+GCVumMrCxciP1lBghDgDm"
901
+ "hu8/fzM8ev2S4f7zp+//fft6Bljq9TNwcG7H1ZQCCCBEGojlQ3gG3K1ilWP4/HmBhqyu4+zE"
902
+ "KQyP+W4Cs/9vhoenPjPUzqp4zMDOuwiRDZlhPSQmIPsHAxPbQ2A5cRqY2K6gFdcIf56ApAGA"
903
+ "AMLdLP///xEwJLxuPL7V59YWlNkUWs2Q7h7JMIV1CbDu573LwMFdA7EYuRxgRLDBFv/Hk2Ah"
904
+ "ACCACHRMgOUnO0/W91//LpTOr2k9//CKiCCPENBMViZwwxdc7v9Hy46ELUUGAAFERM8IaCAz"
905
+ "yywGDpbDy3avncjIyuXKwMrFimEvmQAggIjsmoFsYrrOwMHl/f8vcyWwWaUI9SbFTgAIMAAF"
906
+ "XnDxjsZXyQAAAABJRU5ErkJggg==")
907
+
908
+ #----------------------------------------------------------------------
909
+
910
+ def FontFromFont(font):
911
+ """
912
+ Creates a copy of the input `font`.
913
+
914
+ :param `font`: an instance of :class:`wx.Font`.
915
+ """
916
+
917
+ new_font = wx.Font(font.GetPointSize(), font.GetFamily(), font.GetStyle(),
918
+ font.GetWeight(), font.GetUnderlined(),
919
+ font.GetFaceName(), font.GetEncoding())
920
+
921
+ return new_font
922
+
923
+
924
+ # ----------------------------------------------------------------------------
925
+ # HTMLHelpWindow is a frame containing the HTML help page for ShortcutEditor
926
+ # ----------------------------------------------------------------------------
927
+
928
+ class HTMLHelpWindow(wx.Frame):
929
+ """
930
+ A simple :class:`wx.Frame` container for the basic help provided to :class:`ShortcutEditor`.
931
+ The help page is actually straightly derived from:
932
+
933
+ http://graphicssoft.about.com/od/gimptutorials/tp/keyboard-shortcut-editor.htm
934
+ """
935
+
936
+ def __init__(self, parent, htmlFile):
937
+ """
938
+ Default class constructor.
939
+
940
+ :param `parent`: an instance of :class:`ShortcutEditor`;
941
+ :param string `htmlFile`: a valid HTML file containing either the default help
942
+ or your particular definition of help.
943
+ """
944
+
945
+ wx.Frame.__init__(self, parent, title=_('Configure Keyboard Shortcuts Help'))
946
+
947
+ self.htmlFile = htmlFile
948
+
949
+ toolbar = self.CreateToolBar(wx.TB_HORIZONTAL|wx.TB_FLAT|wx.TB_TEXT)
950
+ self.BuildToolBar(toolbar)
951
+
952
+ self.html = wx.html.HtmlWindow(self, style=wx.SUNKEN_BORDER)
953
+ self.printer = wx.html.HtmlEasyPrinting()
954
+
955
+ box = wx.BoxSizer(wx.VERTICAL)
956
+ box.Add(self.html, 1, wx.EXPAND)
957
+
958
+ self.SetSizer(box)
959
+ self.SetAutoLayout(True)
960
+
961
+ self.SetIcon(parent.GetIcon())
962
+ self.CreateStatusBar()
963
+
964
+ xvideo = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_X)
965
+ yvideo = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)
966
+
967
+ self.SetSize((xvideo/2, yvideo/2))
968
+
969
+ self.html.LoadFile(self.htmlFile)
970
+ self.Show()
971
+
972
+
973
+ def BuildToolBar(self, toolbar):
974
+ """
975
+ Creates a toolbar for :class:`HTMLHelpWindow` containing the standard browsing
976
+ buttons like `Back`, `Forward`, `Home`, `Refresh` and `Print`.
977
+
978
+ :param `toolbar`: an instance of :class:`ToolBar`.
979
+ """
980
+
981
+ w, h = _html_reload.GetBitmap().GetWidth(), _html_reload.GetBitmap().GetHeight()
982
+ toolbar.SetToolBitmapSize((w, h))
983
+
984
+ toolbar.AddTool(wx.ID_BACKWARD, _('Back'), _html_back.GetBitmap(), wx.NullBitmap, shortHelpString=_('Back'),
985
+ longHelpString=_('Go to the previous page'))
986
+
987
+ toolbar.AddTool(wx.ID_FORWARD, _('Forward'), _html_forward.GetBitmap(), wx.NullBitmap, shortHelpString=_('Forward'),
988
+ longHelpString=_('Go to the next page'))
989
+
990
+ toolbar.AddSeparator()
991
+
992
+ toolbar.AddTool(wx.ID_HOME, _('Home'), _html_home.GetBitmap(), wx.NullBitmap, shortHelpString=_('Home Page'),
993
+ longHelpString=_('Go to the home page'))
994
+
995
+ toolbar.AddTool(wx.ID_REFRESH, _('Refresh'), _html_reload.GetBitmap(), wx.NullBitmap, shortHelpString=_('Refresh'),
996
+ longHelpString=_('Refresh the current page'))
997
+
998
+ toolbar.AddSeparator()
999
+ toolbar.AddStretchableSpace()
1000
+
1001
+ toolbar.AddTool(wx.ID_PRINT, _('Print'), _html_print.GetBitmap(), wx.NullBitmap, shortHelpString=_('Print'),
1002
+ longHelpString=_('Print the current page'))
1003
+
1004
+ toolbar.Realize()
1005
+
1006
+ self.Bind(wx.EVT_TOOL, self.OnHTMLToolbar)
1007
+ self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI)
1008
+ self.Bind(wx.EVT_CLOSE, self.OnClose)
1009
+
1010
+
1011
+ def OnHTMLToolbar(self, event):
1012
+ """
1013
+ Handles all the ``wx.EVT_TOOL`` events for :class:`HTMLHelpWindow`.
1014
+
1015
+ :param `event`: an instance of :class:`CommandEvent`.
1016
+ """
1017
+
1018
+ evId = event.GetId()
1019
+
1020
+ if evId == wx.ID_BACKWARD:
1021
+ self.html.HistoryBack()
1022
+ elif evId == wx.ID_FORWARD:
1023
+ self.html.HistoryForward()
1024
+ elif evId == wx.ID_HOME:
1025
+ self.html.LoadFile(self.htmlFile)
1026
+ elif evId == wx.ID_REFRESH:
1027
+ self.html.LoadPage(self.html.GetOpenedPage())
1028
+ elif evId == wx.ID_PRINT:
1029
+ self.printer.GetPrintData().SetPaperId(wx.PAPER_LETTER)
1030
+ self.printer.PrintFile(self.html.GetOpenedPage())
1031
+ else:
1032
+ raise Exception('Invalid toolbar item in HTMLHelpWindow')
1033
+
1034
+
1035
+ def OnUpdateUI(self, event):
1036
+ """
1037
+ Handles all the ``wx.EVT_UPDATE_UI`` events for :class:`HTMLHelpWindow`.
1038
+
1039
+ :param `event`: an instance of :class:`UpdateUIEvent`.
1040
+ """
1041
+
1042
+ evId = event.GetId()
1043
+
1044
+ if evId == wx.ID_BACKWARD:
1045
+ event.Enable(self.html.HistoryCanBack())
1046
+ elif evId == wx.ID_FORWARD:
1047
+ event.Enable(self.html.HistoryCanForward())
1048
+ else:
1049
+ event.Skip()
1050
+
1051
+
1052
+ def OnClose(self, event):
1053
+ """
1054
+ Handles the ``wx.EVT_CLOSE`` event for :class:`HTMLHelpWindow`.
1055
+
1056
+ :param `event`: an instance of :class:`CloseEvent`.
1057
+ """
1058
+
1059
+ parent = self.GetParent()
1060
+ self.Destroy()
1061
+
1062
+ parent.htmlWindow = None
1063
+ event.Skip()
1064
+
1065
+
1066
+ # ----------------------------------------------------------------------------
1067
+ # ShortcutEvent is a special subclassing of wx.PyCommandEvent
1068
+ # ----------------------------------------------------------------------------
1069
+
1070
+ class ShortcutEvent(wx.PyCommandEvent):
1071
+ """
1072
+ :class:`ShortcutEvent` is a special subclassing of :class:`PyCommandEvent`.
1073
+
1074
+ This event gets emitted when the user is about to change a shortcut (via ``EVT_SHORTCUT_CHANGING``)
1075
+ and when the user has changed a shortcut (via ``EVT_SHORTCUT_CHANGED``).
1076
+ """
1077
+
1078
+ def __init__(self, evtType, evtId, **kwargs):
1079
+ """
1080
+ Default class constructor.
1081
+ For internal use: do not call it in your code!
1082
+
1083
+ :param integer `evtType`: the event type;
1084
+ :param integer `evtId`: the event identifier.
1085
+ """
1086
+
1087
+ wx.PyCommandEvent.__init__(self, evtType, evtId, **kwargs)
1088
+
1089
+
1090
+ def GetAccelerator(self):
1091
+ """
1092
+ Gets the shortcut string for which the operation was performed for ``EVT_SHORTCUT_CHANGED``
1093
+ and ``EVT_SHORTCUT_CHANGING`` events.
1094
+
1095
+ :return: A string representing the new shortcut string (accelerator).
1096
+ """
1097
+
1098
+ return self.accelerator
1099
+
1100
+
1101
+ def SetAccelerator(self, accelerator):
1102
+ """
1103
+ Sets the shortcut string for which the operation was performed for ``EVT_SHORTCUT_CHANGED``
1104
+ and ``EVT_SHORTCUT_CHANGING`` events.
1105
+
1106
+ :param string `accelerator`: a string representing the new shortcut string (accelerator).
1107
+ """
1108
+
1109
+ self.accelerator = accelerator
1110
+
1111
+
1112
+ def GetOldAccelerator(self):
1113
+ """
1114
+ Returns the previous shortcut string for ``EVT_SHORTCUT_CHANGED`` and
1115
+ ``EVT_SHORTCUT_CHANGING`` events.
1116
+
1117
+ :return: A string representing the old shortcut string (accelerator).
1118
+ """
1119
+
1120
+ return self.oldAccelerator
1121
+
1122
+
1123
+ def SetOldAccelerator(self, accelerator):
1124
+ """
1125
+ Sets the previous shortcut string for ``EVT_SHORTCUT_CHANGED`` and
1126
+ ``EVT_SHORTCUT_CHANGING`` events.
1127
+
1128
+ :param string `accelerator`: a string representing the old shortcut string (accelerator).
1129
+ """
1130
+
1131
+ self.oldAccelerator = accelerator
1132
+
1133
+
1134
+ def SetShortcut(self, shortcut):
1135
+ """
1136
+ Sets the shortcut class used for ``EVT_SHORTCUT_CHANGED`` and
1137
+ ``EVT_SHORTCUT_CHANGING`` events.
1138
+
1139
+ :param `shortcut`: an instance of :class:`Shortcut`.
1140
+ """
1141
+
1142
+ self.shortcut = shortcut
1143
+ self.accelerator = shortcut.accelerator
1144
+
1145
+
1146
+ def GetShortcut(self):
1147
+ """
1148
+ Returns the shortcut class used for ``EVT_SHORTCUT_CHANGED`` and
1149
+ ``EVT_SHORTCUT_CHANGING`` events.
1150
+
1151
+ :return: An instance of :class:`Shortcut`.
1152
+ """
1153
+
1154
+ return self.shortcut
1155
+
1156
+
1157
+ # ----------------------------------------------------------------------------
1158
+ # Shortcut is a class containing the details for a shortcut, whether from
1159
+ # a menu item, an accelerator or a user-defined shortcut. It behaves like
1160
+ # a tree, with children and parents.
1161
+ # ----------------------------------------------------------------------------
1162
+
1163
+ class Shortcut(object):
1164
+ """
1165
+ :class:`Shortcut` is a class containing the details for a shortcut, whether from
1166
+ a menu item, an accelerator or a user-defined shortcut. It behaves like
1167
+ a tree, with children and parents.
1168
+ """
1169
+
1170
+ def __init__(self, label='', accelerator='', bitmap=wx.NullBitmap, help='',
1171
+ menuItem=None, accelId=None):
1172
+ """
1173
+ Default class constructor.
1174
+
1175
+ :param string `label`: the shortcut label string;
1176
+ :param string `accelerator`: the shortcut accelerator string;
1177
+ :param `bitmap`: an instance of :class:`wx.Bitmap`, to display along the shortcut `label`
1178
+ in the interface tree;
1179
+ :param string `help`: the help string for this shortcut, to display in the interface tree;
1180
+ :param `menuItem`: if this :class:`Shortcut` is derived from a :class:`wx.Menu` or :class:`wx.MenuItem`,
1181
+ that object. It is read once, to record its id and (via :meth:`~Shortcut.FromMenuItem`) its label,
1182
+ accelerator, help text and bitmap; it is not kept, since it may be destroyed later with no
1183
+ notification to this object;
1184
+ :param integer `accelId`: if this :class:`Shortcut` is derived from an accelerator in a :class:`AcceleratorTable`
1185
+ or from a custom, developer-defined shortcut, it represents the ID it is associated with.
1186
+ """
1187
+
1188
+ self.label = label
1189
+ self.accelerator = accelerator
1190
+ self.bitmap = bitmap
1191
+ self.help = help
1192
+ self.accelId = accelId
1193
+
1194
+ # The wx.MenuItem/wx.Menu itself is deliberately not kept: it may be
1195
+ # destroyed (menu rebuilt, item removed) any time after this Shortcut
1196
+ # is built, with no notification to the Python wrapper. Everything
1197
+ # this class needs from it afterwards is captured here instead.
1198
+ self._isMenu = isinstance(menuItem, wx.Menu)
1199
+ self._id = (1 if self._isMenu else menuItem.GetId()) if menuItem is not None else None
1200
+ # Keeps the mnemonic ('&'), unlike self.label (GetItemLabelText()).
1201
+ self._itemLabel = menuItem.GetItemLabel() if (menuItem is not None and not self._isMenu) else None
1202
+
1203
+ self.parent = None
1204
+ self.topMenu = False
1205
+ self.imageIndex = -1
1206
+ self.changed = False
1207
+ self.shown = True
1208
+ self.position = None
1209
+
1210
+ self.originalAccelerator = accelerator
1211
+ self.children = []
1212
+
1213
+
1214
+ def AppendItem(self, item):
1215
+ """
1216
+ Appends a :class:`Shortcut` item as a last child of its parent.
1217
+
1218
+ :param `item`: an instance of :class:`Shortcut`.
1219
+ """
1220
+
1221
+ item.parent = self
1222
+ self.children.append(item)
1223
+
1224
+
1225
+ def GetAccelerator(self):
1226
+ """ Returns the string accelerator associated with this shortcut. """
1227
+
1228
+ return self.accelerator
1229
+
1230
+
1231
+ def SetAccelerator(self, accelerator):
1232
+ """
1233
+ Sets the string accelerator associated with this shortcut.
1234
+
1235
+ :param string `accelerator`: a string representing the shortcut string (accelerator).
1236
+ """
1237
+
1238
+ self.accelerator = accelerator
1239
+ self.changed = False
1240
+
1241
+ if self.originalAccelerator != accelerator:
1242
+ self.changed = True
1243
+
1244
+
1245
+ def HasChanged(self):
1246
+ """
1247
+ Returns ``True`` if the current accelerator associated with this :class:`Shortcut` is
1248
+ different from the original one, ``False`` otherwise.
1249
+ """
1250
+
1251
+ return self.changed
1252
+
1253
+
1254
+ def GetBitmap(self):
1255
+ """
1256
+ Returns the bitmap associated with this :class:`Shortcut`.
1257
+
1258
+ :note: You should always check if the returned bitmap is a valid one or not::
1259
+
1260
+ bitmap = shortcut.GetBitmap()
1261
+ if bitmap.IsOk():
1262
+ DoSomething()
1263
+
1264
+
1265
+ as the default bitmap associated with a :class:`Shortcut` is :class:`NullBitmap`.
1266
+ """
1267
+
1268
+ return self.bitmap
1269
+
1270
+
1271
+ def SetBitmap(self, bitmap):
1272
+ """
1273
+ Sets the bitmap associated with this :class:`Shortcut`.
1274
+
1275
+ :param `bitmap`: an instance of :class:`wx.Bitmap` (can be invalid, i.e., :class:`NullBitmap`).
1276
+ """
1277
+
1278
+ self.bitmap = bitmap
1279
+
1280
+
1281
+ def GetLabel(self):
1282
+ """ Returns the string label associated with this shortcut. """
1283
+
1284
+ return self.label
1285
+
1286
+
1287
+ def IsTop(self):
1288
+ """
1289
+ Returns ``True`` if this :class:`Shortcut` is associated with a top-level :class:`wx.Menu`,
1290
+ (i.e., in the top :class:`wx.MenuBar` level), ``False`` otherwise.
1291
+ """
1292
+
1293
+ return self.topMenu
1294
+
1295
+
1296
+ def GetFirstChild(self, item):
1297
+ """
1298
+ Returns this :class:`Shortcut`'s first child and an integer value 'cookie'.
1299
+ Call :meth:`~Shortcut.GetNextChild` for the next child using this very 'cookie' return
1300
+ value as an input.
1301
+
1302
+ :param `item`: an instance of :class:`Shortcut`.
1303
+
1304
+ :return: A tuple with the first value being an instance of :class:`Shortcut` or ``None`` if there are no
1305
+ further children, and as second value an integer parameter 'cookie'.
1306
+
1307
+ :note: This method returns ``None`` if there are no further children.
1308
+ """
1309
+
1310
+ cookie = 0
1311
+ return self.GetNextChild(item, cookie)
1312
+
1313
+
1314
+ def GetNextChild(self, item, cookie):
1315
+ """
1316
+ Returns this :class:`Shortcut`'s next child.
1317
+
1318
+ :param `item`: an instance of :class:`Shortcut`;
1319
+ :param integer `cookie`: a parameter which is opaque for the application but is necessary
1320
+ for the library to make this function reentrant (i.e. allow more than one
1321
+ enumeration on one and the same object simultaneously).
1322
+
1323
+ :return: A tuple with the first value being an instance of :class:`Shortcut` or ``None`` if there are no
1324
+ further children, and as second value an integer parameter 'cookie'.
1325
+
1326
+ :note: This method returns ``None`` if there are no further children.
1327
+ """
1328
+
1329
+ children = item.children
1330
+ if cookie < len(children):
1331
+ return children[cookie], cookie + 1
1332
+
1333
+ return None, cookie
1334
+
1335
+
1336
+ def GetImageIndex(self):
1337
+ """ Returns an integer index to be used in the :class:`ListShortcut` own :class:`wx.ImageList`. """
1338
+
1339
+ return self.imageIndex
1340
+
1341
+
1342
+ def CheckAccelerator(self, item, shortcut, accelerator):
1343
+ """
1344
+ Checks if a shortcut string entered by the user has already been taken by another entry
1345
+ in the :class:`Shortcut` hierarchy.
1346
+
1347
+ :param `item`: an instance of :class:`Shortcut`;
1348
+ :param `shortcut`: another instance of :class:`Shortcut`, to compare with the previous `item`;
1349
+ :param string `accelerator`: the user-edited accelerator string to check.
1350
+
1351
+ :return: An instance of :class:`Shortcut` if the shortcut string entered by the user conflicts
1352
+ with an existing one, ``None`` otherwise.
1353
+ """
1354
+
1355
+ child, cookie = self.GetFirstChild(item)
1356
+
1357
+ while child:
1358
+ existingAccel = child.accelerator.lower().split('+')
1359
+ existingAccel.sort()
1360
+
1361
+ if existingAccel == accelerator and shortcut != child:
1362
+ return child
1363
+
1364
+ conflict = self.CheckAccelerator(child, shortcut, accelerator)
1365
+
1366
+ if conflict:
1367
+ return conflict
1368
+
1369
+ child, cookie = self.GetNextChild(item, cookie)
1370
+
1371
+ return None
1372
+
1373
+
1374
+ def Match(self, filter='', item=None):
1375
+ """
1376
+ Matches this :class:`Shortcut` label string against the `filter` input variable.
1377
+
1378
+ :param string `filter`: a string to match;
1379
+ :param `item`: an instance of :class:`Shortcut`: its label string is compared with
1380
+ the `filter` string to look for a match.
1381
+
1382
+ :return: An instance of :class:`Shortcut` if the `filter` string is contained in
1383
+ the `item` label, ``None`` otherwise.
1384
+
1385
+ :note: The string-matching is case-insensitive.
1386
+ """
1387
+
1388
+ if item is None:
1389
+ item = self
1390
+
1391
+ child, cookie = self.GetFirstChild(item)
1392
+
1393
+ while child:
1394
+
1395
+ if filter in child.label.lower():
1396
+ self.ShowHierarchy(child)
1397
+
1398
+ self.Match(filter, child)
1399
+ child, cookie = self.GetNextChild(item, cookie)
1400
+
1401
+
1402
+ def ShowHierarchy(self, item):
1403
+ """
1404
+ Set the status of this :class:`Shortcut` ans its parent as `shown` in the
1405
+ :class:`ListShortcut` tree hierarchy.
1406
+
1407
+ :param `item`: an instance of :class:`Shortcut`.
1408
+ """
1409
+
1410
+ item.shown = True
1411
+ parent = item.parent
1412
+
1413
+ while parent:
1414
+ parent.shown = True
1415
+ parent = parent.parent
1416
+
1417
+
1418
+ def ResetVisibility(self, item=None):
1419
+ """
1420
+ Set the status of this :class:`Shortcut` and its parent as `hidden` in the
1421
+ :class:`ListShortcut` tree hierarchy.
1422
+
1423
+ :param `item`: an instance of :class:`Shortcut`, used only to make this function reentrant
1424
+ (i.e. allow more than one enumeration on one and the same object simultaneously).
1425
+ """
1426
+
1427
+ if item is None:
1428
+ item = self
1429
+
1430
+ child, cookie = self.GetFirstChild(item)
1431
+
1432
+ while child:
1433
+ child.shown = False
1434
+ item.shown = False
1435
+ self.ResetVisibility(child)
1436
+ child, cookie = self.GetNextChild(item, cookie)
1437
+
1438
+
1439
+ def Get(self, label, item=None):
1440
+ """
1441
+ Returns an instance of :class:`Shortcut` whose label matches the input `label` string.
1442
+
1443
+ :param string `label`: the string label to compare against this :class:`Shortcut` label;
1444
+ :param `item`: an instance of :class:`Shortcut`, used only to make this function reentrant
1445
+ (i.e. allow more than one enumeration on one and the same object simultaneously).
1446
+
1447
+ :return: An instance of :class:`Shortcut` or ``None`` if no match was found.
1448
+ """
1449
+
1450
+ if item is None:
1451
+ item = self
1452
+
1453
+ child, cookie = self.GetFirstChild(item)
1454
+ retChild = None
1455
+
1456
+ while child:
1457
+ if child.label.lower() == label.lower():
1458
+ return child
1459
+
1460
+ retChild = self.Get(label, child)
1461
+ child, cookie = self.GetNextChild(item, cookie)
1462
+
1463
+ return retChild
1464
+
1465
+
1466
+ def GetById(self, id, item=None):
1467
+ """
1468
+ Returns an instance of :class:`Shortcut` whose ID matches the input `id`.
1469
+
1470
+ :param integer `id`: an integer ID to compare against this :class:`Shortcut` id;
1471
+ :param `item`: an instance of :class:`Shortcut`, used only to make this function reentrant
1472
+ (i.e. allow more than one enumeration on one and the same object simultaneously).
1473
+
1474
+ :return: An instance of :class:`Shortcut` or ``None`` if no match was found.
1475
+ """
1476
+
1477
+ if item is None:
1478
+ item = self
1479
+
1480
+ child, cookie = self.GetFirstChild(item)
1481
+ retChild = None
1482
+
1483
+ while child:
1484
+ if child._id is not None and child._id == id:
1485
+ return child
1486
+ elif child.accelId == id:
1487
+ return child
1488
+
1489
+ retChild = self.GetById(id, child)
1490
+ child, cookie = self.GetNextChild(item, cookie)
1491
+
1492
+ return retChild
1493
+
1494
+
1495
+ def GetId(self):
1496
+ """ Returns this :class:`Shortcut` ID. """
1497
+
1498
+ if self._id is not None:
1499
+ return self._id
1500
+
1501
+ return self.accelId
1502
+
1503
+
1504
+ def RestoreDefaults(self, item=None):
1505
+ """
1506
+ Restore the original shortcut string for this :class:`Shortcut`.
1507
+
1508
+ :param `item`: an instance of :class:`Shortcut`, used only to make this function reentrant
1509
+ (i.e. allow more than one enumeration on one and the same object simultaneously).
1510
+ """
1511
+
1512
+ if item is None:
1513
+ item = self
1514
+
1515
+ child, cookie = self.GetFirstChild(item)
1516
+
1517
+ while child:
1518
+ child.accelerator = child.originalAccelerator
1519
+ child.changed = False
1520
+ self.RestoreDefaults(child)
1521
+ child, cookie = self.GetNextChild(item, cookie)
1522
+
1523
+
1524
+ def FromMenuItem(self, menuItem):
1525
+ """
1526
+ Constructs this :class:`Shortcut` starting from a :class:`wx.Menu` or :class:`wx.MenuItem`.
1527
+
1528
+ The attributes needed to properly construct a :class:`Shortcut` are the label,
1529
+ the accelerator string, the help string (optional) and the bitmap associated
1530
+ with it (optional).
1531
+
1532
+ :param `menuItem`: the :class:`wx.Menu` or :class:`wx.MenuItem` this :class:`Shortcut`
1533
+ was built from; only read here, not retained, since it may be destroyed later
1534
+ with no notification to this object.
1535
+ """
1536
+
1537
+ if menuItem is None:
1538
+ return
1539
+
1540
+ if isinstance(menuItem, wx.Menu):
1541
+ label = menuItem.GetTitle()
1542
+ accelerator = DISABLED_STRING
1543
+ help = ''
1544
+ bitmap = wx.NullBitmap
1545
+ else:
1546
+ label = menuItem.GetItemLabelText()
1547
+ accelerator = menuItem.GetItemLabel()
1548
+
1549
+ if '\t' in accelerator:
1550
+ accelerator = accelerator[accelerator.index('\t')+1:]
1551
+ else:
1552
+ accelerator = DISABLED_STRING
1553
+
1554
+ help = menuItem.GetHelp()
1555
+ bitmap = menuItem.GetBitmap()
1556
+
1557
+ self.label = label
1558
+ self.accelerator = accelerator
1559
+ self.help = help
1560
+ self.bitmap = bitmap
1561
+
1562
+ self.originalAccelerator = accelerator
1563
+
1564
+
1565
+ def ToMenuItem(self, menuBar):
1566
+ """
1567
+ Dumps this :class:`Shortcut` into a :class:`wx.Menu` or :class:`wx.MenuItem`.
1568
+
1569
+ The attributes needed to properly dump a :class:`Shortcut` into a :class:`wx.Menu` or :class:`wx.MenuBar`
1570
+ are the label and the accelerator string.
1571
+
1572
+ :param `menuBar`: an instance of :class:`wx.MenuBar`.
1573
+ """
1574
+
1575
+ if self._id is None or not self.changed:
1576
+ return
1577
+
1578
+ if self._isMenu:
1579
+
1580
+ if self.accelerator == DISABLED_STRING:
1581
+ label = self.label
1582
+ else:
1583
+ label = '%s\t%s'%(self.label, self.accelerator)
1584
+
1585
+ menuBar.SetMenuLabel(self.position, label)
1586
+
1587
+ else:
1588
+
1589
+ label = self._itemLabel
1590
+ if '\t' in label:
1591
+ label = label[0:label.index('\t')]
1592
+
1593
+ if self.accelerator != DISABLED_STRING:
1594
+ label = '%s\t%s'%(label, self.accelerator)
1595
+
1596
+ menuBar.SetLabel(self._id, label)
1597
+
1598
+
1599
+ def ToAcceleratorItem(self, table):
1600
+ """
1601
+ Dumps this :class:`Shortcut` into a tuple of 3 elements:
1602
+
1603
+ * **flags**: a bitmask of ``wx.ACCEL_ALT``, ``wx.ACCEL_SHIFT``, ``wx.ACCEL_CTRL``, ``wx.ACCEL_CMD``
1604
+ or ``wx.ACCEL_NORMAL`` used to specify which modifier keys are held down;
1605
+ * **keyCode**: the keycode to be detected (i.e., ord('b'), wx.WXK_F10, etc...);
1606
+ * **cmdID**: the menu or control command ID to use for the accelerator event.
1607
+
1608
+ :param `table`: a list of tuples, with the above specifications.
1609
+ """
1610
+
1611
+ if self._id is not None or not self.changed:
1612
+ return
1613
+
1614
+ if self.GetId() is None:
1615
+ return
1616
+
1617
+ accelerator = self.accelerator
1618
+ accelId = self.accelId
1619
+
1620
+ split = accelerator.split('+')
1621
+ modifiers, keyCode = split[0:-1], split[-1]
1622
+
1623
+ inv_Accel = dict(zip(ACCELERATORS.values(), ACCELERATORS.keys()))
1624
+ inv_KeyMap = dict(zip(KEYMAP.values(), KEYMAP.keys()))
1625
+
1626
+ base = wx.ACCEL_NORMAL
1627
+
1628
+ for mod in modifiers:
1629
+ base |= inv_Accel[mod]
1630
+
1631
+ if keyCode in inv_KeyMap:
1632
+ keyCode = inv_KeyMap[keyCode]
1633
+ else:
1634
+ keyCode = ord(keyCode)
1635
+
1636
+ accelItem = (base, keyCode, accelId)
1637
+ table.append(accelItem)
1638
+
1639
+
1640
+ # ----------------------------------------------------------------------------
1641
+ # ConflictDialog is a subclass of GenericMessageDialog, customized to look
1642
+ # like the GIMP conflict dialog.
1643
+ # ----------------------------------------------------------------------------
1644
+
1645
+ class ConflictDialog(GMD.GenericMessageDialog):
1646
+ """
1647
+ :class:`ConflictDialog` is a subclass of :class:`GenericMessageDialog`, customized to look
1648
+ like the GIMP conflict dialog. This class is used to resolve shortcut
1649
+ conflicts when the user assigns a shortcut that is already taken by another
1650
+ entry in the shortcut list.
1651
+ """
1652
+
1653
+ def __init__(self, parent, conflict):
1654
+ """
1655
+ Default class constructor.
1656
+
1657
+ :param `parent`: an instance of :class:`ShortcutEditor`;
1658
+ :param `conflict`: an instance of :class:`Shortcut`, representing the conflicting
1659
+ shortcut.
1660
+ """
1661
+
1662
+ transDict = dict(shortcut=conflict.accelerator, item=conflict.label, group=conflict.parent.label)
1663
+ message = _('Shortcut "%(shortcut)s" is already taken by\n"%(item)s" from the "%(group)s" group. ')%transDict
1664
+
1665
+ transDict = dict(item=conflict.label)
1666
+ extendedMessage = _('Reassigning the shortcut will cause it to be removed from \n"%(item)s". ')%transDict
1667
+
1668
+ GMD.GenericMessageDialog.__init__(self, parent, message, _('Conflicting Shortcuts'),
1669
+ wx.OK|wx.CANCEL|wx.ICON_EXCLAMATION)
1670
+
1671
+ self.SetOKLabel(_('Reassing shortcut '))
1672
+ self.SetOKBitmap(_reassign.GetBitmap())
1673
+
1674
+ self.SetExtendedMessage(extendedMessage + '\n')
1675
+ self.SetIcon(parent.GetParent().GetIcon())
1676
+
1677
+
1678
+ # ----------------------------------------------------------------------------
1679
+ # ListShortcut is a subclass of HyperTreeList, customized to look
1680
+ # like the GIMP main shortcut list.
1681
+ # ----------------------------------------------------------------------------
1682
+
1683
+ class ListShortcut(HTL.HyperTreeList, treemixin.ExpansionState):
1684
+ """
1685
+ :class:`ListShortcut` is a subclass of :class:`~wx.lib.agw.hypertreelist.HyperTreeList`,
1686
+ customized to look like the GIMP main shortcut list. This class is used to display the
1687
+ shortcut label (with an optional bitmap next to it), its accelerator and
1688
+ the help string associated with it (if present).
1689
+
1690
+ This information is displayed in 3 columns inside :class:`ListShortcut`.
1691
+ """
1692
+
1693
+ def __init__(self, parent):
1694
+ """
1695
+ Default class constructor.
1696
+
1697
+ :param `parent`: an instance of :class:`ShortcutEditor`.
1698
+ """
1699
+
1700
+ HTL.HyperTreeList.__init__(self, parent, style=wx.BORDER_THEME,
1701
+ agwStyle=wx.TR_DEFAULT_STYLE|wx.TR_HIDE_ROOT|
1702
+ wx.TR_FULL_ROW_HIGHLIGHT|HTL.TR_ELLIPSIZE_LONG_ITEMS)
1703
+
1704
+ self.SetBackgroundColour(wx.WHITE)
1705
+
1706
+ self.AddColumn(_('Action'))
1707
+ self.AddColumn(_('Shortcut'))
1708
+ self.AddColumn(_('Help Label'))
1709
+ self.SetMainColumn(0) # the one with the tree in it...
1710
+
1711
+ self.AddRoot('')
1712
+ self.CalculateOffset()
1713
+
1714
+ self.selectedItem = None
1715
+ self.hookBound = False
1716
+ self.filter = ''
1717
+ self.expansionState = []
1718
+
1719
+ self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged)
1720
+ self.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.OnExpandCollapse)
1721
+ self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnExpandCollapse)
1722
+
1723
+ mainWindow = self.GetMainWindow()
1724
+ mainWindow.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
1725
+ mainWindow.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
1726
+
1727
+
1728
+ def CalculateOffset(self):
1729
+ """
1730
+ Calculates an offset (in pixels) so that the :class:`Shortcut` items without
1731
+ a bitmap look parallel to the ones with a bitmap.
1732
+ """
1733
+
1734
+ dc = wx.MemoryDC()
1735
+ dc.SelectObject(wx.Bitmap(20, 20))
1736
+ dc.SetFont(self.GetFont())
1737
+
1738
+ space = 0
1739
+ text = ''
1740
+
1741
+ while space < 15:
1742
+ space, dummy = dc.GetTextExtent(text)
1743
+ text += ' '
1744
+
1745
+ dc.SelectObject(wx.NullBitmap)
1746
+ self.offset = text
1747
+
1748
+ boldFont = FontFromFont(self.GetFont())
1749
+ boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
1750
+
1751
+ self.boldFont = boldFont
1752
+
1753
+
1754
+ def Populate(self, item=None, shortcut=None):
1755
+ """
1756
+ Recursively populates the :class:`ListShortcut` with information from the :class:`Shortcut` tree.
1757
+
1758
+ :param `item`: an instance of :class:`~wx.lib.agw.customtreectrl.GenericTreeItem`. If ``None``, it is defaulted to
1759
+ the :class:`ListShortcut` root item to make this function reentrant (i.e. allow more than one
1760
+ enumeration on one and the same object simultaneously);
1761
+ :param `shortcut`: an instance of :class:`Shortcut`. If ``None``, it is defaulted to
1762
+ `self.manager` to make this function reentrant (i.e. allow more than one
1763
+ enumeration on one and the same object simultaneously).
1764
+ """
1765
+
1766
+ if shortcut is None:
1767
+ shortcut = self.manager
1768
+ item = self.GetRootItem()
1769
+
1770
+ for child in shortcut.children:
1771
+
1772
+ if not child.shown:
1773
+ continue
1774
+
1775
+ image = child.GetImageIndex()
1776
+ label = child.label
1777
+
1778
+ if image < 0:
1779
+ if not child.IsTop():
1780
+ label = self.offset + label
1781
+
1782
+ newItem = self.AppendItem(item, label, data=child)
1783
+ else:
1784
+ newItem = self.AppendItem(item, label, image=image, data=child)
1785
+
1786
+ if child.IsTop():
1787
+ self.SetItemFont(newItem, self.boldFont)
1788
+
1789
+ self.SetItemText(newItem, child.accelerator, 1)
1790
+ self.SetItemText(newItem, child.help, 2)
1791
+
1792
+ colour = (child.HasChanged() and [wx.RED] or [wx.BLACK])[0]
1793
+ self.SetItemTextColour(newItem, colour)
1794
+
1795
+ self.Populate(newItem, child)
1796
+
1797
+
1798
+ def MakeImageList(self):
1799
+ """ Builds the :class:`ListShortcut` image list based on the bitmaps in the :class:`Shortcut` hierarchy. """
1800
+
1801
+ self.imageList = wx.ImageList(16, 16)
1802
+ self.BuildImageList()
1803
+ self.AssignImageList(self.imageList)
1804
+
1805
+
1806
+ def BuildImageList(self, shortcut=None, index=None):
1807
+ """
1808
+ Recursively builds the :class:`ListShortcut` image list based on the bitmaps in the
1809
+ :class:`Shortcut` hierarchy.
1810
+
1811
+ :param `shortcut`: an instance of :class:`Shortcut`. If ``None``, it is defaulted to
1812
+ `self.manager` to make this function reentrant (i.e. allow more than one
1813
+ enumeration on one and the same object simultaneously);
1814
+ :param integer `index`: the current image index inside the :class:`ListShortcut` own :class:`wx.ImageList`.
1815
+ """
1816
+
1817
+ if shortcut is None:
1818
+ shortcut = self.manager
1819
+ index = 0
1820
+
1821
+ for child in shortcut.children:
1822
+ bitmap = child.GetBitmap()
1823
+
1824
+ if bitmap.IsOk():
1825
+ if bitmap.GetSize() != (16, 16):
1826
+ bitmap = bitmap.ConvertToImage().Scale(16, 16, wx.IMAGE_QUALITY_HIGH).ConvertToBitmap()
1827
+ self.imageList.Add(bitmap)
1828
+ child.imageIndex = index
1829
+ index += 1
1830
+
1831
+ index = self.BuildImageList(child, index)
1832
+
1833
+ return index
1834
+
1835
+
1836
+ def GetItemIdentity(self, item):
1837
+ """
1838
+ Return a hashable object that represents the identity of a :class:`ListShortcut` item.
1839
+
1840
+ In this implementation this returns the item label.
1841
+
1842
+ :param `item`: an instance of :class:`~wx.lib.agw.customtreectrl.GenericTreeItem`.
1843
+ """
1844
+
1845
+ return self.GetItemText(item)
1846
+
1847
+
1848
+ def OnSelChanged(self, event):
1849
+ """
1850
+ Handles the ``wx.EVT_TREE_SEL_CHANGED`` event for :class:`ListShortcut`.
1851
+
1852
+ :param `event`: an instance of :class:`TreeEvent`.
1853
+ """
1854
+
1855
+ selectedItem = event.GetItem()
1856
+
1857
+ if selectedItem != self.selectedItem:
1858
+ if self.selectedItem is not None:
1859
+ pydata = self.GetPyData(self.selectedItem)
1860
+ self.SetItemText(self.selectedItem, pydata.accelerator, 1)
1861
+ else:
1862
+ pydata = self.GetPyData(selectedItem)
1863
+ if pydata.GetId() is not None:
1864
+ self.SetItemText(selectedItem, NEW_ACCEL_STRING, 1)
1865
+ else:
1866
+
1867
+ pydata = self.GetPyData(selectedItem)
1868
+ self.SetItemText(selectedItem, pydata.accelerator, 1)
1869
+
1870
+ self.selectedItem = selectedItem
1871
+ self.ShowShortcutText(False)
1872
+
1873
+
1874
+ def OnExpandCollapse(self, event):
1875
+ """
1876
+ Handles the ``wx.EVT_TREE_ITEM_COLLAPSED`` / ``wx.EVT_TREE_ITEM_EXPANDED`` events for :class:`ListShortcut`.
1877
+
1878
+ :param `event`: an instance of :class:`TreeEvent`.
1879
+ """
1880
+
1881
+ event.Skip()
1882
+ self.expansionState = self.GetExpansionState()
1883
+
1884
+
1885
+ def OnLeftDown(self, event):
1886
+ """
1887
+ Handles the ``wx.EVT_LEFT_DOWN`` event for :class:`ListShortcut`.
1888
+
1889
+ :param `event`: an instance of :class:`MouseEvent`.
1890
+ """
1891
+
1892
+ if not self.hookBound:
1893
+ self.GetParent().Bind(wx.EVT_CHAR_HOOK, self.OnShortcut)
1894
+ self.hookBound = True
1895
+
1896
+ currentItem, flags, column = self.HitTest(event.GetPosition())
1897
+
1898
+ if self.selectedItem is None or not currentItem:
1899
+ event.Skip()
1900
+ return
1901
+
1902
+ pydata = self.GetPyData(currentItem)
1903
+
1904
+ if pydata.GetId() is None:
1905
+ event.Skip()
1906
+ return
1907
+
1908
+ if self.GetItemText(currentItem, 1) != NEW_ACCEL_STRING:
1909
+ self.SetItemText(currentItem, NEW_ACCEL_STRING, 1)
1910
+ else:
1911
+ self.SetItemText(currentItem, pydata.accelerator, 1)
1912
+
1913
+ event.Skip()
1914
+
1915
+
1916
+ def OnKillFocus(self, event):
1917
+ """
1918
+ Handles the ``wx.EVT_KILL_FOCUS`` event for :class:`ListShortcut`.
1919
+
1920
+ :param `event`: an instance of :class:`FocusEvent`.
1921
+ """
1922
+
1923
+ self.GetParent().Unbind(wx.EVT_CHAR_HOOK)
1924
+ self.hookBound = False
1925
+
1926
+ self.ShowShortcutText(False)
1927
+
1928
+ if self.selectedItem:
1929
+ pydata = self.GetPyData(self.selectedItem)
1930
+ self.SetItemText(self.selectedItem, pydata.accelerator, 1)
1931
+
1932
+ event.Skip()
1933
+
1934
+
1935
+ def OnShortcut(self, event):
1936
+ """
1937
+ Handles the ``wx.EVT_CHAR_HOOK`` event for :class:`ShortcutEditor`, implemented in :class:`ListShortcut`
1938
+ as it is easier to deal with in this class.
1939
+
1940
+ :param `event`: an instance of :class:`KeyEvent`.
1941
+ """
1942
+
1943
+ if self.selectedItem is None:
1944
+ # How did we get here???
1945
+ event.Skip()
1946
+ return
1947
+
1948
+ pydata = self.GetPyData(self.selectedItem)
1949
+ currentText = self.GetItemText(self.selectedItem, 1)
1950
+
1951
+ if pydata.GetId() is None:
1952
+ # Don't allow to change labels for shortcuts without an ID
1953
+ event.Skip()
1954
+ return
1955
+
1956
+ self.ShowShortcutText(True)
1957
+ textCtrl = self.GetParent().hiddenText
1958
+
1959
+ keyCode = event.GetKeyCode()
1960
+ modifiers = event.GetModifiers()
1961
+
1962
+ # If we press backspace with no modifiers down, *and* the current text is
1963
+ # "New accelerator..." then we reset the accelerator to "Disabled"
1964
+ if keyCode == wx.WXK_BACK and modifiers == 0 and currentText in [NEW_ACCEL_STRING, DISABLED_STRING]:
1965
+
1966
+ accelerator = DISABLED_STRING
1967
+
1968
+ if not self.FireShortcutChanging(pydata, accelerator):
1969
+ return
1970
+
1971
+ pydata.SetAccelerator(accelerator)
1972
+ self.SetItemText(self.selectedItem, pydata.accelerator, 1)
1973
+
1974
+ colour = (pydata.HasChanged() and [wx.RED] or [wx.BLACK])[0]
1975
+ self.SetItemTextColour(self.selectedItem, colour)
1976
+
1977
+ self.ShowShortcutText(False)
1978
+ self.FireShortcutChanged(pydata, accelerator)
1979
+
1980
+ return
1981
+
1982
+ newContent = ''
1983
+
1984
+ for mod_int, mod_name in MODIFIERS:
1985
+
1986
+ if modifiers & mod_int == 0:
1987
+ continue
1988
+
1989
+ newContent += mod_name + '+'
1990
+
1991
+ if newContent.strip():
1992
+ textCtrl.ChangeValue(newContent)
1993
+
1994
+ accelerator = ''
1995
+
1996
+ if keyCode in KEYMAP:
1997
+ accelerator = newContent + KEYMAP[keyCode]
1998
+ else:
1999
+ try:
2000
+ toChar = chr(keyCode)
2001
+ accelerator = newContent + toChar
2002
+ except ValueError:
2003
+ pass
2004
+
2005
+ if accelerator:
2006
+
2007
+ if not self.FireShortcutChanging(pydata, accelerator):
2008
+ return
2009
+
2010
+ if self.AcceptShortcut(pydata, accelerator):
2011
+
2012
+ pydata.SetAccelerator(accelerator)
2013
+ self.SetItemText(self.selectedItem, pydata.accelerator, 1)
2014
+
2015
+ colour = (pydata.HasChanged() and [wx.RED] or [wx.BLACK])[0]
2016
+ self.SetItemTextColour(self.selectedItem, colour)
2017
+
2018
+ self.ShowShortcutText(False)
2019
+ self.FireShortcutChanged(pydata, accelerator)
2020
+
2021
+
2022
+ def AcceptShortcut(self, shortcut, accelerator):
2023
+ """
2024
+ Returns ``True`` if the input `accelerator` is a valid shortcut, ``False`` otherwise.
2025
+
2026
+ :param `shortcut`: an instance of :class:`Shortcut`;
2027
+ :param string `accelerator`: the new accelerator to check.
2028
+
2029
+ :note: Conflicting shortcuts are handled inside this method by presenting the user with
2030
+ a conflict dialog. At this point the user can decide to reassign an existing shortcut
2031
+ or to back away, in which case this method will return ``False``.
2032
+ """
2033
+
2034
+ sortedAccel = accelerator.lower().split('+')
2035
+ sortedAccel.sort()
2036
+
2037
+ conflict = self.manager.CheckAccelerator(self.manager, shortcut, sortedAccel)
2038
+
2039
+ if conflict is None:
2040
+ return True
2041
+
2042
+ dlg = ConflictDialog(self.GetParent(), conflict)
2043
+
2044
+ if dlg.ShowModal() == wx.ID_OK:
2045
+ self.DisableShortcut(conflict)
2046
+ dlg.Destroy()
2047
+ return True
2048
+
2049
+ dlg.Destroy()
2050
+ return False
2051
+
2052
+
2053
+ def DisableShortcut(self, conflict, item=None):
2054
+ """
2055
+ If the user decides to reassign a shortcut to another item, this method will disable
2056
+ the conflicting shortcut (by putting a "Disabled" string as its accelerator).
2057
+
2058
+ :param `conflict`: an instance of :class:`Shortcut` to reset;
2059
+ :param `item`: an instance of :class:`~wx.lib.agw.customtreectrl.GenericTreeItem`. If defaulted to ``None``, it is set
2060
+ to the :class:`ListShortcut` root item and used only to make this function reentrant
2061
+ (i.e. allow more than one enumeration on one and the same object simultaneously).
2062
+ """
2063
+
2064
+ if item is None:
2065
+ item = self.GetRootItem()
2066
+
2067
+ child, cookie = self.GetFirstChild(item)
2068
+
2069
+ while child:
2070
+ if child.GetData() == conflict:
2071
+ conflict.SetAccelerator(DISABLED_STRING)
2072
+ self.SetItemText(child, conflict.accelerator, 1)
2073
+
2074
+ colour = (conflict.HasChanged() and [wx.RED] or [wx.BLACK])[0]
2075
+ self.SetItemTextColour(child, colour)
2076
+ return
2077
+
2078
+ self.DisableShortcut(conflict, child)
2079
+ child, cookie = self.GetNextChild(item, cookie)
2080
+
2081
+
2082
+ def FireShortcutChanging(self, shortcut, newAccel):
2083
+ """
2084
+ Fires the ``EVT_SHORTCUT_CHANGING`` event for :class:`ListShortcut`.
2085
+
2086
+ The event propagation (and thus the shortcut renaming by the user) can be
2087
+ interrupted by *not* calling `event.Skip()` in your handler for this event.
2088
+
2089
+ :param `shortcut`: an instance of :class:`Shortcut` that is about to be renamed;
2090
+ :param string `newAccel`: the new accelerator just entered by the user.
2091
+ """
2092
+
2093
+ event = ShortcutEvent(wxEVT_SHORTCUT_CHANGING, self.GetId())
2094
+ event.SetShortcut(shortcut)
2095
+ event.oldAccelerator = shortcut.accelerator
2096
+ event.accelerator = newAccel
2097
+ event.SetEventObject(self)
2098
+
2099
+ if self.GetEventHandler().ProcessEvent(event):
2100
+ # the caller didn't use event.Skip()
2101
+ return False
2102
+
2103
+ return True
2104
+
2105
+
2106
+ def FireShortcutChanged(self, shortcut, newAccel):
2107
+ """
2108
+ Fires the ``EVT_SHORTCUT_CHANGED`` event for :class:`ListShortcut`.
2109
+
2110
+ :param `shortcut`: an instance of :class:`Shortcut` that has been renamed;
2111
+ :param string `newAccel`: the new accelerator just entered by the user.
2112
+ """
2113
+
2114
+ event = ShortcutEvent(wxEVT_SHORTCUT_CHANGED, self.GetId())
2115
+ event.SetShortcut(shortcut)
2116
+ event.oldAccelerator = shortcut.accelerator
2117
+ event.accelerator = newAccel
2118
+ event.SetEventObject(self)
2119
+
2120
+ self.GetEventHandler().ProcessEvent(event)
2121
+
2122
+ return True
2123
+
2124
+
2125
+ def ShowShortcutText(self, show):
2126
+ """
2127
+ Shows/Hides a :class:`TextCtrl` used to display the combination of keystrokes the user
2128
+ has entered. This :class:`TextCtrl` remains visible only for a short amount of time
2129
+ and only when some keys are down.
2130
+
2131
+ :param bool `show`: ``True`` to show the :class:`TextCtrl`, ``False`` to hide it.
2132
+ """
2133
+
2134
+ textCtrl = self.GetParent().hiddenText
2135
+
2136
+ if show and not textCtrl.IsShown():
2137
+ textCtrl.Show()
2138
+
2139
+ elif not show and textCtrl.IsShown():
2140
+ textCtrl.Hide()
2141
+
2142
+
2143
+ def SetFilter(self, filter=''):
2144
+ """
2145
+ Sets the `filter` string against all the shortcuts in the :class:`ListShortcut` are matched.
2146
+
2147
+ :param string `filter`: a string to match.
2148
+ """
2149
+
2150
+ self.filter = filter
2151
+
2152
+ self.manager.ResetVisibility()
2153
+ self.manager.Match(filter)
2154
+ self.RecreateTree()
2155
+
2156
+
2157
+ def RecreateTree(self):
2158
+ """ Recreates the entire :class:`ListShortcut` (columns excluded). """
2159
+
2160
+ self.Freeze()
2161
+ self.DeleteAllItems()
2162
+ self.AddRoot('')
2163
+
2164
+ self.Populate()
2165
+
2166
+ if not self.expansionState:
2167
+ # Only the root item
2168
+ self.ExpandAll()
2169
+ else:
2170
+ self.SetExpansionState(self.expansionState)
2171
+
2172
+ self.Thaw()
2173
+
2174
+
2175
+ def HasFlag(self, flag):
2176
+ """
2177
+ Overridden from :class:`wx.Window` as a workaround on the conflicts between `treemixin` and
2178
+ :class:`~wx.lib.agw.hypertreelist.HyperTreeList` with the ``wx.TR_HIDE_ROOT`` `agwStyle` set.
2179
+
2180
+ :param integer `flag`: an integer bit flag specifying the `agwStyle` style.
2181
+
2182
+ :return: ``True`` if the :class:`ListShortcut` has the input `flag` set, ``False`` otherwise.
2183
+
2184
+ :note: Overridden from :class:`wx.Window`.
2185
+ """
2186
+
2187
+ return self.HasAGWFlag(flag)
2188
+
2189
+
2190
+ # ----------------------------------------------------------------------------
2191
+ # ShortcutEditor is a subclass of wx.Dialog, customized to look
2192
+ # like the GIMP main shortcut dialog.
2193
+ # ----------------------------------------------------------------------------
2194
+
2195
+ class ShortcutEditor(wx.Dialog):
2196
+ """
2197
+ :class:`ShortcutEditor` is a widget that allows the user to customize and change keyboard
2198
+ shortcuts via a dialog. It can be used to edit :class:`wx.MenuItem` shortcuts or accelerators
2199
+ defined in a :class:`AcceleratorTable`.
2200
+
2201
+ The interface itself is very much inpired by the GIMP shortcut editor:
2202
+
2203
+ http://graphicssoft.about.com/od/gimptutorials/tp/keyboard-shortcut-editor.htm
2204
+
2205
+ There are very few minor UI differences between :class:`ShortcutEditor` and the GIMP one,
2206
+ although the behaviour should be pretty much equivalent.
2207
+ """
2208
+
2209
+ def __init__(self, parent):
2210
+ """
2211
+ Default class constructor.
2212
+
2213
+ :param `parent`: an instance of :class:`wx.Window`, it can also be ``None``.
2214
+ """
2215
+
2216
+ wx.Dialog.__init__(self, parent, title=_('Configure Keyboard Shortcuts'),
2217
+ style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
2218
+
2219
+ self.htmlFile = os.path.join(DATA_DIR, 'default_help_text.html')
2220
+ self.htmlWindow = None
2221
+
2222
+ self.CreateWidgets()
2223
+ self.DoLayout()
2224
+ self.BindEvents()
2225
+
2226
+ if parent is not None and isinstance(parent, wx.TopLevelWindow):
2227
+ self.SetIcon(parent.GetIcon())
2228
+
2229
+ self.Init()
2230
+
2231
+
2232
+ def CreateWidgets(self):
2233
+ """
2234
+ Creates all the widgets needed to populate the interface, such as buttons,
2235
+ texts and, most importantly, :class:`ListShortcut`.
2236
+ """
2237
+
2238
+ self.topStatic = wx.StaticText(self, -1, _('&Search:'))
2239
+ self.searchText = wx.TextCtrl(self, -1, '')
2240
+
2241
+ clearBmp = _clear.GetBitmap()
2242
+ self.clearButton = wx.BitmapButton(self, wx.ID_CLEAR, clearBmp, style=wx.NO_BORDER)
2243
+
2244
+ self.listShortcut = ListShortcut(self)
2245
+ self.hiddenText = wx.TextCtrl(self, -1, '', style=wx.BORDER_THEME)
2246
+
2247
+ w, h, d, e = self.hiddenText.GetFullTextExtent('Ctrl+Shift+Alt+q+g+M', self.hiddenText.GetFont())
2248
+ self.hiddenText.SetMinSize((w, h+d-e+1))
2249
+
2250
+ defaultBmp = _default.GetBitmap()
2251
+ self.defaultButton = buttons.ThemedGenBitmapTextButton(self, wx.ID_RESET, defaultBmp,
2252
+ _('Restore Defaults '), size=(-1, 29))
2253
+
2254
+ self.infoBitmap = wx.StaticBitmap(self, -1, _info.GetBitmap())
2255
+
2256
+ message = _('To edit a shortcut key, click on the corresponding row\n' \
2257
+ 'and type a new accelerator, or press backspace to clear.')
2258
+
2259
+ italicFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
2260
+ italicFont.SetStyle(wx.FONTSTYLE_ITALIC)
2261
+
2262
+ self.infoStatic = wx.StaticText(self, -1, message)
2263
+ self.infoStatic.SetFont(italicFont)
2264
+
2265
+ okBmp = _ok.GetBitmap()
2266
+ cancelBmp = _cancel.GetBitmap()
2267
+ helpBmp = _help.GetBitmap()
2268
+
2269
+ self.okButton = buttons.ThemedGenBitmapTextButton(self, wx.ID_OK, okBmp, _('OK'))
2270
+ self.cancelButton = buttons.ThemedGenBitmapTextButton(self, wx.ID_CANCEL, cancelBmp, _('Cancel'))
2271
+ self.helpButton = buttons.ThemedGenBitmapTextButton(self, wx.ID_HELP, helpBmp, _('Help'))
2272
+
2273
+ self.okButton.SetDefault()
2274
+
2275
+
2276
+ def DoLayout(self):
2277
+ """ Lays out the widgets using sizers in a platform-independent way. """
2278
+
2279
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
2280
+ topSizer = wx.BoxSizer(wx.HORIZONTAL)
2281
+
2282
+ mainSizer.Add((0, 5))
2283
+ topSizer.Add(self.topStatic, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
2284
+ topSizer.Add(self.searchText, 1, wx.RIGHT, 5)
2285
+ topSizer.Add(self.clearButton, 0, wx.ALIGN_CENTER_VERTICAL)
2286
+
2287
+ mainSizer.Add(topSizer, 0, wx.ALL|wx.EXPAND, 10)
2288
+ mainSizer.Add(self.listShortcut, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 10)
2289
+ mainSizer.Add((0, 5))
2290
+
2291
+ hiddenSizer = wx.BoxSizer(wx.HORIZONTAL)
2292
+ hiddenSizer.Add(self.hiddenText, 0, wx.LEFT|wx.RIGHT|wx.RESERVE_SPACE_EVEN_IF_HIDDEN, 10)
2293
+ hiddenSizer.Add((1, 0), 1, wx.EXPAND)
2294
+ hiddenSizer.Add(self.defaultButton, 0, wx.EXPAND|wx.LEFT|wx.RIGHT, 10)
2295
+
2296
+ mainSizer.Add(hiddenSizer, 0, wx.EXPAND|wx.BOTTOM, 5)
2297
+
2298
+ centerSizer = wx.BoxSizer(wx.HORIZONTAL)
2299
+ centerSizer.Add(self.infoBitmap, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 10)
2300
+ centerSizer.Add(self.infoStatic, 1, wx.ALIGN_CENTER)
2301
+
2302
+ mainSizer.Add(centerSizer, 0, wx.TOP|wx.BOTTOM|wx.RIGHT, 10)
2303
+
2304
+ otherSizer = wx.BoxSizer(wx.HORIZONTAL)
2305
+ # Add the fancy buttons
2306
+ otherSizer.Add(self.okButton, 0, wx.ALL, 10)
2307
+ otherSizer.Add((0, 0), 1, wx.EXPAND)
2308
+ otherSizer.Add(self.cancelButton, 0, wx.LEFT|wx.TOP|wx.BOTTOM, 10)
2309
+ otherSizer.Add(self.helpButton, 0, wx.ALL, 10)
2310
+ mainSizer.Add(otherSizer, 0, wx.EXPAND|wx.TOP, 5)
2311
+
2312
+ self.hiddenText.Hide()
2313
+ self.SetSizer(mainSizer)
2314
+ mainSizer.Layout()
2315
+
2316
+
2317
+ def BindEvents(self):
2318
+ """
2319
+ Binds a few events we will need to process:
2320
+
2321
+ * ``wx.EVT_TEXT`` for the label filtering;
2322
+ * ``wx.EVT_BUTTON`` for clearing the filtering, for the HTML help window and
2323
+ to reset all the shortcuts to their defaults.
2324
+ """
2325
+
2326
+ self.searchText.Bind(wx.EVT_TEXT, self.OnSetFilter)
2327
+ self.clearButton.Bind(wx.EVT_BUTTON, self.OnClearFilter)
2328
+
2329
+ self.defaultButton.Bind(wx.EVT_BUTTON, self.OnRestoreDefaults)
2330
+ self.helpButton.Bind(wx.EVT_BUTTON, self.OnHTMLHelp)
2331
+
2332
+
2333
+ def Init(self):
2334
+ """ Common initialization procedures. """
2335
+
2336
+ self.manager = Shortcut()
2337
+ self.listShortcut.manager = self.manager
2338
+
2339
+
2340
+ def FromMenuBar(self, topWindow):
2341
+ """
2342
+ Builds the entire shortcut hierarchy starting from a :class:`wx.MenuBar`.
2343
+
2344
+ :param `topWindow`: an instance of :class:`TopLevelWindow`, containing the :class:`wx.MenuBar`
2345
+ we wish to scan.
2346
+ """
2347
+
2348
+ def MenuItemSearch(menu, item):
2349
+
2350
+ for menuItem in list(menu.GetMenuItems()):
2351
+ label = menuItem.GetItemLabel()
2352
+
2353
+ if not label:
2354
+ # It's a separator
2355
+ continue
2356
+
2357
+ shortcutItem = Shortcut(menuItem=menuItem)
2358
+ shortcutItem.FromMenuItem(menuItem)
2359
+
2360
+ item.AppendItem(shortcutItem)
2361
+
2362
+ subMenu = menuItem.GetSubMenu()
2363
+
2364
+ if subMenu:
2365
+ MenuItemSearch(subMenu, shortcutItem)
2366
+
2367
+ position = 0
2368
+
2369
+ for menu, name in topWindow.GetMenuBar().GetMenus():
2370
+
2371
+ shortcutItem = Shortcut(menuItem=menu)
2372
+ shortcutItem.topMenu = True
2373
+ shortcutItem.position = position
2374
+ shortcutItem.FromMenuItem(menu)
2375
+
2376
+ position += 1
2377
+ self.manager.AppendItem(shortcutItem)
2378
+ MenuItemSearch(menu, item=shortcutItem)
2379
+
2380
+
2381
+ def ToMenuBar(self, topWindow):
2382
+ """
2383
+ Dumps the entire shortcut hierarchy (for shortcuts associated with a :class:`wx.MenuItem`), into
2384
+ a :class:`wx.MenuBar`, changing only the :class:`wx.Menu` / :class:`wx.MenuItem` labels (it does **not** rebuild
2385
+ the :class:`wx.MenuBar`).
2386
+
2387
+ :param `topWindow`: an instance of :class:`TopLevelWindow`, containing the :class:`wx.MenuBar`
2388
+ we wish to repopulate.
2389
+ """
2390
+
2391
+ def MenuItemSet(shortcut, menuBar):
2392
+
2393
+ child, cookie = shortcut.GetFirstChild(shortcut)
2394
+
2395
+ while child:
2396
+ child.ToMenuItem(menuBar)
2397
+ MenuItemSet(child, menuBar)
2398
+ child, cookie = shortcut.GetNextChild(shortcut, cookie)
2399
+
2400
+ manager = self.GetShortcutManager()
2401
+ menuBar = topWindow.GetMenuBar()
2402
+
2403
+ MenuItemSet(manager, menuBar)
2404
+
2405
+
2406
+ def FromAcceleratorTable(self, accelTable):
2407
+ """
2408
+ Builds the entire shortcut hierarchy starting from a modified version of a :class:`AcceleratorTable`.
2409
+
2410
+ :param `accelTable`: a modified version of :class:`AcceleratorTable`, is a list of tuples (4 elements per tuple),
2411
+ populated like this::
2412
+
2413
+ accelTable = []
2414
+
2415
+ # Every tuple is defined in this way:
2416
+
2417
+ for label, flags, keyCode, cmdID in my_accelerators:
2418
+ # label: the string used to show the accelerator into the ShortcutEditor dialog
2419
+ # flags: a bitmask of wx.ACCEL_ALT, wx.ACCEL_SHIFT, wx.ACCEL_CTRL, wx.ACCEL_CMD,
2420
+ # or wx.ACCEL_NORMAL used to specify which modifier keys are held down
2421
+ # keyCode: the keycode to be detected (i.e., ord('b'), wx.WXK_F10, etc...)
2422
+ # cmdID: the menu or control command ID to use for the accelerator event.
2423
+
2424
+ accel_tuple = (label, flags, keyCode, cmdID)
2425
+ accelTable.append(accel_tuple)
2426
+
2427
+ """
2428
+
2429
+ parentShortcut = Shortcut(_('Accelerators'))
2430
+
2431
+ parentShortcut.topMenu = True
2432
+ self.manager.AppendItem(parentShortcut)
2433
+
2434
+ for text, modifier, accel, ids in accelTable:
2435
+ modifier = ACCELERATORS[modifier]
2436
+ if accel in KEYMAP:
2437
+ accel = KEYMAP[accel]
2438
+ else:
2439
+ accel = chr(accel)
2440
+
2441
+ shortcut = (modifier and ['%s+%s'%(modifier, accel)] or [accel])[0]
2442
+ shortcutItem = Shortcut(text, shortcut, accelId=ids)
2443
+ parentShortcut.AppendItem(shortcutItem)
2444
+
2445
+
2446
+ def ToAcceleratorTable(self, window):
2447
+ """
2448
+ Dumps the entire shortcut hierarchy (for shortcuts associated with a :class:`AcceleratorTable`), into
2449
+ a :class:`AcceleratorTable`. This method **does** rebuild the :class:`AcceleratorTable` and sets it back
2450
+ to the input `window`.
2451
+
2452
+ :param `window`: an instance of :class:`wx.Window`, to which the new :class:`AcceleratorTable` should be set.
2453
+ """
2454
+
2455
+ def AccelItemSet(shortcut, table):
2456
+
2457
+ child, cookie = shortcut.GetFirstChild(shortcut)
2458
+
2459
+ while child:
2460
+ child.ToAcceleratorItem(table)
2461
+ table = AccelItemSet(child, table)
2462
+ child, cookie = shortcut.GetNextChild(shortcut, cookie)
2463
+
2464
+ return table
2465
+
2466
+ manager = self.GetShortcutManager()
2467
+ table = AccelItemSet(manager, table=[])
2468
+
2469
+ window.SetAcceleratorTable(wx.AcceleratorTable(table))
2470
+
2471
+
2472
+ def SetColumnWidths(self):
2473
+ """
2474
+ Sets the :class:`ListShortcut` columns widths to acceptable and eye-pleasing
2475
+ numbers (in pixels).
2476
+ """
2477
+
2478
+ total_width = 0
2479
+ for col in range(self.listShortcut.GetColumnCount()):
2480
+ self.listShortcut.SetColumnWidth(col, wx.LIST_AUTOSIZE)
2481
+ width = self.listShortcut.GetColumnWidth(col)
2482
+
2483
+ if col == 0:
2484
+ width += 20
2485
+ elif col == 1:
2486
+ width += 5
2487
+ else:
2488
+ width = min(width, 200)
2489
+
2490
+ width = max(50, width)
2491
+ self.listShortcut.SetColumnWidth(col, width)
2492
+ total_width += width
2493
+
2494
+ self.listShortcut.GetMainWindow()._lineHeight += 5
2495
+ dialogHeight = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)/2
2496
+
2497
+ self.SetSize((total_width+60, dialogHeight))
2498
+
2499
+ self.Center()
2500
+
2501
+
2502
+ def OnSetFilter(self, event=None):
2503
+ """
2504
+ Handles the ``wx.EVT_TEXT`` event for :class:`ShortcutEditor`.
2505
+
2506
+ :param `event`: if not ``None``, an instance of :class:`KeyEvent`.
2507
+ """
2508
+
2509
+ if event:
2510
+ event.Skip()
2511
+
2512
+ filter = self.searchText.GetValue()
2513
+ filter = filter.lower().strip()
2514
+
2515
+ self.listShortcut.SetFilter(filter)
2516
+
2517
+
2518
+ def OnClearFilter(self, event):
2519
+ """
2520
+ Handles the ``wx.EVT_BUTTON`` event for :class:`ShortcutEditor` when the user clears the
2521
+ label filter at the top of the user interface.
2522
+
2523
+ :param `event`: an instance of :class:`CommandEvent`.
2524
+ """
2525
+
2526
+ self.searchText.SetValue('')
2527
+
2528
+
2529
+ def OnRestoreDefaults(self, event):
2530
+ """
2531
+ Handles the ``wx.EVT_BUTTON`` event for :class:`ShortcutEditor` when the user restores the
2532
+ original shortcuts.
2533
+
2534
+ :param `event`: an instance of :class:`CommandEvent`.
2535
+ """
2536
+
2537
+ self.manager.RestoreDefaults()
2538
+ self.listShortcut.RecreateTree()
2539
+
2540
+
2541
+ def OnHTMLHelp(self, event):
2542
+ """
2543
+ Handles the ``wx.EVT_BUTTON`` event for :class:`ShortcutEditor` when the user presses the ``Help``
2544
+ button.
2545
+
2546
+ :param `event`: an instance of :class:`CommandEvent`.
2547
+
2548
+ .. note::
2549
+
2550
+ By default, this method launches a :class:`html.HtmlWindow` containing the default
2551
+ HTML help file. If you wish to load another help file, you should call :meth:`~ShortcutEditor.SetHTMLHelpFile`
2552
+ with another input HTML file.
2553
+
2554
+ """
2555
+
2556
+ if self.htmlWindow:
2557
+ self.htmlWindow.Show()
2558
+ self.htmlWindow.Restore()
2559
+ self.htmlWindow.Raise()
2560
+ return
2561
+
2562
+ self.htmlWindow = HTMLHelpWindow(self, self.htmlFile)
2563
+
2564
+
2565
+ def GetShortcutManager(self):
2566
+ """ Returns the root :class:`Shortcut` containing the whole shortcut hierarchy. """
2567
+
2568
+ return self.manager
2569
+
2570
+
2571
+ def SetHTMLHelpFile(self, htmlFile):
2572
+ """
2573
+ Sets a new HTML help file (a valid html file) to be loaded when the user seeks
2574
+ for an explanation on how the UI works.
2575
+
2576
+ :param string `htmlFile`: a valid HTML file.
2577
+ """
2578
+
2579
+ if not os.path.isfile(htmlFile):
2580
+ raise Exception('Invalid HTML help file passed to ShortcutEditor')
2581
+
2582
+ self.htmlFile = htmlFile
2583
+
2584
+ if self.htmlWindow is not None:
2585
+ self.htmlWindow.htmlFile = htmlFile
2586
+ self.htmlWindow.LoadFile(self.htmlFile)
2587
+
2588
+
2589
+ def PreShow(self):
2590
+ """ Does some more common initialization before showing :class:`ShortcutEditor`. """
2591
+
2592
+ self.listShortcut.MakeImageList()
2593
+ self.listShortcut.RecreateTree()
2594
+
2595
+ self.SetColumnWidths()
2596
+
2597
+
2598
+ def ShowModal(self):
2599
+ """
2600
+ Shows the :class:`ShortcutEditor` dialog in an application-modal way.
2601
+
2602
+ Program flow does not return until the dialog has been dismissed with `EndModal`.
2603
+
2604
+ :return: The value set with :meth:`~Dialog.SetReturnCode`.
2605
+
2606
+ .. note::
2607
+
2608
+ Notice that it is possible to call :meth:`~ShortcutEditor.ShowModal` for a dialog which had been
2609
+ previously shown with :meth:`~ShortcutEditor.Show`, this allows to make an existing modeless dialog
2610
+ modal. However :meth:`~ShortcutEditor.ShowModal` can't be called twice without intervening `EndModal` calls.
2611
+
2612
+
2613
+ .. note::
2614
+
2615
+ Note that this function creates a temporary event loop which takes precedence
2616
+ over the application's main event loop (see :class:`EventLoopBase`) and which is
2617
+ destroyed when the dialog is dismissed. This also results in a call to
2618
+ :meth:`AppConsole.ProcessPendingEvents` ().
2619
+
2620
+ """
2621
+
2622
+ self.PreShow()
2623
+ return wx.Dialog.ShowModal(self)
2624
+
2625
+
2626
+ def Show(self, show=True):
2627
+ """
2628
+ Hides or shows the :class:`ShortcutEditor` dialog.
2629
+
2630
+ The preferred way of dismissing a modal dialog is to use `EndModal`.
2631
+
2632
+ :param bool `show`: if ``True``, the dialog box is shown and brought to the front,
2633
+ otherwise the box is hidden. If ``False`` and the dialog is modal, control is
2634
+ returned to the calling program.
2635
+
2636
+ :note: Reimplemented from :class:`wx.Window`.
2637
+ """
2638
+
2639
+ self.PreShow()
2640
+ wx.Dialog.Show(self, show)
2641
+
2642
+