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/tips.py
ADDED
@@ -0,0 +1,591 @@
|
|
1
|
+
"""
|
2
|
+
A simple module to display some startup tips.
|
3
|
+
You can add more tips, every tip has three elements:
|
4
|
+
a) the info-text to display in the panel
|
5
|
+
b) an (optional) command to be executed in the 'Try it out' button
|
6
|
+
c) an (optional) image (url) to be shown
|
7
|
+
"""
|
8
|
+
import os
|
9
|
+
import urllib
|
10
|
+
import webbrowser
|
11
|
+
|
12
|
+
import wx
|
13
|
+
|
14
|
+
from ..kernel import get_safe_path
|
15
|
+
from .icons import (
|
16
|
+
icon_outline,
|
17
|
+
icon_youtube,
|
18
|
+
icons8_circled_left,
|
19
|
+
icons8_circled_right,
|
20
|
+
icons8_console,
|
21
|
+
icons8_detective,
|
22
|
+
icons8_light_on,
|
23
|
+
icons8_manager,
|
24
|
+
)
|
25
|
+
from .mwindow import MWindow
|
26
|
+
from .wxutils import TextCtrl, dip_size, wxButton, wxCheckBox, wxStaticBitmap, wxStaticText
|
27
|
+
|
28
|
+
_ = wx.GetTranslation
|
29
|
+
|
30
|
+
|
31
|
+
class TipPanel(wx.Panel):
|
32
|
+
"""
|
33
|
+
Display MeerK40t usage tips
|
34
|
+
"""
|
35
|
+
|
36
|
+
def __init__(self, *args, context=None, **kwds):
|
37
|
+
# begin wxGlade: PositionPanel.__init__
|
38
|
+
kwds["style"] = kwds.get("style", 0) | wx.TAB_TRAVERSAL
|
39
|
+
wx.Panel.__init__(self, *args, **kwds)
|
40
|
+
self.context = context
|
41
|
+
self.context.themes.set_window_colors(self)
|
42
|
+
self.tip_command = ""
|
43
|
+
self.tip_image = ""
|
44
|
+
self.tips = []
|
45
|
+
|
46
|
+
safe_dir = os.path.realpath(get_safe_path(self.context.kernel.name))
|
47
|
+
self.local_file = os.path.join(safe_dir, "tips.txt")
|
48
|
+
|
49
|
+
self.setup_tips()
|
50
|
+
self.context.setting(bool, "show_tips", True)
|
51
|
+
# Has the user already agreed to download automatically
|
52
|
+
# if it can't be found? Defaults to False - please note that the
|
53
|
+
# consent will be set to False by default
|
54
|
+
consent = self.context.setting(bool, "tip_access_consent", False)
|
55
|
+
|
56
|
+
# Reset for debug purposes
|
57
|
+
# self.context.tip_access_consent = False
|
58
|
+
self.SetHelpText("tips")
|
59
|
+
icon_size = dip_size(self, 25, 25)
|
60
|
+
icon_size *= self.context.root.bitmap_correction_scale
|
61
|
+
# Main Sizer
|
62
|
+
sizer_main = wx.BoxSizer(wx.VERTICAL)
|
63
|
+
self.image_tip = wxStaticBitmap(self, wx.ID_ANY, style=wx.SB_FLAT)
|
64
|
+
self.image_tip.SetMinSize(dip_size(self, 250, -1))
|
65
|
+
self.no_image_message = TextCtrl(self, wx.ID_ANY, _("Image missing!"))
|
66
|
+
self.no_image_message.SetToolTip(
|
67
|
+
_(
|
68
|
+
"Couldn't find the cached image for this tip!\nNo permissions to download from the internet."
|
69
|
+
)
|
70
|
+
)
|
71
|
+
self.no_image_message.Show(False)
|
72
|
+
# self.image_tip.SetMaxSize(wx.Size(250, -1))
|
73
|
+
# self.image_tip.SetSize(wx.Size(250, -1))
|
74
|
+
self.text_tip = TextCtrl(
|
75
|
+
self, wx.ID_ANY, "", style=wx.TE_READONLY | wx.TE_MULTILINE
|
76
|
+
)
|
77
|
+
tip_area = wx.BoxSizer(wx.HORIZONTAL)
|
78
|
+
tip_area.Add(self.no_image_message, 1, wx.ALIGN_CENTER_VERTICAL, 0)
|
79
|
+
tip_area.Add(self.image_tip, 1, wx.EXPAND, 0)
|
80
|
+
tip_area.Add(self.text_tip, 3, wx.EXPAND, 0)
|
81
|
+
|
82
|
+
sizer_main.Add(tip_area, 1, wx.EXPAND, 0)
|
83
|
+
button_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
84
|
+
self.button_prev = wxButton(self, wx.ID_ANY, _("Previous tip"))
|
85
|
+
self.button_prev.SetBitmap(icons8_circled_left.GetBitmap(resize=icon_size[0]))
|
86
|
+
self.button_prev.SetToolTip(_("Jump back to the previously displayed tip"))
|
87
|
+
|
88
|
+
self.label_position = wxStaticText(
|
89
|
+
self, wx.ID_ANY, "", style=wx.ALIGN_CENTRE_HORIZONTAL
|
90
|
+
)
|
91
|
+
|
92
|
+
self.button_next = wxButton(self, wx.ID_ANY, _("Next tip"))
|
93
|
+
self.button_next.SetBitmap(icons8_circled_right.GetBitmap(resize=icon_size[0]))
|
94
|
+
self.button_next.SetToolTip(_("Jump to the next tip"))
|
95
|
+
|
96
|
+
button_sizer.Add(self.button_prev, 0, wx.ALIGN_CENTER_VERTICAL, 0)
|
97
|
+
button_sizer.Add(self.label_position, 1, wx.ALIGN_CENTER_VERTICAL, 0)
|
98
|
+
button_sizer.Add(self.button_next, 0, wx.ALIGN_CENTER_VERTICAL, 0)
|
99
|
+
sizer_main.Add(button_sizer, 0, wx.EXPAND, 0)
|
100
|
+
|
101
|
+
self.check_startup = wxCheckBox(self, wx.ID_ANY, _("Show tips at startup"))
|
102
|
+
self.check_startup.SetToolTip(
|
103
|
+
_(
|
104
|
+
"Show tips at program start.\n"
|
105
|
+
+ "Even if disabled, 'Tips & Tricks' are always available in the Help-menu."
|
106
|
+
)
|
107
|
+
)
|
108
|
+
self.check_startup.SetValue(self.context.show_tips)
|
109
|
+
|
110
|
+
option_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
111
|
+
self.button_try = wxButton(self, wx.ID_ANY, _("Try it out"))
|
112
|
+
self.button_try.SetToolTip(
|
113
|
+
_(
|
114
|
+
"Launch an example, please be aware that this might change your design,\n"
|
115
|
+
+ "as new elements could be created to show the functionality"
|
116
|
+
)
|
117
|
+
)
|
118
|
+
self.button_try.SetBitmap(icons8_detective.GetBitmap(resize=icon_size[0]))
|
119
|
+
self.checkbox_update = wxCheckBox(self, wx.ID_ANY, _("Automatically Update"))
|
120
|
+
self.checkbox_update.SetFont(
|
121
|
+
wx.Font(8, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
|
122
|
+
)
|
123
|
+
self.checkbox_update.SetToolTip(
|
124
|
+
_(
|
125
|
+
"Look for new tips on MeerK40ts website.\n"
|
126
|
+
+ "The list of tips is constantly expanded.\n"
|
127
|
+
)
|
128
|
+
)
|
129
|
+
self.checkbox_update.SetValue(consent)
|
130
|
+
option_sizer.Add(self.button_try, 0, wx.ALIGN_CENTER_VERTICAL)
|
131
|
+
option_sizer.AddStretchSpacer()
|
132
|
+
option_sizer.Add(self.checkbox_update, 0, wx.ALIGN_CENTER_VERTICAL, 0)
|
133
|
+
option_sizer.Add(self.check_startup, 0, wx.ALIGN_CENTER_VERTICAL, 0)
|
134
|
+
sizer_main.Add(option_sizer, 0, wx.EXPAND, 0)
|
135
|
+
|
136
|
+
self.SetSizer(sizer_main)
|
137
|
+
sizer_main.Fit(self)
|
138
|
+
|
139
|
+
self.check_startup.Bind(wx.EVT_CHECKBOX, self.on_check_startup)
|
140
|
+
self.button_prev.Bind(wx.EVT_BUTTON, self.on_tip_prev)
|
141
|
+
self.button_next.Bind(wx.EVT_BUTTON, self.on_tip_next)
|
142
|
+
self.button_try.Bind(wx.EVT_BUTTON, self.on_button_try)
|
143
|
+
self.checkbox_update.Bind(wx.EVT_CHECKBOX, self.on_check_consent)
|
144
|
+
|
145
|
+
self.cache_dir = self.establish_picture_cache()
|
146
|
+
self.context.setting(int, "next_tip", 0)
|
147
|
+
self.current_tip = self.context.next_tip
|
148
|
+
if consent:
|
149
|
+
self.update_tips()
|
150
|
+
|
151
|
+
@property
|
152
|
+
def current_tip(self):
|
153
|
+
return self._current_tip
|
154
|
+
|
155
|
+
@current_tip.setter
|
156
|
+
def current_tip(self, newvalue):
|
157
|
+
if newvalue < 0:
|
158
|
+
newvalue = len(self.tips) - 1
|
159
|
+
if newvalue >= len(self.tips):
|
160
|
+
newvalue = 0
|
161
|
+
self._current_tip = newvalue
|
162
|
+
# Store it for the next session
|
163
|
+
self.context.next_tip = newvalue + 1
|
164
|
+
self.load_tip()
|
165
|
+
|
166
|
+
def load_tip(self):
|
167
|
+
if len(self.tips) == 0:
|
168
|
+
return
|
169
|
+
if self._current_tip >= len(self.tips):
|
170
|
+
self._current_tip = 0
|
171
|
+
my_tip = self.tips[self._current_tip]
|
172
|
+
self.text_tip.SetValue(my_tip[0])
|
173
|
+
if my_tip[1]:
|
174
|
+
self.button_try.Show(True)
|
175
|
+
self.tip_command = my_tip[1]
|
176
|
+
else:
|
177
|
+
self.button_try.Show(False)
|
178
|
+
self.tip_command = ""
|
179
|
+
have_img = False
|
180
|
+
if my_tip[2]:
|
181
|
+
have_img = self.set_tip_image(
|
182
|
+
my_tip[2], self._current_tip, self.context.tip_access_consent
|
183
|
+
)
|
184
|
+
if not have_img:
|
185
|
+
# Let's use the default image...
|
186
|
+
have_img = self.set_tip_image(
|
187
|
+
icons8_light_on.GetBitmap(resize=200),
|
188
|
+
self._current_tip,
|
189
|
+
self.context.tip_access_consent,
|
190
|
+
)
|
191
|
+
|
192
|
+
# self.set_tip_image("", self._current_tip, self.context.tip_access_consent)
|
193
|
+
self.label_position.SetLabel(
|
194
|
+
_("Tip {idx}/{maxidx}").format(
|
195
|
+
idx=self._current_tip + 1, maxidx=len(self.tips)
|
196
|
+
)
|
197
|
+
)
|
198
|
+
self.Layout()
|
199
|
+
|
200
|
+
def _download_image(self, uri, local_file):
|
201
|
+
"""
|
202
|
+
Download image from given URI to local_file.
|
203
|
+
@param uri:
|
204
|
+
@param local_file:
|
205
|
+
@return:
|
206
|
+
"""
|
207
|
+
if not self.context.tip_access_consent:
|
208
|
+
raise PermissionError("We do not have consent to download.")
|
209
|
+
try:
|
210
|
+
with urllib.request.urlopen(uri) as file:
|
211
|
+
content = file.read()
|
212
|
+
except Exception as e:
|
213
|
+
# print (f"Error: {e}")
|
214
|
+
return False
|
215
|
+
# If the file object is successfully opened, read its content as a string
|
216
|
+
try:
|
217
|
+
with open(local_file, "wb") as f:
|
218
|
+
f.write(content)
|
219
|
+
return True
|
220
|
+
except (OSError, PermissionError, RuntimeError) as e:
|
221
|
+
# print (f"Error @ image write to {local_path}: {e}")
|
222
|
+
return False
|
223
|
+
|
224
|
+
def set_tip_image(self, path, counter, automatic_download):
|
225
|
+
"""
|
226
|
+
path: URL of the image to be loaded
|
227
|
+
counter: an additional naming element to
|
228
|
+
avoid ending up with the same name for equally called images
|
229
|
+
display: apply and display the image
|
230
|
+
"""
|
231
|
+
# print (f"Image request: flag={automatic_download}, consent={self.context.tip_access_consent}, {path}\n")
|
232
|
+
self.no_image_message.Show(False)
|
233
|
+
if isinstance(path, wx.Bitmap):
|
234
|
+
self.image_tip.SetBitmap(path)
|
235
|
+
self.image_tip.Show(True)
|
236
|
+
return True
|
237
|
+
|
238
|
+
# self.image_tip.SetBitmap(wx.NullBitmap)
|
239
|
+
self.image_tip.Show(False)
|
240
|
+
self.tip_image = path
|
241
|
+
if not path or not self.cache_dir:
|
242
|
+
# Path was not established
|
243
|
+
return False
|
244
|
+
|
245
|
+
parts = path.split("/")
|
246
|
+
if len(parts) <= 0:
|
247
|
+
# Malformed path.
|
248
|
+
return False
|
249
|
+
|
250
|
+
# basename = f"_{counter}_{parts[-1]}"
|
251
|
+
basename = hex(hash(path))
|
252
|
+
local_path = os.path.join(self.cache_dir, basename)
|
253
|
+
if not local_path:
|
254
|
+
return False
|
255
|
+
# Is this file already on the disk? If not load it...
|
256
|
+
if not os.path.exists(local_path):
|
257
|
+
if automatic_download:
|
258
|
+
found = self._download_image(path, local_path)
|
259
|
+
# We still need to scale and display it
|
260
|
+
else:
|
261
|
+
self.no_image_message.Show(True)
|
262
|
+
if not os.path.exists(local_path):
|
263
|
+
# File still does not exist.
|
264
|
+
self.no_image_message.Show(True)
|
265
|
+
return False
|
266
|
+
|
267
|
+
bmp = wx.Bitmap()
|
268
|
+
try:
|
269
|
+
res = bmp.LoadFile(local_path)
|
270
|
+
if res:
|
271
|
+
new_x, new_y = bmp.Size
|
272
|
+
if new_x == 0 or new_y == 0:
|
273
|
+
res = False
|
274
|
+
except Exception:
|
275
|
+
res = False
|
276
|
+
if not res:
|
277
|
+
# Bitmap failed to load.
|
278
|
+
self.no_image_message.Show(True)
|
279
|
+
return False
|
280
|
+
new_x, new_y = bmp.Size
|
281
|
+
img_size = self.image_tip.GetSize()
|
282
|
+
# print(f"bmp: {int(new_x)}x{int(new_y)}, space: {img_size[0]}x{img_size[1]}")
|
283
|
+
if new_x > img_size[0] or new_y > img_size[1]:
|
284
|
+
if new_x > img_size[0]:
|
285
|
+
fact = img_size[0] / new_x
|
286
|
+
new_y *= fact
|
287
|
+
new_x *= fact
|
288
|
+
if new_y > img_size[1]:
|
289
|
+
fact = img_size[1] / new_y
|
290
|
+
new_y *= fact
|
291
|
+
new_x *= fact
|
292
|
+
image = bmp.ConvertToImage()
|
293
|
+
# print(f"Will be rescaled to {int(new_x)}x{int(new_y)}")
|
294
|
+
image.Rescale(int(new_x), int(new_y))
|
295
|
+
bmp = wx.Bitmap(image)
|
296
|
+
|
297
|
+
try:
|
298
|
+
self.image_tip.SetScaleMode(wxStaticBitmap.Scale_None)
|
299
|
+
except AttributeError:
|
300
|
+
# Old version of wxpython
|
301
|
+
pass
|
302
|
+
self.image_tip.SetBitmap(bmp)
|
303
|
+
self.image_tip.Show(True)
|
304
|
+
return True
|
305
|
+
|
306
|
+
def on_button_try(self, event):
|
307
|
+
if self.tip_command:
|
308
|
+
if self.tip_command.startswith("http"):
|
309
|
+
webbrowser.open(self.tip_command, new=0, autoraise=True)
|
310
|
+
else:
|
311
|
+
self.context(f"{self.tip_command}\n")
|
312
|
+
|
313
|
+
def on_check_consent(self, event):
|
314
|
+
state = self.checkbox_update.GetValue()
|
315
|
+
self.context.tip_access_consent = state
|
316
|
+
self.load_tip()
|
317
|
+
if state:
|
318
|
+
self.update_tips()
|
319
|
+
|
320
|
+
def on_check_startup(self, event):
|
321
|
+
state = self.check_startup.GetValue()
|
322
|
+
self.context.show_tips = state
|
323
|
+
|
324
|
+
def on_tip_prev(self, event):
|
325
|
+
self.current_tip -= 1
|
326
|
+
|
327
|
+
def on_tip_next(self, event):
|
328
|
+
self.current_tip += 1
|
329
|
+
|
330
|
+
def setup_tips(self):
|
331
|
+
self.tips.clear()
|
332
|
+
# This initial list of tips does contain only very basic and very limited tips
|
333
|
+
# and very intentional does not have any image resources from the web.
|
334
|
+
# The user has the opportunity to download more and more sophisticated tips
|
335
|
+
# by clicking the update button.
|
336
|
+
self.tips.append(
|
337
|
+
(
|
338
|
+
_(
|
339
|
+
"Do you want to get extended information about a feature in MeerK40t?\n"
|
340
|
+
+ "Just place your mouse over a window or an UI-element and press F11."
|
341
|
+
),
|
342
|
+
"",
|
343
|
+
icons8_light_on.GetBitmap(resize=200),
|
344
|
+
)
|
345
|
+
)
|
346
|
+
self.tips.append(
|
347
|
+
(
|
348
|
+
_(
|
349
|
+
"MeerK40t supports more than 'just' a K40 laser.\n"
|
350
|
+
+ "You can add more devices in the Device-Manager.\n"
|
351
|
+
+ "And you can even add multiple instances for the same physical device, "
|
352
|
+
+ "where you can have different configuration settings (eg regular and rotary)."
|
353
|
+
),
|
354
|
+
"window open DeviceManager",
|
355
|
+
icons8_manager.GetBitmap(resize=200),
|
356
|
+
),
|
357
|
+
)
|
358
|
+
self.tips.append(
|
359
|
+
(
|
360
|
+
_(
|
361
|
+
"There are a couple of YouTube-videos that deal with some specific functionalities and explain their usage:\n"
|
362
|
+
+ "https://www.youtube.com/channel/UCsAUV23O2FyKxC0HN7nkAQQ"
|
363
|
+
),
|
364
|
+
"https://www.youtube.com/channel/UCsAUV23O2FyKxC0HN7nkAQQ",
|
365
|
+
icon_youtube.GetBitmap(resize=200),
|
366
|
+
)
|
367
|
+
)
|
368
|
+
self.tips.append(
|
369
|
+
(
|
370
|
+
_(
|
371
|
+
"More instructional videos? Sure, here is another channel:\n\n"
|
372
|
+
+ "https://www.youtube.com/channel/UCMN9gGvpacxZINPZCSOecaQ"
|
373
|
+
),
|
374
|
+
"https://www.youtube.com/channel/UCMN9gGvpacxZINPZCSOecaQ",
|
375
|
+
icon_youtube.GetBitmap(resize=200),
|
376
|
+
)
|
377
|
+
)
|
378
|
+
self.tips.append(
|
379
|
+
(
|
380
|
+
_(
|
381
|
+
"MeerK40t can create a so called outline around an element.\nJust select the element, right click on top of it to get the context menu and choose from the 'Outline elements' menu..."
|
382
|
+
),
|
383
|
+
"rect 2cm 2cm 4cm 4cm fill black outline 2mm --steps 4 --outer stroke red",
|
384
|
+
icon_outline.GetBitmap(resize=200),
|
385
|
+
),
|
386
|
+
)
|
387
|
+
self.tips.append(
|
388
|
+
(
|
389
|
+
_(
|
390
|
+
"MeerK40t has an extensive set of commands that allow a lot of scriptable actions.\nJust open the console window and type 'help'"
|
391
|
+
),
|
392
|
+
"pane show console\nhelp",
|
393
|
+
icons8_console.GetBitmap(resize=200),
|
394
|
+
),
|
395
|
+
)
|
396
|
+
self.tips.append(
|
397
|
+
(
|
398
|
+
_(
|
399
|
+
"Do you want to see more Tips & Tricks?\n"
|
400
|
+
+ "Just click on the 'Update'-button to load additional hints from MeerK40ts website.\n"
|
401
|
+
+ "The list of tips is constantly expanded, so please update it every now and then to learn about new or hidden features."
|
402
|
+
),
|
403
|
+
"",
|
404
|
+
icons8_light_on.GetBitmap(resize=200),
|
405
|
+
),
|
406
|
+
)
|
407
|
+
|
408
|
+
self.load_tips_from_local_cache()
|
409
|
+
|
410
|
+
def update_tips(self):
|
411
|
+
"""
|
412
|
+
Called on startup if permission is given. And called when checkbox is checked.
|
413
|
+
@return:
|
414
|
+
"""
|
415
|
+
self.load_tips_from_github()
|
416
|
+
self.setup_tips()
|
417
|
+
self.load_tip()
|
418
|
+
|
419
|
+
def load_tips_from_github(self):
|
420
|
+
successful = False
|
421
|
+
|
422
|
+
content = ""
|
423
|
+
url = "https://github.com/meerk40t/meerk40t/raw/main/locale/"
|
424
|
+
# Do we have a localized version?
|
425
|
+
locale = "en"
|
426
|
+
lang = self.context.language
|
427
|
+
if lang is None:
|
428
|
+
lang = 0
|
429
|
+
languages = list(self.context.app.supported_languages)
|
430
|
+
try:
|
431
|
+
locale = languages[lang][0]
|
432
|
+
except IndexError:
|
433
|
+
pass
|
434
|
+
# print(self.context.language, locale, languages)
|
435
|
+
if locale and locale != "en":
|
436
|
+
try:
|
437
|
+
with urllib.request.urlopen(url + locale + "/tips.txt") as file:
|
438
|
+
content = file.read().decode("utf-8", errors="ignore")
|
439
|
+
successful = True
|
440
|
+
except Exception:
|
441
|
+
pass
|
442
|
+
|
443
|
+
# if we don't have anything localized then let's use the english master
|
444
|
+
if not successful:
|
445
|
+
try:
|
446
|
+
with urllib.request.urlopen(url + "tips.txt") as file:
|
447
|
+
content = file.read().decode("utf-8", errors="ignore")
|
448
|
+
successful = True
|
449
|
+
except Exception as e:
|
450
|
+
# print (f"Error: {e}")
|
451
|
+
pass
|
452
|
+
|
453
|
+
if successful:
|
454
|
+
# Store the result to the local cache file
|
455
|
+
if len(content):
|
456
|
+
try:
|
457
|
+
with open(self.local_file, mode="w") as f:
|
458
|
+
f.write(content)
|
459
|
+
except (OSError, RuntimeError, PermissionError, FileNotFoundError):
|
460
|
+
pass
|
461
|
+
|
462
|
+
def load_tips_from_local_cache(self):
|
463
|
+
def comparable_version(version):
|
464
|
+
"""
|
465
|
+
Return a comparable sequence from a version string
|
466
|
+
"""
|
467
|
+
result = list()
|
468
|
+
if version is not None:
|
469
|
+
if version.startswith("v"):
|
470
|
+
version = version[1:]
|
471
|
+
if " " in version:
|
472
|
+
version, ending = version.split(" ", 1)
|
473
|
+
result = list(map(int, version.split(".")))
|
474
|
+
if len(result) > 3:
|
475
|
+
result = result[0:2]
|
476
|
+
while len(result) < 3:
|
477
|
+
result.append(0)
|
478
|
+
return result
|
479
|
+
|
480
|
+
def add_tip(tip, cmd, img, version, current_version):
|
481
|
+
if version:
|
482
|
+
minimal_version = comparable_version(version)
|
483
|
+
# print (f"comparing {current_version} to {minimal_version}")
|
484
|
+
if current_version < minimal_version:
|
485
|
+
tip = ""
|
486
|
+
if tip:
|
487
|
+
# Replace '\n' with real line breaks
|
488
|
+
tip = tip.replace(r"\n", "\n")
|
489
|
+
if cmd:
|
490
|
+
cmd = cmd.replace(r"\n", "\n")
|
491
|
+
self.tips.append((tip, cmd, img))
|
492
|
+
|
493
|
+
myversion = comparable_version(self.context.kernel.version)
|
494
|
+
|
495
|
+
try:
|
496
|
+
with open(self.local_file, mode="r") as f:
|
497
|
+
ver = ""
|
498
|
+
tip = ""
|
499
|
+
cmd = ""
|
500
|
+
img = ""
|
501
|
+
lastline_was_tip = False
|
502
|
+
for line in f:
|
503
|
+
cline = line.strip()
|
504
|
+
if cline.startswith("#") or len(cline) == 0:
|
505
|
+
continue
|
506
|
+
if cline.startswith("tip="):
|
507
|
+
lastline_was_tip = True
|
508
|
+
# Store previous
|
509
|
+
add_tip(tip, cmd, img, ver, myversion)
|
510
|
+
ver = ""
|
511
|
+
tip = cline[len("tip=") :]
|
512
|
+
cmd = ""
|
513
|
+
img = ""
|
514
|
+
elif cline.startswith("version="):
|
515
|
+
lastline_was_tip = False
|
516
|
+
ver = cline[len("version=") :]
|
517
|
+
elif cline.startswith("cmd="):
|
518
|
+
lastline_was_tip = False
|
519
|
+
cmd = cline[len("cmd=") :]
|
520
|
+
elif cline.startswith("image="):
|
521
|
+
lastline_was_tip = False
|
522
|
+
img = cline[len("image=") :]
|
523
|
+
elif cline.startswith("img="):
|
524
|
+
lastline_was_tip = False
|
525
|
+
img = cline[len("img=") :]
|
526
|
+
else:
|
527
|
+
if lastline_was_tip:
|
528
|
+
tip += "\n" + cline
|
529
|
+
|
530
|
+
# Something pending?
|
531
|
+
add_tip(tip, cmd, img, ver, myversion)
|
532
|
+
|
533
|
+
except (OSError, RuntimeError, PermissionError, FileNotFoundError):
|
534
|
+
return
|
535
|
+
|
536
|
+
def establish_picture_cache(self):
|
537
|
+
"""
|
538
|
+
Check for existence of a subdirectory to store images
|
539
|
+
and create it if not found
|
540
|
+
"""
|
541
|
+
safe_dir = os.path.realpath(get_safe_path(self.context.kernel.name))
|
542
|
+
cache_dir = os.path.join(safe_dir, "tip_images")
|
543
|
+
if not os.path.exists(cache_dir):
|
544
|
+
try:
|
545
|
+
os.mkdir(cache_dir)
|
546
|
+
except (OSError, PermissionError, RuntimeError):
|
547
|
+
cache_dir = ""
|
548
|
+
return cache_dir
|
549
|
+
|
550
|
+
def pane_show(self, *args):
|
551
|
+
self.load_tip()
|
552
|
+
|
553
|
+
def pane_hide(self, *args):
|
554
|
+
pass
|
555
|
+
|
556
|
+
|
557
|
+
class Tips(MWindow):
|
558
|
+
def __init__(self, *args, **kwds):
|
559
|
+
super().__init__(550, 350, *args, **kwds)
|
560
|
+
sizer = wx.BoxSizer(wx.VERTICAL)
|
561
|
+
self.panel = TipPanel(
|
562
|
+
self,
|
563
|
+
wx.ID_ANY,
|
564
|
+
context=self.context,
|
565
|
+
)
|
566
|
+
self.sizer.Add(self.panel, 1, wx.EXPAND, 0)
|
567
|
+
_icon = wx.NullIcon
|
568
|
+
_icon.CopyFromBitmap(icons8_detective.GetBitmap())
|
569
|
+
self.SetIcon(_icon)
|
570
|
+
self.SetTitle(_("Tips"))
|
571
|
+
self.Layout()
|
572
|
+
self.restore_aspect(honor_initial_values=True)
|
573
|
+
|
574
|
+
def window_open(self):
|
575
|
+
self.panel.pane_show()
|
576
|
+
self.CenterOnParent()
|
577
|
+
|
578
|
+
def window_close(self):
|
579
|
+
self.panel.pane_hide()
|
580
|
+
|
581
|
+
def delegates(self):
|
582
|
+
yield self.panel
|
583
|
+
|
584
|
+
@staticmethod
|
585
|
+
def submenu():
|
586
|
+
# Suppress...
|
587
|
+
return "Tips", "Tips", True
|
588
|
+
|
589
|
+
@staticmethod
|
590
|
+
def helptext():
|
591
|
+
return _("Display some tips and tricks how to best use MeerK40t")
|
@@ -1,35 +1,35 @@
|
|
1
|
-
import wx
|
2
|
-
|
3
|
-
|
4
|
-
class CircleBrush:
|
5
|
-
"""
|
6
|
-
Circular Brush to be drawn for area-based tools.
|
7
|
-
"""
|
8
|
-
|
9
|
-
def __init__(self):
|
10
|
-
self.tool_size = 100
|
11
|
-
self.pos = 0 + 0j
|
12
|
-
self.scale = 1.0
|
13
|
-
self.range = self.tool_size * self.scale
|
14
|
-
self.brush_fill = wx.Brush(wx.Colour(alpha=64, red=0, green=255, blue=0))
|
15
|
-
self.using = False
|
16
|
-
|
17
|
-
def set_location(self, x: float, y: float):
|
18
|
-
self.pos = complex(x, y)
|
19
|
-
|
20
|
-
def contains(self, x: float, y: float) -> bool:
|
21
|
-
c = complex(x, y)
|
22
|
-
return abs(self.pos - c) < self.range
|
23
|
-
|
24
|
-
def draw(self, gc: wx.GraphicsContext):
|
25
|
-
if self.using:
|
26
|
-
self.draw_brush(gc)
|
27
|
-
|
28
|
-
def draw_brush(self, gc: wx.GraphicsContext):
|
29
|
-
gc.SetBrush(self.brush_fill)
|
30
|
-
gc.DrawEllipse(
|
31
|
-
self.pos.real - self.tool_size / 2.0,
|
32
|
-
self.pos.imag - self.tool_size / 2.0,
|
33
|
-
self.tool_size,
|
34
|
-
self.tool_size,
|
35
|
-
)
|
1
|
+
import wx
|
2
|
+
|
3
|
+
|
4
|
+
class CircleBrush:
|
5
|
+
"""
|
6
|
+
Circular Brush to be drawn for area-based tools.
|
7
|
+
"""
|
8
|
+
|
9
|
+
def __init__(self):
|
10
|
+
self.tool_size = 100
|
11
|
+
self.pos = 0 + 0j
|
12
|
+
self.scale = 1.0
|
13
|
+
self.range = self.tool_size * self.scale
|
14
|
+
self.brush_fill = wx.Brush(wx.Colour(alpha=64, red=0, green=255, blue=0))
|
15
|
+
self.using = False
|
16
|
+
|
17
|
+
def set_location(self, x: float, y: float):
|
18
|
+
self.pos = complex(x, y)
|
19
|
+
|
20
|
+
def contains(self, x: float, y: float) -> bool:
|
21
|
+
c = complex(x, y)
|
22
|
+
return abs(self.pos - c) < self.range
|
23
|
+
|
24
|
+
def draw(self, gc: wx.GraphicsContext):
|
25
|
+
if self.using:
|
26
|
+
self.draw_brush(gc)
|
27
|
+
|
28
|
+
def draw_brush(self, gc: wx.GraphicsContext):
|
29
|
+
gc.SetBrush(self.brush_fill)
|
30
|
+
gc.DrawEllipse(
|
31
|
+
self.pos.real - self.tool_size / 2.0,
|
32
|
+
self.pos.imag - self.tool_size / 2.0,
|
33
|
+
self.tool_size,
|
34
|
+
self.tool_size,
|
35
|
+
)
|