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.
- meerk40t/__init__.py +1 -1
- meerk40t/balormk/balor_params.py +167 -167
- meerk40t/balormk/clone_loader.py +457 -457
- meerk40t/balormk/controller.py +1566 -1512
- meerk40t/balormk/cylindermod.py +64 -0
- meerk40t/balormk/device.py +966 -1959
- meerk40t/balormk/driver.py +778 -591
- meerk40t/balormk/galvo_commands.py +1195 -0
- meerk40t/balormk/gui/balorconfig.py +237 -111
- meerk40t/balormk/gui/balorcontroller.py +191 -184
- meerk40t/balormk/gui/baloroperationproperties.py +116 -115
- meerk40t/balormk/gui/corscene.py +845 -0
- meerk40t/balormk/gui/gui.py +179 -147
- meerk40t/balormk/livelightjob.py +466 -382
- meerk40t/balormk/mock_connection.py +131 -109
- meerk40t/balormk/plugin.py +133 -135
- meerk40t/balormk/usb_connection.py +306 -301
- meerk40t/camera/__init__.py +1 -1
- meerk40t/camera/camera.py +514 -397
- meerk40t/camera/gui/camerapanel.py +1241 -1095
- meerk40t/camera/gui/gui.py +58 -58
- meerk40t/camera/plugin.py +441 -399
- meerk40t/ch341/__init__.py +27 -27
- meerk40t/ch341/ch341device.py +628 -628
- meerk40t/ch341/libusb.py +595 -589
- meerk40t/ch341/mock.py +171 -171
- meerk40t/ch341/windriver.py +157 -157
- meerk40t/constants.py +13 -0
- meerk40t/core/__init__.py +1 -1
- meerk40t/core/bindalias.py +550 -539
- meerk40t/core/core.py +47 -47
- meerk40t/core/cutcode/cubiccut.py +73 -73
- meerk40t/core/cutcode/cutcode.py +315 -312
- meerk40t/core/cutcode/cutgroup.py +141 -137
- meerk40t/core/cutcode/cutobject.py +192 -185
- meerk40t/core/cutcode/dwellcut.py +37 -37
- meerk40t/core/cutcode/gotocut.py +29 -29
- meerk40t/core/cutcode/homecut.py +29 -29
- meerk40t/core/cutcode/inputcut.py +34 -34
- meerk40t/core/cutcode/linecut.py +33 -33
- meerk40t/core/cutcode/outputcut.py +34 -34
- meerk40t/core/cutcode/plotcut.py +335 -335
- meerk40t/core/cutcode/quadcut.py +61 -61
- meerk40t/core/cutcode/rastercut.py +168 -148
- meerk40t/core/cutcode/waitcut.py +34 -34
- meerk40t/core/cutplan.py +1843 -1316
- meerk40t/core/drivers.py +330 -329
- meerk40t/core/elements/align.py +801 -669
- meerk40t/core/elements/branches.py +1844 -1507
- meerk40t/core/elements/clipboard.py +229 -219
- meerk40t/core/elements/element_treeops.py +4561 -2837
- meerk40t/core/elements/element_types.py +125 -105
- meerk40t/core/elements/elements.py +4329 -3617
- meerk40t/core/elements/files.py +117 -64
- meerk40t/core/elements/geometry.py +473 -224
- meerk40t/core/elements/grid.py +467 -316
- meerk40t/core/elements/materials.py +158 -94
- meerk40t/core/elements/notes.py +50 -38
- meerk40t/core/elements/offset_clpr.py +933 -912
- meerk40t/core/elements/offset_mk.py +963 -955
- meerk40t/core/elements/penbox.py +339 -267
- meerk40t/core/elements/placements.py +300 -83
- meerk40t/core/elements/render.py +785 -687
- meerk40t/core/elements/shapes.py +2618 -2092
- meerk40t/core/elements/trace.py +651 -563
- meerk40t/core/elements/tree_commands.py +415 -409
- meerk40t/core/elements/undo_redo.py +116 -58
- meerk40t/core/elements/wordlist.py +319 -200
- meerk40t/core/exceptions.py +9 -9
- meerk40t/core/laserjob.py +220 -220
- meerk40t/core/logging.py +63 -63
- meerk40t/core/node/blobnode.py +83 -86
- meerk40t/core/node/bootstrap.py +105 -103
- meerk40t/core/node/branch_elems.py +40 -31
- meerk40t/core/node/branch_ops.py +45 -38
- meerk40t/core/node/branch_regmark.py +48 -41
- meerk40t/core/node/cutnode.py +29 -32
- meerk40t/core/node/effect_hatch.py +375 -257
- meerk40t/core/node/effect_warp.py +398 -0
- meerk40t/core/node/effect_wobble.py +441 -309
- meerk40t/core/node/elem_ellipse.py +404 -309
- meerk40t/core/node/elem_image.py +1082 -801
- meerk40t/core/node/elem_line.py +358 -292
- meerk40t/core/node/elem_path.py +259 -201
- meerk40t/core/node/elem_point.py +129 -102
- meerk40t/core/node/elem_polyline.py +310 -246
- meerk40t/core/node/elem_rect.py +376 -286
- meerk40t/core/node/elem_text.py +445 -418
- meerk40t/core/node/filenode.py +59 -40
- meerk40t/core/node/groupnode.py +138 -74
- meerk40t/core/node/image_processed.py +777 -766
- meerk40t/core/node/image_raster.py +156 -113
- meerk40t/core/node/layernode.py +31 -31
- meerk40t/core/node/mixins.py +135 -107
- meerk40t/core/node/node.py +1427 -1304
- meerk40t/core/node/nutils.py +117 -114
- meerk40t/core/node/op_cut.py +462 -335
- meerk40t/core/node/op_dots.py +296 -251
- meerk40t/core/node/op_engrave.py +414 -311
- meerk40t/core/node/op_image.py +755 -369
- meerk40t/core/node/op_raster.py +787 -522
- meerk40t/core/node/place_current.py +37 -40
- meerk40t/core/node/place_point.py +329 -126
- meerk40t/core/node/refnode.py +58 -47
- meerk40t/core/node/rootnode.py +225 -219
- meerk40t/core/node/util_console.py +48 -48
- meerk40t/core/node/util_goto.py +84 -65
- meerk40t/core/node/util_home.py +61 -61
- meerk40t/core/node/util_input.py +102 -102
- meerk40t/core/node/util_output.py +102 -102
- meerk40t/core/node/util_wait.py +65 -65
- meerk40t/core/parameters.py +709 -707
- meerk40t/core/planner.py +875 -785
- meerk40t/core/plotplanner.py +656 -652
- meerk40t/core/space.py +120 -113
- meerk40t/core/spoolers.py +706 -705
- meerk40t/core/svg_io.py +1836 -1549
- meerk40t/core/treeop.py +534 -445
- meerk40t/core/undos.py +278 -124
- meerk40t/core/units.py +784 -680
- meerk40t/core/view.py +393 -322
- meerk40t/core/webhelp.py +62 -62
- meerk40t/core/wordlist.py +513 -504
- meerk40t/cylinder/cylinder.py +247 -0
- meerk40t/cylinder/gui/cylindersettings.py +41 -0
- meerk40t/cylinder/gui/gui.py +24 -0
- meerk40t/device/__init__.py +1 -1
- meerk40t/device/basedevice.py +322 -123
- meerk40t/device/devicechoices.py +50 -0
- meerk40t/device/dummydevice.py +163 -128
- meerk40t/device/gui/defaultactions.py +618 -602
- meerk40t/device/gui/effectspanel.py +114 -0
- meerk40t/device/gui/formatterpanel.py +253 -290
- meerk40t/device/gui/warningpanel.py +337 -260
- meerk40t/device/mixins.py +13 -13
- meerk40t/dxf/__init__.py +1 -1
- meerk40t/dxf/dxf_io.py +766 -554
- meerk40t/dxf/plugin.py +47 -35
- meerk40t/external_plugins.py +79 -79
- meerk40t/external_plugins_build.py +28 -28
- meerk40t/extra/cag.py +112 -116
- meerk40t/extra/coolant.py +403 -0
- meerk40t/extra/encode_detect.py +198 -0
- meerk40t/extra/ezd.py +1165 -1165
- meerk40t/extra/hershey.py +835 -340
- meerk40t/extra/imageactions.py +322 -316
- meerk40t/extra/inkscape.py +630 -622
- meerk40t/extra/lbrn.py +424 -424
- meerk40t/extra/outerworld.py +284 -0
- meerk40t/extra/param_functions.py +1542 -1556
- meerk40t/extra/potrace.py +257 -253
- meerk40t/extra/serial_exchange.py +118 -0
- meerk40t/extra/updater.py +602 -453
- meerk40t/extra/vectrace.py +147 -146
- meerk40t/extra/winsleep.py +83 -83
- meerk40t/extra/xcs_reader.py +597 -0
- meerk40t/fill/fills.py +781 -335
- meerk40t/fill/patternfill.py +1061 -1061
- meerk40t/fill/patterns.py +614 -567
- meerk40t/grbl/control.py +87 -87
- meerk40t/grbl/controller.py +990 -903
- meerk40t/grbl/device.py +1081 -768
- meerk40t/grbl/driver.py +989 -771
- meerk40t/grbl/emulator.py +532 -497
- meerk40t/grbl/gcodejob.py +783 -767
- meerk40t/grbl/gui/grblconfiguration.py +373 -298
- meerk40t/grbl/gui/grblcontroller.py +485 -271
- meerk40t/grbl/gui/grblhardwareconfig.py +269 -153
- meerk40t/grbl/gui/grbloperationconfig.py +105 -0
- meerk40t/grbl/gui/gui.py +147 -116
- meerk40t/grbl/interpreter.py +44 -44
- meerk40t/grbl/loader.py +22 -22
- meerk40t/grbl/mock_connection.py +56 -56
- meerk40t/grbl/plugin.py +294 -264
- meerk40t/grbl/serial_connection.py +93 -88
- meerk40t/grbl/tcp_connection.py +81 -79
- meerk40t/grbl/ws_connection.py +112 -0
- meerk40t/gui/__init__.py +1 -1
- meerk40t/gui/about.py +2042 -296
- meerk40t/gui/alignment.py +1644 -1608
- meerk40t/gui/autoexec.py +199 -0
- meerk40t/gui/basicops.py +791 -670
- meerk40t/gui/bufferview.py +77 -71
- meerk40t/gui/busy.py +170 -133
- meerk40t/gui/choicepropertypanel.py +1673 -1469
- meerk40t/gui/consolepanel.py +706 -542
- meerk40t/gui/devicepanel.py +687 -581
- meerk40t/gui/dialogoptions.py +110 -107
- meerk40t/gui/executejob.py +316 -306
- meerk40t/gui/fonts.py +90 -90
- meerk40t/gui/functionwrapper.py +252 -0
- meerk40t/gui/gui_mixins.py +729 -0
- meerk40t/gui/guicolors.py +205 -182
- meerk40t/gui/help_assets/help_assets.py +218 -201
- meerk40t/gui/helper.py +154 -0
- meerk40t/gui/hersheymanager.py +1430 -846
- meerk40t/gui/icons.py +3422 -2747
- meerk40t/gui/imagesplitter.py +555 -508
- meerk40t/gui/keymap.py +354 -344
- meerk40t/gui/laserpanel.py +892 -806
- meerk40t/gui/laserrender.py +1470 -1232
- meerk40t/gui/lasertoolpanel.py +805 -793
- meerk40t/gui/magnetoptions.py +436 -0
- meerk40t/gui/materialmanager.py +2917 -0
- meerk40t/gui/materialtest.py +1722 -1694
- meerk40t/gui/mkdebug.py +646 -359
- meerk40t/gui/mwindow.py +163 -140
- meerk40t/gui/navigationpanels.py +2605 -2467
- meerk40t/gui/notes.py +143 -142
- meerk40t/gui/opassignment.py +414 -410
- meerk40t/gui/operation_info.py +310 -299
- meerk40t/gui/plugin.py +494 -328
- meerk40t/gui/position.py +714 -669
- meerk40t/gui/preferences.py +901 -650
- meerk40t/gui/propertypanels/attributes.py +1461 -1131
- meerk40t/gui/propertypanels/blobproperty.py +117 -114
- meerk40t/gui/propertypanels/consoleproperty.py +83 -80
- meerk40t/gui/propertypanels/gotoproperty.py +77 -0
- meerk40t/gui/propertypanels/groupproperties.py +223 -217
- meerk40t/gui/propertypanels/hatchproperty.py +489 -469
- meerk40t/gui/propertypanels/imageproperty.py +2244 -1384
- meerk40t/gui/propertypanels/inputproperty.py +59 -58
- meerk40t/gui/propertypanels/opbranchproperties.py +82 -80
- meerk40t/gui/propertypanels/operationpropertymain.py +1890 -1638
- meerk40t/gui/propertypanels/outputproperty.py +59 -58
- meerk40t/gui/propertypanels/pathproperty.py +389 -380
- meerk40t/gui/propertypanels/placementproperty.py +1214 -383
- meerk40t/gui/propertypanels/pointproperty.py +140 -136
- meerk40t/gui/propertypanels/propertywindow.py +313 -181
- meerk40t/gui/propertypanels/rasterwizardpanels.py +996 -912
- meerk40t/gui/propertypanels/regbranchproperties.py +76 -0
- meerk40t/gui/propertypanels/textproperty.py +770 -755
- meerk40t/gui/propertypanels/waitproperty.py +56 -55
- meerk40t/gui/propertypanels/warpproperty.py +121 -0
- meerk40t/gui/propertypanels/wobbleproperty.py +255 -204
- meerk40t/gui/ribbon.py +2468 -2210
- meerk40t/gui/scene/scene.py +1100 -1051
- meerk40t/gui/scene/sceneconst.py +22 -22
- meerk40t/gui/scene/scenepanel.py +439 -349
- meerk40t/gui/scene/scenespacewidget.py +365 -365
- meerk40t/gui/scene/widget.py +518 -505
- meerk40t/gui/scenewidgets/affinemover.py +215 -215
- meerk40t/gui/scenewidgets/attractionwidget.py +315 -309
- meerk40t/gui/scenewidgets/bedwidget.py +120 -97
- meerk40t/gui/scenewidgets/elementswidget.py +137 -107
- meerk40t/gui/scenewidgets/gridwidget.py +785 -745
- meerk40t/gui/scenewidgets/guidewidget.py +765 -765
- meerk40t/gui/scenewidgets/laserpathwidget.py +66 -66
- meerk40t/gui/scenewidgets/machineoriginwidget.py +86 -86
- meerk40t/gui/scenewidgets/nodeselector.py +28 -28
- meerk40t/gui/scenewidgets/rectselectwidget.py +589 -346
- meerk40t/gui/scenewidgets/relocatewidget.py +33 -33
- meerk40t/gui/scenewidgets/reticlewidget.py +83 -83
- meerk40t/gui/scenewidgets/selectionwidget.py +2952 -2756
- meerk40t/gui/simpleui.py +357 -333
- meerk40t/gui/simulation.py +2431 -2094
- meerk40t/gui/snapoptions.py +208 -203
- meerk40t/gui/spoolerpanel.py +1227 -1180
- meerk40t/gui/statusbarwidgets/defaultoperations.py +480 -353
- meerk40t/gui/statusbarwidgets/infowidget.py +520 -483
- meerk40t/gui/statusbarwidgets/opassignwidget.py +356 -355
- meerk40t/gui/statusbarwidgets/selectionwidget.py +172 -171
- meerk40t/gui/statusbarwidgets/shapepropwidget.py +754 -236
- meerk40t/gui/statusbarwidgets/statusbar.py +272 -260
- meerk40t/gui/statusbarwidgets/statusbarwidget.py +268 -270
- meerk40t/gui/statusbarwidgets/strokewidget.py +267 -251
- meerk40t/gui/themes.py +200 -78
- meerk40t/gui/tips.py +591 -0
- meerk40t/gui/toolwidgets/circlebrush.py +35 -35
- meerk40t/gui/toolwidgets/toolcircle.py +248 -242
- meerk40t/gui/toolwidgets/toolcontainer.py +82 -77
- meerk40t/gui/toolwidgets/tooldraw.py +97 -90
- meerk40t/gui/toolwidgets/toolellipse.py +219 -212
- meerk40t/gui/toolwidgets/toolimagecut.py +25 -132
- meerk40t/gui/toolwidgets/toolline.py +39 -144
- meerk40t/gui/toolwidgets/toollinetext.py +79 -236
- meerk40t/gui/toolwidgets/toollinetext_inline.py +296 -0
- meerk40t/gui/toolwidgets/toolmeasure.py +160 -216
- meerk40t/gui/toolwidgets/toolnodeedit.py +2088 -2074
- meerk40t/gui/toolwidgets/toolnodemove.py +92 -94
- meerk40t/gui/toolwidgets/toolparameter.py +754 -668
- meerk40t/gui/toolwidgets/toolplacement.py +108 -108
- meerk40t/gui/toolwidgets/toolpoint.py +68 -59
- meerk40t/gui/toolwidgets/toolpointlistbuilder.py +294 -0
- meerk40t/gui/toolwidgets/toolpointmove.py +183 -0
- meerk40t/gui/toolwidgets/toolpolygon.py +288 -403
- meerk40t/gui/toolwidgets/toolpolyline.py +38 -196
- meerk40t/gui/toolwidgets/toolrect.py +211 -207
- meerk40t/gui/toolwidgets/toolrelocate.py +72 -72
- meerk40t/gui/toolwidgets/toolribbon.py +598 -113
- meerk40t/gui/toolwidgets/tooltabedit.py +546 -0
- meerk40t/gui/toolwidgets/tooltext.py +98 -89
- meerk40t/gui/toolwidgets/toolvector.py +213 -204
- meerk40t/gui/toolwidgets/toolwidget.py +39 -39
- meerk40t/gui/usbconnect.py +98 -91
- meerk40t/gui/utilitywidgets/buttonwidget.py +18 -18
- meerk40t/gui/utilitywidgets/checkboxwidget.py +90 -90
- meerk40t/gui/utilitywidgets/controlwidget.py +14 -14
- meerk40t/gui/utilitywidgets/cyclocycloidwidget.py +343 -340
- meerk40t/gui/utilitywidgets/debugwidgets.py +148 -0
- meerk40t/gui/utilitywidgets/handlewidget.py +27 -27
- meerk40t/gui/utilitywidgets/harmonograph.py +450 -447
- meerk40t/gui/utilitywidgets/openclosewidget.py +40 -40
- meerk40t/gui/utilitywidgets/rotationwidget.py +54 -54
- meerk40t/gui/utilitywidgets/scalewidget.py +75 -75
- meerk40t/gui/utilitywidgets/seekbarwidget.py +183 -183
- meerk40t/gui/utilitywidgets/togglewidget.py +142 -142
- meerk40t/gui/utilitywidgets/toolbarwidget.py +8 -8
- meerk40t/gui/wordlisteditor.py +985 -931
- meerk40t/gui/wxmeerk40t.py +1444 -1169
- meerk40t/gui/wxmmain.py +5578 -4112
- meerk40t/gui/wxmribbon.py +1591 -1076
- meerk40t/gui/wxmscene.py +1635 -1453
- meerk40t/gui/wxmtree.py +2410 -2089
- meerk40t/gui/wxutils.py +1769 -1099
- meerk40t/gui/zmatrix.py +102 -102
- meerk40t/image/__init__.py +1 -1
- meerk40t/image/dither.py +429 -0
- meerk40t/image/imagetools.py +2778 -2269
- meerk40t/internal_plugins.py +150 -130
- meerk40t/kernel/__init__.py +63 -12
- meerk40t/kernel/channel.py +259 -212
- meerk40t/kernel/context.py +538 -538
- meerk40t/kernel/exceptions.py +41 -41
- meerk40t/kernel/functions.py +463 -414
- meerk40t/kernel/jobs.py +100 -100
- meerk40t/kernel/kernel.py +3809 -3571
- meerk40t/kernel/lifecycles.py +71 -71
- meerk40t/kernel/module.py +49 -49
- meerk40t/kernel/service.py +147 -147
- meerk40t/kernel/settings.py +383 -343
- meerk40t/lihuiyu/controller.py +883 -876
- meerk40t/lihuiyu/device.py +1181 -1069
- meerk40t/lihuiyu/driver.py +1466 -1372
- meerk40t/lihuiyu/gui/gui.py +127 -106
- meerk40t/lihuiyu/gui/lhyaccelgui.py +377 -363
- meerk40t/lihuiyu/gui/lhycontrollergui.py +741 -651
- meerk40t/lihuiyu/gui/lhydrivergui.py +470 -446
- meerk40t/lihuiyu/gui/lhyoperationproperties.py +238 -237
- meerk40t/lihuiyu/gui/tcpcontroller.py +226 -190
- meerk40t/lihuiyu/interpreter.py +53 -53
- meerk40t/lihuiyu/laserspeed.py +450 -450
- meerk40t/lihuiyu/loader.py +90 -90
- meerk40t/lihuiyu/parser.py +404 -404
- meerk40t/lihuiyu/plugin.py +101 -102
- meerk40t/lihuiyu/tcp_connection.py +111 -109
- meerk40t/main.py +231 -165
- meerk40t/moshi/builder.py +788 -781
- meerk40t/moshi/controller.py +505 -499
- meerk40t/moshi/device.py +495 -442
- meerk40t/moshi/driver.py +862 -696
- meerk40t/moshi/gui/gui.py +78 -76
- meerk40t/moshi/gui/moshicontrollergui.py +538 -522
- meerk40t/moshi/gui/moshidrivergui.py +87 -75
- meerk40t/moshi/plugin.py +43 -43
- meerk40t/network/console_server.py +102 -57
- meerk40t/network/kernelserver.py +10 -9
- meerk40t/network/tcp_server.py +142 -140
- meerk40t/network/udp_server.py +103 -77
- meerk40t/network/web_server.py +390 -0
- meerk40t/newly/controller.py +1158 -1144
- meerk40t/newly/device.py +874 -732
- meerk40t/newly/driver.py +540 -412
- meerk40t/newly/gui/gui.py +219 -188
- meerk40t/newly/gui/newlyconfig.py +116 -101
- meerk40t/newly/gui/newlycontroller.py +193 -186
- meerk40t/newly/gui/operationproperties.py +51 -51
- meerk40t/newly/mock_connection.py +82 -82
- meerk40t/newly/newly_params.py +56 -56
- meerk40t/newly/plugin.py +1214 -1246
- meerk40t/newly/usb_connection.py +322 -322
- meerk40t/rotary/gui/gui.py +52 -46
- meerk40t/rotary/gui/rotarysettings.py +240 -232
- meerk40t/rotary/rotary.py +202 -98
- meerk40t/ruida/control.py +291 -91
- meerk40t/ruida/controller.py +138 -1088
- meerk40t/ruida/device.py +672 -231
- meerk40t/ruida/driver.py +534 -472
- meerk40t/ruida/emulator.py +1494 -1491
- meerk40t/ruida/exceptions.py +4 -4
- meerk40t/ruida/gui/gui.py +71 -76
- meerk40t/ruida/gui/ruidaconfig.py +239 -72
- meerk40t/ruida/gui/ruidacontroller.py +187 -184
- meerk40t/ruida/gui/ruidaoperationproperties.py +48 -47
- meerk40t/ruida/loader.py +54 -52
- meerk40t/ruida/mock_connection.py +57 -109
- meerk40t/ruida/plugin.py +124 -87
- meerk40t/ruida/rdjob.py +2084 -945
- meerk40t/ruida/serial_connection.py +116 -0
- meerk40t/ruida/tcp_connection.py +146 -0
- meerk40t/ruida/udp_connection.py +73 -0
- meerk40t/svgelements.py +9671 -9669
- meerk40t/tools/driver_to_path.py +584 -579
- meerk40t/tools/geomstr.py +5583 -4680
- meerk40t/tools/jhfparser.py +357 -292
- meerk40t/tools/kerftest.py +904 -890
- meerk40t/tools/livinghinges.py +1168 -1033
- meerk40t/tools/pathtools.py +987 -949
- meerk40t/tools/pmatrix.py +234 -0
- meerk40t/tools/pointfinder.py +942 -942
- meerk40t/tools/polybool.py +940 -940
- meerk40t/tools/rasterplotter.py +1660 -547
- meerk40t/tools/shxparser.py +989 -901
- meerk40t/tools/ttfparser.py +726 -446
- meerk40t/tools/zinglplotter.py +595 -593
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/LICENSE +21 -21
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/METADATA +150 -139
- meerk40t-0.9.7010.dist-info/RECORD +445 -0
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/WHEEL +1 -1
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/top_level.txt +0 -1
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/zip-safe +1 -1
- meerk40t/balormk/elementlightjob.py +0 -159
- meerk40t-0.9.3001.dist-info/RECORD +0 -437
- test/bootstrap.py +0 -63
- test/test_cli.py +0 -12
- test/test_core_cutcode.py +0 -418
- test/test_core_elements.py +0 -144
- test/test_core_plotplanner.py +0 -397
- test/test_core_viewports.py +0 -312
- test/test_drivers_grbl.py +0 -108
- test/test_drivers_lihuiyu.py +0 -443
- test/test_drivers_newly.py +0 -113
- test/test_element_degenerate_points.py +0 -43
- test/test_elements_classify.py +0 -97
- test/test_elements_penbox.py +0 -22
- test/test_file_svg.py +0 -176
- test/test_fill.py +0 -155
- test/test_geomstr.py +0 -1523
- test/test_geomstr_nodes.py +0 -18
- test/test_imagetools_actualize.py +0 -306
- test/test_imagetools_wizard.py +0 -258
- test/test_kernel.py +0 -200
- test/test_laser_speeds.py +0 -3303
- test/test_length.py +0 -57
- test/test_lifecycle.py +0 -66
- test/test_operations.py +0 -251
- test/test_operations_hatch.py +0 -57
- test/test_ruida.py +0 -19
- test/test_spooler.py +0 -22
- test/test_tools_rasterplotter.py +0 -29
- test/test_wobble.py +0 -133
- test/test_zingl.py +0 -124
- {test → meerk40t/cylinder}/__init__.py +0 -0
- /meerk40t/{core/element_commands.py → cylinder/gui/__init__.py} +0 -0
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7010.dist-info}/entry_points.txt +0 -0
meerk40t/gui/scene/scene.py
CHANGED
@@ -1,1051 +1,1100 @@
|
|
1
|
-
import platform
|
2
|
-
import threading
|
3
|
-
import time
|
4
|
-
|
5
|
-
import wx
|
6
|
-
|
7
|
-
from meerk40t.core.elements.element_types import elem_nodes
|
8
|
-
from meerk40t.gui.laserrender import (
|
9
|
-
DRAW_MODE_ANIMATE,
|
10
|
-
DRAW_MODE_FLIPXY,
|
11
|
-
DRAW_MODE_INVERT,
|
12
|
-
DRAW_MODE_REFRESH,
|
13
|
-
)
|
14
|
-
from meerk40t.gui.scene.sceneconst import (
|
15
|
-
HITCHAIN_DELEGATE,
|
16
|
-
HITCHAIN_DELEGATE_AND_HIT,
|
17
|
-
HITCHAIN_HIT,
|
18
|
-
HITCHAIN_HIT_AND_DELEGATE,
|
19
|
-
HITCHAIN_PRIORITY_HIT,
|
20
|
-
ORIENTATION_RELATIVE,
|
21
|
-
RESPONSE_ABORT,
|
22
|
-
RESPONSE_CHAIN,
|
23
|
-
RESPONSE_CONSUME,
|
24
|
-
RESPONSE_DROP,
|
25
|
-
)
|
26
|
-
from meerk40t.gui.scene.scenespacewidget import SceneSpaceWidget
|
27
|
-
from meerk40t.
|
28
|
-
from meerk40t.
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
self.
|
50
|
-
self.
|
51
|
-
self.
|
52
|
-
self.
|
53
|
-
self.
|
54
|
-
self.
|
55
|
-
self.
|
56
|
-
|
57
|
-
|
58
|
-
self.
|
59
|
-
self.
|
60
|
-
self.
|
61
|
-
self.
|
62
|
-
self.
|
63
|
-
|
64
|
-
|
65
|
-
self.
|
66
|
-
self.
|
67
|
-
|
68
|
-
|
69
|
-
self.
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
self.
|
81
|
-
self.
|
82
|
-
self.
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
self.
|
89
|
-
self.
|
90
|
-
self.
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
self.
|
95
|
-
self.
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
@
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
self.
|
108
|
-
self.
|
109
|
-
self.
|
110
|
-
self.
|
111
|
-
self.
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
self.
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
gc.
|
138
|
-
gc.
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
self.
|
160
|
-
self.
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
@param
|
170
|
-
@param
|
171
|
-
@
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
self.
|
176
|
-
|
177
|
-
self.
|
178
|
-
self.
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
self.
|
206
|
-
|
207
|
-
|
208
|
-
self.
|
209
|
-
|
210
|
-
self.
|
211
|
-
self.
|
212
|
-
self.
|
213
|
-
self.
|
214
|
-
|
215
|
-
self.
|
216
|
-
self.
|
217
|
-
self.
|
218
|
-
|
219
|
-
self.
|
220
|
-
self.
|
221
|
-
|
222
|
-
self.
|
223
|
-
|
224
|
-
self.
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
self.
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
self.
|
233
|
-
self.
|
234
|
-
|
235
|
-
self.
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
self.context.
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
self.
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
except AttributeError:
|
304
|
-
pass
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
self.
|
327
|
-
self.
|
328
|
-
|
329
|
-
def
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
if self.
|
358
|
-
self.
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
self.
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
if
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
if
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
)
|
425
|
-
|
426
|
-
self.
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
width
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
"""
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
def
|
520
|
-
"""
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
"""
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
"""
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
def
|
568
|
-
"""
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
self.
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
self.
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
for
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
"
|
697
|
-
"
|
698
|
-
|
699
|
-
"
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
)
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
if
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
else:
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
"""
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
"""
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
self.
|
946
|
-
|
947
|
-
|
948
|
-
"
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
def
|
979
|
-
"""
|
980
|
-
Recalculate the
|
981
|
-
|
982
|
-
@
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
if
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1
|
+
import platform
|
2
|
+
import threading
|
3
|
+
import time
|
4
|
+
|
5
|
+
import wx
|
6
|
+
|
7
|
+
from meerk40t.core.elements.element_types import elem_nodes
|
8
|
+
from meerk40t.gui.laserrender import (
|
9
|
+
DRAW_MODE_ANIMATE,
|
10
|
+
DRAW_MODE_FLIPXY,
|
11
|
+
DRAW_MODE_INVERT,
|
12
|
+
DRAW_MODE_REFRESH,
|
13
|
+
)
|
14
|
+
from meerk40t.gui.scene.sceneconst import (
|
15
|
+
HITCHAIN_DELEGATE,
|
16
|
+
HITCHAIN_DELEGATE_AND_HIT,
|
17
|
+
HITCHAIN_HIT,
|
18
|
+
HITCHAIN_HIT_AND_DELEGATE,
|
19
|
+
HITCHAIN_PRIORITY_HIT,
|
20
|
+
ORIENTATION_RELATIVE,
|
21
|
+
RESPONSE_ABORT,
|
22
|
+
RESPONSE_CHAIN,
|
23
|
+
RESPONSE_CONSUME,
|
24
|
+
RESPONSE_DROP,
|
25
|
+
)
|
26
|
+
from meerk40t.gui.scene.scenespacewidget import SceneSpaceWidget
|
27
|
+
from meerk40t.gui.wxutils import get_matrix_scale
|
28
|
+
from meerk40t.kernel import Job, Module
|
29
|
+
from meerk40t.svgelements import Matrix, Point
|
30
|
+
|
31
|
+
_reused_identity_widget = Matrix()
|
32
|
+
XCELLS = 15
|
33
|
+
YCELLS = 15
|
34
|
+
|
35
|
+
TYPE_BOUND = 0
|
36
|
+
TYPE_POINT = 1
|
37
|
+
TYPE_MIDDLE = 2
|
38
|
+
TYPE_CENTER = 3
|
39
|
+
TYPE_GRID = 4
|
40
|
+
TYPE_MIDDLE_SMALL = 5
|
41
|
+
|
42
|
+
|
43
|
+
class SceneToast:
|
44
|
+
"""
|
45
|
+
SceneToast is drawn directly by the Scene. It creates a text message in a box that animates a fade.
|
46
|
+
"""
|
47
|
+
|
48
|
+
def __init__(self, scene, left, top, right, bottom):
|
49
|
+
self.scene = scene
|
50
|
+
self.left = left
|
51
|
+
self.top = top
|
52
|
+
self.right = right
|
53
|
+
self.bottom = bottom
|
54
|
+
self.countdown = 0
|
55
|
+
self.message = None
|
56
|
+
self.token = None
|
57
|
+
|
58
|
+
self.brush = wx.Brush()
|
59
|
+
self.pen = wx.Pen()
|
60
|
+
self.font = wx.Font()
|
61
|
+
self.brush_color = wx.Colour()
|
62
|
+
self.pen_color = wx.Colour()
|
63
|
+
self.font_color = wx.Colour()
|
64
|
+
|
65
|
+
self.pen.SetWidth(10)
|
66
|
+
self.text_height = float("inf")
|
67
|
+
self.text_width = float("inf")
|
68
|
+
|
69
|
+
self.alpha = None
|
70
|
+
self.set_alpha(255)
|
71
|
+
|
72
|
+
def tick(self):
|
73
|
+
"""
|
74
|
+
Each tick reduces countdown by 1. Once countdown is below 20 we call requests for animation.
|
75
|
+
@return:
|
76
|
+
"""
|
77
|
+
self.countdown -= 1
|
78
|
+
if self.countdown <= 20:
|
79
|
+
self.scene.invalidate(
|
80
|
+
self.left - 10,
|
81
|
+
self.top - 10,
|
82
|
+
self.right + 10,
|
83
|
+
self.bottom + 10,
|
84
|
+
animate=True,
|
85
|
+
)
|
86
|
+
if self.countdown <= 0:
|
87
|
+
self.scene.invalidate(
|
88
|
+
self.left - 10,
|
89
|
+
self.top - 10,
|
90
|
+
self.right + 10,
|
91
|
+
self.bottom + 10,
|
92
|
+
animate=False,
|
93
|
+
)
|
94
|
+
# self.scene.request_refresh()
|
95
|
+
self.message = None
|
96
|
+
self.token = None
|
97
|
+
return self.countdown > 0
|
98
|
+
|
99
|
+
def set_alpha(self, alpha):
|
100
|
+
"""
|
101
|
+
We set the alpha for all the colors.
|
102
|
+
|
103
|
+
@param alpha:
|
104
|
+
@return:
|
105
|
+
"""
|
106
|
+
if alpha != self.alpha:
|
107
|
+
self.alpha = alpha
|
108
|
+
self.brush_color.SetRGBA(0xFFFFFF | alpha << 24)
|
109
|
+
self.pen_color.SetRGBA(0x70FF70 | alpha << 24)
|
110
|
+
self.font_color.SetRGBA(0x000000 | alpha << 24)
|
111
|
+
self.brush.SetColour(self.brush_color)
|
112
|
+
self.pen.SetColour(self.pen_color)
|
113
|
+
|
114
|
+
def draw(self, gc: wx.GraphicsContext):
|
115
|
+
if not self.message:
|
116
|
+
return
|
117
|
+
alpha = 255
|
118
|
+
if self.countdown <= 20:
|
119
|
+
alpha = int(self.countdown * 12.5)
|
120
|
+
self.set_alpha(alpha)
|
121
|
+
|
122
|
+
width = self.right - self.left
|
123
|
+
height = self.bottom - self.top
|
124
|
+
text_size = height
|
125
|
+
|
126
|
+
while self.text_height > height or self.text_width > width:
|
127
|
+
# If we do not fit in the box, decrease size
|
128
|
+
text_size *= 0.9
|
129
|
+
try:
|
130
|
+
self.font.SetFractionalPointSize(text_size)
|
131
|
+
except AttributeError:
|
132
|
+
self.font.SetPointSize(int(text_size))
|
133
|
+
gc.SetFont(self.font, self.font_color)
|
134
|
+
self.text_width, self.text_height = gc.GetTextExtent(self.message)
|
135
|
+
if text_size == height:
|
136
|
+
gc.SetFont(self.font, self.font_color)
|
137
|
+
gc.SetPen(self.pen)
|
138
|
+
gc.SetBrush(self.brush)
|
139
|
+
gc.DrawRectangle(
|
140
|
+
self.left, self.top, self.right - self.left, self.bottom - self.top
|
141
|
+
)
|
142
|
+
|
143
|
+
toast_x = self.left + (width - self.text_width) / 2.0
|
144
|
+
toast_y = self.top
|
145
|
+
gc.DrawText(self.message, toast_x, toast_y)
|
146
|
+
|
147
|
+
def start_threaded(self):
|
148
|
+
"""
|
149
|
+
First start of threaded animate. Refresh to draw.
|
150
|
+
@return:
|
151
|
+
"""
|
152
|
+
self.scene.request_refresh()
|
153
|
+
|
154
|
+
def stop_threaded(self):
|
155
|
+
"""
|
156
|
+
Stop of threaded animate. Unset text dims and delete the toast.
|
157
|
+
@return:
|
158
|
+
"""
|
159
|
+
self.scene._toast = None
|
160
|
+
self.text_height = float("inf")
|
161
|
+
self.text_width = float("inf")
|
162
|
+
|
163
|
+
def set_message(self, message, token=-1, duration=100):
|
164
|
+
"""
|
165
|
+
Sets the message. If the token is different, we reset the text position.
|
166
|
+
|
167
|
+
We always reset the duration.
|
168
|
+
|
169
|
+
@param message:
|
170
|
+
@param token:
|
171
|
+
@param duration:
|
172
|
+
@return:
|
173
|
+
"""
|
174
|
+
if token != self.token or token == -1:
|
175
|
+
self.text_height = float("inf")
|
176
|
+
self.text_width = float("inf")
|
177
|
+
self.message = message
|
178
|
+
self.token = token
|
179
|
+
self.countdown = duration
|
180
|
+
|
181
|
+
|
182
|
+
class Scene(Module, Job):
|
183
|
+
"""
|
184
|
+
The Scene Module holds all the needed references to widgets and catches the events from the ScenePanel which
|
185
|
+
stores this object primarily.
|
186
|
+
|
187
|
+
Scene overloads both Module being registered in "module/Scene" and the Job to handle the refresh.
|
188
|
+
|
189
|
+
The Scene is the infinite space of the scene as seen through the panel's viewpoint. It serves to zoom, pan, and
|
190
|
+
manipulate various elements. This is done through a matrix which translates the scene space to window space. The
|
191
|
+
scene space to window space. The widgets are stored in a tree within the scene. The primary widget is the
|
192
|
+
SceneSpaceWidget which draws elements in two different forms. It first draws the scene and all scenewidgets added
|
193
|
+
to the scene and then the interface widget which contains all the non-scene widget elements.
|
194
|
+
"""
|
195
|
+
|
196
|
+
def __init__(self, context, path, gui, pane=None, **kwargs):
|
197
|
+
Module.__init__(self, context, path)
|
198
|
+
Job.__init__(
|
199
|
+
self,
|
200
|
+
job_name=f"Scene-{path}",
|
201
|
+
process=self.refresh_scene,
|
202
|
+
conditional=lambda: self.screen_refresh_is_requested,
|
203
|
+
run_main=True,
|
204
|
+
)
|
205
|
+
self.stack = []
|
206
|
+
|
207
|
+
# Scene lock is used for widget structure modification and scene drawing.
|
208
|
+
self.scene_lock = threading.RLock()
|
209
|
+
|
210
|
+
self.log = context.channel("scene")
|
211
|
+
self.log_events = context.channel("scene-events")
|
212
|
+
self.gui = gui
|
213
|
+
self.pane = pane
|
214
|
+
self.hittable_elements = list()
|
215
|
+
self.hit_chain = list()
|
216
|
+
self.widget_root = None
|
217
|
+
self.push_stack(SceneSpaceWidget(self))
|
218
|
+
|
219
|
+
self.interval = 1.0 / 60.0 # 60fps
|
220
|
+
self.last_position = None
|
221
|
+
self._down_start_time = None
|
222
|
+
self._down_start_pos = None
|
223
|
+
self._cursor = None
|
224
|
+
self.suppress_changes = True
|
225
|
+
|
226
|
+
self.colors = self.context.colors
|
227
|
+
|
228
|
+
self.screen_refresh_is_requested = True
|
229
|
+
self.clip = wx.Rect(0, 0, 0, 0)
|
230
|
+
|
231
|
+
self.background_brush = wx.Brush(self.colors.color_background)
|
232
|
+
self._hasbackgrounds = {}
|
233
|
+
self._backgrounds = {}
|
234
|
+
# If set this color will be used for the scene background (used during burn)
|
235
|
+
self.overrule_background = None
|
236
|
+
|
237
|
+
self._animating = list()
|
238
|
+
self._animate_lock = threading.Lock()
|
239
|
+
self._adding_widgets = list()
|
240
|
+
self._animate_job = Job(
|
241
|
+
self._animate_scene,
|
242
|
+
job_name=f"Animate-Scene{path}",
|
243
|
+
run_main=True,
|
244
|
+
interval=1.0 / 60.0,
|
245
|
+
)
|
246
|
+
self._toast = None
|
247
|
+
# Snap information
|
248
|
+
self.snap_display_points = None
|
249
|
+
self.snap_attraction_points = None
|
250
|
+
|
251
|
+
@property
|
252
|
+
def has_background(self):
|
253
|
+
devlabel = self.context.device.label
|
254
|
+
if devlabel not in self._hasbackgrounds:
|
255
|
+
self._hasbackgrounds[devlabel] = False
|
256
|
+
return self._hasbackgrounds[devlabel]
|
257
|
+
|
258
|
+
@has_background.setter
|
259
|
+
def has_background(self, value):
|
260
|
+
devlabel = self.context.device.label
|
261
|
+
self._hasbackgrounds[devlabel] = value
|
262
|
+
if not value:
|
263
|
+
self.active_background = None
|
264
|
+
|
265
|
+
@property
|
266
|
+
def active_background(self):
|
267
|
+
devlabel = self.context.device.label
|
268
|
+
if devlabel not in self._hasbackgrounds:
|
269
|
+
self._backgrounds[devlabel] = None
|
270
|
+
return self._backgrounds[devlabel]
|
271
|
+
|
272
|
+
@active_background.setter
|
273
|
+
def active_background(self, value):
|
274
|
+
devlabel = self.context.device.label
|
275
|
+
self._backgrounds[devlabel] = value
|
276
|
+
|
277
|
+
def module_open(self, *args, **kwargs):
|
278
|
+
context = self.context
|
279
|
+
context.setting(int, "draw_mode", 0)
|
280
|
+
context.setting(bool, "mouse_zoom_invert", False)
|
281
|
+
context.setting(bool, "mouse_pan_invert", False)
|
282
|
+
context.setting(bool, "mouse_wheel_pan", False)
|
283
|
+
context.setting(float, "zoom_factor", 0.1)
|
284
|
+
context.setting(float, "pan_factor", 25.0)
|
285
|
+
context.setting(int, "fps", 40)
|
286
|
+
if context.fps <= 0:
|
287
|
+
context.fps = 60
|
288
|
+
self.interval = 1.0 / float(context.fps)
|
289
|
+
self.commit()
|
290
|
+
|
291
|
+
def commit(self):
|
292
|
+
context = self.context
|
293
|
+
self._init_widget(self.widget_root, context)
|
294
|
+
|
295
|
+
def module_close(self, *args, **kwargs):
|
296
|
+
self._final_widget(self.widget_root, self.context)
|
297
|
+
self.scene_lock.acquire() # calling shutdown live locks here since it's already shutting down.
|
298
|
+
self.context.unschedule(self)
|
299
|
+
|
300
|
+
def _init_widget(self, widget, context):
|
301
|
+
try:
|
302
|
+
widget.init(context)
|
303
|
+
except AttributeError:
|
304
|
+
pass
|
305
|
+
for w in widget:
|
306
|
+
if w is None:
|
307
|
+
continue
|
308
|
+
self._init_widget(w, context)
|
309
|
+
|
310
|
+
def _final_widget(self, widget, context):
|
311
|
+
try:
|
312
|
+
widget.final(context)
|
313
|
+
except AttributeError:
|
314
|
+
pass
|
315
|
+
for w in widget:
|
316
|
+
if w is None:
|
317
|
+
continue
|
318
|
+
self._final_widget(w, context)
|
319
|
+
|
320
|
+
def push_stack(self, widget):
|
321
|
+
if self.widget_root is not None:
|
322
|
+
try:
|
323
|
+
widget.init(self.context)
|
324
|
+
except AttributeError:
|
325
|
+
pass
|
326
|
+
self.stack.append(self.widget_root)
|
327
|
+
self.widget_root = widget
|
328
|
+
|
329
|
+
def pop_stack(self):
|
330
|
+
widget = self.stack.pop()
|
331
|
+
try:
|
332
|
+
self.widget_root.final(self.context)
|
333
|
+
except AttributeError:
|
334
|
+
pass
|
335
|
+
self.widget_root = widget
|
336
|
+
|
337
|
+
def set_fps(self, fps):
|
338
|
+
"""
|
339
|
+
Set the scene frames per second which sets the interval for the Job.
|
340
|
+
"""
|
341
|
+
if fps == 0:
|
342
|
+
fps = 1
|
343
|
+
self.context.fps = fps
|
344
|
+
self.interval = 1.0 / float(self.context.fps)
|
345
|
+
|
346
|
+
def request_refresh_for_animation(self):
|
347
|
+
"""Called on the various signals trying to animate the screen."""
|
348
|
+
try:
|
349
|
+
if self.context.draw_mode & DRAW_MODE_ANIMATE == 0:
|
350
|
+
self.request_refresh()
|
351
|
+
except AttributeError:
|
352
|
+
pass
|
353
|
+
|
354
|
+
def request_refresh(self, origin=None, *args):
|
355
|
+
"""Request an update to the scene."""
|
356
|
+
try:
|
357
|
+
if self.context.draw_mode & DRAW_MODE_REFRESH == 0:
|
358
|
+
self.screen_refresh_is_requested = True
|
359
|
+
except AttributeError:
|
360
|
+
pass
|
361
|
+
|
362
|
+
def invalidate(self, min_x, min_y, max_x, max_y, animate=False):
|
363
|
+
self.clip.Union((min_x, min_y, max_x - min_x, max_y - min_y))
|
364
|
+
if animate:
|
365
|
+
self.request_refresh_for_animation()
|
366
|
+
else:
|
367
|
+
self.request_refresh()
|
368
|
+
|
369
|
+
def animate(self, widget):
|
370
|
+
with self._animate_lock:
|
371
|
+
if widget not in self._adding_widgets:
|
372
|
+
self._adding_widgets.append(widget)
|
373
|
+
if self.log:
|
374
|
+
self.log("Start Animation...")
|
375
|
+
self.context.schedule(self._animate_job)
|
376
|
+
|
377
|
+
def _animate_scene(self, *args, **kwargs):
|
378
|
+
if self.log:
|
379
|
+
self.log("Animating Scene...")
|
380
|
+
if self._adding_widgets:
|
381
|
+
with self._animate_lock:
|
382
|
+
animate_add = list(self._adding_widgets)
|
383
|
+
self._adding_widgets.clear()
|
384
|
+
for widget in animate_add:
|
385
|
+
self._animating.append(widget)
|
386
|
+
try:
|
387
|
+
widget.start_threaded()
|
388
|
+
except AttributeError:
|
389
|
+
pass
|
390
|
+
if self._animating:
|
391
|
+
for idx in range(len(self._animating) - 1, -1, -1):
|
392
|
+
widget = self._animating[idx]
|
393
|
+
try:
|
394
|
+
more = widget.tick()
|
395
|
+
if not more:
|
396
|
+
try:
|
397
|
+
widget.stop_threaded()
|
398
|
+
except AttributeError:
|
399
|
+
pass
|
400
|
+
del self._animating[idx]
|
401
|
+
except AttributeError:
|
402
|
+
pass
|
403
|
+
if not self._animating:
|
404
|
+
self._animate_job.cancel()
|
405
|
+
if self.log:
|
406
|
+
self.log("Removing Animation...")
|
407
|
+
|
408
|
+
def refresh_scene(self, *args, **kwargs):
|
409
|
+
"""
|
410
|
+
Called by the Scheduler at a given the specified framerate.
|
411
|
+
Called in the UI thread.
|
412
|
+
"""
|
413
|
+
if not self.screen_refresh_is_requested:
|
414
|
+
return
|
415
|
+
if self.scene_lock.acquire(timeout=0.2):
|
416
|
+
try:
|
417
|
+
self._update_buffer_ui_thread()
|
418
|
+
self.gui.Refresh()
|
419
|
+
self.gui.Update()
|
420
|
+
except RuntimeError:
|
421
|
+
# May hit runtime error.
|
422
|
+
pass
|
423
|
+
self.screen_refresh_is_requested = False
|
424
|
+
self.scene_lock.release()
|
425
|
+
else:
|
426
|
+
self.screen_refresh_is_requested = False
|
427
|
+
|
428
|
+
def _update_buffer_ui_thread(self):
|
429
|
+
"""Performs redrawing of the data in the UI thread."""
|
430
|
+
dm = self.context.draw_mode
|
431
|
+
buf = self.gui.scene_buffer
|
432
|
+
if buf is None or buf.GetSize() != self.gui.ClientSize or not buf.IsOk():
|
433
|
+
self.gui.set_buffer()
|
434
|
+
buf = self.gui.scene_buffer
|
435
|
+
dc = wx.MemoryDC()
|
436
|
+
if self.clip.width != 0 and self.clip.height != 0:
|
437
|
+
dc.SetClippingRegion(self.clip)
|
438
|
+
self.clip.SetX(0)
|
439
|
+
self.clip.SetY(0)
|
440
|
+
self.clip.SetWidth(0)
|
441
|
+
self.clip.SetHeight(0)
|
442
|
+
|
443
|
+
dc.SelectObject(buf)
|
444
|
+
if self.overrule_background is None:
|
445
|
+
self.background_brush.SetColour(self.colors.color_background)
|
446
|
+
else:
|
447
|
+
self.background_brush.SetColour(self.overrule_background)
|
448
|
+
dc.SetBackground(self.background_brush)
|
449
|
+
dc.Clear()
|
450
|
+
w, h = dc.Size
|
451
|
+
if dm & DRAW_MODE_FLIPXY != 0:
|
452
|
+
dc.SetUserScale(-1, -1)
|
453
|
+
dc.SetLogicalOrigin(w, h)
|
454
|
+
gc = wx.GraphicsContext.Create(dc)
|
455
|
+
gc.dc = dc
|
456
|
+
gc.Size = dc.Size
|
457
|
+
|
458
|
+
font = wx.Font(14, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)
|
459
|
+
gc.SetFont(font, wx.BLACK)
|
460
|
+
self.draw(gc)
|
461
|
+
if dm & DRAW_MODE_INVERT != 0:
|
462
|
+
dc.Blit(0, 0, w, h, dc, 0, 0, wx.SRC_INVERT)
|
463
|
+
gc.Destroy()
|
464
|
+
dc.SelectObject(wx.NullBitmap)
|
465
|
+
del gc.dc
|
466
|
+
del dc
|
467
|
+
|
468
|
+
def toast(self, message, token=-1):
|
469
|
+
if self._toast is None:
|
470
|
+
self._toast = SceneToast(
|
471
|
+
self, self.x(0.1), self.y(0.8), self.x(0.9), self.y(0.9)
|
472
|
+
)
|
473
|
+
self._toast.set_message(message, token)
|
474
|
+
self.animate(self._toast)
|
475
|
+
else:
|
476
|
+
self._toast.set_message(message, token)
|
477
|
+
self.animate(self._toast)
|
478
|
+
|
479
|
+
def x(self, v):
|
480
|
+
width, height = self.gui.ClientSize
|
481
|
+
return width * v
|
482
|
+
|
483
|
+
def y(self, v):
|
484
|
+
width, height = self.gui.ClientSize
|
485
|
+
return height * v
|
486
|
+
|
487
|
+
def cell(self):
|
488
|
+
width, height = self.gui.ClientSize
|
489
|
+
return min(width / XCELLS, height / YCELLS)
|
490
|
+
|
491
|
+
def _signal_widget(self, widget, *args, **kwargs):
|
492
|
+
"""
|
493
|
+
Calls the signal widget with the given args. Calls signal for the entire widget node tree.
|
494
|
+
"""
|
495
|
+
try:
|
496
|
+
widget.signal(*args)
|
497
|
+
except AttributeError:
|
498
|
+
pass
|
499
|
+
for w in widget:
|
500
|
+
if w is None:
|
501
|
+
continue
|
502
|
+
self._signal_widget(w, *args, **kwargs)
|
503
|
+
|
504
|
+
def notify_added_to_parent(self, parent):
|
505
|
+
"""
|
506
|
+
Called when node is added to parent. Notifying the scene as a whole.
|
507
|
+
"""
|
508
|
+
pass
|
509
|
+
|
510
|
+
def notify_added_child(self, child):
|
511
|
+
"""
|
512
|
+
Called when a child is added to the tree. Notifies scene as a whole.
|
513
|
+
"""
|
514
|
+
try:
|
515
|
+
child.init(self.context)
|
516
|
+
except AttributeError:
|
517
|
+
pass
|
518
|
+
|
519
|
+
def notify_removed_from_parent(self, parent):
|
520
|
+
"""
|
521
|
+
Called when a widget is removed from its parent. Notifies scene as a whole.
|
522
|
+
"""
|
523
|
+
pass
|
524
|
+
|
525
|
+
def notify_removed_child(self, child):
|
526
|
+
"""
|
527
|
+
Called when a widget's child is removed. Notifies scene as a whole.
|
528
|
+
"""
|
529
|
+
try:
|
530
|
+
child.final(self.context)
|
531
|
+
except AttributeError:
|
532
|
+
pass
|
533
|
+
|
534
|
+
def notify_moved_child(self, child):
|
535
|
+
"""
|
536
|
+
Called when a widget is moved from one widget parent to another.
|
537
|
+
"""
|
538
|
+
pass
|
539
|
+
|
540
|
+
def draw(self, canvas):
|
541
|
+
"""
|
542
|
+
Scene Draw routine to be called on paint when the _Buffer bitmap needs to be redrawn.
|
543
|
+
"""
|
544
|
+
if self.widget_root is not None and not self.suppress_changes:
|
545
|
+
self.widget_root.draw(canvas)
|
546
|
+
if self.log:
|
547
|
+
self.log("Redraw Canvas")
|
548
|
+
if self._toast is not None:
|
549
|
+
self._toast.draw(canvas)
|
550
|
+
|
551
|
+
def convert_scene_to_window(self, position):
|
552
|
+
"""
|
553
|
+
Convert the scene space to the window space for a particular point.
|
554
|
+
The position given in the scene, produces the position on the screen.
|
555
|
+
"""
|
556
|
+
point = self.widget_root.scene_widget.matrix.point_in_matrix_space(position)
|
557
|
+
return point[0], point[1]
|
558
|
+
|
559
|
+
def convert_window_to_scene(self, position):
|
560
|
+
"""
|
561
|
+
Convert the window space to the scene space for a particular point.
|
562
|
+
The position given is the window pixel, produces the position within the scene.
|
563
|
+
"""
|
564
|
+
point = self.widget_root.scene_widget.matrix.point_in_inverse_space(position)
|
565
|
+
return point[0], point[1]
|
566
|
+
|
567
|
+
def rebuild_hittable_chain(self):
|
568
|
+
"""
|
569
|
+
Iterates through the tree and adds all hittable elements to the hittable_elements list.
|
570
|
+
This is dynamically rebuilt on the mouse event.
|
571
|
+
"""
|
572
|
+
self.hittable_elements.clear()
|
573
|
+
self.rebuild_hit_chain(self.widget_root, _reused_identity_widget)
|
574
|
+
|
575
|
+
def rebuild_hit_chain(self, current_widget, current_matrix=None):
|
576
|
+
"""
|
577
|
+
Iterates through the hit chain to find elements which respond to their hit() function that they are HITCHAIN_HIT
|
578
|
+
and registers this within the hittable_elements list if they are able to hit at the current time. Given the
|
579
|
+
dimensions of the widget and the current matrix within the widget tree.
|
580
|
+
|
581
|
+
HITCHAIN_HIT means that this is a hit value and should the termination of this branch of the widget tree.
|
582
|
+
HITCHAIN_DELEGATE means that this is not a hittable widget and should not receive mouse events.
|
583
|
+
HITCHAIN_HIT_AND_DELEGATE means that this is a hittable widget, but other widgets within it might also matter.
|
584
|
+
HITCHAIN_DELEGATE_AND_HIT means that other widgets in the tree should be checked first, but after those this
|
585
|
+
widget should be checked.
|
586
|
+
|
587
|
+
The hitchain is the current matrix and current widget in the order of depth.
|
588
|
+
|
589
|
+
"""
|
590
|
+
# If there is a matrix for the widget concatenate it.
|
591
|
+
if current_widget.matrix is not None:
|
592
|
+
matrix_within_scene = Matrix(current_widget.matrix)
|
593
|
+
matrix_within_scene.post_cat(current_matrix)
|
594
|
+
else:
|
595
|
+
matrix_within_scene = Matrix(current_matrix)
|
596
|
+
|
597
|
+
# Add to list and recurse for children based on response.
|
598
|
+
response = current_widget.hit()
|
599
|
+
if response == HITCHAIN_HIT:
|
600
|
+
self.hittable_elements.append((current_widget, matrix_within_scene))
|
601
|
+
elif response == HITCHAIN_PRIORITY_HIT:
|
602
|
+
self.hittable_elements.insert(0, (current_widget, matrix_within_scene))
|
603
|
+
elif response == HITCHAIN_DELEGATE:
|
604
|
+
for w in current_widget:
|
605
|
+
self.rebuild_hit_chain(w, matrix_within_scene)
|
606
|
+
elif response == HITCHAIN_HIT_AND_DELEGATE:
|
607
|
+
self.hittable_elements.append((current_widget, matrix_within_scene))
|
608
|
+
for w in current_widget:
|
609
|
+
self.rebuild_hit_chain(w, matrix_within_scene)
|
610
|
+
elif response == HITCHAIN_DELEGATE_AND_HIT:
|
611
|
+
for w in current_widget:
|
612
|
+
self.rebuild_hit_chain(w, matrix_within_scene)
|
613
|
+
self.hittable_elements.append((current_widget, matrix_within_scene))
|
614
|
+
|
615
|
+
def find_hit_chain(self, position):
|
616
|
+
"""
|
617
|
+
Processes the hittable_elements list and find which elements are hit at a given position.
|
618
|
+
|
619
|
+
This gives the actual hits with regard to the position of the event.
|
620
|
+
"""
|
621
|
+
self.hit_chain.clear()
|
622
|
+
for current_widget, current_matrix in self.hittable_elements:
|
623
|
+
try:
|
624
|
+
hit_point = Point(current_matrix.point_in_inverse_space(position))
|
625
|
+
except ZeroDivisionError:
|
626
|
+
current_matrix.reset()
|
627
|
+
# Some object is zero matrixed, reset it.
|
628
|
+
return
|
629
|
+
if current_widget.contains(hit_point.x, hit_point.y):
|
630
|
+
self.hit_chain.append((current_widget, current_matrix))
|
631
|
+
|
632
|
+
def event(
|
633
|
+
self, window_pos, event_type="", nearest_snap=None, modifiers=None, keycode=None
|
634
|
+
):
|
635
|
+
"""
|
636
|
+
Scene event code. Processes all the events for a particular mouse event bound in the ScenePanel.
|
637
|
+
|
638
|
+
Many mousedown events trigger the specific start of the hitchain matching, and processes the given hitchain.
|
639
|
+
Subsequent delegation of the events will be processed with regard to whether the matching event struck a
|
640
|
+
particular widget. This permits a hit widget to get all further events.
|
641
|
+
|
642
|
+
Responses to events are:
|
643
|
+
RESPONSE_ABORT: Aborts any future mouse events within the sequence.
|
644
|
+
RESPONSE_CONSUME: Consumes the event and prevents any event further in the hitchain from getting the event
|
645
|
+
RESPONSE_CHAIN: Permit the event to move to the next event in the hitchain
|
646
|
+
RESPONSE_DROP: Remove this item from the hitchain and continue to process the events. Future events will not
|
647
|
+
consider the dropped element within the hitchain.
|
648
|
+
|
649
|
+
Returns a flag whether the event was consumed by someone
|
650
|
+
"""
|
651
|
+
if self.log_events:
|
652
|
+
self.log_events(
|
653
|
+
f"{event_type}: {str(window_pos)} {str(nearest_snap)} {str(modifiers)} {str(keycode)}"
|
654
|
+
)
|
655
|
+
|
656
|
+
if window_pos is None:
|
657
|
+
# Capture Lost
|
658
|
+
for i, hit in enumerate(self.hit_chain):
|
659
|
+
if hit is None:
|
660
|
+
continue # Element was dropped.
|
661
|
+
current_widget, current_matrix = hit
|
662
|
+
current_widget.event(
|
663
|
+
window_pos=None,
|
664
|
+
scene_pos=None,
|
665
|
+
event_type=event_type,
|
666
|
+
nearest_snap=None,
|
667
|
+
modifiers=None,
|
668
|
+
)
|
669
|
+
return False
|
670
|
+
if self.last_position is None:
|
671
|
+
self.last_position = window_pos
|
672
|
+
dx = window_pos[0] - self.last_position[0]
|
673
|
+
dy = window_pos[1] - self.last_position[1]
|
674
|
+
window_pos = (
|
675
|
+
window_pos[0],
|
676
|
+
window_pos[1],
|
677
|
+
self.last_position[0],
|
678
|
+
self.last_position[1],
|
679
|
+
dx,
|
680
|
+
dy,
|
681
|
+
)
|
682
|
+
self.last_position = window_pos
|
683
|
+
previous_top_element = None
|
684
|
+
try:
|
685
|
+
idx = 0
|
686
|
+
while idx < len(self.hit_chain):
|
687
|
+
if not self.hit_chain[idx][0].transparent:
|
688
|
+
previous_top_element = self.hit_chain[idx][0]
|
689
|
+
break
|
690
|
+
idx += 1
|
691
|
+
|
692
|
+
except (IndexError, TypeError):
|
693
|
+
pass
|
694
|
+
|
695
|
+
if event_type in (
|
696
|
+
"key_down",
|
697
|
+
"key_up",
|
698
|
+
):
|
699
|
+
# print("Keyboard-Event raised: %s" % event_type)
|
700
|
+
self.rebuild_hittable_chain()
|
701
|
+
for current_widget, current_matrix in self.hittable_elements:
|
702
|
+
space_pos = window_pos
|
703
|
+
if current_matrix is not None and not current_matrix.is_identity():
|
704
|
+
space_cur = current_matrix.point_in_inverse_space(window_pos[0:2])
|
705
|
+
space_last = current_matrix.point_in_inverse_space(window_pos[2:4])
|
706
|
+
sdx = space_cur[0] - space_last[0]
|
707
|
+
sdy = space_cur[1] - space_last[1]
|
708
|
+
space_pos = (
|
709
|
+
space_cur[0],
|
710
|
+
space_cur[1],
|
711
|
+
space_last[0],
|
712
|
+
space_last[1],
|
713
|
+
sdx,
|
714
|
+
sdy,
|
715
|
+
)
|
716
|
+
response = current_widget.event(
|
717
|
+
window_pos=window_pos,
|
718
|
+
space_pos=space_pos,
|
719
|
+
event_type=event_type,
|
720
|
+
nearest_snap=nearest_snap,
|
721
|
+
modifiers=modifiers,
|
722
|
+
keycode=keycode,
|
723
|
+
)
|
724
|
+
|
725
|
+
if response == RESPONSE_ABORT:
|
726
|
+
self.hit_chain.clear()
|
727
|
+
# print (f"Response abort of {event_type}, {keycode}/{modifiers} by {current_widget}")
|
728
|
+
return True
|
729
|
+
elif response == RESPONSE_CONSUME:
|
730
|
+
# if event_type in ("leftdown", "middledown", "middleup", "leftup", "move", "leftclick"):
|
731
|
+
# widgetname = type(current_widget).__name__
|
732
|
+
# print("Event %s was consumed by %s" % (event_type, widgetname))
|
733
|
+
# print (f"Response consume of {event_type}, {keycode}/{modifiers} by {current_widget}")
|
734
|
+
return True
|
735
|
+
elif response == RESPONSE_CHAIN:
|
736
|
+
continue
|
737
|
+
elif response == RESPONSE_DROP:
|
738
|
+
# self.hit_chain[i] = None
|
739
|
+
continue
|
740
|
+
#
|
741
|
+
# if response == RESPONSE_ABORT:
|
742
|
+
# self.hit_chain.clear()
|
743
|
+
return False
|
744
|
+
|
745
|
+
if event_type in (
|
746
|
+
"leftdown",
|
747
|
+
"middledown",
|
748
|
+
"rightdown",
|
749
|
+
"wheeldown",
|
750
|
+
"wheelup",
|
751
|
+
"hover",
|
752
|
+
):
|
753
|
+
self._down_start_time = time.time()
|
754
|
+
self._down_start_pos = window_pos
|
755
|
+
self.rebuild_hittable_chain()
|
756
|
+
self.find_hit_chain(window_pos)
|
757
|
+
for i, hit in enumerate(self.hit_chain):
|
758
|
+
if hit is None:
|
759
|
+
continue # Element was dropped.
|
760
|
+
current_widget, current_matrix = hit
|
761
|
+
if current_widget is None:
|
762
|
+
continue
|
763
|
+
space_pos = window_pos
|
764
|
+
if current_matrix is not None and not current_matrix.is_identity():
|
765
|
+
space_cur = current_matrix.point_in_inverse_space(window_pos[0:2])
|
766
|
+
space_last = current_matrix.point_in_inverse_space(window_pos[2:4])
|
767
|
+
sdx = space_cur[0] - space_last[0]
|
768
|
+
sdy = space_cur[1] - space_last[1]
|
769
|
+
space_pos = (
|
770
|
+
space_cur[0],
|
771
|
+
space_cur[1],
|
772
|
+
space_last[0],
|
773
|
+
space_last[1],
|
774
|
+
sdx,
|
775
|
+
sdy,
|
776
|
+
)
|
777
|
+
|
778
|
+
if (
|
779
|
+
i == 0
|
780
|
+
and event_type == "hover"
|
781
|
+
and previous_top_element is not current_widget
|
782
|
+
):
|
783
|
+
if previous_top_element is not None:
|
784
|
+
if self.log_events:
|
785
|
+
self.log_events(f"Converted hover_end: {str(window_pos)}")
|
786
|
+
previous_top_element.event(
|
787
|
+
window_pos=window_pos,
|
788
|
+
space_pos=space_pos,
|
789
|
+
event_type="hover_end",
|
790
|
+
nearest_snap=None,
|
791
|
+
modifiers=modifiers,
|
792
|
+
keycode=keycode,
|
793
|
+
)
|
794
|
+
current_widget.event(
|
795
|
+
window_pos=window_pos,
|
796
|
+
space_pos=space_pos,
|
797
|
+
event_type="hover_start",
|
798
|
+
nearest_snap=None,
|
799
|
+
modifiers=modifiers,
|
800
|
+
keycode=keycode,
|
801
|
+
)
|
802
|
+
if self.log_events:
|
803
|
+
self.log_events(f"Converted hover_start: {str(window_pos)}")
|
804
|
+
previous_top_element = current_widget
|
805
|
+
if (
|
806
|
+
event_type == "leftup"
|
807
|
+
and time.time() - self._down_start_time <= 0.30
|
808
|
+
and abs(complex(*window_pos[:2]) - complex(*self._down_start_pos[:2]))
|
809
|
+
< 50
|
810
|
+
): # Anything within 0.3 seconds will be converted to a leftclick
|
811
|
+
response = current_widget.event(
|
812
|
+
window_pos=window_pos,
|
813
|
+
space_pos=space_pos,
|
814
|
+
event_type="leftclick",
|
815
|
+
nearest_snap=nearest_snap,
|
816
|
+
modifiers=modifiers,
|
817
|
+
keycode=keycode,
|
818
|
+
)
|
819
|
+
if self.log_events:
|
820
|
+
self.log_events(f"Converted leftclick: {str(window_pos)}")
|
821
|
+
elif event_type == "leftup":
|
822
|
+
if self.log_events:
|
823
|
+
self.log_events(
|
824
|
+
f"Did not convert to click, {time.time() - self._down_start_time}"
|
825
|
+
)
|
826
|
+
response = current_widget.event(
|
827
|
+
window_pos=window_pos,
|
828
|
+
space_pos=space_pos,
|
829
|
+
event_type=event_type,
|
830
|
+
nearest_snap=nearest_snap,
|
831
|
+
modifiers=modifiers,
|
832
|
+
keycode=keycode,
|
833
|
+
)
|
834
|
+
# print ("Leftup called for widget #%d" % i )
|
835
|
+
# print (response)
|
836
|
+
else:
|
837
|
+
response = current_widget.event(
|
838
|
+
window_pos=window_pos,
|
839
|
+
space_pos=space_pos,
|
840
|
+
event_type=event_type,
|
841
|
+
nearest_snap=nearest_snap,
|
842
|
+
modifiers=modifiers,
|
843
|
+
keycode=keycode,
|
844
|
+
)
|
845
|
+
|
846
|
+
##################
|
847
|
+
# PROCESS RESPONSE
|
848
|
+
##################
|
849
|
+
if type(response) is tuple:
|
850
|
+
# print (f"Nearest snap provided")
|
851
|
+
# We get two additional parameters which are the screen location of the nearest snap point
|
852
|
+
params = response[1:]
|
853
|
+
response = response[0]
|
854
|
+
if len(params) > 1:
|
855
|
+
new_x_space = params[0]
|
856
|
+
new_y_space = params[1]
|
857
|
+
new_x = window_pos[0]
|
858
|
+
new_y = window_pos[1]
|
859
|
+
|
860
|
+
sdx = new_x_space - space_pos[0]
|
861
|
+
if current_matrix is not None and not current_matrix.is_identity():
|
862
|
+
sdx *= get_matrix_scale(current_matrix)
|
863
|
+
snap_x = window_pos[0] + sdx
|
864
|
+
sdy = new_y_space - space_pos[1]
|
865
|
+
if current_matrix is not None and not current_matrix.is_identity():
|
866
|
+
sdy *= current_matrix.value_scale_y()
|
867
|
+
# print("Shift x by %.1f pixel (%.1f), Shift y by %.1f pixel (%.1f)" % (sdx, odx, sdy, ody))
|
868
|
+
snap_y = window_pos[1] + sdy
|
869
|
+
|
870
|
+
# dx = new_x - self.last_position[0]
|
871
|
+
# dy = new_y - self.last_position[1]
|
872
|
+
if snap_x is None:
|
873
|
+
nearest_snap = None
|
874
|
+
else:
|
875
|
+
# We are providing the space and screen coordinates
|
876
|
+
snap_space = current_matrix.point_in_inverse_space(
|
877
|
+
(snap_x, snap_y)
|
878
|
+
)
|
879
|
+
nearest_snap = (
|
880
|
+
snap_space[0],
|
881
|
+
snap_space[1],
|
882
|
+
snap_x,
|
883
|
+
snap_y,
|
884
|
+
)
|
885
|
+
self.pane.last_snap = nearest_snap
|
886
|
+
|
887
|
+
if response == RESPONSE_ABORT:
|
888
|
+
self.hit_chain.clear()
|
889
|
+
return True
|
890
|
+
elif response == RESPONSE_CONSUME:
|
891
|
+
# if event_type in ("leftdown", "middledown", "middleup", "leftup", "move", "leftclick"):
|
892
|
+
# widgetname = type(current_widget).__name__
|
893
|
+
# print("Event %s was consumed by %s" % (event_type, widgetname))
|
894
|
+
return True
|
895
|
+
elif response == RESPONSE_CHAIN:
|
896
|
+
continue
|
897
|
+
elif response == RESPONSE_DROP:
|
898
|
+
self.hit_chain[i] = None
|
899
|
+
continue
|
900
|
+
else:
|
901
|
+
break
|
902
|
+
return False
|
903
|
+
|
904
|
+
def cursor(self, cursor, always=False):
|
905
|
+
"""
|
906
|
+
Routine to centralize and correct cursor info.
|
907
|
+
@param cursor: Changed cursor
|
908
|
+
@param always: Force cursor change
|
909
|
+
@return:
|
910
|
+
"""
|
911
|
+
if cursor == "sizing":
|
912
|
+
new_cursor = wx.CURSOR_SIZING
|
913
|
+
elif cursor in ("size_nw", "size_se"):
|
914
|
+
new_cursor = wx.CURSOR_SIZENWSE
|
915
|
+
elif cursor in ("size_sw", "size_ne"):
|
916
|
+
new_cursor = wx.CURSOR_SIZENESW
|
917
|
+
elif cursor in ("size_n", "size_s", "skew_y"):
|
918
|
+
new_cursor = wx.CURSOR_SIZENS
|
919
|
+
elif cursor in ("size_e", "size_w", "skew_x"):
|
920
|
+
new_cursor = wx.CURSOR_SIZEWE
|
921
|
+
elif cursor == "arrow":
|
922
|
+
new_cursor = wx.CURSOR_ARROW
|
923
|
+
elif cursor == "cross":
|
924
|
+
new_cursor = wx.CROSS_CURSOR
|
925
|
+
elif cursor == "rotate1":
|
926
|
+
new_cursor = wx.CURSOR_CROSS
|
927
|
+
elif cursor == "rotate2":
|
928
|
+
new_cursor = wx.CURSOR_CROSS
|
929
|
+
elif cursor == "rotmove":
|
930
|
+
new_cursor = wx.CURSOR_HAND
|
931
|
+
elif cursor == "reference":
|
932
|
+
new_cursor = wx.CURSOR_BULLSEYE
|
933
|
+
elif cursor == "text":
|
934
|
+
new_cursor = wx.CURSOR_IBEAM
|
935
|
+
else:
|
936
|
+
new_cursor = wx.CURSOR_ARROW
|
937
|
+
self.log("Invalid cursor.")
|
938
|
+
if platform.system() == "Linux":
|
939
|
+
if cursor == "sizing":
|
940
|
+
new_cursor = wx.CURSOR_SIZENWSE
|
941
|
+
elif cursor in ("size_nw", "size_se"):
|
942
|
+
new_cursor = wx.CURSOR_SIZING
|
943
|
+
elif cursor in ("size_sw", "size_ne"):
|
944
|
+
new_cursor = wx.CURSOR_SIZING
|
945
|
+
if new_cursor != self._cursor or always:
|
946
|
+
self._cursor = new_cursor
|
947
|
+
self.gui.scene_panel.SetCursor(wx.Cursor(self._cursor))
|
948
|
+
self.log(f"Cursor changed to {cursor}")
|
949
|
+
|
950
|
+
def add_scenewidget(self, widget, properties=ORIENTATION_RELATIVE):
|
951
|
+
"""
|
952
|
+
Delegate to the SceneSpaceWidget scene.
|
953
|
+
"""
|
954
|
+
self.widget_root.scene_widget.add_widget(-1, widget, properties)
|
955
|
+
|
956
|
+
def add_interfacewidget(self, widget, properties=ORIENTATION_RELATIVE):
|
957
|
+
"""
|
958
|
+
Delegate to the SceneSpaceWidget interface.
|
959
|
+
"""
|
960
|
+
self.widget_root.interface_widget.add_widget(-1, widget, properties)
|
961
|
+
|
962
|
+
# --- Centralised snap_point calculation
|
963
|
+
def _calculate_snap_points(self, my_x, my_y, length):
|
964
|
+
"""
|
965
|
+
Recalculate the snap element attraction points
|
966
|
+
|
967
|
+
@param length:
|
968
|
+
@return:
|
969
|
+
"""
|
970
|
+
for pts in self.snap_attraction_points:
|
971
|
+
if self.pane.modif_active:
|
972
|
+
if pts[3]:
|
973
|
+
# No snap points for emphasized objects.
|
974
|
+
continue
|
975
|
+
if abs(pts[0] - my_x) <= length and abs(pts[1] - my_y) <= length:
|
976
|
+
self.snap_display_points.append([pts[0], pts[1], pts[2]])
|
977
|
+
|
978
|
+
def _calculate_grid_points(self, my_x, my_y, length):
|
979
|
+
"""
|
980
|
+
Recalculate the local grid points
|
981
|
+
|
982
|
+
@param length:
|
983
|
+
@return:
|
984
|
+
"""
|
985
|
+
for pts in self.pane.grid.grid_points:
|
986
|
+
if abs(pts[0] - my_x) <= length and abs(pts[1] - my_y) <= length:
|
987
|
+
self.snap_display_points.append([pts[0], pts[1], TYPE_GRID])
|
988
|
+
|
989
|
+
def _calculate_attraction_points(self):
|
990
|
+
"""
|
991
|
+
Looks at all elements (all_points=True) or at non-selected elements (all_points=False) and identifies all
|
992
|
+
attraction points (center, corners, sides)
|
993
|
+
"""
|
994
|
+
self.context.elements.set_start_time("attr_calc_points")
|
995
|
+
self.snap_attraction_points = [] # Clear all
|
996
|
+
translation_table = {
|
997
|
+
"bounds top_left": TYPE_BOUND,
|
998
|
+
"bounds top_right": TYPE_BOUND,
|
999
|
+
"bounds bottom_left": TYPE_BOUND,
|
1000
|
+
"bounds bottom_right": TYPE_BOUND,
|
1001
|
+
"bounds center_center": TYPE_CENTER,
|
1002
|
+
"bounds top_center": TYPE_MIDDLE,
|
1003
|
+
"bounds bottom_center": TYPE_MIDDLE,
|
1004
|
+
"bounds center_left": TYPE_MIDDLE,
|
1005
|
+
"bounds center_right": TYPE_MIDDLE,
|
1006
|
+
"endpoint": TYPE_POINT,
|
1007
|
+
"point": TYPE_POINT,
|
1008
|
+
"midpoint": TYPE_MIDDLE_SMALL,
|
1009
|
+
}
|
1010
|
+
|
1011
|
+
for e in self.context.elements.flat(types=elem_nodes):
|
1012
|
+
emph = e.emphasized
|
1013
|
+
if hasattr(e, "points"):
|
1014
|
+
for pt in e.points:
|
1015
|
+
try:
|
1016
|
+
pt_type = translation_table[pt[2]]
|
1017
|
+
except:
|
1018
|
+
print(f"Unknown type: {pt[2]}")
|
1019
|
+
pt_type = TYPE_POINT
|
1020
|
+
self.snap_attraction_points.append([pt[0], pt[1], pt_type, emph])
|
1021
|
+
|
1022
|
+
self.context.elements.set_end_time(
|
1023
|
+
"attr_calc_points",
|
1024
|
+
message=f"points added={len(self.snap_attraction_points)}",
|
1025
|
+
)
|
1026
|
+
|
1027
|
+
def calculate_display_points(self, my_x, my_y, snap_points, snap_grid):
|
1028
|
+
"""
|
1029
|
+
Recalculate the points that need to be displayed for the user.
|
1030
|
+
|
1031
|
+
@return:
|
1032
|
+
"""
|
1033
|
+
self.snap_display_points = []
|
1034
|
+
if my_x is None:
|
1035
|
+
return
|
1036
|
+
if self.snap_attraction_points is None and snap_points:
|
1037
|
+
self._calculate_attraction_points()
|
1038
|
+
|
1039
|
+
matrix = self.widget_root.scene_widget.matrix
|
1040
|
+
length = self.context.show_attract_len / get_matrix_scale(matrix)
|
1041
|
+
|
1042
|
+
if snap_points and self.snap_attraction_points:
|
1043
|
+
self._calculate_snap_points(my_x, my_y, length)
|
1044
|
+
|
1045
|
+
if snap_grid and self.pane.grid.grid_points:
|
1046
|
+
self._calculate_grid_points(my_x, my_y, length)
|
1047
|
+
|
1048
|
+
def calculate_snap(self, my_x, my_y):
|
1049
|
+
"""
|
1050
|
+
Calculates the nearest_snap
|
1051
|
+
"""
|
1052
|
+
# Loop through display points, find closest.
|
1053
|
+
res_x = None
|
1054
|
+
res_y = None
|
1055
|
+
if self.snap_display_points and my_x is not None:
|
1056
|
+
# Has to be lower than the action threshold
|
1057
|
+
min_delta = float("inf")
|
1058
|
+
new_x = None
|
1059
|
+
new_y = None
|
1060
|
+
for pt in self.snap_display_points:
|
1061
|
+
dx = pt[0] - my_x
|
1062
|
+
dy = pt[1] - my_y
|
1063
|
+
delta = dx * dx + dy * dy
|
1064
|
+
if delta < min_delta:
|
1065
|
+
new_x = pt[0]
|
1066
|
+
new_y = pt[1]
|
1067
|
+
min_delta = delta
|
1068
|
+
if new_x is not None:
|
1069
|
+
matrix = self.widget_root.scene_widget.matrix
|
1070
|
+
pixel = self.context.action_attract_len / get_matrix_scale(matrix)
|
1071
|
+
if abs(new_x - my_x) <= pixel and abs(new_y - my_y) <= pixel:
|
1072
|
+
# If the distance is small enough: snap.
|
1073
|
+
res_x = new_x
|
1074
|
+
res_y = new_y
|
1075
|
+
return res_x, res_y
|
1076
|
+
|
1077
|
+
def get_snap_point(self, sx, sy, modifiers):
|
1078
|
+
resx = sx
|
1079
|
+
resy = sy
|
1080
|
+
sgrid = self.context.snap_grid
|
1081
|
+
spoints = self.context.snap_points
|
1082
|
+
if "shift" in modifiers:
|
1083
|
+
sgrid = not sgrid
|
1084
|
+
spoints = False
|
1085
|
+
if sgrid or spoints:
|
1086
|
+
if "shift" in modifiers:
|
1087
|
+
# Need to recalculate
|
1088
|
+
self.reset_snap_attraction()
|
1089
|
+
self.calculate_display_points(sx, sy, spoints, sgrid)
|
1090
|
+
nx, ny = self.calculate_snap(sx, sy)
|
1091
|
+
if nx is not None:
|
1092
|
+
resx = nx
|
1093
|
+
resy = ny
|
1094
|
+
if "shift" in modifiers:
|
1095
|
+
# Need to recalculate again
|
1096
|
+
self.reset_snap_attraction()
|
1097
|
+
return resx, resy
|
1098
|
+
|
1099
|
+
def reset_snap_attraction(self):
|
1100
|
+
self.snap_attraction_points = None
|