meerk40t 0.9.3001__py2.py3-none-any.whl → 0.9.7020__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 +1194 -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 +1858 -1507
- meerk40t/core/elements/clipboard.py +229 -219
- meerk40t/core/elements/element_treeops.py +4595 -2837
- meerk40t/core/elements/element_types.py +125 -105
- meerk40t/core/elements/elements.py +4315 -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 +934 -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/testcases.py +105 -0
- 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 +463 -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 +204 -0
- meerk40t/extra/ezd.py +1165 -1165
- meerk40t/extra/hershey.py +834 -340
- meerk40t/extra/imageactions.py +322 -316
- meerk40t/extra/inkscape.py +628 -622
- meerk40t/extra/lbrn.py +424 -424
- meerk40t/extra/outerworld.py +283 -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 +1084 -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 +232 -133
- meerk40t/gui/choicepropertypanel.py +1662 -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 +1440 -846
- meerk40t/gui/icons.py +3422 -2747
- meerk40t/gui/imagesplitter.py +555 -508
- meerk40t/gui/keymap.py +354 -344
- meerk40t/gui/laserpanel.py +897 -806
- meerk40t/gui/laserrender.py +1470 -1232
- meerk40t/gui/lasertoolpanel.py +805 -793
- meerk40t/gui/magnetoptions.py +436 -0
- meerk40t/gui/materialmanager.py +2944 -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 +500 -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 +2471 -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 +592 -346
- meerk40t/gui/scenewidgets/relocatewidget.py +33 -33
- meerk40t/gui/scenewidgets/reticlewidget.py +83 -83
- meerk40t/gui/scenewidgets/selectionwidget.py +2958 -2756
- meerk40t/gui/simpleui.py +362 -333
- meerk40t/gui/simulation.py +2451 -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 +590 -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 +163 -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 +1447 -1169
- meerk40t/gui/wxmmain.py +5644 -4112
- meerk40t/gui/wxmribbon.py +1591 -1076
- meerk40t/gui/wxmscene.py +1631 -1453
- meerk40t/gui/wxmtree.py +2416 -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 +2793 -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 +3828 -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 +140 -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 +404 -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 +676 -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 +941 -940
- meerk40t/tools/rasterplotter.py +1660 -547
- meerk40t/tools/shxparser.py +1047 -901
- meerk40t/tools/ttfparser.py +726 -446
- meerk40t/tools/zinglplotter.py +595 -593
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/LICENSE +21 -21
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/METADATA +150 -139
- meerk40t-0.9.7020.dist-info/RECORD +446 -0
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/WHEEL +1 -1
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/top_level.txt +0 -1
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.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.7020.dist-info}/entry_points.txt +0 -0
@@ -1,1638 +1,1890 @@
|
|
1
|
-
import wx
|
2
|
-
|
3
|
-
from meerk40t.gui.wxutils import
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
_("
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
self.
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
self.
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
self.
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
)
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
self
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
# self.
|
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
|
-
self.
|
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
|
-
if self.operation.
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
)
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
)
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
self.context.elements.signal(
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
self.
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
self.
|
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
|
-
self
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
self.
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
)
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
self.
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
"
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
return
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
if self.
|
596
|
-
self.operation.power
|
597
|
-
|
598
|
-
self.
|
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
|
-
self.
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
self.text_kerf.
|
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
|
-
self.
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
self.
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
)
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
)
|
876
|
-
|
877
|
-
|
878
|
-
self.operation = node
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
self.
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
self.
|
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
|
-
self.
|
958
|
-
self.
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
"op
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
self.operation
|
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
|
-
self.
|
1010
|
-
|
1011
|
-
|
1012
|
-
self.
|
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
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
self
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
)
|
1296
|
-
self.
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
)
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
+
|
1356
|
-
|
1357
|
-
)
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1362
|
-
)
|
1363
|
-
self.
|
1364
|
-
self.
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1369
|
-
)
|
1370
|
-
|
1371
|
-
|
1372
|
-
|
1373
|
-
|
1374
|
-
|
1375
|
-
|
1376
|
-
|
1377
|
-
|
1378
|
-
|
1379
|
-
|
1380
|
-
|
1381
|
-
)
|
1382
|
-
|
1383
|
-
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1387
|
-
|
1388
|
-
self.
|
1389
|
-
|
1390
|
-
|
1391
|
-
|
1392
|
-
"
|
1393
|
-
|
1394
|
-
|
1395
|
-
|
1396
|
-
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1406
|
-
self.
|
1407
|
-
|
1408
|
-
|
1409
|
-
|
1410
|
-
|
1411
|
-
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1417
|
-
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
|
1432
|
-
|
1433
|
-
|
1434
|
-
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
1441
|
-
|
1442
|
-
|
1443
|
-
|
1444
|
-
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
self.
|
1457
|
-
self.
|
1458
|
-
|
1459
|
-
)
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1470
|
-
|
1471
|
-
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1475
|
-
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
1485
|
-
|
1486
|
-
self.
|
1487
|
-
|
1488
|
-
)
|
1489
|
-
|
1490
|
-
|
1491
|
-
self.SetSizer(
|
1492
|
-
|
1493
|
-
self.Layout()
|
1494
|
-
|
1495
|
-
self.
|
1496
|
-
|
1497
|
-
|
1498
|
-
|
1499
|
-
|
1500
|
-
|
1501
|
-
|
1502
|
-
|
1503
|
-
|
1504
|
-
|
1505
|
-
|
1506
|
-
|
1507
|
-
|
1508
|
-
self.
|
1509
|
-
|
1510
|
-
|
1511
|
-
|
1512
|
-
|
1513
|
-
self.
|
1514
|
-
|
1515
|
-
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1519
|
-
|
1520
|
-
|
1521
|
-
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
1538
|
-
self.
|
1539
|
-
self.operation
|
1540
|
-
|
1541
|
-
|
1542
|
-
|
1543
|
-
|
1544
|
-
|
1545
|
-
|
1546
|
-
|
1547
|
-
|
1548
|
-
|
1549
|
-
|
1550
|
-
|
1551
|
-
|
1552
|
-
|
1553
|
-
|
1554
|
-
|
1555
|
-
|
1556
|
-
|
1557
|
-
|
1558
|
-
|
1559
|
-
|
1560
|
-
|
1561
|
-
|
1562
|
-
|
1563
|
-
|
1564
|
-
self.
|
1565
|
-
|
1566
|
-
self.
|
1567
|
-
|
1568
|
-
self.
|
1569
|
-
|
1570
|
-
)
|
1571
|
-
|
1572
|
-
|
1573
|
-
|
1574
|
-
|
1575
|
-
|
1576
|
-
)
|
1577
|
-
|
1578
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
self.
|
1583
|
-
|
1584
|
-
self.
|
1585
|
-
|
1586
|
-
self.
|
1587
|
-
|
1588
|
-
|
1589
|
-
|
1590
|
-
|
1591
|
-
|
1592
|
-
|
1593
|
-
|
1594
|
-
|
1595
|
-
|
1596
|
-
|
1597
|
-
|
1598
|
-
|
1599
|
-
|
1600
|
-
|
1601
|
-
|
1602
|
-
|
1603
|
-
|
1604
|
-
|
1605
|
-
|
1606
|
-
|
1607
|
-
|
1608
|
-
|
1609
|
-
|
1610
|
-
|
1611
|
-
|
1612
|
-
|
1613
|
-
|
1614
|
-
|
1615
|
-
|
1616
|
-
|
1617
|
-
|
1618
|
-
|
1619
|
-
|
1620
|
-
|
1621
|
-
|
1622
|
-
|
1623
|
-
|
1624
|
-
|
1625
|
-
|
1626
|
-
|
1627
|
-
|
1628
|
-
|
1629
|
-
|
1630
|
-
|
1631
|
-
|
1632
|
-
|
1633
|
-
|
1634
|
-
|
1635
|
-
|
1636
|
-
|
1637
|
-
|
1638
|
-
|
1
|
+
import wx
|
2
|
+
|
3
|
+
from meerk40t.gui.wxutils import (
|
4
|
+
ScrolledPanel,
|
5
|
+
StaticBoxSizer,
|
6
|
+
TextCtrl,
|
7
|
+
dip_size,
|
8
|
+
set_ctrl_value,
|
9
|
+
wxButton,
|
10
|
+
wxCheckBox,
|
11
|
+
wxComboBox,
|
12
|
+
wxRadioBox,
|
13
|
+
wxStaticBitmap,
|
14
|
+
wxStaticText,
|
15
|
+
)
|
16
|
+
from meerk40t.constants import (
|
17
|
+
RASTER_T2B,
|
18
|
+
RASTER_B2T,
|
19
|
+
RASTER_R2L,
|
20
|
+
RASTER_L2R,
|
21
|
+
RASTER_HATCH,
|
22
|
+
RASTER_GREEDY_H,
|
23
|
+
RASTER_GREEDY_V,
|
24
|
+
RASTER_CROSSOVER,
|
25
|
+
RASTER_SPIRAL,
|
26
|
+
)
|
27
|
+
from meerk40t.kernel import lookup_listener, signal_listener
|
28
|
+
from meerk40t.gui.icons import icon_letter_h
|
29
|
+
from ...core.units import UNITS_PER_MM, Length
|
30
|
+
from ...svgelements import Color
|
31
|
+
from ..laserrender import swizzlecolor
|
32
|
+
from .attributes import IdPanel
|
33
|
+
|
34
|
+
_ = wx.GetTranslation
|
35
|
+
|
36
|
+
# OPERATION_TYPE_TOOLTIP = _(
|
37
|
+
# """Operation Type
|
38
|
+
|
39
|
+
# Cut & Engrave are vector operations, Raster and Image are raster operations.
|
40
|
+
|
41
|
+
# Cut and Engrave operations are essentially the same except that for a Cut operation with Cut Outer Paths last, only closed Paths in Cut operations are considered as being Outer-most."""
|
42
|
+
# )
|
43
|
+
|
44
|
+
|
45
|
+
def validate_raster_settings(node):
|
46
|
+
# Make sure things are properly set...
|
47
|
+
if node.raster_direction in (RASTER_T2B, ):
|
48
|
+
node.raster_preference_top = True
|
49
|
+
elif node.raster_direction in (RASTER_B2T, ):
|
50
|
+
node.raster_preference_top = False
|
51
|
+
elif node.raster_direction in (RASTER_R2L, ):
|
52
|
+
node.raster_preference_left = True
|
53
|
+
elif node.raster_direction in (RASTER_L2R, ):
|
54
|
+
node.raster_preference_left = False
|
55
|
+
elif node.raster_direction in (RASTER_HATCH, RASTER_CROSSOVER):
|
56
|
+
node.raster_preference_top = True
|
57
|
+
node.raster_preference_left = True
|
58
|
+
if node.raster_direction in (RASTER_CROSSOVER, RASTER_GREEDY_H, RASTER_GREEDY_V, RASTER_SPIRAL):
|
59
|
+
node.bidirectional = True
|
60
|
+
|
61
|
+
class LayerSettingPanel(wx.Panel):
|
62
|
+
def __init__(self, *args, context=None, node=None, **kwds):
|
63
|
+
# begin wxGlade: LayerSettingPanel.__init__
|
64
|
+
kwds["style"] = kwds.get("style", 0)
|
65
|
+
wx.Panel.__init__(self, *args, **kwds)
|
66
|
+
self.context = context
|
67
|
+
self.context.themes.set_window_colors(self)
|
68
|
+
self.operation = node
|
69
|
+
|
70
|
+
layer_sizer = StaticBoxSizer(self, wx.ID_ANY, _("Layer:"), wx.HORIZONTAL)
|
71
|
+
|
72
|
+
self.button_layer_color = wxButton(self, wx.ID_ANY, "")
|
73
|
+
self.button_layer_color.SetBackgroundColour(wx.Colour(0, 0, 0))
|
74
|
+
COLOR_TOOLTIP = _(
|
75
|
+
"Change/View color of this layer. When Meerk40t classifies elements to operations,"
|
76
|
+
) + _("this exact color is used to match elements to this operation.")
|
77
|
+
|
78
|
+
self.button_layer_color.SetToolTip(COLOR_TOOLTIP)
|
79
|
+
layer_sizer.Add(self.button_layer_color, 0, wx.EXPAND, 0)
|
80
|
+
h_classify_sizer = StaticBoxSizer(
|
81
|
+
self, wx.ID_ANY, _("Restrict classification"), wx.HORIZONTAL
|
82
|
+
)
|
83
|
+
h_property_sizer = StaticBoxSizer(
|
84
|
+
self, wx.ID_ANY, _("Properties"), wx.HORIZONTAL
|
85
|
+
)
|
86
|
+
rastertooltip = ""
|
87
|
+
if self.operation.type == "op raster":
|
88
|
+
rastertooltip = (
|
89
|
+
"\n"
|
90
|
+
+ _("If neither stroke nor fill are checked, then the raster op")
|
91
|
+
+ "\n"
|
92
|
+
+ _("will classify all elements that have a fill")
|
93
|
+
+ "\n"
|
94
|
+
+ _("or stroke that are either black or white.")
|
95
|
+
)
|
96
|
+
try:
|
97
|
+
self.has_stroke = self.operation.has_color_attribute("stroke")
|
98
|
+
self.checkbox_stroke = wxCheckBox(self, wx.ID_ANY, _("Stroke"))
|
99
|
+
self.checkbox_stroke.SetToolTip(
|
100
|
+
_("Look at the stroke color to restrict classification.")
|
101
|
+
+ rastertooltip
|
102
|
+
)
|
103
|
+
self.checkbox_stroke.SetValue(1 if self.has_stroke else 0)
|
104
|
+
h_classify_sizer.Add(self.checkbox_stroke, 1, 0, 0)
|
105
|
+
self.Bind(wx.EVT_CHECKBOX, self.on_check_stroke, self.checkbox_stroke)
|
106
|
+
except AttributeError:
|
107
|
+
self.has_stroke = None
|
108
|
+
|
109
|
+
try:
|
110
|
+
self.has_fill = self.operation.has_color_attribute("fill")
|
111
|
+
self.checkbox_fill = wxCheckBox(self, wx.ID_ANY, _("Fill"))
|
112
|
+
self.checkbox_fill.SetToolTip(
|
113
|
+
_("Look at the fill color to restrict classification.") + rastertooltip
|
114
|
+
)
|
115
|
+
self.checkbox_fill.SetValue(1 if self.has_fill else 0)
|
116
|
+
h_classify_sizer.Add(self.checkbox_fill, 1, 0, 0)
|
117
|
+
self.Bind(wx.EVT_CHECKBOX, self.on_check_fill, self.checkbox_fill)
|
118
|
+
except AttributeError:
|
119
|
+
self.has_fill = None
|
120
|
+
|
121
|
+
self.checkbox_stop = wxCheckBox(self, wx.ID_ANY, _("Stop"))
|
122
|
+
self.checkbox_stop.SetToolTip(
|
123
|
+
_("If active, then this op will prevent further classification")
|
124
|
+
+ "\n"
|
125
|
+
+ _("from other ops if it could classify an element by itself.")
|
126
|
+
)
|
127
|
+
h_classify_sizer.Add(self.checkbox_stop, 1, 0, 0)
|
128
|
+
self.Bind(wx.EVT_CHECKBOX, self.on_check_stop, self.checkbox_stop)
|
129
|
+
self.has_stop = hasattr(self.operation, "stopop")
|
130
|
+
if not self.has_stop:
|
131
|
+
self.checkbox_stop.SetValue(False)
|
132
|
+
self.checkbox_stop.Enable(False)
|
133
|
+
else:
|
134
|
+
self.checkbox_stop.SetValue(self.operation.stopop)
|
135
|
+
self.checkbox_stop.Enable(True)
|
136
|
+
|
137
|
+
if (
|
138
|
+
self.has_fill is not None
|
139
|
+
or self.has_stroke is not None
|
140
|
+
or self.has_stop is not None
|
141
|
+
):
|
142
|
+
layer_sizer.Add(h_classify_sizer, 1, wx.EXPAND, 0)
|
143
|
+
|
144
|
+
# self.combo_type = wxComboBox(
|
145
|
+
# self,
|
146
|
+
# wx.ID_ANY,
|
147
|
+
# choices=["Engrave", "Cut", "Raster", "Image", "Hatch", "Dots"],
|
148
|
+
# style=wx.CB_DROPDOWN,
|
149
|
+
# )
|
150
|
+
# self.combo_type.SetToolTip(OPERATION_TYPE_TOOLTIP)
|
151
|
+
# self.combo_type.SetSelection(0)
|
152
|
+
# layer_sizer.Add(self.combo_type, 1, 0, 0)
|
153
|
+
|
154
|
+
self.checkbox_output = wxCheckBox(self, wx.ID_ANY, _("Enable"))
|
155
|
+
self.checkbox_output.SetToolTip(
|
156
|
+
_("Enable this operation for inclusion in Execute Job.")
|
157
|
+
)
|
158
|
+
self.checkbox_output.SetValue(1)
|
159
|
+
h_property_sizer.Add(self.checkbox_output, 1, 0, 0)
|
160
|
+
|
161
|
+
self.checkbox_visible = wxCheckBox(self, wx.ID_ANY, _("Visible"))
|
162
|
+
self.checkbox_visible.SetToolTip(
|
163
|
+
_("Hide all contained elements on scene if not set.")
|
164
|
+
)
|
165
|
+
self.checkbox_visible.SetValue(1)
|
166
|
+
self.checkbox_visible.Enable(False)
|
167
|
+
h_property_sizer.Add(self.checkbox_visible, 1, 0, 0)
|
168
|
+
|
169
|
+
self.checkbox_default = wxCheckBox(self, wx.ID_ANY, _("Default"))
|
170
|
+
OPERATION_DEFAULT_TOOLTIP = (
|
171
|
+
_(
|
172
|
+
"When classifying elements, Default operations gain all appropriate elements "
|
173
|
+
)
|
174
|
+
+ _("not matched to an existing operation of the same colour, ")
|
175
|
+
+ _("rather than a new operation of that color being created.")
|
176
|
+
)
|
177
|
+
|
178
|
+
self.checkbox_default.SetToolTip(OPERATION_DEFAULT_TOOLTIP)
|
179
|
+
self.checkbox_default.SetValue(1)
|
180
|
+
h_property_sizer.Add(self.checkbox_default, 1, 0, 0)
|
181
|
+
|
182
|
+
layer_sizer.Add(h_property_sizer, 1, wx.EXPAND, 0)
|
183
|
+
|
184
|
+
self.SetSizer(layer_sizer)
|
185
|
+
|
186
|
+
self.Layout()
|
187
|
+
|
188
|
+
self.Bind(wx.EVT_BUTTON, self.on_button_layer, self.button_layer_color)
|
189
|
+
# self.Bind(wx.EVT_COMBOBOX, self.on_combo_operation, self.combo_type)
|
190
|
+
self.Bind(wx.EVT_CHECKBOX, self.on_check_output, self.checkbox_output)
|
191
|
+
self.Bind(wx.EVT_CHECKBOX, self.on_check_visible, self.checkbox_visible)
|
192
|
+
self.Bind(wx.EVT_CHECKBOX, self.on_check_default, self.checkbox_default)
|
193
|
+
# end wxGlade
|
194
|
+
|
195
|
+
def pane_hide(self):
|
196
|
+
pass
|
197
|
+
|
198
|
+
def pane_show(self):
|
199
|
+
pass
|
200
|
+
|
201
|
+
def accepts(self, node):
|
202
|
+
return node.type in (
|
203
|
+
"op cut",
|
204
|
+
"op engrave",
|
205
|
+
"op raster",
|
206
|
+
"op image",
|
207
|
+
"op dots",
|
208
|
+
)
|
209
|
+
|
210
|
+
def set_widgets(self, node):
|
211
|
+
self.operation = node
|
212
|
+
if self.operation is None or not self.accepts(node):
|
213
|
+
self.Hide()
|
214
|
+
return
|
215
|
+
self.button_layer_color.SetBackgroundColour(
|
216
|
+
wx.Colour(swizzlecolor(self.operation.color))
|
217
|
+
)
|
218
|
+
if self.operation.output is not None:
|
219
|
+
self.checkbox_output.SetValue(self.operation.output)
|
220
|
+
flag_set = True
|
221
|
+
flag_enabled = False
|
222
|
+
if self.operation.output is not None:
|
223
|
+
if not self.operation.output:
|
224
|
+
flag_enabled = True
|
225
|
+
flag_set = self.operation.is_visible
|
226
|
+
self.checkbox_visible.SetValue(flag_set)
|
227
|
+
self.checkbox_visible.Enable(flag_enabled)
|
228
|
+
if self.operation.default is not None:
|
229
|
+
self.checkbox_default.SetValue(self.operation.default)
|
230
|
+
try:
|
231
|
+
if self.has_fill:
|
232
|
+
self.checkbox_fill.SetValue(
|
233
|
+
1 if self.operation.has_color_attribute("fill") else 0
|
234
|
+
)
|
235
|
+
except AttributeError:
|
236
|
+
pass
|
237
|
+
try:
|
238
|
+
if self.has_stroke:
|
239
|
+
self.checkbox_stroke.SetValue(
|
240
|
+
1 if self.operation.has_color_attribute("stroke") else 0
|
241
|
+
)
|
242
|
+
except AttributeError:
|
243
|
+
pass
|
244
|
+
self.has_stop = hasattr(self.operation, "stopop")
|
245
|
+
if not self.has_stop:
|
246
|
+
self.checkbox_stop.SetValue(False)
|
247
|
+
self.checkbox_stop.Enable(False)
|
248
|
+
else:
|
249
|
+
self.checkbox_stop.SetValue(self.operation.stopop)
|
250
|
+
self.checkbox_stop.Enable(True)
|
251
|
+
|
252
|
+
self.Layout()
|
253
|
+
self.Show()
|
254
|
+
|
255
|
+
def on_button_layer(self, event=None): # wxGlade: OperationProperty.<event_handler>
|
256
|
+
data = wx.ColourData()
|
257
|
+
if self.operation.color is not None and self.operation.color != "none":
|
258
|
+
data.SetColour(wx.Colour(swizzlecolor(self.operation.color)))
|
259
|
+
dlg = wx.ColourDialog(self, data)
|
260
|
+
if dlg.ShowModal() == wx.ID_OK:
|
261
|
+
data = dlg.GetColourData()
|
262
|
+
color = data.GetColour()
|
263
|
+
rgb = color.GetRGB()
|
264
|
+
color = swizzlecolor(rgb)
|
265
|
+
self.operation.color = Color(color, 1.0)
|
266
|
+
try:
|
267
|
+
self.button_layer_color.SetBackgroundColour(
|
268
|
+
wx.Colour(swizzlecolor(self.operation.color))
|
269
|
+
)
|
270
|
+
except RuntimeError:
|
271
|
+
return
|
272
|
+
# Ask the user if she/he wants to assign the color of the contained objects
|
273
|
+
try:
|
274
|
+
candidate_stroke = bool(self.checkbox_stroke.GetValue())
|
275
|
+
except AttributeError:
|
276
|
+
candidate_stroke = False
|
277
|
+
try:
|
278
|
+
candidate_fill = bool(self.checkbox_fill.GetValue())
|
279
|
+
except AttributeError:
|
280
|
+
candidate_fill = False
|
281
|
+
if (
|
282
|
+
self.operation.type in ("op engrave", "op cut")
|
283
|
+
and len(self.operation.children) > 0
|
284
|
+
and (candidate_fill or candidate_stroke)
|
285
|
+
):
|
286
|
+
changed = []
|
287
|
+
for e in self.operation.children:
|
288
|
+
if e.type.startswith("effect "):
|
289
|
+
e.stroke = self.operation.color
|
290
|
+
changed.append(e)
|
291
|
+
dlg = wx.MessageDialog(
|
292
|
+
None,
|
293
|
+
message=_(
|
294
|
+
"Do you want to change the color of the contained elements too?"
|
295
|
+
),
|
296
|
+
caption=_("Update Colors?"),
|
297
|
+
style=wx.YES_NO | wx.ICON_QUESTION,
|
298
|
+
)
|
299
|
+
response = dlg.ShowModal()
|
300
|
+
dlg.Destroy()
|
301
|
+
if response == wx.ID_YES:
|
302
|
+
for refnode in self.operation.children:
|
303
|
+
if refnode in changed:
|
304
|
+
continue
|
305
|
+
if hasattr(refnode, "node"):
|
306
|
+
cnode = refnode.node
|
307
|
+
else:
|
308
|
+
cnode = refnode
|
309
|
+
add_to_change = False
|
310
|
+
if candidate_stroke and hasattr(cnode, "stroke"):
|
311
|
+
cnode.stroke = self.operation.color
|
312
|
+
add_to_change = True
|
313
|
+
|
314
|
+
if candidate_fill and hasattr(cnode, "fill"):
|
315
|
+
cnode.fill = self.operation.color
|
316
|
+
add_to_change = True
|
317
|
+
|
318
|
+
if add_to_change:
|
319
|
+
changed.append(cnode)
|
320
|
+
if len(changed) > 0:
|
321
|
+
self.context.elements.signal("element_property_update", changed)
|
322
|
+
self.context.elements.signal("refresh_scene", "Scene")
|
323
|
+
|
324
|
+
self.context.elements.signal(
|
325
|
+
"element_property_reload", self.operation, "button_layer"
|
326
|
+
)
|
327
|
+
self.context.elements.signal("updateop_tree")
|
328
|
+
|
329
|
+
def on_check_output(self, event=None): # wxGlade: OperationProperty.<event_handler>
|
330
|
+
if self.operation.output != bool(self.checkbox_output.GetValue()):
|
331
|
+
self.operation.output = bool(self.checkbox_output.GetValue())
|
332
|
+
self.context.elements.signal(
|
333
|
+
"element_property_reload", self.operation, "check_output"
|
334
|
+
)
|
335
|
+
self.context.elements.signal("updateop_tree")
|
336
|
+
self.checkbox_visible.Enable(not bool(self.checkbox_output.GetValue()))
|
337
|
+
|
338
|
+
def on_check_visible(self, event=None):
|
339
|
+
if self.operation.is_visible != bool(self.checkbox_visible.GetValue()):
|
340
|
+
self.operation.is_visible = bool(self.checkbox_visible.GetValue())
|
341
|
+
self.context.elements.validate_selected_area()
|
342
|
+
self.context.elements.signal("element_property_update", self.operation)
|
343
|
+
self.context.elements.signal("refresh_scene", "Scene")
|
344
|
+
|
345
|
+
def on_check_default(self, event=None):
|
346
|
+
if self.operation.default != bool(self.checkbox_default.GetValue()):
|
347
|
+
self.operation.default = bool(self.checkbox_default.GetValue())
|
348
|
+
self.context.elements.signal(
|
349
|
+
"element_property_reload", self.operation, "check_default"
|
350
|
+
)
|
351
|
+
|
352
|
+
def on_check_fill(self, event=None):
|
353
|
+
if self.checkbox_fill.GetValue():
|
354
|
+
self.operation.add_color_attribute("fill")
|
355
|
+
else:
|
356
|
+
self.operation.remove_color_attribute("fill")
|
357
|
+
self.context.elements.signal(
|
358
|
+
"element_property_reload", self.operation, "check_fill"
|
359
|
+
)
|
360
|
+
event.Skip()
|
361
|
+
|
362
|
+
def on_check_stroke(self, event=None):
|
363
|
+
if self.checkbox_stroke.GetValue():
|
364
|
+
self.operation.add_color_attribute("stroke")
|
365
|
+
else:
|
366
|
+
self.operation.remove_color_attribute("stroke")
|
367
|
+
self.context.elements.signal(
|
368
|
+
"element_property_reload", self.operation, "check_stroke"
|
369
|
+
)
|
370
|
+
event.Skip()
|
371
|
+
|
372
|
+
def on_check_stop(self, event=None):
|
373
|
+
if self.checkbox_stop.GetValue():
|
374
|
+
self.operation.stopop = True
|
375
|
+
else:
|
376
|
+
self.operation.stopop = False
|
377
|
+
self.context.elements.signal(
|
378
|
+
"element_property_reload", self.operation, "check_stopop"
|
379
|
+
)
|
380
|
+
event.Skip()
|
381
|
+
|
382
|
+
|
383
|
+
# end of class LayerSettingPanel
|
384
|
+
|
385
|
+
|
386
|
+
class SpeedPpiPanel(wx.Panel):
|
387
|
+
def __init__(self, *args, context=None, node=None, **kwds):
|
388
|
+
# begin wxGlade: SpeedPpiPanel.__init__
|
389
|
+
kwds["style"] = kwds.get("style", 0)
|
390
|
+
wx.Panel.__init__(self, *args, **kwds)
|
391
|
+
self.context = context
|
392
|
+
self.context.themes.set_window_colors(self)
|
393
|
+
self.operation = node
|
394
|
+
|
395
|
+
self.context.device.setting(bool, "use_percent_for_power_display", False)
|
396
|
+
self.use_percent = self.context.device.use_percent_for_power_display
|
397
|
+
self.context.device.setting(bool, "use_mm_min_for_speed_display", False)
|
398
|
+
self.use_mm_min = self.context.device.use_mm_min_for_speed_display
|
399
|
+
|
400
|
+
speed_power_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
401
|
+
if self.use_mm_min:
|
402
|
+
speed_fact = 60
|
403
|
+
else:
|
404
|
+
speed_fact = 1
|
405
|
+
|
406
|
+
speed_sizer = StaticBoxSizer(self, wx.ID_ANY, _("Speed"), wx.HORIZONTAL)
|
407
|
+
speed_power_sizer.Add(speed_sizer, 1, wx.EXPAND, 0)
|
408
|
+
|
409
|
+
self.text_speed = TextCtrl(
|
410
|
+
self,
|
411
|
+
wx.ID_ANY,
|
412
|
+
f"{20 * speed_fact:.0f}",
|
413
|
+
limited=True,
|
414
|
+
check="float",
|
415
|
+
style=wx.TE_PROCESS_ENTER,
|
416
|
+
nonzero=True,
|
417
|
+
)
|
418
|
+
self.trailer_speed = wxStaticText(self, id=wx.ID_ANY)
|
419
|
+
speed_sizer.Add(self.text_speed, 1, wx.EXPAND, 0)
|
420
|
+
speed_sizer.Add(self.trailer_speed, 0, wx.ALIGN_CENTER_VERTICAL, 0)
|
421
|
+
|
422
|
+
self.power_sizer = StaticBoxSizer(
|
423
|
+
self, wx.ID_ANY, _("Power (ppi)"), wx.HORIZONTAL
|
424
|
+
)
|
425
|
+
speed_power_sizer.Add(self.power_sizer, 1, wx.EXPAND, 0)
|
426
|
+
|
427
|
+
self.text_power = TextCtrl(
|
428
|
+
self,
|
429
|
+
wx.ID_ANY,
|
430
|
+
"1000.0",
|
431
|
+
limited=True,
|
432
|
+
check="float",
|
433
|
+
style=wx.TE_PROCESS_ENTER,
|
434
|
+
)
|
435
|
+
self.trailer_power = wxStaticText(self, id=wx.ID_ANY, label=_("/1000"))
|
436
|
+
self.power_sizer.Add(self.text_power, 1, wx.EXPAND, 0)
|
437
|
+
self.power_sizer.Add(self.trailer_power, 0, wx.ALIGN_CENTER_VERTICAL, 0)
|
438
|
+
|
439
|
+
self.update_power_speed_properties()
|
440
|
+
|
441
|
+
freq = self.context.device.lookup("frequency")
|
442
|
+
if freq:
|
443
|
+
frequency_sizer = StaticBoxSizer(
|
444
|
+
self, wx.ID_ANY, _("Frequency (kHz)"), wx.HORIZONTAL
|
445
|
+
)
|
446
|
+
speed_power_sizer.Add(frequency_sizer, 1, wx.EXPAND, 0)
|
447
|
+
|
448
|
+
self.text_frequency = TextCtrl(
|
449
|
+
self,
|
450
|
+
wx.ID_ANY,
|
451
|
+
"20.0",
|
452
|
+
limited=True,
|
453
|
+
check="float",
|
454
|
+
style=wx.TE_PROCESS_ENTER,
|
455
|
+
)
|
456
|
+
OPERATION_FREQUENCY_TOOLTIP = (
|
457
|
+
_("Laser frequency in kHz.")
|
458
|
+
+ "\n"
|
459
|
+
+ _("For lasers with frequencies that can be set.")
|
460
|
+
)
|
461
|
+
self.text_frequency.SetToolTip(OPERATION_FREQUENCY_TOOLTIP)
|
462
|
+
self.text_frequency.set_warn_level(*freq)
|
463
|
+
frequency_sizer.Add(self.text_frequency, 1, wx.EXPAND, 0)
|
464
|
+
else:
|
465
|
+
self.text_frequency = None
|
466
|
+
|
467
|
+
self.SetSizer(speed_power_sizer)
|
468
|
+
|
469
|
+
self.Layout()
|
470
|
+
|
471
|
+
self.text_speed.SetActionRoutine(self.on_text_speed)
|
472
|
+
self.text_power.SetActionRoutine(self.on_text_power)
|
473
|
+
|
474
|
+
if self.text_frequency:
|
475
|
+
self.text_frequency.SetActionRoutine(self.on_text_frequency)
|
476
|
+
|
477
|
+
# end wxGlade
|
478
|
+
|
479
|
+
def pane_hide(self):
|
480
|
+
pass
|
481
|
+
|
482
|
+
def pane_show(self):
|
483
|
+
self.update_power_speed_properties()
|
484
|
+
|
485
|
+
def on_device_update(self):
|
486
|
+
try:
|
487
|
+
self.update_power_speed_properties()
|
488
|
+
except RuntimeError:
|
489
|
+
# Pane was already destroyed
|
490
|
+
return
|
491
|
+
self.set_widgets(self.operation)
|
492
|
+
|
493
|
+
def update_power_speed_properties(self):
|
494
|
+
speed_min = None
|
495
|
+
speed_max = None
|
496
|
+
power_min = None
|
497
|
+
power_max = None
|
498
|
+
|
499
|
+
op = self.operation.type
|
500
|
+
if op.startswith("op "): # Should, shouldn't it?
|
501
|
+
op = op[3:]
|
502
|
+
else:
|
503
|
+
op = ""
|
504
|
+
if op != "":
|
505
|
+
label = "dangerlevel_op_" + op
|
506
|
+
warning = [False, 0, False, 0, False, 0, False, 0]
|
507
|
+
if hasattr(self.context.device, label):
|
508
|
+
dummy = getattr(self.context.device, label)
|
509
|
+
if isinstance(dummy, (tuple, list)) and len(dummy) == len(warning):
|
510
|
+
warning = dummy
|
511
|
+
if warning[0]:
|
512
|
+
power_min = warning[1]
|
513
|
+
if warning[2]:
|
514
|
+
power_max = warning[3]
|
515
|
+
if warning[4]:
|
516
|
+
speed_min = warning[5]
|
517
|
+
if warning[6]:
|
518
|
+
speed_max = warning[7]
|
519
|
+
self.use_mm_min = self.context.device.use_mm_min_for_speed_display
|
520
|
+
if self.use_mm_min:
|
521
|
+
if speed_min is not None:
|
522
|
+
speed_min *= 60
|
523
|
+
if speed_max is not None:
|
524
|
+
speed_max *= 60
|
525
|
+
speed_unit = "mm/min"
|
526
|
+
else:
|
527
|
+
speed_unit = "mm/s"
|
528
|
+
self.trailer_speed.SetLabel(speed_unit)
|
529
|
+
OPERATION_SPEED_TOOLTIP = (
|
530
|
+
_("Speed at which the head moves in {unit}.").format(unit=speed_unit)
|
531
|
+
+ "\n"
|
532
|
+
+ _(
|
533
|
+
"For Cut/Engrave vector operations, this is the speed of the head regardless of direction i.e. the separate x/y speeds vary according to the direction."
|
534
|
+
)
|
535
|
+
+ "\n"
|
536
|
+
+ _(
|
537
|
+
"For Raster/Image operations, this is the speed of the head as it sweeps backwards and forwards."
|
538
|
+
)
|
539
|
+
)
|
540
|
+
self.text_speed.SetToolTip(OPERATION_SPEED_TOOLTIP)
|
541
|
+
self.text_speed.set_error_level(0, None)
|
542
|
+
self.text_speed.set_warn_level(speed_min, speed_max)
|
543
|
+
|
544
|
+
self.use_percent = self.context.device.use_percent_for_power_display
|
545
|
+
if self.use_percent:
|
546
|
+
self.trailer_power.SetLabel("%")
|
547
|
+
self.text_power._check = "percent"
|
548
|
+
if power_min is not None:
|
549
|
+
power_min /= 10
|
550
|
+
if power_max is not None:
|
551
|
+
power_max /= 10
|
552
|
+
self.text_power.set_range(0, 100)
|
553
|
+
self.text_power.set_warn_level(power_min, power_max)
|
554
|
+
OPERATION_POWER_TOOLTIP = _(
|
555
|
+
"% of maximum power - This is a percentage of the maximum power of the laser."
|
556
|
+
)
|
557
|
+
self.power_sizer.SetLabel(_("Power"))
|
558
|
+
else:
|
559
|
+
self.trailer_power.SetLabel(_("/1000"))
|
560
|
+
self.text_power._check = "float"
|
561
|
+
self.text_power.set_range(0, 1000)
|
562
|
+
self.text_power.set_warn_level(power_min, power_max)
|
563
|
+
OPERATION_POWER_TOOLTIP = _(
|
564
|
+
_("Pulses Per Inch - This is software created laser power control.")
|
565
|
+
+ "\n"
|
566
|
+
+ _("1000 is always on, 500 is half power (fire every other step).")
|
567
|
+
+ "\n"
|
568
|
+
+ _(
|
569
|
+
'Values of 100 or have pulses > 1/10" and are generally used only for dotted or perforated lines.'
|
570
|
+
)
|
571
|
+
)
|
572
|
+
self.power_sizer.SetLabel(_("Power (ppi)"))
|
573
|
+
self.text_power.SetToolTip(OPERATION_POWER_TOOLTIP)
|
574
|
+
|
575
|
+
def accepts(self, node):
|
576
|
+
return node.type in (
|
577
|
+
"op cut",
|
578
|
+
"op engrave",
|
579
|
+
"op raster",
|
580
|
+
"op image",
|
581
|
+
"op dots",
|
582
|
+
)
|
583
|
+
|
584
|
+
def set_widgets(self, node):
|
585
|
+
self.operation = node
|
586
|
+
if self.operation is None or not self.accepts(node):
|
587
|
+
self.Hide()
|
588
|
+
return
|
589
|
+
if self.operation.speed is not None:
|
590
|
+
if self.use_mm_min:
|
591
|
+
set_ctrl_value(self.text_speed, str(self.operation.speed * 60))
|
592
|
+
else:
|
593
|
+
set_ctrl_value(self.text_speed, str(self.operation.speed))
|
594
|
+
if self.operation.power is not None:
|
595
|
+
if self.use_percent:
|
596
|
+
set_ctrl_value(self.text_power, f"{self.operation.power / 10.0:.0f}")
|
597
|
+
else:
|
598
|
+
set_ctrl_value(self.text_power, f"{self.operation.power:.0f}")
|
599
|
+
self.update_power_label()
|
600
|
+
if self.operation.frequency is not None and self.text_frequency:
|
601
|
+
set_ctrl_value(self.text_frequency, str(self.operation.frequency))
|
602
|
+
self.Show()
|
603
|
+
|
604
|
+
def on_text_speed(self): # wxGlade: OperationProperty.<event_handler>
|
605
|
+
try:
|
606
|
+
value = float(self.text_speed.GetValue())
|
607
|
+
if self.use_mm_min:
|
608
|
+
value /= 60
|
609
|
+
if self.operation.speed != value:
|
610
|
+
self.operation.speed = value
|
611
|
+
self.context.elements.signal(
|
612
|
+
"element_property_reload", self.operation, "text_speed"
|
613
|
+
)
|
614
|
+
self.context.elements.signal("updateop_tree")
|
615
|
+
except ValueError:
|
616
|
+
pass
|
617
|
+
|
618
|
+
def on_text_frequency(self):
|
619
|
+
try:
|
620
|
+
value = float(self.text_frequency.GetValue())
|
621
|
+
if self.operation.frequency != value:
|
622
|
+
self.operation.frequency = value
|
623
|
+
self.context.elements.signal(
|
624
|
+
"element_property_reload", self.operation, "text_frquency"
|
625
|
+
)
|
626
|
+
except ValueError:
|
627
|
+
pass
|
628
|
+
|
629
|
+
def update_power_label(self):
|
630
|
+
# if self.operation.power <= 100:
|
631
|
+
# self.power_label.SetLabel(_("Power (ppi):") + "⚠️")
|
632
|
+
# else:
|
633
|
+
# self.power_label.SetLabel(_("Power (ppi):"))
|
634
|
+
if self.use_percent:
|
635
|
+
return
|
636
|
+
try:
|
637
|
+
value = float(self.text_power.GetValue())
|
638
|
+
self.power_sizer.SetLabel(_("Power (ppi)") + f" ({value/10:.1f}%)")
|
639
|
+
except ValueError:
|
640
|
+
return
|
641
|
+
|
642
|
+
def on_text_power(self):
|
643
|
+
try:
|
644
|
+
value = float(self.text_power.GetValue())
|
645
|
+
if self.use_percent:
|
646
|
+
value *= 10
|
647
|
+
if self.operation.power != value:
|
648
|
+
self.operation.power = value
|
649
|
+
self.update_power_label()
|
650
|
+
self.context.elements.signal(
|
651
|
+
"element_property_reload", self.operation, "text_power"
|
652
|
+
)
|
653
|
+
self.context.elements.signal("updateop_tree")
|
654
|
+
except ValueError:
|
655
|
+
return
|
656
|
+
|
657
|
+
|
658
|
+
# end of class SpeedPpiPanel
|
659
|
+
|
660
|
+
|
661
|
+
class PassesPanel(wx.Panel):
|
662
|
+
def __init__(self, *args, context=None, node=None, **kwds):
|
663
|
+
# begin wxGlade: PassesPanel.__init__
|
664
|
+
kwds["style"] = kwds.get("style", 0)
|
665
|
+
wx.Panel.__init__(self, *args, **kwds)
|
666
|
+
self.context = context
|
667
|
+
self.context.themes.set_window_colors(self)
|
668
|
+
self.operation = node
|
669
|
+
self.has_kerf = False
|
670
|
+
|
671
|
+
sizer_main = wx.BoxSizer(wx.HORIZONTAL)
|
672
|
+
|
673
|
+
self.sizer_kerf = StaticBoxSizer(
|
674
|
+
self, wx.ID_ANY, _("Kerf compensation:"), wx.HORIZONTAL
|
675
|
+
)
|
676
|
+
self.text_kerf = TextCtrl(
|
677
|
+
self,
|
678
|
+
wx.ID_ANY,
|
679
|
+
"0",
|
680
|
+
limited=True,
|
681
|
+
check="length",
|
682
|
+
style=wx.TE_PROCESS_ENTER,
|
683
|
+
)
|
684
|
+
self.text_kerf.SetToolTip(
|
685
|
+
_(
|
686
|
+
"Enter half the width of your laserbeam (kerf)\n"
|
687
|
+
+ "if you want to have a shape with an exact size.\n"
|
688
|
+
+ "Use the negative value if you are using the cutout\n"
|
689
|
+
+ "as a placeholder for another part (eg inlays)."
|
690
|
+
)
|
691
|
+
)
|
692
|
+
self.kerf_label = wxStaticText(self, wx.ID_ANY, "")
|
693
|
+
self.sizer_kerf.Add(self.text_kerf, 1, wx.EXPAND, 0)
|
694
|
+
self.sizer_kerf.Add(self.kerf_label, 0, wx.ALIGN_CENTER_VERTICAL, 0)
|
695
|
+
|
696
|
+
self.sizer_coolant = StaticBoxSizer(
|
697
|
+
self, wx.ID_ANY, _("Coolant:"), wx.HORIZONTAL
|
698
|
+
)
|
699
|
+
cool_choices = [_("No changes"), _("Turn on"), _("Turn off")]
|
700
|
+
self.combo_coolant = wxComboBox(
|
701
|
+
self,
|
702
|
+
wx.ID_ANY,
|
703
|
+
choices=cool_choices,
|
704
|
+
style=wx.CB_DROPDOWN | wx.CB_READONLY,
|
705
|
+
)
|
706
|
+
self.combo_coolant.SetToolTip(
|
707
|
+
_(
|
708
|
+
"Define whether coolant support shall be explicitly turned on or off at the start of the operation, or whether it should be left at its current state."
|
709
|
+
)
|
710
|
+
)
|
711
|
+
self.sizer_coolant.Add(self.combo_coolant, 1, wx.EXPAND, 0)
|
712
|
+
|
713
|
+
sizer_passes = StaticBoxSizer(self, wx.ID_ANY, _("Passes:"), wx.HORIZONTAL)
|
714
|
+
|
715
|
+
self.check_passes = wxCheckBox(self, wx.ID_ANY, _("Passes"))
|
716
|
+
self.check_passes.SetToolTip(_("Enable Operation Passes"))
|
717
|
+
sizer_passes.Add(self.check_passes, 0, wx.EXPAND, 0)
|
718
|
+
|
719
|
+
self.text_passes = TextCtrl(
|
720
|
+
self, wx.ID_ANY, "1", limited=True, check="int", style=wx.TE_PROCESS_ENTER
|
721
|
+
)
|
722
|
+
OPERATION_PASSES_TOOLTIP = (
|
723
|
+
_("How many times to repeat this operation?")
|
724
|
+
+ "\n"
|
725
|
+
+ _(
|
726
|
+
"Setting e.g. passes to 2 is essentially equivalent to Duplicating the operation, "
|
727
|
+
)
|
728
|
+
+ _(
|
729
|
+
"creating a second identical operation with the same settings and same elements."
|
730
|
+
)
|
731
|
+
+ "\n"
|
732
|
+
+ _("The number of Operation Passes can be changed extremely easily, ")
|
733
|
+
+ _("but you cannot change any of the other settings.")
|
734
|
+
+ "\n"
|
735
|
+
+ _(
|
736
|
+
"Duplicating the Operation gives more flexibility for changing settings, "
|
737
|
+
)
|
738
|
+
+ _("but is far more cumbersome to change the number of duplications ")
|
739
|
+
+ _("because you need to add and delete the duplicates one by one.")
|
740
|
+
)
|
741
|
+
|
742
|
+
self.text_passes.SetToolTip(OPERATION_PASSES_TOOLTIP)
|
743
|
+
sizer_passes.Add(self.text_passes, 1, wx.EXPAND, 0)
|
744
|
+
|
745
|
+
sizer_main.Add(sizer_passes, 1, wx.EXPAND, 0)
|
746
|
+
sizer_main.Add(self.sizer_kerf, 1, wx.EXPAND, 0)
|
747
|
+
sizer_main.Add(self.sizer_coolant, 1, wx.EXPAND, 0)
|
748
|
+
|
749
|
+
self.SetSizer(sizer_main)
|
750
|
+
|
751
|
+
self.Layout()
|
752
|
+
|
753
|
+
self.Bind(wx.EVT_CHECKBOX, self.on_check_passes, self.check_passes)
|
754
|
+
self.Bind(wx.EVT_COMBOBOX, self.on_combo_coolant, self.combo_coolant)
|
755
|
+
|
756
|
+
self.text_passes.SetActionRoutine(self.on_text_passes)
|
757
|
+
self.text_kerf.SetActionRoutine(self.on_text_kerf)
|
758
|
+
# end wxGlade
|
759
|
+
|
760
|
+
def pane_hide(self):
|
761
|
+
pass
|
762
|
+
|
763
|
+
def pane_show(self):
|
764
|
+
pass
|
765
|
+
|
766
|
+
def accepts(self, node):
|
767
|
+
return node.type in (
|
768
|
+
"op cut",
|
769
|
+
"op engrave",
|
770
|
+
"op raster",
|
771
|
+
"op image",
|
772
|
+
"op dots",
|
773
|
+
)
|
774
|
+
|
775
|
+
def set_widgets(self, node):
|
776
|
+
self.operation = node
|
777
|
+
if self.operation is None or not self.accepts(node):
|
778
|
+
self.Hide()
|
779
|
+
return
|
780
|
+
self.has_kerf = bool(self.operation.type == "op cut")
|
781
|
+
if self.has_kerf:
|
782
|
+
s_label = ""
|
783
|
+
s_kerf = "0"
|
784
|
+
try:
|
785
|
+
ll = Length(self.operation.kerf, digits=2, preferred_units="mm")
|
786
|
+
kval = float(ll)
|
787
|
+
s_kerf = ll.preferred_length
|
788
|
+
if kval < 0:
|
789
|
+
s_label = " " + _("Inward")
|
790
|
+
elif kval > 0:
|
791
|
+
s_label = " " + _("Outward")
|
792
|
+
else:
|
793
|
+
s_kerf = "0"
|
794
|
+
|
795
|
+
except ValueError:
|
796
|
+
pass
|
797
|
+
self.text_kerf.SetValue(s_kerf)
|
798
|
+
self.kerf_label.SetLabel(s_label)
|
799
|
+
if self.operation.passes_custom is not None:
|
800
|
+
self.check_passes.SetValue(self.operation.passes_custom)
|
801
|
+
if self.operation.passes is not None:
|
802
|
+
set_ctrl_value(self.text_passes, str(self.operation.passes))
|
803
|
+
on = self.check_passes.GetValue()
|
804
|
+
self.text_passes.Enable(on)
|
805
|
+
self.sizer_kerf.ShowItems(self.has_kerf)
|
806
|
+
self.sizer_kerf.Show(self.has_kerf)
|
807
|
+
if hasattr(self.operation, "coolant"):
|
808
|
+
show_cool = True
|
809
|
+
value = self.operation.coolant
|
810
|
+
if value is None:
|
811
|
+
value = 0
|
812
|
+
self.combo_coolant.SetSelection(value)
|
813
|
+
else:
|
814
|
+
show_cool = False
|
815
|
+
if hasattr(self.context.device, "device_coolant"):
|
816
|
+
enable_cool = True
|
817
|
+
if self.context.device.device_coolant is None:
|
818
|
+
enable_cool = False
|
819
|
+
else:
|
820
|
+
enable_cool = False
|
821
|
+
self.combo_coolant.Enable(enable_cool)
|
822
|
+
self.sizer_coolant.ShowItems(show_cool)
|
823
|
+
self.sizer_coolant.Show(show_cool)
|
824
|
+
self.Layout()
|
825
|
+
self.Show()
|
826
|
+
|
827
|
+
def on_combo_coolant(self, event=None):
|
828
|
+
value = self.combo_coolant.GetSelection()
|
829
|
+
if value < 0:
|
830
|
+
value = 0
|
831
|
+
self.operation.coolant = value
|
832
|
+
self.context.elements.signal(
|
833
|
+
"element_property_reload", self.operation, "coolant"
|
834
|
+
)
|
835
|
+
event.Skip()
|
836
|
+
|
837
|
+
def on_check_passes(self, event=None): # wxGlade: OperationProperty.<event_handler>
|
838
|
+
on = self.check_passes.GetValue()
|
839
|
+
self.text_passes.Enable(on)
|
840
|
+
self.operation.passes_custom = bool(on)
|
841
|
+
self.context.elements.signal(
|
842
|
+
"element_property_reload", self.operation, "check_passes"
|
843
|
+
)
|
844
|
+
event.Skip()
|
845
|
+
|
846
|
+
def on_text_passes(self):
|
847
|
+
try:
|
848
|
+
value = int(self.text_passes.GetValue())
|
849
|
+
if self.operation.passes != value:
|
850
|
+
self.operation.passes = value
|
851
|
+
self.context.elements.signal(
|
852
|
+
"element_property_reload", self.operation, "text_Passes"
|
853
|
+
)
|
854
|
+
except ValueError:
|
855
|
+
pass
|
856
|
+
|
857
|
+
def on_text_kerf(self):
|
858
|
+
try:
|
859
|
+
value = float(Length(self.text_kerf.GetValue()))
|
860
|
+
if self.operation.kerf != value:
|
861
|
+
self.operation.kerf = value
|
862
|
+
self.context.elements.signal(
|
863
|
+
"element_property_reload", self.operation, "text_kerf"
|
864
|
+
)
|
865
|
+
except ValueError:
|
866
|
+
pass
|
867
|
+
|
868
|
+
|
869
|
+
# end of class PassesPanel
|
870
|
+
|
871
|
+
|
872
|
+
class InfoPanel(wx.Panel):
|
873
|
+
def __init__(self, *args, context=None, node=None, **kwds):
|
874
|
+
# begin wxGlade: PassesPanel.__init__
|
875
|
+
kwds["style"] = kwds.get("style", 0)
|
876
|
+
wx.Panel.__init__(self, *args, **kwds)
|
877
|
+
self.context = context
|
878
|
+
self.operation = node
|
879
|
+
|
880
|
+
sizer_info = StaticBoxSizer(self, wx.ID_ANY, _("Info:"), wx.HORIZONTAL)
|
881
|
+
|
882
|
+
sizer_children = StaticBoxSizer(self, wx.ID_ANY, _("Children:"), wx.HORIZONTAL)
|
883
|
+
sizer_time = StaticBoxSizer(
|
884
|
+
self, wx.ID_ANY, _("Est. burn-time:"), wx.HORIZONTAL
|
885
|
+
)
|
886
|
+
|
887
|
+
self.text_children = TextCtrl(self, wx.ID_ANY, "0", style=wx.TE_READONLY)
|
888
|
+
self.text_children.SetMinSize(dip_size(self, 25, -1))
|
889
|
+
self.text_children.SetMaxSize(dip_size(self, 55, -1))
|
890
|
+
self.text_time = TextCtrl(self, wx.ID_ANY, "---", style=wx.TE_READONLY)
|
891
|
+
self.text_time.SetMinSize(dip_size(self, 55, -1))
|
892
|
+
self.text_time.SetMaxSize(dip_size(self, 100, -1))
|
893
|
+
self.text_children.SetToolTip(
|
894
|
+
_("How many elements does this operation contain")
|
895
|
+
)
|
896
|
+
self.text_time.SetToolTip(_("Estimated time for execution (hh:mm:ss)"))
|
897
|
+
self.btn_update = wxButton(self, wx.ID_ANY, _("Calculate"))
|
898
|
+
self.btn_update.Bind(wx.EVT_BUTTON, self.on_button_calculate)
|
899
|
+
|
900
|
+
self.btn_recalc = wxButton(self, wx.ID_ANY, _("Re-Classify"))
|
901
|
+
self.btn_recalc.Bind(wx.EVT_BUTTON, self.on_button_refresh)
|
902
|
+
|
903
|
+
sizer_children.Add(self.text_children, 1, wx.EXPAND, 0)
|
904
|
+
sizer_time.Add(self.text_time, 1, wx.EXPAND, 0)
|
905
|
+
sizer_time.Add(self.btn_update, 0, wx.EXPAND, 0)
|
906
|
+
sizer_time.AddSpacer(20)
|
907
|
+
sizer_time.Add(self.btn_recalc, 0, wx.EXPAND, 0)
|
908
|
+
|
909
|
+
sizer_info.Add(sizer_children, 1, wx.EXPAND, 0)
|
910
|
+
sizer_info.Add(sizer_time, 2, wx.EXPAND, 0)
|
911
|
+
|
912
|
+
self.SetSizer(sizer_info)
|
913
|
+
|
914
|
+
self.Layout()
|
915
|
+
|
916
|
+
# end wxGlade
|
917
|
+
|
918
|
+
def pane_hide(self):
|
919
|
+
pass
|
920
|
+
|
921
|
+
def pane_show(self):
|
922
|
+
pass
|
923
|
+
|
924
|
+
def on_button_refresh(self, event):
|
925
|
+
if not hasattr(self.operation, "classify"):
|
926
|
+
return
|
927
|
+
|
928
|
+
infotxt = (
|
929
|
+
_("Do you really want to reassign elements to this operation?")
|
930
|
+
+ "\n"
|
931
|
+
+ _("Atttention: This will delete all existing assignments!")
|
932
|
+
)
|
933
|
+
dlg = wx.MessageDialog(
|
934
|
+
None, infotxt, "Re-Classify", wx.YES_NO | wx.ICON_WARNING
|
935
|
+
)
|
936
|
+
result = dlg.ShowModal()
|
937
|
+
dlg.Destroy()
|
938
|
+
if result == wx.ID_YES:
|
939
|
+
with self.context.elements.undoscope("Re-Classify"):
|
940
|
+
myop = self.operation
|
941
|
+
myop.remove_all_children()
|
942
|
+
data = list(self.context.elements.elems())
|
943
|
+
reverse = self.context.elements.classify_reverse
|
944
|
+
fuzzy = self.context.elements.classify_fuzzy
|
945
|
+
fuzzydistance = self.context.elements.classify_fuzzydistance
|
946
|
+
if reverse:
|
947
|
+
data = reversed(data)
|
948
|
+
for node in data:
|
949
|
+
# result is a tuple containing classified, should_break, feedback
|
950
|
+
result = myop.classify(
|
951
|
+
node,
|
952
|
+
fuzzy=fuzzy,
|
953
|
+
fuzzydistance=fuzzydistance,
|
954
|
+
usedefault=False,
|
955
|
+
)
|
956
|
+
# Probably moot as the next command will move the focus away...
|
957
|
+
self.refresh_display()
|
958
|
+
self.context.signal("tree_changed")
|
959
|
+
self.context.signal("activate_single_node", myop)
|
960
|
+
|
961
|
+
def on_button_calculate(self, event):
|
962
|
+
self.text_time.SetValue(self.operation.time_estimate())
|
963
|
+
|
964
|
+
def refresh_display(self):
|
965
|
+
childs = len(self.operation.children)
|
966
|
+
self.text_time.SetValue("---")
|
967
|
+
self.text_children.SetValue(str(childs))
|
968
|
+
|
969
|
+
def accepts(self, node):
|
970
|
+
return node.type in (
|
971
|
+
"op cut",
|
972
|
+
"op engrave",
|
973
|
+
"op raster",
|
974
|
+
"op image",
|
975
|
+
"op dots",
|
976
|
+
)
|
977
|
+
|
978
|
+
def set_widgets(self, node):
|
979
|
+
self.operation = node
|
980
|
+
if self.operation is None or not self.accepts(node):
|
981
|
+
self.Hide()
|
982
|
+
return
|
983
|
+
self.refresh_display()
|
984
|
+
self.Show()
|
985
|
+
|
986
|
+
|
987
|
+
# end of class InfoPanel
|
988
|
+
|
989
|
+
|
990
|
+
class PanelStartPreference(wx.Panel):
|
991
|
+
def __init__(self, *args, context=None, node=None, **kwds):
|
992
|
+
# begin wxGlade: PanelStartPreference.__init__
|
993
|
+
kwds["style"] = kwds.get("style", 0)
|
994
|
+
wx.Panel.__init__(self, *args, **kwds)
|
995
|
+
self.context = context
|
996
|
+
self.operation = node
|
997
|
+
|
998
|
+
sizer_main = StaticBoxSizer(self, wx.ID_ANY, _("Start Preference:"), wx.VERTICAL)
|
999
|
+
|
1000
|
+
self.slider_pref_left = wx.Slider(self, wx.ID_ANY, 1, 0, 1)
|
1001
|
+
sizer_main.Add(self.slider_pref_left, 0, wx.EXPAND, 0)
|
1002
|
+
|
1003
|
+
sizer_top_display = wx.BoxSizer(wx.HORIZONTAL)
|
1004
|
+
sizer_main.Add(sizer_top_display, 1, wx.EXPAND, 0)
|
1005
|
+
|
1006
|
+
self.slider_pref_top = wx.Slider(self, wx.ID_ANY, 1, 0, 1, style=wx.SL_VERTICAL)
|
1007
|
+
sizer_top_display.Add(self.slider_pref_top, 0, wx.EXPAND, 0)
|
1008
|
+
|
1009
|
+
self.display_panel = wx.Panel(self, wx.ID_ANY)
|
1010
|
+
sizer_top_display.Add(self.display_panel, 1, wx.EXPAND, 0)
|
1011
|
+
|
1012
|
+
self.SetSizer(sizer_main)
|
1013
|
+
|
1014
|
+
self.Layout()
|
1015
|
+
|
1016
|
+
self.Bind(wx.EVT_SLIDER, self.on_slider_pref_left, self.slider_pref_left)
|
1017
|
+
self.Bind(wx.EVT_SLIDER, self.on_slider_pref_top, self.slider_pref_top)
|
1018
|
+
# end wxGlade
|
1019
|
+
self.Bind(wx.EVT_SIZE, self.on_size)
|
1020
|
+
self.display_panel.Bind(wx.EVT_PAINT, self.on_display_paint)
|
1021
|
+
self.display_panel.Bind(wx.EVT_ERASE_BACKGROUND, self.on_display_erase)
|
1022
|
+
|
1023
|
+
self.raster_pen = wx.Pen()
|
1024
|
+
self.raster_pen.SetColour(wx.BLACK)
|
1025
|
+
self.raster_pen.SetWidth(2)
|
1026
|
+
|
1027
|
+
self.travel_pen = wx.Pen()
|
1028
|
+
self.travel_pen.SetColour(wx.Colour(255, 127, 255, 127))
|
1029
|
+
self.travel_pen.SetWidth(2)
|
1030
|
+
|
1031
|
+
self.direction_pen = wx.Pen()
|
1032
|
+
self.direction_pen.SetColour(wx.Colour(127, 127, 255))
|
1033
|
+
self.direction_pen.SetWidth(2)
|
1034
|
+
|
1035
|
+
self.raster_lines = None
|
1036
|
+
self.travel_lines = None
|
1037
|
+
self.direction_lines = None
|
1038
|
+
|
1039
|
+
self._Buffer = None
|
1040
|
+
|
1041
|
+
def pane_hide(self):
|
1042
|
+
pass
|
1043
|
+
|
1044
|
+
def pane_show(self):
|
1045
|
+
pass
|
1046
|
+
|
1047
|
+
# @signal_listener("element_property_reload")
|
1048
|
+
def on_element_property_reload(self, *args):
|
1049
|
+
self.set_widgets(self.operation)
|
1050
|
+
self._reload_display()
|
1051
|
+
|
1052
|
+
def accepts(self, node):
|
1053
|
+
return node.type in (
|
1054
|
+
"op raster",
|
1055
|
+
"op image",
|
1056
|
+
)
|
1057
|
+
|
1058
|
+
def set_widgets(self, node):
|
1059
|
+
self.operation = node
|
1060
|
+
if self.operation is None or not self.accepts(node):
|
1061
|
+
self.Hide()
|
1062
|
+
return
|
1063
|
+
if self.operation.raster_direction in (
|
1064
|
+
RASTER_CROSSOVER, RASTER_SPIRAL,
|
1065
|
+
): # Crossover
|
1066
|
+
self.Hide()
|
1067
|
+
return
|
1068
|
+
validate_raster_settings(self.operation)
|
1069
|
+
self._toggle_sliders()
|
1070
|
+
self.refresh_display()
|
1071
|
+
self.Show()
|
1072
|
+
|
1073
|
+
def on_display_paint(self, event=None):
|
1074
|
+
try:
|
1075
|
+
wx.BufferedPaintDC(self.display_panel, self._Buffer)
|
1076
|
+
except RuntimeError:
|
1077
|
+
pass
|
1078
|
+
|
1079
|
+
def on_display_erase(self, event=None):
|
1080
|
+
pass
|
1081
|
+
|
1082
|
+
def set_buffer(self):
|
1083
|
+
width, height = self.display_panel.Size
|
1084
|
+
if width <= 0:
|
1085
|
+
width = 1
|
1086
|
+
if height <= 0:
|
1087
|
+
height = 1
|
1088
|
+
self._Buffer = wx.Bitmap(width, height)
|
1089
|
+
|
1090
|
+
def on_size(self, event=None):
|
1091
|
+
self.Layout()
|
1092
|
+
self.set_buffer()
|
1093
|
+
self.raster_lines = None
|
1094
|
+
self.travel_lines = None
|
1095
|
+
self.direction_lines = None
|
1096
|
+
wx.CallAfter(self.refresh_in_ui)
|
1097
|
+
|
1098
|
+
def refresh_display(self):
|
1099
|
+
if self._Buffer is None:
|
1100
|
+
self.set_buffer()
|
1101
|
+
|
1102
|
+
if not wx.IsMainThread():
|
1103
|
+
wx.CallAfter(self.refresh_in_ui)
|
1104
|
+
else:
|
1105
|
+
self.refresh_in_ui()
|
1106
|
+
|
1107
|
+
def calculate_raster_lines(self):
|
1108
|
+
w, h = self._Buffer.Size
|
1109
|
+
if w<10 or h<10: # Ini initialisation phase and too small anyway...
|
1110
|
+
return
|
1111
|
+
|
1112
|
+
from_left = self.operation.raster_preference_left
|
1113
|
+
from_top = self.operation.raster_preference_top
|
1114
|
+
|
1115
|
+
last = None
|
1116
|
+
direction = self.operation.raster_direction
|
1117
|
+
# Rasterline Indicator
|
1118
|
+
r_start = []
|
1119
|
+
r_end = []
|
1120
|
+
# Travel Indicator
|
1121
|
+
t_start = []
|
1122
|
+
t_end = []
|
1123
|
+
# Direction Indicator
|
1124
|
+
d_start = []
|
1125
|
+
d_end = []
|
1126
|
+
factor = 3
|
1127
|
+
bidirectional = self.operation.bidirectional
|
1128
|
+
dpi = max(1, self.operation.dpi)
|
1129
|
+
|
1130
|
+
def dir_arrow_up_down(up: bool):
|
1131
|
+
d_start.append((w * 0.05, h * 0.05))
|
1132
|
+
d_end.append((w * 0.05, h * 0.95))
|
1133
|
+
# Direction Arrow
|
1134
|
+
d_start.append((w * 0.05, (h * 0.95) if up else (h * 0.05)))
|
1135
|
+
d_end.append((w * 0.05 + 4, (h * 0.95 - 4) if up else (h * 0.05 + 4)))
|
1136
|
+
d_start.append((w * 0.05, (h * 0.95) if up else (h * 0.05)))
|
1137
|
+
d_end.append((w * 0.05 - 4, (h * 0.95 - 4) if up else (h * 0.05 + 4)))
|
1138
|
+
|
1139
|
+
def dir_arrow_left_right(left: bool):
|
1140
|
+
# Direction Line
|
1141
|
+
d_start.append((w * 0.05, h * 0.05))
|
1142
|
+
d_end.append((w * 0.95, h * 0.05))
|
1143
|
+
# Direction Arrow
|
1144
|
+
d_start.append(((w * 0.95) if left else (w * 0.05), h * 0.05))
|
1145
|
+
d_end.append(((w * 0.95 - 4) if left else (w * 0.05 + 4), h * 0.05 - 4))
|
1146
|
+
d_start.append(((w * 0.95) if left else (w * 0.05), h * 0.05))
|
1147
|
+
d_end.append(((w * 0.95 - 4) if left else (w * 0.05 + 4), h * 0.05 + 4))
|
1148
|
+
|
1149
|
+
if direction in (RASTER_T2B, RASTER_B2T, RASTER_HATCH, RASTER_GREEDY_H, RASTER_CROSSOVER): # Horizontal mode, raster will be built from top to bottom (or vice versa)
|
1150
|
+
# Direction Line
|
1151
|
+
if direction in (RASTER_B2T, ):
|
1152
|
+
# Bottom to Top
|
1153
|
+
dir_arrow_up_down(False)
|
1154
|
+
start = int(h * 0.9)
|
1155
|
+
end = int(h * 0.1)
|
1156
|
+
step = -1000 / dpi * factor
|
1157
|
+
else:
|
1158
|
+
# Top to Bottom or Crosshatch
|
1159
|
+
dir_arrow_up_down(True)
|
1160
|
+
start = int(h * 0.1)
|
1161
|
+
end = int(h * 0.9)
|
1162
|
+
step = 1000 / dpi * factor
|
1163
|
+
if step == 0:
|
1164
|
+
step = abs(start-end) / 10
|
1165
|
+
while abs(step) > abs(start - end):
|
1166
|
+
step /= 2
|
1167
|
+
while abs(start - end) / abs(step) > 100:
|
1168
|
+
step *= 2
|
1169
|
+
|
1170
|
+
pos = start
|
1171
|
+
while min(start, end) <= pos <= max(start, end):
|
1172
|
+
# Primary Line Horizontal Raster, no need to be fancy and be directional here...
|
1173
|
+
r_start.append((w * 0.1, pos))
|
1174
|
+
r_end.append((w * 0.9, pos))
|
1175
|
+
|
1176
|
+
# Travel segment
|
1177
|
+
if last is not None:
|
1178
|
+
# Travel Lines, from end of last line to next
|
1179
|
+
t_start.append((last[0], last[1]))
|
1180
|
+
t_end.append((w * 0.1 if from_left else w * 0.9, pos))
|
1181
|
+
|
1182
|
+
# Arrow segment
|
1183
|
+
r_start.append((w * 0.9 if from_left else w * 0.1, pos))
|
1184
|
+
r_end.append((w * 0.9 - 2 if from_left else w * 0.1 + 2, pos - 2))
|
1185
|
+
last = r_start[-1]
|
1186
|
+
if bidirectional:
|
1187
|
+
from_left = not from_left
|
1188
|
+
pos += step
|
1189
|
+
if direction in (RASTER_R2L, RASTER_L2R, RASTER_HATCH, RASTER_GREEDY_V, RASTER_CROSSOVER): # Vertical mode, raster will be built from left to right (or vice versa)
|
1190
|
+
if direction in (RASTER_R2L, ):
|
1191
|
+
# Right to Left
|
1192
|
+
dir_arrow_left_right(False)
|
1193
|
+
start = int(w * 0.9)
|
1194
|
+
end = int(w * 0.1)
|
1195
|
+
step = -1000 / dpi * factor
|
1196
|
+
else:
|
1197
|
+
# Left to Right or Crosshatch
|
1198
|
+
dir_arrow_left_right(True)
|
1199
|
+
start = int(w * 0.1)
|
1200
|
+
end = int(w * 0.9)
|
1201
|
+
step = 1000 / dpi * factor
|
1202
|
+
if step == 0:
|
1203
|
+
step = abs(start-end) / 10
|
1204
|
+
while abs(step) > abs(start - end):
|
1205
|
+
step /= 2
|
1206
|
+
while abs(start - end) / abs(step) > 100:
|
1207
|
+
step *= 2
|
1208
|
+
|
1209
|
+
pos = start
|
1210
|
+
while min(start, end) <= pos <= max(start, end):
|
1211
|
+
# Primary Line Vertical Raster.
|
1212
|
+
r_start.append((pos, h * 0.1))
|
1213
|
+
r_end.append((pos, h * 0.9))
|
1214
|
+
|
1215
|
+
# Travel Segment
|
1216
|
+
if last is not None:
|
1217
|
+
# Travel Lines
|
1218
|
+
t_start.append((last[0], last[1]))
|
1219
|
+
t_end.append((pos, h * 0.1 if from_top else h * 0.9))
|
1220
|
+
|
1221
|
+
# Arrow Segment
|
1222
|
+
r_start.append((pos, h * 0.9 if from_top else h * 0.1))
|
1223
|
+
r_end.append((pos - 2, (h * 0.9) - 2 if from_top else (h * 0.1) + 2))
|
1224
|
+
|
1225
|
+
last = r_start[-1]
|
1226
|
+
if bidirectional:
|
1227
|
+
from_top = not from_top
|
1228
|
+
pos += step
|
1229
|
+
self.raster_lines = r_start, r_end
|
1230
|
+
self.travel_lines = t_start, t_end
|
1231
|
+
self.direction_lines = d_start, d_end
|
1232
|
+
|
1233
|
+
def refresh_in_ui(self):
|
1234
|
+
"""Performs redrawing of the data in the UI thread."""
|
1235
|
+
try:
|
1236
|
+
visible = self.Shown
|
1237
|
+
except RuntimeError:
|
1238
|
+
# May have already been deleted....
|
1239
|
+
return
|
1240
|
+
dc = wx.MemoryDC()
|
1241
|
+
dc.SelectObject(self._Buffer)
|
1242
|
+
dc.SetBackground(wx.WHITE_BRUSH)
|
1243
|
+
dc.Clear()
|
1244
|
+
gc = wx.GraphicsContext.Create(dc)
|
1245
|
+
if visible:
|
1246
|
+
if self.raster_lines is None:
|
1247
|
+
self.calculate_raster_lines()
|
1248
|
+
if self.raster_lines is not None:
|
1249
|
+
starts, ends = self.raster_lines
|
1250
|
+
if len(starts):
|
1251
|
+
gc.SetPen(self.raster_pen)
|
1252
|
+
gc.StrokeLineSegments(starts, ends)
|
1253
|
+
if self.travel_lines is not None:
|
1254
|
+
starts, ends = self.travel_lines
|
1255
|
+
if len(starts):
|
1256
|
+
gc.SetPen(self.travel_pen)
|
1257
|
+
gc.StrokeLineSegments(starts, ends)
|
1258
|
+
if self.direction_lines is not None:
|
1259
|
+
starts, ends = self.direction_lines
|
1260
|
+
if len(starts):
|
1261
|
+
gc.SetPen(self.direction_pen)
|
1262
|
+
gc.StrokeLineSegments(starts, ends)
|
1263
|
+
gc.Destroy()
|
1264
|
+
dc.SelectObject(wx.NullBitmap)
|
1265
|
+
del dc
|
1266
|
+
self.display_panel.Refresh()
|
1267
|
+
self.display_panel.Update()
|
1268
|
+
|
1269
|
+
def _toggle_sliders(self):
|
1270
|
+
direction = self.operation.raster_direction
|
1271
|
+
prefer_min_y = self.operation.raster_preference_top
|
1272
|
+
prefer_min_x = self.operation.raster_preference_left
|
1273
|
+
|
1274
|
+
self.slider_pref_left.Enable(direction in (RASTER_T2B, RASTER_B2T, RASTER_GREEDY_H, RASTER_GREEDY_V))
|
1275
|
+
self.slider_pref_top.Enable(direction in (RASTER_L2R, RASTER_R2L, RASTER_GREEDY_H, RASTER_GREEDY_V))
|
1276
|
+
self.slider_pref_left.SetValue(0 if prefer_min_x else 1)
|
1277
|
+
self.slider_pref_top.SetValue(0 if prefer_min_y else 1)
|
1278
|
+
|
1279
|
+
|
1280
|
+
def _reload_display(self):
|
1281
|
+
self.raster_lines = None
|
1282
|
+
self.travel_lines = None
|
1283
|
+
self.refresh_display()
|
1284
|
+
|
1285
|
+
def on_slider_pref_left(self, event=None): # wxGlade: OperationProperty.<event_handler>
|
1286
|
+
value = self.slider_pref_left.GetValue() == 0
|
1287
|
+
if self.operation.raster_preference_left != value:
|
1288
|
+
self.operation.raster_preference_left = value
|
1289
|
+
self._reload_display()
|
1290
|
+
self.context.elements.signal(
|
1291
|
+
"element_property_update", self.operation, "slider_top"
|
1292
|
+
)
|
1293
|
+
|
1294
|
+
def on_slider_pref_top(self, event=None): # wxGlade: OperationProperty.<event_handler>
|
1295
|
+
value = self.slider_pref_top.GetValue() == 0
|
1296
|
+
if self.operation.raster_preference_top != value:
|
1297
|
+
self.operation.raster_preference_top = value
|
1298
|
+
self._reload_display()
|
1299
|
+
self.context.elements.signal(
|
1300
|
+
"element_property_update", self.operation, "slider_left"
|
1301
|
+
)
|
1302
|
+
# end of class PanelStartPreference
|
1303
|
+
|
1304
|
+
|
1305
|
+
class RasterSettingsPanel(wx.Panel):
|
1306
|
+
def __init__(self, *args, context=None, node=None, **kwds):
|
1307
|
+
# begin wxGlade: RasterSettingsPanel.__init__
|
1308
|
+
kwds["style"] = kwds.get("style", 0)
|
1309
|
+
wx.Panel.__init__(self, *args, **kwds)
|
1310
|
+
self.context = context
|
1311
|
+
self.operation = node
|
1312
|
+
iconsize = dip_size(self, 30, 20)
|
1313
|
+
bmpsize = min(iconsize[0], iconsize[1]) * self.context.root.bitmap_correction_scale
|
1314
|
+
|
1315
|
+
raster_sizer = StaticBoxSizer(self, wx.ID_ANY, _("Raster:"), wx.VERTICAL)
|
1316
|
+
param_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
1317
|
+
|
1318
|
+
sizer_dpi = StaticBoxSizer(self, wx.ID_ANY, _("DPI:"), wx.HORIZONTAL)
|
1319
|
+
param_sizer.Add(sizer_dpi, 1, wx.EXPAND, 0)
|
1320
|
+
self.check_overrule_dpi = wxCheckBox(self, wx.ID_ANY)
|
1321
|
+
self.check_overrule_dpi.SetToolTip(_("Overrules image dpi settings and uses this value instead"))
|
1322
|
+
self.text_dpi = TextCtrl(
|
1323
|
+
self,
|
1324
|
+
wx.ID_ANY,
|
1325
|
+
"500",
|
1326
|
+
limited=True,
|
1327
|
+
check="int",
|
1328
|
+
style=wx.TE_PROCESS_ENTER,
|
1329
|
+
)
|
1330
|
+
self.text_dpi.set_default_values(
|
1331
|
+
[
|
1332
|
+
(str(dpi), _("Set DPI to {value}").format(value=str(dpi)))
|
1333
|
+
for dpi in self.context.device.view.get_sensible_dpi_values()
|
1334
|
+
]
|
1335
|
+
)
|
1336
|
+
self.text_dpi.set_error_level(1, 100000)
|
1337
|
+
OPERATION_DPI_TOOLTIP = (
|
1338
|
+
_('In a raster engrave, the step size is the distance between raster lines in 1/1000" ') +
|
1339
|
+
_("and also the number of raster dots that get combined together.") + "\n" +
|
1340
|
+
_('Because the laser dot is >> 1/1000" in diameter, at step 1 the raster lines overlap a lot, ') +
|
1341
|
+
_("and consequently you can raster with steps > 1 without leaving gaps between the lines.") + "\n" +
|
1342
|
+
_("The step size before you get gaps will depend on your focus and the size of your laser dot.") + "\n"+
|
1343
|
+
_("Step size > 1 reduces the laser energy delivered by the same factor, so you may need to increase ") +
|
1344
|
+
_("power equivalently with a higher front-panel power, a higher PPI or by rastering at a slower speed.") + "\n" +
|
1345
|
+
_("Step size > 1 also turns the laser on and off fewer times, and combined with a slower speed") +
|
1346
|
+
_("this can prevent your laser from stuttering.")
|
1347
|
+
)
|
1348
|
+
self.text_dpi.SetToolTip(OPERATION_DPI_TOOLTIP)
|
1349
|
+
sizer_dpi.Add(self.check_overrule_dpi, 0, wx.EXPAND, 0)
|
1350
|
+
sizer_dpi.Add(self.text_dpi, 1, wx.EXPAND, 0)
|
1351
|
+
|
1352
|
+
sizer_optimize = StaticBoxSizer(self, wx.ID_ANY, _("Optimize movement:"), wx.HORIZONTAL)
|
1353
|
+
self.check_laserdot = wxCheckBox(self, wx.ID_ANY, _("Consider laserdot") )
|
1354
|
+
self.check_laserdot.SetToolTip(
|
1355
|
+
_("A laser dot has a certain diameter, so for high dpi values, lines will overlap a lot.") + "\n" +
|
1356
|
+
_("Active: don't burn pixels already overlapped") + "\n" +
|
1357
|
+
_("Inactive: burn all pixels regardless of a possible overlap.")
|
1358
|
+
)
|
1359
|
+
sizer_optimize.Add(self.check_laserdot, 1, wx.EXPAND, 0)
|
1360
|
+
param_sizer.Add(sizer_optimize, 1, wx.EXPAND, 0)
|
1361
|
+
|
1362
|
+
self.sizer_grayscale = StaticBoxSizer(self, wx.ID_ANY, _("Override black/white image:"), wx.HORIZONTAL)
|
1363
|
+
param_sizer.Add(self.sizer_grayscale, 1, wx.EXPAND, 0)
|
1364
|
+
self.check_grayscale = wxCheckBox(self, wx.ID_ANY, _("Use grayscale instead") )
|
1365
|
+
self.check_grayscale.SetToolTip(
|
1366
|
+
_("Usually a raster will be created as a grayscale picture and the burn-power of a pixel will depend on its darkness.") + "\n" +
|
1367
|
+
_("If you uncheck this value then every non-white pixel (even very light ones) will become black and will be burned at full power.")
|
1368
|
+
)
|
1369
|
+
self.sizer_grayscale.Add(self.check_grayscale, 1, wx.EXPAND, 0)
|
1370
|
+
|
1371
|
+
sizer_overscan = StaticBoxSizer(self, wx.ID_ANY, _("Overscan:"), wx.HORIZONTAL)
|
1372
|
+
param_sizer.Add(sizer_overscan, 1, wx.EXPAND, 0)
|
1373
|
+
self.text_overscan = TextCtrl(
|
1374
|
+
self,
|
1375
|
+
wx.ID_ANY,
|
1376
|
+
"0mm",
|
1377
|
+
limited=True,
|
1378
|
+
check="length",
|
1379
|
+
style=wx.TE_PROCESS_ENTER,
|
1380
|
+
)
|
1381
|
+
self.text_overscan.SetToolTip(_("Padding that will be added at the end of a scanline to allow the laser to slow down"))
|
1382
|
+
sizer_overscan.Add(self.text_overscan, 1, wx.EXPAND, 0)
|
1383
|
+
|
1384
|
+
raster_sizer.Add(param_sizer, 0, wx.EXPAND, 0)
|
1385
|
+
|
1386
|
+
sizer_4 = StaticBoxSizer(self, wx.ID_ANY, _("Direction:"), wx.HORIZONTAL)
|
1387
|
+
raster_sizer.Add(sizer_4, 0, wx.EXPAND, 0)
|
1388
|
+
self.raster_terms = [
|
1389
|
+
(RASTER_T2B, "Top To Bottom"),
|
1390
|
+
(RASTER_B2T, "Bottom To Top"),
|
1391
|
+
(RASTER_R2L, "Right To Left"),
|
1392
|
+
(RASTER_L2R, "Left To Right"),
|
1393
|
+
(RASTER_HATCH, "Crosshatch"),
|
1394
|
+
(RASTER_GREEDY_H, "Greedy horizontal"),
|
1395
|
+
(RASTER_GREEDY_V, "Greedy vertical"),
|
1396
|
+
(RASTER_CROSSOVER, "Crossover"),
|
1397
|
+
(RASTER_SPIRAL, "Spiral"),
|
1398
|
+
]
|
1399
|
+
# Look for registered raster (image) preprocessors,
|
1400
|
+
# these are routines that take one image as parameter
|
1401
|
+
# and deliver a set of (result image, method (aka raster_direction) )
|
1402
|
+
# that will be dealt with independently
|
1403
|
+
# The registered datastructure is (rasterid, description, method)
|
1404
|
+
self.raster_terms.extend(
|
1405
|
+
(key, description)
|
1406
|
+
for key, description, method in self.context.kernel.lookup_all(
|
1407
|
+
"raster_preprocessor/.*"
|
1408
|
+
)
|
1409
|
+
)
|
1410
|
+
# Add a couple of testcases
|
1411
|
+
# test_methods = (
|
1412
|
+
# (-1, "Test: Horizontal Rectangle"),
|
1413
|
+
# (-2, "Test: Vertical Rectangle"),
|
1414
|
+
# (-3, "Test: Horizontal Snake"),
|
1415
|
+
# (-4, "Test: Vertical Snake"),
|
1416
|
+
# (-5, "Test: Spiral"),
|
1417
|
+
# )
|
1418
|
+
# self.raster_terms.extend(test_methods)
|
1419
|
+
|
1420
|
+
self.raster_methods = [ key for key, info in self.raster_terms ]
|
1421
|
+
|
1422
|
+
self.combo_raster_direction = wxComboBox(
|
1423
|
+
self,
|
1424
|
+
wx.ID_ANY,
|
1425
|
+
style=wx.CB_DROPDOWN | wx.CB_READONLY,
|
1426
|
+
)
|
1427
|
+
OPERATION_RASTERDIRECTION_TOOLTIP = (
|
1428
|
+
_("Direction to perform a raster")
|
1429
|
+
+ "\n"
|
1430
|
+
+ _(
|
1431
|
+
"Normally you would raster in an X-direction and select Top-to-Bottom (T2B) or Bottom-to-Top (B2T)."
|
1432
|
+
)
|
1433
|
+
+ "\n"
|
1434
|
+
+ _(
|
1435
|
+
"This is because rastering in the X-direction involve moving only the laser head which is relatively low mass."
|
1436
|
+
)
|
1437
|
+
+ "\n"
|
1438
|
+
+ _(
|
1439
|
+
"Rastering in the Y-direction (Left-to-Right or Right-to-Left) involves moving not only the laser head "
|
1440
|
+
)
|
1441
|
+
+ _(
|
1442
|
+
"but additionally the entire x-axis gantry assembly including the stepper motor, mirror and the gantry itself."
|
1443
|
+
)
|
1444
|
+
+ "\n"
|
1445
|
+
+ _(
|
1446
|
+
"This total mass is much greater, acceleration therefore needs to be much slower, "
|
1447
|
+
)
|
1448
|
+
+ _(
|
1449
|
+
"and allow for space at each end of the raster to reverse direction the speed has to be much slower."
|
1450
|
+
)
|
1451
|
+
)
|
1452
|
+
|
1453
|
+
self.combo_raster_direction.SetToolTip(OPERATION_RASTERDIRECTION_TOOLTIP)
|
1454
|
+
# OSX needs an early population, as events might occur before pane_show has been called
|
1455
|
+
self.fill_raster_combo()
|
1456
|
+
self.combo_raster_direction.SetSelection(0)
|
1457
|
+
sizer_4.Add(self.combo_raster_direction, 1, wx.ALIGN_CENTER_VERTICAL, 0)
|
1458
|
+
self.btn_instruction = wxStaticBitmap(self, wx.ID_ANY)
|
1459
|
+
self.btn_instruction.SetBitmap(icon_letter_h.GetBitmap(resize=bmpsize))
|
1460
|
+
self.btn_instruction.SetToolTip(_("Quick info about the available modes"))
|
1461
|
+
sizer_4.Add(self.btn_instruction, 0, wx.ALIGN_CENTER_VERTICAL, 0)
|
1462
|
+
|
1463
|
+
self.radio_raster_swing = wxRadioBox(
|
1464
|
+
self,
|
1465
|
+
wx.ID_ANY,
|
1466
|
+
_("Directional Raster:"),
|
1467
|
+
choices=[_("Unidirectional"), _("Bidirectional")],
|
1468
|
+
majorDimension=1,
|
1469
|
+
style=wx.RA_SPECIFY_ROWS,
|
1470
|
+
)
|
1471
|
+
OPERATION_RASTERSWING_TOOLTIP = (
|
1472
|
+
_("Raster on forward and backswing or only forward swing?")
|
1473
|
+
+ "\n"
|
1474
|
+
+ _(
|
1475
|
+
"Rastering only on forward swings will double the time required to complete the raster."
|
1476
|
+
)
|
1477
|
+
+ "\n"
|
1478
|
+
+ _(
|
1479
|
+
"It seems doubtful that there will be significant quality benefits from rastering in one direction."
|
1480
|
+
)
|
1481
|
+
)
|
1482
|
+
self.radio_raster_swing.SetToolTip(OPERATION_RASTERSWING_TOOLTIP)
|
1483
|
+
self.radio_raster_swing.SetSelection(0)
|
1484
|
+
raster_sizer.Add(self.radio_raster_swing, 0, wx.EXPAND, 0)
|
1485
|
+
|
1486
|
+
self.panel_start = PanelStartPreference(
|
1487
|
+
self, wx.ID_ANY, context=context, node=node
|
1488
|
+
)
|
1489
|
+
raster_sizer.Add(self.panel_start, 1, wx.EXPAND, 0)
|
1490
|
+
|
1491
|
+
self.SetSizer(raster_sizer)
|
1492
|
+
|
1493
|
+
self.Layout()
|
1494
|
+
self.Bind(wx.EVT_CHECKBOX, self.on_overrule, self.check_overrule_dpi)
|
1495
|
+
self.Bind(wx.EVT_CHECKBOX, self.on_check_grayscale, self.check_grayscale)
|
1496
|
+
self.Bind(wx.EVT_CHECKBOX, self.on_check_laserdot, self.check_laserdot)
|
1497
|
+
self.text_dpi.SetActionRoutine(self.on_text_dpi)
|
1498
|
+
self.text_overscan.SetActionRoutine(self.on_text_overscan)
|
1499
|
+
|
1500
|
+
self.Bind(
|
1501
|
+
wx.EVT_COMBOBOX, self.on_combo_raster_direction, self.combo_raster_direction
|
1502
|
+
)
|
1503
|
+
self.Bind(wx.EVT_RADIOBOX, self.on_radio_directional, self.radio_raster_swing)
|
1504
|
+
self.btn_instruction.Bind(wx.EVT_LEFT_DOWN, self.on_raster_help)
|
1505
|
+
|
1506
|
+
def fill_raster_combo(self):
|
1507
|
+
unsupported = ()
|
1508
|
+
if hasattr(self.context.device, "get_raster_instructions"):
|
1509
|
+
instructions = self.context.device.get_raster_instructions()
|
1510
|
+
unsupported = instructions.get("unsupported_opt", ())
|
1511
|
+
# print (f"fill raster called: {unsupported}")
|
1512
|
+
self.raster_methods = [ key for key, info in self.raster_terms if key not in unsupported ]
|
1513
|
+
choices = [ info for key, info in self.raster_terms if key not in unsupported ]
|
1514
|
+
self.combo_raster_direction.Clear()
|
1515
|
+
self.combo_raster_direction.SetItems(choices)
|
1516
|
+
if self.operation is not None:
|
1517
|
+
self.set_raster_combo()
|
1518
|
+
|
1519
|
+
@lookup_listener("service/device/active")
|
1520
|
+
def on_device_update(self, *args):
|
1521
|
+
if self.Shown():
|
1522
|
+
self.fill_raster_combo()
|
1523
|
+
|
1524
|
+
def pane_hide(self):
|
1525
|
+
self.panel_start.pane_hide()
|
1526
|
+
|
1527
|
+
def pane_show(self):
|
1528
|
+
self.fill_raster_combo()
|
1529
|
+
self.panel_start.pane_show()
|
1530
|
+
|
1531
|
+
def accepts(self, node):
|
1532
|
+
return node.type in (
|
1533
|
+
"op raster",
|
1534
|
+
"op image",
|
1535
|
+
)
|
1536
|
+
|
1537
|
+
def set_widgets(self, node):
|
1538
|
+
self.operation = node
|
1539
|
+
if self.operation is None or not self.accepts(node):
|
1540
|
+
self.Hide()
|
1541
|
+
return
|
1542
|
+
if self.operation.dpi is not None:
|
1543
|
+
dpi = int(self.operation.dpi)
|
1544
|
+
set_ctrl_value(self.text_dpi, str(dpi))
|
1545
|
+
if hasattr(self.operation, "use_grayscale"):
|
1546
|
+
self.sizer_grayscale.ShowItems(True)
|
1547
|
+
|
1548
|
+
self.check_grayscale.SetValue(self.operation.use_grayscale)
|
1549
|
+
else:
|
1550
|
+
self.sizer_grayscale.ShowItems(False)
|
1551
|
+
if hasattr(self.operation, "overrule_dpi"):
|
1552
|
+
self.check_overrule_dpi.Show(True)
|
1553
|
+
overrule = self.operation.overrule_dpi
|
1554
|
+
if overrule is None:
|
1555
|
+
overrule = False
|
1556
|
+
self.check_overrule_dpi.SetValue(overrule)
|
1557
|
+
self.text_dpi.Enable(overrule)
|
1558
|
+
else:
|
1559
|
+
self.check_overrule_dpi.Show(False)
|
1560
|
+
self.text_dpi.Enable(True)
|
1561
|
+
if self.operation.overscan is not None:
|
1562
|
+
set_ctrl_value(self.text_overscan, str(self.operation.overscan))
|
1563
|
+
self.set_raster_combo()
|
1564
|
+
if self.operation.bidirectional is not None:
|
1565
|
+
self.radio_raster_swing.SetSelection(self.operation.bidirectional)
|
1566
|
+
self.check_laserdot.SetValue(self.operation.consider_laserspot)
|
1567
|
+
# Hide it for now...
|
1568
|
+
# self.check_laserdot.Show(False)
|
1569
|
+
self.allow_controls_according_to_optimization()
|
1570
|
+
self.Show()
|
1571
|
+
|
1572
|
+
def allow_controls_according_to_optimization(self):
|
1573
|
+
direction = self.operation.raster_direction
|
1574
|
+
overscan_okay = direction not in (RASTER_GREEDY_H, RASTER_GREEDY_V)
|
1575
|
+
swing_okay = direction in (RASTER_B2T, RASTER_T2B, RASTER_R2L, RASTER_L2R, RASTER_HATCH)
|
1576
|
+
self.text_overscan.Enable(overscan_okay)
|
1577
|
+
self.radio_raster_swing.Enable(swing_okay)
|
1578
|
+
if not swing_okay:
|
1579
|
+
self.radio_raster_swing.SetSelection(True)
|
1580
|
+
|
1581
|
+
def on_overrule(self, event):
|
1582
|
+
if self.operation is None or not hasattr(self.operation, "overrule_dpi"):
|
1583
|
+
return
|
1584
|
+
b = self.check_overrule_dpi.GetValue()
|
1585
|
+
self.text_dpi.Enable(b)
|
1586
|
+
if self.operation.overrule_dpi != b:
|
1587
|
+
self.operation.overrule_dpi = b
|
1588
|
+
self.context.signal(
|
1589
|
+
"element_property_reload", self.operation, "text_dpi"
|
1590
|
+
)
|
1591
|
+
self.context.signal("warn_state_update")
|
1592
|
+
|
1593
|
+
def on_text_dpi(self):
|
1594
|
+
try:
|
1595
|
+
value = int(self.text_dpi.GetValue())
|
1596
|
+
except ValueError as e:
|
1597
|
+
# print (e)
|
1598
|
+
return
|
1599
|
+
if self.operation.dpi != value:
|
1600
|
+
self.operation.dpi = value
|
1601
|
+
self.context.signal(
|
1602
|
+
"element_property_reload", self.operation, "text_dpi"
|
1603
|
+
)
|
1604
|
+
self.context.signal("warn_state_update")
|
1605
|
+
|
1606
|
+
def on_check_grayscale(self, event):
|
1607
|
+
value = self.check_grayscale.GetValue()
|
1608
|
+
if self.operation.use_grayscale != value:
|
1609
|
+
self.operation.use_grayscale = value
|
1610
|
+
self.context.elements.signal("element_property_reload", self.operation)
|
1611
|
+
|
1612
|
+
def on_check_laserdot(self, event):
|
1613
|
+
value = self.check_laserdot.GetValue()
|
1614
|
+
if self.operation.consider_laserspot != value:
|
1615
|
+
self.operation.consider_laserspot = value
|
1616
|
+
self.context.elements.signal("element_property_reload", self.operation)
|
1617
|
+
|
1618
|
+
def on_text_overscan(self):
|
1619
|
+
try:
|
1620
|
+
v = Length(
|
1621
|
+
self.text_overscan.GetValue(),
|
1622
|
+
unitless=UNITS_PER_MM,
|
1623
|
+
preferred_units="mm",
|
1624
|
+
digits=4,
|
1625
|
+
)
|
1626
|
+
except ValueError:
|
1627
|
+
return
|
1628
|
+
# print ("Start overscan=%s - target=%s" % (start_text, str(v.preferred_length)))
|
1629
|
+
value = v.preferred_length
|
1630
|
+
if v._amount < 1e-10:
|
1631
|
+
value = 0
|
1632
|
+
if self.operation.overscan != value:
|
1633
|
+
self.operation.overscan = value
|
1634
|
+
self.context.elements.signal(
|
1635
|
+
"element_property_reload", self.operation, "text_overscan"
|
1636
|
+
)
|
1637
|
+
|
1638
|
+
def on_combo_raster_direction(self, event=None):
|
1639
|
+
idx = self.combo_raster_direction.GetSelection()
|
1640
|
+
if idx < 0:
|
1641
|
+
return
|
1642
|
+
value = self.raster_methods[idx]
|
1643
|
+
|
1644
|
+
if (self.operation.raster_direction != value ):
|
1645
|
+
self.operation.raster_direction = value
|
1646
|
+
validate_raster_settings(self.operation)
|
1647
|
+
|
1648
|
+
self.context.raster_direction = self.operation.raster_direction
|
1649
|
+
self.context.elements.signal(
|
1650
|
+
"element_property_reload", self.operation, "combo_raster"
|
1651
|
+
)
|
1652
|
+
event.Skip()
|
1653
|
+
|
1654
|
+
def on_radio_directional(self, event=None):
|
1655
|
+
self.operation.bidirectional = bool(self.radio_raster_swing.GetSelection())
|
1656
|
+
self.context.elements.signal(
|
1657
|
+
"element_property_reload", self.operation, "radio_direct"
|
1658
|
+
)
|
1659
|
+
event.Skip()
|
1660
|
+
|
1661
|
+
def set_raster_combo(self):
|
1662
|
+
idx = -1
|
1663
|
+
if self.operation is not None and self.operation.raster_direction is not None:
|
1664
|
+
try:
|
1665
|
+
idx = self.raster_methods.index(self.operation.raster_direction)
|
1666
|
+
except ValueError:
|
1667
|
+
idx = 0
|
1668
|
+
self.combo_raster_direction.SetSelection(idx)
|
1669
|
+
|
1670
|
+
def on_raster_help(self, event):
|
1671
|
+
unsupported = ()
|
1672
|
+
if hasattr(self.context.device, "get_raster_instructions"):
|
1673
|
+
instructions = self.context.device.get_raster_instructions()
|
1674
|
+
unsupported = instructions.get("unsupported_opt", ())
|
1675
|
+
|
1676
|
+
inform = {
|
1677
|
+
RASTER_T2B: _("- Top To Bottom: follows the picture line by line starting at the top"),
|
1678
|
+
RASTER_B2T: _("- Bottom To Top: follows the picture line by line starting at the bottom"),
|
1679
|
+
RASTER_R2L: _("- Right To Left: follows the picture column by column starting at the right side"),
|
1680
|
+
RASTER_L2R: _("- Left To Right: follows the picture column by column starting at the left side"),
|
1681
|
+
RASTER_HATCH: _("- Crosshatch: Makes two passes: one horizontally then another one vertically"),
|
1682
|
+
RASTER_GREEDY_H:
|
1683
|
+
_("- Greedy horizontal: Instead of following a complete line,") + "\n" +
|
1684
|
+
_(" this will choose the nearest to be drawn segment,") + "\n" +
|
1685
|
+
_(" lasering these segments with vertical lines.") + "\n" +
|
1686
|
+
_(" Usually much faster on an image with a lot of white pixels."),
|
1687
|
+
RASTER_GREEDY_V:
|
1688
|
+
_("- Greedy vertical: Instead of following a complete line,") + "\n" +
|
1689
|
+
_(" this will choose the nearest to be drawn segment,") + "\n" +
|
1690
|
+
_(" lasering these segments with vertical lines.") + "\n" +
|
1691
|
+
_(" Usually much faster on an image with a lot of white pixels."),
|
1692
|
+
RASTER_CROSSOVER:
|
1693
|
+
_("- Crossover: Sweeping over the image drawing first all lines") + "\n" +
|
1694
|
+
_(" with a majority of black pixels and then drawing the columns") + "\n" +
|
1695
|
+
_(" where we have a majority.") + "\n" +
|
1696
|
+
_(" Usually much faster on an image with a lot of white pixels."),
|
1697
|
+
RASTER_SPIRAL:
|
1698
|
+
_("- Spiral: Starting in the center spiralling outwards"),
|
1699
|
+
}
|
1700
|
+
lines = [_("You can choose from the following modes to laser an image:")]
|
1701
|
+
lines.extend( [info for key, info in inform.items() if key not in unsupported] )
|
1702
|
+
|
1703
|
+
message = "\n".join(lines)
|
1704
|
+
wx.MessageBox(
|
1705
|
+
caption=_("Help"),
|
1706
|
+
message=message,
|
1707
|
+
style=wx.OK|wx.ICON_INFORMATION
|
1708
|
+
)
|
1709
|
+
|
1710
|
+
# end of class RasterSettingsPanel
|
1711
|
+
|
1712
|
+
|
1713
|
+
class DwellSettingsPanel(wx.Panel):
|
1714
|
+
def __init__(self, *args, context=None, node=None, **kwds):
|
1715
|
+
# begin wxGlade: PassesPanel.__init__
|
1716
|
+
kwds["style"] = kwds.get("style", 0)
|
1717
|
+
wx.Panel.__init__(self, *args, **kwds)
|
1718
|
+
self.context = context
|
1719
|
+
self.operation = node
|
1720
|
+
|
1721
|
+
sizer_passes = StaticBoxSizer(
|
1722
|
+
self, wx.ID_ANY, _("Dwell Time: (ms)"), wx.HORIZONTAL
|
1723
|
+
)
|
1724
|
+
|
1725
|
+
self.text_dwelltime = TextCtrl(
|
1726
|
+
self,
|
1727
|
+
wx.ID_ANY,
|
1728
|
+
"1.0",
|
1729
|
+
limited=True,
|
1730
|
+
style=wx.TE_PROCESS_ENTER,
|
1731
|
+
check="float",
|
1732
|
+
)
|
1733
|
+
self.text_dwelltime.SetToolTip(
|
1734
|
+
_("Dwell time (ms) at each location in the sequence")
|
1735
|
+
)
|
1736
|
+
sizer_passes.Add(self.text_dwelltime, 1, wx.EXPAND, 0)
|
1737
|
+
|
1738
|
+
self.SetSizer(sizer_passes)
|
1739
|
+
|
1740
|
+
self.Layout()
|
1741
|
+
|
1742
|
+
self.text_dwelltime.SetActionRoutine(self.on_text_dwelltime)
|
1743
|
+
# end wxGlade
|
1744
|
+
|
1745
|
+
def pane_hide(self):
|
1746
|
+
pass
|
1747
|
+
|
1748
|
+
def pane_show(self):
|
1749
|
+
pass
|
1750
|
+
|
1751
|
+
def accepts(self, node):
|
1752
|
+
return node.type in ("op dots",)
|
1753
|
+
|
1754
|
+
def set_widgets(self, node):
|
1755
|
+
self.operation = node
|
1756
|
+
if self.operation is None or not self.accepts(node):
|
1757
|
+
self.Hide()
|
1758
|
+
return
|
1759
|
+
set_ctrl_value(self.text_dwelltime, str(self.operation.dwell_time))
|
1760
|
+
self.Show()
|
1761
|
+
|
1762
|
+
def on_text_dwelltime(self):
|
1763
|
+
try:
|
1764
|
+
value = float(self.text_dwelltime.GetValue())
|
1765
|
+
if self.operation.dwell_time != value:
|
1766
|
+
self.operation.dwell_time = value
|
1767
|
+
self.context.elements.signal(
|
1768
|
+
"element_property_reload", self.operation, "text_dwell"
|
1769
|
+
)
|
1770
|
+
except ValueError:
|
1771
|
+
pass
|
1772
|
+
|
1773
|
+
|
1774
|
+
# end of class PassesPanel
|
1775
|
+
|
1776
|
+
|
1777
|
+
class ParameterPanel(ScrolledPanel):
|
1778
|
+
name = _("Properties")
|
1779
|
+
priority = -1
|
1780
|
+
|
1781
|
+
def __init__(self, *args, context=None, node=None, **kwds):
|
1782
|
+
# begin wxGlade: ParameterPanel.__init__
|
1783
|
+
kwds["style"] = kwds.get("style", 0)
|
1784
|
+
ScrolledPanel.__init__(self, *args, **kwds)
|
1785
|
+
self.context = context
|
1786
|
+
self.operation = node
|
1787
|
+
self.panels = []
|
1788
|
+
self.SetHelpText("operationproperty")
|
1789
|
+
|
1790
|
+
param_sizer = wx.BoxSizer(wx.VERTICAL)
|
1791
|
+
|
1792
|
+
self.id_panel = IdPanel(
|
1793
|
+
self,
|
1794
|
+
wx.ID_ANY,
|
1795
|
+
context=context,
|
1796
|
+
node=node,
|
1797
|
+
showid=True,
|
1798
|
+
)
|
1799
|
+
param_sizer.Add(self.id_panel, 0, wx.EXPAND, 0)
|
1800
|
+
self.panels.append(self.id_panel)
|
1801
|
+
|
1802
|
+
self.layer_panel = LayerSettingPanel(
|
1803
|
+
self, wx.ID_ANY, context=context, node=node
|
1804
|
+
)
|
1805
|
+
param_sizer.Add(self.layer_panel, 0, wx.EXPAND, 0)
|
1806
|
+
self.panels.append(self.layer_panel)
|
1807
|
+
|
1808
|
+
self.speedppi_panel = SpeedPpiPanel(self, wx.ID_ANY, context=context, node=node)
|
1809
|
+
param_sizer.Add(self.speedppi_panel, 0, wx.EXPAND, 0)
|
1810
|
+
self.panels.append(self.speedppi_panel)
|
1811
|
+
|
1812
|
+
self.passes_panel = PassesPanel(self, wx.ID_ANY, context=context, node=node)
|
1813
|
+
param_sizer.Add(self.passes_panel, 0, wx.EXPAND, 0)
|
1814
|
+
self.panels.append(self.passes_panel)
|
1815
|
+
|
1816
|
+
self.raster_panel = RasterSettingsPanel(
|
1817
|
+
self, wx.ID_ANY, context=context, node=node
|
1818
|
+
)
|
1819
|
+
param_sizer.Add(self.raster_panel, 1, wx.EXPAND, 0)
|
1820
|
+
self.panels.append(self.raster_panel)
|
1821
|
+
|
1822
|
+
self.dwell_panel = DwellSettingsPanel(
|
1823
|
+
self, wx.ID_ANY, context=context, node=node
|
1824
|
+
)
|
1825
|
+
param_sizer.Add(self.dwell_panel, 0, wx.EXPAND, 0)
|
1826
|
+
self.panels.append(self.dwell_panel)
|
1827
|
+
|
1828
|
+
self.info_panel = InfoPanel(self, wx.ID_ANY, context=context, node=node)
|
1829
|
+
param_sizer.Add(self.info_panel, 0, wx.EXPAND, 0)
|
1830
|
+
self.panels.append(self.info_panel)
|
1831
|
+
|
1832
|
+
self.SetSizer(param_sizer)
|
1833
|
+
|
1834
|
+
self.Layout()
|
1835
|
+
# end wxGlade
|
1836
|
+
|
1837
|
+
@signal_listener("power_percent")
|
1838
|
+
@signal_listener("speed_min")
|
1839
|
+
@lookup_listener("service/device/active")
|
1840
|
+
def on_device_update(self, *args):
|
1841
|
+
self.speedppi_panel.on_device_update()
|
1842
|
+
|
1843
|
+
@signal_listener("element_property_reload")
|
1844
|
+
def on_element_property_reload(self, origin=None, *args):
|
1845
|
+
# Is this something I should care about?
|
1846
|
+
# element_property_reload provides a list of nodes that are affected
|
1847
|
+
# if self.operation isn't one of them, then we just let it slip
|
1848
|
+
for_me = False
|
1849
|
+
if len(args) > 0:
|
1850
|
+
element = args[0]
|
1851
|
+
if isinstance(element, (tuple, list)):
|
1852
|
+
for node in element:
|
1853
|
+
if node == self.operation:
|
1854
|
+
for_me = True
|
1855
|
+
break
|
1856
|
+
elif self.operation == element:
|
1857
|
+
for_me = True
|
1858
|
+
if not for_me:
|
1859
|
+
return
|
1860
|
+
|
1861
|
+
# if origin is None:
|
1862
|
+
# print ("EPR called with no origin")
|
1863
|
+
# else:
|
1864
|
+
# print ("EPR called from:", args)
|
1865
|
+
try:
|
1866
|
+
self.raster_panel.panel_start.on_element_property_reload(*args)
|
1867
|
+
except AttributeError:
|
1868
|
+
pass
|
1869
|
+
self.set_widgets(self.operation)
|
1870
|
+
self.Layout()
|
1871
|
+
|
1872
|
+
def set_widgets(self, node):
|
1873
|
+
try:
|
1874
|
+
self.operation = node
|
1875
|
+
for panel in self.panels:
|
1876
|
+
panel.set_widgets(node)
|
1877
|
+
except RuntimeError:
|
1878
|
+
# Already deleted
|
1879
|
+
return
|
1880
|
+
|
1881
|
+
def pane_hide(self):
|
1882
|
+
for panel in self.panels:
|
1883
|
+
panel.pane_hide()
|
1884
|
+
|
1885
|
+
def pane_show(self):
|
1886
|
+
for panel in self.panels:
|
1887
|
+
panel.pane_show()
|
1888
|
+
|
1889
|
+
|
1890
|
+
# end of class ParameterPanel
|