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/core/treeop.py CHANGED
@@ -2,12 +2,28 @@
2
2
  Tree Operation decorators help define the Tree Operations found mostly in element_treeop class. We create dynamic menus
3
3
  and thus need to classify the various different methods to access a node, without actually creating giant and
4
4
  redundant code for each command on each code type.
5
+
6
+ These functions are overwhelmingly decorators. The `tree_operation` decorator sets the default values for the function
7
+ and all the other decorators set those values.
8
+
9
+ This data is expected to be called in a menu, but can be called via the console or through other methods.
5
10
  """
6
11
 
7
12
  import functools
8
13
 
9
14
 
10
15
  def tree_calc(value_name, calc_func):
16
+ """
17
+ Decorate a calc function.
18
+
19
+ A calculator function will be called for each `value` in values or iterator, and will be permitted to calculate
20
+ some dynamic value from that function.
21
+
22
+ @param value_name:
23
+ @param calc_func:
24
+ @return:
25
+ """
26
+
11
27
  def decor(func):
12
28
  func.calcs.append((value_name, calc_func))
13
29
  return func
@@ -16,6 +32,13 @@ def tree_calc(value_name, calc_func):
16
32
 
17
33
 
18
34
  def tree_values(value_name, values):
35
+ """
36
+ Append explicit list of values and value_name to the function.
37
+ @param value_name:
38
+ @param values:
39
+ @return:
40
+ """
41
+
19
42
  def decor(func):
20
43
  func.value_name = value_name
21
44
  func.values = values
@@ -25,6 +48,16 @@ def tree_values(value_name, values):
25
48
 
26
49
 
27
50
  def tree_iterate(value_name, start, stop, step=1):
51
+ """
52
+ Append range list of values to function.
53
+
54
+ @param value_name:
55
+ @param start: Start value
56
+ @param stop: stop value
57
+ @param step: step amount
58
+ @return:
59
+ """
60
+
28
61
  def decor(func):
29
62
  func.value_name = value_name
30
63
  func.values = range(start, stop, step)
@@ -34,6 +67,13 @@ def tree_iterate(value_name, start, stop, step=1):
34
67
 
35
68
 
36
69
  def tree_radio(radio_function):
70
+ """
71
+ Append radio value to the operation for menus.
72
+
73
+ @param radio_function:
74
+ @return:
75
+ """
76
+
37
77
  def decor(func):
38
78
  func.radio = radio_function
39
79
  return func
@@ -42,6 +82,13 @@ def tree_radio(radio_function):
42
82
 
43
83
 
44
84
  def tree_check(check_function):
85
+ """
86
+ Append checkbox function to the operation for menus.
87
+
88
+ @param check_function:
89
+ @return:
90
+ """
91
+
45
92
  def decor(func):
46
93
  func.check = check_function
47
94
  return func
@@ -50,6 +97,13 @@ def tree_check(check_function):
50
97
 
51
98
 
52
99
  def tree_submenu(submenu):
100
+ """
101
+ Decorate a submenu on to the operation for menus.
102
+
103
+ @param submenu: submenu to use.
104
+ @return:
105
+ """
106
+
53
107
  def decor(func):
54
108
  func.submenu = submenu
55
109
  return func
@@ -58,6 +112,16 @@ def tree_submenu(submenu):
58
112
 
59
113
 
60
114
  def tree_prompt(attr, prompt, data_type=str):
115
+ """
116
+ Decorate a tree_prompt for the operations for menu, this function will request this information from the user
117
+ before calling the tree_operation function with the given attr.
118
+
119
+ @param attr:
120
+ @param prompt:
121
+ @param data_type:
122
+ @return:
123
+ """
124
+
61
125
  def decor(func):
62
126
  func.user_prompt.append(
63
127
  {
@@ -72,6 +136,15 @@ def tree_prompt(attr, prompt, data_type=str):
72
136
 
73
137
 
74
138
  def tree_conditional(conditional):
139
+ """
140
+ Decorate a conditional to the operation for menus.
141
+
142
+ Each conditional decorated to a function must pass for this menu item to show to the user.
143
+
144
+ @param conditional:
145
+ @return:
146
+ """
147
+
75
148
  def decor(func):
76
149
  func.conditionals.append(conditional)
77
150
  return func
@@ -80,6 +153,15 @@ def tree_conditional(conditional):
80
153
 
81
154
 
82
155
  def tree_conditional_try(conditional):
156
+ """
157
+ Decorate a try conditional on this operation for menu.
158
+
159
+ Try conditionals will not crash for the node, and can query states that may not exist.
160
+
161
+ @param conditional:
162
+ @return:
163
+ """
164
+
83
165
  def decor(func):
84
166
  func.try_conditionals.append(conditional)
85
167
  return func
@@ -88,6 +170,12 @@ def tree_conditional_try(conditional):
88
170
 
89
171
 
90
172
  def tree_reference(node):
173
+ """
174
+ Decorate a reference to on the tree.
175
+ @param node:
176
+ @return:
177
+ """
178
+
91
179
  def decor(func):
92
180
  func.reference = node
93
181
  return func
@@ -96,6 +184,12 @@ def tree_reference(node):
96
184
 
97
185
 
98
186
  def tree_separator_after():
187
+ """
188
+ Decorator to flag this operation as having a separator after it.
189
+
190
+ @return:
191
+ """
192
+
99
193
  def decor(func):
100
194
  func.separate_after = True
101
195
  return func
@@ -104,6 +198,12 @@ def tree_separator_after():
104
198
 
105
199
 
106
200
  def tree_separator_before():
201
+ """
202
+ Decorator to flag this operation as having a separator before it.
203
+
204
+ @return:
205
+ """
206
+
107
207
  def decor(func):
108
208
  func.separate_before = True
109
209
  return func
@@ -114,9 +214,28 @@ def tree_separator_before():
114
214
  def tree_operation(
115
215
  registration, name, node_type=None, help=None, enable=True, **kwargs
116
216
  ):
217
+ """
218
+ Main tree registration decorator. Registers the tree operation with the given help and set the enabled state.
219
+
220
+ @param registration: This is either a service or a kernel.
221
+ @param name: Name of the tree operation being registered (required)
222
+ @param node_type: types of node this operation applies to.
223
+ @param help: Help data to be displayed in menu or other help information locations.
224
+ @param enable: Should this be enabled.
225
+ @param kwargs: Any remaining keywords.
226
+ @return:
227
+ """
228
+
117
229
  def decorator(func):
118
230
  @functools.wraps(func)
119
231
  def inner(node, **ik):
232
+ """
233
+ Wrapped inner function executes the operation.
234
+
235
+ @param node:
236
+ @param ik:
237
+ @return:
238
+ """
120
239
  returned = func(node, **ik, **kwargs)
121
240
  return returned
122
241
 
@@ -127,32 +246,70 @@ def tree_operation(
127
246
 
128
247
  # inner.long_help = func.__doc__
129
248
  inner.help = help
249
+
250
+ # Tuple of node types this applies to.
130
251
  inner.node_type = ins
252
+
253
+ # Name of function.
131
254
  inner.name = name
255
+
256
+ # attached radio commands.
132
257
  inner.radio = None
258
+
259
+ # submenu of the operation
133
260
  inner.submenu = None
261
+
262
+ # Optional information
134
263
  inner.reference = None
264
+
265
+ # Should add a separator after this function.
135
266
  inner.separate_after = False
267
+
268
+ # Should add a separator before this function.
136
269
  inner.separate_before = False
270
+
271
+ # Conditionals required to be true to enable function.
137
272
  inner.conditionals = list()
273
+
274
+ # Conditional attempted in a try-execute block (these may throw errors)
138
275
  inner.try_conditionals = list()
276
+
277
+ # Prompt the user to discover this information.
139
278
  inner.user_prompt = list()
279
+
280
+ # Calculations for the values.
140
281
  inner.calcs = list()
282
+
283
+ # List of accepted values.
141
284
  inner.values = [0]
285
+
286
+ # Function enabled/disabled
142
287
  inner.enabled = enable
288
+
289
+ # Registered name is the same as the function name this is attached to.
143
290
  registered_name = inner.__name__
144
291
 
145
292
  for _in in ins:
293
+ # Register tree/node/name for each node within the registration.
146
294
  p = f"tree/{_in}/{registered_name}"
147
295
  if p in registration._registered:
296
+ # We used the name so we may not have duplicate tree operations with the same name.
148
297
  raise NameError(f"A function of this name was already registered: {p}")
149
298
  registration.register(p, inner)
150
299
  return inner
151
300
 
301
+ # Return the entire decorator.
152
302
  return decorator
153
303
 
154
304
 
155
305
  def get_tree_operation(registration):
306
+ """
307
+ Returns a tree op for all the function calls with the registration already set.
308
+
309
+ @param registration:
310
+ @return:
311
+ """
312
+
156
313
  def treeop(name, node_type=None, help=None, enable=True, **kwargs):
157
314
  return tree_operation(
158
315
  registration, name, node_type=node_type, help=help, enable=enable, **kwargs
@@ -162,17 +319,26 @@ def get_tree_operation(registration):
162
319
 
163
320
 
164
321
  def tree_operations_for_node(registration, node):
322
+ """
323
+ Generator to produce all tree operations for the given node.
324
+
325
+ @param registration: kernel or service on which to find these operations
326
+ @param node:
327
+ @return:
328
+ """
165
329
  if node.type is None:
166
330
  return
167
331
  for func, m, sname in registration.find("tree", node.type, ".*"):
168
332
  reject = False
169
333
  for cond in func.conditionals:
334
+ # Do not provide this if the conditionals fail.
170
335
  if not cond(node):
171
336
  reject = True
172
337
  break
173
338
  if reject:
174
339
  continue
175
340
  for cond in func.try_conditionals:
341
+ # Do not provide this if the try conditional fail. Crash is a pass.
176
342
  try:
177
343
  if not cond(node):
178
344
  reject = True
@@ -193,6 +359,13 @@ def tree_operations_for_node(registration, node):
193
359
  )
194
360
 
195
361
  def unescaped(filename):
362
+ """
363
+ Provide unescaped name/label.
364
+ OS dependency is moot.
365
+
366
+ @param filename:
367
+ @return:
368
+ """
196
369
  from platform import system
197
370
 
198
371
  OS_NAME = system()
@@ -202,11 +375,13 @@ def tree_operations_for_node(registration, node):
202
375
  newstring = filename.replace("&", "&&")
203
376
  return newstring
204
377
 
378
+ # Create the operation calling dictionary.
205
379
  func_dict = {
206
380
  "name": unescaped(node_name),
207
381
  "label": unescaped(node_label),
208
382
  }
209
383
 
384
+ # @tree_values / @tree_iterate values to be appended to function dictionary.
210
385
  iterator = func.values
211
386
  if iterator is None:
212
387
  iterator = [0]
@@ -215,7 +390,9 @@ def tree_operations_for_node(registration, node):
215
390
  iterator = list(iterator())
216
391
  except TypeError:
217
392
  pass
393
+
218
394
  for i, value in enumerate(iterator):
395
+ # Every value in the func.values gets an operation for the node.
219
396
  func_dict["iterator"] = i
220
397
  func_dict["value"] = value
221
398
  try:
@@ -224,30 +401,44 @@ def tree_operations_for_node(registration, node):
224
401
  pass
225
402
 
226
403
  for calc in func.calcs:
404
+ # Calculators are done called for the given value, result is set in the call dictionary.
227
405
  key, c = calc
228
406
  value = c(value)
229
407
  func_dict[key] = value
230
408
  if func.radio is not None:
409
+ # Sets the radio state by the radio function.
231
410
  try:
232
411
  func.radio_state = func.radio(node, **func_dict)
233
412
  except:
234
413
  func.radio_state = False
235
414
  else:
236
415
  func.radio_state = None
416
+
237
417
  if hasattr(func, "check") and func.check is not None:
418
+ # Sets the checkbox state by the checkbox function.
238
419
  try:
239
420
  func.check_state = func.check(node, **func_dict)
240
421
  except:
241
422
  func.check_state = False
242
423
  else:
243
424
  func.check_state = None
425
+
426
+ # Function name is formatted such that any {} format brackets are filled with their values.
244
427
  name = func.name.format_map(func_dict)
428
+
429
+ # Set the function and real name and provide it to the caller.
245
430
  func.func_dict = func_dict
246
431
  func.real_name = name
247
432
  yield func
248
433
 
249
434
 
250
435
  def get_tree_operation_for_node(registration):
436
+ """
437
+ Provide treeops for the given registration without needing to provide the registration each time, only the node.
438
+ @param registration:
439
+ @return:
440
+ """
441
+
251
442
  def treeop(node):
252
443
  return tree_operations_for_node(registration, node)
253
444
 
meerk40t/core/undos.py CHANGED
@@ -20,7 +20,8 @@ class UndoState:
20
20
 
21
21
 
22
22
  class Undo:
23
- def __init__(self, tree):
23
+ def __init__(self, service, tree):
24
+ self.service = service
24
25
  self.tree = tree
25
26
  self._lock = threading.Lock()
26
27
  self._undo_stack = []
@@ -53,6 +54,7 @@ class Undo:
53
54
  pass
54
55
  del self._undo_stack[self._undo_index + 1 :]
55
56
  self.message = None
57
+ self.service.signal("undoredo")
56
58
 
57
59
  def undo(self):
58
60
  """
