meerk40t 0.9.3001__py2.py3-none-any.whl → 0.9.7010__py2.py3-none-any.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 (445) hide show
  1. meerk40t/__init__.py +1 -1
  2. meerk40t/balormk/balor_params.py +167 -167
  3. meerk40t/balormk/clone_loader.py +457 -457
  4. meerk40t/balormk/controller.py +1566 -1512
  5. meerk40t/balormk/cylindermod.py +64 -0
  6. meerk40t/balormk/device.py +966 -1959
  7. meerk40t/balormk/driver.py +778 -591
  8. meerk40t/balormk/galvo_commands.py +1195 -0
  9. meerk40t/balormk/gui/balorconfig.py +237 -111
  10. meerk40t/balormk/gui/balorcontroller.py +191 -184
  11. meerk40t/balormk/gui/baloroperationproperties.py +116 -115
  12. meerk40t/balormk/gui/corscene.py +845 -0
  13. meerk40t/balormk/gui/gui.py +179 -147
  14. meerk40t/balormk/livelightjob.py +466 -382
  15. meerk40t/balormk/mock_connection.py +131 -109
  16. meerk40t/balormk/plugin.py +133 -135
  17. meerk40t/balormk/usb_connection.py +306 -301
  18. meerk40t/camera/__init__.py +1 -1
  19. meerk40t/camera/camera.py +514 -397
  20. meerk40t/camera/gui/camerapanel.py +1241 -1095
  21. meerk40t/camera/gui/gui.py +58 -58
  22. meerk40t/camera/plugin.py +441 -399
  23. meerk40t/ch341/__init__.py +27 -27
  24. meerk40t/ch341/ch341device.py +628 -628
  25. meerk40t/ch341/libusb.py +595 -589
  26. meerk40t/ch341/mock.py +171 -171
  27. meerk40t/ch341/windriver.py +157 -157
  28. meerk40t/constants.py +13 -0
  29. meerk40t/core/__init__.py +1 -1
  30. meerk40t/core/bindalias.py +550 -539
  31. meerk40t/core/core.py +47 -47
  32. meerk40t/core/cutcode/cubiccut.py +73 -73
  33. meerk40t/core/cutcode/cutcode.py +315 -312
  34. meerk40t/core/cutcode/cutgroup.py +141 -137
  35. meerk40t/core/cutcode/cutobject.py +192 -185
  36. meerk40t/core/cutcode/dwellcut.py +37 -37
  37. meerk40t/core/cutcode/gotocut.py +29 -29
  38. meerk40t/core/cutcode/homecut.py +29 -29
  39. meerk40t/core/cutcode/inputcut.py +34 -34
  40. meerk40t/core/cutcode/linecut.py +33 -33
  41. meerk40t/core/cutcode/outputcut.py +34 -34
  42. meerk40t/core/cutcode/plotcut.py +335 -335
  43. meerk40t/core/cutcode/quadcut.py +61 -61
  44. meerk40t/core/cutcode/rastercut.py +168 -148
  45. meerk40t/core/cutcode/waitcut.py +34 -34
  46. meerk40t/core/cutplan.py +1843 -1316
  47. meerk40t/core/drivers.py +330 -329
  48. meerk40t/core/elements/align.py +801 -669
  49. meerk40t/core/elements/branches.py +1844 -1507
  50. meerk40t/core/elements/clipboard.py +229 -219
  51. meerk40t/core/elements/element_treeops.py +4561 -2837
  52. meerk40t/core/elements/element_types.py +125 -105
  53. meerk40t/core/elements/elements.py +4329 -3617
  54. meerk40t/core/elements/files.py +117 -64
  55. meerk40t/core/elements/geometry.py +473 -224
  56. meerk40t/core/elements/grid.py +467 -316
  57. meerk40t/core/elements/materials.py +158 -94
  58. meerk40t/core/elements/notes.py +50 -38
  59. meerk40t/core/elements/offset_clpr.py +933 -912
  60. meerk40t/core/elements/offset_mk.py +963 -955
  61. meerk40t/core/elements/penbox.py +339 -267
  62. meerk40t/core/elements/placements.py +300 -83
  63. meerk40t/core/elements/render.py +785 -687
  64. meerk40t/core/elements/shapes.py +2618 -2092
  65. meerk40t/core/elements/trace.py +651 -563
  66. meerk40t/core/elements/tree_commands.py +415 -409
  67. meerk40t/core/elements/undo_redo.py +116 -58
  68. meerk40t/core/elements/wordlist.py +319 -200
  69. meerk40t/core/exceptions.py +9 -9
  70. meerk40t/core/laserjob.py +220 -220
  71. meerk40t/core/logging.py +63 -63
  72. meerk40t/core/node/blobnode.py +83 -86
  73. meerk40t/core/node/bootstrap.py +105 -103
  74. meerk40t/core/node/branch_elems.py +40 -31
  75. meerk40t/core/node/branch_ops.py +45 -38
  76. meerk40t/core/node/branch_regmark.py +48 -41
  77. meerk40t/core/node/cutnode.py +29 -32
  78. meerk40t/core/node/effect_hatch.py +375 -257
  79. meerk40t/core/node/effect_warp.py +398 -0
  80. meerk40t/core/node/effect_wobble.py +441 -309
  81. meerk40t/core/node/elem_ellipse.py +404 -309
  82. meerk40t/core/node/elem_image.py +1082 -801
  83. meerk40t/core/node/elem_line.py +358 -292
  84. meerk40t/core/node/elem_path.py +259 -201
  85. meerk40t/core/node/elem_point.py +129 -102
  86. meerk40t/core/node/elem_polyline.py +310 -246
  87. meerk40t/core/node/elem_rect.py +376 -286
  88. meerk40t/core/node/elem_text.py +445 -418
  89. meerk40t/core/node/filenode.py +59 -40
  90. meerk40t/core/node/groupnode.py +138 -74
  91. meerk40t/core/node/image_processed.py +777 -766
  92. meerk40t/core/node/image_raster.py +156 -113
  93. meerk40t/core/node/layernode.py +31 -31
  94. meerk40t/core/node/mixins.py +135 -107
  95. meerk40t/core/node/node.py +1427 -1304
  96. meerk40t/core/node/nutils.py +117 -114
  97. meerk40t/core/node/op_cut.py +462 -335
  98. meerk40t/core/node/op_dots.py +296 -251
  99. meerk40t/core/node/op_engrave.py +414 -311
  100. meerk40t/core/node/op_image.py +755 -369
  101. meerk40t/core/node/op_raster.py +787 -522
  102. meerk40t/core/node/place_current.py +37 -40
  103. meerk40t/core/node/place_point.py +329 -126
  104. meerk40t/core/node/refnode.py +58 -47
  105. meerk40t/core/node/rootnode.py +225 -219
  106. meerk40t/core/node/util_console.py +48 -48
  107. meerk40t/core/node/util_goto.py +84 -65
  108. meerk40t/core/node/util_home.py +61 -61
  109. meerk40t/core/node/util_input.py +102 -102
  110. meerk40t/core/node/util_output.py +102 -102
  111. meerk40t/core/node/util_wait.py +65 -65
  112. meerk40t/core/parameters.py +709 -707
  113. meerk40t/core/planner.py +875 -785
  114. meerk40t/core/plotplanner.py +656 -652
  115. meerk40t/core/space.py +120 -113
  116. meerk40t/core/spoolers.py +706 -705
  117. meerk40t/core/svg_io.py +1836 -1549
  118. meerk40t/core/treeop.py +534 -445
  119. meerk40t/core/undos.py +278 -124
  120. meerk40t/core/units.py +784 -680
  121. meerk40t/core/view.py +393 -322
  122. meerk40t/core/webhelp.py +62 -62
  123. meerk40t/core/wordlist.py +513 -504
  124. meerk40t/cylinder/cylinder.py +247 -0
  125. meerk40t/cylinder/gui/cylindersettings.py +41 -0
  126. meerk40t/cylinder/gui/gui.py +24 -0
  127. meerk40t/device/__init__.py +1 -1
  128. meerk40t/device/basedevice.py +322 -123
  129. meerk40t/device/devicechoices.py +50 -0
  130. meerk40t/device/dummydevice.py +163 -128
  131. meerk40t/device/gui/defaultactions.py +618 -602
  132. meerk40t/device/gui/effectspanel.py +114 -0
  133. meerk40t/device/gui/formatterpanel.py +253 -290
  134. meerk40t/device/gui/warningpanel.py +337 -260
  135. meerk40t/device/mixins.py +13 -13
  136. meerk40t/dxf/__init__.py +1 -1
  137. meerk40t/dxf/dxf_io.py +766 -554
  138. meerk40t/dxf/plugin.py +47 -35
  139. meerk40t/external_plugins.py +79 -79
  140. meerk40t/external_plugins_build.py +28 -28
  141. meerk40t/extra/cag.py +112 -116
  142. meerk40t/extra/coolant.py +403 -0
  143. meerk40t/extra/encode_detect.py +198 -0
  144. meerk40t/extra/ezd.py +1165 -1165
  145. meerk40t/extra/hershey.py +835 -340
  146. meerk40t/extra/imageactions.py +322 -316
  147. meerk40t/extra/inkscape.py +630 -622
  148. meerk40t/extra/lbrn.py +424 -424
  149. meerk40t/extra/outerworld.py +284 -0
  150. meerk40t/extra/param_functions.py +1542 -1556
  151. meerk40t/extra/potrace.py +257 -253
  152. meerk40t/extra/serial_exchange.py +118 -0
  153. meerk40t/extra/updater.py +602 -453
  154. meerk40t/extra/vectrace.py +147 -146
  155. meerk40t/extra/winsleep.py +83 -83
  156. meerk40t/extra/xcs_reader.py +597 -0
  157. meerk40t/fill/fills.py +781 -335
  158. meerk40t/fill/patternfill.py +1061 -1061
  159. meerk40t/fill/patterns.py +614 -567
  160. meerk40t/grbl/control.py +87 -87
  161. meerk40t/grbl/controller.py +990 -903
  162. meerk40t/grbl/device.py +1081 -768
  163. meerk40t/grbl/driver.py +989 -771
  164. meerk40t/grbl/emulator.py +532 -497
  165. meerk40t/grbl/gcodejob.py +783 -767
  166. meerk40t/grbl/gui/grblconfiguration.py +373 -298
  167. meerk40t/grbl/gui/grblcontroller.py +485 -271
  168. meerk40t/grbl/gui/grblhardwareconfig.py +269 -153
  169. meerk40t/grbl/gui/grbloperationconfig.py +105 -0
  170. meerk40t/grbl/gui/gui.py +147 -116
  171. meerk40t/grbl/interpreter.py +44 -44
  172. meerk40t/grbl/loader.py +22 -22
  173. meerk40t/grbl/mock_connection.py +56 -56
  174. meerk40t/grbl/plugin.py +294 -264
  175. meerk40t/grbl/serial_connection.py +93 -88
  176. meerk40t/grbl/tcp_connection.py +81 -79
  177. meerk40t/grbl/ws_connection.py +112 -0
  178. meerk40t/gui/__init__.py +1 -1
  179. meerk40t/gui/about.py +2042 -296
  180. meerk40t/gui/alignment.py +1644 -1608
  181. meerk40t/gui/autoexec.py +199 -0
  182. meerk40t/gui/basicops.py +791 -670
  183. meerk40t/gui/bufferview.py +77 -71
  184. meerk40t/gui/busy.py +170 -133
  185. meerk40t/gui/choicepropertypanel.py +1673 -1469
  186. meerk40t/gui/consolepanel.py +706 -542
  187. meerk40t/gui/devicepanel.py +687 -581
  188. meerk40t/gui/dialogoptions.py +110 -107
  189. meerk40t/gui/executejob.py +316 -306
  190. meerk40t/gui/fonts.py +90 -90
  191. meerk40t/gui/functionwrapper.py +252 -0
  192. meerk40t/gui/gui_mixins.py +729 -0
  193. meerk40t/gui/guicolors.py +205 -182
  194. meerk40t/gui/help_assets/help_assets.py +218 -201
  195. meerk40t/gui/helper.py +154 -0
  196. meerk40t/gui/hersheymanager.py +1430 -846
  197. meerk40t/gui/icons.py +3422 -2747
  198. meerk40t/gui/imagesplitter.py +555 -508
  199. meerk40t/gui/keymap.py +354 -344
  200. meerk40t/gui/laserpanel.py +892 -806
  201. meerk40t/gui/laserrender.py +1470 -1232
  202. meerk40t/gui/lasertoolpanel.py +805 -793
  203. meerk40t/gui/magnetoptions.py +436 -0
  204. meerk40t/gui/materialmanager.py +2917 -0
  205. meerk40t/gui/materialtest.py +1722 -1694
  206. meerk40t/gui/mkdebug.py +646 -359
  207. meerk40t/gui/mwindow.py +163 -140
  208. meerk40t/gui/navigationpanels.py +2605 -2467
  209. meerk40t/gui/notes.py +143 -142
  210. meerk40t/gui/opassignment.py +414 -410
  211. meerk40t/gui/operation_info.py +310 -299
  212. meerk40t/gui/plugin.py +494 -328
  213. meerk40t/gui/position.py +714 -669
  214. meerk40t/gui/preferences.py +901 -650
  215. meerk40t/gui/propertypanels/attributes.py +1461 -1131
  216. meerk40t/gui/propertypanels/blobproperty.py +117 -114
  217. meerk40t/gui/propertypanels/consoleproperty.py +83 -80
  218. meerk40t/gui/propertypanels/gotoproperty.py +77 -0
  219. meerk40t/gui/propertypanels/groupproperties.py +223 -217
  220. meerk40t/gui/propertypanels/hatchproperty.py +489 -469
  221. meerk40t/gui/propertypanels/imageproperty.py +2244 -1384
  222. meerk40t/gui/propertypanels/inputproperty.py +59 -58
  223. meerk40t/gui/propertypanels/opbranchproperties.py +82 -80
  224. meerk40t/gui/propertypanels/operationpropertymain.py +1890 -1638
  225. meerk40t/gui/propertypanels/outputproperty.py +59 -58
  226. meerk40t/gui/propertypanels/pathproperty.py +389 -380
  227. meerk40t/gui/propertypanels/placementproperty.py +1214 -383
  228. meerk40t/gui/propertypanels/pointproperty.py +140 -136
  229. meerk40t/gui/propertypanels/propertywindow.py +313 -181
  230. meerk40t/gui/propertypanels/rasterwizardpanels.py +996 -912
  231. meerk40t/gui/propertypanels/regbranchproperties.py +76 -0
  232. meerk40t/gui/propertypanels/textproperty.py +770 -755
  233. meerk40t/gui/propertypanels/waitproperty.py +56 -55
  234. meerk40t/gui/propertypanels/warpproperty.py +121 -0
  235. meerk40t/gui/propertypanels/wobbleproperty.py +255 -204
  236. meerk40t/gui/ribbon.py +2468 -2210
  237. meerk40t/gui/scene/scene.py +1100 -1051
  238. meerk40t/gui/scene/sceneconst.py +22 -22
  239. meerk40t/gui/scene/scenepanel.py +439 -349
  240. meerk40t/gui/scene/scenespacewidget.py +365 -365
  241. meerk40t/gui/scene/widget.py +518 -505
  242. meerk40t/gui/scenewidgets/affinemover.py +215 -215
  243. meerk40t/gui/scenewidgets/attractionwidget.py +315 -309
  244. meerk40t/gui/scenewidgets/bedwidget.py +120 -97
  245. meerk40t/gui/scenewidgets/elementswidget.py +137 -107
  246. meerk40t/gui/scenewidgets/gridwidget.py +785 -745
  247. meerk40t/gui/scenewidgets/guidewidget.py +765 -765
  248. meerk40t/gui/scenewidgets/laserpathwidget.py +66 -66
  249. meerk40t/gui/scenewidgets/machineoriginwidget.py +86 -86
  250. meerk40t/gui/scenewidgets/nodeselector.py +28 -28
  251. meerk40t/gui/scenewidgets/rectselectwidget.py +589 -346
  252. meerk40t/gui/scenewidgets/relocatewidget.py +33 -33
  253. meerk40t/gui/scenewidgets/reticlewidget.py +83 -83
  254. meerk40t/gui/scenewidgets/selectionwidget.py +2952 -2756
  255. meerk40t/gui/simpleui.py +357 -333
  256. meerk40t/gui/simulation.py +2431 -2094
  257. meerk40t/gui/snapoptions.py +208 -203
  258. meerk40t/gui/spoolerpanel.py +1227 -1180
  259. meerk40t/gui/statusbarwidgets/defaultoperations.py +480 -353
  260. meerk40t/gui/statusbarwidgets/infowidget.py +520 -483
  261. meerk40t/gui/statusbarwidgets/opassignwidget.py +356 -355
  262. meerk40t/gui/statusbarwidgets/selectionwidget.py +172 -171
  263. meerk40t/gui/statusbarwidgets/shapepropwidget.py +754 -236
  264. meerk40t/gui/statusbarwidgets/statusbar.py +272 -260
  265. meerk40t/gui/statusbarwidgets/statusbarwidget.py +268 -270
  266. meerk40t/gui/statusbarwidgets/strokewidget.py +267 -251
  267. meerk40t/gui/themes.py +200 -78
  268. meerk40t/gui/tips.py +591 -0
  269. meerk40t/gui/toolwidgets/circlebrush.py +35 -35
  270. meerk40t/gui/toolwidgets/toolcircle.py +248 -242
  271. meerk40t/gui/toolwidgets/toolcontainer.py +82 -77
  272. meerk40t/gui/toolwidgets/tooldraw.py +97 -90
  273. meerk40t/gui/toolwidgets/toolellipse.py +219 -212
  274. meerk40t/gui/toolwidgets/toolimagecut.py +25 -132
  275. meerk40t/gui/toolwidgets/toolline.py +39 -144
  276. meerk40t/gui/toolwidgets/toollinetext.py +79 -236
  277. meerk40t/gui/toolwidgets/toollinetext_inline.py +296 -0
  278. meerk40t/gui/toolwidgets/toolmeasure.py +160 -216
  279. meerk40t/gui/toolwidgets/toolnodeedit.py +2088 -2074
  280. meerk40t/gui/toolwidgets/toolnodemove.py +92 -94
  281. meerk40t/gui/toolwidgets/toolparameter.py +754 -668
  282. meerk40t/gui/toolwidgets/toolplacement.py +108 -108
  283. meerk40t/gui/toolwidgets/toolpoint.py +68 -59
  284. meerk40t/gui/toolwidgets/toolpointlistbuilder.py +294 -0
  285. meerk40t/gui/toolwidgets/toolpointmove.py +183 -0
  286. meerk40t/gui/toolwidgets/toolpolygon.py +288 -403
  287. meerk40t/gui/toolwidgets/toolpolyline.py +38 -196
  288. meerk40t/gui/toolwidgets/toolrect.py +211 -207
  289. meerk40t/gui/toolwidgets/toolrelocate.py +72 -72
  290. meerk40t/gui/toolwidgets/toolribbon.py +598 -113
  291. meerk40t/gui/toolwidgets/tooltabedit.py +546 -0
  292. meerk40t/gui/toolwidgets/tooltext.py +98 -89
  293. meerk40t/gui/toolwidgets/toolvector.py +213 -204
  294. meerk40t/gui/toolwidgets/toolwidget.py +39 -39
  295. meerk40t/gui/usbconnect.py +98 -91
  296. meerk40t/gui/utilitywidgets/buttonwidget.py +18 -18
  297. meerk40t/gui/utilitywidgets/checkboxwidget.py +90 -90
  298. meerk40t/gui/utilitywidgets/controlwidget.py +14 -14
  299. meerk40t/gui/utilitywidgets/cyclocycloidwidget.py +343 -340
  300. meerk40t/gui/utilitywidgets/debugwidgets.py +148 -0
  301. meerk40t/gui/utilitywidgets/handlewidget.py +27 -27
  302. meerk40t/gui/utilitywidgets/harmonograph.py +450 -447
  303. meerk40t/gui/utilitywidgets/openclosewidget.py +40 -40
  304. meerk40t/gui/utilitywidgets/rotationwidget.py +54 -54
  305. meerk40t/gui/utilitywidgets/scalewidget.py +75 -75
  306. meerk40t/gui/utilitywidgets/seekbarwidget.py +183 -183
  307. meerk40t/gui/utilitywidgets/togglewidget.py +142 -142
  308. meerk40t/gui/utilitywidgets/toolbarwidget.py +8 -8
  309. meerk40t/gui/wordlisteditor.py +985 -931
  310. meerk40t/gui/wxmeerk40t.py +1444 -1169
  311. meerk40t/gui/wxmmain.py +5578 -4112
  312. meerk40t/gui/wxmribbon.py +1591 -1076
  313. meerk40t/gui/wxmscene.py +1635 -1453
  314. meerk40t/gui/wxmtree.py +2410 -2089
  315. meerk40t/gui/wxutils.py +1769 -1099
  316. meerk40t/gui/zmatrix.py +102 -102
  317. meerk40t/image/__init__.py +1 -1
  318. meerk40t/image/dither.py +429 -0
  319. meerk40t/image/imagetools.py +2778 -2269
  320. meerk40t/internal_plugins.py +150 -130
  321. meerk40t/kernel/__init__.py +63 -12
  322. meerk40t/kernel/channel.py +259 -212
  323. meerk40t/kernel/context.py +538 -538
  324. meerk40t/kernel/exceptions.py +41 -41
  325. meerk40t/kernel/functions.py +463 -414
  326. meerk40t/kernel/jobs.py +100 -100
  327. meerk40t/kernel/kernel.py +3809 -3571
  328. meerk40t/kernel/lifecycles.py +71 -71
  329. meerk40t/kernel/module.py +49 -49
  330. meerk40t/kernel/service.py +147 -147
  331. meerk40t/kernel/settings.py +383 -343
  332. meerk40t/lihuiyu/controller.py +883 -876
  333. meerk40t/lihuiyu/device.py +1181 -1069
  334. meerk40t/lihuiyu/driver.py +1466 -1372
  335. meerk40t/lihuiyu/gui/gui.py +127 -106
  336. meerk40t/lihuiyu/gui/lhyaccelgui.py +377 -363
  337. meerk40t/lihuiyu/gui/lhycontrollergui.py +741 -651
  338. meerk40t/lihuiyu/gui/lhydrivergui.py +470 -446
  339. meerk40t/lihuiyu/gui/lhyoperationproperties.py +238 -237
  340. meerk40t/lihuiyu/gui/tcpcontroller.py +226 -190
  341. meerk40t/lihuiyu/interpreter.py +53 -53
  342. meerk40t/lihuiyu/laserspeed.py +450 -450
  343. meerk40t/lihuiyu/loader.py +90 -90
  344. meerk40t/lihuiyu/parser.py +404 -404
  345. meerk40t/lihuiyu/plugin.py +101 -102
  346. meerk40t/lihuiyu/tcp_connection.py +111 -109
  347. meerk40t/main.py +231 -165
  348. meerk40t/moshi/builder.py +788 -781
  349. meerk40t/moshi/controller.py +505 -499
  350. meerk40t/moshi/device.py +495 -442
  351. meerk40t/moshi/driver.py +862 -696
  352. meerk40t/moshi/gui/gui.py +78 -76
  353. meerk40t/moshi/gui/moshicontrollergui.py +538 -522
  354. meerk40t/moshi/gui/moshidrivergui.py +87 -75
  355. meerk40t/moshi/plugin.py +43 -43
  356. meerk40t/network/console_server.py +102 -57
  357. meerk40t/network/kernelserver.py +10 -9
  358. meerk40t/network/tcp_server.py +142 -140
  359. meerk40t/network/udp_server.py +103 -77
  360. meerk40t/network/web_server.py +390 -0
  361. meerk40t/newly/controller.py +1158 -1144
  362. meerk40t/newly/device.py +874 -732
  363. meerk40t/newly/driver.py +540 -412
  364. meerk40t/newly/gui/gui.py +219 -188
  365. meerk40t/newly/gui/newlyconfig.py +116 -101
  366. meerk40t/newly/gui/newlycontroller.py +193 -186
  367. meerk40t/newly/gui/operationproperties.py +51 -51
  368. meerk40t/newly/mock_connection.py +82 -82
  369. meerk40t/newly/newly_params.py +56 -56
  370. meerk40t/newly/plugin.py +1214 -1246
  371. meerk40t/newly/usb_connection.py +322 -322
  372. meerk40t/rotary/gui/gui.py +52 -46
  373. meerk40t/rotary/gui/rotarysettings.py +240 -232
  374. meerk40t/rotary/rotary.py +202 -98
  375. meerk40t/ruida/control.py +291 -91
  376. meerk40t/ruida/controller.py +138 -1088
  377. meerk40t/ruida/device.py +672 -231
  378. meerk40t/ruida/driver.py +534 -472
  379. meerk40t/ruida/emulator.py +1494 -1491
  380. meerk40t/ruida/exceptions.py +4 -4
  381. meerk40t/ruida/gui/gui.py +71 -76
  382. meerk40t/ruida/gui/ruidaconfig.py +239 -72
  383. meerk40t/ruida/gui/ruidacontroller.py +187 -184
  384. meerk40t/ruida/gui/ruidaoperationproperties.py +48 -47
  385. meerk40t/ruida/loader.py +54 -52
  386. meerk40t/ruida/mock_connection.py +57 -109
  387. meerk40t/ruida/plugin.py +124 -87
  388. meerk40t/ruida/rdjob.py +2084 -945
  389. meerk40t/ruida/serial_connection.py +116 -0
  390. meerk40t/ruida/tcp_connection.py +146 -0
  391. meerk40t/ruida/udp_connection.py +73 -0
  392. meerk40t/svgelements.py +9671 -9669
  393. meerk40t/tools/driver_to_path.py +584 -579
  394. meerk40t/tools/geomstr.py +5583 -4680
  395. meerk40t/tools/jhfparser.py +357 -292
  396. meerk40t/tools/kerftest.py +904 -890
  397. meerk40t/tools/livinghinges.py +1168 -1033
  398. meerk40t/tools/pathtools.py +987 -949
  399. meerk40t/tools/pmatrix.py +234 -0
  400. meerk40t/tools/pointfinder.py +942 -942
  401. meerk40t/tools/polybool.py +940 -940
  402. meerk40t/tools/rasterplotter.py +1660 -547
  403. meerk40t/tools/shxparser.py +989 -901
  404. meerk40t/tools/ttfparser.py +726 -446
  405. meerk40t/tools/zinglplotter.py +595 -593
  406. {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/LICENSE +21 -21
  407. {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/METADATA +150 -139
  408. meerk40t-0.9.7010.dist-info/RECORD +445 -0
  409. {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/WHEEL +1 -1
  410. {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/top_level.txt +0 -1
  411. {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/zip-safe +1 -1
  412. meerk40t/balormk/elementlightjob.py +0 -159
  413. meerk40t-0.9.3001.dist-info/RECORD +0 -437
  414. test/bootstrap.py +0 -63
  415. test/test_cli.py +0 -12
  416. test/test_core_cutcode.py +0 -418
  417. test/test_core_elements.py +0 -144
  418. test/test_core_plotplanner.py +0 -397
  419. test/test_core_viewports.py +0 -312
  420. test/test_drivers_grbl.py +0 -108
  421. test/test_drivers_lihuiyu.py +0 -443
  422. test/test_drivers_newly.py +0 -113
  423. test/test_element_degenerate_points.py +0 -43
  424. test/test_elements_classify.py +0 -97
  425. test/test_elements_penbox.py +0 -22
  426. test/test_file_svg.py +0 -176
  427. test/test_fill.py +0 -155
  428. test/test_geomstr.py +0 -1523
  429. test/test_geomstr_nodes.py +0 -18
  430. test/test_imagetools_actualize.py +0 -306
  431. test/test_imagetools_wizard.py +0 -258
  432. test/test_kernel.py +0 -200
  433. test/test_laser_speeds.py +0 -3303
  434. test/test_length.py +0 -57
  435. test/test_lifecycle.py +0 -66
  436. test/test_operations.py +0 -251
  437. test/test_operations_hatch.py +0 -57
  438. test/test_ruida.py +0 -19
  439. test/test_spooler.py +0 -22
  440. test/test_tools_rasterplotter.py +0 -29
  441. test/test_wobble.py +0 -133
  442. test/test_zingl.py +0 -124
  443. {test → meerk40t/cylinder}/__init__.py +0 -0
  444. /meerk40t/{core/element_commands.py → cylinder/gui/__init__.py} +0 -0
  445. {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/entry_points.txt +0 -0
@@ -1,346 +1,589 @@
1
- """
2
- Specifically draws the rectangle selection box and deals with emphasis of selected objects.
3
- """
4
-
5
-
6
- import wx
7
-
8
- from meerk40t.gui.scene.scene import (
9
- HITCHAIN_HIT,
10
- RESPONSE_CHAIN,
11
- RESPONSE_CONSUME,
12
- RESPONSE_DROP,
13
- )
14
- from meerk40t.gui.scene.widget import Widget
15
-
16
-
17
- class RectSelectWidget(Widget):
18
- """
19
- SceneWidget
20
-
21
- Rectangle Selection Widget, draws the selection rectangle if left-clicked and dragged
22
- """
23
-
24
- # selection_method = 1 = hit, 2 = cross, 3 = enclose
25
- SELECTION_TOUCH = 1
26
- SELECTION_CROSS = 2
27
- SELECTION_ENCLOSE = 3
28
- selection_text_shift = " Previously selected remain selected!"
29
- selection_text_control = " Invert selection state of elements!"
30
-
31
- # 2 | 1 Define Selection method per sector, movement of mouse from point of origin into that sector...
32
- # - + -
33
- # 3 | 0
34
- #
35
- selection_method = [
36
- SELECTION_ENCLOSE,
37
- SELECTION_ENCLOSE,
38
- SELECTION_TOUCH,
39
- SELECTION_TOUCH,
40
- ] # Selection rectangle to the right: enclose, to the left: touch
41
-
42
- was_lb_raised = False
43
-
44
- def __init__(self, scene):
45
- Widget.__init__(self, scene, all=True)
46
- # Color for selection rectangle (hit, cross, enclose)
47
- self.selection_style = [
48
- [
49
- self.scene.colors.color_selection1,
50
- wx.PENSTYLE_DOT_DASH,
51
- "Select all elements the selection rectangle touches.",
52
- ],
53
- [
54
- self.scene.colors.color_selection2,
55
- wx.PENSTYLE_DOT,
56
- "Select all elements the selection rectangle crosses.",
57
- ],
58
- [
59
- self.scene.colors.color_selection3,
60
- wx.PENSTYLE_SHORT_DASH,
61
- "Select all elements the selection rectangle encloses.",
62
- ],
63
- ]
64
- self.selection_pen = wx.Pen()
65
- self.selection_pen.SetColour(self.selection_style[0][0])
66
- self.selection_pen.SetWidth(25)
67
- self.selection_pen.SetStyle(self.selection_style[0][1])
68
- # want to have sharp edges
69
- self.selection_pen.SetJoin(wx.JOIN_MITER)
70
- self.start_location = None
71
- self.end_location = None
72
- self.modifiers = []
73
-
74
- def hit(self):
75
- return HITCHAIN_HIT
76
-
77
- store_last_msg = ""
78
-
79
- @property
80
- def sector(self):
81
- sx = self.start_location[0]
82
- sy = self.start_location[1]
83
- ex = self.end_location[0]
84
- ey = self.end_location[1]
85
- if sx <= ex:
86
- if sy <= ey:
87
- return 0
88
- else:
89
- return 1
90
- else:
91
- if sy <= ey:
92
- return 3
93
- else:
94
- return 2
95
-
96
- def rect_select(self, elements, sx, sy, ex, ey):
97
- sector = self.sector
98
- for node in elements.elems():
99
- try:
100
- q = node.bounds
101
- except AttributeError:
102
- continue # This element has no bounds.
103
- if q is None:
104
- continue
105
- if hasattr(node, "can_emphasize") and not node.can_emphasize:
106
- continue
107
- xmin = q[0]
108
- ymin = q[1]
109
- xmax = q[2]
110
- ymax = q[3]
111
- # no hit
112
- cover = 0
113
- # Check Hit
114
- # The rectangles don't overlap if
115
- # one rectangle's minimum in some dimension
116
- # is greater than the other's maximum in
117
- # that dimension.
118
- if not ((sx > xmax) or (xmin > ex) or (sy > ymax) or (ymin > ey)):
119
- cover = self.SELECTION_TOUCH
120
- # If selection rect is fully inside an object then ignore
121
- if sx > xmin and ex < xmax and sy > ymin and ey < ymax:
122
- cover = 0
123
-
124
- # Check Cross
125
- if (
126
- ((sx <= xmin) and (xmax <= ex))
127
- and not ((sy > ymax) or (ey < ymin))
128
- or ((sy <= ymin) and (ymax <= ey))
129
- and not ((sx > xmax) or (ex < xmin))
130
- ):
131
- cover = self.SELECTION_CROSS
132
- # Check contain
133
- if ((sx <= xmin) and (xmax <= ex)) and ((sy <= ymin) and (ymax <= ey)):
134
- cover = self.SELECTION_ENCLOSE
135
-
136
- if "shift" in self.modifiers:
137
- # Add Selection
138
- if cover >= self.selection_method[sector]:
139
- node.emphasized = True
140
- node.selected = True
141
- elif "ctrl" in self.modifiers:
142
- # Invert Selection
143
- if cover >= self.selection_method[sector]:
144
- node.emphasized = not node.emphasized
145
- node.selected = node.emphasized
146
- else:
147
- # Replace Selection
148
- if cover >= self.selection_method[sector]:
149
- node.emphasized = True
150
- node.selected = True
151
- else:
152
- node.emphasized = False
153
- node.selected = False
154
-
155
- def update_statusmsg(self, value):
156
- if value != self.store_last_msg:
157
- self.store_last_msg = value
158
- self.scene.context.signal("statusmsg", value)
159
-
160
- # debug_msg = ""
161
-
162
- def event(
163
- self, window_pos=None, space_pos=None, event_type=None, modifiers=None, **kwargs
164
- ):
165
- if modifiers is not None:
166
- self.modifiers = modifiers
167
-
168
- elements = self.scene.context.elements
169
- if event_type == "leftdown":
170
- self.start_location = space_pos
171
- self.end_location = space_pos
172
- # print ("RectSelect consumed leftdown")
173
- return RESPONSE_CONSUME
174
- elif event_type == "leftclick":
175
- # That's too fast
176
- # still chaining though
177
- self.scene.request_refresh()
178
- self.start_location = None
179
- self.end_location = None
180
- return RESPONSE_CHAIN
181
- elif event_type == "leftup":
182
- if self.start_location is None:
183
- return RESPONSE_CHAIN
184
- _ = self.scene.context._
185
- self.update_statusmsg(_("Status"))
186
- elements.validate_selected_area()
187
- sx = min(self.start_location[0], self.end_location[0])
188
- sy = min(self.start_location[1], self.end_location[1])
189
- ex = max(self.start_location[0], self.end_location[0])
190
- ey = max(self.start_location[1], self.end_location[1])
191
- self.rect_select(elements, sx, sy, ex, ey)
192
-
193
- self.scene.request_refresh()
194
- self.scene.context.signal("select_emphasized_tree", 0)
195
-
196
- self.start_location = None
197
- self.end_location = None
198
-
199
- return RESPONSE_CONSUME
200
- elif event_type == "move":
201
- self.scene.request_refresh()
202
- self.end_location = space_pos
203
- return RESPONSE_CONSUME
204
- elif event_type == "lost":
205
- self.start_location = None
206
- self.end_location = None
207
- return RESPONSE_CONSUME
208
- return RESPONSE_DROP
209
-
210
- def draw_rectangle(self, gc, x0, y0, x1, y1, tcolor, tstyle):
211
- matrix = self.parent.matrix
212
- self.selection_pen.SetColour(tcolor)
213
- self.selection_pen.SetStyle(tstyle)
214
- gc.SetPen(self.selection_pen)
215
-
216
- linewidth = 2.0 / matrix.value_scale_x()
217
- if linewidth < 1:
218
- linewidth = 1
219
- try:
220
- self.selection_pen.SetWidth(linewidth)
221
- except TypeError:
222
- self.selection_pen.SetWidth(int(linewidth))
223
- gc.SetPen(self.selection_pen)
224
- gc.StrokeLine(x0, y0, x1, y0)
225
- gc.StrokeLine(x1, y0, x1, y1)
226
- gc.StrokeLine(x1, y1, x0, y1)
227
- gc.StrokeLine(x0, y1, x0, y0)
228
-
229
- def draw_tiny_indicator(self, gc, symbol, x0, y0, x1, y1, tcolor, tstyle):
230
- matrix = self.parent.matrix
231
- self.selection_pen.SetColour(tcolor)
232
- self.selection_pen.SetStyle(tstyle)
233
-
234
- linewidth = 2.0 / matrix.value_scale_x()
235
- if linewidth < 1:
236
- linewidth = 1
237
- try:
238
- self.selection_pen.SetWidth(linewidth)
239
- except TypeError:
240
- self.selection_pen.SetWidth(int(linewidth))
241
- gc.SetPen(self.selection_pen)
242
- delta_X = 15.0 / matrix.value_scale_x()
243
- delta_Y = 15.0 / matrix.value_scale_y()
244
- if abs(x1 - x0) > delta_X and abs(y1 - y0) > delta_Y: # Don't draw if too tiny
245
- # Draw tiny '+' in corner of pointer
246
- x_signum = +1 * delta_X if x0 < x1 else -1 * delta_X
247
- y_signum = +1 * delta_Y if y0 < y1 else -1 * delta_X
248
- ax1 = x1 - x_signum
249
- ay1 = y1 - y_signum
250
-
251
- gc.SetPen(self.selection_pen)
252
- gc.StrokeLine(ax1, y1, ax1, ay1)
253
- gc.StrokeLine(ax1, ay1, x1, ay1)
254
- font_size = 10.0 / matrix.value_scale_x()
255
- if font_size < 1.0:
256
- font_size = 1.0
257
- try:
258
- font = wx.Font(
259
- font_size,
260
- wx.FONTFAMILY_SWISS,
261
- wx.FONTSTYLE_NORMAL,
262
- wx.FONTWEIGHT_NORMAL,
263
- )
264
- except TypeError:
265
- font = wx.Font(
266
- int(font_size),
267
- wx.FONTFAMILY_SWISS,
268
- wx.FONTSTYLE_NORMAL,
269
- wx.FONTWEIGHT_NORMAL,
270
- )
271
- gc.SetFont(font, tcolor)
272
- (t_width, t_height) = gc.GetTextExtent(symbol)
273
- gc.DrawText(
274
- symbol, (ax1 + x1) / 2 - t_width / 2, (ay1 + y1) / 2 - t_height / 2
275
- )
276
- if (
277
- abs(x1 - x0) > 2 * delta_X and abs(y1 - y0) > 2 * delta_Y
278
- ): # Don't draw if too tiny
279
- # Draw second symbol at origin
280
- ax1 = x0 + x_signum
281
- ay1 = y0 + y_signum
282
- gc.StrokeLine(ax1, y0, ax1, ay1)
283
- gc.StrokeLine(ax1, ay1, x0, ay1)
284
- gc.DrawText(
285
- symbol, (ax1 + x0) / 2 - t_width / 2, (ay1 + y0) / 2 - t_height / 2
286
- )
287
-
288
- def process_draw(self, gc):
289
- """
290
- Draw the selection rectangle
291
- """
292
- if self.start_location is not None and self.end_location is not None:
293
- self.selection_style[0][0] = self.scene.colors.color_selection1
294
- self.selection_style[1][0] = self.scene.colors.color_selection2
295
- self.selection_style[2][0] = self.scene.colors.color_selection3
296
- x0 = self.start_location[0]
297
- y0 = self.start_location[1]
298
- x1 = self.end_location[0]
299
- y1 = self.end_location[1]
300
- sector = self.sector
301
-
302
- _ = self.scene.context._
303
- statusmsg = _(self.selection_style[self.selection_method[sector] - 1][2])
304
- if "shift" in self.modifiers:
305
- statusmsg += _(self.selection_text_shift)
306
- elif "ctrl" in self.modifiers:
307
- statusmsg += _(self.selection_text_control)
308
-
309
- self.update_statusmsg(statusmsg)
310
- gcstyle = self.selection_style[self.selection_method[sector] - 1][0]
311
- gccolor = self.selection_style[self.selection_method[sector] - 1][1]
312
- self.draw_rectangle(
313
- gc,
314
- x0,
315
- y0,
316
- x1,
317
- y1,
318
- gcstyle,
319
- gccolor,
320
- )
321
-
322
- # Determine Colour on selection mode: standard (from left top to right bottom) = Blue, else Green
323
- # Draw indicator...
324
- if "shift" in self.modifiers:
325
- self.draw_tiny_indicator(
326
- gc,
327
- "+",
328
- x0,
329
- y0,
330
- x1,
331
- y1,
332
- gcstyle,
333
- gccolor,
334
- )
335
-
336
- elif "ctrl" in self.modifiers:
337
- self.draw_tiny_indicator(
338
- gc,
339
- "^",
340
- x0,
341
- y0,
342
- x1,
343
- y1,
344
- self.selection_style[self.selection_method[sector] - 1][0],
345
- self.selection_style[self.selection_method[sector] - 1][1],
346
- )
1
+ """
2
+ Specifically draws the rectangle selection box and deals with emphasis of selected objects.
3
+ Special case: if the user did not move the mouse within the first 0.5 seconds after
4
+ the initial mouse press then we assume a drag move.
5
+ """
6
+ from time import perf_counter
7
+
8
+ import numpy as np
9
+ import wx
10
+
11
+ from meerk40t.core.elements.element_types import elem_nodes
12
+ from meerk40t.gui.scene.scene import (
13
+ HITCHAIN_HIT,
14
+ RESPONSE_CHAIN,
15
+ RESPONSE_CONSUME,
16
+ RESPONSE_DROP,
17
+ )
18
+ from meerk40t.gui.scene.widget import Widget
19
+ from meerk40t.gui.wxutils import get_matrix_scale, get_gc_full_scale
20
+ from meerk40t.tools.geomstr import NON_GEOMETRY_TYPES
21
+
22
+
23
+ class RectSelectWidget(Widget):
24
+ """
25
+ SceneWidget
26
+
27
+ Rectangle Selection Widget, draws the selection rectangle if left-clicked and dragged
28
+ """
29
+
30
+ # selection_method = 1 = hit, 2 = cross, 3 = enclose
31
+ SELECTION_TOUCH = 1
32
+ SELECTION_CROSS = 2
33
+ SELECTION_ENCLOSE = 3
34
+ selection_text_shift = " Previously selected remain selected!"
35
+ selection_text_control = " Invert selection state of elements!"
36
+
37
+ # 2 | 1 Define Selection method per sector, movement of mouse from point of origin into that sector...
38
+ # - + -
39
+ # 3 | 0
40
+ #
41
+ selection_method = [
42
+ SELECTION_ENCLOSE,
43
+ SELECTION_ENCLOSE,
44
+ SELECTION_TOUCH,
45
+ SELECTION_TOUCH,
46
+ ] # Selection rectangle to the right: enclose, to the left: touch
47
+
48
+ was_lb_raised = False
49
+
50
+ def __init__(self, scene):
51
+ Widget.__init__(self, scene, all=True)
52
+ # Color for selection rectangle (hit, cross, enclose)
53
+ self.selection_style = [
54
+ [
55
+ self.scene.colors.color_selection1,
56
+ wx.PENSTYLE_DOT_DASH,
57
+ "Select all elements the selection rectangle touches.",
58
+ ],
59
+ [
60
+ self.scene.colors.color_selection2,
61
+ wx.PENSTYLE_DOT,
62
+ "Select all elements the selection rectangle crosses.",
63
+ ],
64
+ [
65
+ self.scene.colors.color_selection3,
66
+ wx.PENSTYLE_SHORT_DASH,
67
+ "Select all elements the selection rectangle encloses.",
68
+ ],
69
+ ]
70
+ self.selection_pen = wx.Pen()
71
+ self.selection_pen.SetColour(self.selection_style[0][0])
72
+ self.selection_pen.SetWidth(25)
73
+ self.selection_pen.SetStyle(self.selection_style[0][1])
74
+ # want to have sharp edges
75
+ self.selection_pen.SetJoin(wx.JOIN_MITER)
76
+ self.start_location = None
77
+ self.end_location = None
78
+ self.modifiers = []
79
+ self.mouse_down_time = 0
80
+ self.scene.context.setting(bool, "delayed_move", True)
81
+ self.mode = "select"
82
+ self.can_drag_move = False
83
+
84
+ def hit(self):
85
+ return HITCHAIN_HIT
86
+
87
+ store_last_msg = ""
88
+
89
+ @property
90
+ def sector(self):
91
+ sx = self.start_location[0]
92
+ sy = self.start_location[1]
93
+ ex = self.end_location[0]
94
+ ey = self.end_location[1]
95
+ if sx <= ex:
96
+ if sy <= ey:
97
+ return 0
98
+ else:
99
+ return 1
100
+ else:
101
+ if sy <= ey:
102
+ return 3
103
+ else:
104
+ return 2
105
+
106
+ def rect_select(self, elements, sx, sy, ex, ey):
107
+ sector = self.sector
108
+ selected = False
109
+ # We don't want every single element to to issue a signal
110
+ with elements.signalfree("emphasized"):
111
+ for node in elements.elems():
112
+ try:
113
+ q = node.bounds
114
+ except AttributeError:
115
+ continue # This element has no bounds.
116
+ if q is None:
117
+ continue
118
+ if hasattr(node, "hidden") and node.hidden:
119
+ continue
120
+ if hasattr(node, "can_emphasize") and not node.can_emphasize:
121
+ continue
122
+ xmin = q[0]
123
+ ymin = q[1]
124
+ xmax = q[2]
125
+ ymax = q[3]
126
+ # no hit
127
+ cover = 0
128
+ # Check Hit
129
+ # The rectangles don't overlap if
130
+ # one rectangle's minimum in some dimension
131
+ # is greater than the other's maximum in
132
+ # that dimension.
133
+ if not ((sx > xmax) or (xmin > ex) or (sy > ymax) or (ymin > ey)):
134
+ cover = self.SELECTION_TOUCH
135
+ # If selection rect is fully inside an object then ignore
136
+ if sx > xmin and ex < xmax and sy > ymin and ey < ymax:
137
+ cover = 0
138
+
139
+ # Check Cross
140
+ if (
141
+ ((sx <= xmin) and (xmax <= ex))
142
+ and not ((sy > ymax) or (ey < ymin))
143
+ or ((sy <= ymin) and (ymax <= ey))
144
+ and not ((sx > xmax) or (ex < xmin))
145
+ ):
146
+ cover = self.SELECTION_CROSS
147
+ # Check contain
148
+ if ((sx <= xmin) and (xmax <= ex)) and ((sy <= ymin) and (ymax <= ey)):
149
+ cover = self.SELECTION_ENCLOSE
150
+
151
+ if "shift" in self.modifiers:
152
+ # Add Selection
153
+ if cover >= self.selection_method[sector]:
154
+ node.emphasized = True
155
+ node.selected = True
156
+ selected = True
157
+ elif "ctrl" in self.modifiers:
158
+ # Invert Selection
159
+ if cover >= self.selection_method[sector]:
160
+ node.emphasized = not node.emphasized
161
+ node.selected = node.emphasized
162
+ selected = True
163
+ else:
164
+ # Replace Selection
165
+ if cover >= self.selection_method[sector]:
166
+ node.emphasized = True
167
+ node.selected = True
168
+ selected = True
169
+ else:
170
+ node.emphasized = False
171
+ node.selected = False
172
+ if selected:
173
+ self.scene.context.signal("element_clicked")
174
+
175
+ def update_statusmsg(self, value):
176
+ if value != self.store_last_msg:
177
+ self.store_last_msg = value
178
+ self.scene.context.signal("statusmsg", value)
179
+
180
+ # debug_msg = ""
181
+
182
+ def event(
183
+ self, window_pos=None, space_pos=None, event_type=None, modifiers=None, **kwargs
184
+ ):
185
+ def contains(box, x, y=None):
186
+ if box is None:
187
+ return False
188
+ if y is None:
189
+ y = x[1]
190
+ x = x[0]
191
+ return box[0] <= x <= box[2] and box[1] <= y <= box[3]
192
+
193
+ def move_to(dx, dy):
194
+ if dx == 0 and dy == 0:
195
+ return
196
+ # self.total_dx += dx
197
+ # self.total_dy += dy
198
+ b = self.scene.context.elements._emphasized_bounds
199
+ if b is None:
200
+ b = self.scene.context.elements.selected_area()
201
+ if b is None:
202
+ # There is no emphasized bounds or selected area.
203
+ return
204
+ allowlockmove = self.scene.context.elements.lock_allows_move
205
+ with self.scene.context.elements.undofree():
206
+ for e in self.scene.context.elements.flat(
207
+ types=elem_nodes, emphasized=True
208
+ ):
209
+ if not e.can_move(allowlockmove):
210
+ continue
211
+ e.matrix.post_translate(dx, dy)
212
+ # We would normally not adjust the node properties,
213
+ # but the pure adjustment of the bbox is hopefully not hurting
214
+ e.translated(dx, dy)
215
+ self.scene.context.elements.update_bounds(
216
+ [b[0] + dx, b[1] + dy, b[2] + dx, b[3] + dy]
217
+ )
218
+ self.scene.request_refresh()
219
+
220
+ if modifiers is not None:
221
+ self.modifiers = modifiers
222
+
223
+ elements = self.scene.context.elements
224
+ if event_type == "leftdown":
225
+ self.mouse_down_time = perf_counter()
226
+ self.mode = "unclear"
227
+ self.start_location = space_pos
228
+ self.end_location = space_pos
229
+ if contains(self.scene.context.elements._emphasized_bounds, space_pos):
230
+ self.can_drag_move = True
231
+ # print ("RectSelect consumed leftdown")
232
+ return RESPONSE_CONSUME
233
+ elif event_type == "leftclick":
234
+ # That's too fast
235
+ # still chaining though
236
+ self.scene.request_refresh()
237
+ self.reset()
238
+ return RESPONSE_CHAIN
239
+ elif event_type == "leftup":
240
+ if self.mode == "select":
241
+ if self.start_location is None:
242
+ return RESPONSE_CHAIN
243
+ _ = self.scene.context._
244
+ self.update_statusmsg(_("Status"))
245
+ elements.validate_selected_area()
246
+ sx = min(self.start_location[0], self.end_location[0])
247
+ sy = min(self.start_location[1], self.end_location[1])
248
+ ex = max(self.start_location[0], self.end_location[0])
249
+ ey = max(self.start_location[1], self.end_location[1])
250
+ self.rect_select(elements, sx, sy, ex, ey)
251
+
252
+ self.scene.request_refresh()
253
+ self.scene.context.signal("select_emphasized_tree", 0)
254
+ else:
255
+
256
+ def shortest_distance(p1, p2, tuplemode):
257
+ """
258
+ Calculates the shortest distance between two arrays of 2-dimensional points.
259
+ """
260
+ # Calculate the Euclidean distance between each point in p1 and p2
261
+ if tuplemode:
262
+ # For an array of tuples:
263
+ dist = np.sqrt(np.sum((p1[:, np.newaxis] - p2) ** 2, axis=2))
264
+ else:
265
+ # For an array of complex numbers
266
+ dist = np.abs(p1[:, np.newaxis] - p2[np.newaxis, :])
267
+
268
+ # Find the minimum distance and its corresponding indices
269
+ min_dist = np.min(dist)
270
+ if np.isnan(min_dist):
271
+ return None, 0, 0
272
+ min_indices = np.argwhere(dist == min_dist)
273
+
274
+ # Return the coordinates of the two points
275
+ return min_dist, p1[min_indices[0][0]], p2[min_indices[0][1]]
276
+
277
+ b = self.scene.context.elements._emphasized_bounds
278
+ if b is None:
279
+ b = self.scene.context.elements.selected_area()
280
+ matrix = self.scene.widget_root.scene_widget.matrix
281
+ did_snap_to_point = False
282
+ if (
283
+ self.scene.context.snap_points
284
+ and "shift" not in modifiers
285
+ and b is not None
286
+ ):
287
+ gap = self.scene.context.action_attract_len / get_matrix_scale(matrix)
288
+ # We gather all points of non-selected elements,
289
+ # but only those that lie within the boundaries
290
+ # of the selected area
291
+ # We compare every point of the selected elements
292
+ # with the points of the non-selected elements (provided they
293
+ # lie within the selection area plus boundary) and look for
294
+ # the closest distance.
295
+
296
+ # t1 = perf_counter()
297
+ other_points = []
298
+ selected_points = []
299
+ for e in self.scene.context.elements.elems():
300
+ if e.emphasized:
301
+ target = selected_points
302
+ else:
303
+ target = other_points
304
+ if not hasattr(e, "as_geometry"):
305
+ continue
306
+ geom = e.as_geometry()
307
+ last = None
308
+ for seg in geom.segments[: geom.index]:
309
+ start = seg[0]
310
+ seg_type = geom._segtype(seg)
311
+ end = seg[4]
312
+ if seg_type in NON_GEOMETRY_TYPES:
313
+ continue
314
+ if np.isnan(start) or np.isnan(end):
315
+ print (f"Strange, encountered within rectselect a segment with type: {seg_type} and start={start}, end={end} - coming from element type {e.type}\nPlease inform the developers")
316
+ continue
317
+ if start != last:
318
+ xx = start.real
319
+ yy = start.imag
320
+ ignore = (
321
+ xx < b[0] - gap
322
+ or xx > b[2] + gap
323
+ or yy < b[1] - gap
324
+ or yy > b[3] + gap
325
+ )
326
+ if not ignore:
327
+ target.append(start)
328
+ xx = end.real
329
+ yy = end.imag
330
+ ignore = (
331
+ xx < b[0] - gap
332
+ or xx > b[2] + gap
333
+ or yy < b[1] - gap
334
+ or yy > b[3] + gap
335
+ )
336
+ if not ignore:
337
+ target.append(end)
338
+ last = end
339
+ # t2 = perf_counter()
340
+ if (
341
+ other_points is not None
342
+ and selected_points is not None
343
+ and len(other_points) > 0
344
+ and len(selected_points) > 0
345
+ ):
346
+ np_other = np.asarray(other_points)
347
+ np_selected = np.asarray(selected_points)
348
+ dist, pt1, pt2 = shortest_distance(np_other, np_selected, False)
349
+
350
+ if dist is not None and dist < gap:
351
+ did_snap_to_point = True
352
+ dx = pt1.real - pt2.real
353
+ dy = pt1.imag - pt2.imag
354
+ move_to(dx, dy)
355
+ # Get new value
356
+ b = self.scene.context.elements._emphasized_bounds
357
+ # t3 = perf_counter()
358
+ # print (f"Snap, compared {len(selected_points)} pts to {len(other_points)} pts. Total time: {t3-t1:.2f}sec, Generation: {t2-t1:.2f}sec, shortest: {t3-t2:.2f}sec")
359
+ if (
360
+ self.scene.context.snap_grid
361
+ and "shift" not in modifiers
362
+ and b is not None
363
+ and not did_snap_to_point
364
+ ):
365
+ # t1 = perf_counter()
366
+ gap = self.scene.context.grid_attract_len / get_matrix_scale(matrix)
367
+ # Check for corner points + center:
368
+ selected_points = (
369
+ (b[0], b[1]),
370
+ (b[2], b[1]),
371
+ (b[0], b[3]),
372
+ (b[2], b[3]),
373
+ ((b[0] + b[2]) / 2, (b[1] + b[3]) / 2),
374
+ )
375
+ other_points = self.scene.pane.grid.grid_points
376
+ if (
377
+ other_points is not None
378
+ and selected_points is not None
379
+ and len(other_points) > 0
380
+ and len(selected_points) > 0
381
+ ):
382
+ np_other = np.asarray(other_points)
383
+ np_selected = np.asarray(selected_points)
384
+ dist, pt1, pt2 = shortest_distance(np_other, np_selected, True)
385
+ if dist is not None and dist < gap:
386
+ # did_snap_to_point = True
387
+ dx = pt1[0] - pt2[0]
388
+ dy = pt1[1] - pt2[1]
389
+ move_to(dx, dy)
390
+ # Get new value
391
+ b = self.scene.context.elements._emphasized_bounds
392
+
393
+ # t2 = perf_counter()
394
+ # print (f"Corner-points, compared {len(selected_points)} pts to {len(other_points)} pts. Total time: {t2-t1:.2f}sec")
395
+ # Even then magnets win!
396
+ dx, dy = self.scene.pane.revised_magnet_bound(b)
397
+ move_to(dx, dy)
398
+
399
+ self.reset()
400
+
401
+ return RESPONSE_CONSUME
402
+ elif event_type == "move":
403
+ if self.mode == "unclear":
404
+ current_time = perf_counter()
405
+ # print (f"{current_time - self.mouse_down_time:.2f}sec.")
406
+ if current_time - self.mouse_down_time > 0.5 and self.can_drag_move:
407
+ self.mode = "move"
408
+ self.scene.cursor("sizing")
409
+ else:
410
+ self.mode = "select"
411
+ self.scene.cursor("arrow")
412
+
413
+ if self.mode == "select":
414
+ self.scene.request_refresh()
415
+ self.end_location = space_pos
416
+ elif self.mode == "move":
417
+ dx = space_pos[4]
418
+ dy = space_pos[5]
419
+ move_to(dx, dy)
420
+
421
+ return RESPONSE_CONSUME
422
+ elif event_type == "lost":
423
+ self.reset()
424
+ return RESPONSE_CONSUME
425
+ return RESPONSE_DROP
426
+
427
+ def reset(self):
428
+ self.start_location = None
429
+ self.end_location = None
430
+ self.mode = "unclear"
431
+ self.mouse_down_time = 0
432
+ self.can_drag_move = False
433
+ self.scene.cursor("arrow")
434
+
435
+ def draw_rectangle(self, gc, x0, y0, x1, y1, tcolor, tstyle):
436
+ # Linux / Darwin do not recognize the GraphicsContext TransformationMatrix
437
+ # when drawing dashed/dotted lines, so they always appear to be solid
438
+ # (even if they are dotted on a microscopic level)
439
+ # To circumvent this issue, we scale the gc back
440
+ gc.PushState()
441
+ sx, sy = get_gc_full_scale(gc)
442
+ gc.Scale(1 / sx, 1 / sy)
443
+ self.selection_pen.SetColour(tcolor)
444
+ self.selection_pen.SetStyle(tstyle)
445
+ gc.SetPen(self.selection_pen)
446
+ linewidth = 1
447
+ try:
448
+ self.selection_pen.SetWidth(linewidth)
449
+ except TypeError:
450
+ self.selection_pen.SetWidth(int(linewidth))
451
+ gc.SetPen(self.selection_pen)
452
+ gc.StrokeLine(x0 * sx, y0 * sy, x1 * sx, y0 * sy)
453
+ gc.StrokeLine(x1 * sx, y0 * sy, x1 * sx, y1 * sy)
454
+ gc.StrokeLine(x1 * sx, y1 * sy, x0 * sx, y1 * sy)
455
+ gc.StrokeLine(x0 * sx, y1 * sy, x0 * sx, y0 * sy)
456
+ gc.PopState()
457
+
458
+ def draw_tiny_indicator(self, gc, symbol, x0, y0, x1, y1, tcolor, tstyle):
459
+ # Linux / Darwin do not recognize the GraphicsContext TransformationMatrix
460
+ # when drawing dashed/dotted lines, so they always appear to be solid
461
+ # (even if they are dotted on a microscopic level)
462
+ # To circumvent this issue, we scale the gc back
463
+ gc.PushState()
464
+ sx, sy = get_gc_full_scale(gc)
465
+ # print (f"sx={sx}, sy={sy}")
466
+ gc.Scale(1 / sx, 1 / sy)
467
+ self.selection_pen.SetColour(tcolor)
468
+ self.selection_pen.SetStyle(tstyle)
469
+
470
+ linewidth = 1
471
+ try:
472
+ self.selection_pen.SetWidth(linewidth)
473
+ except TypeError:
474
+ self.selection_pen.SetWidth(int(linewidth))
475
+ gc.SetPen(self.selection_pen)
476
+ delta_X = 15.0
477
+ delta_Y = 15.0
478
+ x0 *= sx
479
+ x1 *= sx
480
+ y0 *= sx
481
+ y1 *= sx
482
+ if abs(x1 - x0) > delta_X and abs(y1 - y0) > delta_Y: # Don't draw if too tiny
483
+ # Draw tiny '+' in corner of pointer
484
+ x_signum = +1 * delta_X if x0 < x1 else -1 * delta_X
485
+ y_signum = +1 * delta_Y if y0 < y1 else -1 * delta_X
486
+ ax1 = x1 - x_signum
487
+ ay1 = y1 - y_signum
488
+
489
+ gc.SetPen(self.selection_pen)
490
+ gc.StrokeLine(ax1, y1, ax1, ay1)
491
+ gc.StrokeLine(ax1, ay1, x1, ay1)
492
+ font_size = 10.0
493
+ if font_size < 1.0:
494
+ font_size = 1.0
495
+ try:
496
+ font = wx.Font(
497
+ font_size,
498
+ wx.FONTFAMILY_SWISS,
499
+ wx.FONTSTYLE_NORMAL,
500
+ wx.FONTWEIGHT_NORMAL,
501
+ )
502
+ except TypeError:
503
+ font = wx.Font(
504
+ int(font_size),
505
+ wx.FONTFAMILY_SWISS,
506
+ wx.FONTSTYLE_NORMAL,
507
+ wx.FONTWEIGHT_NORMAL,
508
+ )
509
+ gc.SetFont(font, tcolor)
510
+ (t_width, t_height) = gc.GetTextExtent(symbol)
511
+ gc.DrawText(
512
+ symbol, (ax1 + x1) / 2 - t_width / 2, (ay1 + y1) / 2 - t_height / 2
513
+ )
514
+ if (
515
+ abs(x1 - x0) > 2 * delta_X and abs(y1 - y0) > 2 * delta_Y
516
+ ): # Don't draw if too tiny
517
+ # Draw second symbol at origin
518
+ ax1 = x0 + x_signum
519
+ ay1 = y0 + y_signum
520
+ gc.StrokeLine(ax1, y0, ax1, ay1)
521
+ gc.StrokeLine(ax1, ay1, x0, ay1)
522
+ gc.DrawText(
523
+ symbol, (ax1 + x0) / 2 - t_width / 2, (ay1 + y0) / 2 - t_height / 2
524
+ )
525
+ gc.PopState()
526
+
527
+ def process_draw(self, gc):
528
+ """
529
+ Draw the selection rectangle
530
+ """
531
+ if (
532
+ self.mode == "select"
533
+ and self.start_location is not None
534
+ and self.end_location is not None
535
+ ):
536
+ self.selection_style[0][0] = self.scene.colors.color_selection1
537
+ self.selection_style[1][0] = self.scene.colors.color_selection2
538
+ self.selection_style[2][0] = self.scene.colors.color_selection3
539
+ x0 = self.start_location[0]
540
+ y0 = self.start_location[1]
541
+ x1 = self.end_location[0]
542
+ y1 = self.end_location[1]
543
+ sector = self.sector
544
+
545
+ _ = self.scene.context._
546
+ statusmsg = _(self.selection_style[self.selection_method[sector] - 1][2])
547
+ if "shift" in self.modifiers:
548
+ statusmsg += _(self.selection_text_shift)
549
+ elif "ctrl" in self.modifiers:
550
+ statusmsg += _(self.selection_text_control)
551
+
552
+ self.update_statusmsg(statusmsg)
553
+ gcstyle = self.selection_style[self.selection_method[sector] - 1][0]
554
+ gccolor = self.selection_style[self.selection_method[sector] - 1][1]
555
+ self.draw_rectangle(
556
+ gc,
557
+ x0,
558
+ y0,
559
+ x1,
560
+ y1,
561
+ gcstyle,
562
+ gccolor,
563
+ )
564
+
565
+ # Determine Colour on selection mode: standard (from left top to right bottom) = Blue, else Green
566
+ # Draw indicator...
567
+ if "shift" in self.modifiers:
568
+ self.draw_tiny_indicator(
569
+ gc,
570
+ "+",
571
+ x0,
572
+ y0,
573
+ x1,
574
+ y1,
575
+ gcstyle,
576
+ gccolor,
577
+ )
578
+
579
+ elif "ctrl" in self.modifiers:
580
+ self.draw_tiny_indicator(
581
+ gc,
582
+ "^",
583
+ x0,
584
+ y0,
585
+ x1,
586
+ y1,
587
+ self.selection_style[self.selection_method[sector] - 1][0],
588
+ self.selection_style[self.selection_method[sector] - 1][1],
589
+ )