meerk40t 0.9.2000__py2.py3-none-any.whl → 0.9.3001__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.
Files changed (187) hide show
  1. meerk40t/balormk/balor_params.py +1 -43
  2. meerk40t/balormk/controller.py +1 -41
  3. meerk40t/balormk/device.py +16 -22
  4. meerk40t/balormk/driver.py +4 -4
  5. meerk40t/balormk/gui/balorconfig.py +2 -2
  6. meerk40t/balormk/gui/balorcontroller.py +13 -5
  7. meerk40t/balormk/gui/baloroperationproperties.py +0 -46
  8. meerk40t/balormk/gui/gui.py +17 -17
  9. meerk40t/camera/gui/camerapanel.py +18 -11
  10. meerk40t/core/cutcode/rastercut.py +3 -1
  11. meerk40t/core/cutplan.py +145 -14
  12. meerk40t/core/elements/clipboard.py +18 -9
  13. meerk40t/core/elements/element_treeops.py +320 -180
  14. meerk40t/core/elements/element_types.py +7 -2
  15. meerk40t/core/elements/elements.py +53 -27
  16. meerk40t/core/elements/geometry.py +8 -0
  17. meerk40t/core/elements/offset_clpr.py +129 -4
  18. meerk40t/core/elements/offset_mk.py +3 -1
  19. meerk40t/core/elements/shapes.py +28 -25
  20. meerk40t/core/laserjob.py +7 -0
  21. meerk40t/core/node/bootstrap.py +4 -0
  22. meerk40t/core/node/effect_hatch.py +85 -96
  23. meerk40t/core/node/effect_wobble.py +309 -0
  24. meerk40t/core/node/elem_image.py +49 -19
  25. meerk40t/core/node/elem_line.py +60 -0
  26. meerk40t/core/node/elem_rect.py +5 -3
  27. meerk40t/core/node/image_processed.py +766 -0
  28. meerk40t/core/node/image_raster.py +113 -0
  29. meerk40t/core/node/node.py +120 -1
  30. meerk40t/core/node/op_cut.py +2 -8
  31. meerk40t/core/node/op_dots.py +0 -8
  32. meerk40t/core/node/op_engrave.py +2 -18
  33. meerk40t/core/node/op_image.py +22 -35
  34. meerk40t/core/node/op_raster.py +0 -9
  35. meerk40t/core/planner.py +32 -2
  36. meerk40t/core/svg_io.py +699 -461
  37. meerk40t/core/treeop.py +191 -0
  38. meerk40t/core/undos.py +15 -1
  39. meerk40t/core/units.py +14 -4
  40. meerk40t/device/dummydevice.py +3 -2
  41. meerk40t/device/gui/defaultactions.py +43 -55
  42. meerk40t/device/gui/formatterpanel.py +58 -49
  43. meerk40t/device/gui/warningpanel.py +12 -12
  44. meerk40t/device/mixins.py +13 -0
  45. meerk40t/dxf/dxf_io.py +9 -5
  46. meerk40t/extra/ezd.py +28 -26
  47. meerk40t/extra/imageactions.py +300 -308
  48. meerk40t/extra/lbrn.py +19 -2
  49. meerk40t/fill/fills.py +6 -6
  50. meerk40t/fill/patternfill.py +1061 -1061
  51. meerk40t/fill/patterns.py +2 -6
  52. meerk40t/grbl/controller.py +168 -52
  53. meerk40t/grbl/device.py +23 -18
  54. meerk40t/grbl/driver.py +39 -0
  55. meerk40t/grbl/emulator.py +79 -19
  56. meerk40t/grbl/gcodejob.py +10 -0
  57. meerk40t/grbl/gui/grblconfiguration.py +2 -2
  58. meerk40t/grbl/gui/grblcontroller.py +24 -8
  59. meerk40t/grbl/gui/grblhardwareconfig.py +153 -0
  60. meerk40t/grbl/gui/gui.py +17 -14
  61. meerk40t/grbl/mock_connection.py +15 -34
  62. meerk40t/grbl/plugin.py +0 -4
  63. meerk40t/grbl/serial_connection.py +2 -1
  64. meerk40t/gui/about.py +8 -5
  65. meerk40t/gui/alignment.py +10 -6
  66. meerk40t/gui/basicops.py +27 -17
  67. meerk40t/gui/bufferview.py +2 -2
  68. meerk40t/gui/choicepropertypanel.py +101 -13
  69. meerk40t/gui/consolepanel.py +12 -9
  70. meerk40t/gui/devicepanel.py +38 -25
  71. meerk40t/gui/executejob.py +6 -4
  72. meerk40t/gui/help_assets/help_assets.py +13 -10
  73. meerk40t/gui/hersheymanager.py +8 -6
  74. meerk40t/gui/icons.py +1951 -3065
  75. meerk40t/gui/imagesplitter.py +14 -7
  76. meerk40t/gui/keymap.py +3 -3
  77. meerk40t/gui/laserpanel.py +151 -84
  78. meerk40t/gui/laserrender.py +61 -70
  79. meerk40t/gui/lasertoolpanel.py +8 -7
  80. meerk40t/gui/materialtest.py +3 -3
  81. meerk40t/gui/mkdebug.py +254 -1
  82. meerk40t/gui/navigationpanels.py +321 -180
  83. meerk40t/gui/notes.py +3 -3
  84. meerk40t/gui/opassignment.py +12 -12
  85. meerk40t/gui/operation_info.py +13 -13
  86. meerk40t/gui/plugin.py +5 -0
  87. meerk40t/gui/position.py +20 -18
  88. meerk40t/gui/preferences.py +21 -6
  89. meerk40t/gui/propertypanels/attributes.py +70 -22
  90. meerk40t/gui/propertypanels/blobproperty.py +2 -2
  91. meerk40t/gui/propertypanels/consoleproperty.py +2 -2
  92. meerk40t/gui/propertypanels/groupproperties.py +3 -3
  93. meerk40t/gui/propertypanels/hatchproperty.py +11 -18
  94. meerk40t/gui/propertypanels/imageproperty.py +4 -3
  95. meerk40t/gui/propertypanels/opbranchproperties.py +1 -1
  96. meerk40t/gui/propertypanels/pathproperty.py +2 -2
  97. meerk40t/gui/propertypanels/pointproperty.py +2 -2
  98. meerk40t/gui/propertypanels/propertywindow.py +4 -4
  99. meerk40t/gui/propertypanels/textproperty.py +3 -3
  100. meerk40t/gui/propertypanels/wobbleproperty.py +204 -0
  101. meerk40t/gui/ribbon.py +367 -259
  102. meerk40t/gui/scene/scene.py +31 -5
  103. meerk40t/gui/scenewidgets/elementswidget.py +12 -4
  104. meerk40t/gui/scenewidgets/gridwidget.py +2 -2
  105. meerk40t/gui/scenewidgets/laserpathwidget.py +7 -2
  106. meerk40t/gui/scenewidgets/machineoriginwidget.py +6 -2
  107. meerk40t/gui/scenewidgets/relocatewidget.py +1 -1
  108. meerk40t/gui/scenewidgets/reticlewidget.py +9 -0
  109. meerk40t/gui/scenewidgets/selectionwidget.py +12 -7
  110. meerk40t/gui/simpleui.py +95 -8
  111. meerk40t/gui/simulation.py +44 -36
  112. meerk40t/gui/spoolerpanel.py +124 -26
  113. meerk40t/gui/statusbarwidgets/defaultoperations.py +18 -6
  114. meerk40t/gui/statusbarwidgets/infowidget.py +2 -2
  115. meerk40t/gui/statusbarwidgets/opassignwidget.py +12 -12
  116. meerk40t/gui/statusbarwidgets/shapepropwidget.py +45 -18
  117. meerk40t/gui/statusbarwidgets/statusbar.py +11 -4
  118. meerk40t/gui/themes.py +78 -0
  119. meerk40t/gui/toolwidgets/toolcircle.py +2 -1
  120. meerk40t/gui/toolwidgets/toolellipse.py +2 -1
  121. meerk40t/gui/toolwidgets/toolimagecut.py +132 -0
  122. meerk40t/gui/toolwidgets/toolline.py +144 -0
  123. meerk40t/gui/toolwidgets/toolnodeedit.py +72 -145
  124. meerk40t/gui/toolwidgets/toolpoint.py +1 -1
  125. meerk40t/gui/toolwidgets/toolpolygon.py +8 -55
  126. meerk40t/gui/toolwidgets/toolrect.py +2 -1
  127. meerk40t/gui/usbconnect.py +2 -2
  128. meerk40t/gui/utilitywidgets/cyclocycloidwidget.py +2 -2
  129. meerk40t/gui/utilitywidgets/harmonograph.py +7 -7
  130. meerk40t/gui/utilitywidgets/scalewidget.py +1 -1
  131. meerk40t/gui/wordlisteditor.py +33 -18
  132. meerk40t/gui/wxmeerk40t.py +166 -66
  133. meerk40t/gui/wxmmain.py +236 -157
  134. meerk40t/gui/wxmribbon.py +49 -25
  135. meerk40t/gui/wxmscene.py +49 -38
  136. meerk40t/gui/wxmtree.py +216 -85
  137. meerk40t/gui/wxutils.py +62 -4
  138. meerk40t/image/imagetools.py +443 -15
  139. meerk40t/internal_plugins.py +2 -10
  140. meerk40t/kernel/kernel.py +12 -4
  141. meerk40t/lihuiyu/controller.py +7 -7
  142. meerk40t/lihuiyu/device.py +3 -1
  143. meerk40t/lihuiyu/driver.py +3 -0
  144. meerk40t/lihuiyu/gui/gui.py +8 -8
  145. meerk40t/lihuiyu/gui/lhyaccelgui.py +2 -2
  146. meerk40t/lihuiyu/gui/lhycontrollergui.py +73 -27
  147. meerk40t/lihuiyu/gui/lhydrivergui.py +2 -2
  148. meerk40t/lihuiyu/gui/tcpcontroller.py +22 -9
  149. meerk40t/main.py +6 -1
  150. meerk40t/moshi/controller.py +5 -5
  151. meerk40t/moshi/device.py +5 -2
  152. meerk40t/moshi/driver.py +4 -0
  153. meerk40t/moshi/gui/gui.py +8 -8
  154. meerk40t/moshi/gui/moshicontrollergui.py +24 -8
  155. meerk40t/moshi/gui/moshidrivergui.py +2 -2
  156. meerk40t/newly/controller.py +2 -0
  157. meerk40t/newly/device.py +9 -2
  158. meerk40t/newly/driver.py +4 -0
  159. meerk40t/newly/gui/gui.py +16 -17
  160. meerk40t/newly/gui/newlyconfig.py +2 -2
  161. meerk40t/newly/gui/newlycontroller.py +13 -5
  162. meerk40t/rotary/gui/gui.py +2 -2
  163. meerk40t/rotary/gui/rotarysettings.py +2 -2
  164. meerk40t/ruida/device.py +3 -0
  165. meerk40t/ruida/driver.py +4 -0
  166. meerk40t/ruida/gui/gui.py +6 -6
  167. meerk40t/ruida/gui/ruidaconfig.py +2 -2
  168. meerk40t/ruida/gui/ruidacontroller.py +13 -5
  169. meerk40t/svgelements.py +9 -9
  170. meerk40t/tools/geomstr.py +849 -153
  171. meerk40t/tools/kerftest.py +8 -4
  172. meerk40t/tools/livinghinges.py +15 -8
  173. {meerk40t-0.9.2000.dist-info → meerk40t-0.9.3001.dist-info}/METADATA +21 -16
  174. {meerk40t-0.9.2000.dist-info → meerk40t-0.9.3001.dist-info}/RECORD +185 -177
  175. {meerk40t-0.9.2000.dist-info → meerk40t-0.9.3001.dist-info}/entry_points.txt +0 -1
  176. test/test_core_elements.py +8 -24
  177. test/test_file_svg.py +88 -0
  178. test/test_fill.py +9 -9
  179. test/test_geomstr.py +258 -8
  180. test/test_kernel.py +4 -0
  181. test/test_tools_rasterplotter.py +29 -0
  182. meerk40t/extra/embroider.py +0 -56
  183. meerk40t/extra/pathoptimize.py +0 -249
  184. {meerk40t-0.9.2000.dist-info → meerk40t-0.9.3001.dist-info}/LICENSE +0 -0
  185. {meerk40t-0.9.2000.dist-info → meerk40t-0.9.3001.dist-info}/WHEEL +0 -0
  186. {meerk40t-0.9.2000.dist-info → meerk40t-0.9.3001.dist-info}/top_level.txt +0 -0
  187. {meerk40t-0.9.2000.dist-info → meerk40t-0.9.3001.dist-info}/zip-safe +0 -0