@@ -81,6 +83,7 @@ class Undo:
81
83
  undo.state = self.tree.backup_tree() # Get unused copy
82
84
  except KeyError:
83
85
  pass
86
+ self.service.signal("undoredo")
84
87
  return True
85
88
 
86
89
  def redo(self):
@@ -102,9 +105,20 @@ class Undo:
102
105
  redo.state = self.tree.backup_tree() # Get unused copy
103
106
  except KeyError:
104
107
  pass
108
+ self.service.signal("undoredo")
105
109
  return True
106
110
 
107
111
  def undolist(self):
108
112
  for i, v in enumerate(self._undo_stack):
109
113
  q = "*" if i == self._undo_index else " "
110
114
  yield f"{q}{str(i).ljust(5)}: state {str(v)}"
115
+
116
+ def has_undo(self, *args):
117
+ if self._undo_index == 0:
118
+ # At bottom of stack.
119
+ return False
120
+ # Stack is entirely empty.
121
+ return len(self._undo_stack) != 0
122
+
123
+ def has_redo(self, *args):
124
+ return self._undo_index < len(self._undo_stack) - 1
meerk40t/core/units.py CHANGED
@@ -462,7 +462,7 @@ class Angle:
462
462
  converts to other forms of angle. Failures to parse raise ValueError.
