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
wx/lib/ogl/basic.py ADDED
@@ -0,0 +1,3989 @@
1
+ # -*- coding: utf-8 -*-
2
+ #----------------------------------------------------------------------------
3
+ # Name: basic.py
4
+ # Purpose: The basic OGL shapes
5
+ #
6
+ # Author: Pierre Hjälm (from C++ original by Julian Smart)
7
+ #
8
+ # Created: 2004-05-08
9
+ # Copyright: (c) 2004 Pierre Hjälm - 1998 Julian Smart
10
+ # Licence: wxWindows license
11
+ # Tags: phoenix-port, unittest, py3-port, documented
12
+ #----------------------------------------------------------------------------
13
+ """
14
+ The basic shapes for OGL
15
+ """
16
+
17
+ import wx
18
+ import math
19
+
20
+ from .oglmisc import *
21
+
22
+ DragOffsetX = 0.0
23
+ DragOffsetY = 0.0
24
+
25
+
26
+ def OGLInitialize():
27
+ """Initialize OGL.
28
+
29
+ :note: This creates some pens and brushes that the OGL library uses.
30
+ It should be called after the app object has been created, but
31
+ before OGL is used.
32
+ """
33
+ global WhiteBackgroundPen, WhiteBackgroundBrush, TransparentPen
34
+ global BlackForegroundPen, NormalFont
35
+
36
+ WhiteBackgroundPen = wx.Pen(wx.WHITE, 1, wx.PENSTYLE_SOLID)
37
+ WhiteBackgroundBrush = wx.Brush(wx.WHITE, wx.BRUSHSTYLE_SOLID)
38
+
39
+ TransparentPen = wx.Pen(wx.WHITE, 1, wx.PENSTYLE_TRANSPARENT)
40
+ BlackForegroundPen = wx.Pen(wx.BLACK, 1, wx.PENSTYLE_SOLID)
41
+
42
+ NormalFont = wx.Font(10, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
43
+
44
+
45
+ def OGLCleanUp():
46
+ """not implemented???"""
47
+ pass
48
+
49
+
50
+ class ShapeTextLine(object):
51
+ """The :class:`ShapeTextLine` class."""
52
+ def __init__(self, the_x, the_y, the_line):
53
+ """
54
+ Default class constructor.
55
+
56
+ :param int `the_x`: the x position
57
+ :param int `the_y`: the y position
58
+ :param str `the_line`: the text
59
+
60
+ """
61
+ self._x = the_x
62
+ self._y = the_y
63
+ self._line = the_line
64
+
65
+ def GetX(self):
66
+ """Get the x position."""
67
+ return self._x
68
+
69
+ def GetY(self):
70
+ """Get the y position."""
71
+ return self._y
72
+
73
+ def SetX(self, x):
74
+ """
75
+ Set the x position.
76
+
77
+ :param int `x`: the x position
78
+
79
+ """
80
+ self._x = x
81
+
82
+ def SetY(self, y):
83
+ """
84
+ Set the y position.
85
+
86
+ :param int `y`: the x position
87
+
88
+ """
89
+ self._y = y
90
+
91
+ def SetText(self, text):
92
+ """
93
+ Set the text.
94
+
95
+ :param str `text`: the text
96
+
97
+ """
98
+ self._line = text
99
+
100
+ def GetText(self):
101
+ """Get the text."""
102
+ return self._line
103
+
104
+
105
+ class ShapeEvtHandler(object):
106
+ """The :class:`ShapeEvtHandler` class."""
107
+ def __init__(self, prev = None, shape = None):
108
+ """
109
+ Default class constructor.
110
+
111
+ :param `pref`: the previous event handler, an instance of
112
+ :class:`ShapeEvtHandler` ???
113
+ :param `shape`: the shape, an instance of :class:`Shape`
114
+
115
+ """
116
+ self._previousHandler = prev
117
+ self._handlerShape = shape
118
+
119
+ def SetShape(self, sh):
120
+ """
121
+ Set associated shape
122
+
123
+ :param `sh`: the shape, an instance of :class:`Shape`
124
+
125
+ """
126
+ self._handlerShape = sh
127
+
128
+ def GetShape(self):
129
+ """Get associated shape."""
130
+ return self._handlerShape
131
+
132
+ def SetPreviousHandler(self, handler):
133
+ """
134
+ Set previous event handler.
135
+
136
+ :param `handler`: the previous handler, an instance of
137
+ :class:`ShapeEvtHandler` ???
138
+
139
+ """
140
+ self._previousHandler = handler
141
+
142
+ def GetPreviousHandler(self):
143
+ """Get previous event handler."""
144
+ return self._previousHandler
145
+
146
+ def OnDelete(self):
147
+ """The delete handler."""
148
+ if self!=self.GetShape():
149
+ del self
150
+
151
+ def OnDraw(self, dc):
152
+ """The draw handler."""
153
+ if self._previousHandler:
154
+ self._previousHandler.OnDraw(dc)
155
+
156
+ def OnMoveLinks(self, dc):
157
+ """The move links handler."""
158
+ if self._previousHandler:
159
+ self._previousHandler.OnMoveLinks(dc)
160
+
161
+ def OnMoveLink(self, dc, moveControlPoints = True):
162
+ """The move link handler."""
163
+ if self._previousHandler:
164
+ self._previousHandler.OnMoveLink(dc, moveControlPoints)
165
+
166
+ def OnDrawContents(self, dc):
167
+ """The draw contents handler."""
168
+ if self._previousHandler:
169
+ self._previousHandler.OnDrawContents(dc)
170
+
171
+ def OnDrawBranches(self, dc, erase = False):
172
+ """The draw branches handler."""
173
+ if self._previousHandler:
174
+ self._previousHandler.OnDrawBranches(dc, erase = erase)
175
+
176
+ def OnSize(self, x, y):
177
+ """The size handler."""
178
+ if self._previousHandler:
179
+ self._previousHandler.OnSize(x, y)
180
+
181
+ def OnMovePre(self, dc, x, y, old_x, old_y, display = True):
182
+ """The pre move handler."""
183
+ if self._previousHandler:
184
+ return self._previousHandler.OnMovePre(dc, x, y, old_x, old_y, display)
185
+ else:
186
+ return True
187
+
188
+ def OnMovePost(self, dc, x, y, old_x, old_y, display = True):
189
+ """The post move handler."""
190
+ if self._previousHandler:
191
+ return self._previousHandler.OnMovePost(dc, x, y, old_x, old_y, display)
192
+ else:
193
+ return True
194
+
195
+ def OnErase(self, dc):
196
+ """The erase handler."""
197
+ if self._previousHandler:
198
+ self._previousHandler.OnErase(dc)
199
+
200
+ def OnEraseContents(self, dc):
201
+ """The erase contents handler."""
202
+ if self._previousHandler:
203
+ self._previousHandler.OnEraseContents(dc)
204
+
205
+ def OnHighlight(self, dc):
206
+ """The highlight handler."""
207
+ if self._previousHandler:
208
+ self._previousHandler.OnHighlight(dc)
209
+
210
+ def OnLeftClick(self, x, y, keys, attachment):
211
+ """The left click handler."""
212
+ if self._previousHandler:
213
+ self._previousHandler.OnLeftClick(x, y, keys, attachment)
214
+
215
+ def OnLeftDoubleClick(self, x, y, keys = 0, attachment = 0):
216
+ """The left double click handler."""
217
+ if self._previousHandler:
218
+ self._previousHandler.OnLeftDoubleClick(x, y, keys, attachment)
219
+
220
+ def OnRightClick(self, x, y, keys = 0, attachment = 0):
221
+ """The right click handler."""
222
+ if self._previousHandler:
223
+ self._previousHandler.OnRightClick(x, y, keys, attachment)
224
+
225
+ def OnDragLeft(self, draw, x, y, keys = 0, attachment = 0):
226
+ """The drag left handler."""
227
+ if self._previousHandler:
228
+ self._previousHandler.OnDragLeft(draw, x, y, keys, attachment)
229
+
230
+ def OnBeginDragLeft(self, x, y, keys = 0, attachment = 0):
231
+ """The begin drag left handler."""
232
+ if self._previousHandler:
233
+ self._previousHandler.OnBeginDragLeft(x, y, keys, attachment)
234
+
235
+ def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
236
+ """The end drag left handler."""
237
+ if self._previousHandler:
238
+ self._previousHandler.OnEndDragLeft(x, y, keys, attachment)
239
+
240
+ def OnDragRight(self, draw, x, y, keys = 0, attachment = 0):
241
+ """The drag right handler."""
242
+ if self._previousHandler:
243
+ self._previousHandler.OnDragRight(draw, x, y, keys, attachment)
244
+
245
+ def OnBeginDragRight(self, x, y, keys = 0, attachment = 0):
246
+ """The begin drag right handler."""
247
+ if self._previousHandler:
248
+ self._previousHandler.OnBeginDragRight(x, y, keys, attachment)
249
+
250
+ def OnEndDragRight(self, x, y, keys = 0, attachment = 0):
251
+ """The end drag right handler."""
252
+ if self._previousHandler:
253
+ self._previousHandler.OnEndDragRight(x, y, keys, attachment)
254
+
255
+ # Control points ('handles') redirect control to the actual shape,
256
+ # to make it easier to override sizing behaviour.
257
+ def OnSizingDragLeft(self, pt, draw, x, y, keys = 0, attachment = 0):
258
+ """The sizing drag left handler."""
259
+ if self._previousHandler:
260
+ self._previousHandler.OnSizingDragLeft(pt, draw, x, y, keys, attachment)
261
+
262
+ def OnSizingBeginDragLeft(self, pt, x, y, keys = 0, attachment = 0):
263
+ """The sizing begin drag left handler."""
264
+ if self._previousHandler:
265
+ self._previousHandler.OnSizingBeginDragLeft(pt, x, y, keys, attachment)
266
+
267
+ def OnSizingEndDragLeft(self, pt, x, y, keys = 0, attachment = 0):
268
+ """The sizing end drag left handler."""
269
+ if self._previousHandler:
270
+ self._previousHandler.OnSizingEndDragLeft(pt, x, y, keys, attachment)
271
+
272
+ def OnBeginSize(self, w, h):
273
+ """not implemented???"""
274
+ pass
275
+
276
+ def OnEndSize(self, w, h):
277
+ """not implemented???"""
278
+ pass
279
+
280
+ def OnDrawOutline(self, dc, x, y, w, h):
281
+ """The drag outline handler."""
282
+ if self._previousHandler:
283
+ self._previousHandler.OnDrawOutline(dc, x, y, w, h)
284
+
285
+ def OnDrawControlPoints(self, dc):
286
+ """The draw control points handler."""
287
+ if self._previousHandler:
288
+ self._previousHandler.OnDrawControlPoints(dc)
289
+
290
+ def OnEraseControlPoints(self, dc):
291
+ """The erase control points handler."""
292
+ if self._previousHandler:
293
+ self._previousHandler.OnEraseControlPoints(dc)
294
+
295
+ # Can override this to prevent or intercept line reordering.
296
+ def OnChangeAttachment(self, attachment, line, ordering):
297
+ """The change attachment handler."""
298
+ if self._previousHandler:
299
+ self._previousHandler.OnChangeAttachment(attachment, line, ordering)
300
+
301
+
302
+ class Shape(ShapeEvtHandler):
303
+ """
304
+ The :class:`Shape` is the base class for OGL shapes.
305
+
306
+ The :class:`Shape` is the top-level, abstract object that all other objects
307
+ are derived from. All common functionality is represented by :class:`Shape`
308
+ members, and overridden members that appear in derived classes and have
309
+ behaviour as documented for :class:`Shape`, are not documented separately.
310
+ """
311
+ GraphicsInSizeToContents = False
312
+
313
+ def __init__(self, canvas = None):
314
+ """
315
+ Default class constructor.
316
+
317
+ :param `canvas`: an instance of :class:`~lib.ogl.Canvas`
318
+
319
+ """
320
+ ShapeEvtHandler.__init__(self)
321
+
322
+ self._eventHandler = self
323
+ self.SetShape(self)
324
+ self._id = 0
325
+ self._formatted = False
326
+ self._canvas = canvas
327
+ self._xpos = 0.0
328
+ self._ypos = 0.0
329
+ self._pen = BlackForegroundPen
330
+ self._brush = wx.WHITE_BRUSH
331
+ self._font = NormalFont
332
+ self._textColour = wx.BLACK
333
+ self._textColourName = wx.BLACK
334
+ self._visible = False
335
+ self._selected = False
336
+ self._attachmentMode = ATTACHMENT_MODE_NONE
337
+ self._spaceAttachments = True
338
+ self._disableLabel = False
339
+ self._fixedWidth = False
340
+ self._fixedHeight = False
341
+ self._drawHandles = True
342
+ self._sensitivity = OP_ALL
343
+ self._draggable = True
344
+ self._parent = None
345
+ self._formatMode = FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT
346
+ self._shadowMode = SHADOW_NONE
347
+ self._shadowOffsetX = 6
348
+ self._shadowOffsetY = 6
349
+ self._shadowBrush = wx.BLACK_BRUSH
350
+ self._textMarginX = 5
351
+ self._textMarginY = 5
352
+ self._regionName = "0"
353
+ self._centreResize = True
354
+ self._maintainAspectRatio = False
355
+ self._highlighted = False
356
+ self._rotation = 0.0
357
+ self._branchNeckLength = 10
358
+ self._branchStemLength = 10
359
+ self._branchSpacing = 10
360
+ self._branchStyle = BRANCHING_ATTACHMENT_NORMAL
361
+
362
+ self._regions = []
363
+ self._lines = []
364
+ self._controlPoints = []
365
+ self._attachmentPoints = []
366
+ self._text = []
367
+ self._children = []
368
+
369
+ # Set up a default region. Much of the above will be put into
370
+ # the region eventually (the duplication is for compatibility)
371
+ region = ShapeRegion()
372
+ region.SetName("0")
373
+ region.SetFont(NormalFont)
374
+ region.SetFormatMode(FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT)
375
+ region.SetColour("BLACK")
376
+ self._regions.append(region)
377
+
378
+ def __str__(self):
379
+ return "<%s.%s>" % (self.__class__.__module__, self.__class__.__name__)
380
+
381
+ def GetClassName(self):
382
+ return str(self.__class__).split(".")[-1][:-2]
383
+
384
+ def Delete(self):
385
+ """
386
+ Fully disconnect this shape from parents, children, the
387
+ canvas, etc.
388
+ """
389
+ if self._parent:
390
+ self._parent.GetChildren().remove(self)
391
+
392
+ for child in self.GetChildren():
393
+ child.Delete()
394
+
395
+ self.ClearText()
396
+ self.ClearRegions()
397
+ self.ClearAttachments()
398
+
399
+ self._handlerShape = None
400
+
401
+ if self._canvas:
402
+ self.RemoveFromCanvas(self._canvas)
403
+
404
+ if self.GetEventHandler():
405
+ self.GetEventHandler().OnDelete()
406
+ self._eventHandler = None
407
+
408
+ def Draggable(self):
409
+ """
410
+ Is shape draggable?
411
+
412
+ :returns: `True` if the shape may be dragged by the user.
413
+ """
414
+ return True
415
+
416
+ def SetShape(self, sh):
417
+ """Set shape ???
418
+
419
+ :param `sh`: an instance of :class:`Shape`
420
+
421
+ """
422
+ self._handlerShape = sh
423
+
424
+ def GetCanvas(self):
425
+ """Get the internal canvas."""
426
+ return self._canvas
427
+
428
+ def GetBranchStyle(self):
429
+ """Get the branch style."""
430
+ return self._branchStyle
431
+
432
+ def GetRotation(self):
433
+ """Return the angle of rotation in radians."""
434
+ return self._rotation
435
+
436
+ def SetRotation(self, rotation):
437
+ """Set rotation
438
+
439
+ :param int `rotation`: rotation
440
+
441
+ """
442
+ self._rotation = rotation
443
+
444
+ def SetHighlight(self, hi, recurse = False):
445
+ """Set the highlight for a shape. Shape highlighting is unimplemented."""
446
+ self._highlighted = hi
447
+ if recurse:
448
+ for shape in self._children:
449
+ shape.SetHighlight(hi, recurse)
450
+
451
+ def SetSensitivityFilter(self, sens = OP_ALL, recursive = False):
452
+ """
453
+ Set the shape to be sensitive or insensitive to specific mouse
454
+ operations.
455
+
456
+ :param `sens`: is a bitlist of the following:
457
+
458
+ ========================== ===================
459
+ Mouse operation Description
460
+ ========================== ===================
461
+ `OP_CLICK_LEFT` left clicked
462
+ `OP_CLICK_RIGHT` right clicked
463
+ `OP_DRAG_LEFT` left drag
464
+ `OP_DRAG_RIGHT` right drag
465
+ `OP_ALL` all of the above
466
+ ========================== ===================
467
+
468
+ :param `recursive`: if `True` recurse through children
469
+
470
+ """
471
+ self._draggable = sens & OP_DRAG_LEFT
472
+
473
+ self._sensitivity = sens
474
+ if recursive:
475
+ for shape in self._children:
476
+ shape.SetSensitivityFilter(sens, True)
477
+
478
+ def SetDraggable(self, drag, recursive = False):
479
+ """Set the shape to be draggable or not draggable.
480
+
481
+ :param `drag`: if `True` make shape draggable
482
+ :param `recursive`: if `True` recurse through children
483
+
484
+ """
485
+ self._draggable = drag
486
+ if drag:
487
+ self._sensitivity |= OP_DRAG_LEFT
488
+ elif self._sensitivity & OP_DRAG_LEFT:
489
+ self._sensitivity -= OP_DRAG_LEFT
490
+
491
+ if recursive:
492
+ for shape in self._children:
493
+ shape.SetDraggable(drag, True)
494
+
495
+ def SetDrawHandles(self, drawH):
496
+ """
497
+ Set the drawHandles flag for this shape and all descendants.
498
+
499
+ :param `drawH`: if `True` (the default), any handles (control points)
500
+ will be drawn. Otherwise, the handles will not be drawn.
501
+
502
+ """
503
+ self._drawHandles = drawH
504
+ for shape in self._children:
505
+ shape.SetDrawHandles(drawH)
506
+
507
+ def SetShadowMode(self, mode, redraw = False):
508
+ """
509
+ Set the shadow mode (whether a shadow is drawn or not).
510
+
511
+ :param `mode`: can be one of the following:
512
+
513
+ =============================== ===========================
514
+ Shadow mode Description
515
+ =============================== ===========================
516
+ `SHADOW_NONE` No shadow (the default)
517
+ `SHADOW_LEFT` Shadow on the left side
518
+ `SHADOW_RIGHT` Shadow on the right side
519
+ =============================== ===========================
520
+
521
+ """
522
+ if redraw and self.GetCanvas():
523
+ dc = wx.MemoryDC()
524
+ dc.SelectObject(self.GetCanvas().GetBuffer())
525
+ self.GetCanvas().PrepareDC(dc)
526
+ self.Erase(dc)
527
+ self._shadowMode = mode
528
+ self.Draw(dc)
529
+ else:
530
+ self._shadowMode = mode
531
+
532
+ def GetShadowMode(self):
533
+ """Get the current shadow mode setting."""
534
+ return self._shadowMode
535
+
536
+ def SetCanvas(self, theCanvas):
537
+ """
538
+ Set the canvas, identical to Shape.Attach.
539
+
540
+ :param `theCanvas`: an instance of :class:`~lib.ogl.Canvas`
541
+
542
+ """
543
+ self._canvas = theCanvas
544
+ for shape in self._children:
545
+ shape.SetCanvas(theCanvas)
546
+
547
+ def AddToCanvas(self, theCanvas, addAfter = None):
548
+ """
549
+ Add the shape to the canvas's shape list.
550
+
551
+ :param `theCanvas`: an instance of :class:`~lib.ogl.Canvas`
552
+ :param `addAfter`: if non-NULL, will add the shape after this shape
553
+
554
+ """
555
+ theCanvas.AddShape(self, addAfter)
556
+
557
+ lastImage = self
558
+ for object in self._children:
559
+ object.AddToCanvas(theCanvas, lastImage)
560
+ lastImage = object
561
+
562
+ def InsertInCanvas(self, theCanvas):
563
+ """
564
+ Insert the shape at the front of the shape list of canvas.
565
+
566
+ :param `theCanvas`: an instance of :class:`~lib.ogl.Canvas`
567
+
568
+ """
569
+ theCanvas.InsertShape(self)
570
+
571
+ lastImage = self
572
+ for object in self._children:
573
+ object.AddToCanvas(theCanvas, lastImage)
574
+ lastImage = object
575
+
576
+ def RemoveFromCanvas(self, theCanvas):
577
+ """
578
+ Remove the shape from the canvas.
579
+
580
+ :param `theCanvas`: an instance of :class:`~lib.ogl.Canvas`
581
+
582
+ """
583
+ if self.Selected():
584
+ self.Select(False)
585
+
586
+ self._canvas = None
587
+ theCanvas.RemoveShape(self)
588
+ for object in self._children:
589
+ object.RemoveFromCanvas(theCanvas)
590
+
591
+ def ClearAttachments(self):
592
+ """Clear internal custom attachment point shapes (of class
593
+ :class:`~lib.ogl.AttachmentPoint`)
594
+ """
595
+ self._attachmentPoints = []
596
+
597
+ def ClearText(self, regionId = 0):
598
+ """
599
+ Clear the text from the specified text region.
600
+
601
+ :param `regionId`: the region identifier
602
+
603
+ """
604
+ if regionId == 0:
605
+ self._text = ""
606
+ if regionId < len(self._regions):
607
+ self._regions[regionId].ClearText()
608
+
609
+ def ClearRegions(self):
610
+ """Clear the ShapeRegions from the shape."""
611
+ self._regions = []
612
+
613
+ def AddRegion(self, region):
614
+ """Add a region to the shape."""
615
+ self._regions.append(region)
616
+
617
+ def SetDefaultRegionSize(self):
618
+ """Set the default region to be consistent with the shape size."""
619
+ if not self._regions:
620
+ return
621
+ w, h = self.GetBoundingBoxMax()
622
+ self._regions[0].SetSize(w, h)
623
+
624
+ def HitTest(self, x, y):
625
+ """
626
+ Given a point on a canvas, returns `True` if the point was on the
627
+ shape, and returns the nearest attachment point and distance from
628
+ the given point and target.
629
+
630
+ :param `x`: the x position
631
+ :param `y`: the y position
632
+
633
+ """
634
+ width, height = self.GetBoundingBoxMax()
635
+ if abs(width) < 4:
636
+ width = 4.0
637
+ if abs(height) < 4:
638
+ height = 4.0
639
+
640
+ width += 4 # Allowance for inaccurate mousing
641
+ height += 4
642
+
643
+ left = self._xpos - width / 2.0
644
+ top = self._ypos - height / 2.0
645
+ right = self._xpos + width / 2.0
646
+ bottom = self._ypos + height / 2.0
647
+
648
+ nearest_attachment = 0
649
+
650
+ # If within the bounding box, check the attachment points
651
+ # within the object.
652
+ if x >= left and x <= right and y >= top and y <= bottom:
653
+ n = self.GetNumberOfAttachments()
654
+ nearest = 999999
655
+
656
+ # GetAttachmentPosition[Edge] takes a logical attachment position,
657
+ # i.e. if it's rotated through 90%, position 0 is East-facing.
658
+
659
+ for i in range(n):
660
+ e = self.GetAttachmentPositionEdge(i)
661
+ if e:
662
+ xp, yp = e
663
+ l = math.sqrt(((xp - x) * (xp - x)) + (yp - y) * (yp - y))
664
+ if l < nearest:
665
+ nearest = l
666
+ nearest_attachment = i
667
+
668
+ return nearest_attachment, nearest
669
+ return False
670
+
671
+ # Format a text string according to the region size, adding
672
+ # strings with positions to region text list
673
+
674
+ def FormatText(self, dc, s, i = 0):
675
+ """
676
+ Reformat the given text region; defaults to formatting the
677
+ default region.
678
+
679
+ :param `dc`: the device contexr
680
+ :param str `s`: the text string
681
+ :param int `i`: the region identifier
682
+
683
+ """
684
+ self.ClearText(i)
685
+
686
+ if not self._regions:
687
+ return
688
+
689
+ if i >= len(self._regions):
690
+ return
691
+
692
+ region = self._regions[i]
693
+ region._regionText = s
694
+ dc.SetFont(region.GetFont())
695
+
696
+ w, h = region.GetSize()
697
+
698
+ stringList = FormatText(dc, s, (w - 2 * self._textMarginX), (h - 2 * self._textMarginY), region.GetFormatMode())
699
+ for s in stringList:
700
+ line = ShapeTextLine(0.0, 0.0, s)
701
+ region.GetFormattedText().append(line)
702
+
703
+ actualW = w
704
+ actualH = h
705
+ # Don't try to resize an object with more than one image (this
706
+ # case should be dealt with by overridden handlers)
707
+ if (region.GetFormatMode() & FORMAT_SIZE_TO_CONTENTS) and \
708
+ len(region.GetFormattedText()) and \
709
+ len(self._regions) == 1 and \
710
+ not Shape.GraphicsInSizeToContents:
711
+
712
+ actualW, actualH = GetCentredTextExtent(dc, region.GetFormattedText())
713
+ if actualW + 2 * self._textMarginX != w or actualH + 2 * self._textMarginY != h:
714
+ # If we are a descendant of a composite, must make sure
715
+ # the composite gets resized properly
716
+
717
+ topAncestor = self.GetTopAncestor()
718
+ if topAncestor != self:
719
+ Shape.GraphicsInSizeToContents = True
720
+
721
+ composite = topAncestor
722
+ composite.Erase(dc)
723
+ self.SetSize(actualW + 2 * self._textMarginX, actualH + 2 * self._textMarginY)
724
+ self.Move(dc, self._xpos, self._ypos)
725
+ composite.CalculateSize()
726
+ if composite.Selected():
727
+ composite.DeleteControlPoints(dc)
728
+ composite.MakeControlPoints()
729
+ composite.MakeMandatoryControlPoints()
730
+ # Where infinite recursion might happen if we didn't stop it
731
+ composite.Draw(dc)
732
+ Shape.GraphicsInSizeToContents = False
733
+ else:
734
+ self.Erase(dc)
735
+
736
+ self.SetSize(actualW + 2 * self._textMarginX, actualH + 2 * self._textMarginY)
737
+ self.Move(dc, self._xpos, self._ypos)
738
+ self.EraseContents(dc)
739
+ CentreText(dc, region.GetFormattedText(), self._xpos, self._ypos, actualW - 2 * self._textMarginX, actualH - 2 * self._textMarginY, region.GetFormatMode())
740
+ self._formatted = True
741
+
742
+ def Recentre(self, dc):
743
+ """
744
+ Recentre (or other formatting) all the text regions for this shape.
745
+ """
746
+ w, h = self.GetBoundingBoxMin()
747
+ for region in self._regions:
748
+ CentreText(dc, region.GetFormattedText(), self._xpos, self._ypos, w - 2 * self._textMarginX, h - 2 * self._textMarginY, region.GetFormatMode())
749
+
750
+ def GetPerimeterPoint(self, x1, y1, x2, y2):
751
+ """
752
+ Get the point at which the line from (x1, y1) to (x2, y2) hits
753
+ the shape.
754
+
755
+ :param `x1`: the x1 position
756
+ :param `y1`: the y1 position
757
+ :param `x2`: the x2 position
758
+ :param `y2`: the y2 position
759
+
760
+ :returns: `False` if the line doesn't hit the perimeter.
761
+
762
+ """
763
+ return False
764
+
765
+ def SetPen(self, the_pen):
766
+ """Set the pen for drawing the shape's outline."""
767
+ self._pen = the_pen
768
+
769
+ def SetBrush(self, the_brush):
770
+ """Set the brush for filling the shape's shape."""
771
+ self._brush = the_brush
772
+
773
+ # Get the top - most (non-division) ancestor, or self
774
+ def GetTopAncestor(self):
775
+ """
776
+ Return the top-most ancestor of this shape (the root of
777
+ the composite).
778
+ """
779
+ if not self.GetParent():
780
+ return self
781
+
782
+ if isinstance(self.GetParent(), DivisionShape):
783
+ return self
784
+ return self.GetParent().GetTopAncestor()
785
+
786
+ # Region functions
787
+ def SetFont(self, the_font, regionId = 0):
788
+ """
789
+ Set the font for the specified text region.
790
+
791
+ :param `the_font`: an instance of :class:`wx.Font` ???
792
+ :param `regionId`: the region identifier
793
+
794
+ """
795
+ self._font = the_font
796
+ if regionId < len(self._regions):
797
+ self._regions[regionId].SetFont(the_font)
798
+
799
+ def GetFont(self, regionId = 0):
800
+ """
801
+ Get the font for the specified text region.
802
+
803
+ :param `regionId`: the region identifier
804
+
805
+ """
806
+ if regionId >= len(self._regions):
807
+ return None
808
+ return self._regions[regionId].GetFont()
809
+
810
+ def SetFormatMode(self, mode, regionId = 0):
811
+ """
812
+ Set the format mode of the region.
813
+
814
+ :param `mode`: can be a bit list of the following
815
+
816
+ ============================== ==============================
817
+ Format mode Description
818
+ ============================== ==============================
819
+ `FORMAT_NONE` No formatting
820
+ `FORMAT_CENTRE_HORIZ` Horizontal centring
821
+ `FORMAT_CENTRE_VERT` Vertical centring
822
+ ============================== ==============================
823
+
824
+ :param `regionId`: the region identifier, default=0
825
+
826
+ """
827
+ if regionId < len(self._regions):
828
+ self._regions[regionId].SetFormatMode(mode)
829
+
830
+ def GetFormatMode(self, regionId = 0):
831
+ """
832
+ Get the format mode.
833
+
834
+ :param `regionId`: the region identifier, default=0
835
+
836
+ """
837
+ if regionId >= len(self._regions):
838
+ return 0
839
+ return self._regions[regionId].GetFormatMode()
840
+
841
+ def SetTextColour(self, the_colour, regionId = 0):
842
+ """
843
+ Set the colour for the specified text region.
844
+
845
+ :param str `the_colour`: a valid colour name,
846
+ see :class:`wx.ColourDatabase`
847
+ :param `regionId`: the region identifier
848
+
849
+ """
850
+ self._textColour = wx.TheColourDatabase.Find(the_colour)
851
+ self._textColourName = the_colour
852
+
853
+ if regionId < len(self._regions):
854
+ self._regions[regionId].SetColour(the_colour)
855
+
856
+ def GetTextColour(self, regionId = 0):
857
+ """
858
+ Get the colour for the specified text region.
859
+
860
+ :param `regionId`: the region identifier
861
+
862
+ """
863
+ if regionId >= len(self._regions):
864
+ return ""
865
+ return self._regions[regionId].GetColour()
866
+
867
+ def SetRegionName(self, name, regionId = 0):
868
+ """
869
+ Set the name for this region.
870
+
871
+ :param str `name`: the name to set
872
+ :param `regionId`: the region identifier
873
+
874
+ :note: The name for a region is unique within the scope of the whole
875
+ composite, whereas a region id is unique only for a single image.
876
+
877
+ """
878
+ if regionId < len(self._regions):
879
+ self._regions[regionId].SetName(name)
880
+
881
+ def GetRegionName(self, regionId = 0):
882
+ """
883
+ Get the region's name.
884
+
885
+ :param `regionId`: the region identifier
886
+
887
+ :note: A region's name can be used to uniquely determine a region within
888
+ an entire composite image hierarchy. See also
889
+ :meth:`~lib.ogl.Shape.SetRegionName`.
890
+
891
+ """
892
+ if regionId >= len(self._regions):
893
+ return ""
894
+ return self._regions[regionId].GetName()
895
+
896
+ def GetRegionId(self, name):
897
+ """
898
+ Get the region's identifier by name.
899
+
900
+ :param str `name`: the regions name
901
+
902
+ :note: This is not unique for within an entire composite, but is unique
903
+ for the image.
904
+
905
+ """
906
+ for i, r in enumerate(self._regions):
907
+ if r.GetName() == name:
908
+ return i
909
+ return -1
910
+
911
+ # Name all _regions in all subimages recursively
912
+ def NameRegions(self, parentName=""):
913
+ """
914
+ Make unique names for all the regions in a shape or composite shape.
915
+
916
+ :param str `parentName`: a prefix for the region names
917
+
918
+ """
919
+ n = self.GetNumberOfTextRegions()
920
+ for i in range(n):
921
+ if parentName:
922
+ buff = parentName+"."+str(i)
923
+ else:
924
+ buff = str(i)
925
+ self.SetRegionName(buff, i)
926
+
927
+ for j, child in enumerate(self._children):
928
+ if parentName:
929
+ buff = parentName+"."+str(j)
930
+ else:
931
+ buff = str(j)
932
+ child.NameRegions(buff)
933
+
934
+ # Get a region by name, possibly looking recursively into composites
935
+ def FindRegion(self, name):
936
+ """
937
+ Find the actual image ('this' if non-composite) and region id
938
+ for the given region name.
939
+
940
+ :param str `name`: the region name
941
+
942
+ """
943
+ id = self.GetRegionId(name)
944
+ if id > -1:
945
+ return self, id
946
+
947
+ for child in self._children:
948
+ actualImage, regionId = child.FindRegion(name)
949
+ if actualImage:
950
+ return actualImage, regionId
951
+
952
+ return None, -1
953
+
954
+ # Finds all region names for this image (composite or simple).
955
+ def FindRegionNames(self):
956
+ """Get a list of all region names for this image (composite or simple)."""
957
+ list = []
958
+ n = self.GetNumberOfTextRegions()
959
+ for i in range(n):
960
+ list.append(self.GetRegionName(i))
961
+
962
+ for child in self._children:
963
+ list += child.FindRegionNames()
964
+
965
+ return list
966
+
967
+ def AssignNewIds(self):
968
+ """Assign new ids to this image and its children."""
969
+ self._id = wx.NewIdRef()
970
+ for child in self._children:
971
+ child.AssignNewIds()
972
+
973
+ def OnDraw(self, dc):
974
+ """not implemented???"""
975
+ pass
976
+
977
+ def OnMoveLinks(self, dc):
978
+ """The move links handler."""
979
+ # Want to set the ends of all attached links
980
+ # to point to / from this object
981
+
982
+ for line in self._lines:
983
+ line.GetEventHandler().OnMoveLink(dc)
984
+
985
+ def OnDrawContents(self, dc):
986
+ """The draw contents handler."""
987
+ if not self._regions:
988
+ return
989
+
990
+ bound_x, bound_y = self.GetBoundingBoxMin()
991
+
992
+ if self._pen:
993
+ dc.SetPen(self._pen)
994
+
995
+ for region in self._regions:
996
+ if region.GetFont():
997
+ dc.SetFont(region.GetFont())
998
+
999
+ dc.SetTextForeground(region.GetActualColourObject())
1000
+ dc.SetBackgroundMode(wx.TRANSPARENT)
1001
+ if not self._formatted:
1002
+ CentreText(dc, region.GetFormattedText(), self._xpos, self._ypos, bound_x - 2 * self._textMarginX, bound_y - 2 * self._textMarginY, region.GetFormatMode())
1003
+ self._formatted = True
1004
+
1005
+ if not self.GetDisableLabel():
1006
+ DrawFormattedText(dc, region.GetFormattedText(), self._xpos, self._ypos, bound_x - 2 * self._textMarginX, bound_y - 2 * self._textMarginY, region.GetFormatMode())
1007
+
1008
+ def DrawContents(self, dc):
1009
+ """
1010
+ Draw the internal graphic of the shape (such as text).
1011
+
1012
+ Do not override this function: override OnDrawContents, which
1013
+ is called by this function.
1014
+ """
1015
+ self.GetEventHandler().OnDrawContents(dc)
1016
+
1017
+ def OnSize(self, x, y):
1018
+ """not implemented???"""
1019
+ pass
1020
+
1021
+ def OnMovePre(self, dc, x, y, old_x, old_y, display = True):
1022
+ return True
1023
+
1024
+ def OnErase(self, dc):
1025
+ """The erase handler."""
1026
+ if not self._visible:
1027
+ return
1028
+
1029
+ # Erase links
1030
+ for line in self._lines:
1031
+ line.GetEventHandler().OnErase(dc)
1032
+
1033
+ self.GetEventHandler().OnEraseContents(dc)
1034
+
1035
+ def OnEraseContents(self, dc):
1036
+ """The erase contents handler."""
1037
+ if not self._visible:
1038
+ return
1039
+
1040
+ xp, yp = self.GetX(), self.GetY()
1041
+ minX, minY = self.GetBoundingBoxMin()
1042
+ maxX, maxY = self.GetBoundingBoxMax()
1043
+
1044
+ topLeftX = xp - maxX / 2.0 - 2
1045
+ topLeftY = yp - maxY / 2.0 - 2
1046
+
1047
+ penWidth = 0
1048
+ if self._pen:
1049
+ penWidth = self._pen.GetWidth()
1050
+
1051
+ dc.SetPen(self.GetBackgroundPen())
1052
+ dc.SetBrush(self.GetBackgroundBrush())
1053
+
1054
+ dc.DrawRectangle(int(topLeftX - penWidth), int(topLeftY - penWidth), int(maxX + penWidth * 2 + 4), int(maxY + penWidth * 2 + 4))
1055
+
1056
+ def EraseLinks(self, dc, attachment = -1, recurse = False):
1057
+ """
1058
+ Erase links attached to this shape, but do not repair damage
1059
+ caused to other shapes.
1060
+
1061
+ :param `dc`: the device context
1062
+ :param `attachment`: ???
1063
+ :param `recurse`: if `True` recurse through the children
1064
+
1065
+ """
1066
+ if not self._visible:
1067
+ return
1068
+
1069
+ for line in self._lines:
1070
+ if attachment == -1 or (line.GetTo() == self and line.GetAttachmentTo() == attachment or line.GetFrom() == self and line.GetAttachmentFrom() == attachment):
1071
+ line.GetEventHandler().OnErase(dc)
1072
+
1073
+ if recurse:
1074
+ for child in self._children:
1075
+ child.EraseLinks(dc, attachment, recurse)
1076
+
1077
+ def DrawLinks(self, dc, attachment = -1, recurse = False):
1078
+ """
1079
+ Draws any lines linked to this shape.
1080
+
1081
+ :param `dc`: the device context
1082
+ :param `attachment`: ???
1083
+ :param `recurse`: if `True` recurse through the children
1084
+
1085
+ """
1086
+ if not self._visible:
1087
+ return
1088
+
1089
+ for line in self._lines:
1090
+ if attachment == -1 or (line.GetTo() == self and line.GetAttachmentTo() == attachment or line.GetFrom() == self and line.GetAttachmentFrom() == attachment):
1091
+ line.Draw(dc)
1092
+
1093
+ if recurse:
1094
+ for child in self._children:
1095
+ child.DrawLinks(dc, attachment, recurse)
1096
+
1097
+ # Returns TRUE if pt1 <= pt2 in the sense that one point comes before
1098
+ # another on an edge of the shape.
1099
+ # attachmentPoint is the attachment point (= side) in question.
1100
+
1101
+ # This is the default, rectangular implementation.
1102
+ def AttachmentSortTest(self, attachmentPoint, pt1, pt2):
1103
+ """
1104
+ Return TRUE if pt1 is less than or equal to pt2, in the sense
1105
+ that one point comes before another on an edge of the shape.
1106
+
1107
+ attachment is the attachment point (side) in question.
1108
+
1109
+ This function is used in Shape.MoveLineToNewAttachment to determine
1110
+ the new line ordering.
1111
+ """
1112
+ physicalAttachment = self.LogicalToPhysicalAttachment(attachmentPoint)
1113
+ if physicalAttachment in [0, 2]:
1114
+ return pt1[0] <= pt2[0]
1115
+ elif physicalAttachment in [1, 3]:
1116
+ return pt1[1] <= pt2[1]
1117
+
1118
+ return False
1119
+
1120
+ def MoveLineToNewAttachment(self, dc, to_move, x, y):
1121
+ """
1122
+ Move the given line (which must already be attached to the shape)
1123
+ to a different attachment point on the shape, or a different order
1124
+ on the same attachment.
1125
+
1126
+ Calls Shape.AttachmentSortTest and then
1127
+ ShapeEvtHandler.OnChangeAttachment.
1128
+ """
1129
+ if self.GetAttachmentMode() == ATTACHMENT_MODE_NONE:
1130
+ return False
1131
+
1132
+ # Is (x, y) on this object? If so, find the new attachment point
1133
+ # the user has moved the point to
1134
+ hit = self.HitTest(x, y)
1135
+ if not hit:
1136
+ return False
1137
+
1138
+ newAttachment, distance = hit
1139
+
1140
+ self.EraseLinks(dc)
1141
+
1142
+ if to_move.GetTo() == self:
1143
+ oldAttachment = to_move.GetAttachmentTo()
1144
+ else:
1145
+ oldAttachment = to_move.GetAttachmentFrom()
1146
+
1147
+ # The links in a new ordering
1148
+ # First, add all links to the new list
1149
+ newOrdering = self._lines[:]
1150
+
1151
+ # Delete the line object from the list of links; we're going to move
1152
+ # it to another position in the list
1153
+ del newOrdering[newOrdering.index(to_move)]
1154
+
1155
+ old_x = -99999.9
1156
+ old_y = -99999.9
1157
+
1158
+ found = False
1159
+
1160
+ for line in newOrdering:
1161
+ if line.GetTo() == self and oldAttachment == line.GetAttachmentTo() or \
1162
+ line.GetFrom() == self and oldAttachment == line.GetAttachmentFrom():
1163
+ startX, startY, endX, endY = line.GetEnds()
1164
+ if line.GetTo() == self:
1165
+ xp = endX
1166
+ yp = endY
1167
+ else:
1168
+ xp = startX
1169
+ yp = startY
1170
+
1171
+ thisPoint = wx.RealPoint(xp, yp)
1172
+ lastPoint = wx.RealPoint(old_x, old_y)
1173
+ newPoint = wx.RealPoint(x, y)
1174
+
1175
+ if self.AttachmentSortTest(newAttachment, newPoint, thisPoint) and self.AttachmentSortTest(newAttachment, lastPoint, newPoint):
1176
+ found = True
1177
+ newOrdering.insert(newOrdering.index(line), to_move)
1178
+
1179
+ old_x = xp
1180
+ old_y = yp
1181
+ if found:
1182
+ break
1183
+
1184
+ if not found:
1185
+ newOrdering.append(to_move)
1186
+
1187
+ self.GetEventHandler().OnChangeAttachment(newAttachment, to_move, newOrdering)
1188
+ return True
1189
+
1190
+ def OnChangeAttachment(self, attachment, line, ordering):
1191
+ """Change attachment handler."""
1192
+ if line.GetTo() == self:
1193
+ line.SetAttachmentTo(attachment)
1194
+ else:
1195
+ line.SetAttachmentFrom(attachment)
1196
+
1197
+ self.ApplyAttachmentOrdering(ordering)
1198
+
1199
+ dc = wx.MemoryDC()
1200
+ dc.SelectObject(self.GetCanvas().GetBuffer())
1201
+ self.GetCanvas().PrepareDC(dc)
1202
+ self.MoveLinks(dc)
1203
+
1204
+ if not self.GetCanvas().GetQuickEditMode():
1205
+ self.GetCanvas().Redraw(dc)
1206
+
1207
+ # Reorders the lines according to the given list
1208
+ def ApplyAttachmentOrdering(self, linesToSort):
1209
+ """
1210
+ Apply the line ordering in linesToSort to the shape, to reorder
1211
+ the way lines are attached.
1212
+ """
1213
+ linesStore = self._lines[:]
1214
+
1215
+ self._lines = []
1216
+
1217
+ for line in linesToSort:
1218
+ if line in linesStore:
1219
+ del linesStore[linesStore.index(line)]
1220
+ self._lines.append(line)
1221
+
1222
+ # Now add any lines that haven't been listed in linesToSort
1223
+ self._lines += linesStore
1224
+
1225
+ def SortLines(self, attachment, linesToSort):
1226
+ """
1227
+ Reorder the lines coming into the node image at this attachment
1228
+ position, in the order in which they appear in linesToSort.
1229
+
1230
+ Any remaining lines not in the list will be added to the end.
1231
+ """
1232
+ # This is a temporary store of all the lines at this attachment
1233
+ # point. We'll tick them off as we've processed them.
1234
+ linesAtThisAttachment = []
1235
+
1236
+ for line in self._lines[:]:
1237
+ if line.GetTo() == self and line.GetAttachmentTo() == attachment or \
1238
+ line.GetFrom() == self and line.GetAttachmentFrom() == attachment:
1239
+ linesAtThisAttachment.append(line)
1240
+ del self._lines[self._lines.index(line)]
1241
+
1242
+ for line in linesToSort:
1243
+ if line in linesAtThisAttachment:
1244
+ # Done this one
1245
+ del linesAtThisAttachment[linesAtThisAttachment.index(line)]
1246
+ self._lines.append(line)
1247
+
1248
+ # Now add any lines that haven't been listed in linesToSort
1249
+ self._lines += linesAtThisAttachment
1250
+
1251
+ def OnHighlight(self, dc):
1252
+ """not implemented???"""
1253
+ pass
1254
+
1255
+ def OnLeftClick(self, x, y, keys = 0, attachment = 0):
1256
+ """The left click handler."""
1257
+ if self._sensitivity & OP_CLICK_LEFT != OP_CLICK_LEFT:
1258
+ if self._parent:
1259
+ attachment, dist = self._parent.HitTest(x, y)
1260
+ self._parent.GetEventHandler().OnLeftClick(x, y, keys, attachment)
1261
+
1262
+ def OnRightClick(self, x, y, keys = 0, attachment = 0):
1263
+ """The right click handler."""
1264
+ if self._sensitivity & OP_CLICK_RIGHT != OP_CLICK_RIGHT:
1265
+ attachment, dist = self._parent.HitTest(x, y)
1266
+ self._parent.GetEventHandler().OnRightClick(x, y, keys, attachment)
1267
+
1268
+ def OnDragLeft(self, draw, x, y, keys = 0, attachment = 0):
1269
+ """The drag left handler."""
1270
+ if self._sensitivity & OP_DRAG_LEFT != OP_DRAG_LEFT:
1271
+ if self._parent:
1272
+ hit = self._parent.HitTest(x, y)
1273
+ if hit:
1274
+ attachment, dist = hit
1275
+ self._parent.GetEventHandler().OnDragLeft(draw, x, y, keys, attachment)
1276
+ return
1277
+
1278
+ dc = wx.ClientDC(self.GetCanvas())
1279
+ self.GetCanvas().PrepareDC(dc)
1280
+ dc.SetLogicalFunction(OGLRBLF)
1281
+
1282
+ dottedPen = wx.Pen(wx.BLACK, 1, wx.PENSTYLE_DOT)
1283
+
1284
+ dc.SetPen(dottedPen)
1285
+ dc.SetBrush(wx.TRANSPARENT_BRUSH)
1286
+
1287
+ xx = x + DragOffsetX
1288
+ yy = y + DragOffsetY
1289
+
1290
+ xx, yy = self._canvas.Snap(xx, yy)
1291
+ w, h = self.GetBoundingBoxMax()
1292
+ self.GetEventHandler().OnDrawOutline(dc, xx, yy, w, h)
1293
+
1294
+ def OnBeginDragLeft(self, x, y, keys = 0, attachment = 0):
1295
+ """The begin drag left handler."""
1296
+ global DragOffsetX, DragOffsetY
1297
+
1298
+ if self._sensitivity & OP_DRAG_LEFT != OP_DRAG_LEFT:
1299
+ if self._parent:
1300
+ hit = self._parent.HitTest(x, y)
1301
+ if hit:
1302
+ attachment, dist = hit
1303
+ self._parent.GetEventHandler().OnBeginDragLeft(x, y, keys, attachment)
1304
+ return
1305
+
1306
+ DragOffsetX = self._xpos - x
1307
+ DragOffsetY = self._ypos - y
1308
+
1309
+ dc = wx.ClientDC(self.GetCanvas())
1310
+ self.GetCanvas().PrepareDC(dc)
1311
+ dc.SetLogicalFunction(OGLRBLF)
1312
+
1313
+ # New policy: don't erase shape until end of drag.
1314
+ # self.Erase(dc)
1315
+ xx = x + DragOffsetX
1316
+ yy = y + DragOffsetY
1317
+ xx, yy = self._canvas.Snap(xx, yy)
1318
+
1319
+ dottedPen = wx.Pen(wx.BLACK, 1, wx.PENSTYLE_DOT)
1320
+ dc.SetPen(dottedPen)
1321
+ dc.SetBrush(wx.TRANSPARENT_BRUSH)
1322
+
1323
+ w, h = self.GetBoundingBoxMax()
1324
+ self.GetEventHandler().OnDrawOutline(dc, xx, yy, w, h)
1325
+ self._canvas.CaptureMouse()
1326
+
1327
+ def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
1328
+ """The end drag left handler."""
1329
+ if self._canvas.HasCapture():
1330
+ self._canvas.ReleaseMouse()
1331
+ if self._sensitivity & OP_DRAG_LEFT != OP_DRAG_LEFT:
1332
+ if self._parent:
1333
+ hit = self._parent.HitTest(x, y)
1334
+ if hit:
1335
+ attachment, dist = hit
1336
+ self._parent.GetEventHandler().OnEndDragLeft(x, y, keys, attachment)
1337
+ return
1338
+
1339
+ dc = wx.ClientDC(self.GetCanvas())
1340
+ self.GetCanvas().PrepareDC(dc)
1341
+ dc.SetLogicalFunction(wx.COPY)
1342
+
1343
+ xx = x + DragOffsetX
1344
+ yy = y + DragOffsetY
1345
+ xx, yy = self._canvas.Snap(xx, yy)
1346
+
1347
+ # New policy: erase shape at end of drag.
1348
+ self.Erase(dc)
1349
+
1350
+ self.Move(dc, xx, yy)
1351
+ if self._canvas and not self._canvas.GetQuickEditMode():
1352
+ self._canvas.Redraw(dc)
1353
+
1354
+ def OnDragRight(self, draw, x, y, keys = 0, attachment = 0):
1355
+ """The drag right handler."""
1356
+ if self._sensitivity & OP_DRAG_RIGHT != OP_DRAG_RIGHT:
1357
+ if self._parent:
1358
+ attachment, dist = self._parent.HitTest(x, y)
1359
+ self._parent.GetEventHandler().OnDragRight(draw, x, y, keys, attachment)
1360
+ return
1361
+
1362
+ def OnBeginDragRight(self, x, y, keys = 0, attachment = 0):
1363
+ """The begin drag right handler."""
1364
+ if self._sensitivity & OP_DRAG_RIGHT != OP_DRAG_RIGHT:
1365
+ if self._parent:
1366
+ attachment, dist = self._parent.HitTest(x, y)
1367
+ self._parent.GetEventHandler().OnBeginDragRight(x, y, keys, attachment)
1368
+ return
1369
+
1370
+ def OnEndDragRight(self, x, y, keys = 0, attachment = 0):
1371
+ """The end drag right handler."""
1372
+ if self._sensitivity & OP_DRAG_RIGHT != OP_DRAG_RIGHT:
1373
+ if self._parent:
1374
+ attachment, dist = self._parent.HitTest(x, y)
1375
+ self._parent.GetEventHandler().OnEndDragRight(x, y, keys, attachment)
1376
+ return
1377
+
1378
+ def OnDrawOutline(self, dc, x, y, w, h):
1379
+ """The draw outline handler."""
1380
+ points = [[int(x - w / 2.0), int(y - h / 2.0)],
1381
+ [int(x + w / 2.0), int(y - h / 2.0)],
1382
+ [int(x + w / 2.0), int(y + h / 2.0)],
1383
+ [int(x - w / 2.0), int(y + h / 2.0)],
1384
+ [int(x - w / 2.0), int(y - h / 2.0)],
1385
+ ]
1386
+
1387
+ dc.DrawLines(points)
1388
+
1389
+ def Attach(self, can):
1390
+ """Set the shape's internal canvas pointer to point to the given canvas."""
1391
+ self._canvas = can
1392
+
1393
+ def Detach(self):
1394
+ """Disassociates the shape from its canvas."""
1395
+ self._canvas = None
1396
+
1397
+ def Move(self, dc, x, y, display = True):
1398
+ """
1399
+ Move the shape to the given position.
1400
+
1401
+ :param `dc`: the device context
1402
+ :param `x`: the x position
1403
+ :param `y`: the y position
1404
+ :param `display`: if `True` redraw
1405
+
1406
+ """
1407
+ old_x = self._xpos
1408
+ old_y = self._ypos
1409
+
1410
+ if not self.GetEventHandler().OnMovePre(dc, x, y, old_x, old_y, display):
1411
+ return
1412
+
1413
+ self._xpos, self._ypos = x, y
1414
+
1415
+ self.ResetControlPoints()
1416
+
1417
+ if display:
1418
+ self.Draw(dc)
1419
+
1420
+ self.MoveLinks(dc)
1421
+
1422
+ self.GetEventHandler().OnMovePost(dc, x, y, old_x, old_y, display)
1423
+
1424
+ def MoveLinks(self, dc):
1425
+ """Redraw all the lines attached to the shape."""
1426
+ self.GetEventHandler().OnMoveLinks(dc)
1427
+
1428
+ def Draw(self, dc):
1429
+ """
1430
+ Draw the whole shape and any lines attached to it.
1431
+
1432
+ Do not override this function: override OnDraw, which is called
1433
+ by this function.
1434
+ """
1435
+ if self._visible:
1436
+ self.GetEventHandler().OnDraw(dc)
1437
+ self.GetEventHandler().OnDrawContents(dc)
1438
+ self.GetEventHandler().OnDrawControlPoints(dc)
1439
+ self.GetEventHandler().OnDrawBranches(dc)
1440
+
1441
+ def Flash(self):
1442
+ """Flash the shape."""
1443
+ if self.GetCanvas():
1444
+ dc = wx.MemoryDC()
1445
+ dc.SelectObject(self.GetCanvas().GetBuffer())
1446
+ self.GetCanvas().PrepareDC(dc)
1447
+ dc.SetLogicalFunction(OGLRBLF)
1448
+ self.Draw(dc)
1449
+ dc.SetLogicalFunction(wx.COPY)
1450
+ self.Draw(dc)
1451
+
1452
+ def Show(self, show):
1453
+ """Set a flag indicating whether the shape should be drawn."""
1454
+ self._visible = show
1455
+ for child in self._children:
1456
+ child.Show(show)
1457
+
1458
+ def Erase(self, dc):
1459
+ """
1460
+ Erase the shape.
1461
+
1462
+ Does not repair damage caused to other shapes.
1463
+ """
1464
+ self.GetEventHandler().OnErase(dc)
1465
+ self.GetEventHandler().OnEraseControlPoints(dc)
1466
+ self.GetEventHandler().OnDrawBranches(dc, erase = True)
1467
+
1468
+ def EraseContents(self, dc):
1469
+ """
1470
+ Erase the shape contents, that is, the area within the shape's
1471
+ minimum bounding box.
1472
+ """
1473
+ self.GetEventHandler().OnEraseContents(dc)
1474
+
1475
+ def AddText(self, string):
1476
+ """Add a line of text to the shape's default text region."""
1477
+ if not self._regions:
1478
+ return
1479
+
1480
+ region = self._regions[0]
1481
+ #region.ClearText()
1482
+ new_line = ShapeTextLine(0, 0, string)
1483
+ text = region.GetFormattedText()
1484
+ text.append(new_line)
1485
+
1486
+ self._formatted = False
1487
+
1488
+ def SetSize(self, x, y, recursive = True):
1489
+ """Set the shape's size.
1490
+
1491
+ :param `x`: the x position
1492
+ :param `y`: the y position
1493
+ :param `recursive`: not used
1494
+
1495
+ """
1496
+ self.SetAttachmentSize(x, y)
1497
+ self.SetDefaultRegionSize()
1498
+
1499
+ def SetAttachmentSize(self, w, h):
1500
+ """
1501
+ Set the attachment size.
1502
+
1503
+ :param `w`: width
1504
+ :param `h`: height
1505
+
1506
+ """
1507
+ width, height = self.GetBoundingBoxMin()
1508
+ if width == 0:
1509
+ scaleX = 1.0
1510
+ else:
1511
+ scaleX = float(w) / width
1512
+ if height == 0:
1513
+ scaleY = 1.0
1514
+ else:
1515
+ scaleY = float(h) / height
1516
+
1517
+ for point in self._attachmentPoints:
1518
+ point._x = point._x * scaleX
1519
+ point._y = point._y * scaleY
1520
+
1521
+ # Add line FROM this object
1522
+ def AddLine(self, line, other, attachFrom = 0, attachTo = 0, positionFrom = -1, positionTo = -1):
1523
+ """
1524
+ Add a line between this shape and the given other shape, at the
1525
+ specified attachment points.
1526
+
1527
+ :param `line`: the line an instance of :class:`~lib.ogl.LineShape`
1528
+ :param `other`: the other shape, an instance of :class:`Shape`
1529
+ :param `attachFrom`: the attachment from point ???
1530
+ :param `attachTo`: the attachment to point ???
1531
+ :param `positionFrom`: the from position
1532
+ :param `positionTo`: the to position
1533
+
1534
+ :note: The position in the list of lines at each end can also be
1535
+ specified, so that the line will be drawn at a particular point on
1536
+ its attachment point.
1537
+
1538
+ """
1539
+ if positionFrom == -1:
1540
+ if not line in self._lines:
1541
+ self._lines.append(line)
1542
+ else:
1543
+ # Don't preserve old ordering if we have new ordering instructions
1544
+ try:
1545
+ self._lines.remove(line)
1546
+ except ValueError:
1547
+ pass
1548
+ if positionFrom < len(self._lines):
1549
+ self._lines.insert(positionFrom, line)
1550
+ else:
1551
+ self._lines.append(line)
1552
+
1553
+ if positionTo == -1:
1554
+ if not other in other._lines:
1555
+ other._lines.append(line)
1556
+ else:
1557
+ # Don't preserve old ordering if we have new ordering instructions
1558
+ try:
1559
+ other._lines.remove(line)
1560
+ except ValueError:
1561
+ pass
1562
+ if positionTo < len(other._lines):
1563
+ other._lines.insert(positionTo, line)
1564
+ else:
1565
+ other._lines.append(line)
1566
+
1567
+ line.SetFrom(self)
1568
+ line.SetTo(other)
1569
+ line.SetAttachments(attachFrom, attachTo)
1570
+
1571
+ dc = wx.MemoryDC()
1572
+ dc.SelectObject(self.GetCanvas().GetBuffer())
1573
+ self.GetCanvas().PrepareDC(dc)
1574
+ self.MoveLinks(dc)
1575
+
1576
+ def RemoveLine(self, line):
1577
+ """
1578
+ Remove the given line from the shape's list of attached lines.
1579
+
1580
+ :param `line`: an instance of :class:`~lib.ogl.LineShape`
1581
+
1582
+ """
1583
+ if line.GetFrom() == self:
1584
+ line.GetTo()._lines.remove(line)
1585
+ else:
1586
+ line.GetFrom()._lines.remove(line)
1587
+
1588
+ self._lines.remove(line)
1589
+
1590
+ # Default - make 6 control points
1591
+ def MakeControlPoints(self):
1592
+ """
1593
+ Make a list of control points (draggable handles) appropriate to
1594
+ the shape.
1595
+ """
1596
+ maxX, maxY = self.GetBoundingBoxMax()
1597
+ minX, minY = self.GetBoundingBoxMin()
1598
+
1599
+ widthMin = minX + CONTROL_POINT_SIZE + 2
1600
+ heightMin = minY + CONTROL_POINT_SIZE + 2
1601
+
1602
+ # Offsets from main object
1603
+ top = -heightMin / 2.0
1604
+ bottom = heightMin / 2.0 + (maxY - minY)
1605
+ left = -widthMin / 2.0
1606
+ right = widthMin / 2.0 + (maxX - minX)
1607
+
1608
+ control = ControlPoint(self._canvas, self, CONTROL_POINT_SIZE, left, top, CONTROL_POINT_DIAGONAL)
1609
+ self._canvas.AddShape(control)
1610
+ self._controlPoints.append(control)
1611
+
1612
+ control = ControlPoint(self._canvas, self, CONTROL_POINT_SIZE, 0, top, CONTROL_POINT_VERTICAL)
1613
+ self._canvas.AddShape(control)
1614
+ self._controlPoints.append(control)
1615
+
1616
+ control = ControlPoint(self._canvas, self, CONTROL_POINT_SIZE, right, top, CONTROL_POINT_DIAGONAL)
1617
+ self._canvas.AddShape(control)
1618
+ self._controlPoints.append(control)
1619
+
1620
+ control = ControlPoint(self._canvas, self, CONTROL_POINT_SIZE, right, 0, CONTROL_POINT_HORIZONTAL)
1621
+ self._canvas.AddShape(control)
1622
+ self._controlPoints.append(control)
1623
+
1624
+ control = ControlPoint(self._canvas, self, CONTROL_POINT_SIZE, right, bottom, CONTROL_POINT_DIAGONAL)
1625
+ self._canvas.AddShape(control)
1626
+ self._controlPoints.append(control)
1627
+
1628
+ control = ControlPoint(self._canvas, self, CONTROL_POINT_SIZE, 0, bottom, CONTROL_POINT_VERTICAL)
1629
+ self._canvas.AddShape(control)
1630
+ self._controlPoints.append(control)
1631
+
1632
+ control = ControlPoint(self._canvas, self, CONTROL_POINT_SIZE, left, bottom, CONTROL_POINT_DIAGONAL)
1633
+ self._canvas.AddShape(control)
1634
+ self._controlPoints.append(control)
1635
+
1636
+ control = ControlPoint(self._canvas, self, CONTROL_POINT_SIZE, left, 0, CONTROL_POINT_HORIZONTAL)
1637
+ self._canvas.AddShape(control)
1638
+ self._controlPoints.append(control)
1639
+
1640
+ def MakeMandatoryControlPoints(self):
1641
+ """
1642
+ Make the mandatory control points.
1643
+
1644
+ For example, the control point on a dividing line should appear even
1645
+ if the divided rectangle shape's handles should not appear (because
1646
+ it is the child of a composite, and children are not resizable).
1647
+ """
1648
+ for child in self._children:
1649
+ child.MakeMandatoryControlPoints()
1650
+
1651
+ def ResetMandatoryControlPoints(self):
1652
+ """Reset the mandatory control points."""
1653
+ for child in self._children:
1654
+ child.ResetMandatoryControlPoints()
1655
+
1656
+ def ResetControlPoints(self):
1657
+ """
1658
+ Reset the positions of the control points (for instance when the
1659
+ shape's shape has changed).
1660
+ """
1661
+ self.ResetMandatoryControlPoints()
1662
+
1663
+ if len(self._controlPoints) == 0:
1664
+ return
1665
+
1666
+ maxX, maxY = self.GetBoundingBoxMax()
1667
+ minX, minY = self.GetBoundingBoxMin()
1668
+
1669
+ widthMin = minX + CONTROL_POINT_SIZE + 2
1670
+ heightMin = minY + CONTROL_POINT_SIZE + 2
1671
+
1672
+ # Offsets from main object
1673
+ top = -heightMin / 2.0
1674
+ bottom = heightMin / 2.0 + (maxY - minY)
1675
+ left = -widthMin / 2.0
1676
+ right = widthMin / 2.0 + (maxX - minX)
1677
+
1678
+ self._controlPoints[0]._xoffset = left
1679
+ self._controlPoints[0]._yoffset = top
1680
+
1681
+ self._controlPoints[1]._xoffset = 0
1682
+ self._controlPoints[1]._yoffset = top
1683
+
1684
+ self._controlPoints[2]._xoffset = right
1685
+ self._controlPoints[2]._yoffset = top
1686
+
1687
+ self._controlPoints[3]._xoffset = right
1688
+ self._controlPoints[3]._yoffset = 0
1689
+
1690
+ self._controlPoints[4]._xoffset = right
1691
+ self._controlPoints[4]._yoffset = bottom
1692
+
1693
+ self._controlPoints[5]._xoffset = 0
1694
+ self._controlPoints[5]._yoffset = bottom
1695
+
1696
+ self._controlPoints[6]._xoffset = left
1697
+ self._controlPoints[6]._yoffset = bottom
1698
+
1699
+ self._controlPoints[7]._xoffset = left
1700
+ self._controlPoints[7]._yoffset = 0
1701
+
1702
+ def DeleteControlPoints(self, dc = None):
1703
+ """
1704
+ Delete the control points (or handles) for the shape.
1705
+
1706
+ Does not redraw the shape.
1707
+ """
1708
+ for control in self._controlPoints[:]:
1709
+ if dc:
1710
+ control.GetEventHandler().OnErase(dc)
1711
+ control.Delete()
1712
+ self._controlPoints.remove(control)
1713
+ self._controlPoints = []
1714
+
1715
+ # Children of divisions are contained objects,
1716
+ # so stop here
1717
+ if not isinstance(self, DivisionShape):
1718
+ for child in self._children:
1719
+ child.DeleteControlPoints(dc)
1720
+
1721
+ def OnDrawControlPoints(self, dc):
1722
+ """The draw control points handler."""
1723
+ if not self._drawHandles:
1724
+ return
1725
+
1726
+ dc.SetBrush(wx.BLACK_BRUSH)
1727
+ dc.SetPen(wx.BLACK_PEN)
1728
+
1729
+ for control in self._controlPoints:
1730
+ control.Draw(dc)
1731
+
1732
+ # Children of divisions are contained objects,
1733
+ # so stop here.
1734
+ # This test bypasses the type facility for speed
1735
+ # (critical when drawing)
1736
+
1737
+ if not isinstance(self, DivisionShape):
1738
+ for child in self._children:
1739
+ child.GetEventHandler().OnDrawControlPoints(dc)
1740
+
1741
+ def OnEraseControlPoints(self, dc):
1742
+ """The erase control points handler."""
1743
+ for control in self._controlPoints:
1744
+ control.Erase(dc)
1745
+
1746
+ if not isinstance(self, DivisionShape):
1747
+ for child in self._children:
1748
+ child.GetEventHandler().OnEraseControlPoints(dc)
1749
+
1750
+ def Select(self, select, dc = None):
1751
+ """
1752
+ Select or deselect the given shape, drawing or erasing control points
1753
+ (handles) as necessary.
1754
+
1755
+ :param `select`: `True` to select
1756
+ :param `dc`: the device context
1757
+
1758
+ """
1759
+ self._selected = select
1760
+ if select:
1761
+ self.MakeControlPoints()
1762
+ # Children of divisions are contained objects,
1763
+ # so stop here
1764
+ if not isinstance(self, DivisionShape):
1765
+ for child in self._children:
1766
+ child.MakeMandatoryControlPoints()
1767
+ if dc:
1768
+ self.GetEventHandler().OnDrawControlPoints(dc)
1769
+ else:
1770
+ self.DeleteControlPoints(dc)
1771
+ if not isinstance(self, DivisionShape):
1772
+ for child in self._children:
1773
+ child.DeleteControlPoints(dc)
1774
+
1775
+ def Selected(self):
1776
+ """`True` if the shape is currently selected."""
1777
+ return self._selected
1778
+
1779
+ def AncestorSelected(self):
1780
+ """`True` if the shape's ancestor is currently selected."""
1781
+ if self._selected:
1782
+ return True
1783
+ if not self.GetParent():
1784
+ return False
1785
+ return self.GetParent().AncestorSelected()
1786
+
1787
+ def GetNumberOfAttachments(self):
1788
+ """Get the number of attachment points for this shape."""
1789
+ # Should return the MAXIMUM attachment point id here,
1790
+ # so higher-level functions can iterate through all attachments,
1791
+ # even if they're not contiguous.
1792
+
1793
+ if len(self._attachmentPoints) == 0:
1794
+ return 4
1795
+ else:
1796
+ maxN = 3
1797
+ for point in self._attachmentPoints:
1798
+ if point._id > maxN:
1799
+ maxN = point._id
1800
+ return maxN + 1
1801
+
1802
+ def AttachmentIsValid(self, attachment):
1803
+ """`True` if attachment is a valid attachment point."""
1804
+ if len(self._attachmentPoints) == 0:
1805
+ return attachment in range(4)
1806
+
1807
+ for point in self._attachmentPoints:
1808
+ if point._id == attachment:
1809
+ return True
1810
+ return False
1811
+
1812
+ def GetAttachmentPosition(self, attachment, nth = 0, no_arcs = 1, line = None):
1813
+ """
1814
+ Get the position at which the given attachment point should be drawn.
1815
+
1816
+ :param `attachment`: the attachment ???
1817
+ :param `nth`: get nth attachment ???
1818
+ :param `no_arcs`: ???
1819
+ :param `line`: ???
1820
+
1821
+ If attachment isn't found among the attachment points of the shape,
1822
+ returns None.
1823
+ """
1824
+ if self._attachmentMode == ATTACHMENT_MODE_NONE:
1825
+ return self._xpos, self._ypos
1826
+ elif self._attachmentMode == ATTACHMENT_MODE_BRANCHING:
1827
+ pt, stemPt = self.GetBranchingAttachmentPoint(attachment, nth)
1828
+ return pt[0], pt[1]
1829
+ elif self._attachmentMode == ATTACHMENT_MODE_EDGE:
1830
+ if len(self._attachmentPoints):
1831
+ for point in self._attachmentPoints:
1832
+ if point._id == attachment:
1833
+ return self._xpos + point._x, self._ypos + point._y
1834
+ return None
1835
+ else:
1836
+ # Assume is rectangular
1837
+ w, h = self.GetBoundingBoxMax()
1838
+ top = self._ypos + h / 2.0
1839
+ bottom = self._ypos - h / 2.0
1840
+ left = self._xpos - w / 2.0
1841
+ right = self._xpos + w / 2.0
1842
+
1843
+ # wtf?
1844
+ line and line.IsEnd(self)
1845
+
1846
+ physicalAttachment = self.LogicalToPhysicalAttachment(attachment)
1847
+
1848
+ # Simplified code
1849
+ if physicalAttachment == 0:
1850
+ pt = self.CalcSimpleAttachment((left, bottom), (right, bottom), nth, no_arcs, line)
1851
+ elif physicalAttachment == 1:
1852
+ pt = self.CalcSimpleAttachment((right, bottom), (right, top), nth, no_arcs, line)
1853
+ elif physicalAttachment == 2:
1854
+ pt = self.CalcSimpleAttachment((left, top), (right, top), nth, no_arcs, line)
1855
+ elif physicalAttachment == 3:
1856
+ pt = self.CalcSimpleAttachment((left, bottom), (left, top), nth, no_arcs, line)
1857
+ else:
1858
+ return None
1859
+ return pt[0], pt[1]
1860
+ return None
1861
+
1862
+ def GetBoundingBoxMax(self):
1863
+ """
1864
+ Get the maximum bounding box for the shape, taking into account
1865
+ external features such as shadows.
1866
+ """
1867
+ ww, hh = self.GetBoundingBoxMin()
1868
+ if self._shadowMode != SHADOW_NONE:
1869
+ ww += self._shadowOffsetX
1870
+ hh += self._shadowOffsetY
1871
+ return ww, hh
1872
+
1873
+ def GetBoundingBoxMin(self):
1874
+ """
1875
+ Get the minimum bounding box for the shape, that defines the area
1876
+ available for drawing the contents (such as text).
1877
+
1878
+ Must be overridden.
1879
+ """
1880
+ return 0, 0
1881
+
1882
+ def HasDescendant(self, image):
1883
+ """
1884
+ Is image a descendant of this composite.
1885
+
1886
+ :param `image`: the image, is this a shape???
1887
+ :returns: `True` if it is a descendant
1888
+
1889
+ """
1890
+ if image == self:
1891
+ return True
1892
+ for child in self._children:
1893
+ if child.HasDescendant(image):
1894
+ return True
1895
+ return False
1896
+
1897
+ # Assuming the attachment lies along a vertical or horizontal line,
1898
+ # calculate the position on that point.
1899
+ def CalcSimpleAttachment(self, pt1, pt2, nth, noArcs, line):
1900
+ """
1901
+ Assuming the attachment lies along a vertical or horizontal line,
1902
+ calculate the position on that point.
1903
+
1904
+ :param `pt1`: The first point of the line representing the edge of
1905
+ the shape
1906
+ :param `pt2`: The second point of the line representing the edge of
1907
+ the shape
1908
+ :param `nth`: The position on the edge (for example there may be 6
1909
+ lines at this attachment point, and this may be the 2nd line.
1910
+ :param `noArcs`: The number of lines at this edge.
1911
+ :param `line`: The line shape.
1912
+
1913
+ :note: This function expects the line to be either vertical or horizontal,
1914
+ and determines which.
1915
+
1916
+ """
1917
+ isEnd = line and line.IsEnd(self)
1918
+
1919
+ # Are we horizontal or vertical?
1920
+ isHorizontal = RoughlyEqual(pt1[1], pt2[1])
1921
+
1922
+ if isHorizontal:
1923
+ if pt1[0] > pt2[0]:
1924
+ firstPoint = pt2
1925
+ secondPoint = pt1
1926
+ else:
1927
+ firstPoint = pt1
1928
+ secondPoint = pt2
1929
+
1930
+ if self._spaceAttachments:
1931
+ if line and line.GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE:
1932
+ # Align line according to the next handle along
1933
+ point = line.GetNextControlPoint(self)
1934
+ if point[0] < firstPoint[0]:
1935
+ x = firstPoint[0]
1936
+ elif point[0] > secondPoint[0]:
1937
+ x = secondPoint[0]
1938
+ else:
1939
+ x = point[0]
1940
+ else:
1941
+ x = firstPoint[0] + (nth + 1) * (secondPoint[0] - firstPoint[0]) / (noArcs + 1.0)
1942
+ else:
1943
+ x = (secondPoint[0] - firstPoint[0]) / 2.0 # Midpoint
1944
+ y = pt1[1]
1945
+ else:
1946
+ assert RoughlyEqual(pt1[0], pt2[0])
1947
+
1948
+ if pt1[1] > pt2[1]:
1949
+ firstPoint = pt2
1950
+ secondPoint = pt1
1951
+ else:
1952
+ firstPoint = pt1
1953
+ secondPoint = pt2
1954
+
1955
+ if self._spaceAttachments:
1956
+ if line and line.GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE:
1957
+ # Align line according to the next handle along
1958
+ point = line.GetNextControlPoint(self)
1959
+ if point[1] < firstPoint[1]:
1960
+ y = firstPoint[1]
1961
+ elif point[1] > secondPoint[1]:
1962
+ y = secondPoint[1]
1963
+ else:
1964
+ y = point[1]
1965
+ else:
1966
+ y = firstPoint[1] + (nth + 1) * (secondPoint[1] - firstPoint[1]) / (noArcs + 1.0)
1967
+ else:
1968
+ y = (secondPoint[1] - firstPoint[1]) / 2.0 # Midpoint
1969
+ x = pt1[0]
1970
+
1971
+ return x, y
1972
+
1973
+ def GetLinePosition(self, line):
1974
+ """
1975
+ Get the zero-based position of line in the list of lines
1976
+ for this shape.
1977
+
1978
+ :param `line`: line to find position for
1979
+
1980
+ """
1981
+ try:
1982
+ return self._lines.index(line)
1983
+ except:
1984
+ return 0
1985
+
1986
+
1987
+ # |________|
1988
+ # | <- root
1989
+ # | <- neck
1990
+ # shoulder1 ->---------<- shoulder2
1991
+ # | | | | |
1992
+ # <- branching attachment point N-1
1993
+
1994
+ def GetBranchingAttachmentInfo(self, attachment):
1995
+ """
1996
+ Get information about where branching connections go.
1997
+
1998
+ :param `attachment`: ???
1999
+ :returns: `False` if there are no lines at this attachment.
2000
+ """
2001
+ physicalAttachment = self.LogicalToPhysicalAttachment(attachment)
2002
+
2003
+ # Number of lines at this attachment
2004
+ lineCount = self.GetAttachmentLineCount(attachment)
2005
+
2006
+ if not lineCount:
2007
+ return False
2008
+
2009
+ totalBranchLength = self._branchSpacing * (lineCount - 1)
2010
+ root = self.GetBranchingAttachmentRoot(attachment)
2011
+
2012
+ neck = wx.RealPoint()
2013
+ shoulder1 = wx.RealPoint()
2014
+ shoulder2 = wx.RealPoint()
2015
+
2016
+ # Assume that we have attachment points 0 to 3: top, right, bottom, left
2017
+ if physicalAttachment == 0:
2018
+ neck[0] = self.GetX()
2019
+ neck[1] = root[1] - self._branchNeckLength
2020
+
2021
+ shoulder1[0] = root[0] - totalBranchLength / 2.0
2022
+ shoulder2[0] = root[0] + totalBranchLength / 2.0
2023
+
2024
+ shoulder1[1] = neck[1]
2025
+ shoulder2[1] = neck[1]
2026
+ elif physicalAttachment == 1:
2027
+ neck[0] = root[0] + self._branchNeckLength
2028
+ neck[1] = root[1]
2029
+
2030
+ shoulder1[0] = neck[0]
2031
+ shoulder2[0] = neck[0]
2032
+
2033
+ shoulder1[1] = neck[1] - totalBranchLength / 2.0
2034
+ shoulder1[1] = neck[1] + totalBranchLength / 2.0
2035
+ elif physicalAttachment == 2:
2036
+ neck[0] = self.GetX()
2037
+ neck[1] = root[1] + self._branchNeckLength
2038
+
2039
+ shoulder1[0] = root[0] - totalBranchLength / 2.0
2040
+ shoulder2[0] = root[0] + totalBranchLength / 2.0
2041
+
2042
+ shoulder1[1] = neck[1]
2043
+ shoulder2[1] = neck[1]
2044
+ elif physicalAttachment == 3:
2045
+ neck[0] = root[0] - self._branchNeckLength
2046
+ neck[1] = root[1]
2047
+
2048
+ shoulder1[0] = neck[0]
2049
+ shoulder2[0] = neck[0]
2050
+
2051
+ shoulder1[1] = neck[1] - totalBranchLength / 2.0
2052
+ shoulder2[1] = neck[1] + totalBranchLength / 2.0
2053
+ else:
2054
+ raise ValueError("Unrecognised attachment point in GetBranchingAttachmentInfo")
2055
+ return root, neck, shoulder1, shoulder2
2056
+
2057
+ def GetBranchingAttachmentPoint(self, attachment, n):
2058
+ """
2059
+ Get branching attachment point.
2060
+
2061
+ :param `attachment`: ???
2062
+ :param `n`: ???
2063
+
2064
+ """
2065
+ physicalAttachment = self.LogicalToPhysicalAttachment(attachment)
2066
+
2067
+ root, neck, shoulder1, shoulder2 = self.GetBranchingAttachmentInfo(attachment)
2068
+ pt = wx.RealPoint()
2069
+ stemPt = wx.RealPoint()
2070
+
2071
+ if physicalAttachment == 0:
2072
+ pt[1] = neck[1] - self._branchStemLength
2073
+ pt[0] = shoulder1[0] + n * self._branchSpacing
2074
+
2075
+ stemPt[0] = pt[0]
2076
+ stemPt[1] = neck[1]
2077
+ elif physicalAttachment == 2:
2078
+ pt[1] = neck[1] + self._branchStemLength
2079
+ pt[0] = shoulder1[0] + n * self._branchStemLength
2080
+
2081
+ stemPt[0] = pt[0]
2082
+ stemPt[1] = neck[1]
2083
+ elif physicalAttachment == 1:
2084
+ pt[0] = neck[0] + self._branchStemLength
2085
+ pt[1] = shoulder1[1] + n * self._branchSpacing
2086
+
2087
+ stemPt[0] = neck[0]
2088
+ stemPt[1] = pt[1]
2089
+ elif physicalAttachment == 3:
2090
+ pt[0] = neck[0] - self._branchStemLength
2091
+ pt[1] = shoulder1[1] + n * self._branchSpacing
2092
+
2093
+ stemPt[0] = neck[0]
2094
+ stemPt[1] = pt[1]
2095
+ else:
2096
+ raise ValueError("Unrecognised attachment point in GetBranchingAttachmentPoint")
2097
+
2098
+ return pt, stemPt
2099
+
2100
+ def GetAttachmentLineCount(self, attachment):
2101
+ """
2102
+ Get the number of lines at this attachment position.
2103
+
2104
+ :param `attachment`: ???
2105
+ :returns: the count of lines at this position
2106
+
2107
+ """
2108
+ count = 0
2109
+ for lineShape in self._lines:
2110
+ if lineShape.GetFrom() == self and lineShape.GetAttachmentFrom() == attachment:
2111
+ count += 1
2112
+ elif lineShape.GetTo() == self and lineShape.GetAttachmentTo() == attachment:
2113
+ count += 1
2114
+ return count
2115
+
2116
+ def GetBranchingAttachmentRoot(self, attachment):
2117
+ """
2118
+ Get the root point at the given attachment.
2119
+
2120
+ :param `attachment`: ???
2121
+
2122
+ """
2123
+ physicalAttachment = self.LogicalToPhysicalAttachment(attachment)
2124
+
2125
+ root = wx.RealPoint()
2126
+
2127
+ width, height = self.GetBoundingBoxMax()
2128
+
2129
+ # Assume that we have attachment points 0 to 3: top, right, bottom, left
2130
+ if physicalAttachment == 0:
2131
+ root[0] = self.GetX()
2132
+ root[1] = self.GetY() - height / 2.0
2133
+ elif physicalAttachment == 1:
2134
+ root[0] = self.GetX() + width / 2.0
2135
+ root[1] = self.GetY()
2136
+ elif physicalAttachment == 2:
2137
+ root[0] = self.GetX()
2138
+ root[1] = self.GetY() + height / 2.0
2139
+ elif physicalAttachment == 3:
2140
+ root[0] = self.GetX() - width / 2.0
2141
+ root[1] = self.GetY()
2142
+ else:
2143
+ raise ValueError("Unrecognised attachment point in GetBranchingAttachmentRoot")
2144
+
2145
+ return root
2146
+
2147
+ # Draw or erase the branches (not the actual arcs though)
2148
+ def OnDrawBranchesAttachment(self, dc, attachment, erase = False):
2149
+ """The draw branches attachment handler."""
2150
+ count = self.GetAttachmentLineCount(attachment)
2151
+ if count == 0:
2152
+ return
2153
+
2154
+ root, neck, shoulder1, shoulder2 = self.GetBranchingAttachmentInfo(attachment)
2155
+
2156
+ if erase:
2157
+ dc.SetPen(wx.WHITE_PEN)
2158
+ dc.SetBrush(wx.WHITE_BRUSH)
2159
+ else:
2160
+ dc.SetPen(wx.BLACK_PEN)
2161
+ dc.SetBrush(wx.BLACK_BRUSH)
2162
+
2163
+ # Draw neck
2164
+ dc.DrawLine(root[0], root[1], neck[0], neck[1])
2165
+
2166
+ if count > 1:
2167
+ # Draw shoulder-to-shoulder line
2168
+ dc.DrawLine(shoulder1[0], shoulder1[1], shoulder2[0], shoulder2[1])
2169
+ # Draw all the little branches
2170
+ for i in range(count):
2171
+ pt, stemPt = self.GetBranchingAttachmentPoint(attachment, i)
2172
+ dc.DrawLine(stemPt[0], stemPt[1], pt[0], pt[1])
2173
+
2174
+ if self.GetBranchStyle() & BRANCHING_ATTACHMENT_BLOB and count > 1:
2175
+ blobSize = 6.0
2176
+ dc.DrawEllipse(stemPt[0] - blobSize / 2.0, stemPt[1] - blobSize / 2.0, blobSize, blobSize)
2177
+
2178
+ def OnDrawBranches(self, dc, erase = False):
2179
+ """The draw branches handler."""
2180
+ if self._attachmentMode != ATTACHMENT_MODE_BRANCHING:
2181
+ return
2182
+ for i in range(self.GetNumberOfAttachments()):
2183
+ self.OnDrawBranchesAttachment(dc, i, erase)
2184
+
2185
+ def GetAttachmentPositionEdge(self, attachment, nth = 0, no_arcs = 1, line = None):
2186
+ """
2187
+ Only get the attachment position at the _edge_ of the shape,
2188
+ ignoring branching mode. This is used e.g. to indicate the edge of
2189
+ interest, not the point on the attachment branch.
2190
+
2191
+ :param `attachment`: the attachment ???
2192
+ :param `nth`: get nth attachment ???
2193
+ :param `no_arcs`: ???
2194
+ :param `line`: ???
2195
+
2196
+ """
2197
+ oldMode = self._attachmentMode
2198
+
2199
+ # Calculate as if to edge, not branch
2200
+ if self._attachmentMode == ATTACHMENT_MODE_BRANCHING:
2201
+ self._attachmentMode = ATTACHMENT_MODE_EDGE
2202
+ res = self.GetAttachmentPosition(attachment, nth, no_arcs, line)
2203
+ self._attachmentMode = oldMode
2204
+
2205
+ return res
2206
+
2207
+ def PhysicalToLogicalAttachment(self, physicalAttachment):
2208
+ """
2209
+ Rotate the standard attachment point from physical
2210
+ (0 is always North) to logical (0 -> 1 if rotated by 90 degrees)
2211
+
2212
+ :param `physicalAttachment`: ???
2213
+
2214
+ """
2215
+ if RoughlyEqual(self.GetRotation(), 0):
2216
+ i = physicalAttachment
2217
+ elif RoughlyEqual(self.GetRotation(), math.pi / 2.0):
2218
+ i = physicalAttachment - 1
2219
+ elif RoughlyEqual(self.GetRotation(), math.pi):
2220
+ i = physicalAttachment - 2
2221
+ elif RoughlyEqual(self.GetRotation(), 3 * math.pi / 2.0):
2222
+ i = physicalAttachment - 3
2223
+ else:
2224
+ # Can't handle -- assume the same
2225
+ return physicalAttachment
2226
+
2227
+ if i < 0:
2228
+ i += 4
2229
+
2230
+ return i
2231
+
2232
+ def LogicalToPhysicalAttachment(self, logicalAttachment):
2233
+ """
2234
+ Rotate the standard attachment point from logical
2235
+ to physical (0 is always North).
2236
+
2237
+ :param `logicalAttachment`: ???
2238
+
2239
+ """
2240
+ if RoughlyEqual(self.GetRotation(), 0):
2241
+ i = logicalAttachment
2242
+ elif RoughlyEqual(self.GetRotation(), math.pi / 2.0):
2243
+ i = logicalAttachment + 1
2244
+ elif RoughlyEqual(self.GetRotation(), math.pi):
2245
+ i = logicalAttachment + 2
2246
+ elif RoughlyEqual(self.GetRotation(), 3 * math.pi / 2.0):
2247
+ i = logicalAttachment + 3
2248
+ else:
2249
+ return logicalAttachment
2250
+
2251
+ if i > 3:
2252
+ i -= 4
2253
+
2254
+ return i
2255
+
2256
+ def Rotate(self, x, y, theta):
2257
+ """
2258
+ Rotate about the given axis by the given amount in radians.
2259
+
2260
+ :param `x`: the x position
2261
+ :param `y`: the y position
2262
+ :param `theta`: the theta
2263
+
2264
+ """
2265
+ self._rotation = theta
2266
+ if self._rotation < 0:
2267
+ self._rotation += 2 * math.pi
2268
+ elif self._rotation > 2 * math.pi:
2269
+ self._rotation -= 2 * math.pi
2270
+
2271
+ def GetBackgroundPen(self):
2272
+ """Return pen of the right colour for the background."""
2273
+ if self.GetCanvas():
2274
+ return wx.Pen(self.GetCanvas().GetBackgroundColour(), 1, wx.PENSTYLE_SOLID)
2275
+ return WhiteBackgroundPen
2276
+
2277
+ def GetBackgroundBrush(self):
2278
+ """Return brush of the right colour for the background."""
2279
+ if self.GetCanvas():
2280
+ return wx.Brush(self.GetCanvas().GetBackgroundColour(), wx.BRUSHSTYLE_SOLID)
2281
+ return WhiteBackgroundBrush
2282
+
2283
+ def GetX(self):
2284
+ """Get the x position of the centre of the shape."""
2285
+ return self._xpos
2286
+
2287
+ def GetY(self):
2288
+ """Get the y position of the centre of the shape."""
2289
+ return self._ypos
2290
+
2291
+ def SetX(self, x):
2292
+ """
2293
+ Set the x position of the shape.
2294
+
2295
+ :param `x`: the x position
2296
+ """
2297
+ self._xpos = x
2298
+
2299
+ def SetY(self, y):
2300
+ """
2301
+ Set the y position of the shape.
2302
+
2303
+ :param `y`: the y position
2304
+
2305
+ """
2306
+ self._ypos = y
2307
+
2308
+ def GetParent(self):
2309
+ """Get the parent of this shape, if it is part of a composite."""
2310
+ return self._parent
2311
+
2312
+ def SetParent(self, p):
2313
+ """Set the parent
2314
+
2315
+ :param `p`: the parent
2316
+
2317
+ """
2318
+ self._parent = p
2319
+
2320
+ def GetChildren(self):
2321
+ """Get the list of children for this shape."""
2322
+ return self._children
2323
+
2324
+ def GetDrawHandles(self):
2325
+ """Get the list of drawhandles."""
2326
+ return self._drawHandles
2327
+
2328
+ def GetEventHandler(self):
2329
+ """Get the event handler for this shape."""
2330
+ return self._eventHandler
2331
+
2332
+ def SetEventHandler(self, handler):
2333
+ """Set the event handler for this shape.
2334
+
2335
+ :param `handler`: an instance of :class:`ShapeEvtHandler`
2336
+
2337
+ """
2338
+ self._eventHandler = handler
2339
+
2340
+ def Recompute(self):
2341
+ """
2342
+ Recomputes any constraints associated with the shape.
2343
+
2344
+ Normally applicable to CompositeShapes only, but harmless for
2345
+ other classes of Shape.
2346
+ """
2347
+ return True
2348
+
2349
+ def IsHighlighted(self):
2350
+ """
2351
+ `True` if the shape is highlighted. Shape highlighting is unimplemented.
2352
+ """
2353
+ return self._highlighted
2354
+
2355
+ def GetSensitivityFilter(self):
2356
+ """
2357
+ Get the sensitivity filter, a bitlist of values.
2358
+
2359
+ See :meth:`Shape.SetSensitivityFilter`
2360
+
2361
+ """
2362
+ return self._sensitivity
2363
+
2364
+ def SetFixedSize(self, x, y):
2365
+ """
2366
+ Set the shape to be fixed size.
2367
+
2368
+ :param `x`: the width
2369
+ :param `y`: the height
2370
+
2371
+ """
2372
+ self._fixedWidth = x
2373
+ self._fixedHeight = y
2374
+
2375
+ def GetFixedSize(self):
2376
+ """
2377
+ Return flags indicating whether the shape is of fixed size in
2378
+ either direction.
2379
+ """
2380
+ return self._fixedWidth, self._fixedHeight
2381
+
2382
+ def GetFixedWidth(self):
2383
+ """`True` if the shape cannot be resized in the horizontal plane."""
2384
+ return self._fixedWidth
2385
+
2386
+ def GetFixedHeight(self):
2387
+ """`True` if the shape cannot be resized in the vertical plane."""
2388
+ return self._fixedHeight
2389
+
2390
+ def SetSpaceAttachments(self, sp):
2391
+ """
2392
+ Indicate whether lines should be spaced out evenly at the point
2393
+ they touch the node.
2394
+
2395
+ :param `sp`: if `True` space out evently, else they should join at a
2396
+ single point.
2397
+
2398
+ """
2399
+ self._spaceAttachments = sp
2400
+
2401
+ def GetSpaceAttachments(self):
2402
+ """
2403
+ Get whether lines should be spaced out evenly at the point they
2404
+ touch the node (True), or whether they should join at a single point
2405
+ (False).
2406
+ """
2407
+ return self._spaceAttachments
2408
+
2409
+ def SetCentreResize(self, cr):
2410
+ """
2411
+ Specify whether the shape is to be resized from the centre (the
2412
+ centre stands still) or from the corner or side being dragged (the
2413
+ other corner or side stands still).
2414
+ """
2415
+ self._centreResize = cr
2416
+
2417
+ def GetCentreResize(self):
2418
+ """
2419
+ `True` if the shape is to be resized from the centre (the centre stands
2420
+ still), or `False` if from the corner or side being dragged (the other
2421
+ corner or side stands still)
2422
+
2423
+ """
2424
+ return self._centreResize
2425
+
2426
+ def SetMaintainAspectRatio(self, ar):
2427
+ """
2428
+ Set whether a shape that resizes should not change the aspect ratio
2429
+ (width and height should be in the original proportion).
2430
+
2431
+ """
2432
+ self._maintainAspectRatio = ar
2433
+
2434
+ def GetMaintainAspectRatio(self):
2435
+ """`True` if shape keeps aspect ratio during resize."""
2436
+ return self._maintainAspectRatio
2437
+
2438
+ def GetLines(self):
2439
+ """Return the list of lines connected to this shape."""
2440
+ return self._lines
2441
+
2442
+ def SetDisableLabel(self, flag):
2443
+ """Set flag to `True` to stop the default region being shown."""
2444
+ self._disableLabel = flag
2445
+
2446
+ def GetDisableLabel(self):
2447
+ """`True` if the default region will not be shown, `False` otherwise."""
2448
+ return self._disableLabel
2449
+
2450
+ def SetAttachmentMode(self, mode):
2451
+ """
2452
+ Set the attachment mode.
2453
+
2454
+ :param `mode`: if `True` attachment points will be significant when
2455
+ drawing lines to and from this shape. If `False` lines will be drawn
2456
+ as if to the centre of the shape.
2457
+
2458
+ """
2459
+ self._attachmentMode = mode
2460
+
2461
+ def GetAttachmentMode(self):
2462
+ """
2463
+ Get the attachment mode.
2464
+
2465
+ See :meth:`Shape.SetAttachmentMode`
2466
+ """
2467
+ return self._attachmentMode
2468
+
2469
+ def SetId(self, i):
2470
+ """Set the integer identifier for this shape."""
2471
+ self._id = i
2472
+
2473
+ def GetId(self):
2474
+ """Get the integer identifier for this shape."""
2475
+ return self._id
2476
+
2477
+ def IsShown(self):
2478
+ """
2479
+ `True` if the shape is in a visible state, `False` otherwise.
2480
+
2481
+ :note: That this has nothing to do with whether the window is hidden
2482
+ or the shape has scrolled off the canvas; it refers to the internal
2483
+ visibility flag.
2484
+
2485
+ """
2486
+ return self._visible
2487
+
2488
+ def GetPen(self):
2489
+ """Get the pen used for drawing the shape's outline."""
2490
+ return self._pen
2491
+
2492
+ def GetBrush(self):
2493
+ """Get the brush used for filling the shape."""
2494
+ return self._brush
2495
+
2496
+ def GetNumberOfTextRegions(self):
2497
+ """Get the number of text regions for this shape."""
2498
+ return len(self._regions)
2499
+
2500
+ def GetRegions(self):
2501
+ """Get the list of ShapeRegions."""
2502
+ return self._regions
2503
+
2504
+ # Control points ('handles') redirect control to the actual shape, to
2505
+ # make it easier to override sizing behaviour.
2506
+ def OnSizingDragLeft(self, pt, draw, x, y, keys = 0, attachment = 0):
2507
+ """The sizing drag left handler."""
2508
+ bound_x, bound_y = self.GetBoundingBoxMin()
2509
+
2510
+ dc = wx.MemoryDC()
2511
+ dc.SelectObject(self.GetCanvas().GetBuffer())
2512
+ self.GetCanvas().PrepareDC(dc)
2513
+ dc.SetLogicalFunction(OGLRBLF)
2514
+
2515
+ dottedPen = wx.Pen(wx.BLACK, 1, wx.PENSTYLE_DOT)
2516
+ dc.SetPen(dottedPen)
2517
+ dc.SetBrush(wx.TRANSPARENT_BRUSH)
2518
+
2519
+ if self.GetCentreResize():
2520
+ # Maintain the same centre point
2521
+ new_width = 2.0 * abs(x - self.GetX())
2522
+ new_height = 2.0 * abs(y - self.GetY())
2523
+
2524
+ # Constrain sizing according to what control point you're dragging
2525
+ if pt._type == CONTROL_POINT_HORIZONTAL:
2526
+ if self.GetMaintainAspectRatio():
2527
+ new_height = bound_y * (new_width / bound_x)
2528
+ else:
2529
+ new_height = bound_y
2530
+ elif pt._type == CONTROL_POINT_VERTICAL:
2531
+ if self.GetMaintainAspectRatio():
2532
+ new_width = bound_x * (new_height / bound_y)
2533
+ else:
2534
+ new_width = bound_x
2535
+ elif pt._type == CONTROL_POINT_DIAGONAL and (keys & KEY_SHIFT):
2536
+ new_height = bound_y * (new_width / bound_x)
2537
+
2538
+ if self.GetFixedWidth():
2539
+ new_width = bound_x
2540
+
2541
+ if self.GetFixedHeight():
2542
+ new_height = bound_y
2543
+
2544
+ pt._controlPointDragEndWidth = new_width
2545
+ pt._controlPointDragEndHeight = new_height
2546
+
2547
+ self.GetEventHandler().OnDrawOutline(dc, self.GetX(), self.GetY(), new_width, new_height)
2548
+ else:
2549
+ # Don't maintain the same centre point
2550
+ newX1 = min(pt._controlPointDragStartX, x)
2551
+ newY1 = min(pt._controlPointDragStartY, y)
2552
+ newX2 = max(pt._controlPointDragStartX, x)
2553
+ newY2 = max(pt._controlPointDragStartY, y)
2554
+ if pt._type == CONTROL_POINT_HORIZONTAL:
2555
+ newY1 = pt._controlPointDragStartY
2556
+ newY2 = newY1 + pt._controlPointDragStartHeight
2557
+ elif pt._type == CONTROL_POINT_VERTICAL:
2558
+ newX1 = pt._controlPointDragStartX
2559
+ newX2 = newX1 + pt._controlPointDragStartWidth
2560
+ elif pt._type == CONTROL_POINT_DIAGONAL and (keys & KEY_SHIFT or self.GetMaintainAspectRatio()):
2561
+ newH = (newX2 - newX1) * (float(pt._controlPointDragStartHeight) / pt._controlPointDragStartWidth)
2562
+ if self.GetY() > pt._controlPointDragStartY:
2563
+ newY2 = newY1 + newH
2564
+ else:
2565
+ newY1 = newY2 - newH
2566
+
2567
+ newWidth = float(newX2 - newX1)
2568
+ newHeight = float(newY2 - newY1)
2569
+
2570
+ if pt._type == CONTROL_POINT_VERTICAL and self.GetMaintainAspectRatio():
2571
+ newWidth = bound_x * (newHeight / bound_y)
2572
+
2573
+ if pt._type == CONTROL_POINT_HORIZONTAL and self.GetMaintainAspectRatio():
2574
+ newHeight = bound_y * (newWidth / bound_x)
2575
+
2576
+ pt._controlPointDragPosX = newX1 + newWidth / 2.0
2577
+ pt._controlPointDragPosY = newY1 + newHeight / 2.0
2578
+ if self.GetFixedWidth():
2579
+ newWidth = bound_x
2580
+
2581
+ if self.GetFixedHeight():
2582
+ newHeight = bound_y
2583
+
2584
+ pt._controlPointDragEndWidth = newWidth
2585
+ pt._controlPointDragEndHeight = newHeight
2586
+ self.GetEventHandler().OnDrawOutline(dc, pt._controlPointDragPosX, pt._controlPointDragPosY, newWidth, newHeight)
2587
+
2588
+ def OnSizingBeginDragLeft(self, pt, x, y, keys = 0, attachment = 0):
2589
+ """The sizing begin drag left handler."""
2590
+ self._canvas.CaptureMouse()
2591
+
2592
+ dc = wx.MemoryDC()
2593
+ dc.SelectObject(self.GetCanvas().GetBuffer())
2594
+ self.GetCanvas().PrepareDC(dc)
2595
+ dc.SetLogicalFunction(OGLRBLF)
2596
+
2597
+ bound_x, bound_y = self.GetBoundingBoxMin()
2598
+ self.GetEventHandler().OnBeginSize(bound_x, bound_y)
2599
+
2600
+ # Choose the 'opposite corner' of the object as the stationary
2601
+ # point in case this is non-centring resizing.
2602
+ if pt.GetX() < self.GetX():
2603
+ pt._controlPointDragStartX = self.GetX() + bound_x / 2.0
2604
+ else:
2605
+ pt._controlPointDragStartX = self.GetX() - bound_x / 2.0
2606
+
2607
+ if pt.GetY() < self.GetY():
2608
+ pt._controlPointDragStartY = self.GetY() + bound_y / 2.0
2609
+ else:
2610
+ pt._controlPointDragStartY = self.GetY() - bound_y / 2.0
2611
+
2612
+ if pt._type == CONTROL_POINT_HORIZONTAL:
2613
+ pt._controlPointDragStartY = self.GetY() - bound_y / 2.0
2614
+ elif pt._type == CONTROL_POINT_VERTICAL:
2615
+ pt._controlPointDragStartX = self.GetX() - bound_x / 2.0
2616
+
2617
+ # We may require the old width and height
2618
+ pt._controlPointDragStartWidth = bound_x
2619
+ pt._controlPointDragStartHeight = bound_y
2620
+
2621
+ dottedPen = wx.Pen(wx.BLACK, 1, wx.PENSTYLE_DOT)
2622
+ dc.SetPen(dottedPen)
2623
+ dc.SetBrush(wx.TRANSPARENT_BRUSH)
2624
+
2625
+ if self.GetCentreResize():
2626
+ new_width = 2.0 * abs(x - self.GetX())
2627
+ new_height = 2.0 * abs(y - self.GetY())
2628
+
2629
+ # Constrain sizing according to what control point you're dragging
2630
+ if pt._type == CONTROL_POINT_HORIZONTAL:
2631
+ if self.GetMaintainAspectRatio():
2632
+ new_height = bound_y * (new_width / bound_x)
2633
+ else:
2634
+ new_height = bound_y
2635
+ elif pt._type == CONTROL_POINT_VERTICAL:
2636
+ if self.GetMaintainAspectRatio():
2637
+ new_width = bound_x * (new_height / bound_y)
2638
+ else:
2639
+ new_width = bound_x
2640
+ elif pt._type == CONTROL_POINT_DIAGONAL and (keys & KEY_SHIFT):
2641
+ new_height = bound_y * (new_width / bound_x)
2642
+
2643
+ if self.GetFixedWidth():
2644
+ new_width = bound_x
2645
+
2646
+ if self.GetFixedHeight():
2647
+ new_height = bound_y
2648
+
2649
+ pt._controlPointDragEndWidth = new_width
2650
+ pt._controlPointDragEndHeight = new_height
2651
+ self.GetEventHandler().OnDrawOutline(dc, self.GetX(), self.GetY(), new_width, new_height)
2652
+ else:
2653
+ # Don't maintain the same centre point
2654
+ newX1 = min(pt._controlPointDragStartX, x)
2655
+ newY1 = min(pt._controlPointDragStartY, y)
2656
+ newX2 = max(pt._controlPointDragStartX, x)
2657
+ newY2 = max(pt._controlPointDragStartY, y)
2658
+ if pt._type == CONTROL_POINT_HORIZONTAL:
2659
+ newY1 = pt._controlPointDragStartY
2660
+ newY2 = newY1 + pt._controlPointDragStartHeight
2661
+ elif pt._type == CONTROL_POINT_VERTICAL:
2662
+ newX1 = pt._controlPointDragStartX
2663
+ newX2 = newX1 + pt._controlPointDragStartWidth
2664
+ elif pt._type == CONTROL_POINT_DIAGONAL and (keys & KEY_SHIFT or self.GetMaintainAspectRatio()):
2665
+ newH = (newX2 - newX1) * (float(pt._controlPointDragStartHeight) / pt._controlPointDragStartWidth)
2666
+ if pt.GetY() > pt._controlPointDragStartY:
2667
+ newY2 = newY1 + newH
2668
+ else:
2669
+ newY1 = newY2 - newH
2670
+
2671
+ newWidth = float(newX2 - newX1)
2672
+ newHeight = float(newY2 - newY1)
2673
+
2674
+ if pt._type == CONTROL_POINT_VERTICAL and self.GetMaintainAspectRatio():
2675
+ newWidth = bound_x * (newHeight / bound_y)
2676
+
2677
+ if pt._type == CONTROL_POINT_HORIZONTAL and self.GetMaintainAspectRatio():
2678
+ newHeight = bound_y * (newWidth / bound_x)
2679
+
2680
+ pt._controlPointDragPosX = newX1 + newWidth / 2.0
2681
+ pt._controlPointDragPosY = newY1 + newHeight / 2.0
2682
+ if self.GetFixedWidth():
2683
+ newWidth = bound_x
2684
+
2685
+ if self.GetFixedHeight():
2686
+ newHeight = bound_y
2687
+
2688
+ pt._controlPointDragEndWidth = newWidth
2689
+ pt._controlPointDragEndHeight = newHeight
2690
+ self.GetEventHandler().OnDrawOutline(dc, pt._controlPointDragPosX, pt._controlPointDragPosY, newWidth, newHeight)
2691
+
2692
+ def OnSizingEndDragLeft(self, pt, x, y, keys = 0, attachment = 0):
2693
+ """The sizing end drag left handler."""
2694
+ dc = wx.MemoryDC()
2695
+ dc.SelectObject(self.GetCanvas().GetBuffer())
2696
+ self.GetCanvas().PrepareDC(dc)
2697
+
2698
+ if self._canvas.HasCapture():
2699
+ self._canvas.ReleaseMouse()
2700
+ dc.SetLogicalFunction(wx.COPY)
2701
+ self.Recompute()
2702
+ self.ResetControlPoints()
2703
+
2704
+ self.Erase(dc)
2705
+
2706
+ self.SetSize(pt._controlPointDragEndWidth, pt._controlPointDragEndHeight)
2707
+
2708
+ # The next operation could destroy this control point (it does for
2709
+ # label objects, via formatting the text), so save all values we're
2710
+ # going to use, or we'll be accessing garbage.
2711
+
2712
+ #return
2713
+
2714
+ if self.GetCentreResize():
2715
+ self.Move(dc, self.GetX(), self.GetY())
2716
+ else:
2717
+ self.Move(dc, pt._controlPointDragPosX, pt._controlPointDragPosY)
2718
+
2719
+ # Recursively redraw links if we have a composite
2720
+ if len(self.GetChildren()):
2721
+ self.DrawLinks(dc, -1, True)
2722
+
2723
+ width, height = self.GetBoundingBoxMax()
2724
+ self.GetEventHandler().OnEndSize(width, height)
2725
+
2726
+ if not self._canvas.GetQuickEditMode() and pt._eraseObject:
2727
+ self._canvas.Redraw(dc)
2728
+
2729
+
2730
+ class RectangleShape(Shape):
2731
+ """
2732
+ The :class:`wx.RectangleShape` class has rounded or square corners.
2733
+ """
2734
+ def __init__(self, w = 0.0, h = 0.0):
2735
+ """
2736
+ Default class constructor
2737
+
2738
+ :param float `w`: the width
2739
+ :param float `h`: the height
2740
+
2741
+ """
2742
+ Shape.__init__(self)
2743
+ self._width = w
2744
+ self._height = h
2745
+ self._cornerRadius = 0.0
2746
+ self.SetDefaultRegionSize()
2747
+
2748
+ def OnDraw(self, dc):
2749
+ """The draw handler."""
2750
+ x1 = self._xpos - self._width / 2.0
2751
+ y1 = self._ypos - self._height / 2.0
2752
+
2753
+ if self._shadowMode != SHADOW_NONE:
2754
+ if self._shadowBrush:
2755
+ dc.SetBrush(self._shadowBrush)
2756
+ dc.SetPen(TransparentPen)
2757
+
2758
+ if self._cornerRadius:
2759
+ dc.DrawRoundedRectangle(int(x1 + self._shadowOffsetX), int(y1 + self._shadowOffsetY), int(self._width), int(self._height), self._cornerRadius)
2760
+ else:
2761
+ dc.DrawRectangle(int(x1 + self._shadowOffsetX), int(y1 + self._shadowOffsetY), int(self._width), int(self._height))
2762
+
2763
+ if self._pen:
2764
+ if self._pen.GetWidth() == 0:
2765
+ dc.SetPen(TransparentPen)
2766
+ else:
2767
+ dc.SetPen(self._pen)
2768
+ if self._brush:
2769
+ dc.SetBrush(self._brush)
2770
+
2771
+ if self._cornerRadius:
2772
+ dc.DrawRoundedRectangle(int(x1), int(y1), int(self._width), int(self._height), self._cornerRadius)
2773
+ else:
2774
+ dc.DrawRectangle(int(x1), int(y1), int(self._width), int(self._height))
2775
+
2776
+ def GetBoundingBoxMin(self):
2777
+ """Get the bounding box minimum."""
2778
+ return self._width, self._height
2779
+
2780
+ def SetSize(self, x, y, recursive = False):
2781
+ """
2782
+ Set the size.
2783
+
2784
+ :param `x`: the width
2785
+ :param `y`: the height
2786
+ :param `recursive`: not used
2787
+
2788
+ """
2789
+ self.SetAttachmentSize(x, y)
2790
+ self._width = max(x, 1)
2791
+ self._height = max(y, 1)
2792
+ self.SetDefaultRegionSize()
2793
+
2794
+ def GetCornerRadius(self):
2795
+ """Get the radius of the rectangle's rounded corners."""
2796
+ return self._cornerRadius
2797
+
2798
+ def SetCornerRadius(self, rad):
2799
+ """
2800
+ Set the radius of the rectangle's rounded corners.
2801
+
2802
+ :param `rad`: If the radius is zero, a non-rounded rectangle will be
2803
+ drawn. If the radius is negative, the value is the proportion of the
2804
+ smaller dimension of the rectangle.
2805
+
2806
+ """
2807
+ self._cornerRadius = rad
2808
+
2809
+ # Assume (x1, y1) is centre of box (most generally, line end at box)
2810
+ def GetPerimeterPoint(self, x1, y1, x2, y2):
2811
+ """
2812
+ Get the perimeter point.
2813
+
2814
+ :param `x1`: ???
2815
+ :param `y1`: ???
2816
+ :param `x2`: ???
2817
+ :param `y2`: ???
2818
+
2819
+ """
2820
+ bound_x, bound_y = self.GetBoundingBoxMax()
2821
+ return FindEndForBox(bound_x, bound_y, self._xpos, self._ypos, x2, y2)
2822
+
2823
+ def GetWidth(self):
2824
+ """Get the width."""
2825
+ return self._width
2826
+
2827
+ def GetHeight(self):
2828
+ """Get the height."""
2829
+ return self._height
2830
+
2831
+ def SetWidth(self, w):
2832
+ """
2833
+ Set the width.
2834
+
2835
+ :param `w`: width to be set
2836
+
2837
+ """
2838
+ self._width = w
2839
+
2840
+ def SetHeight(self, h):
2841
+ """
2842
+ Set the height.
2843
+
2844
+ :param `h`: height to be set
2845
+
2846
+ """
2847
+ self._height = h
2848
+
2849
+
2850
+ class PolygonShape(Shape):
2851
+ """
2852
+ The :class:`PolygonShape` class shape is defined by a number of points
2853
+ passed to the object's constructor. It can be used to create new shapes
2854
+ such as diamonds and triangles.
2855
+ """
2856
+ def __init__(self):
2857
+ """
2858
+ Default class constructor
2859
+
2860
+ Does not follow above statement, should it? or is Create called
2861
+ automagically?
2862
+
2863
+ """
2864
+ Shape.__init__(self)
2865
+
2866
+ self._points = None
2867
+ self._originalPoints = None
2868
+
2869
+ def Create(self, the_points = None):
2870
+ """
2871
+ Takes a list of :class:`wx.Points` or tuples; each point is an offset
2872
+ from the centre.
2873
+ """
2874
+ self.ClearPoints()
2875
+
2876
+ if not the_points:
2877
+ self._originalPoints = []
2878
+ self._points = []
2879
+ else:
2880
+ self._originalPoints = the_points
2881
+
2882
+ # Duplicate the list of points
2883
+ self._points = []
2884
+ for point in the_points:
2885
+ new_point = wx.Point(int(point[0]), int(point[1]))
2886
+ self._points.append(new_point)
2887
+ self.CalculateBoundingBox()
2888
+ self._originalWidth = self._boundWidth
2889
+ self._originalHeight = self._boundHeight
2890
+ self.SetDefaultRegionSize()
2891
+
2892
+ def ClearPoints(self):
2893
+ """Clear the points."""
2894
+ self._points = []
2895
+ self._originalPoints = []
2896
+
2897
+ # Width and height. Centre of object is centre of box
2898
+ def GetBoundingBoxMin(self):
2899
+ """Get minimum bounding box."""
2900
+ return self._boundWidth, self._boundHeight
2901
+
2902
+ def GetPoints(self):
2903
+ """Return the internal list of polygon vertices."""
2904
+ return self._points
2905
+
2906
+ def GetOriginalPoints(self):
2907
+ """Get the original points."""
2908
+ return self._originalPoints
2909
+
2910
+ def GetOriginalWidth(self):
2911
+ """Get the original width."""
2912
+ return self._originalWidth
2913
+
2914
+ def GetOriginalHeight(self):
2915
+ """Get the original height."""
2916
+ return self._originalHeight
2917
+
2918
+ def SetOriginalWidth(self, w):
2919
+ """
2920
+ Set the original width.
2921
+
2922
+ :param `w`: the width
2923
+
2924
+ """
2925
+ self._originalWidth = w
2926
+
2927
+ def SetOriginalHeight(self, h):
2928
+ """
2929
+ Set the original height.
2930
+
2931
+ :param `w`: the height
2932
+
2933
+ """
2934
+ self._originalHeight = h
2935
+
2936
+ def CalculateBoundingBox(self):
2937
+ """Calculate the bounding box."""
2938
+ left = 10000
2939
+ right = -10000
2940
+ top = 10000
2941
+ bottom = -10000
2942
+
2943
+ for point in self._points:
2944
+ if point[0] < left:
2945
+ left = point[0]
2946
+ if point[0] > right:
2947
+ right = point[0]
2948
+
2949
+ if point[1] < top:
2950
+ top = point[1]
2951
+ if point[1] > bottom:
2952
+ bottom = point[1]
2953
+
2954
+ self._boundWidth = right - left
2955
+ self._boundHeight = bottom - top
2956
+
2957
+ def CalculatePolygonCentre(self):
2958
+ """
2959
+ Recalculates the centre of the polygon, and
2960
+ readjusts the point offsets accordingly.
2961
+ Necessary since the centre of the polygon
2962
+ is expected to be the real centre of the bounding
2963
+ box.
2964
+ """
2965
+ left = 10000
2966
+ right = -10000
2967
+ top = 10000
2968
+ bottom = -10000
2969
+
2970
+ for point in self._points:
2971
+ if point[0] < left:
2972
+ left = point[0]
2973
+ if point[0] > right:
2974
+ right = point[0]
2975
+
2976
+ if point[1] < top:
2977
+ top = point[1]
2978
+ if point[1] > bottom:
2979
+ bottom = point[1]
2980
+
2981
+ bwidth = right - left
2982
+ bheight = bottom - top
2983
+
2984
+ newCentreX = left + bwidth / 2.0
2985
+ newCentreY = top + bheight / 2.0
2986
+
2987
+ for i in range(len(self._points)):
2988
+ self._points[i] = self._points[i][0] - newCentreX, self._points[i][1] - newCentreY
2989
+ self._xpos += newCentreX
2990
+ self._ypos += newCentreY
2991
+
2992
+ def HitTest(self, x, y):
2993
+ """Hit text
2994
+
2995
+ :param `x`: the x position
2996
+ :param `y`: the y position
2997
+
2998
+ """
2999
+ # Imagine four lines radiating from this point. If all of these lines
3000
+ # hit the polygon, we're inside it, otherwise we're not. Obviously
3001
+ # we'd need more radiating lines to be sure of correct results for
3002
+ # very strange (concave) shapes.
3003
+ endPointsX = [x, x + 1000, x, x - 1000]
3004
+ endPointsY = [y - 1000, y, y + 1000, y]
3005
+
3006
+ xpoints = []
3007
+ ypoints = []
3008
+
3009
+ for point in self._points:
3010
+ xpoints.append(point[0] + self._xpos)
3011
+ ypoints.append(point[1] + self._ypos)
3012
+
3013
+ # We assume it's inside the polygon UNLESS one or more
3014
+ # lines don't hit the outline.
3015
+ isContained = True
3016
+
3017
+ for i in range(4):
3018
+ if not PolylineHitTest(xpoints, ypoints, x, y, endPointsX[i], endPointsY[i]):
3019
+ isContained = False
3020
+
3021
+ if not isContained:
3022
+ return False
3023
+
3024
+ nearest_attachment = 0
3025
+
3026
+ # If a hit, check the attachment points within the object
3027
+ nearest = 999999
3028
+
3029
+ for i in range(self.GetNumberOfAttachments()):
3030
+ e = self.GetAttachmentPositionEdge(i)
3031
+ if e:
3032
+ xp, yp = e
3033
+ l = math.sqrt((xp - x) * (xp - x) + (yp - y) * (yp - y))
3034
+ if l < nearest:
3035
+ nearest = l
3036
+ nearest_attachment = i
3037
+
3038
+ return nearest_attachment, nearest
3039
+
3040
+ # Really need to be able to reset the shape! Otherwise, if the
3041
+ # points ever go to zero, we've lost it, and can't resize.
3042
+ def SetSize(self, new_width, new_height, recursive = True):
3043
+ """
3044
+ Set the size
3045
+
3046
+ :param `new_width`: the width
3047
+ :param `new_height`: the height
3048
+ :param `recursive`: not used
3049
+
3050
+ """
3051
+ self.SetAttachmentSize(new_width, new_height)
3052
+
3053
+ # Multiply all points by proportion of new size to old size
3054
+ x_proportion = abs(float(new_width) / self._originalWidth)
3055
+ y_proportion = abs(float(new_height) / self._originalHeight)
3056
+
3057
+ for i in range(max(len(self._points), len(self._originalPoints))):
3058
+ self._points[i] = wx.Point(self._originalPoints[i][0] * x_proportion, self._originalPoints[i][1] * y_proportion)
3059
+
3060
+ self._boundWidth = abs(new_width)
3061
+ self._boundHeight = abs(new_height)
3062
+ self.SetDefaultRegionSize()
3063
+
3064
+ # Make the original points the same as the working points
3065
+ def UpdateOriginalPoints(self):
3066
+ """
3067
+ If we've changed the shape, must make the original points match the
3068
+ working points with this function.
3069
+
3070
+ """
3071
+ self._originalPoints = []
3072
+
3073
+ for point in self._points:
3074
+ original_point = wx.RealPoint(point[0], point[1])
3075
+ self._originalPoints.append(original_point)
3076
+
3077
+ self.CalculateBoundingBox()
3078
+ self._originalWidth = self._boundWidth
3079
+ self._originalHeight = self._boundHeight
3080
+
3081
+ def AddPolygonPoint(self, pos):
3082
+ """
3083
+ Add a control point after the given point.
3084
+
3085
+ :param `pos`: position of point
3086
+
3087
+ """
3088
+ try:
3089
+ firstPoint = self._points[pos]
3090
+ except ValueError:
3091
+ firstPoint = self._points[0]
3092
+
3093
+ try:
3094
+ secondPoint = self._points[pos + 1]
3095
+ except ValueError:
3096
+ secondPoint = self._points[0]
3097
+
3098
+ x = (secondPoint[0] - firstPoint[0]) / 2.0 + firstPoint[0]
3099
+ y = (secondPoint[1] - firstPoint[1]) / 2.0 + firstPoint[1]
3100
+ point = wx.RealPoint(x, y)
3101
+
3102
+ if pos >= len(self._points) - 1:
3103
+ self._points.append(point)
3104
+ else:
3105
+ self._points.insert(pos + 1, point)
3106
+
3107
+ self.UpdateOriginalPoints()
3108
+
3109
+ if self._selected:
3110
+ self.DeleteControlPoints()
3111
+ self.MakeControlPoints()
3112
+
3113
+ def DeletePolygonPoint(self, pos):
3114
+ """
3115
+
3116
+ Delete the given control point.
3117
+
3118
+ :param `pos`: position of point
3119
+
3120
+ """
3121
+ if pos < len(self._points):
3122
+ del self._points[pos]
3123
+ self.UpdateOriginalPoints()
3124
+ if self._selected:
3125
+ self.DeleteControlPoints()
3126
+ self.MakeControlPoints()
3127
+
3128
+ # Assume (x1, y1) is centre of box (most generally, line end at box)
3129
+ def GetPerimeterPoint(self, x1, y1, x2, y2):
3130
+ """
3131
+ Get the perimeter point.
3132
+
3133
+ :param `x1`: the x1 position
3134
+ :param `y1`: the y1 position
3135
+ :param `x2`: the x2 position
3136
+ :param `y2`: the y2 position
3137
+
3138
+ """
3139
+ # First check for situation where the line is vertical,
3140
+ # and we would want to connect to a point on that vertical --
3141
+ # oglFindEndForPolyline can't cope with this (the arrow
3142
+ # gets drawn to the wrong place).
3143
+ if self._attachmentMode == ATTACHMENT_MODE_NONE and x1 == x2:
3144
+ # Look for the point we'd be connecting to. This is
3145
+ # a heuristic...
3146
+ for point in self._points:
3147
+ if point[0] == 0:
3148
+ if y2 > y1 and point[1] > 0:
3149
+ return point[0] + self._xpos, point[1] + self._ypos
3150
+ elif y2 < y1 and point[1] < 0:
3151
+ return point[0] + self._xpos, point[1] + self._ypos
3152
+
3153
+ xpoints = []
3154
+ ypoints = []
3155
+ for point in self._points:
3156
+ xpoints.append(point[0] + self._xpos)
3157
+ ypoints.append(point[1] + self._ypos)
3158
+
3159
+ return FindEndForPolyline(xpoints, ypoints, x1, y1, x2, y2)
3160
+
3161
+ def OnDraw(self, dc):
3162
+ """The draw handler."""
3163
+ if self._shadowMode != SHADOW_NONE:
3164
+ if self._shadowBrush:
3165
+ dc.SetBrush(self._shadowBrush)
3166
+ dc.SetPen(TransparentPen)
3167
+
3168
+ dc.DrawPolygon(self._points, self._xpos + self._shadowOffsetX, self._ypos, self._shadowOffsetY)
3169
+
3170
+ if self._pen:
3171
+ if self._pen.GetWidth() == 0:
3172
+ dc.SetPen(TransparentPen)
3173
+ else:
3174
+ dc.SetPen(self._pen)
3175
+ if self._brush:
3176
+ dc.SetBrush(self._brush)
3177
+ dc.DrawPolygon(self._points, int(self._xpos), int(self._ypos))
3178
+
3179
+ def OnDrawOutline(self, dc, x, y, w, h):
3180
+ """The draw outline handler."""
3181
+ dc.SetBrush(wx.TRANSPARENT_BRUSH)
3182
+ # Multiply all points by proportion of new size to old size
3183
+ x_proportion = abs(float(w) / self._originalWidth)
3184
+ y_proportion = abs(float(h) / self._originalHeight)
3185
+
3186
+ intPoints = []
3187
+ for point in self._originalPoints:
3188
+ intPoints.append(wx.Point(int(x_proportion * point[0]), int(y_proportion * point[1])))
3189
+ dc.DrawPolygon(intPoints, int(x), int(y))
3190
+
3191
+ # Make as many control points as there are vertices
3192
+ def MakeControlPoints(self):
3193
+ """Make control points."""
3194
+ for point in self._points:
3195
+ control = PolygonControlPoint(self._canvas, self, CONTROL_POINT_SIZE, point, point[0], point[1])
3196
+ self._canvas.AddShape(control)
3197
+ self._controlPoints.append(control)
3198
+
3199
+ def ResetControlPoints(self):
3200
+ """Reset control points."""
3201
+ for i in range(min(len(self._points), len(self._controlPoints))):
3202
+ point = self._points[i]
3203
+ self._controlPoints[i]._xoffset = point[0]
3204
+ self._controlPoints[i]._yoffset = point[1]
3205
+ self._controlPoints[i].polygonVertex = point
3206
+
3207
+ def GetNumberOfAttachments(self):
3208
+ """Get number of attachments."""
3209
+ maxN = max(len(self._points) - 1, 0)
3210
+ for point in self._attachmentPoints:
3211
+ if point._id > maxN:
3212
+ maxN = point._id
3213
+ return maxN + 1
3214
+
3215
+ def GetAttachmentPosition(self, attachment, nth = 0, no_arcs = 1, line = None):
3216
+ """
3217
+ Get attachment position.
3218
+
3219
+ :param `attachment`: the attachment ???
3220
+ :param `nth`: get nth attachment ???
3221
+ :param `no_arcs`: ???
3222
+ :param `line`: ???
3223
+
3224
+ """
3225
+ if self._attachmentMode == ATTACHMENT_MODE_EDGE and self._points and attachment < len(self._points):
3226
+ point = self._points[0]
3227
+ return point[0] + self._xpos, point[1] + self._ypos
3228
+ return Shape.GetAttachmentPosition(self, attachment, nth, no_arcs, line)
3229
+
3230
+ def AttachmentIsValid(self, attachment):
3231
+ """
3232
+ Is attachment valid?
3233
+
3234
+ :param `attachment`: ???
3235
+
3236
+ """
3237
+ if not self._points:
3238
+ return False
3239
+
3240
+ if attachment >= 0 and attachment < len(self._points):
3241
+ return True
3242
+
3243
+ for point in self._attachmentPoints:
3244
+ if point._id == attachment:
3245
+ return True
3246
+
3247
+ return False
3248
+
3249
+ def Rotate(self, x, y, theta):
3250
+ """
3251
+ Rotate about the given axis by the given amount in radians.
3252
+
3253
+ :param `x`: the x position
3254
+ :param `y`: the y position
3255
+ :param `theta`: the theta
3256
+
3257
+ """
3258
+
3259
+ actualTheta = theta - self._rotation
3260
+
3261
+ # Rotate attachment points
3262
+ sinTheta = math.sin(actualTheta)
3263
+ cosTheta = math.cos(actualTheta)
3264
+
3265
+ for point in self._attachmentPoints:
3266
+ x1 = point._x
3267
+ y1 = point._y
3268
+
3269
+ point._x = x1 * cosTheta - y1 * sinTheta + x * (1 - cosTheta) + y * sinTheta
3270
+ point._y = x1 * sinTheta + y1 * cosTheta + y * (1 - cosTheta) + x * sinTheta
3271
+
3272
+ for i in range(len(self._points)):
3273
+ x1, y1 = self._points[i]
3274
+
3275
+ self._points[i] = x1 * cosTheta - y1 * sinTheta + x * (1 - cosTheta) + y * sinTheta, x1 * sinTheta + y1 * cosTheta + y * (1 - cosTheta) + x * sinTheta
3276
+
3277
+ for i in range(len(self._originalPoints)):
3278
+ x1, y1 = self._originalPoints[i]
3279
+
3280
+ self._originalPoints[i] = x1 * cosTheta - y1 * sinTheta + x * (1 - cosTheta) + y * sinTheta, x1 * sinTheta + y1 * cosTheta + y * (1 - cosTheta) + x * sinTheta
3281
+
3282
+ # Added by Pierre Hjälm. If we don't do this the outline will be
3283
+ # the wrong size. Hopefully it won't have any ill effects.
3284
+ self.UpdateOriginalPoints()
3285
+
3286
+ self._rotation = theta
3287
+
3288
+ self.CalculatePolygonCentre()
3289
+ self.CalculateBoundingBox()
3290
+ self.ResetControlPoints()
3291
+
3292
+ # Control points ('handles') redirect control to the actual shape, to
3293
+ # make it easier to override sizing behaviour.
3294
+ def OnSizingDragLeft(self, pt, draw, x, y, keys = 0, attachment = 0):
3295
+ """The sizing drag left handler."""
3296
+ dc = wx.MemoryDC()
3297
+ dc.SelectObject(self.GetCanvas().GetBuffer())
3298
+ self.GetCanvas().PrepareDC(dc)
3299
+ dc.SetLogicalFunction(OGLRBLF)
3300
+
3301
+ dottedPen = wx.Pen(wx.BLACK, 1, wx.PENSTYLE_DOT)
3302
+ dc.SetPen(dottedPen)
3303
+ dc.SetBrush(wx.TRANSPARENT_BRUSH)
3304
+
3305
+ # Code for CTRL-drag in C++ version commented out
3306
+
3307
+ pt.CalculateNewSize(x, y)
3308
+
3309
+ self.GetEventHandler().OnDrawOutline(dc, self.GetX(), self.GetY(), pt.GetNewSize()[0], pt.GetNewSize()[1])
3310
+
3311
+ def OnSizingBeginDragLeft(self, pt, x, y, keys = 0, attachment = 0):
3312
+ """The sizing begin drag left handler."""
3313
+ dc = wx.MemoryDC()
3314
+ dc.SelectObject(self.GetCanvas().GetBuffer())
3315
+ self.GetCanvas().PrepareDC(dc)
3316
+ dc.SetLogicalFunction(OGLRBLF)
3317
+
3318
+ self.Erase(dc)
3319
+
3320
+ bound_x, bound_y = self.GetBoundingBoxMin()
3321
+
3322
+ dist = math.sqrt((x - self.GetX()) * (x - self.GetX()) + (y - self.GetY()) * (y - self.GetY()))
3323
+
3324
+ pt._originalDistance = dist
3325
+ pt._originalSize[0] = bound_x
3326
+ pt._originalSize[1] = bound_y
3327
+
3328
+ if pt._originalDistance == 0:
3329
+ pt._originalDistance = 0.0001
3330
+
3331
+ dottedPen = wx.Pen(wx.BLACK, 1, wx.PENSTYLE_DOT)
3332
+ dc.SetPen(dottedPen)
3333
+ dc.SetBrush(wx.TRANSPARENT_BRUSH)
3334
+
3335
+ # Code for CTRL-drag in C++ version commented out
3336
+
3337
+ pt.CalculateNewSize(x, y)
3338
+
3339
+ self.GetEventHandler().OnDrawOutline(dc, self.GetX(), self.GetY(), pt.GetNewSize()[0], pt.GetNewSize()[1])
3340
+
3341
+ self._canvas.CaptureMouse()
3342
+
3343
+ def OnSizingEndDragLeft(self, pt, x, y, keys = 0, attachment = 0):
3344
+ """The sizing end drag left handler."""
3345
+ dc = wx.MemoryDC()
3346
+ dc.SelectObject(self.GetCanvas().GetBuffer())
3347
+ self.GetCanvas().PrepareDC(dc)
3348
+
3349
+ if self._canvas.HasCapture():
3350
+ self._canvas.ReleaseMouse()
3351
+ dc.SetLogicalFunction(wx.COPY)
3352
+
3353
+ # If we're changing shape, must reset the original points
3354
+ if keys & KEY_CTRL:
3355
+ self.CalculateBoundingBox()
3356
+ self.CalculatePolygonCentre()
3357
+ else:
3358
+ self.SetSize(pt.GetNewSize()[0], pt.GetNewSize()[1])
3359
+
3360
+ self.Recompute()
3361
+ self.ResetControlPoints()
3362
+ self.Move(dc, self.GetX(), self.GetY())
3363
+ if not self._canvas.GetQuickEditMode():
3364
+ self._canvas.Redraw(dc)
3365
+
3366
+
3367
+ class EllipseShape(Shape):
3368
+ """
3369
+ The :class:`EllipseShape` class behaves similarly to the
3370
+ :class`RectangleShape` but is elliptical.
3371
+
3372
+ """
3373
+ def __init__(self, w, h):
3374
+ """
3375
+ Default class constructor
3376
+
3377
+ :param `w`: the width
3378
+ :param `h`: the height
3379
+
3380
+ """
3381
+ Shape.__init__(self)
3382
+ self._width = w
3383
+ self._height = h
3384
+ self.SetDefaultRegionSize()
3385
+
3386
+ def GetBoundingBoxMin(self):
3387
+ """Get the minimum bounding box."""
3388
+ return self._width, self._height
3389
+
3390
+ def GetPerimeterPoint(self, x1, y1, x2, y2):
3391
+ """
3392
+ Get the perimeter point.
3393
+
3394
+ :param `x1`: the x1 position
3395
+ :param `y1`: the y1 position
3396
+ :param `x2`: the x2 position
3397
+ :param `y2`: the y2 position
3398
+
3399
+ """
3400
+ bound_x, bound_y = self.GetBoundingBoxMax()
3401
+
3402
+ return DrawArcToEllipse(self._xpos, self._ypos, bound_x, bound_y, x2, y2, x1, y1)
3403
+
3404
+ def GetWidth(self):
3405
+ """Get the width."""
3406
+ return self._width
3407
+
3408
+ def GetHeight(self):
3409
+ """Get the height."""
3410
+ return self._height
3411
+
3412
+ def SetWidth(self, w):
3413
+ """
3414
+ Set the width.
3415
+
3416
+ :param `w`: the width
3417
+
3418
+ """
3419
+ self._width = w
3420
+
3421
+ def SetHeight(self, h):
3422
+ """
3423
+ Set the height.
3424
+
3425
+ :param `h`: the height
3426
+
3427
+ """
3428
+ self._height = h
3429
+
3430
+ def OnDraw(self, dc):
3431
+ """The draw handler."""
3432
+ if self._shadowMode != SHADOW_NONE:
3433
+ if self._shadowBrush:
3434
+ dc.SetBrush(self._shadowBrush)
3435
+ dc.SetPen(TransparentPen)
3436
+ dc.DrawEllipse(self._xpos - self.GetWidth() / 2.0 + self._shadowOffsetX,
3437
+ self._ypos - self.GetHeight() / 2.0 + self._shadowOffsetY,
3438
+ self.GetWidth(), self.GetHeight())
3439
+
3440
+ if self._pen:
3441
+ if self._pen.GetWidth() == 0:
3442
+ dc.SetPen(TransparentPen)
3443
+ else:
3444
+ dc.SetPen(self._pen)
3445
+ if self._brush:
3446
+ dc.SetBrush(self._brush)
3447
+ dc.DrawEllipse(int(self._xpos - self.GetWidth() / 2.0), int(self._ypos - self.GetHeight() / 2.0), int(self.GetWidth()), int(self.GetHeight()))
3448
+
3449
+ def SetSize(self, x, y, recursive = True):
3450
+ """
3451
+ Set the size.
3452
+
3453
+ :param `x`: the width
3454
+ :param `y`: the height
3455
+ :recursive: not used
3456
+
3457
+ """
3458
+ self.SetAttachmentSize(x, y)
3459
+ self._width = x
3460
+ self._height = y
3461
+ self.SetDefaultRegionSize()
3462
+
3463
+ def GetNumberOfAttachments(self):
3464
+ """Get number of attachments."""
3465
+ return Shape.GetNumberOfAttachments(self)
3466
+
3467
+ # There are 4 attachment points on an ellipse - 0 = top, 1 = right,
3468
+ # 2 = bottom, 3 = left.
3469
+ def GetAttachmentPosition(self, attachment, nth = 0, no_arcs = 1, line = None):
3470
+ """
3471
+ Get attachment position.
3472
+
3473
+ :param `attachment`: the attachment ???
3474
+ :param `nth`: get nth attachment ???
3475
+ :param `no_arcs`: ???
3476
+ :param `line`: ???
3477
+
3478
+ """
3479
+ if self._attachmentMode == ATTACHMENT_MODE_BRANCHING:
3480
+ return Shape.GetAttachmentPosition(self, attachment, nth, no_arcs, line)
3481
+
3482
+ if self._attachmentMode != ATTACHMENT_MODE_NONE:
3483
+ top = self._ypos + self._height / 2.0
3484
+ bottom = self._ypos - self._height / 2.0
3485
+ left = self._xpos - self._width / 2.0
3486
+ right = self._xpos + self._width / 2.0
3487
+
3488
+ physicalAttachment = self.LogicalToPhysicalAttachment(attachment)
3489
+
3490
+ if physicalAttachment == 0:
3491
+ if self._spaceAttachments:
3492
+ x = left + (nth + 1) * self._width / (no_arcs + 1.0)
3493
+ else:
3494
+ x = self._xpos
3495
+ y = top
3496
+ # We now have the point on the bounding box: but get the point
3497
+ # on the ellipse by imagining a vertical line from
3498
+ # (x, self._ypos - self._height - 500) to (x, self._ypos) intersecting
3499
+ # the ellipse.
3500
+
3501
+ return DrawArcToEllipse(self._xpos, self._ypos, self._width, self._height, x, self._ypos - self._height - 500, x, self._ypos)
3502
+ elif physicalAttachment == 1:
3503
+ x = right
3504
+ if self._spaceAttachments:
3505
+ y = bottom + (nth + 1) * self._height / (no_arcs + 1.0)
3506
+ else:
3507
+ y = self._ypos
3508
+ return DrawArcToEllipse(self._xpos, self._ypos, self._width, self._height, self._xpos + self._width + 500, y, self._xpos, y)
3509
+ elif physicalAttachment == 2:
3510
+ if self._spaceAttachments:
3511
+ x = left + (nth + 1) * self._width / (no_arcs + 1.0)
3512
+ else:
3513
+ x = self._xpos
3514
+ y = bottom
3515
+ return DrawArcToEllipse(self._xpos, self._ypos, self._width, self._height, x, self._ypos + self._height + 500, x, self._ypos)
3516
+ elif physicalAttachment == 3:
3517
+ x = left
3518
+ if self._spaceAttachments:
3519
+ y = bottom + (nth + 1) * self._height / (no_arcs + 1.0)
3520
+ else:
3521
+ y = self._ypos
3522
+ return DrawArcToEllipse(self._xpos, self._ypos, self._width, self._height, self._xpos - self._width - 500, y, self._xpos, y)
3523
+ else:
3524
+ return Shape.GetAttachmentPosition(self, attachment, x, y, nth, no_arcs, line)
3525
+ else:
3526
+ return self._xpos, self._ypos
3527
+
3528
+
3529
+ class CircleShape(EllipseShape):
3530
+ """
3531
+ The :class:`CircleShape` class is an :class:`EllipseShape` whose width
3532
+ and height are the same.
3533
+ """
3534
+ def __init__(self, diameter):
3535
+ """
3536
+ Default class constructor
3537
+
3538
+ :param `diameter`: the diameter
3539
+
3540
+ """
3541
+ EllipseShape.__init__(self, diameter, diameter)
3542
+ self.SetMaintainAspectRatio(True)
3543
+
3544
+ def GetPerimeterPoint(self, x1, y1, x2, y2):
3545
+ """
3546
+ Get the perimeter point.
3547
+
3548
+ :param `x1`: ???
3549
+ :param `y1`: ???
3550
+ :param `x2`: ???
3551
+ :param `y2`: ???
3552
+ :returns: ???
3553
+
3554
+ """
3555
+ return FindEndForCircle(self._width / 2.0, self._xpos, self._ypos, x2, y2)
3556
+
3557
+
3558
+ class TextShape(RectangleShape):
3559
+ """
3560
+ The :class:`TextShape` class like :class:`wx.RectangleShape` but only the
3561
+ text is displayed.
3562
+ """
3563
+ def __init__(self, width, height):
3564
+ """
3565
+ Default class constructor
3566
+
3567
+ :param `width`: the width
3568
+ :param `height`: the height
3569
+
3570
+ """
3571
+ RectangleShape.__init__(self, width, height)
3572
+
3573
+ def OnDraw(self, dc):
3574
+ """not implemented???"""
3575
+ pass
3576
+
3577
+
3578
+ class ShapeRegion(object):
3579
+ """The :class:`ShapeRegion` class."""
3580
+ def __init__(self, region = None):
3581
+ """
3582
+ Default class constructor
3583
+
3584
+ :param `region`: a parent region or None???
3585
+
3586
+ """
3587
+ if region:
3588
+ self._regionText = region._regionText
3589
+ self._regionName = region._regionName
3590
+ self._textColour = region._textColour
3591
+
3592
+ self._font = region._font
3593
+ self._minHeight = region._minHeight
3594
+ self._minWidth = region._minWidth
3595
+ self._width = region._width
3596
+ self._height = region._height
3597
+ self._x = region._x
3598
+ self._y = region._y
3599
+
3600
+ self._regionProportionX = region._regionProportionX
3601
+ self._regionProportionY = region._regionProportionY
3602
+ self._formatMode = region._formatMode
3603
+ self._actualColourObject = region._actualColourObject
3604
+ self._actualPenObject = None
3605
+ self._penStyle = region._penStyle
3606
+ self._penColour = region._penColour
3607
+
3608
+ self.ClearText()
3609
+ for line in region._formattedText:
3610
+ new_line = ShapeTextLine(line.GetX(), line.GetY(), line.GetText())
3611
+ self._formattedText.append(new_line)
3612
+ else:
3613
+ self._regionText = ""
3614
+ self._font = NormalFont
3615
+ self._minHeight = 5.0
3616
+ self._minWidth = 5.0
3617
+ self._width = 0.0
3618
+ self._height = 0.0
3619
+ self._x = 0.0
3620
+ self._y = 0.0
3621
+
3622
+ self._regionProportionX = -1.0
3623
+ self._regionProportionY = -1.0
3624
+ self._formatMode = FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT
3625
+ self._regionName = ""
3626
+ self._textColour = "BLACK"
3627
+ self._penColour = "BLACK"
3628
+ self._penStyle = wx.PENSTYLE_SOLID
3629
+ self._actualColourObject = wx.TheColourDatabase.Find("BLACK")
3630
+ self._actualPenObject = None
3631
+
3632
+ self._formattedText = []
3633
+
3634
+ def ClearText(self):
3635
+ """Clear the text."""
3636
+ self._formattedText = []
3637
+
3638
+ def SetFont(self, f):
3639
+ """
3640
+ Set the font.
3641
+
3642
+ :param `f`: an instance of :class:`wx.Font`
3643
+ """
3644
+ self._font = f
3645
+
3646
+ def SetMinSize(self, w, h):
3647
+ """
3648
+ Set the minimum size.
3649
+
3650
+ :param `w`: the minimum width
3651
+ :Param `h`: the minimum height
3652
+
3653
+ """
3654
+ self._minWidth = w
3655
+ self._minHeight = h
3656
+
3657
+ def SetSize(self, w, h):
3658
+ """
3659
+ Set the size.
3660
+
3661
+ :param `w`: the width
3662
+ :Param `h`: the jeight
3663
+
3664
+ """
3665
+ self._width = w
3666
+ self._height = h
3667
+
3668
+ def SetPosition(self, xp, yp):
3669
+ """
3670
+ Set the position.
3671
+
3672
+ :param `xp`: the x position
3673
+ :Param `yp`: the y position
3674
+
3675
+ """
3676
+ self._x = xp
3677
+ self._y = yp
3678
+
3679
+ def SetProportions(self, xp, yp):
3680
+ """
3681
+ Set the proportions.
3682
+
3683
+ :param `xp`: the x region proportion
3684
+ :Param `yp`: the y region proportion
3685
+
3686
+ """
3687
+ self._regionProportionX = xp
3688
+ self._regionProportionY = yp
3689
+
3690
+ def SetFormatMode(self, mode):
3691
+ """
3692
+ Set the format mode of the region.
3693
+
3694
+ :param `mode`: can be a bit list of the following
3695
+
3696
+ ============================== ==============================
3697
+ Format mode Description
3698
+ ============================== ==============================
3699
+ `FORMAT_NONE` No formatting
3700
+ `FORMAT_CENTRE_HORIZ` Horizontal centring
3701
+ `FORMAT_CENTRE_VERT` Vertical centring
3702
+ ============================== ==============================
3703
+
3704
+ """
3705
+ self._formatMode = mode
3706
+
3707
+ def SetColour(self, col):
3708
+ """
3709
+ Set the colour.
3710
+
3711
+ :param str `col`: a valid colour name,
3712
+ see :class:`wx.ColourDatabase`
3713
+
3714
+ """
3715
+ self._textColour = col
3716
+ self._actualColourObject = col
3717
+
3718
+ def GetActualColourObject(self):
3719
+ """Get the actual colour object from the :class:`wx.ColourDatabase`."""
3720
+ self._actualColourObject = wx.TheColourDatabase.Find(self.GetColour())
3721
+ return self._actualColourObject
3722
+
3723
+ def SetPenColour(self, col):
3724
+ """
3725
+ Set the pen colour.
3726
+
3727
+ :param str `col`: a valid colour name,
3728
+ see :class:`wx.ColourDatabase`
3729
+
3730
+ """
3731
+ self._penColour = col
3732
+ self._actualPenObject = None
3733
+
3734
+ def GetActualPen(self):
3735
+ """
3736
+ Get actual pen.
3737
+
3738
+ :note: Returns NULL if the pen is invisible
3739
+ (different to pen being transparent; indicates that
3740
+ region boundary should not be drawn.)
3741
+
3742
+ """
3743
+ if self._actualPenObject:
3744
+ return self._actualPenObject
3745
+
3746
+ if not self._penColour:
3747
+ return None
3748
+ if self._penColour=="Invisible":
3749
+ return None
3750
+ self._actualPenObject = wx.Pen(self._penColour, 1, self._penStyle)
3751
+ return self._actualPenObject
3752
+
3753
+ def SetText(self, s):
3754
+ """
3755
+ Set the text.
3756
+
3757
+ :param str `s`: the text
3758
+
3759
+ """
3760
+ self._regionText = s
3761
+
3762
+ def SetName(self, s):
3763
+ """
3764
+ Set the name.
3765
+
3766
+ :param str `s`: the name
3767
+
3768
+ """
3769
+ self._regionName = s
3770
+
3771
+ def GetText(self):
3772
+ """Get the text."""
3773
+ return self._regionText
3774
+
3775
+ def GetFont(self):
3776
+ """Get the font."""
3777
+ return self._font
3778
+
3779
+ def GetMinSize(self):
3780
+ """Get the minimum size."""
3781
+ return self._minWidth, self._minHeight
3782
+
3783
+ def GetProportion(self):
3784
+ """Get the proportion."""
3785
+ return self._regionProportionX, self._regionProportionY
3786
+
3787
+ def GetSize(self):
3788
+ """Get the size."""
3789
+ return self._width, self._height
3790
+
3791
+ def GetPosition(self):
3792
+ """Get the position."""
3793
+ return self._x, self._y
3794
+
3795
+ def GetFormatMode(self):
3796
+ """Get the format mode."""
3797
+ return self._formatMode
3798
+
3799
+ def GetName(self):
3800
+ """Get the name."""
3801
+ return self._regionName
3802
+
3803
+ def GetColour(self):
3804
+ """Get the colour."""
3805
+ return self._textColour
3806
+
3807
+ def GetFormattedText(self):
3808
+ """Get the formatted text."""
3809
+ return self._formattedText
3810
+
3811
+ def GetPenColour(self):
3812
+ """Get the pen colour"""
3813
+ return self._penColour
3814
+
3815
+ def GetPenStyle(self):
3816
+ """Get the pen style."""
3817
+ return self._penStyle
3818
+
3819
+ def SetPenStyle(self, style):
3820
+ """
3821
+ Set the pen style.
3822
+
3823
+ :param `style`: the style, see :class:`wx.Pen`
3824
+
3825
+ """
3826
+ self._penStyle = style
3827
+ self._actualPenObject = None
3828
+
3829
+ def GetWidth(self):
3830
+ """Get the width."""
3831
+ return self._width
3832
+
3833
+ def GetHeight(self):
3834
+ """Get the height."""
3835
+ return self._height
3836
+
3837
+
3838
+ class ControlPoint(RectangleShape):
3839
+ """The :class:`wx.ControlPoint` class."""
3840
+ def __init__(self, theCanvas, object, size, the_xoffset, the_yoffset, the_type):
3841
+ """
3842
+ Default class constructor
3843
+
3844
+ :param `theCanvas`: a :class:`~lib.ogl.Canvas`
3845
+ :param `object`: the shape, instance of :class:`~lib.ogl.Shape`
3846
+ :param float `size`: the size
3847
+ :param float `the_xoffset`: the x position
3848
+ :param float `the_yoffset`: the y position
3849
+ :param int `the_type`: one of the following types ???
3850
+
3851
+ ======================================== ==================================
3852
+ Control point type Description
3853
+ ======================================== ==================================
3854
+ `CONTROL_POINT_VERTICAL` Vertical
3855
+ `CONTROL_POINT_HORIZONTAL` Horizontal
3856
+ `CONTROL_POINT_DIAGONAL` Diagonal
3857
+ ======================================== ==================================
3858
+
3859
+ """
3860
+ RectangleShape.__init__(self, size, size)
3861
+
3862
+ self._canvas = theCanvas
3863
+ self._shape = object
3864
+ self._xoffset = the_xoffset
3865
+ self._yoffset = the_yoffset
3866
+ self._type = the_type
3867
+ self.SetPen(BlackForegroundPen)
3868
+ self.SetBrush(wx.BLACK_BRUSH)
3869
+ self._oldCursor = None
3870
+ self._visible = True
3871
+ self._eraseObject = True
3872
+
3873
+ # Don't even attempt to draw any text - waste of time
3874
+ def OnDrawContents(self, dc):
3875
+ """not implemented???"""
3876
+ pass
3877
+
3878
+ def OnDraw(self, dc):
3879
+ """The draw handler."""
3880
+ self._xpos = self._shape.GetX() + self._xoffset
3881
+ self._ypos = self._shape.GetY() + self._yoffset
3882
+ RectangleShape.OnDraw(self, dc)
3883
+
3884
+ def OnErase(self, dc):
3885
+ """The erase handler."""
3886
+ RectangleShape.OnErase(self, dc)
3887
+
3888
+ # Implement resizing of canvas object
3889
+ def OnDragLeft(self, draw, x, y, keys = 0, attachment = 0):
3890
+ """The drag left handler."""
3891
+ self._shape.GetEventHandler().OnSizingDragLeft(self, draw, x, y, keys, attachment)
3892
+
3893
+ def OnBeginDragLeft(self, x, y, keys = 0, attachment = 0):
3894
+ """The begin drag left handler."""
3895
+ self._shape.GetEventHandler().OnSizingBeginDragLeft(self, x, y, keys, attachment)
3896
+
3897
+ def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
3898
+ """The end drag left handler."""
3899
+ self._shape.GetEventHandler().OnSizingEndDragLeft(self, x, y, keys, attachment)
3900
+
3901
+ def GetNumberOfAttachments(self):
3902
+ """Get the number of attachments."""
3903
+ return 1
3904
+
3905
+ def GetAttachmentPosition(self, attachment, nth = 0, no_arcs = 1, line = None):
3906
+ """
3907
+ Get the attachment position.
3908
+
3909
+ :param `attachment`: the attachment ???
3910
+ :param `nth`: get nth attachment ???
3911
+ :param `no_arcs`: ???
3912
+ :param `line`: ???
3913
+
3914
+ """
3915
+ return self._xpos, self._ypos
3916
+
3917
+ def SetEraseObject(self, er):
3918
+ """
3919
+ Set the erase object ???
3920
+
3921
+ :param `er`: the object
3922
+
3923
+ """
3924
+ self._eraseObject = er
3925
+
3926
+
3927
+ class PolygonControlPoint(ControlPoint):
3928
+ """The :class:`PolygonControlPoint` class."""
3929
+ def __init__(self, theCanvas, object, size, vertex, the_xoffset, the_yoffset):
3930
+ """
3931
+ Default class constructor
3932
+
3933
+ :param `theCanvas`: a :class:`~lib.ogl.Canvas`
3934
+ :param `object`: the shape, instance of :class:`~lib.ogl.Shape`
3935
+ :param float `size`: the size
3936
+ :param `vertext`: the vertex
3937
+ :param float `the_xoffset`: the x position
3938
+ :param float `the_yoffset`: the y position
3939
+ :param int `the_type`: one of the following types ???
3940
+
3941
+ ======================================== ==================================
3942
+ Control point type Description
3943
+ ======================================== ==================================
3944
+ `CONTROL_POINT_VERTICAL` Vertical
3945
+ `CONTROL_POINT_HORIZONTAL` Horizontal
3946
+ `CONTROL_POINT_DIAGONAL` Diagonal
3947
+ ======================================== ==================================
3948
+
3949
+ """
3950
+ ControlPoint.__init__(self, theCanvas, object, size, the_xoffset, the_yoffset, 0)
3951
+ self._polygonVertex = vertex
3952
+ self._originalDistance = 0.0
3953
+ self._newSize = wx.RealPoint()
3954
+ self._originalSize = wx.RealPoint()
3955
+
3956
+ def GetNewSize(self):
3957
+ """Get the new size."""
3958
+ return self._newSize
3959
+
3960
+ def CalculateNewSize(self, x, y):
3961
+ """
3962
+ Calculate what new size would be, at end of resize.
3963
+
3964
+ :param `x`: x ???
3965
+ :param `y`: y ???
3966
+
3967
+ """
3968
+ bound_x, bound_y = self.GetShape().GetBoundingBoxMax()
3969
+ dist = math.sqrt((x - self._shape.GetX()) * (x - self._shape.GetX()) + (y - self._shape.GetY()) * (y - self._shape.GetY()))
3970
+
3971
+ self._newSize[0] = dist / self._originalDistance * self._originalSize[0]
3972
+ self._newSize[1] = dist / self._originalDistance * self._originalSize[1]
3973
+
3974
+ # Implement resizing polygon or moving the vertex
3975
+ def OnDragLeft(self, draw, x, y, keys = 0, attachment = 0):
3976
+ """The drag left handler."""
3977
+ self._shape.GetEventHandler().OnSizingDragLeft(self, draw, x, y, keys, attachment)
3978
+
3979
+ def OnBeginDragLeft(self, x, y, keys = 0, attachment = 0):
3980
+ """The begin drag left handler."""
3981
+ self._shape.GetEventHandler().OnSizingBeginDragLeft(self, x, y, keys, attachment)
3982
+
3983
+ def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
3984
+ """The end drag left handler."""
3985
+ self._shape.GetEventHandler().OnSizingEndDragLeft(self, x, y, keys, attachment)
3986
+
3987
+ from .canvas import *
3988
+ from .lines import *
3989
+ from .composit import *