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/wxmeerk40t.py
CHANGED
@@ -1,1169 +1,1444 @@
|
|
1
|
-
import os
|
2
|
-
import platform
|
3
|
-
import sys
|
4
|
-
import traceback
|
5
|
-
from datetime import datetime
|
6
|
-
|
7
|
-
import wx
|
8
|
-
from wx import aui
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
|
19
|
-
from
|
20
|
-
|
21
|
-
|
22
|
-
from meerk40t.
|
23
|
-
from meerk40t.
|
24
|
-
|
25
|
-
from
|
26
|
-
from
|
27
|
-
|
28
|
-
from
|
29
|
-
from .
|
30
|
-
from .
|
31
|
-
from .
|
32
|
-
from .
|
33
|
-
from .
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
from .
|
49
|
-
from .
|
50
|
-
from .
|
51
|
-
from .
|
52
|
-
from .
|
53
|
-
from .
|
54
|
-
from .
|
55
|
-
from .
|
56
|
-
from .propertypanels.
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
from .propertypanels.
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
from .propertypanels.
|
68
|
-
from .propertypanels.
|
69
|
-
from .propertypanels.
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
from .
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
"""
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
self.
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
self.
|
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
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
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
|
-
self.
|
228
|
-
|
229
|
-
|
230
|
-
self.
|
231
|
-
self.
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
.
|
242
|
-
|
243
|
-
.
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
context(
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
.
|
262
|
-
|
263
|
-
|
264
|
-
.
|
265
|
-
.
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
pane
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
context
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
)
|
283
|
-
pane.control = panel
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
.
|
299
|
-
.
|
300
|
-
.
|
301
|
-
.
|
302
|
-
.
|
303
|
-
|
304
|
-
|
305
|
-
)
|
306
|
-
pane.
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
)
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
def
|
330
|
-
context("
|
331
|
-
|
332
|
-
pane = (
|
333
|
-
aui.AuiPaneInfo()
|
334
|
-
.
|
335
|
-
.
|
336
|
-
.MinSize(40, 40)
|
337
|
-
.FloatingSize(98, 98)
|
338
|
-
.Name("
|
339
|
-
.Hide()
|
340
|
-
.CaptionVisible(not context.pane_lock)
|
341
|
-
)
|
342
|
-
pane.submenu = "_10_" + _("Laser")
|
343
|
-
pane.
|
344
|
-
|
345
|
-
|
346
|
-
fgcol = None
|
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
|
-
|
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
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
self.
|
430
|
-
|
431
|
-
#
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
self.
|
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
|
-
import
|
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
|
-
if
|
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
|
-
if
|
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
|
-
kernel.
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
kernel.
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
kernel.
|
814
|
-
kernel.
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
kernel.
|
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
|
-
from meerk40t.gui.
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
kernel.register("
|
895
|
-
kernel.register("
|
896
|
-
kernel.register("
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
kernel.register("
|
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
|
-
|
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
|
-
|
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
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
)
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
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
|
-
|
1
|
+
import os
|
2
|
+
import platform
|
3
|
+
import sys
|
4
|
+
import traceback
|
5
|
+
from datetime import datetime
|
6
|
+
|
7
|
+
import wx
|
8
|
+
from wx import aui
|
9
|
+
|
10
|
+
from meerk40t.gui.consolepanel import Console
|
11
|
+
from meerk40t.gui.navigationpanels import Navigation
|
12
|
+
from meerk40t.gui.spoolerpanel import JobSpooler
|
13
|
+
|
14
|
+
# try:
|
15
|
+
# # According to https://docs.wxpython.org/wx.richtext.1moduleindex.html
|
16
|
+
# # richtext needs to be imported before wx.App i.e. wxMeerK40t is instantiated
|
17
|
+
# # so, we are doing it here even though we do not refer to it in this file
|
18
|
+
# # richtext is used for the Console panel.
|
19
|
+
# from wx import richtext
|
20
|
+
# except ImportError:
|
21
|
+
# pass
|
22
|
+
from meerk40t.gui.themes import Themes
|
23
|
+
from meerk40t.gui.wxmscene import SceneWindow
|
24
|
+
from meerk40t.gui.wxutils import TextCtrl, wxButton, wxStaticText
|
25
|
+
from meerk40t.kernel import CommandSyntaxError, Module, get_safe_path
|
26
|
+
from meerk40t.kernel.kernel import Job
|
27
|
+
|
28
|
+
from ..main import APPLICATION_NAME, APPLICATION_VERSION
|
29
|
+
from ..tools.kerftest import KerfTool
|
30
|
+
from ..tools.livinghinges import LivingHingeTool
|
31
|
+
from .about import About
|
32
|
+
from .alignment import Alignment
|
33
|
+
from .autoexec import AutoExec
|
34
|
+
from .bufferview import BufferView
|
35
|
+
from .devicepanel import DeviceManager
|
36
|
+
from .executejob import ExecuteJob
|
37
|
+
from .hersheymanager import (
|
38
|
+
HersheyFontManager,
|
39
|
+
HersheyFontSelector,
|
40
|
+
register_hershey_stuff,
|
41
|
+
)
|
42
|
+
from .icons import (
|
43
|
+
icons8_emergency_stop_button,
|
44
|
+
icons8_gas_industry,
|
45
|
+
icons8_home_filled,
|
46
|
+
icons8_pause,
|
47
|
+
)
|
48
|
+
from .imagesplitter import RenderSplit
|
49
|
+
from .keymap import Keymap
|
50
|
+
from .lasertoolpanel import LaserTool
|
51
|
+
from .materialmanager import MaterialManager
|
52
|
+
from .materialtest import TemplateTool
|
53
|
+
from .notes import Notes
|
54
|
+
from .operation_info import OperationInformation
|
55
|
+
from .preferences import Preferences
|
56
|
+
from .propertypanels.blobproperty import BlobPropertyPanel
|
57
|
+
from .propertypanels.consoleproperty import ConsolePropertiesPanel
|
58
|
+
from .propertypanels.gotoproperty import GotoPropertyPanel
|
59
|
+
from .propertypanels.groupproperties import FilePropertiesPanel, GroupPropertiesPanel
|
60
|
+
from .propertypanels.hatchproperty import HatchPropertyPanel
|
61
|
+
from .propertypanels.imageproperty import (
|
62
|
+
ContourPanel,
|
63
|
+
ImageModificationPanel,
|
64
|
+
ImagePropertyPanel,
|
65
|
+
ImageVectorisationPanel,
|
66
|
+
)
|
67
|
+
from .propertypanels.inputproperty import InputPropertyPanel
|
68
|
+
from .propertypanels.opbranchproperties import OpBranchPanel
|
69
|
+
from .propertypanels.operationpropertymain import ParameterPanel
|
70
|
+
from .propertypanels.outputproperty import OutputPropertyPanel
|
71
|
+
from .propertypanels.pathproperty import PathPropertyPanel
|
72
|
+
from .propertypanels.placementproperty import PlacementParameterPanel
|
73
|
+
from .propertypanels.pointproperty import PointPropertyPanel
|
74
|
+
from .propertypanels.propertywindow import PropertyWindow
|
75
|
+
from .propertypanels.rasterwizardpanels import (
|
76
|
+
AutoContrastPanel,
|
77
|
+
ContrastPanel,
|
78
|
+
EdgePanel,
|
79
|
+
GammaPanel,
|
80
|
+
HalftonePanel,
|
81
|
+
SharpenPanel,
|
82
|
+
ToneCurvePanel,
|
83
|
+
)
|
84
|
+
from .propertypanels.regbranchproperties import RegBranchPanel
|
85
|
+
from .propertypanels.textproperty import TextPropertyPanel
|
86
|
+
from .propertypanels.waitproperty import WaitPropertyPanel
|
87
|
+
from .propertypanels.warpproperty import WarpPropertyPanel
|
88
|
+
from .propertypanels.wobbleproperty import WobblePropertyPanel
|
89
|
+
from .simpleui import SimpleUI
|
90
|
+
from .simulation import Simulation
|
91
|
+
from .tips import Tips
|
92
|
+
from .functionwrapper import ConsoleCommandUI
|
93
|
+
from .wordlisteditor import WordlistEditor
|
94
|
+
from .wxmmain import MeerK40t
|
95
|
+
|
96
|
+
"""
|
97
|
+
Laser software for the Stock-LIHUIYU laserboard.
|
98
|
+
|
99
|
+
MeerK40t (pronounced MeerKat) is a built-from-the-ground-up MIT licensed
|
100
|
+
open-source laser cutting software. See https://github.com/meerk40t/meerk40t
|
101
|
+
for full details.
|
102
|
+
|
103
|
+
wxMeerK40t is the primary gui addon for MeerK40t. It requires wxPython for the interface.
|
104
|
+
The Transformations work in Windows/OSX/Linux for wxPython 4.0+ (and likely before)
|
105
|
+
|
106
|
+
"""
|
107
|
+
|
108
|
+
_ = wx.GetTranslation
|
109
|
+
|
110
|
+
class ActionPanel(wx.Panel):
|
111
|
+
def __init__(
|
112
|
+
self,
|
113
|
+
*args,
|
114
|
+
context=None,
|
115
|
+
action=None,
|
116
|
+
action_right=None,
|
117
|
+
fgcolor=None,
|
118
|
+
bgcolor=None,
|
119
|
+
icon=None,
|
120
|
+
tooltip="",
|
121
|
+
**kwds,
|
122
|
+
):
|
123
|
+
kwds["style"] = kwds.get("style", 0)
|
124
|
+
wx.Panel.__init__(self, *args, **kwds)
|
125
|
+
|
126
|
+
self.context = context
|
127
|
+
self.context.themes.set_window_colors(self)
|
128
|
+
self.button_go = wxButton(self, wx.ID_ANY)
|
129
|
+
self.icon = icon
|
130
|
+
self.fgcolor = fgcolor
|
131
|
+
self.resize_job = Job(
|
132
|
+
process=self.resize_button,
|
133
|
+
job_name=f"_resize_actionpanel_{self.Id}",
|
134
|
+
interval=0.1,
|
135
|
+
times=1,
|
136
|
+
run_main=True,
|
137
|
+
)
|
138
|
+
if bgcolor is not None:
|
139
|
+
self.button_go.SetBackgroundColour(bgcolor)
|
140
|
+
self.button_go.SetToolTip(tooltip)
|
141
|
+
# self.button_go.SetBitmapMargins(0, 0)
|
142
|
+
self.action = action
|
143
|
+
self.action_right = action_right
|
144
|
+
|
145
|
+
main_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
146
|
+
main_sizer.Add(self.button_go, 1, wx.EXPAND, 0)
|
147
|
+
self.SetSizer(main_sizer)
|
148
|
+
main_sizer.Fit(self)
|
149
|
+
self.button_go.Bind(wx.EVT_BUTTON, self.on_button_go_click)
|
150
|
+
if self.action_right is not None:
|
151
|
+
self.button_go.Bind(wx.EVT_RIGHT_DOWN, self.on_button_go_click_right)
|
152
|
+
|
153
|
+
self.button_go.Bind(wx.EVT_SIZE, self.on_button_resize)
|
154
|
+
# Initial resize
|
155
|
+
self.resize_button()
|
156
|
+
|
157
|
+
def on_button_go_click(self, event):
|
158
|
+
if self.action is not None:
|
159
|
+
self.action()
|
160
|
+
|
161
|
+
def on_button_go_click_right(self, event):
|
162
|
+
if self.action_right is not None:
|
163
|
+
self.action_right()
|
164
|
+
|
165
|
+
def resize_button(self):
|
166
|
+
# The job might be called when the window is already destroyed
|
167
|
+
if self.context.kernel.is_shutdown:
|
168
|
+
return
|
169
|
+
try:
|
170
|
+
size = self.button_go.Size
|
171
|
+
except RuntimeError:
|
172
|
+
return
|
173
|
+
minsize = min(size[0], size[1])
|
174
|
+
# Leave some room at the edges,
|
175
|
+
# for every 25 pixel 1 pixel at each side
|
176
|
+
room = int(minsize / 25) * 2
|
177
|
+
best_size = minsize - room
|
178
|
+
# At least 20 px high
|
179
|
+
best_size = max(best_size, 20)
|
180
|
+
border = 2
|
181
|
+
bmp = self.icon.GetBitmap(color=self.fgcolor, resize=best_size, buffer=border)
|
182
|
+
s = bmp.Size
|
183
|
+
self.button_go.SetBitmap(bmp)
|
184
|
+
bmp = self.icon.GetBitmap(resize=best_size, buffer=border)
|
185
|
+
self.button_go.SetBitmapFocus(bmp)
|
186
|
+
|
187
|
+
t = self.button_go.GetBitmap().Size
|
188
|
+
# print(f"Was asking for {best_size}x{best_size}, got {s[0]}x{s[1]}, button has {t[0]}x{t[1]}")
|
189
|
+
scale_x = s[0] / t[0]
|
190
|
+
scale_y = s[1] / t[1]
|
191
|
+
if abs(1 - scale_x) > 1e-2 or abs(1 - scale_y) > 1e-2:
|
192
|
+
# print(f"Scale factors: {scale_x:.2f}, {scale_y:.2f}")
|
193
|
+
# This is a bug within wxPython! It seems to appear only here at very high scale factors under windows
|
194
|
+
bmp = self.icon.GetBitmap(
|
195
|
+
color=self.fgcolor,
|
196
|
+
resize=(best_size * scale_x, best_size * scale_y),
|
197
|
+
buffer=border,
|
198
|
+
)
|
199
|
+
self.button_go.SetBitmap(bmp)
|
200
|
+
bmp = self.icon.GetBitmap(
|
201
|
+
resize=(best_size * scale_x, best_size * scale_y), buffer=border
|
202
|
+
)
|
203
|
+
self.button_go.SetBitmapFocus(bmp)
|
204
|
+
|
205
|
+
def on_button_resize(self, event):
|
206
|
+
event.Skip()
|
207
|
+
self.context.schedule(self.resize_job)
|
208
|
+
|
209
|
+
|
210
|
+
class GoPanel(ActionPanel):
|
211
|
+
def __init__(self, *args, context=None, **kwds):
|
212
|
+
# begin wxGlade: PassesPanel.__init__
|
213
|
+
kwds["style"] = kwds.get("style", 0)
|
214
|
+
fgcol = context.themes.get("start_fg")
|
215
|
+
bgcol = context.themes.get("start_bg")
|
216
|
+
ActionPanel.__init__(
|
217
|
+
self,
|
218
|
+
context=context,
|
219
|
+
action=None,
|
220
|
+
fgcolor=fgcol,
|
221
|
+
bgcolor=bgcol,
|
222
|
+
icon=icons8_gas_industry,
|
223
|
+
tooltip=_("One Touch: Send Job To Laser "),
|
224
|
+
*args,
|
225
|
+
**kwds,
|
226
|
+
)
|
227
|
+
self.context.themes.set_window_colors(self)
|
228
|
+
self.click_time = 0
|
229
|
+
self.was_mouse = False
|
230
|
+
self.button_go.Bind(wx.EVT_BUTTON, self.on_button_go_click)
|
231
|
+
self.button_go.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_down)
|
232
|
+
|
233
|
+
def on_mouse_down(self, event):
|
234
|
+
self.was_mouse = True
|
235
|
+
event.Skip()
|
236
|
+
|
237
|
+
def on_button_go_click(self, event):
|
238
|
+
from time import perf_counter
|
239
|
+
|
240
|
+
this_time = perf_counter()
|
241
|
+
if this_time - self.click_time < 0.5:
|
242
|
+
return
|
243
|
+
if not self.was_mouse:
|
244
|
+
channel = self.context.kernel.channel("console")
|
245
|
+
channel(
|
246
|
+
_(
|
247
|
+
"We intentionally ignored a request to start a job via the keyboard.\n"
|
248
|
+
+ "You need to make your intent clear by a deliberate mouse-click"
|
249
|
+
)
|
250
|
+
)
|
251
|
+
return
|
252
|
+
if not self.button_go.Enabled:
|
253
|
+
return
|
254
|
+
|
255
|
+
self.button_go.Enable(False)
|
256
|
+
self.context.kernel.busyinfo.start(msg=_("Processing and sending..."))
|
257
|
+
self.context(
|
258
|
+
"planz clear copy preprocess validate blob preopt optimize spool\n"
|
259
|
+
)
|
260
|
+
self.context.kernel.busyinfo.end()
|
261
|
+
self.button_go.Enable(True)
|
262
|
+
# Reset...
|
263
|
+
# Deliberately at the end, as clicks queue...
|
264
|
+
self.click_time = perf_counter()
|
265
|
+
self.was_mouse = False
|
266
|
+
|
267
|
+
|
268
|
+
def register_panel_go(window, context):
|
269
|
+
pane = (
|
270
|
+
aui.AuiPaneInfo()
|
271
|
+
.Bottom()
|
272
|
+
.Caption(_("Go"))
|
273
|
+
.MinSize(40, 40)
|
274
|
+
.FloatingSize(98, 98)
|
275
|
+
.Name("go")
|
276
|
+
.CaptionVisible(not context.pane_lock)
|
277
|
+
.Hide()
|
278
|
+
)
|
279
|
+
pane.submenu = "_10_" + _("Laser")
|
280
|
+
pane.helptext = _("Display a laser start button")
|
281
|
+
pane.dock_proportion = 98
|
282
|
+
panel = GoPanel(window, wx.ID_ANY, context=context)
|
283
|
+
pane.control = panel
|
284
|
+
|
285
|
+
window.on_pane_create(pane)
|
286
|
+
context.register("pane/go", pane)
|
287
|
+
|
288
|
+
|
289
|
+
def register_panel_stop(window, context):
|
290
|
+
# Define Stop.
|
291
|
+
def action():
|
292
|
+
context("estop\n")
|
293
|
+
|
294
|
+
pane = (
|
295
|
+
aui.AuiPaneInfo()
|
296
|
+
.Bottom()
|
297
|
+
.Caption(_("Stop"))
|
298
|
+
.MinSize(40, 40)
|
299
|
+
.FloatingSize(98, 98)
|
300
|
+
.Name("stop")
|
301
|
+
.Hide()
|
302
|
+
.CaptionVisible(not context.pane_lock)
|
303
|
+
)
|
304
|
+
pane.submenu = "_10_" + _("Laser")
|
305
|
+
pane.helptext = _("Display a job abort button")
|
306
|
+
pane.dock_proportion = 98
|
307
|
+
fgcol = context.themes.get("stop_fg")
|
308
|
+
bgcol = context.themes.get("stop_bg")
|
309
|
+
panel = ActionPanel(
|
310
|
+
window,
|
311
|
+
wx.ID_ANY,
|
312
|
+
context=context,
|
313
|
+
action=action,
|
314
|
+
fgcolor=fgcol,
|
315
|
+
bgcolor=bgcol,
|
316
|
+
icon=icons8_emergency_stop_button,
|
317
|
+
tooltip=_("Emergency stop/reset the controller."),
|
318
|
+
)
|
319
|
+
pane.control = panel
|
320
|
+
window.on_pane_create(pane)
|
321
|
+
context.register("pane/stop", pane)
|
322
|
+
|
323
|
+
|
324
|
+
def register_panel_home(window, context):
|
325
|
+
# Define Home.
|
326
|
+
def action():
|
327
|
+
context("home\n")
|
328
|
+
|
329
|
+
def action_right():
|
330
|
+
context("physical_home\n")
|
331
|
+
|
332
|
+
pane = (
|
333
|
+
aui.AuiPaneInfo()
|
334
|
+
.Bottom()
|
335
|
+
.Caption(_("Home"))
|
336
|
+
.MinSize(40, 40)
|
337
|
+
.FloatingSize(98, 98)
|
338
|
+
.Name("home")
|
339
|
+
.Hide()
|
340
|
+
.CaptionVisible(not context.pane_lock)
|
341
|
+
)
|
342
|
+
pane.submenu = "_10_" + _("Laser")
|
343
|
+
pane.helptext = _("Display a laser homing button")
|
344
|
+
pane.dock_proportion = 98
|
345
|
+
|
346
|
+
fgcol = None
|
347
|
+
bgcol = None
|
348
|
+
panel = ActionPanel(
|
349
|
+
window,
|
350
|
+
wx.ID_ANY,
|
351
|
+
context=context,
|
352
|
+
action=action,
|
353
|
+
action_right=action_right,
|
354
|
+
fgcolor=fgcol,
|
355
|
+
bgcolor=bgcol,
|
356
|
+
icon=icons8_home_filled,
|
357
|
+
tooltip=_("Send laser to home position"),
|
358
|
+
)
|
359
|
+
pane.control = panel
|
360
|
+
window.on_pane_create(pane)
|
361
|
+
context.register("pane/home", pane)
|
362
|
+
|
363
|
+
|
364
|
+
def register_panel_pause(window, context):
|
365
|
+
# Define Pause.
|
366
|
+
def action():
|
367
|
+
context("pause\n")
|
368
|
+
|
369
|
+
pane = (
|
370
|
+
aui.AuiPaneInfo()
|
371
|
+
.Caption(_("Pause"))
|
372
|
+
.Bottom()
|
373
|
+
.MinSize(40, 40)
|
374
|
+
.FloatingSize(98, 98)
|
375
|
+
.Name("pause")
|
376
|
+
.Hide()
|
377
|
+
.CaptionVisible(not context.pane_lock)
|
378
|
+
)
|
379
|
+
pane.submenu = "_10_" + _("Laser")
|
380
|
+
pane.helptext = _("Display a job pause button")
|
381
|
+
pane.dock_proportion = 98
|
382
|
+
|
383
|
+
bgcol = context.themes.get("pause_bg")
|
384
|
+
fgcol = None
|
385
|
+
panel = ActionPanel(
|
386
|
+
window,
|
387
|
+
wx.ID_ANY,
|
388
|
+
context=context,
|
389
|
+
action=action,
|
390
|
+
fgcolor=fgcol,
|
391
|
+
bgcolor=bgcol,
|
392
|
+
icon=icons8_pause,
|
393
|
+
tooltip=_("Pause/Resume the controller"),
|
394
|
+
)
|
395
|
+
pane.control = panel
|
396
|
+
window.on_pane_create(pane)
|
397
|
+
context.register("pane/pause", pane)
|
398
|
+
|
399
|
+
|
400
|
+
supported_languages = (
|
401
|
+
("en", "English", wx.LANGUAGE_ENGLISH),
|
402
|
+
("it", "italiano", wx.LANGUAGE_ITALIAN),
|
403
|
+
("fr", "français", wx.LANGUAGE_FRENCH),
|
404
|
+
("de", "Deutsch", wx.LANGUAGE_GERMAN),
|
405
|
+
("es", "español", wx.LANGUAGE_SPANISH),
|
406
|
+
("zh", "中文", wx.LANGUAGE_CHINESE),
|
407
|
+
("hu", "Magyar", wx.LANGUAGE_HUNGARIAN),
|
408
|
+
("pt_PT", "português", wx.LANGUAGE_PORTUGUESE),
|
409
|
+
("pt_BR", "português brasileiro", wx.LANGUAGE_PORTUGUESE_BRAZILIAN),
|
410
|
+
("ja", "日本", wx.LANGUAGE_JAPANESE),
|
411
|
+
("nl", "Nederlands", wx.LANGUAGE_DUTCH),
|
412
|
+
)
|
413
|
+
|
414
|
+
|
415
|
+
def resource_path(relative_path):
|
416
|
+
"""Get absolute path to resource, works for dev and for PyInstaller"""
|
417
|
+
base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
|
418
|
+
return os.path.join(base_path, relative_path)
|
419
|
+
|
420
|
+
|
421
|
+
class wxMeerK40t(wx.App, Module):
|
422
|
+
"""
|
423
|
+
wxMeerK40t is the wx.App main class and a qualified Module for the MeerK40t kernel.
|
424
|
+
Running MeerK40t without the wxMeerK40t gui is both possible and reasonable. This should not change the way the
|
425
|
+
underlying code runs. It should just be a series of frames held together with the kernel.
|
426
|
+
"""
|
427
|
+
|
428
|
+
def __init__(self, context, path):
|
429
|
+
self.context = context
|
430
|
+
wx.App.__init__(self, 0)
|
431
|
+
# Is this a Windows machine? If yes:
|
432
|
+
# Turn on high-DPI awareness to make sure rendering is sharp on big
|
433
|
+
# monitors with font scaling enabled.
|
434
|
+
|
435
|
+
high_dpi = context.setting(bool, "high_dpi", True)
|
436
|
+
if platform.system() == "Windows" and high_dpi:
|
437
|
+
try:
|
438
|
+
# https://discuss.wxpython.org/t/support-for-high-dpi-on-windows-10/32925
|
439
|
+
from ctypes import OleDLL
|
440
|
+
|
441
|
+
OleDLL("shcore").SetProcessDpiAwareness(1)
|
442
|
+
except (AttributeError, ImportError):
|
443
|
+
# We're on a non-Windows box.
|
444
|
+
pass
|
445
|
+
except OSError:
|
446
|
+
# Potential access denied.
|
447
|
+
pass
|
448
|
+
self.supported_languages = supported_languages
|
449
|
+
import meerk40t.gui.icons as icons
|
450
|
+
|
451
|
+
self.timer = wx.Timer(self, id=wx.ID_ANY)
|
452
|
+
self.Bind(wx.EVT_TIMER, context._kernel.scheduler_main, self.timer)
|
453
|
+
context._kernel.scheduler_handles_main_thread_jobs = False
|
454
|
+
self.timer.Start(50)
|
455
|
+
# try:
|
456
|
+
# res = wx.SystemSettings().GetAppearance().IsDark()
|
457
|
+
# except AttributeError:
|
458
|
+
# res = wx.SystemSettings().GetColour(wx.SYS_COLOUR_WINDOW)[0] < 127
|
459
|
+
Module.__init__(self, context, path)
|
460
|
+
theme = Themes(kernel=context._kernel)
|
461
|
+
icons.DARKMODE = theme.dark
|
462
|
+
self.locale = None
|
463
|
+
self.Bind(wx.EVT_CLOSE, self.on_app_close)
|
464
|
+
self.Bind(wx.EVT_QUERY_END_SESSION, self.on_app_close) # MAC DOCK QUIT.
|
465
|
+
self.Bind(wx.EVT_END_SESSION, self.on_app_close)
|
466
|
+
self.Bind(wx.EVT_END_PROCESS, self.on_app_close)
|
467
|
+
# This catches events when the app is asked to activate by some other process
|
468
|
+
self.Bind(wx.EVT_ACTIVATE_APP, self.OnActivate)
|
469
|
+
provider = wx.SimpleHelpProvider()
|
470
|
+
wx.HelpProvider.Set(provider)
|
471
|
+
# App started add the except hook
|
472
|
+
sys.excepthook = handleGUIException
|
473
|
+
|
474
|
+
# Monkey patch for pycharm excepthook override issue. https://youtrack.jetbrains.com/issue/PY-39723
|
475
|
+
try:
|
476
|
+
import importlib
|
477
|
+
|
478
|
+
pydevd = importlib.import_module("_pydevd_bundle.pydevd_breakpoints")
|
479
|
+
except ImportError:
|
480
|
+
pass
|
481
|
+
else:
|
482
|
+
pydevd._fallback_excepthook = sys.excepthook
|
483
|
+
|
484
|
+
# Set the delay after which the tooltip disappears or how long a tooltip remains visible.
|
485
|
+
self.context.setting(int, "tooltip_autopop", 10000)
|
486
|
+
# Set the delay after which the tooltip appears.
|
487
|
+
self.context.setting(int, "tooltip_delay", 100)
|
488
|
+
autopop_ms = self.context.tooltip_autopop
|
489
|
+
delay_ms = self.context.tooltip_delay
|
490
|
+
wx.ToolTip.SetAutoPop(autopop_ms)
|
491
|
+
wx.ToolTip.SetDelay(delay_ms)
|
492
|
+
wx.ToolTip.SetReshow(0)
|
493
|
+
|
494
|
+
def on_app_close(self, event=None):
|
495
|
+
try:
|
496
|
+
if self.context is not None:
|
497
|
+
self.context("quit\n")
|
498
|
+
except AttributeError:
|
499
|
+
pass
|
500
|
+
|
501
|
+
def OnInit(self):
|
502
|
+
self.name = f"MeerK40t-{wx.GetUserId()}"
|
503
|
+
self.instance = wx.SingleInstanceChecker(self.name)
|
504
|
+
self.context.setting(bool, "single_instance_only", True)
|
505
|
+
if self.context.kernel._was_restarted:
|
506
|
+
return True
|
507
|
+
if self.context.single_instance_only and self.instance.IsAnotherRunning():
|
508
|
+
dlg = wx.MessageDialog(
|
509
|
+
None,
|
510
|
+
"Another instance is running!\nDo you want to run another copy of the app?",
|
511
|
+
"ERROR",
|
512
|
+
wx.YES_NO | wx.ICON_QUESTION | wx.NO_DEFAULT,
|
513
|
+
)
|
514
|
+
result = dlg.ShowModal() == wx.ID_YES
|
515
|
+
dlg.Destroy()
|
516
|
+
if not result:
|
517
|
+
return False
|
518
|
+
return True
|
519
|
+
|
520
|
+
def InitLocale(self):
|
521
|
+
import sys
|
522
|
+
|
523
|
+
if sys.platform.startswith("win") and sys.version_info > (3, 8):
|
524
|
+
# This hack is needed to deal with a new Python 3.8 behaviour to
|
525
|
+
# set the locale at runtime. wxpython assumes it can do with the
|
526
|
+
# locale objects whatever it wants, so we need to bring it back to
|
527
|
+
# a defined default
|
528
|
+
|
529
|
+
import locale
|
530
|
+
|
531
|
+
locale.setlocale(locale.LC_ALL, "C")
|
532
|
+
|
533
|
+
def BringWindowToFront(self):
|
534
|
+
try: # it's possible for this event to come when the frame is closed
|
535
|
+
self.GetTopWindow().Raise()
|
536
|
+
except Exception:
|
537
|
+
pass
|
538
|
+
|
539
|
+
def OnActivate(self, event):
|
540
|
+
# if this is an activate event, rather than something else, like iconize.
|
541
|
+
if event.GetActive():
|
542
|
+
self.BringWindowToFront()
|
543
|
+
event.Skip()
|
544
|
+
|
545
|
+
def MacReopenApp(self):
|
546
|
+
"""Called when the doc icon is clicked, and ???"""
|
547
|
+
self.BringWindowToFront()
|
548
|
+
|
549
|
+
def MacNewFile(self):
|
550
|
+
try:
|
551
|
+
if self.context is not None:
|
552
|
+
with self.context.elements.undoscope("New"):
|
553
|
+
self.context.elements.clear_all()
|
554
|
+
except AttributeError:
|
555
|
+
pass
|
556
|
+
|
557
|
+
def MacPrintFile(self, file_path):
|
558
|
+
pass
|
559
|
+
|
560
|
+
def MacOpenFile(self, filename):
|
561
|
+
try:
|
562
|
+
if self.context is not None:
|
563
|
+
self.context.elements.load(os.path.realpath(filename))
|
564
|
+
except AttributeError:
|
565
|
+
pass
|
566
|
+
|
567
|
+
def MacOpenFiles(self, filenames):
|
568
|
+
try:
|
569
|
+
if self.context is not None:
|
570
|
+
for filename in filenames:
|
571
|
+
self.context.elements.load(os.path.realpath(filename))
|
572
|
+
except AttributeError:
|
573
|
+
pass
|
574
|
+
|
575
|
+
@staticmethod
|
576
|
+
def sub_register(kernel):
|
577
|
+
#################
|
578
|
+
# WINDOW COMMANDS
|
579
|
+
#################
|
580
|
+
|
581
|
+
@kernel.console_option(
|
582
|
+
"path",
|
583
|
+
"p",
|
584
|
+
type=str,
|
585
|
+
default="/",
|
586
|
+
help=_("Context Path at which to open the window"),
|
587
|
+
)
|
588
|
+
@kernel.console_command(
|
589
|
+
"window", output_type="window", help=_("Base window command")
|
590
|
+
)
|
591
|
+
def window_base(channel, _, path=None, remainder=None, **kwargs):
|
592
|
+
"""
|
593
|
+
Opens a MeerK40t window or provides information. This command is restricted to use with the wxMeerK40t gui.
|
594
|
+
This also allows use of a -p flag that sets the context path for this window to operate at. This should
|
595
|
+
often be restricted to where the windows are typically opened since their function and settings usually
|
596
|
+
depend on the context used. Windows often cannot open multiple copies of the same window at the same context
|
597
|
+
The default root path is "/". E.g. "window -p / open Preferences"
|
598
|
+
"""
|
599
|
+
context = kernel.root
|
600
|
+
if path is None:
|
601
|
+
path = context
|
602
|
+
else:
|
603
|
+
path = kernel.get_context(path)
|
604
|
+
|
605
|
+
if remainder is None:
|
606
|
+
channel(
|
607
|
+
_("Loaded Windows in Context {name}:").format(
|
608
|
+
name=str(context.path)
|
609
|
+
)
|
610
|
+
)
|
611
|
+
for i, name in enumerate(context.opened):
|
612
|
+
if not name.startswith("window"):
|
613
|
+
continue
|
614
|
+
module = context.opened[name]
|
615
|
+
channel(
|
616
|
+
_("{index}: {name} as type of {type}").format(
|
617
|
+
index=i + 1, name=name, type=type(module)
|
618
|
+
)
|
619
|
+
)
|
620
|
+
|
621
|
+
channel("----------")
|
622
|
+
if path is context:
|
623
|
+
return "window", path
|
624
|
+
channel(_("Loaded Windows in Path {path}:").format(path=str(path.path)))
|
625
|
+
for i, name in enumerate(path.opened):
|
626
|
+
if not name.startswith("window"):
|
627
|
+
continue
|
628
|
+
module = path.opened[name]
|
629
|
+
channel(
|
630
|
+
_("{index}: {name} as type of {type}").format(
|
631
|
+
index=i + 1, name=name, type=type(module)
|
632
|
+
)
|
633
|
+
)
|
634
|
+
channel("----------")
|
635
|
+
return "window", path
|
636
|
+
|
637
|
+
@kernel.console_command(
|
638
|
+
"list",
|
639
|
+
input_type="window",
|
640
|
+
output_type="window",
|
641
|
+
help=_("List available windows."),
|
642
|
+
)
|
643
|
+
def window_list(channel, _, data, **kwargs):
|
644
|
+
channel(_("----------"))
|
645
|
+
channel(_("Windows Registered:"))
|
646
|
+
context = kernel.root
|
647
|
+
for i, name in enumerate(context.match("window")):
|
648
|
+
name = name[7:]
|
649
|
+
channel(f"{i + 1}: {name}")
|
650
|
+
return "window", data
|
651
|
+
|
652
|
+
@kernel.console_command(
|
653
|
+
"displays",
|
654
|
+
input_type="window",
|
655
|
+
output_type="window",
|
656
|
+
help=_("Give display info for the current opened windows"),
|
657
|
+
)
|
658
|
+
def displays(channel, _, data, **kwargs):
|
659
|
+
for idx in range(wx.Display.GetCount()):
|
660
|
+
d = wx.Display(idx)
|
661
|
+
channel(f"{idx} Primary: {d.IsPrimary()} {d.GetGeometry()}")
|
662
|
+
channel(_("----------"))
|
663
|
+
path = data
|
664
|
+
for opened in path.opened:
|
665
|
+
if opened.startswith("window/"):
|
666
|
+
window = path.opened[opened]
|
667
|
+
display = wx.Display.GetFromWindow(window)
|
668
|
+
if display == wx.NOT_FOUND:
|
669
|
+
display = "Display Not Found"
|
670
|
+
channel(
|
671
|
+
f"Window {opened} with bounds {window.GetRect()} is located on display: {display})"
|
672
|
+
)
|
673
|
+
return "window", data
|
674
|
+
|
675
|
+
@kernel.console_option(
|
676
|
+
"multi",
|
677
|
+
"m",
|
678
|
+
type=int,
|
679
|
+
help=_("Multi window flag for launching multiple copies of this window."),
|
680
|
+
)
|
681
|
+
@kernel.console_argument("window", type=str, help=_("window to be opened"))
|
682
|
+
@kernel.console_command(
|
683
|
+
("open", "toggle"),
|
684
|
+
input_type="window",
|
685
|
+
help=_("open/toggle the supplied window"),
|
686
|
+
)
|
687
|
+
def window_open(
|
688
|
+
command, channel, _, data, multi=None, window=None, args=(), **kwargs
|
689
|
+
):
|
690
|
+
context = kernel.root
|
691
|
+
path = data
|
692
|
+
try:
|
693
|
+
parent = context.gui
|
694
|
+
except AttributeError:
|
695
|
+
parent = None
|
696
|
+
window_uri = f"window/{window}"
|
697
|
+
window_class = context.lookup(window_uri)
|
698
|
+
if isinstance(window_class, str):
|
699
|
+
window_uri = window_class
|
700
|
+
window_class = context.lookup(window_uri)
|
701
|
+
|
702
|
+
new_path = context.lookup(f"winpath/{window}")
|
703
|
+
if new_path:
|
704
|
+
path = new_path
|
705
|
+
else:
|
706
|
+
path = context
|
707
|
+
|
708
|
+
window_name = f"{window_uri}:{multi}" if multi is not None else window_uri
|
709
|
+
|
710
|
+
def window_open(*a, **k):
|
711
|
+
path.open_as(window_uri, window_name, parent, *args)
|
712
|
+
channel(_("Window opened: {window}").format(window=window))
|
713
|
+
|
714
|
+
def window_close(*a, **k):
|
715
|
+
path.close(window_name, *args)
|
716
|
+
channel(_("Window closed: {window}").format(window=window))
|
717
|
+
|
718
|
+
if command == "open":
|
719
|
+
if path.lookup(window_uri) is not None:
|
720
|
+
if wx.IsMainThread():
|
721
|
+
with wx.BusyCursor():
|
722
|
+
window_open(None)
|
723
|
+
else:
|
724
|
+
wx.CallAfter(window_open, None)
|
725
|
+
# kernel.run_later(window_open, None)
|
726
|
+
else:
|
727
|
+
channel(_("No such window as {window}").format(window=window))
|
728
|
+
raise CommandSyntaxError
|
729
|
+
else: # Toggle.
|
730
|
+
if window_class is not None:
|
731
|
+
to_be_closed = bool(window_name in path.opened)
|
732
|
+
if to_be_closed:
|
733
|
+
win = path.opened[window_name]
|
734
|
+
if hasattr(win, "IsIconized") and win.IsIconized():
|
735
|
+
# Minimized windows will reappear first
|
736
|
+
to_be_closed = False
|
737
|
+
|
738
|
+
if to_be_closed:
|
739
|
+
if wx.IsMainThread():
|
740
|
+
window_close(None)
|
741
|
+
else:
|
742
|
+
wx.CallAfter(window_close, None)
|
743
|
+
# kernel.run_later(window_close, None)
|
744
|
+
else:
|
745
|
+
if wx.IsMainThread():
|
746
|
+
with wx.BusyCursor():
|
747
|
+
window_open(None)
|
748
|
+
else:
|
749
|
+
wx.CallAfter(window_open, None)
|
750
|
+
# kernel.run_later(window_open, None)
|
751
|
+
else:
|
752
|
+
channel(_("No such window as {name}").format(name=window))
|
753
|
+
raise CommandSyntaxError
|
754
|
+
|
755
|
+
@kernel.console_argument("window", type=str, help=_("window to be closed"))
|
756
|
+
@kernel.console_command(
|
757
|
+
"close",
|
758
|
+
input_type="window",
|
759
|
+
output_type="window",
|
760
|
+
help=_("close the supplied window"),
|
761
|
+
)
|
762
|
+
def window_close(channel, _, data, window=None, args=(), **kwargs):
|
763
|
+
path = data
|
764
|
+
context = kernel.root
|
765
|
+
try:
|
766
|
+
parent = context.gui if hasattr(context, "gui") else None
|
767
|
+
if wx.IsMainThread():
|
768
|
+
path.close(f"window/{window}", parent, *args)
|
769
|
+
else:
|
770
|
+
wx.CallAfter(path.close(f"window/{window}", parent, *args), None)
|
771
|
+
channel(_("Window closed."))
|
772
|
+
except (KeyError, ValueError):
|
773
|
+
channel(_("No such window as {window}").format(window=window))
|
774
|
+
except IndexError:
|
775
|
+
raise CommandSyntaxError
|
776
|
+
|
777
|
+
@kernel.console_argument("window", type=str, help=_("window to be reset"))
|
778
|
+
@kernel.console_command(
|
779
|
+
"reset",
|
780
|
+
input_type="window",
|
781
|
+
output_type="window",
|
782
|
+
help=_("reset the supplied window, or '*' for all windows"),
|
783
|
+
)
|
784
|
+
def window_reset(channel, _, data, window=None, **kwargs):
|
785
|
+
for section in list(kernel.section_startswith("window/")):
|
786
|
+
kernel.clear_persistent(section)
|
787
|
+
try:
|
788
|
+
del kernel.contexts[section]
|
789
|
+
except KeyError:
|
790
|
+
pass # No open context for that window, nothing will save out.
|
791
|
+
|
792
|
+
@kernel.console_command("refresh", help=_("Refresh the main wxMeerK40 window"))
|
793
|
+
def scene_refresh(command, channel, _, **kwargs):
|
794
|
+
context = kernel.root
|
795
|
+
context.signal("refresh_scene", "Scene")
|
796
|
+
context.signal("rebuild_tree")
|
797
|
+
channel(_("Refreshed."))
|
798
|
+
|
799
|
+
@kernel.console_command("tooltips_enable", hidden=True)
|
800
|
+
def tooltip_enable(command, channel, _, **kwargs):
|
801
|
+
context = kernel.root
|
802
|
+
context.setting(bool, "disable_tool_tips", False)
|
803
|
+
context.disable_tool_tips = False
|
804
|
+
wx.ToolTip.Enable(not context.disable_tool_tips)
|
805
|
+
|
806
|
+
@kernel.console_command("tooltips_disable", hidden=True)
|
807
|
+
def tooltip_disable(command, channel, _, **kwargs):
|
808
|
+
context = kernel.root
|
809
|
+
context.setting(bool, "disable_tool_tips", False)
|
810
|
+
context.disable_tool_tips = True
|
811
|
+
wx.ToolTip.Enable(not context.disable_tool_tips)
|
812
|
+
|
813
|
+
@kernel.console_argument("func", type=str, help=_("Function to call interactively"))
|
814
|
+
@kernel.console_command("gui", help=_("Provides a GUI wrapper around a console command"))
|
815
|
+
def gui_func(command, channel, _, func=None, **kwargs):
|
816
|
+
if func is None:
|
817
|
+
channel(_("You need to provide a function name"))
|
818
|
+
return
|
819
|
+
if func in ("gui", "help", "?", "??", "quit", "shutdown", "exit"):
|
820
|
+
channel (_("It does not make sense, to run '{command}' in a GUI").format(command=func))
|
821
|
+
return
|
822
|
+
context = kernel.root
|
823
|
+
try:
|
824
|
+
parent = context.gui
|
825
|
+
except AttributeError:
|
826
|
+
parent = None
|
827
|
+
dialog: wx.Dialog = ConsoleCommandUI(parent, wx.ID_ANY, title=_("Command {command}").format(command=func), context=context, command_string=func)
|
828
|
+
res = dialog.ShowModal()
|
829
|
+
if res == wx.ID_OK:
|
830
|
+
dialog.accept_it()
|
831
|
+
else:
|
832
|
+
dialog.cancel_it()
|
833
|
+
dialog.Destroy()
|
834
|
+
|
835
|
+
def module_open(self, *args, **kwargs):
|
836
|
+
context = self.context
|
837
|
+
kernel = context.kernel
|
838
|
+
|
839
|
+
try: # pyinstaller internal location
|
840
|
+
# pylint: disable=no-member
|
841
|
+
_resource_path = os.path.join(sys._MEIPASS, "locale")
|
842
|
+
wx.Locale.AddCatalogLookupPathPrefix(_resource_path)
|
843
|
+
except Exception:
|
844
|
+
pass
|
845
|
+
|
846
|
+
try: # Mac py2app resource
|
847
|
+
_resource_path = os.path.join(os.environ["RESOURCEPATH"], "locale")
|
848
|
+
wx.Locale.AddCatalogLookupPathPrefix(_resource_path)
|
849
|
+
except Exception:
|
850
|
+
pass
|
851
|
+
|
852
|
+
wx.Locale.AddCatalogLookupPathPrefix("locale")
|
853
|
+
|
854
|
+
# Default Locale, prepended. Check this first.
|
855
|
+
basepath = os.path.abspath(os.path.dirname(sys.argv[0]))
|
856
|
+
localedir = os.path.join(basepath, "locale")
|
857
|
+
wx.Locale.AddCatalogLookupPathPrefix(localedir)
|
858
|
+
|
859
|
+
kernel.translation = wx.GetTranslation
|
860
|
+
|
861
|
+
context.app = self # Registers self as kernel.app
|
862
|
+
|
863
|
+
context.setting(int, "language", None)
|
864
|
+
language = context.language
|
865
|
+
# print (f"Language according to settings: {language}")
|
866
|
+
tlang = getattr(kernel.args, "language", "undefined")
|
867
|
+
for idx, content in enumerate(supported_languages):
|
868
|
+
if content[0] == tlang:
|
869
|
+
language = idx
|
870
|
+
break
|
871
|
+
# print (f"Language after cmdline-test: {language}")
|
872
|
+
|
873
|
+
# See issue #2103
|
874
|
+
# context.setting(str, "i18n", "en")
|
875
|
+
# language = context.i18n
|
876
|
+
# self.update_language_kernel(language)
|
877
|
+
|
878
|
+
from meerk40t.gui.help_assets.help_assets import asset
|
879
|
+
|
880
|
+
def get_asset(asset_name):
|
881
|
+
return asset(context, asset_name)
|
882
|
+
|
883
|
+
context.asset = get_asset
|
884
|
+
if language is not None and language != 0:
|
885
|
+
self.update_language(language)
|
886
|
+
|
887
|
+
kernel.register("window/MeerK40t", MeerK40t)
|
888
|
+
|
889
|
+
kernel.register("window/Properties", PropertyWindow)
|
890
|
+
kernel.register("property/RasterOpNode/OpMain", ParameterPanel)
|
891
|
+
kernel.register("property/CutOpNode/OpMain", ParameterPanel)
|
892
|
+
kernel.register("property/EngraveOpNode/OpMain", ParameterPanel)
|
893
|
+
kernel.register("property/ImageOpNode/OpMain", ParameterPanel)
|
894
|
+
kernel.register("property/DotsOpNode/OpMain", ParameterPanel)
|
895
|
+
kernel.register("property/PlaceCurrentNode/OpMain", PlacementParameterPanel)
|
896
|
+
kernel.register("property/PlacePointNode/OpMain", PlacementParameterPanel)
|
897
|
+
|
898
|
+
kernel.register("property/ConsoleOperation/Property", ConsolePropertiesPanel)
|
899
|
+
kernel.register("property/FileNode/Property", FilePropertiesPanel)
|
900
|
+
kernel.register("property/GroupNode/Property", GroupPropertiesPanel)
|
901
|
+
kernel.register("property/EllipseNode/PathProperty", PathPropertyPanel)
|
902
|
+
kernel.register("property/PathNode/PathProperty", PathPropertyPanel)
|
903
|
+
kernel.register("property/LineNode/PathProperty", PathPropertyPanel)
|
904
|
+
kernel.register("property/PolylineNode/PathProperty", PathPropertyPanel)
|
905
|
+
kernel.register("property/RectNode/PathProperty", PathPropertyPanel)
|
906
|
+
kernel.register("property/HatchEffectNode/HatchProperty", HatchPropertyPanel)
|
907
|
+
kernel.register("property/WobbleEffectNode/WobbleProperty", WobblePropertyPanel)
|
908
|
+
kernel.register("property/WarpEffectNode/WarpProperty", WarpPropertyPanel)
|
909
|
+
kernel.register("property/PointNode/PointProperty", PointPropertyPanel)
|
910
|
+
kernel.register("property/TextNode/TextProperty", TextPropertyPanel)
|
911
|
+
kernel.register("property/BlobNode/BlobProperty", BlobPropertyPanel)
|
912
|
+
kernel.register("property/WaitOperation/WaitProperty", WaitPropertyPanel)
|
913
|
+
kernel.register("property/GotoOperation/GotoProperty", GotoPropertyPanel)
|
914
|
+
kernel.register("property/InputOperation/InputProperty", InputPropertyPanel)
|
915
|
+
kernel.register("property/BranchOperationsNode/LoopProperty", OpBranchPanel)
|
916
|
+
kernel.register("property/BranchRegmarkNode/RegmarkProperty", RegBranchPanel)
|
917
|
+
kernel.register("property/OutputOperation/OutputProperty", OutputPropertyPanel)
|
918
|
+
kernel.register("property/ImageNode/ImageProperty", ImagePropertyPanel)
|
919
|
+
|
920
|
+
kernel.register("property/ImageNode/SharpenProperty", SharpenPanel)
|
921
|
+
kernel.register("property/ImageNode/ContrastProperty", ContrastPanel)
|
922
|
+
kernel.register("property/ImageNode/ToneCurveProperty", ToneCurvePanel)
|
923
|
+
kernel.register("property/ImageNode/HalftoneProperty", HalftonePanel)
|
924
|
+
kernel.register("property/ImageNode/GammaProperty", GammaPanel)
|
925
|
+
kernel.register("property/ImageNode/EdgeProperty", EdgePanel)
|
926
|
+
kernel.register("property/ImageNode/AutoContrastProperty", AutoContrastPanel)
|
927
|
+
|
928
|
+
kernel.register("property/ImageNode/ImageModification", ImageModificationPanel)
|
929
|
+
kernel.register(
|
930
|
+
"property/ImageNode/ImageVectorisation", ImageVectorisationPanel
|
931
|
+
)
|
932
|
+
kernel.register(
|
933
|
+
"property/ImageNode/ImageContour", ContourPanel
|
934
|
+
)
|
935
|
+
|
936
|
+
kernel.register("window/Console", Console)
|
937
|
+
if (
|
938
|
+
hasattr(kernel.args, "lock_general_config")
|
939
|
+
and kernel.args.lock_general_config
|
940
|
+
):
|
941
|
+
pass
|
942
|
+
else:
|
943
|
+
kernel.register("window/Preferences", Preferences)
|
944
|
+
kernel.register("window/About", About)
|
945
|
+
kernel.register("window/Keymap", Keymap)
|
946
|
+
kernel.register("window/Wordlist", WordlistEditor)
|
947
|
+
kernel.register("window/MatManager", MaterialManager)
|
948
|
+
kernel.register("window/Navigation", Navigation)
|
949
|
+
kernel.register("window/Notes", Notes)
|
950
|
+
kernel.register("window/AutoExec", AutoExec)
|
951
|
+
kernel.register("window/JobSpooler", JobSpooler)
|
952
|
+
kernel.register("window/Simulation", Simulation)
|
953
|
+
kernel.register("window/Tips", Tips)
|
954
|
+
kernel.register("window/ExecuteJob", ExecuteJob)
|
955
|
+
kernel.register("window/BufferView", BufferView)
|
956
|
+
kernel.register("window/Scene", SceneWindow)
|
957
|
+
if not (
|
958
|
+
hasattr(kernel.args, "lock_device_config")
|
959
|
+
and kernel.args.lock_device_config
|
960
|
+
):
|
961
|
+
kernel.register("window/DeviceManager", DeviceManager)
|
962
|
+
kernel.register("window/Alignment", Alignment)
|
963
|
+
kernel.register("window/HersheyFontManager", HersheyFontManager)
|
964
|
+
kernel.register("window/HersheyFontSelector", HersheyFontSelector)
|
965
|
+
kernel.register("window/SplitImage", RenderSplit)
|
966
|
+
kernel.register("window/OperationInfo", OperationInformation)
|
967
|
+
kernel.register("window/Lasertool", LaserTool)
|
968
|
+
kernel.register("window/Templatetool", TemplateTool)
|
969
|
+
kernel.register("window/Hingetool", LivingHingeTool)
|
970
|
+
kernel.register("window/Kerftest", KerfTool)
|
971
|
+
kernel.register("window/SimpleUI", SimpleUI)
|
972
|
+
# Hershey Manager stuff
|
973
|
+
register_hershey_stuff(kernel)
|
974
|
+
|
975
|
+
from meerk40t.gui.helper import register_panel_helper
|
976
|
+
|
977
|
+
kernel.register("wxpane/helper", register_panel_helper)
|
978
|
+
|
979
|
+
from meerk40t.gui.wxmribbon import register_panel_ribbon
|
980
|
+
|
981
|
+
kernel.register("wxpane/Ribbon", register_panel_ribbon)
|
982
|
+
|
983
|
+
from meerk40t.gui.wxmscene import register_panel_scene
|
984
|
+
|
985
|
+
kernel.register("wxpane/ScenePane", register_panel_scene)
|
986
|
+
|
987
|
+
from meerk40t.gui.wxmtree import register_panel_tree
|
988
|
+
|
989
|
+
kernel.register("wxpane/Tree", register_panel_tree)
|
990
|
+
|
991
|
+
from meerk40t.gui.laserpanel import register_panel_laser
|
992
|
+
|
993
|
+
kernel.register("wxpane/LaserPanel", register_panel_laser)
|
994
|
+
|
995
|
+
from meerk40t.gui.position import register_panel_position
|
996
|
+
|
997
|
+
kernel.register("wxpane/Position", register_panel_position)
|
998
|
+
|
999
|
+
from meerk40t.gui.opassignment import register_panel_operation_assign
|
1000
|
+
|
1001
|
+
kernel.register("wxpane/opassign", register_panel_operation_assign)
|
1002
|
+
|
1003
|
+
from meerk40t.gui.snapoptions import register_panel_snapoptions
|
1004
|
+
|
1005
|
+
kernel.register("wxpane/Snap", register_panel_snapoptions)
|
1006
|
+
|
1007
|
+
from meerk40t.gui.magnetoptions import register_panel_magnetoptions
|
1008
|
+
|
1009
|
+
kernel.register("wxpane/magnet", register_panel_magnetoptions)
|
1010
|
+
|
1011
|
+
from meerk40t.gui.wordlisteditor import register_panel_wordlist
|
1012
|
+
|
1013
|
+
kernel.register("wxpane/wordlist", register_panel_wordlist)
|
1014
|
+
|
1015
|
+
# from meerk40t.gui.auitoolbars import register_toolbars
|
1016
|
+
|
1017
|
+
# kernel.register("wxpane/Toolbars", register_toolbars)
|
1018
|
+
|
1019
|
+
kernel.register("wxpane/Go", register_panel_go)
|
1020
|
+
kernel.register("wxpane/Stop", register_panel_stop)
|
1021
|
+
kernel.register("wxpane/Home", register_panel_home)
|
1022
|
+
kernel.register("wxpane/Pause", register_panel_pause)
|
1023
|
+
|
1024
|
+
from meerk40t.gui.dialogoptions import DialogOptions
|
1025
|
+
|
1026
|
+
kernel.register("dialog/options", DialogOptions)
|
1027
|
+
|
1028
|
+
context = kernel.root
|
1029
|
+
|
1030
|
+
context.setting(bool, "developer_mode", False)
|
1031
|
+
context.setting(bool, "debug_mode", False)
|
1032
|
+
if context.debug_mode:
|
1033
|
+
from meerk40t.gui.mkdebug import (
|
1034
|
+
register_panel_color,
|
1035
|
+
register_panel_crash,
|
1036
|
+
register_panel_debugger,
|
1037
|
+
register_panel_icon,
|
1038
|
+
register_panel_window,
|
1039
|
+
)
|
1040
|
+
|
1041
|
+
kernel.register("wxpane/debug_tree", register_panel_debugger)
|
1042
|
+
kernel.register("wxpane/debug_color", register_panel_color)
|
1043
|
+
kernel.register("wxpane/debug_icons", register_panel_icon)
|
1044
|
+
kernel.register("wxpane/debug_shutdown", register_panel_crash)
|
1045
|
+
kernel.register("wxpane/debug_window", register_panel_window)
|
1046
|
+
|
1047
|
+
from meerk40t.gui.utilitywidgets.debugwidgets import register_widget_icon
|
1048
|
+
|
1049
|
+
register_widget_icon(kernel.root)
|
1050
|
+
|
1051
|
+
wildcard = "Sound-Files|*.wav;*.mp3;*.ogg|All files|*.*"
|
1052
|
+
OS_NAME = platform.system()
|
1053
|
+
addon = ""
|
1054
|
+
if OS_NAME == "Darwin":
|
1055
|
+
wildcard = f"System-Sounds|*.aiff|{wildcard}"
|
1056
|
+
elif OS_NAME == "Linux":
|
1057
|
+
wildcard = f"System-Sounds|*.oga;*.wav;*.mp3|{wildcard}"
|
1058
|
+
addon = "\n" + _("This uses the 'play' command that comes with the sox package,\nso you might need to install it with 'sudo apt install sox' first.")
|
1059
|
+
system_sound = {
|
1060
|
+
"Windows": r"c:\Windows\Media\Alarm01.wav",
|
1061
|
+
"Darwin": "/System/Library/Sounds/Ping.aiff",
|
1062
|
+
"Linux": "/usr/share/sounds/freedesktop/stereo/phone-incoming-call.oga",
|
1063
|
+
}
|
1064
|
+
default_snd = system_sound.get(OS_NAME, "")
|
1065
|
+
|
1066
|
+
choices = [
|
1067
|
+
{
|
1068
|
+
"attr": "single_instance_only",
|
1069
|
+
"object": context.root,
|
1070
|
+
"default": True,
|
1071
|
+
"type": bool,
|
1072
|
+
"label": _("Single Instance"),
|
1073
|
+
"tip": _("Allow only a single instance of MeerK40t."),
|
1074
|
+
"page": "Start",
|
1075
|
+
},
|
1076
|
+
{
|
1077
|
+
"attr": "beep_soundfile",
|
1078
|
+
"object": context.root,
|
1079
|
+
"type": str,
|
1080
|
+
"default": default_snd,
|
1081
|
+
"style": "file",
|
1082
|
+
"wildcard": wildcard,
|
1083
|
+
"label": _("Soundfile"),
|
1084
|
+
"tip": _("Define the soundfile MeerK40t will play when the 'beep' command is issued") + addon,
|
1085
|
+
"page": "Start",
|
1086
|
+
}
|
1087
|
+
]
|
1088
|
+
kernel.register_choices("preferences", choices)
|
1089
|
+
|
1090
|
+
@context.console_argument("sure", type=str, help="Are you sure? 'yes'?")
|
1091
|
+
@context.console_command("nuke_settings", hidden=True)
|
1092
|
+
def nuke_settings(command, channel, _, sure=None, **kwargs):
|
1093
|
+
if sure == "yes":
|
1094
|
+
kernel = self.context.kernel
|
1095
|
+
kernel.delete_all_persistent()
|
1096
|
+
kernel.shutdown()
|
1097
|
+
else:
|
1098
|
+
channel(
|
1099
|
+
'Argument "sure" is required. Requires typing: "nuke_settings yes"'
|
1100
|
+
)
|
1101
|
+
|
1102
|
+
@context.console_argument("crashtype", type=str)
|
1103
|
+
@context.console_command("crash_me_if_you_can", hidden=True)
|
1104
|
+
def crash_mk(command, channel, _, crashtype=None, **kwargs):
|
1105
|
+
def crash_divide(x, y):
|
1106
|
+
return x / y
|
1107
|
+
|
1108
|
+
def crash_key(variable, index):
|
1109
|
+
l = variable
|
1110
|
+
return l[index]
|
1111
|
+
|
1112
|
+
def crash_index(variable, index):
|
1113
|
+
l = variable
|
1114
|
+
return l[index]
|
1115
|
+
|
1116
|
+
def crash_value(variable, dtype):
|
1117
|
+
return dtype(variable)
|
1118
|
+
|
1119
|
+
if crashtype is None:
|
1120
|
+
crashtype = "dividebyzero"
|
1121
|
+
crashtype = crashtype.lower()
|
1122
|
+
if crashtype == "dividebyzero":
|
1123
|
+
a = 0
|
1124
|
+
b = 0
|
1125
|
+
c = crash_divide(a, b)
|
1126
|
+
return
|
1127
|
+
if crashtype == "key":
|
1128
|
+
d = {"a": 0}
|
1129
|
+
b = crash_key(d, "b")
|
1130
|
+
return
|
1131
|
+
if crashtype == "index":
|
1132
|
+
a = (0, 1, 2)
|
1133
|
+
b = crash_index(a, 5)
|
1134
|
+
return
|
1135
|
+
if crashtype == "value":
|
1136
|
+
a = "an invalid number 1"
|
1137
|
+
b = crash_value(a, float)
|
1138
|
+
return
|
1139
|
+
|
1140
|
+
def update_language(self, lang):
|
1141
|
+
"""
|
1142
|
+
Update language to the requested language.
|
1143
|
+
"""
|
1144
|
+
context = self.context
|
1145
|
+
try:
|
1146
|
+
language_code, language_name, language_index = supported_languages[lang]
|
1147
|
+
except (IndexError, ValueError):
|
1148
|
+
return
|
1149
|
+
context.language = lang
|
1150
|
+
# We need to remove the command-line argument now:
|
1151
|
+
if hasattr(context.kernel.args, "language"):
|
1152
|
+
delattr(context.kernel.args, "language")
|
1153
|
+
|
1154
|
+
if self.locale:
|
1155
|
+
assert sys.getrefcount(self.locale) <= 2
|
1156
|
+
del self.locale
|
1157
|
+
self.locale = wx.Locale(language_index)
|
1158
|
+
# wxWidgets is broken. IsOk()==false and pops up error dialog, but it translates fine!
|
1159
|
+
if self.locale.IsOk() or platform.system() == "Linux":
|
1160
|
+
self.locale.AddCatalog("meerk40t")
|
1161
|
+
else:
|
1162
|
+
self.locale = None
|
1163
|
+
context.signal("language", (lang, language_code, language_name, language_index))
|
1164
|
+
|
1165
|
+
def update_language_kernel(self, lang_code):
|
1166
|
+
context = self.context
|
1167
|
+
for i, suplang in enumerate(supported_languages):
|
1168
|
+
language_code, language_name, language_index = suplang
|
1169
|
+
if language_code != lang_code:
|
1170
|
+
continue
|
1171
|
+
context.i18n = language_code
|
1172
|
+
self.context.kernel.set_language(language_code)
|
1173
|
+
if self.locale:
|
1174
|
+
assert sys.getrefcount(self.locale) <= 2
|
1175
|
+
del self.locale
|
1176
|
+
self.locale = wx.Locale(language_index)
|
1177
|
+
# wxWidgets is broken. IsOk()==false and pops up error dialog, but it translates fine!
|
1178
|
+
if self.locale.IsOk() or platform.system() == "Linux":
|
1179
|
+
self.locale.AddCatalog("meerk40t")
|
1180
|
+
else:
|
1181
|
+
self.locale = None
|
1182
|
+
context.signal(
|
1183
|
+
"language", (i, language_code, language_name, language_index)
|
1184
|
+
)
|
1185
|
+
|
1186
|
+
|
1187
|
+
# end of class MeerK40tGui
|
1188
|
+
|
1189
|
+
MEERK40T_HOST = "dev.meerk40t.com"
|
1190
|
+
|
1191
|
+
|
1192
|
+
def send_file_to_developers(filename):
|
1193
|
+
"""
|
1194
|
+
Loads a file to send data to the developers.
|
1195
|
+
|
1196
|
+
@param filename: file to send
|
1197
|
+
@return:
|
1198
|
+
"""
|
1199
|
+
try:
|
1200
|
+
with open(filename) as f:
|
1201
|
+
data = f.read()
|
1202
|
+
except:
|
1203
|
+
return # There is no file, there is no data.
|
1204
|
+
send_data_to_developers(filename, data)
|
1205
|
+
|
1206
|
+
|
1207
|
+
def send_data_to_developers(filename, data):
|
1208
|
+
"""
|
1209
|
+
Sends crash log to a server using rfc1341 7.2 The multipart Content-Type
|
1210
|
+
https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
|
1211
|
+
|
1212
|
+
@param filename: filename to use when sending file
|
1213
|
+
@param data: data to send
|
1214
|
+
@return:
|
1215
|
+
"""
|
1216
|
+
import socket
|
1217
|
+
|
1218
|
+
host = MEERK40T_HOST # Replace with the actual host
|
1219
|
+
port = 80 # Replace with the actual port
|
1220
|
+
|
1221
|
+
# Construct the HTTP request
|
1222
|
+
boundary = "----------------meerk40t-boundary"
|
1223
|
+
body = (
|
1224
|
+
f"--{boundary}\r\n"
|
1225
|
+
f'Content-Disposition: form-data; name="file"; filename="{filename}"\r\n'
|
1226
|
+
f"Content-Type: text/plain\r\n"
|
1227
|
+
"\r\n"
|
1228
|
+
f"{data}\r\n"
|
1229
|
+
f"--{boundary}--\r\n"
|
1230
|
+
)
|
1231
|
+
|
1232
|
+
headers = (
|
1233
|
+
f"POST /upload HTTP/1.1\r\n"
|
1234
|
+
f"Host: {host}\r\n"
|
1235
|
+
"User-Agent: meerk40t/1.0.0\r\n"
|
1236
|
+
f"Content-Type: multipart/form-data; boundary={boundary}\r\n"
|
1237
|
+
f"Content-Length: {len(body)}\r\n"
|
1238
|
+
"\r\n"
|
1239
|
+
)
|
1240
|
+
|
1241
|
+
try:
|
1242
|
+
# Create a socket connection
|
1243
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client_socket:
|
1244
|
+
client_socket.connect((host, port))
|
1245
|
+
|
1246
|
+
# Send the request
|
1247
|
+
request = f"{headers}{body}"
|
1248
|
+
client_socket.sendall(request.encode())
|
1249
|
+
|
1250
|
+
# Receive and print the response
|
1251
|
+
response = client_socket.recv(4096)
|
1252
|
+
response = response.decode("utf-8", errors="ignore")
|
1253
|
+
except Exception:
|
1254
|
+
response = ""
|
1255
|
+
|
1256
|
+
response_lines = response.split("\n")
|
1257
|
+
http_code = response_lines[0]
|
1258
|
+
|
1259
|
+
print(response)
|
1260
|
+
|
1261
|
+
if http_code.startswith("HTTP/1.1 200 OK"):
|
1262
|
+
message = response_lines[-1]
|
1263
|
+
dlg = wx.MessageDialog(
|
1264
|
+
None,
|
1265
|
+
_("We got your message. Thank you for helping\n\n") + message,
|
1266
|
+
_("Thanks"),
|
1267
|
+
wx.OK,
|
1268
|
+
)
|
1269
|
+
dlg.ShowModal()
|
1270
|
+
dlg.Destroy()
|
1271
|
+
else:
|
1272
|
+
# print(response)
|
1273
|
+
MEERK40T_ISSUES = "https://github.com/meerk40t/meerk40t/issues"
|
1274
|
+
dlg = wx.MessageDialog(
|
1275
|
+
None,
|
1276
|
+
_(
|
1277
|
+
"We're sorry, that didn't work. Raise an issue on the github please.\n\n "
|
1278
|
+
"The log file will be in your working directory.\n"
|
1279
|
+
)
|
1280
|
+
+ MEERK40T_ISSUES
|
1281
|
+
+ "\n\n"
|
1282
|
+
+ str(http_code),
|
1283
|
+
_("Thanks"),
|
1284
|
+
wx.OK,
|
1285
|
+
)
|
1286
|
+
dlg.ShowModal()
|
1287
|
+
dlg.Destroy()
|
1288
|
+
|
1289
|
+
|
1290
|
+
in_error_dialog = False
|
1291
|
+
|
1292
|
+
|
1293
|
+
def handleGUIException(exc_type, exc_value, exc_traceback):
|
1294
|
+
"""
|
1295
|
+
Handler for errors. Save error to a file, and create dialog.
|
1296
|
+
|
1297
|
+
@param exc_type:
|
1298
|
+
@param exc_value:
|
1299
|
+
@param exc_traceback:
|
1300
|
+
@return:
|
1301
|
+
"""
|
1302
|
+
|
1303
|
+
def _extended_dialog(caption, header, body):
|
1304
|
+
dlg = wx.Dialog(
|
1305
|
+
None,
|
1306
|
+
wx.ID_ANY,
|
1307
|
+
title=caption,
|
1308
|
+
size=wx.DefaultSize,
|
1309
|
+
pos=wx.DefaultPosition,
|
1310
|
+
style=wx.DEFAULT_DIALOG_STYLE,
|
1311
|
+
)
|
1312
|
+
# contents
|
1313
|
+
sizer = wx.BoxSizer(wx.VERTICAL)
|
1314
|
+
|
1315
|
+
label = wxStaticText(dlg, wx.ID_ANY, header)
|
1316
|
+
sizer.Add(label, 1, wx.EXPAND, 0)
|
1317
|
+
info = TextCtrl(dlg, wx.ID_ANY, style=wx.TE_MULTILINE | wx.TE_READONLY)
|
1318
|
+
info.SetValue(body)
|
1319
|
+
sizer.Add(info, 5, wx.EXPAND, 0)
|
1320
|
+
btnsizer = wx.StdDialogButtonSizer()
|
1321
|
+
btn_yes = wxButton(dlg, wx.ID_YES)
|
1322
|
+
btn_yes.SetDefault()
|
1323
|
+
btnsizer.AddButton(btn_yes)
|
1324
|
+
btn_no = wxButton(dlg, wx.ID_NO)
|
1325
|
+
btnsizer.AddButton(btn_no)
|
1326
|
+
btn_cancel = wxButton(dlg, wx.ID_CANCEL, _("Quit"))
|
1327
|
+
btnsizer.AddButton(btn_cancel)
|
1328
|
+
btnsizer.Realize()
|
1329
|
+
sizer.Add(btnsizer, 0, wx.EXPAND, 0)
|
1330
|
+
btnsizer.SetAffirmativeButton(btn_yes)
|
1331
|
+
btnsizer.SetNegativeButton(btn_no)
|
1332
|
+
btnsizer.SetCancelButton(btn_cancel)
|
1333
|
+
|
1334
|
+
def close_yes(event):
|
1335
|
+
dlg.EndModal(wx.ID_YES)
|
1336
|
+
|
1337
|
+
def close_no(event):
|
1338
|
+
dlg.EndModal(wx.ID_NO)
|
1339
|
+
|
1340
|
+
def close_cancel(event):
|
1341
|
+
wx.Abort()
|
1342
|
+
|
1343
|
+
dlg.Bind(wx.EVT_BUTTON, close_yes, btn_yes)
|
1344
|
+
dlg.Bind(wx.EVT_BUTTON, close_no, btn_no)
|
1345
|
+
dlg.Bind(wx.EVT_BUTTON, close_cancel, btn_cancel)
|
1346
|
+
dlg.SetSizer(sizer)
|
1347
|
+
sizer.Fit(dlg)
|
1348
|
+
dlg.CenterOnScreen()
|
1349
|
+
return dlg
|
1350
|
+
|
1351
|
+
def _variable_summary(vars, indent: int = 0):
|
1352
|
+
info = ""
|
1353
|
+
for name, value in vars.items():
|
1354
|
+
label = f'{" " * indent}{name} : '
|
1355
|
+
total_indent = len(label)
|
1356
|
+
formatted = str(value)
|
1357
|
+
formatted = formatted.replace("\n", "\n" + " " * total_indent)
|
1358
|
+
info += f"{label}{formatted}\n"
|
1359
|
+
return info
|
1360
|
+
|
1361
|
+
global in_error_dialog
|
1362
|
+
if in_error_dialog:
|
1363
|
+
return
|
1364
|
+
in_error_dialog = True
|
1365
|
+
|
1366
|
+
wxversion = "wx"
|
1367
|
+
try:
|
1368
|
+
wxversion = wx.version()
|
1369
|
+
except:
|
1370
|
+
pass
|
1371
|
+
filename = os.path.join(get_safe_path(APPLICATION_NAME), "_crash")
|
1372
|
+
try:
|
1373
|
+
with open(filename, "w") as file:
|
1374
|
+
file.write("MeerK40 crash indicator - you may ignore or delete it.")
|
1375
|
+
except Exception as e:
|
1376
|
+
pass
|
1377
|
+
|
1378
|
+
error_log = (
|
1379
|
+
f"MeerK40t crash log. Version: {APPLICATION_VERSION} on {platform.system()}: "
|
1380
|
+
f"Python {platform.python_version()}: {platform.machine()} - wxPython: {wxversion}\n"
|
1381
|
+
)
|
1382
|
+
error_log += "".join(traceback.format_exception(exc_type, exc_value, exc_traceback))
|
1383
|
+
variable_info = ""
|
1384
|
+
try:
|
1385
|
+
variable_info = "\nLocal variables:\n"
|
1386
|
+
tb = exc_traceback
|
1387
|
+
while tb:
|
1388
|
+
frame = tb.tb_frame
|
1389
|
+
code = frame.f_code
|
1390
|
+
source = f"{code.co_filename}:{tb.tb_lineno}, in {code.co_name}"
|
1391
|
+
variable_info += f"[{source}]:\n" + _variable_summary(frame.f_locals)
|
1392
|
+
tb = tb.tb_next
|
1393
|
+
except Exception:
|
1394
|
+
pass
|
1395
|
+
try:
|
1396
|
+
filename = f"MeerK40t-{datetime.now():%Y-%m-%d_%H_%M_%S}.txt"
|
1397
|
+
except Exception: # I already crashed once, if there's another here just ignore it.
|
1398
|
+
filename = "MeerK40t-Crash.txt"
|
1399
|
+
|
1400
|
+
try:
|
1401
|
+
try:
|
1402
|
+
with open(filename, "w", encoding="utf8") as file:
|
1403
|
+
file.write(error_log)
|
1404
|
+
if variable_info:
|
1405
|
+
file.write(variable_info)
|
1406
|
+
print(error_log)
|
1407
|
+
except PermissionError:
|
1408
|
+
filename = os.path.join(get_safe_path(APPLICATION_NAME), filename)
|
1409
|
+
with open(filename, "w", encoding="utf8") as file:
|
1410
|
+
file.write(error_log)
|
1411
|
+
if variable_info:
|
1412
|
+
file.write(variable_info)
|
1413
|
+
print(error_log)
|
1414
|
+
except Exception:
|
1415
|
+
# I already crashed once, if there's another here just ignore it.
|
1416
|
+
pass
|
1417
|
+
|
1418
|
+
# Ask to send file.
|
1419
|
+
message = _(
|
1420
|
+
"""The bad news is that MeerK40t encountered a crash, and the developers apologise for this bug!
|
1421
|
+
|
1422
|
+
The good news is that you can help us fix this bug by anonymously sending us the crash details."""
|
1423
|
+
)
|
1424
|
+
message += "\n" + _(
|
1425
|
+
"Only the crash details below are sent. No data from your MeerK40t project is sent. No "
|
1426
|
+
+ "personal information is sent either.\n"
|
1427
|
+
+ "Send the following data to the MeerK40t team?"
|
1428
|
+
)
|
1429
|
+
caption = _("Crash Detected! Send Log?")
|
1430
|
+
data = error_log
|
1431
|
+
if variable_info:
|
1432
|
+
data += "\n" + variable_info
|
1433
|
+
try:
|
1434
|
+
dlg = _extended_dialog(caption, message, data)
|
1435
|
+
answer = dlg.ShowModal()
|
1436
|
+
dlg.Destroy()
|
1437
|
+
except Exception as e:
|
1438
|
+
answer = wx.ID_NO
|
1439
|
+
# print (answer)
|
1440
|
+
in_error_dialog = False
|
1441
|
+
if answer in (wx.ID_YES, wx.ID_OK, wx.ID_CLOSE):
|
1442
|
+
send_data_to_developers(filename, data)
|
1443
|
+
if answer == wx.ID_CANCEL:
|
1444
|
+
wx.Abort()
|