463
463
  """
464
464
 
465
- def __init__(self, angle, digits=None):
465
+ def __init__(self, angle, digits=None, preferred_units="rad"):
466
466
  if isinstance(angle, Angle):
467
467
  self._digits = angle._digits
468
468
  self.angle = angle.angle
@@ -471,7 +471,7 @@ class Angle:
471
471
  self._digits = digits
472
472
  if not isinstance(angle, str):
473
473
  self.angle = float(angle)
474
- self.preferred_units = "rad"
474
+ self.preferred_units = preferred_units
475
475
  return
476
476
  angle = angle.lower()
477
477
  if angle.endswith("deg"):
@@ -492,13 +492,15 @@ class Angle:
492
492
  self.preferred_units = "%"
493
493
  else:
494
494
  self.angle = float(angle)
495
- self.preferred_units = "rad"
495
+ self.preferred_units = preferred_units
496
496
 
497
497
  def __str__(self):
498
498
  return self.angle_preferred
499
499
 
500
500
  def __copy__(self):
501
- return Angle(self.angle)
501
+ return Angle(
502
+ self.angle, preferred_units=self.preferred_units, digits=self._digits
503
+ )
502
504
 
503
505
  def __eq__(self, other):
504
506
  if hasattr(other, "angle"):
@@ -506,6 +508,14 @@ class Angle:
506
508
  c1 = abs((self.angle % tau) - (other % tau)) <= 1e-11
507
509
  return c1
508
510
 
511
+ def __float__(self):
512
+ return self.radians
513
+
514
+ def __neg__(self):
515
+ return Angle(
516
+ -self.angle, preferred_units=self.preferred_units, digits=self._digits
517
+ )
518
+
509
519
  def normalize(self):
510
520
  self.angle /= tau
511
521
 
@@ -2,7 +2,7 @@ from meerk40t.core.spoolers import Spooler
2
2
  from meerk40t.core.view import View
3
3
  from meerk40t.kernel import Service
4
4
 
5
- from ..core.units import UNITS_PER_MIL
5
+ from .mixins import Status
6
6
 
7
7
 
8
8
  def plugin(kernel, lifecycle=None):
@@ -27,7 +27,7 @@ def plugin(kernel, lifecycle=None):
27
27
  )
28
28
 
29
29
 
30
- class DummyDevice(Service):
30
+ class DummyDevice(Service, Status):
31
31
  """
