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/core/node/node.py
CHANGED
@@ -1,1304 +1,1427 @@
|
|
1
|
-
"""
|
2
|
-
The 'elements' service stores all the element types in a bootstrapped tree. Specific node types added to the tree become
|
3
|
-
particular class types and the interactions between these types and functions applied are registered in the kernel.
|
4
|
-
|
5
|
-
Types:
|
6
|
-
* root: Root Tree element
|
7
|
-
* branch ops: Operation Branch
|
8
|
-
* branch elems: Elements Branch
|
9
|
-
* branch reg: Regmark Branch
|
10
|
-
* reference: Element below op branch which stores specific data.
|
11
|
-
* op: LayerOperation within Operation Branch.
|
12
|
-
* elem: Element with Element Branch or subgroup.
|
13
|
-
* file: File Group within Elements Branch
|
14
|
-
* group: Group type within Branch Elems or refelem.
|
15
|
-
* cutcode: CutCode type within Operation Branch and Element Branch.
|
16
|
-
|
17
|
-
rasternode: theoretical: would store all the refelems to be rastered. Such that we could store rasters in images.
|
18
|
-
|
19
|
-
Tree Functions are to be stored: tree/command/type. These store many functions like the commands.
|
20
|
-
"""
|
21
|
-
|
22
|
-
|
23
|
-
from
|
24
|
-
from
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
#
|
29
|
-
#
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
#
|
40
|
-
#
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
#
|
49
|
-
#
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
Node
|
72
|
-
|
73
|
-
|
74
|
-
Nodes can be
|
75
|
-
Nodes can be
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
self.
|
81
|
-
self.
|
82
|
-
self.
|
83
|
-
self.
|
84
|
-
self.
|
85
|
-
self.
|
86
|
-
self.
|
87
|
-
self.
|
88
|
-
self.
|
89
|
-
self.
|
90
|
-
self.
|
91
|
-
self.
|
92
|
-
self.
|
93
|
-
self.
|
94
|
-
self.
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
self.
|
110
|
-
self.
|
111
|
-
|
112
|
-
self.
|
113
|
-
|
114
|
-
|
115
|
-
self.
|
116
|
-
|
117
|
-
|
118
|
-
self.
|
119
|
-
|
120
|
-
self.
|
121
|
-
self.
|
122
|
-
self.
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
self.
|
187
|
-
|
188
|
-
@property
|
189
|
-
def
|
190
|
-
return self.
|
191
|
-
|
192
|
-
@
|
193
|
-
def
|
194
|
-
self.
|
195
|
-
self.
|
196
|
-
|
197
|
-
@property
|
198
|
-
def
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
if
|
246
|
-
self.
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
result =
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
def
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
def
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
def
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
return
|
336
|
-
|
337
|
-
@property
|
338
|
-
def
|
339
|
-
return self.
|
340
|
-
|
341
|
-
@property
|
342
|
-
def
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
self.
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
self.
|
405
|
-
self.
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
def
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
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
|
-
|
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
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
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
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
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
|
-
self.
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
def
|
758
|
-
if self._parent is not None:
|
759
|
-
if node is None:
|
760
|
-
node = self
|
761
|
-
self._parent.
|
762
|
-
|
763
|
-
def
|
764
|
-
if self._parent is not None:
|
765
|
-
if node is None:
|
766
|
-
node = self
|
767
|
-
self._parent.
|
768
|
-
|
769
|
-
def
|
770
|
-
self.
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
self.
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
self.
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
self.
|
813
|
-
|
814
|
-
|
815
|
-
self.
|
816
|
-
|
817
|
-
|
818
|
-
if
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
def
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
if
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
self.
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
self.
|
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
|
-
def
|
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
|
-
|
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
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
self.
|
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
|
-
self
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
node
|
1050
|
-
if
|
1051
|
-
(
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
if
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
"""
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
node.
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
"""
|
1242
|
-
if
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
"""
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1
|
+
"""
|
2
|
+
The 'elements' service stores all the element types in a bootstrapped tree. Specific node types added to the tree become
|
3
|
+
particular class types and the interactions between these types and functions applied are registered in the kernel.
|
4
|
+
|
5
|
+
Types:
|
6
|
+
* root: Root Tree element
|
7
|
+
* branch ops: Operation Branch
|
8
|
+
* branch elems: Elements Branch
|
9
|
+
* branch reg: Regmark Branch
|
10
|
+
* reference: Element below op branch which stores specific data.
|
11
|
+
* op: LayerOperation within Operation Branch.
|
12
|
+
* elem: Element with Element Branch or subgroup.
|
13
|
+
* file: File Group within Elements Branch
|
14
|
+
* group: Group type within Branch Elems or refelem.
|
15
|
+
* cutcode: CutCode type within Operation Branch and Element Branch.
|
16
|
+
|
17
|
+
rasternode: theoretical: would store all the refelems to be rastered. Such that we could store rasters in images.
|
18
|
+
|
19
|
+
Tree Functions are to be stored: tree/command/type. These store many functions like the commands.
|
20
|
+
"""
|
21
|
+
|
22
|
+
import ast
|
23
|
+
from copy import copy
|
24
|
+
from enum import IntEnum
|
25
|
+
from time import time
|
26
|
+
|
27
|
+
|
28
|
+
# LINEJOIN
|
29
|
+
# Value arcs | bevel |miter | miter-clip | round
|
30
|
+
# Default value miter
|
31
|
+
class Linejoin(IntEnum):
|
32
|
+
JOIN_ARCS = 0
|
33
|
+
JOIN_BEVEL = 1
|
34
|
+
JOIN_MITER = 2
|
35
|
+
JOIN_MITER_CLIP = 3
|
36
|
+
JOIN_ROUND = 4
|
37
|
+
|
38
|
+
|
39
|
+
# LINECAP
|
40
|
+
# Value butt | round | square
|
41
|
+
# Default value butt
|
42
|
+
class Linecap(IntEnum):
|
43
|
+
CAP_BUTT = 0
|
44
|
+
CAP_ROUND = 1
|
45
|
+
CAP_SQUARE = 2
|
46
|
+
|
47
|
+
|
48
|
+
# FILL-RULE
|
49
|
+
# Value nonzero | evenodd
|
50
|
+
# Default value nonzero
|
51
|
+
class Fillrule(IntEnum):
|
52
|
+
FILLRULE_NONZERO = 0
|
53
|
+
FILLRULE_EVENODD = 1
|
54
|
+
|
55
|
+
|
56
|
+
class Node:
|
57
|
+
"""
|
58
|
+
Nodes are elements within the tree which stores most of the objects in Elements.
|
59
|
+
|
60
|
+
All nodes have children, root, parent, and reference links. The children are subnodes,
|
61
|
+
the root points to the tree root, the parent points to the immediate parent, and references
|
62
|
+
refers to nodes that point to this node type.
|
63
|
+
|
64
|
+
All nodes have type, id, label, and lock values.
|
65
|
+
|
66
|
+
Type is a string value of the given node type and is used to delineate nodes.
|
67
|
+
Label is a string value that will often describe the node.
|
68
|
+
`Id` is a string value, during saving, we make sure this is a unique id.
|
69
|
+
|
70
|
+
|
71
|
+
Node bounds exist, but not all nodes are have geometric bounds.
|
72
|
+
Node paint_bounds exists, not all nodes have painted area bounds.
|
73
|
+
|
74
|
+
Nodes can be emphasized. This is selecting the given node.
|
75
|
+
Nodes can be highlighted.
|
76
|
+
Nodes can be targeted.
|
77
|
+
"""
|
78
|
+
|
79
|
+
def __init__(self, *args, **kwargs):
|
80
|
+
self.type = None
|
81
|
+
self.id = None
|
82
|
+
self.label = None
|
83
|
+
self.lock = False
|
84
|
+
self._can_emphasize = True
|
85
|
+
self._can_highlight = True
|
86
|
+
self._can_target = True
|
87
|
+
self._can_move = True
|
88
|
+
self._can_scale = True
|
89
|
+
self._can_rotate = True
|
90
|
+
self._can_skew = True
|
91
|
+
self._can_modify = True
|
92
|
+
self._can_alter = True
|
93
|
+
self._can_update = True
|
94
|
+
self._can_remove = True
|
95
|
+
self._is_visible = True
|
96
|
+
self._expanded = False
|
97
|
+
self._children = list()
|
98
|
+
self._root = None
|
99
|
+
self._parent = None
|
100
|
+
self._references = list()
|
101
|
+
self._formatter = "{element_type}:{id}"
|
102
|
+
|
103
|
+
self._points = list()
|
104
|
+
self._points_dirty = True
|
105
|
+
|
106
|
+
self._selected = False
|
107
|
+
self._emphasized = False
|
108
|
+
self._emphasized_time = None
|
109
|
+
self._highlighted = False
|
110
|
+
self._target = False
|
111
|
+
|
112
|
+
self._opened = False
|
113
|
+
|
114
|
+
self._bounds = None
|
115
|
+
self._bounds_dirty = True
|
116
|
+
|
117
|
+
self._paint_bounds = None
|
118
|
+
self._paint_bounds_dirty = True
|
119
|
+
|
120
|
+
self._item = None
|
121
|
+
self._cache = None
|
122
|
+
self._default_map = dict()
|
123
|
+
if "expanded" in kwargs:
|
124
|
+
# print (f"Require expanded: {kwargs}")
|
125
|
+
exp_value = kwargs["expanded"]
|
126
|
+
self._expanded = exp_value
|
127
|
+
del kwargs["expanded"]
|
128
|
+
|
129
|
+
for k, v in kwargs.items():
|
130
|
+
if k.startswith("_"):
|
131
|
+
continue
|
132
|
+
if isinstance(v, str) and k not in ("text", "id", "label"):
|
133
|
+
try:
|
134
|
+
v = ast.literal_eval(v)
|
135
|
+
except (ValueError, SyntaxError):
|
136
|
+
pass
|
137
|
+
try:
|
138
|
+
setattr(self, k, v)
|
139
|
+
except AttributeError:
|
140
|
+
# If this is already an attribute, just add it to the node dict.
|
141
|
+
self.__dict__[k] = v
|
142
|
+
|
143
|
+
super().__init__()
|
144
|
+
|
145
|
+
def __repr__(self):
|
146
|
+
return f"{self.__class__.__name__}('{self.type}', {str(self._parent)})"
|
147
|
+
|
148
|
+
def __copy__(self):
|
149
|
+
return self.__class__(**self.node_dict)
|
150
|
+
|
151
|
+
def __str__(self):
|
152
|
+
text = self._formatter
|
153
|
+
if text is None:
|
154
|
+
text = "{element_type}"
|
155
|
+
default_map = self.default_map()
|
156
|
+
try:
|
157
|
+
return text.format_map(default_map)
|
158
|
+
except KeyError as e:
|
159
|
+
raise KeyError(
|
160
|
+
f"mapping '{text}' did not contain a required key in {default_map} for {self.__class__}"
|
161
|
+
) from e
|
162
|
+
|
163
|
+
def __eq__(self, other):
|
164
|
+
return other is self
|
165
|
+
|
166
|
+
def __hash__(self):
|
167
|
+
return id(self)
|
168
|
+
|
169
|
+
@property
|
170
|
+
def node_dict(self):
|
171
|
+
nd = dict()
|
172
|
+
for k, v in self.__dict__.items():
|
173
|
+
if k.startswith("_"):
|
174
|
+
continue
|
175
|
+
if k == "type":
|
176
|
+
continue
|
177
|
+
nd[k] = v
|
178
|
+
return nd
|
179
|
+
|
180
|
+
@property
|
181
|
+
def children(self):
|
182
|
+
return self._children
|
183
|
+
|
184
|
+
@property
|
185
|
+
def references(self):
|
186
|
+
return self._references
|
187
|
+
|
188
|
+
@property
|
189
|
+
def targeted(self):
|
190
|
+
return self._target
|
191
|
+
|
192
|
+
@targeted.setter
|
193
|
+
def targeted(self, value):
|
194
|
+
self._target = value
|
195
|
+
self.notify_targeted(self)
|
196
|
+
|
197
|
+
@property
|
198
|
+
def expanded(self):
|
199
|
+
return self._expanded
|
200
|
+
|
201
|
+
@expanded.setter
|
202
|
+
def expanded(self, value):
|
203
|
+
self._expanded = value
|
204
|
+
# No use case for notify expand
|
205
|
+
# self.notify_expand(self)
|
206
|
+
|
207
|
+
@property
|
208
|
+
def highlighted(self):
|
209
|
+
return self._highlighted
|
210
|
+
|
211
|
+
@highlighted.setter
|
212
|
+
def highlighted(self, value):
|
213
|
+
self._highlighted = value
|
214
|
+
self.notify_highlighted(self)
|
215
|
+
|
216
|
+
@property
|
217
|
+
def is_visible(self):
|
218
|
+
result = True
|
219
|
+
# is it an operation?
|
220
|
+
if hasattr(self, "output"):
|
221
|
+
if self.output:
|
222
|
+
return True
|
223
|
+
else:
|
224
|
+
return self._is_visible
|
225
|
+
if hasattr(self, "references"):
|
226
|
+
valid = False
|
227
|
+
flag = False
|
228
|
+
for n in self.references:
|
229
|
+
if hasattr(n.parent, "output"):
|
230
|
+
valid = True
|
231
|
+
if n.parent.output is None or n.parent.output:
|
232
|
+
flag = True
|
233
|
+
break
|
234
|
+
if n.parent.is_visible:
|
235
|
+
flag = True
|
236
|
+
break
|
237
|
+
# If there aren't any references then it is visible by default
|
238
|
+
if valid:
|
239
|
+
result = flag
|
240
|
+
return result
|
241
|
+
|
242
|
+
@is_visible.setter
|
243
|
+
def is_visible(self, value):
|
244
|
+
# is it an operation?
|
245
|
+
if hasattr(self, "output"):
|
246
|
+
if self.output:
|
247
|
+
value = True
|
248
|
+
else:
|
249
|
+
value = True
|
250
|
+
self._is_visible = value
|
251
|
+
|
252
|
+
@property
|
253
|
+
def emphasized(self):
|
254
|
+
if self.is_visible:
|
255
|
+
result = self._emphasized
|
256
|
+
else:
|
257
|
+
result = False
|
258
|
+
return result
|
259
|
+
|
260
|
+
@emphasized.setter
|
261
|
+
def emphasized(self, value):
|
262
|
+
if not self.is_visible:
|
263
|
+
value = False
|
264
|
+
if value != self._emphasized:
|
265
|
+
self._emphasized = value
|
266
|
+
if value:
|
267
|
+
# Any value that is emphasiezd is automatically selected True
|
268
|
+
# This is not true for the inverse case, a node can be selected
|
269
|
+
# but not necessarily emphasized
|
270
|
+
self._selected = True
|
271
|
+
self._emphasized_time = time() if value else None
|
272
|
+
self.notify_emphasized(self)
|
273
|
+
|
274
|
+
@property
|
275
|
+
def emphasized_time(self):
|
276
|
+
# we intentionally reduce the resolution to 1/100 sec.
|
277
|
+
# to allow simultaneous assignments to return the same delta
|
278
|
+
factor = 100
|
279
|
+
if self._emphasized_time is None:
|
280
|
+
# Insanely high
|
281
|
+
result = float("inf")
|
282
|
+
else:
|
283
|
+
result = self._emphasized_time
|
284
|
+
result = round(result * factor) / factor
|
285
|
+
return result
|
286
|
+
|
287
|
+
def emphasized_since(self, reftime=None, fullres=False):
|
288
|
+
# we intentionally reduce the resolution to 1/100 sec.
|
289
|
+
# to allow simultaneous assignments to return the same delta
|
290
|
+
factor = 100
|
291
|
+
if reftime is None:
|
292
|
+
reftime = time()
|
293
|
+
if self._emphasized_time is None:
|
294
|
+
delta = 0
|
295
|
+
else:
|
296
|
+
delta = reftime - self._emphasized_time
|
297
|
+
if not fullres:
|
298
|
+
delta = round(delta * factor) / factor
|
299
|
+
return delta
|
300
|
+
|
301
|
+
@property
|
302
|
+
def selected(self):
|
303
|
+
return self._selected
|
304
|
+
|
305
|
+
@selected.setter
|
306
|
+
def selected(self, value):
|
307
|
+
self._selected = value
|
308
|
+
self.notify_selected(self)
|
309
|
+
|
310
|
+
@property
|
311
|
+
def parent(self):
|
312
|
+
return self._parent
|
313
|
+
|
314
|
+
@property
|
315
|
+
def root(self):
|
316
|
+
return self._root
|
317
|
+
|
318
|
+
@property
|
319
|
+
def can_emphasize(self):
|
320
|
+
return self._can_emphasize
|
321
|
+
|
322
|
+
@property
|
323
|
+
def can_highlight(self):
|
324
|
+
return self._can_highlight
|
325
|
+
|
326
|
+
@property
|
327
|
+
def can_target(self):
|
328
|
+
return self._can_target
|
329
|
+
|
330
|
+
def can_move(self, optional_permission=False):
|
331
|
+
if not self._can_move:
|
332
|
+
return False
|
333
|
+
if optional_permission:
|
334
|
+
return True
|
335
|
+
return not self.lock
|
336
|
+
|
337
|
+
@property
|
338
|
+
def can_scale(self):
|
339
|
+
return self._can_scale and not self.lock
|
340
|
+
|
341
|
+
@property
|
342
|
+
def can_rotate(self):
|
343
|
+
return self._can_rotate and not self.lock
|
344
|
+
|
345
|
+
@property
|
346
|
+
def can_skew(self):
|
347
|
+
return self._can_skew and not self.lock
|
348
|
+
|
349
|
+
@property
|
350
|
+
def can_modify(self):
|
351
|
+
return self._can_modify and not self.lock
|
352
|
+
|
353
|
+
@property
|
354
|
+
def can_alter(self):
|
355
|
+
return self._can_alter and not self.lock
|
356
|
+
|
357
|
+
@property
|
358
|
+
def can_update(self):
|
359
|
+
return self._can_update and not self.lock
|
360
|
+
|
361
|
+
@property
|
362
|
+
def can_remove(self):
|
363
|
+
return self._can_remove and not self.lock
|
364
|
+
|
365
|
+
@property
|
366
|
+
def bounds(self):
|
367
|
+
if not self._bounds_dirty:
|
368
|
+
return self._bounds
|
369
|
+
|
370
|
+
try:
|
371
|
+
self._bounds = self.bbox(with_stroke=False)
|
372
|
+
except AttributeError:
|
373
|
+
self._bounds = None
|
374
|
+
|
375
|
+
if self._children:
|
376
|
+
self._bounds = Node.union_bounds(self._children, bounds=self._bounds)
|
377
|
+
self._bounds_dirty = False
|
378
|
+
return self._bounds
|
379
|
+
|
380
|
+
@property
|
381
|
+
def paint_bounds(self):
|
382
|
+
# Make sure that bounds is valid
|
383
|
+
if not self._paint_bounds_dirty:
|
384
|
+
return self._paint_bounds
|
385
|
+
|
386
|
+
flag = True
|
387
|
+
if hasattr(self, "stroke"):
|
388
|
+
if self.stroke is None or self.stroke.argb is None:
|
389
|
+
flag = False
|
390
|
+
try:
|
391
|
+
self._paint_bounds = self.bbox(with_stroke=flag)
|
392
|
+
except AttributeError:
|
393
|
+
self._paint_bounds = None
|
394
|
+
|
395
|
+
if self._children:
|
396
|
+
self._paint_bounds = Node.union_bounds(
|
397
|
+
self._children, bounds=self._paint_bounds, attr="paint_bounds"
|
398
|
+
)
|
399
|
+
self._paint_bounds_dirty = False
|
400
|
+
return self._paint_bounds
|
401
|
+
|
402
|
+
def set_dirty_bounds(self):
|
403
|
+
self._paint_bounds_dirty = True
|
404
|
+
self._bounds_dirty = True
|
405
|
+
self._points_dirty = True
|
406
|
+
|
407
|
+
def set_dirty(self):
|
408
|
+
self.points_dirty = True
|
409
|
+
self.empty_cache()
|
410
|
+
|
411
|
+
@property
|
412
|
+
def formatter(self):
|
413
|
+
return self._formatter
|
414
|
+
|
415
|
+
@formatter.setter
|
416
|
+
def formatter(self, formatter):
|
417
|
+
self._formatter = formatter
|
418
|
+
|
419
|
+
def display_label(self):
|
420
|
+
x = self.label
|
421
|
+
if x is None:
|
422
|
+
return None
|
423
|
+
start = 0
|
424
|
+
default_map = self._default_map
|
425
|
+
while True:
|
426
|
+
i1 = x.find("{", start)
|
427
|
+
if i1 < 0:
|
428
|
+
break
|
429
|
+
i2 = x.find("}", i1)
|
430
|
+
if i2 < 0:
|
431
|
+
break
|
432
|
+
nd = x[i1 + 1 : i2]
|
433
|
+
nd_val = ""
|
434
|
+
if nd in default_map:
|
435
|
+
n_val = default_map[nd]
|
436
|
+
if n_val is not None:
|
437
|
+
nd_val = str(n_val)
|
438
|
+
elif hasattr(self, nd):
|
439
|
+
n_val = getattr(self, nd, "")
|
440
|
+
if n_val is not None:
|
441
|
+
nd_val = str(n_val)
|
442
|
+
x = x[:i1] + nd_val + x[i2 + 1 :]
|
443
|
+
start = i1 + len(nd_val)
|
444
|
+
return x
|
445
|
+
|
446
|
+
@property
|
447
|
+
def points(self):
|
448
|
+
"""
|
449
|
+
Returns the node points values
|
450
|
+
|
451
|
+
@return: validated node point values, this is a list of lists of 3 elements.
|
452
|
+
"""
|
453
|
+
if self._points_dirty:
|
454
|
+
self.revalidate_points()
|
455
|
+
self._points_dirty = False
|
456
|
+
return self._points
|
457
|
+
|
458
|
+
def restore_tree(self, tree_data):
|
459
|
+
# Takes a backup and reapplies it again to the tree
|
460
|
+
# Caveat: we can't just simply take the backup and load it into the tree,
|
461
|
+
# although it is already a perfectly independent copy.
|
462
|
+
# self._children.extend(tree_data)
|
463
|
+
# If loaded directly as above then this stored state will be used
|
464
|
+
# as the basis for further modifications consequently changing the
|
465
|
+
# original data (as it is still the original structure) used in the undostack.
|
466
|
+
# tree_data contains the copied branch nodes
|
467
|
+
|
468
|
+
self._children.clear()
|
469
|
+
links = {id(self): (self, None)}
|
470
|
+
attrib_list = ("_selected", "_emphasized", "_emphasized_time", "_highlighted", "_expanded")
|
471
|
+
for c in tree_data:
|
472
|
+
c._build_copy_nodes(links=links)
|
473
|
+
node_copy = copy(c)
|
474
|
+
for att in attrib_list:
|
475
|
+
if getattr(node_copy, att) != getattr(c, att):
|
476
|
+
# print (f"Strange {att} not identical, fixing")
|
477
|
+
setattr(node_copy, att, getattr(c, att))
|
478
|
+
node_copy._root = self._root
|
479
|
+
links[id(c)] = (c, node_copy)
|
480
|
+
|
481
|
+
# Rebuild structure.
|
482
|
+
self._validate_links(links)
|
483
|
+
branches = [links[id(c)][1] for c in tree_data]
|
484
|
+
self._children.extend(branches)
|
485
|
+
self._validate_tree()
|
486
|
+
|
487
|
+
def _validate_links(self, links):
|
488
|
+
for uid, n in links.items():
|
489
|
+
node, node_copy = n
|
490
|
+
if node._parent is None:
|
491
|
+
# Root.
|
492
|
+
continue
|
493
|
+
# Find copy-parent of copy-node and link.
|
494
|
+
original_parent, copied_parent = links[id(node._parent)]
|
495
|
+
if copied_parent is None:
|
496
|
+
# copy_parent should have been copied root, but roots don't copy
|
497
|
+
node_copy._parent = self._root
|
498
|
+
continue
|
499
|
+
node_copy._parent = copied_parent
|
500
|
+
copied_parent._children.append(node_copy)
|
501
|
+
if node.type == "reference":
|
502
|
+
original_referenced, copied_referenced = links[id(node.node)]
|
503
|
+
node_copy.node = copied_referenced
|
504
|
+
copied_referenced._references.append(node_copy)
|
505
|
+
|
506
|
+
def _validate_tree(self):
|
507
|
+
for c in self._children:
|
508
|
+
assert c._parent is self
|
509
|
+
assert c._root is self._root
|
510
|
+
assert c in c._parent._children
|
511
|
+
for q in c._references:
|
512
|
+
assert q.node is c
|
513
|
+
if c.type == "reference":
|
514
|
+
assert c in c.node._references
|
515
|
+
c._validate_tree()
|
516
|
+
|
517
|
+
def _build_copy_nodes(self, links=None):
|
518
|
+
"""
|
519
|
+
Creates a copy of each node, linked to the ID of the original node. This will create
|
520
|
+
a map between id of original node and copy node. Without any structure. The original
|
521
|
+
root will link to `None` since root copies are in-effective.
|
522
|
+
|
523
|
+
@param links:
|
524
|
+
@return:
|
525
|
+
"""
|
526
|
+
if links is None:
|
527
|
+
links = {id(self): (self, None)}
|
528
|
+
attrib_list = ("_selected", "_emphasized", "_emphasized_time", "_highlighted", "_expanded")
|
529
|
+
for c in self._children:
|
530
|
+
c._build_copy_nodes(links=links)
|
531
|
+
node_copy = copy(c)
|
532
|
+
for att in attrib_list:
|
533
|
+
if getattr(node_copy, att) != getattr(c, att):
|
534
|
+
# print (f"Strange {att} not identical, fixing")
|
535
|
+
setattr(node_copy, att, getattr(c, att))
|
536
|
+
node_copy._root = self._root
|
537
|
+
links[id(c)] = (c, node_copy)
|
538
|
+
return links
|
539
|
+
|
540
|
+
def backup_tree(self):
|
541
|
+
"""
|
542
|
+
Creates structured copy of the branches of the tree at the current node.
|
543
|
+
|
544
|
+
This creates copied nodes, relinks the structure and returns branches of
|
545
|
+
the current node.
|
546
|
+
@return:
|
547
|
+
"""
|
548
|
+
links = self._build_copy_nodes()
|
549
|
+
|
550
|
+
# Rebuild structure.
|
551
|
+
self._validate_links(links)
|
552
|
+
branches = [links[id(c)][1] for c in self._children]
|
553
|
+
return branches
|
554
|
+
|
555
|
+
def create_label(self, text=None):
|
556
|
+
if text is None:
|
557
|
+
text = "{element_type}:{id}"
|
558
|
+
# Just for the optical impression (who understands what a "Rect: None" means),
|
559
|
+
# let's replace some of the more obvious ones...
|
560
|
+
mymap = self.default_map()
|
561
|
+
for key in mymap:
|
562
|
+
if hasattr(self, key) and mymap[key] == "None":
|
563
|
+
if getattr(self, key) is None:
|
564
|
+
mymap[key] = "-"
|
565
|
+
# slist = text.split("{")
|
566
|
+
# for item in slist:
|
567
|
+
# idx = item.find("}")
|
568
|
+
# if idx>0:
|
569
|
+
# sitem = item[0:idx]
|
570
|
+
# else:
|
571
|
+
# sitem = item
|
572
|
+
# try:
|
573
|
+
# dummy = mymap[sitem]
|
574
|
+
# except KeyError:
|
575
|
+
# # Addit
|
576
|
+
# mymap[sitem] = "??ERR??"
|
577
|
+
try:
|
578
|
+
result = text.format_map(mymap)
|
579
|
+
except ValueError:
|
580
|
+
result = "<invalid pattern>"
|
581
|
+
return result
|
582
|
+
|
583
|
+
def default_map(self, default_map=None): # , skip_label=False
|
584
|
+
if default_map is None:
|
585
|
+
default_map = self._default_map
|
586
|
+
default_map["id"] = str(self.id) if self.id is not None else "-"
|
587
|
+
lbl = self.display_label()
|
588
|
+
default_map["label"] = lbl if lbl is not None else ""
|
589
|
+
default_map["desc"] = (
|
590
|
+
lbl if lbl is not None else str(self.id) if self.id is not None else "-"
|
591
|
+
)
|
592
|
+
default_map["element_type"] = "Node"
|
593
|
+
default_map["node_type"] = self.type
|
594
|
+
return default_map
|
595
|
+
|
596
|
+
def valid_node_for_reference(self, node):
|
597
|
+
return True
|
598
|
+
|
599
|
+
def copy_children_as_references(self, obj):
|
600
|
+
"""
|
601
|
+
Copy the children of the given object as direct references to those children.
|
602
|
+
@param obj:
|
603
|
+
@return:
|
604
|
+
"""
|
605
|
+
for element in obj.children:
|
606
|
+
self.add_reference(element)
|
607
|
+
|
608
|
+
def copy_with_reified_tree(self):
|
609
|
+
"""
|
610
|
+
Make a copy of the current node, and a copy of the sub-nodes dereferencing any reference nodes
|
611
|
+
@return:
|
612
|
+
"""
|
613
|
+
copy_c = copy(self)
|
614
|
+
copy_c.copy_children_as_real(self)
|
615
|
+
return copy_c
|
616
|
+
|
617
|
+
def copy_children_as_real(self, copy_node):
|
618
|
+
"""
|
619
|
+
Copy the children of copy_node to the current node, dereferencing any reference nodes.
|
620
|
+
@param copy_node:
|
621
|
+
@return:
|
622
|
+
"""
|
623
|
+
for child in copy_node.children:
|
624
|
+
child = child
|
625
|
+
if child.type == "reference":
|
626
|
+
child = child.node
|
627
|
+
copy_child = copy(child)
|
628
|
+
self.add_node(copy_child)
|
629
|
+
copy_child.copy_children_as_real(child)
|
630
|
+
|
631
|
+
def is_draggable(self):
|
632
|
+
return True
|
633
|
+
|
634
|
+
def can_drop(self, drag_node):
|
635
|
+
return False
|
636
|
+
|
637
|
+
def would_accept_drop(self, drag_nodes):
|
638
|
+
# drag_nodes can be a single node or a list of nodes
|
639
|
+
# drag_nodes can be a single node or a list of nodes
|
640
|
+
if isinstance(drag_nodes, (list, tuple)):
|
641
|
+
data = drag_nodes
|
642
|
+
else:
|
643
|
+
data = list(drag_nodes)
|
644
|
+
return any(self.can_drop(node) for node in data)
|
645
|
+
|
646
|
+
def drop(self, drag_node, modify=True, flag=False):
|
647
|
+
"""
|
648
|
+
Process drag and drop node values for tree reordering.
|
649
|
+
|
650
|
+
@param drag_node:
|
651
|
+
@param modify:
|
652
|
+
@return:
|
653
|
+
"""
|
654
|
+
return False
|
655
|
+
|
656
|
+
def reverse(self):
|
657
|
+
self._children.reverse()
|
658
|
+
self.notify_reorder()
|
659
|
+
|
660
|
+
def load(self, settings, section):
|
661
|
+
"""
|
662
|
+
Default loading will read the persistence object, such that any values found in the given section of the
|
663
|
+
settings file. Will load parse the file to the correct type and set the attributes on this node.
|
664
|
+
|
665
|
+
@param settings:
|
666
|
+
@param section:
|
667
|
+
@return:
|
668
|
+
"""
|
669
|
+
settings.read_persistent_object(section, self)
|
670
|
+
|
671
|
+
def save(self, settings, section):
|
672
|
+
"""
|
673
|
+
The default node saving to a settings will write the persistence dictionary of the instance dictionary. This
|
674
|
+
will save to that section any non `_` attributes.
|
675
|
+
|
676
|
+
@param settings:
|
677
|
+
@param section:
|
678
|
+
@return:
|
679
|
+
"""
|
680
|
+
settings.write_persistent_dict(section, self.__dict__)
|
681
|
+
|
682
|
+
def revalidate_points(self):
|
683
|
+
"""
|
684
|
+
Ensure the points values for the node are valid with regard to the node's
|
685
|
+
current state. By default, this calls bounds but valid nodes can be overloaded
|
686
|
+
based on specific node type.
|
687
|
+
|
688
|
+
Should be overloaded by subclasses.
|
689
|
+
|
690
|
+
@return:
|
691
|
+
"""
|
692
|
+
bounds = self.bounds
|
693
|
+
if bounds is None:
|
694
|
+
return
|
695
|
+
if len(self._points) < 5:
|
696
|
+
self._points.extend([None] * (5 - len(self._points)))
|
697
|
+
self._points[0] = [bounds[0], bounds[1], "bounds top_left"]
|
698
|
+
self._points[1] = [bounds[2], bounds[1], "bounds top_right"]
|
699
|
+
self._points[2] = [bounds[0], bounds[3], "bounds bottom_left"]
|
700
|
+
self._points[3] = [bounds[2], bounds[3], "bounds bottom_right"]
|
701
|
+
cx = (bounds[0] + bounds[2]) / 2
|
702
|
+
cy = (bounds[1] + bounds[3]) / 2
|
703
|
+
self._points[4] = [cx, cy, "bounds center_center"]
|
704
|
+
|
705
|
+
def update_point(self, index, point):
|
706
|
+
"""
|
707
|
+
Attempt to update a node value, located at a specific index with the new
|
708
|
+
point provided.
|
709
|
+
|
710
|
+
Should be overloaded by subclasses.
|
711
|
+
|
712
|
+
@param index: updating point index
|
713
|
+
@param point: Point to be updated
|
714
|
+
@return: Whether update was successful
|
715
|
+
"""
|
716
|
+
return False
|
717
|
+
|
718
|
+
def add_point(self, point, index=None):
|
719
|
+
"""
|
720
|
+
Attempts to add a point into node.points.
|
721
|
+
|
722
|
+
Should be overloaded by subclasses.
|
723
|
+
|
724
|
+
@param point: point to be added
|
725
|
+
@param index: index for point insertion
|
726
|
+
@return: Whether append was successful
|
727
|
+
"""
|
728
|
+
# return self._insert_point(point, index)
|
729
|
+
return False
|
730
|
+
|
731
|
+
def _insert_point(self, point, index=None):
|
732
|
+
"""
|
733
|
+
Default implementation of inserting point into points.
|
734
|
+
|
735
|
+
@param point:
|
736
|
+
@param index:
|
737
|
+
@return:
|
738
|
+
"""
|
739
|
+
x = None
|
740
|
+
y = None
|
741
|
+
point_type = None
|
742
|
+
try:
|
743
|
+
x = point[0]
|
744
|
+
y = point[1]
|
745
|
+
point_type = point[3]
|
746
|
+
except IndexError:
|
747
|
+
pass
|
748
|
+
if index is None:
|
749
|
+
self._points.append([x, y, point_type])
|
750
|
+
else:
|
751
|
+
try:
|
752
|
+
self._points.insert(index, [x, y, point_type])
|
753
|
+
except IndexError:
|
754
|
+
return False
|
755
|
+
return True
|
756
|
+
|
757
|
+
def notify_created(self, node=None, **kwargs):
|
758
|
+
if self._parent is not None:
|
759
|
+
if node is None:
|
760
|
+
node = self
|
761
|
+
self._parent.notify_created(node=node, **kwargs)
|
762
|
+
|
763
|
+
def notify_destroyed(self, node=None, **kwargs):
|
764
|
+
if self._parent is not None:
|
765
|
+
if node is None:
|
766
|
+
node = self
|
767
|
+
self._parent.notify_destroyed(node=node, **kwargs)
|
768
|
+
|
769
|
+
def notify_attached(self, node=None, **kwargs):
|
770
|
+
if self._parent is not None:
|
771
|
+
if node is None:
|
772
|
+
node = self
|
773
|
+
self._parent.notify_attached(node=node, **kwargs)
|
774
|
+
|
775
|
+
def notify_detached(self, node=None, **kwargs):
|
776
|
+
if self._parent is not None:
|
777
|
+
if node is None:
|
778
|
+
node = self
|
779
|
+
self._parent.notify_detached(node=node, **kwargs)
|
780
|
+
|
781
|
+
def notify_changed(self, node, **kwargs):
|
782
|
+
if self._parent is not None:
|
783
|
+
if node is None:
|
784
|
+
node = self
|
785
|
+
self._parent.notify_changed(node=node, **kwargs)
|
786
|
+
|
787
|
+
def notify_selected(self, node=None, **kwargs):
|
788
|
+
if self._parent is not None:
|
789
|
+
if node is None:
|
790
|
+
node = self
|
791
|
+
self._parent.notify_selected(node=node, **kwargs)
|
792
|
+
|
793
|
+
def notify_emphasized(self, node=None, **kwargs):
|
794
|
+
if self._parent is not None:
|
795
|
+
if node is None:
|
796
|
+
node = self
|
797
|
+
self._parent.notify_emphasized(node=node, **kwargs)
|
798
|
+
|
799
|
+
def notify_targeted(self, node=None, **kwargs):
|
800
|
+
if self._parent is not None:
|
801
|
+
if node is None:
|
802
|
+
node = self
|
803
|
+
self._parent.notify_targeted(node=node, **kwargs)
|
804
|
+
|
805
|
+
def notify_highlighted(self, node=None, **kwargs):
|
806
|
+
if self._root is not None:
|
807
|
+
if node is None:
|
808
|
+
node = self
|
809
|
+
self._root.notify_highlighted(node=node, **kwargs)
|
810
|
+
|
811
|
+
def notify_modified(self, node=None, **kwargs):
|
812
|
+
if self._parent is not None:
|
813
|
+
if node is None:
|
814
|
+
node = self
|
815
|
+
self._parent.notify_modified(node=node, **kwargs)
|
816
|
+
|
817
|
+
def notify_translated(self, node=None, dx=0, dy=0, invalidate=False, interim=False, **kwargs):
|
818
|
+
if invalidate:
|
819
|
+
self.set_dirty_bounds()
|
820
|
+
if self._parent is not None:
|
821
|
+
if node is None:
|
822
|
+
node = self
|
823
|
+
# Any change to position / size needs a recalculation of the bounds
|
824
|
+
self._parent.notify_translated(
|
825
|
+
node=node, dx=dx, dy=dy, invalidate=True, interim=interim, **kwargs
|
826
|
+
)
|
827
|
+
|
828
|
+
def notify_scaled(
|
829
|
+
self, node=None, sx=1, sy=1, ox=0, oy=0, invalidate=False, interim=False, **kwargs
|
830
|
+
):
|
831
|
+
if invalidate:
|
832
|
+
self.set_dirty_bounds()
|
833
|
+
if self._parent is not None:
|
834
|
+
if node is None:
|
835
|
+
node = self
|
836
|
+
# Any change to position / size needs a recalculation of the bounds
|
837
|
+
self._parent.notify_scaled(
|
838
|
+
node=node, sx=sx, sy=sy, ox=ox, oy=oy, invalidate=True, interim=interim, **kwargs
|
839
|
+
)
|
840
|
+
|
841
|
+
def notify_altered(self, node=None, **kwargs):
|
842
|
+
if self._parent is not None:
|
843
|
+
if node is None:
|
844
|
+
node = self
|
845
|
+
self._parent.notify_altered(node=node, **kwargs)
|
846
|
+
|
847
|
+
def notify_expand(self, node=None, **kwargs):
|
848
|
+
if self._parent is not None:
|
849
|
+
if node is None:
|
850
|
+
node = self
|
851
|
+
self._parent.notify_expand(node=node, **kwargs)
|
852
|
+
|
853
|
+
def notify_collapse(self, node=None, **kwargs):
|
854
|
+
if self._parent is not None:
|
855
|
+
if node is None:
|
856
|
+
node = self
|
857
|
+
self._parent.notify_collapse(node=node, **kwargs)
|
858
|
+
|
859
|
+
def notify_reorder(self, node=None, **kwargs):
|
860
|
+
if self._parent is not None:
|
861
|
+
if node is None:
|
862
|
+
node = self
|
863
|
+
self._parent.notify_reorder(node=node, **kwargs)
|
864
|
+
|
865
|
+
def notify_update(self, node=None, **kwargs):
|
866
|
+
if self._parent is not None:
|
867
|
+
if node is None:
|
868
|
+
node = self
|
869
|
+
self._parent.notify_update(node=node, **kwargs)
|
870
|
+
|
871
|
+
def notify_focus(self, node=None, **kwargs):
|
872
|
+
if self._parent is not None:
|
873
|
+
if node is None:
|
874
|
+
node = self
|
875
|
+
self._parent.notify_focus(node=node, **kwargs)
|
876
|
+
|
877
|
+
def focus(self):
|
878
|
+
self.notify_focus(self)
|
879
|
+
|
880
|
+
def invalidated_node(self):
|
881
|
+
"""
|
882
|
+
Invalidation of the individual node.
|
883
|
+
"""
|
884
|
+
self.set_dirty_bounds()
|
885
|
+
self._bounds = None
|
886
|
+
self._paint_bounds = None
|
887
|
+
|
888
|
+
def invalidated(self):
|
889
|
+
"""
|
890
|
+
Invalidation occurs when the underlying data is altered or modified. This propagates up from children to
|
891
|
+
invalidate the entire parental line.
|
892
|
+
"""
|
893
|
+
self.invalidated_node()
|
894
|
+
if self._parent is not None:
|
895
|
+
self._parent.invalidated()
|
896
|
+
|
897
|
+
def updated(self):
|
898
|
+
"""
|
899
|
+
The nodes display information may have changed but nothing about the matrix or the internal data is altered.
|
900
|
+
"""
|
901
|
+
self.notify_update(self)
|
902
|
+
|
903
|
+
def modified(self):
|
904
|
+
"""
|
905
|
+
The matrix transformation was changed. The object is shaped
|
906
|
+
differently but fundamentally the same structure of data.
|
907
|
+
"""
|
908
|
+
self.invalidated()
|
909
|
+
self.notify_modified(self)
|
910
|
+
|
911
|
+
def translated(self, dx, dy, interim=False):
|
912
|
+
"""
|
913
|
+
This is a special case of the modified call, we are translating
|
914
|
+
the node without fundamentally altering its properties
|
915
|
+
"""
|
916
|
+
if self._bounds_dirty or self._bounds is None:
|
917
|
+
# A pity but we need proper data
|
918
|
+
self.modified()
|
919
|
+
return
|
920
|
+
self._bounds = [
|
921
|
+
self._bounds[0] + dx,
|
922
|
+
self._bounds[1] + dy,
|
923
|
+
self._bounds[2] + dx,
|
924
|
+
self._bounds[3] + dy,
|
925
|
+
]
|
926
|
+
if self._paint_bounds_dirty or self._paint_bounds is None:
|
927
|
+
# Nothing we can do...
|
928
|
+
pass
|
929
|
+
else:
|
930
|
+
self._paint_bounds = [
|
931
|
+
self._paint_bounds[0] + dx,
|
932
|
+
self._paint_bounds[1] + dy,
|
933
|
+
self._paint_bounds[2] + dx,
|
934
|
+
self._paint_bounds[3] + dy,
|
935
|
+
]
|
936
|
+
# self.set_dirty()
|
937
|
+
# No need to translate it as we will apply the matrix later
|
938
|
+
# self.translate_functional_parameter(dx, dy)
|
939
|
+
|
940
|
+
# if self._points_dirty:
|
941
|
+
# self.revalidate_points()
|
942
|
+
# else:
|
943
|
+
# for pt in self._points:
|
944
|
+
# pt[0] += dx
|
945
|
+
# pt[1] += dy
|
946
|
+
self.notify_translated(self, dx=dx, dy=dy, interim=interim)
|
947
|
+
|
948
|
+
def scaled(self, sx, sy, ox, oy, interim=False):
|
949
|
+
"""
|
950
|
+
This is a special case of the modified call, we are scaling
|
951
|
+
the node without fundamentally altering its properties
|
952
|
+
"""
|
953
|
+
def apply_it(box):
|
954
|
+
x0, y0, x1, y1 = box
|
955
|
+
if sx != 1.0:
|
956
|
+
d1 = x0 - ox
|
957
|
+
d2 = x1 - ox
|
958
|
+
x0 = ox + sx * d1
|
959
|
+
x1 = ox + sx * d2
|
960
|
+
if sy != 1.0:
|
961
|
+
d1 = y0 - oy
|
962
|
+
d2 = y1 - oy
|
963
|
+
y0 = oy + sy * d1
|
964
|
+
y1 = oy + sy * d2
|
965
|
+
return min(x0, x1), min(y0, y1), max(x0, x1), max(y0, y1)
|
966
|
+
|
967
|
+
if self._bounds_dirty or self._bounds is None:
|
968
|
+
# A pity but we need proper data
|
969
|
+
self.modified()
|
970
|
+
return
|
971
|
+
self._bounds = apply_it(self._bounds)
|
972
|
+
# self.scale_functional_parameter(sx, sy, ox, oy)
|
973
|
+
# This may not really correct, we need the
|
974
|
+
# implied stroke_width to add, so the inherited
|
975
|
+
# element classes will need to overload it
|
976
|
+
if self._paint_bounds is not None:
|
977
|
+
self._paint_bounds = apply_it(self._paint_bounds)
|
978
|
+
self.set_dirty()
|
979
|
+
self.notify_scaled(self, sx=sx, sy=sy, ox=ox, oy=oy, interim=interim)
|
980
|
+
|
981
|
+
def empty_cache(self):
|
982
|
+
# Remove cached artifacts
|
983
|
+
try:
|
984
|
+
self._cache.UnGetNativePath(self._cache.NativePath)
|
985
|
+
except AttributeError:
|
986
|
+
pass
|
987
|
+
try:
|
988
|
+
del self._cache
|
989
|
+
del self._cache_matrix
|
990
|
+
except AttributeError:
|
991
|
+
pass
|
992
|
+
self._cache = None
|
993
|
+
|
994
|
+
def altered(self, *args, **kwargs):
|
995
|
+
"""
|
996
|
+
The data structure was changed. Any assumptions about what this object is/was are void.
|
997
|
+
"""
|
998
|
+
self.empty_cache()
|
999
|
+
self.invalidated()
|
1000
|
+
self.notify_altered(self)
|
1001
|
+
|
1002
|
+
def unregister_object(self):
|
1003
|
+
self.empty_cache()
|
1004
|
+
|
1005
|
+
def unregister(self):
|
1006
|
+
self.unregister_object()
|
1007
|
+
try:
|
1008
|
+
self.targeted = False
|
1009
|
+
self.emphasized = False
|
1010
|
+
self.highlighted = False
|
1011
|
+
except AttributeError:
|
1012
|
+
pass
|
1013
|
+
|
1014
|
+
def add_reference(self, node=None, pos=None, **kwargs):
|
1015
|
+
"""
|
1016
|
+
Add a new node bound to the data_object of the type to the current node.
|
1017
|
+
If the data_object itself is a node already it is merely attached.
|
1018
|
+
|
1019
|
+
@param node:
|
1020
|
+
@param pos:
|
1021
|
+
@return:
|
1022
|
+
"""
|
1023
|
+
if node is None:
|
1024
|
+
return
|
1025
|
+
if not self.valid_node_for_reference(node):
|
1026
|
+
# We could raise a ValueError but that will break things...
|
1027
|
+
return
|
1028
|
+
ref = self.add(node=node, type="reference", pos=pos, **kwargs)
|
1029
|
+
node._references.append(ref)
|
1030
|
+
|
1031
|
+
def add_node(self, node, pos=None):
|
1032
|
+
"""
|
1033
|
+
Attach an already created node to the tree.
|
1034
|
+
|
1035
|
+
Requires that this node be validated to avoid loops.
|
1036
|
+
|
1037
|
+
@param node:
|
1038
|
+
@param pos:
|
1039
|
+
@return:
|
1040
|
+
"""
|
1041
|
+
if node is None:
|
1042
|
+
# This should not happen and is a sign that something is amiss,
|
1043
|
+
# so we inform at least abount it
|
1044
|
+
print("Tried to add an invalid node...")
|
1045
|
+
return
|
1046
|
+
if node._parent is not None:
|
1047
|
+
raise ValueError("Cannot reparent node on add.")
|
1048
|
+
node._parent = self
|
1049
|
+
node.set_root(self._root)
|
1050
|
+
if pos is None:
|
1051
|
+
self._children.append(node)
|
1052
|
+
else:
|
1053
|
+
self._children.insert(pos, node)
|
1054
|
+
node.notify_attached(node, parent=self, pos=pos)
|
1055
|
+
return node
|
1056
|
+
|
1057
|
+
def create(self, type, **kwargs):
|
1058
|
+
"""
|
1059
|
+
Create node of type with attributes via node bootstrapping. Apply node defaults to values with defaults.
|
1060
|
+
|
1061
|
+
@param type:
|
1062
|
+
@param kwargs:
|
1063
|
+
@return:
|
1064
|
+
"""
|
1065
|
+
from .bootstrap import bootstrap, defaults
|
1066
|
+
|
1067
|
+
node_class = bootstrap.get(type, None)
|
1068
|
+
if node_class is None:
|
1069
|
+
raise ValueError("Attempted to create unbootstrapped node")
|
1070
|
+
node_defaults = defaults.get(type, {})
|
1071
|
+
nd = dict(node_defaults)
|
1072
|
+
nd.update(kwargs)
|
1073
|
+
node = node_class(**nd)
|
1074
|
+
if self._root is not None:
|
1075
|
+
self._root.notify_created(node)
|
1076
|
+
return node
|
1077
|
+
|
1078
|
+
def add(self, type=None, pos=None, **kwargs):
|
1079
|
+
"""
|
1080
|
+
Add a new node bound to the data_object of the type to the current node.
|
1081
|
+
If the data_object itself is a node already it is merely attached.
|
1082
|
+
|
1083
|
+
@param type: Node type to be bootstrapped
|
1084
|
+
@param pos: Position within current node to add this node
|
1085
|
+
@return:
|
1086
|
+
"""
|
1087
|
+
node = self.create(type=type, **kwargs)
|
1088
|
+
if node is not None:
|
1089
|
+
self.add_node(node, pos=pos)
|
1090
|
+
else:
|
1091
|
+
print(f"Did not produce a valid node for type '{type}'")
|
1092
|
+
return node
|
1093
|
+
|
1094
|
+
def set_root(self, root):
|
1095
|
+
"""
|
1096
|
+
Set the root for this and all descendant to the provided root
|
1097
|
+
|
1098
|
+
@param root:
|
1099
|
+
@return:
|
1100
|
+
"""
|
1101
|
+
self._root = root
|
1102
|
+
for c in self._children:
|
1103
|
+
c.set_root(root)
|
1104
|
+
|
1105
|
+
def _flatten(self, node):
|
1106
|
+
"""
|
1107
|
+
Yield this node and all descendants in a flat generation.
|
1108
|
+
|
1109
|
+
@param node: starting node
|
1110
|
+
@return:
|
1111
|
+
"""
|
1112
|
+
yield node
|
1113
|
+
yield from self._flatten_children(node)
|
1114
|
+
|
1115
|
+
def _flatten_children(self, node):
|
1116
|
+
"""
|
1117
|
+
Yield all descendants in a flat generation.
|
1118
|
+
|
1119
|
+
@param node: starting node
|
1120
|
+
@return:
|
1121
|
+
"""
|
1122
|
+
for child in node.children:
|
1123
|
+
yield child
|
1124
|
+
yield from self._flatten_children(child)
|
1125
|
+
|
1126
|
+
def flat(
|
1127
|
+
self,
|
1128
|
+
types=None,
|
1129
|
+
cascade=True,
|
1130
|
+
depth=None,
|
1131
|
+
selected=None,
|
1132
|
+
emphasized=None,
|
1133
|
+
targeted=None,
|
1134
|
+
highlighted=None,
|
1135
|
+
lock=None,
|
1136
|
+
):
|
1137
|
+
"""
|
1138
|
+
Returned flat list of matching nodes. If cascade is set then any matching group will give all the descendants
|
1139
|
+
of the given type, even if those descendants are beyond the depth limit. The sub-elements do not need to match
|
1140
|
+
the criteria with respect to either the depth or the emphases.
|
1141
|
+
|
1142
|
+
@param types: types of nodes permitted to be returned
|
1143
|
+
@param cascade: cascade all subitems if a group matches the criteria.
|
1144
|
+
@param depth: depth to search within the tree.
|
1145
|
+
@param selected: match only selected nodes
|
1146
|
+
@param emphasized: match only emphasized nodes.
|
1147
|
+
@param targeted: match only targeted nodes
|
1148
|
+
@param highlighted: match only highlighted nodes
|
1149
|
+
@param lock: match locked nodes
|
1150
|
+
@return:
|
1151
|
+
"""
|
1152
|
+
node = self
|
1153
|
+
if (
|
1154
|
+
(targeted is None or targeted == node.targeted)
|
1155
|
+
and (emphasized is None or emphasized == node.emphasized)
|
1156
|
+
and (selected is None or selected == node.selected)
|
1157
|
+
and (highlighted is None or highlighted == node.highlighted)
|
1158
|
+
and (lock is None or lock == node.lock)
|
1159
|
+
):
|
1160
|
+
# Matches the emphases.
|
1161
|
+
if cascade:
|
1162
|
+
# Give every type-matched descendant.
|
1163
|
+
for c in self._flatten(node):
|
1164
|
+
if types is None or c.type in types:
|
1165
|
+
yield c
|
1166
|
+
# Do not recurse further. This node is end node.
|
1167
|
+
return
|
1168
|
+
else:
|
1169
|
+
if types is None or node.type in types:
|
1170
|
+
yield node
|
1171
|
+
if depth is not None:
|
1172
|
+
if depth <= 0:
|
1173
|
+
# Depth limit reached. Do not evaluate children.
|
1174
|
+
return
|
1175
|
+
depth -= 1
|
1176
|
+
# Check all children.
|
1177
|
+
for c in node.children:
|
1178
|
+
yield from c.flat(
|
1179
|
+
types, cascade, depth, selected, emphasized, targeted, highlighted, lock
|
1180
|
+
)
|
1181
|
+
|
1182
|
+
def count_children(self):
|
1183
|
+
return len(self._children)
|
1184
|
+
|
1185
|
+
def append_child(self, new_child):
|
1186
|
+
"""
|
1187
|
+
Moves the new_child node as the last child of the current node.
|
1188
|
+
If the node exists elsewhere in the tree it will be removed from that location.
|
1189
|
+
|
1190
|
+
"""
|
1191
|
+
if new_child is None:
|
1192
|
+
return
|
1193
|
+
new_parent = self
|
1194
|
+
belonged_to_me = bool(new_child.parent is self)
|
1195
|
+
if new_child.parent is not None:
|
1196
|
+
source_siblings = new_child.parent.children
|
1197
|
+
if belonged_to_me and source_siblings.index(new_child) == 0:
|
1198
|
+
# The very first will be moved to the end
|
1199
|
+
belonged_to_me = False
|
1200
|
+
source_siblings.remove(new_child) # Remove child
|
1201
|
+
destination_siblings = new_parent.children
|
1202
|
+
|
1203
|
+
new_child.notify_detached(new_child)
|
1204
|
+
|
1205
|
+
if belonged_to_me:
|
1206
|
+
destination_siblings.insert(0, new_child)
|
1207
|
+
new_child._parent = new_parent
|
1208
|
+
new_child.notify_attached(new_child, pos=0)
|
1209
|
+
else:
|
1210
|
+
destination_siblings.append(new_child) # Add child.
|
1211
|
+
new_child._parent = new_parent
|
1212
|
+
new_child.notify_attached(new_child)
|
1213
|
+
|
1214
|
+
def insert_sibling(self, new_sibling, below=True):
|
1215
|
+
"""
|
1216
|
+
Add the new_sibling node next to the current node.
|
1217
|
+
If the node exists elsewhere in the tree it will be removed from that location.
|
1218
|
+
"""
|
1219
|
+
reference_sibling = self
|
1220
|
+
source_siblings = None if new_sibling.parent is None else new_sibling.parent.children
|
1221
|
+
destination_siblings = reference_sibling.parent.children
|
1222
|
+
|
1223
|
+
if source_siblings:
|
1224
|
+
source_siblings.remove(new_sibling)
|
1225
|
+
try:
|
1226
|
+
reference_position = destination_siblings.index(reference_sibling)
|
1227
|
+
if below:
|
1228
|
+
reference_position += 1
|
1229
|
+
except ValueError:
|
1230
|
+
# Not in list, we could have just removed it...
|
1231
|
+
reference_position = 0
|
1232
|
+
|
1233
|
+
new_sibling.notify_detached(new_sibling)
|
1234
|
+
destination_siblings.insert(reference_position, new_sibling)
|
1235
|
+
new_sibling._parent = reference_sibling._parent
|
1236
|
+
new_sibling.notify_attached(new_sibling, pos=reference_position)
|
1237
|
+
|
1238
|
+
def replace_node(self, keep_children=None, *args, **kwargs):
|
1239
|
+
"""
|
1240
|
+
Replace this current node with a bootstrapped replacement node.
|
1241
|
+
"""
|
1242
|
+
if keep_children is None:
|
1243
|
+
keep_children = False
|
1244
|
+
parent = self._parent
|
1245
|
+
index = parent._children.index(self)
|
1246
|
+
parent._children.remove(self)
|
1247
|
+
self.notify_detached(self)
|
1248
|
+
node = parent.add(*args, **kwargs, pos=index)
|
1249
|
+
self.notify_destroyed()
|
1250
|
+
for ref in list(self._references):
|
1251
|
+
ref.remove_node()
|
1252
|
+
if keep_children:
|
1253
|
+
for ref in list(self._children):
|
1254
|
+
node._children.append(ref)
|
1255
|
+
ref._parent = node
|
1256
|
+
# Don't call attach / detach, as the tree
|
1257
|
+
# doesn't know about the new node yet...
|
1258
|
+
self._item = None
|
1259
|
+
self._parent = None
|
1260
|
+
self._root = None
|
1261
|
+
self.unregister()
|
1262
|
+
return node
|
1263
|
+
|
1264
|
+
def swap_node(self, node):
|
1265
|
+
"""
|
1266
|
+
Swap nodes swaps the current node with the provided node in the other position in the same tree. All children
|
1267
|
+
during a swap are kept in place structurally. This permits swapping nodes between two positions that may be
|
1268
|
+
nested, without creating a loop.
|
1269
|
+
|
1270
|
+
Special care is taken for both swaps being children of the same parent.
|
1271
|
+
|
1272
|
+
@param node: Node already in the tree that should be swapped with the current node.
|
1273
|
+
@return:
|
1274
|
+
"""
|
1275
|
+
# Remove self from tree.
|
1276
|
+
parent = self._parent
|
1277
|
+
n_parent = node._parent
|
1278
|
+
|
1279
|
+
index = parent._children.index(self)
|
1280
|
+
n_index = n_parent._children.index(node)
|
1281
|
+
|
1282
|
+
if index < n_index:
|
1283
|
+
# N_index is greater.
|
1284
|
+
del n_parent._children[n_index]
|
1285
|
+
del parent._children[index]
|
1286
|
+
|
1287
|
+
parent._children.insert(index, node)
|
1288
|
+
n_parent._children.insert(n_index, self)
|
1289
|
+
else:
|
1290
|
+
# N_index is lesser, equal
|
1291
|
+
del parent._children[index]
|
1292
|
+
del n_parent._children[n_index]
|
1293
|
+
|
1294
|
+
n_parent._children.insert(n_index, self)
|
1295
|
+
parent._children.insert(index, node)
|
1296
|
+
|
1297
|
+
node._parent = parent
|
1298
|
+
self._parent = n_parent
|
1299
|
+
|
1300
|
+
# Make a copy of children
|
1301
|
+
n_children = list(node._children)
|
1302
|
+
children = list(self._children)
|
1303
|
+
|
1304
|
+
# Delete children.
|
1305
|
+
node._children.clear()
|
1306
|
+
self._children.clear()
|
1307
|
+
|
1308
|
+
# Move children without call attach / detach.
|
1309
|
+
node._children.extend(children)
|
1310
|
+
self._children.extend(n_children)
|
1311
|
+
|
1312
|
+
# Correct parent for all children.
|
1313
|
+
for n in list(n_children):
|
1314
|
+
n._parent = self
|
1315
|
+
for n in list(children):
|
1316
|
+
n._parent = node
|
1317
|
+
|
1318
|
+
# self._root._validate_tree()
|
1319
|
+
self._root.notify_reorder()
|
1320
|
+
|
1321
|
+
def remove_node(self, children=True, references=True, fast=False, destroy=True):
|
1322
|
+
"""
|
1323
|
+
Remove the current node from the tree.
|
1324
|
+
|
1325
|
+
@param children: removes all the children of this node.
|
1326
|
+
@param references: remove the references to this node.
|
1327
|
+
@param fast: Do not send notifications of the detatches and destroys
|
1328
|
+
@param destroy: Do not destroy the node.
|
1329
|
+
@return:
|
1330
|
+
"""
|
1331
|
+
if children:
|
1332
|
+
self.remove_all_children(fast=fast)
|
1333
|
+
if self._parent:
|
1334
|
+
self._parent._children.remove(self)
|
1335
|
+
self._parent.set_dirty_bounds()
|
1336
|
+
if not fast:
|
1337
|
+
self.notify_detached(self)
|
1338
|
+
if destroy:
|
1339
|
+
self.notify_destroyed(self)
|
1340
|
+
if references:
|
1341
|
+
for ref in list(self._references):
|
1342
|
+
ref.remove_node(fast=fast)
|
1343
|
+
self._item = None
|
1344
|
+
self._parent = None
|
1345
|
+
self._root = None
|
1346
|
+
self.unregister()
|
1347
|
+
|
1348
|
+
def remove_all_children(self, fast=False, destroy=True):
|
1349
|
+
"""
|
1350
|
+
Recursively removes all children of the current node.
|
1351
|
+
"""
|
1352
|
+
for child in list(self.children):
|
1353
|
+
child.remove_all_children(fast=fast, destroy=destroy)
|
1354
|
+
child.remove_node(fast=fast, destroy=destroy)
|
1355
|
+
|
1356
|
+
def has_ancestor(self, type):
|
1357
|
+
"""
|
1358
|
+
Return whether this node has an ancestor node that matches the given type, or matches the major type.
|
1359
|
+
|
1360
|
+
@param type:
|
1361
|
+
@return:
|
1362
|
+
"""
|
1363
|
+
if self.parent is None:
|
1364
|
+
return False
|
1365
|
+
|
1366
|
+
if self.parent.type == type:
|
1367
|
+
return True
|
1368
|
+
|
1369
|
+
if " " not in type:
|
1370
|
+
if self.parent.type.startswith(type):
|
1371
|
+
return True
|
1372
|
+
|
1373
|
+
return self.parent.has_ancestor(type=type)
|
1374
|
+
|
1375
|
+
def get(self, type=None):
|
1376
|
+
"""
|
1377
|
+
Recursive call for get to find first sub-nodes with the given type.
|
1378
|
+
@param type:
|
1379
|
+
@return:
|
1380
|
+
"""
|
1381
|
+
if type is None or type == self.type:
|
1382
|
+
return self
|
1383
|
+
for n in self._children:
|
1384
|
+
node = n.get(type)
|
1385
|
+
if node is not None:
|
1386
|
+
return node
|
1387
|
+
return None
|
1388
|
+
|
1389
|
+
def move(self, dest, pos=None):
|
1390
|
+
self._parent.remove(self)
|
1391
|
+
dest.insert_node(self, pos=pos)
|
1392
|
+
|
1393
|
+
@staticmethod
|
1394
|
+
def union_bounds(nodes, bounds=None, attr="bounds", ignore_locked=True, ignore_hidden=False):
|
1395
|
+
"""
|
1396
|
+
Returns the union of the node list given, optionally unioned the given bounds value
|
1397
|
+
|
1398
|
+
@return: union of all bounds within the iterable.
|
1399
|
+
"""
|
1400
|
+
if bounds is None:
|
1401
|
+
xmin = float("inf")
|
1402
|
+
ymin = float("inf")
|
1403
|
+
xmax = -xmin
|
1404
|
+
ymax = -ymin
|
1405
|
+
else:
|
1406
|
+
xmin, ymin, xmax, ymax = bounds
|
1407
|
+
for e in nodes:
|
1408
|
+
if ignore_locked and e.lock:
|
1409
|
+
continue
|
1410
|
+
if ignore_hidden and getattr(e, "hidden", False):
|
1411
|
+
continue
|
1412
|
+
box = getattr(e, attr, None)
|
1413
|
+
if box is None:
|
1414
|
+
continue
|
1415
|
+
if box[0] < xmin:
|
1416
|
+
xmin = box[0]
|
1417
|
+
if box[2] > xmax:
|
1418
|
+
xmax = box[2]
|
1419
|
+
if box[1] < ymin:
|
1420
|
+
ymin = box[1]
|
1421
|
+
if box[3] > ymax:
|
1422
|
+
ymax = box[3]
|
1423
|
+
return xmin, ymin, xmax, ymax
|
1424
|
+
|
1425
|
+
@property
|
1426
|
+
def name(self):
|
1427
|
+
return self.__str__()
|