meerk40t/grbl/emulator.py CHANGED
@@ -83,7 +83,9 @@ lookup = {
83
83
 
84
84
 
85
85
  class GRBLEmulator:
86
- def __init__(self, device=None, units_to_device_matrix=None):
86
+ def __init__(
87
+ self, device=None, units_to_device_matrix=None, reply=None, channel=None
88
+ ):
87
89
  self.device = device
88
90
  self.units_to_device_matrix = units_to_device_matrix
89
91
  self.settings = {
@@ -127,18 +129,23 @@ class GRBLEmulator:
127
129
  self.rapid_scale = 1.0
128
130
  self.power_scale = 1.0
129
131
 
130
- self.reply = None
131
- self.channel = None
132
+ self.reply = reply
133
+ self.channel = channel
132
134
 
133
135
  self._grbl_specific = False
134
136
 
135
137
  self._buffer = list()
138
+ try:
139
+ driver = device.driver
140
+ except AttributeError:
141
+ driver = None
136
142
  self.job = GcodeJob(
137
- driver=device.driver,
143
+ driver=driver,
138
144
  priority=0,
139
145
  channel=self.channel,
140
146
  units_to_device_matrix=units_to_device_matrix,
141
147
  )
148
+ self.job.reply = self.reply
142
149
 
143
150
  def __repr__(self):
144
151
  return "GRBLInterpreter()"
@@ -154,19 +161,27 @@ class GRBLEmulator:
154
161
  def status_update(self):
155
162
  # TODO: This should reference only the driver.status.
156
163
  # Idle, Run, Hold, Jog, Alarm, Door, Check, Home, Sleep
157
- pos, state, minor = self.device.driver.status()
158
- x, y = self.units_to_device_matrix.point_in_inverse_space(pos)
164
+ try:
165
+ pos, state, minor = self.device.driver.status()
166
+ x, y = self.units_to_device_matrix.point_in_inverse_space(pos)
167
+ z = 0.0
168
+ if state == "busy":
169
+ state = "Run"
170
+ elif state == "hold":
171
+ state = "Hold"
172
+ else:
173
+ state = "Idle"
174
+ f = self.device.driver.speed
175
+ s = self.device.driver.power
176
+ except AttributeError:
177
+ state = "Idle"
178
+ x = self.job.x
179
+ y = self.job.y
180
+ z = self.job.z
181
+ f = 0
182
+ s = 0
159
183
  x /= self.job.scale
160
184
  y /= self.job.scale
161
- z = 0.0
162
- if state == "busy":
163
- state = "Run"
164
- elif state == "hold":
165
- state = "Hold"
166
- else:
167
- state = "Idle"
168
- f = self.device.driver.speed
169
- s = self.device.driver.power
170
185
  return f"<{state}|MPos:{x:.3f},{y:.3f},{z:.3f}|FS:{f},{s}>\r\n"
171
186
 
172
187
  def write(self, data):
@@ -194,16 +209,18 @@ class GRBLEmulator:
194
209
  self.device.driver.pause()
195
210
  except AttributeError:
196
211
  pass
197
- elif c in (ord("\r"), ord("\n")):
212
+ elif c in (13, 10): # "\r","\n"
198
213
  # Process CRLF endlines
199
214
  line = "".join(self._buffer)
200
215
  if self._grbl_specific:
201
216
  self._grbl_specific = False
202
217
  self.reply_code(self._grbl_special(line))
203
218
  else:
204
- self.device.spooler.send(self.job, prevent_duplicate=True)
205
- self.job.reply = self.reply
206
219
  self.job.write(line)
220
+ try:
221
+ self.device.spooler.send(self.job, prevent_duplicate=True)
222
+ except AttributeError:
223
+ self.job.execute(None)
207
224
  self._buffer.clear()
208
225
  elif c == 0x08:
209
226
  # Process Backspaces.
@@ -214,6 +231,11 @@ class GRBLEmulator:
214
231
  self.device.driver.reset()
215
232
  except AttributeError:
216
233
  pass
234
+ self._buffer.clear()
235
+ if self.reply:
236
+ self.reply(
237
+ "Grbl 1.1f ['$' for help]\r\n" "[MSG:’$H’|’$X’ to unlock]\r\n"
238
+ )
217
239
  elif c > 0x80:
218
240
  if c == 0x84:
219
241
  # Safety Door
@@ -358,9 +380,47 @@ class GRBLEmulator:
358
380
  elif data == "$I":
359
381
  # View Build Info
360
382
  return 0
383
+ elif data == "$#":
384
+ if self.reply:
385
+ data = [
386
+ "[G54:0.000,0.000,0.000]",
387
+ "[G55:0.000,0.000,0.000]",
388
+ "[G56:0.000,0.000,0.000]",
389
+ "[G57:0.000,0.000,0.000]",
390
+ "[G58:0.000,0.000,0.000]",
391
+ "[G59:0.000,0.000,0.000]",
392
+ "[G28:0.000,0.000,0.000]",
393
+ "[G30:0.000,0.000,0.000]",
394
+ "[G92:0.000,0.000,0.000]",
395
+ "[TLO:0.000]",
396
+ "[PRB:0.000,0.000,0.000:0]",
397
+ "",
398
+ ]
399
+ self.reply("\r\n".join(data))
400
+ return 0
361
401
  elif data == "$G":
362
402
  # View GCode Parser state
363
- return 3
403
+ if self.reply:
404
+ job = self.job
405
+ modals = list()
406
+ # G0 G54 G17 G21 G90 G94 M5 M9 T0 F0 S0
407
+ modals.append(f"G{job.move_mode}")
408
+ modals.append("G54") # default coord system.
409
+ modals.append("G17") # XY plane
410
+ modals.append("G21" if job.units == "mm" else "G20") # MM data.
411
+ modals.append("G91" if job.relative else "G90")
412
+ modals.append(
413
+ "G94" if job.feed_desc in ("inch/min", "mm/min") else "G93"
414
+ )
415
+ modals.append("M5") # Not currently in a program job.
416
+ modals.append("M9") # Mist cooling.
417
+ modals.append("T0") # Tool 0
418
+ modals.append(f"F{int(job.get_feed_rate())}")
419
+ modals.append(f"S{int(job.get_power_rate())}")
420
+
421
+ modes = " ".join(modals)
422
+ self.reply(f"[GC:{modes}]\r\n")
423
+ return 0
364
424
  elif data == "$N":
365
425
  # View saved start up code.
366
426
  return 3
meerk40t/grbl/gcodejob.py CHANGED
@@ -180,6 +180,16 @@ class GcodeJob:
180
180
  else:
181
181
  return "Disabled"
182
182
 
183
+ def get_feed_rate(self):
184
+ if self.speed is None:
185
+ return 0
186
+ return self.feed_invert(self.speed)
187
+
188
+ def get_power_rate(self):
189
+ if self.power is None:
190
+ return 0
191
+ return self.power
192
+
183
193
  def inform(self, last_command):
184
194
  if not hasattr(self._driver, "signal"):
185
195
  return
@@ -6,7 +6,7 @@ from meerk40t.device.gui.defaultactions import DefaultActionPanel
6
6
  from meerk40t.device.gui.formatterpanel import FormatterPanel
7
7
  from meerk40t.device.gui.warningpanel import WarningPanel
8
8
  from meerk40t.gui.choicepropertypanel import ChoicePropertyPanel
9
- from meerk40t.gui.icons import icons8_administrative_tools_50
9
+ from meerk40t.gui.icons import icons8_administrative_tools
10
10
  from meerk40t.gui.mwindow import MWindow
11
11
  from meerk40t.gui.wxutils import ScrolledPanel, StaticBoxSizer
12
12
  from meerk40t.kernel import signal_listener
@@ -130,7 +130,7 @@ class GRBLConfiguration(MWindow):
130
130
  super().__init__(345, 415, *args, **kwds)
131
131
  self.context = self.context.device
132
132
  _icon = wx.NullIcon
133
- _icon.CopyFromBitmap(icons8_administrative_tools_50.GetBitmap())
133
+ _icon.CopyFromBitmap(icons8_administrative_tools.GetBitmap())
134
134
  self.SetIcon(_icon)
135
135
  self.SetTitle(_("GRBL-Configuration"))
136
136
 
@@ -6,7 +6,11 @@ import threading
6
6
 
7
7
  import wx
8
8
 
9
- from meerk40t.gui.icons import icons8_connected_50, icons8_disconnected_50
9
+ from meerk40t.gui.icons import (
10
+ get_default_icon_size,
11
+ icons8_connected,
12
+ icons8_disconnected,
13
+ )
10
14
  from meerk40t.gui.mwindow import MWindow
11
15
  from meerk40t.gui.wxutils import dip_size
12
16
  from meerk40t.kernel import signal_listener
@@ -46,7 +50,7 @@ class GRBLControllerPanel(wx.Panel):
46
50
  _("Force connection/disconnection from the device.")
47
51
  )
48
52
  self.button_device_connect.SetBitmap(
49
- icons8_connected_50.GetBitmap(use_theme=False)
53
+ icons8_connected.GetBitmap(use_theme=False, resize=get_default_icon_size())
50
54
  )
51
55
  sizer_1.Add(self.button_device_connect, 0, wx.EXPAND, 0)
52
56
 
@@ -87,7 +91,11 @@ class GRBLControllerPanel(wx.Panel):
87
91
  btn.Bind(wx.EVT_BUTTON, self.send_gcode(entry[0]))
88
92
  btn.SetToolTip(entry[2])
89
93
  if entry[3] is not None:
90
- btn.SetBitmap(entry[3].GetBitmap(size=25, use_theme=False))
94
+ btn.SetBitmap(
95
+ entry[3].GetBitmap(
96
+ resize=0.5 * get_default_icon_size(), use_theme=False
97
+ )
98
+ )
91
99
  sizer_2.Add(btn, 1, wx.EXPAND, 0)
92
100
  self.btn_clear = wx.Button(self, wx.ID_ANY, _("Clear"))
93
101
  self.btn_clear.SetToolTip(_("Clear log window"))
@@ -180,14 +188,18 @@ class GRBLControllerPanel(wx.Panel):
180
188
  self.button_device_connect.SetBackgroundColour("#ffff00")
181
189
  self.button_device_connect.SetLabel(_("Connect"))
182
190
  self.button_device_connect.SetBitmap(
183
- icons8_disconnected_50.GetBitmap(use_theme=False)
191
+ icons8_disconnected.GetBitmap(
192
+ use_theme=False, resize=get_default_icon_size()
193
+ )
184
194
  )
185
195
  self.button_device_connect.Enable()
186
196
  elif state == "connected":
187
197
  self.button_device_connect.SetBackgroundColour("#00ff00")
188
198
  self.button_device_connect.SetLabel(_("Disconnect"))
189
199
  self.button_device_connect.SetBitmap(
190
- icons8_connected_50.GetBitmap(use_theme=False)
200
+ icons8_connected.GetBitmap(
201
+ use_theme=False, resize=get_default_icon_size()
202
+ )
191
203
  )
192
204
  self.button_device_connect.Enable()
193
205
 
@@ -200,14 +212,18 @@ class GRBLControllerPanel(wx.Panel):
200
212
  self.button_device_connect.SetBackgroundColour("#ffff00")
201
213
  self.button_device_connect.SetLabel(_("Connect"))
202
214
  self.button_device_connect.SetBitmap(
203
- icons8_disconnected_50.GetBitmap(use_theme=False)
215
+ icons8_disconnected.GetBitmap(
216
+ use_theme=False, resize=get_default_icon_size()
217
+ )
204
218
  )
205
219
  self.button_device_connect.Enable()
206
220
  elif self.state == "connected":
207
221
  self.button_device_connect.SetBackgroundColour("#00ff00")
208
222
  self.button_device_connect.SetLabel(_("Disconnect"))
209
223
  self.button_device_connect.SetBitmap(
210
- icons8_connected_50.GetBitmap(use_theme=False)
224
+ icons8_connected.GetBitmap(
225
+ use_theme=False, resize=get_default_icon_size()
226
+ )
211
227
  )
212
228
  self.button_device_connect.Enable()
213
229
 
@@ -221,7 +237,7 @@ class GRBLController(MWindow):
221
237
  self.service = self.context.device
222
238
  self.SetTitle("GRBL Controller")
223
239
  _icon = wx.NullIcon
224
- _icon.CopyFromBitmap(icons8_connected_50.GetBitmap())
240
+ _icon.CopyFromBitmap(icons8_connected.GetBitmap())
225
241
  self.SetIcon(_icon)
226
242
 
227
243
  self.serial_panel = GRBLControllerPanel(self, wx.ID_ANY, context=self.service)
@@ -0,0 +1,153 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: UTF-8 -*-
3
+ #
4
+ # generated by wxGlade 1.0.5 on Mon Nov 13 07:33:41 2023
5
+ #
6
+
7
+ import threading
8
+
9
+ import wx
10
+
11
+ from meerk40t.grbl.controller import hardware_settings
12
+ from meerk40t.gui.icons import icons8_curly_brackets
13
+ from meerk40t.gui.mwindow import MWindow
14
+ from meerk40t.gui.wxutils import EditableListCtrl, ScrolledPanel, dip_size
15
+ from meerk40t.kernel import signal_listener
16
+
17
+ _ = wx.GetTranslation
18
+
19
+
20
+ class GrblIoButtons(wx.Panel):
21
+ def __init__(self, *args, context=None, **kwds):
22
+ self.service = context
23
+ kwds["style"] = kwds.get("style", 0)
24
+ wx.Panel.__init__(self, *args, **kwds)
25
+
26
+ sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
27
+
28
+ self.button_refresh = wx.Button(self, wx.ID_ANY, "Refresh")
29
+ sizer_2.Add(self.button_refresh, 1, 0, 0)
30
+ self.Bind(wx.EVT_BUTTON, self.on_button_refresh, self.button_refresh)
31
+
32
+ # self.button_write = wx.Button(self, wx.ID_ANY, "Write")
33
+ # sizer_2.Add(self.button_write, 1, 0, 0)
34
+ #
35
+ # self.button_export = wx.Button(self, wx.ID_ANY, "Export")
36
+ # sizer_2.Add(self.button_export, 1, 0, 0)
37
+
38
+ self.SetSizer(sizer_2)
39
+
40
+ def on_button_refresh(self, event):
41
+ self.service("gcode $$\n")
42
+
43
+
44
+ class GrblHardwareProperties(ScrolledPanel):
45
+ def __init__(self, *args, context=None, **kwds):
46
+ self.service = context
47
+ kwds["style"] = kwds.get("style", 0)
48
+ ScrolledPanel.__init__(self, *args, **kwds)
49
+
50
+ sizer_1 = wx.BoxSizer(wx.VERTICAL)
51
+
52
+ chart = EditableListCtrl(
53
+ self,
54
+ wx.ID_ANY,
55
+ style=wx.LC_HRULES | wx.LC_REPORT | wx.LC_VRULES | wx.LC_SINGLE_SEL,
56
+ )
57
+ self.chart = chart
58
+ self.build_columns()
59
+ self.fill_chart()
60
+
61
+ chart.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.on_label_start_edit)
62
+ chart.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.on_label_end_edit)
63
+
64
+ sizer_1.Add(self.chart, 8, wx.EXPAND, 0)
65
+
66
+ self.io_panel = GrblIoButtons(self, wx.ID_ANY, context=self.service)
67
+ sizer_1.Add(self.io_panel, 1, wx.EXPAND, 0)
68
+ self.SetSizer(sizer_1)
69
+
70
+ def build_columns(self):
71
+ chart = self.chart
72
+ for column, width in (
73
+ ("$#", 60),
74
+ ("Parameter", 200),
75
+ ("Value", 100),
76
+ ("Unit", 100),
77
+ ("Description", 1000),
78
+ ):
79
+ chart.AppendColumn(
80
+ column,
81
+ format=wx.LIST_FORMAT_LEFT,
82
+ width=width,
83
+ )
84
+
85
+ def fill_chart(self):
86
+ chart = self.chart
87
+ chart.DeleteAllItems()
88
+ settings = hardware_settings
89
+ for i in range(200):
90
+ d = settings(i)
91
+ if d is None:
92
+ continue
93
+ if i in self.service.hardware_config:
94
+ value = str(self.service.hardware_config[i])
95
+ else:
96
+ value = ""
97
+ ignore, parameter, units = d
98
+
99
+ row_id = chart.InsertItem(chart.GetItemCount(), f"${i}")
100
+ chart.SetItem(row_id, 1, str(parameter))
101
+ chart.SetItem(row_id, 2, str(value))
102
+ chart.SetItem(row_id, 3, str(units))
103
+ chart.SetItem(row_id, 4, str(parameter.upper()))
104
+
105
+ def on_label_start_edit(self, event):
106
+ event.Allow()
107
+
108
+ def on_label_end_edit(self, event):
109
+ row_id = event.GetIndex() # Get the current row
110
+ col_id = event.GetColumn() # Get the current column
111
+ new_data = event.GetLabel() # Get the changed data
112
+ self.chart.SetItem(row_id, col_id, new_data)
113
+
114
+ @signal_listener("grbl:hwsettings")
115
+ def hardware_settings_changed(self, origin, *args):
116
+ self.fill_chart()
117
+
118
+ def pane_show(self):
119
+ pass
120
+
121
+ def pane_hide(self):
122
+ return
123
+
124
+
125
+ # end of class GrblHardwareProperties
126
+
127
+
128
+ class GRBLHardwareConfig(MWindow):
129
+ def __init__(self, *args, **kwds):
130
+ super().__init__(1000, 500, *args, **kwds)
131
+ self.service = self.context.device
132
+ self.SetTitle(_("GRBL Hardware Config"))
133
+ _icon = wx.NullIcon
134
+ _icon.CopyFromBitmap(icons8_curly_brackets.GetBitmap())
135
+ self.SetIcon(_icon)
136
+
137
+ self.hw_panel = GrblHardwareProperties(self, wx.ID_ANY, context=self.service)
138
+ self.Layout()
139
+ self._opened_port = None
140
+ # end wxGlade
141
+
142
+ def window_open(self):
143
+ self.hw_panel.pane_show()
144
+
145
+ def window_close(self):
146
+ self.hw_panel.pane_hide()
147
+
148
+ def delegates(self):
149
+ yield self.hw_panel
150
+
151
+ @staticmethod
152
+ def submenu():
153
+ return "Device-Control", "GRBL Hardware Config"
meerk40t/grbl/gui/gui.py CHANGED
@@ -14,14 +14,15 @@ def plugin(service, lifecycle):
14
14
  if lifecycle == "added":