32
32
  DummyDevice is a mock device service. It provides no actual device.
33
33
 
@@ -36,6 +36,7 @@ class DummyDevice(Service):
36
36
 
37
37
  def __init__(self, kernel, path, *args, choices=None, **kwargs):
38
38
  Service.__init__(self, kernel, path)
39
+ Status.__init__(self)
39
40
  self.name = "Dummy Device"
40
41
  if choices is not None:
41
42
  for c in choices:
@@ -2,18 +2,18 @@ import wx
2
2
 
3
3
  from meerk40t.gui.icons import (
4
4
  STD_ICON_SIZE,
5
- icons8_bell_20,
6
- icons8_close_window_20,
7
- icons8_down_50,
8
- icons8_home_20,
9
- icons8_input_20,
10
- icons8_output_20,
11
- icons8_remove_25,
12
- icons8_return_20,
13
- icons8_stop_gesture_20,
14
- icons8_system_task_20,
15
- icons8_timer_20,
16
- icons8_up_50,
5
+ icon_bell,
6
+ icon_close_window,
7
+ icon_console,
8
+ icon_external,
9
+ icon_internal,
10
+ icon_return,
11
+ icon_round_stop,
12
+ icon_timer,
13
+ icon_trash,
14
+ icons8_down,
15
+ icons8_home_filled,
16
+ icons8_up,
17
17
  )
18
18
  from meerk40t.gui.wxutils import StaticBoxSizer, dip_size
19
19
 
@@ -41,17 +41,17 @@ class DefaultActionPanel(wx.Panel):
41
41
  ("Console", "util console", ""),
42
42
  )
43
43
  self.default_images = [
44
- ["console home -f", icons8_home_20],
45
- ["console move_abs", icons8_return_20],
46
- ["console beep", icons8_bell_20],
47
- ["console interrupt", icons8_stop_gesture_20],
48
- ["console quit", icons8_close_window_20],
49
- ["util wait", icons8_timer_20],
50
- ["util home", icons8_home_20],
51
- ["util goto", icons8_return_20], # icons8_visit_20
52
- ["util output", icons8_output_20],
53
- ["util input", icons8_input_20],
54
- ["util console", icons8_system_task_20],
44
+ ["console home -f", icons8_home_filled],
45
+ ["console move_abs", icon_return],
46
+ ["console beep", icon_bell],
47
+ ["console interrupt", icon_round_stop],
48
+ ["console quit", icon_close_window],
49
+ ["util wait", icon_timer],
50
+ ["util home", icons8_home_filled],
51
+ ["util goto", icon_return], # icon_marker
52
+ ["util output", icon_external],
53
+ ["util input", icon_internal],
54
+ ["util console", icon_console],
55
55
  ]
56
56
  self.prepend_ops = []
57
57
  self.append_ops = []
@@ -61,6 +61,8 @@ class DefaultActionPanel(wx.Panel):
61
61
  sizer_after = StaticBoxSizer(self, wx.ID_ANY, _("At job end"), wx.VERTICAL)
62
62
  sizer_middle = wx.BoxSizer(wx.VERTICAL)
63
63
 