15
15
  from meerk40t.grbl.gui.grblconfiguration import GRBLConfiguration
16
16
  from meerk40t.grbl.gui.grblcontroller import GRBLController
17
+ from meerk40t.grbl.gui.grblhardwareconfig import GRBLHardwareConfig
17
18
  from meerk40t.gui.icons import (
18
- icons8_computer_support_50,
19
- icons8_connected_50,
20
- icons8_emergency_stop_button_50,
21
- icons8_flash_off_50,
22
- icons8_info_50,
23
- icons8_pause_50,
24
- icons8_quick_mode_on_50,
19
+ icons8_computer_support,
20
+ icons8_connected,
21
+ icons8_emergency_stop_button,
22
+ icons8_flash_off,
23
+ icons8_flash_on,
24
+ icons8_info,
25
+ icons8_pause,
25
26
  )
26
27
 
27
28
  service.register("window/GRBLController", GRBLController)
@@ -30,13 +31,15 @@ def plugin(service, lifecycle):
30
31
  service.register("window/Configuration", GRBLConfiguration)
31
32
  service.register("winpath/Configuration", service)
32
33
 
34
+ service.register("window/GrblHardwareConfig", GRBLHardwareConfig)
35
+
33
36
  _ = service._
34
37
 
35
38
  service.register(
36
39
  "button/control/Controller",
37
40
  {
38
41
  "label": _("Controller"),
39
- "icon": icons8_connected_50,
42
+ "icon": icons8_connected,
40
43
  "tip": _("Opens Controller Window"),
41
44
  "action": lambda v: service("window toggle GRBLController\n"),
42
45
  },
@@ -45,7 +48,7 @@ def plugin(service, lifecycle):
45
48
  "button/device/Configuration",
46
49
  {
47
50
  "label": _("Config"),
48
- "icon": icons8_computer_support_50,
51
+ "icon": icons8_computer_support,
49
52
  "tip": _("Opens device-specific configuration window"),
50
53
  "action": lambda v: service("window toggle Configuration\n"),
51
54
  },
@@ -54,7 +57,7 @@ def plugin(service, lifecycle):
54
57
  "button/control/Pause",
55
58
  {
56
59
  "label": _("Pause"),
57
- "icon": icons8_pause_50,
60
+ "icon": icons8_pause,
58
61
  "tip": _("Pause the laser"),
59
62
  "action": lambda v: service("pause\n"),
60
63
  },
@@ -64,7 +67,7 @@ def plugin(service, lifecycle):
64
67
  "button/control/Stop",
65
68
  {
66
69
  "label": _("Stop"),
67
- "icon": icons8_emergency_stop_button_50,
70
+ "icon": icons8_emergency_stop_button,
68
71
  "tip": _("Emergency stop the laser"),
69
72
  "action": lambda v: service("estop\n"),
70
73
  },
@@ -82,13 +85,13 @@ def plugin(service, lifecycle):
82
85
  "button/control/Redlight",
83
86
  {
84
87
  "label": _("Red Dot On"),
85
- "icon": icons8_quick_mode_on_50,
88
+ "icon": icons8_flash_on,
86
89
  "tip": _("Turn Redlight On"),
87
90
  "action": lambda v: service("red on\n"),
88
91
  "toggle": {
89
92
  "label": _("Red Dot Off"),
90
93
  "action": lambda v: service("red off\n"),
91
- "icon": icons8_flash_off_50,
94
+ "icon": icons8_flash_off,
92
95
  "signal": "grbl_red_dot",
93
96
  },
94
97
  "rule_enabled": lambda v: has_red_dot_enabled(),
@@ -99,7 +102,7 @@ def plugin(service, lifecycle):
99
102
  "button/control/ClearAlarm",
100
103
  {
101
104
  "label": _("Clear Alarm"),
102
- "icon": icons8_info_50,
105
+ "icon": icons8_info,
103
106
  "tip": _("Send a GRBL Clear Alarm command"),
104
107
  "action": lambda v: service("clear_alarm\n"),
105
108
  },
@@ -5,6 +5,7 @@ Mock Connection for GRBL
5
5
  The mock connection is used for debug and research purposes. And simply prints the data sent to it rather than engaging
6
6
  any hardware.
7
7
  """
8
+ from meerk40t.grbl.emulator import GRBLEmulator
8
9
 
9
10
 
10
11
  class MockConnection:
@@ -13,48 +14,29 @@ class MockConnection:
13
14
  self.controller = controller
14
15
  self.laser = None
15
16
  self.read_buffer = bytearray()
16
- self.just_connected = False
17
+ self.emulator = GRBLEmulator(
18
+ device=None, units_to_device_matrix=service.view.matrix, reply=self.add_read
19
+ )
17
20
 
18
21
  @property
19
22
  def connected(self):
20
23
  return self.laser is not None
21
24
 
22
- @property
23
- def _index_of_read_line(self):
24
- try:
25
- r = self.read_buffer.index(b"\r")
26
- except ValueError:
27
- r = -1
28
- try:
29
- n = self.read_buffer.index(b"\n")
30
- except ValueError:
31
- n = -1
32
-
33
- if n != -1:
34
- return min(n, r) if r != -1 else n
35
- else:
36
- return r
37
-
38
- def read_buffer_command(self):
39
- q = self._index_of_read_line
40
- if q == -1:
41
- raise ValueError("No forward command exists.")
42
- cmd_issued = self.read_buffer[: q + 1]
43
- self.read_buffer = self.read_buffer[q + 1 :]
44
- return cmd_issued
25
+ def add_read(self, code):
26
+ self.read_buffer += bytes(code, encoding="raw_unicode_escape")
45
27
 
46
28
  def read(self):
47
- if self.just_connected:
48
- self.just_connected = False
49
- return "Grbl 1.1f ['$' for help]\r\n" "[MSG:’$H’|’$X’ to unlock]\r\n"
50
- try:
51
- cmd = self.read_buffer_command()
52
- return "ok"
53
- except ValueError:
54
- return ""
29
+ f = self.read_buffer.find(b"\n")
30
+ if f == -1:
31
+ return None
32
+ response = self.read_buffer[:f]
33
+ self.read_buffer = self.read_buffer[f + 1 :]
34
+ str_response = str(response, "raw_unicode_escape")
35
+ str_response = str_response.strip()
36
+ return str_response
55
37
 
56
38
  def write(self, line: str):
57
- self.read_buffer += line.encode(encoding="latin-1")
39
+ self.emulator.write(line)
58
40
 
59
41
  def connect(self):
60
42
  if self.laser:
@@ -63,7 +45,6 @@ class MockConnection:
63
45
  try:
64
46
  self.controller.log("Attempting to Connect...", type="connection")
65
47
  self.laser = True
66
- self.just_connected = True
67
48
  self.controller.log("Connected", type="connection")
68
49
  self.service.signal("grbl;status", "connected")
69
50
  except ConnectionError:
meerk40t/grbl/plugin.py CHANGED
@@ -64,10 +64,6 @@ def plugin(kernel, lifecycle=None):
64
64
  "attr": "label",
65
65
  "default": "FluidNC",
66
66
  },
67
- {
68
- "attr": "requires_validation",
69
- "default": False,
70
- },
71
67
  {
72
68
  "attr": "source",
73
69
  "default": "generic",
@@ -36,7 +36,8 @@ class SerialConnection:
36
36
  def write(self, line):
37
37
  try:
38
38
  self.laser.write(bytes(line, "utf-8"))
39
- except (SerialException, PermissionError) as e:
39
+ except (SerialException, PermissionError, TypeError) as e:
40
+ # Type error occurs when `pipe_abort_write_r` is none, inside serialpostix.read() (out of sequence close)
40
41
  self.controller.log(
41
42
  f"Error when writing '{line}: {str(e)}'", type="connection"
42
43
  )
meerk40t/gui/about.py CHANGED
@@ -3,9 +3,9 @@ import datetime
3
3
  import wx
4
4
 
5
5
  from ..main import APPLICATION_NAME, APPLICATION_VERSION
6
- from .icons import icon_meerk40t, icons8_about_50
6
+ from .icons import icon_about, icon_meerk40t
7
7
  from .mwindow import MWindow
8
- from .wxutils import StaticBoxSizer
8
+ from .wxutils import ScrolledPanel, StaticBoxSizer
9
9
 
10
10
  _ = wx.GetTranslation
11
11
 
@@ -139,11 +139,11 @@ class AboutPanel(wx.Panel):
139
139
  # end wxGlade
140
140
 
141
141
 
142
- class InformationPanel(wx.Panel):
142
+ class InformationPanel(ScrolledPanel):
143
143
  def __init__(self, *args, context=None, **kwds):
144
144
  # begin wxGlade: MovePanel.__init__
145
145
  kwds["style"] = kwds.get("style", 0) | wx.TAB_TRAVERSAL
146
- wx.Panel.__init__(self, *args, **kwds)
146
+ ScrolledPanel.__init__(self, *args, **kwds)
147
147
  self.context = context
148
148
  self.mk_version = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_READONLY)
149
149
  self.py_version = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_READONLY)
@@ -152,12 +152,14 @@ class InformationPanel(wx.Panel):
152
152
  self.os_version = wx.TextCtrl(
153
153
  self, wx.ID_ANY, "", style=wx.TE_READONLY | wx.TE_MULTILINE
154
154
  )
155
+ self.os_version.SetMinSize(wx.Size(-1, 5 * 25))
155
156
  self.info_btn = wx.Button(self, wx.ID_ANY, _("Copy to Clipboard"))
156
157
  self.Bind(wx.EVT_BUTTON, self.copy_debug_info, self.info_btn)
157
158
  self.update_btn = wx.Button(self, wx.ID_ANY, _("Check for Updates"))
158
159
  self.Bind(wx.EVT_BUTTON, self.check_for_updates, self.update_btn)
159
160
  self.__set_properties()
160
161
  self.__do_layout()
162
+ self.SetupScrolling()
161
163
 
162
164
  def __set_properties(self):
163
165
  # Fill the content...
@@ -181,6 +183,7 @@ class InformationPanel(wx.Panel):
181
183
  info += f"Version: {uname.version}" + "\n"
182
184
  info += f"Machine: {uname.machine}" + "\n"
183
185
  info += f"Processor: {uname.processor}" + "\n"
186
+ info += f"Theme: {self.context.themes.theme}, Darkmode: {self.context.themes.dark}\n"
184
187
  try:
185
188
  info += f"Ip-Address: {socket.gethostbyname(socket.gethostname())}"
186
189
  except socket.gaierror:
@@ -284,7 +287,7 @@ class About(MWindow):
284
287
  self.add_module_delegate(self.panel_about)
285
288
  self.add_module_delegate(self.panel_info)
286
289
  _icon = wx.NullIcon
287
- _icon.CopyFromBitmap(icons8_about_50.GetBitmap())
290
+ _icon.CopyFromBitmap(icon_about.GetBitmap())
288
291
  self.SetIcon(_icon)
289
292
  self.SetTitle(_("About"))
290
293