64
+ iconsize = dip_size(self, 30, 20)
65
+ bmpsize = min(iconsize[0], iconsize[1])
64
66
  self.option_list = wx.ListCtrl(
65
67
  self,
66
68
  wx.ID_ANY,
@@ -77,42 +79,24 @@ class DefaultActionPanel(wx.Panel):
77
79
 
78
80
  self.append_list = wx.ListCtrl(self, wx.ID_ANY, style=wx.LC_LIST)
79
81
  self.text_param_append = wx.TextCtrl(self, wx.ID_ANY)
80
- self.button_del_prepend = wx.StaticBitmap(
81
- self, wx.ID_ANY, size=dip_size(self, 30, 30)
82
- )
83
- self.button_up_prepend = wx.StaticBitmap(
84
- self, wx.ID_ANY, size=dip_size(self, 30, 30)
85
- )
86
- self.button_down_prepend = wx.StaticBitmap(
87
- self, wx.ID_ANY, size=dip_size(self, 30, 20)
88
- )
82
+ self.button_del_prepend = wx.StaticBitmap(self, wx.ID_ANY, size=iconsize)
83
+ self.button_up_prepend = wx.StaticBitmap(self, wx.ID_ANY, size=iconsize)
84
+ self.button_down_prepend = wx.StaticBitmap(self, wx.ID_ANY, size=iconsize)
89
85
  self.button_del_prepend.SetBitmap(
90
- icons8_remove_25.GetBitmap(resize=STD_ICON_SIZE / 2)
91
- )
92
- self.button_up_prepend.SetBitmap(
93
- icons8_up_50.GetBitmap(resize=STD_ICON_SIZE / 2)
86
+ icon_trash.GetBitmap(resize=bmpsize, buffer=1)
94
87
  )
88
+ self.button_up_prepend.SetBitmap(icons8_up.GetBitmap(resize=bmpsize, buffer=1))
95
89
  self.button_down_prepend.SetBitmap(
96
- icons8_down_50.GetBitmap(resize=STD_ICON_SIZE / 2)
90
+ icons8_down.GetBitmap(resize=bmpsize, buffer=1)
97
91
  )
98
92
 
99
- self.button_del_append = wx.StaticBitmap(
100
- self, wx.ID_ANY, size=dip_size(self, 30, 30)
101
- )
102
- self.button_up_append = wx.StaticBitmap(
103
- self, wx.ID_ANY, size=dip_size(self, 30, 30)
104
- )
105
- self.button_down_append = wx.StaticBitmap(
106
- self, wx.ID_ANY, size=dip_size(self, 30, 30)
107
- )
108
- self.button_del_append.SetBitmap(
109
- icons8_remove_25.GetBitmap(resize=STD_ICON_SIZE / 2)
110
- )
111
- self.button_up_append.SetBitmap(
112
- icons8_up_50.GetBitmap(resize=STD_ICON_SIZE / 2)
113
- )
93
+ self.button_del_append = wx.StaticBitmap(self, wx.ID_ANY, size=iconsize)
94
+ self.button_up_append = wx.StaticBitmap(self, wx.ID_ANY, size=iconsize)
95
+ self.button_down_append = wx.StaticBitmap(self, wx.ID_ANY, size=iconsize)
96
+ self.button_del_append.SetBitmap(icon_trash.GetBitmap(resize=bmpsize, buffer=1))
97
+ self.button_up_append.SetBitmap(icons8_up.GetBitmap(resize=bmpsize, buffer=1))
114
98
  self.button_down_append.SetBitmap(
115
- icons8_down_50.GetBitmap(resize=STD_ICON_SIZE / 2)
99
+ icons8_down.GetBitmap(resize=bmpsize, buffer=1)
116
100
  )
117
101
 
118
102
  sizer_param = StaticBoxSizer(
@@ -479,7 +463,9 @@ class DefaultActionPanel(wx.Panel):
479
463
  setattr(self.context, str_count, len(self.append_ops))
480
464
 
481
465
  def setup_state_images(self):
482
- iconsize = 20
466
+ testsize = dip_size(self, 20, 20)
467
+ iconsize = testsize[1]
468
+
483
469
  self.options_images = wx.ImageList()
484
470
  self.options_images.Create(width=iconsize, height=iconsize)
485
471
  self.prepend_images = wx.ImageList()
@@ -487,7 +473,9 @@ class DefaultActionPanel(wx.Panel):
487
473
  self.append_images = wx.ImageList()
488
474
  self.append_images.Create(width=iconsize, height=iconsize)
489
475
  for entry in self.default_images:
490
- image = entry[1].GetBitmap(resize=(iconsize, iconsize), noadjustment=True)
476
+ image = entry[1].GetBitmap(
477
+ resize=(iconsize, iconsize), buffer=2, noadjustment=True
478
+ )
491
479
  image_id1 = self.options_images.Add(bitmap=image)
492
480
  image_id2 = self.prepend_images.Add(bitmap=image)
493
481
  image_id3 = self.append_images.Add(bitmap=image)