meerk40t 0.9.7030__py2.py3-none-any.whl → 0.9.7040__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 (79) hide show
  1. meerk40t/balormk/clone_loader.py +3 -2
  2. meerk40t/balormk/controller.py +28 -11
  3. meerk40t/balormk/cylindermod.py +1 -0
  4. meerk40t/balormk/device.py +13 -9
  5. meerk40t/balormk/driver.py +9 -2
  6. meerk40t/balormk/galvo_commands.py +3 -1
  7. meerk40t/balormk/gui/gui.py +6 -0
  8. meerk40t/balormk/livelightjob.py +338 -321
  9. meerk40t/balormk/mock_connection.py +4 -3
  10. meerk40t/balormk/usb_connection.py +11 -2
  11. meerk40t/camera/camera.py +19 -14
  12. meerk40t/camera/gui/camerapanel.py +6 -0
  13. meerk40t/core/cutplan.py +109 -51
  14. meerk40t/core/elements/element_treeops.py +435 -140
  15. meerk40t/core/elements/elements.py +100 -9
  16. meerk40t/core/elements/shapes.py +259 -39
  17. meerk40t/core/elements/tree_commands.py +10 -5
  18. meerk40t/core/node/elem_ellipse.py +18 -8
  19. meerk40t/core/node/elem_image.py +51 -19
  20. meerk40t/core/node/elem_line.py +18 -8
  21. meerk40t/core/node/elem_path.py +18 -8
  22. meerk40t/core/node/elem_point.py +10 -4
  23. meerk40t/core/node/elem_polyline.py +19 -11
  24. meerk40t/core/node/elem_rect.py +18 -8
  25. meerk40t/core/node/elem_text.py +11 -5
  26. meerk40t/core/node/filenode.py +2 -8
  27. meerk40t/core/node/groupnode.py +11 -11
  28. meerk40t/core/node/image_processed.py +11 -5
  29. meerk40t/core/node/image_raster.py +11 -5
  30. meerk40t/core/node/node.py +64 -16
  31. meerk40t/core/node/refnode.py +2 -1
  32. meerk40t/core/svg_io.py +91 -34
  33. meerk40t/device/dummydevice.py +7 -1
  34. meerk40t/extra/vtracer.py +222 -0
  35. meerk40t/grbl/device.py +81 -8
  36. meerk40t/gui/about.py +20 -0
  37. meerk40t/gui/devicepanel.py +20 -16
  38. meerk40t/gui/gui_mixins.py +4 -0
  39. meerk40t/gui/icons.py +330 -253
  40. meerk40t/gui/laserpanel.py +8 -3
  41. meerk40t/gui/laserrender.py +41 -21
  42. meerk40t/gui/magnetoptions.py +158 -65
  43. meerk40t/gui/materialtest.py +229 -39
  44. meerk40t/gui/navigationpanels.py +229 -24
  45. meerk40t/gui/propertypanels/hatchproperty.py +2 -0
  46. meerk40t/gui/propertypanels/imageproperty.py +160 -106
  47. meerk40t/gui/ribbon.py +6 -1
  48. meerk40t/gui/scenewidgets/gridwidget.py +29 -32
  49. meerk40t/gui/scenewidgets/rectselectwidget.py +190 -192
  50. meerk40t/gui/simulation.py +75 -77
  51. meerk40t/gui/statusbarwidgets/defaultoperations.py +84 -48
  52. meerk40t/gui/statusbarwidgets/infowidget.py +2 -2
  53. meerk40t/gui/tips.py +15 -1
  54. meerk40t/gui/toolwidgets/toolpointmove.py +3 -1
  55. meerk40t/gui/wxmmain.py +242 -114
  56. meerk40t/gui/wxmscene.py +107 -24
  57. meerk40t/gui/wxmtree.py +4 -2
  58. meerk40t/gui/wxutils.py +60 -15
  59. meerk40t/image/imagetools.py +129 -65
  60. meerk40t/internal_plugins.py +4 -0
  61. meerk40t/kernel/kernel.py +39 -18
  62. meerk40t/kernel/settings.py +28 -9
  63. meerk40t/lihuiyu/device.py +24 -12
  64. meerk40t/main.py +1 -1
  65. meerk40t/moshi/device.py +20 -6
  66. meerk40t/network/console_server.py +22 -6
  67. meerk40t/newly/device.py +10 -3
  68. meerk40t/newly/gui/gui.py +10 -0
  69. meerk40t/ruida/device.py +22 -2
  70. meerk40t/ruida/loader.py +6 -3
  71. meerk40t/tools/geomstr.py +193 -125
  72. meerk40t/tools/rasterplotter.py +179 -93
  73. {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/METADATA +1 -1
  74. {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/RECORD +79 -78
  75. {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/LICENSE +0 -0
  76. {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/WHEEL +0 -0
  77. {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/entry_points.txt +0 -0
  78. {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/top_level.txt +0 -0
  79. {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/zip-safe +0 -0
@@ -2,7 +2,6 @@
2
2
  This is a giant list of console commands that deal with and often implement the elements system in the program.
3
3
  """
4
4
 
5
-
6
5
  from meerk40t.kernel import CommandSyntaxError
7
6
 
8
7
  from .element_types import *
@@ -39,9 +38,10 @@ def init_commands(kernel):
39
38
  for i, n in enumerate(node.children):
40
39
  p = list(path)
41
40
  p.append(str(i))
42
- channel(
43
- f"{'.'.join(p).ljust(10)}: {str(n._bounds)} - {str(n._bounds_dirty)} {str(n.type)} - {str(str(n)[:16])}"
44
- )
41
+ if hasattr(n, "_bounds"):
42
+ channel(
43
+ f"{'.'.join(p).ljust(10)}: {str(n._bounds)} - {str(n._bounds_dirty)} {str(n.type)} - {str(str(n)[:16])}"
44
+ )
45
45
  b_list(p, n)
46
46
 
47
47
  for d in data:
@@ -49,7 +49,12 @@ def init_commands(kernel):
49
49
  if d.type == "root":
50
50
  channel(_("Tree:"))
51
51
  else:
52
- channel(f"{str(d)}:")
52
+ if hasattr(d, "_bounds"):
53
+ channel(
54
+ f"{str(d)}: {str(d._bounds)} - {str(d._bounds_dirty)} {str(d.type)} - {str(str(d)[:16])}"
55
+ )
56
+ else:
57
+ channel(f"{str(d)}:")
53
58
  b_list([], d)
54
59
  channel("----------")
55
60
 
@@ -3,8 +3,8 @@ from math import cos, sin, sqrt, tau
3
3
 
4
4
  from meerk40t.core.node.mixins import (
5
5
  FunctionalParameter,
6
- Stroked,
7
6
  LabelDisplay,
7
+ Stroked,
8
8
  Suppressable,
9
9
  )
10
10
  from meerk40t.core.node.node import Fillrule, Node
@@ -171,12 +171,16 @@ class EllipseNode(Node, Stroked, FunctionalParameter, LabelDisplay, Suppressable
171
171
  tablen = self.mktablength
172
172
  numtabs = self.mktabpositions
173
173
  if tablen and numtabs:
174
- path = Geomstr.wobble_tab(path, tablen, resolution, numtabs, unit_factor=unit_factor)
174
+ path = Geomstr.wobble_tab(
175
+ path, tablen, resolution, numtabs, unit_factor=unit_factor
176
+ )
175
177
  # Is there a dash/dot pattern to apply?
176
178
  dashlen = self.stroke_dash
177
179
  irrelevant = 50
178
180
  if dashlen:
179
- path = Geomstr.wobble_dash(path, dashlen, resolution, irrelevant, unit_factor=unit_factor)
181
+ path = Geomstr.wobble_dash(
182
+ path, dashlen, resolution, irrelevant, unit_factor=unit_factor
183
+ )
180
184
 
181
185
  return path
182
186
 
@@ -261,19 +265,25 @@ class EllipseNode(Node, Stroked, FunctionalParameter, LabelDisplay, Suppressable
261
265
  return default_map
262
266
 
263
267
  def can_drop(self, drag_node):
268
+ if self.is_a_child_of(drag_node):
269
+ return False
264
270
  # Dragging element into element.
265
271
  return bool(
266
- hasattr(drag_node, "as_geometry") or
267
- hasattr(drag_node, "as_image") or
268
- (drag_node.type.startswith("op ") and drag_node.type != "op dots") or
269
- drag_node.type in ("file", "group")
272
+ hasattr(drag_node, "as_geometry")
273
+ or hasattr(drag_node, "as_image")
274
+ or (drag_node.type.startswith("op ") and drag_node.type != "op dots")
275
+ or drag_node.type in ("file", "group")
270
276
  )
271
277
 
272
278
  def drop(self, drag_node, modify=True, flag=False):
273
279
  # Dragging element into element.
274
280
  if not self.can_drop(drag_node):
275
281
  return False
276
- if hasattr(drag_node, "as_geometry") or hasattr(drag_node, "as_image") or drag_node.type in ("file", "group"):
282
+ if (
283
+ hasattr(drag_node, "as_geometry")
284
+ or hasattr(drag_node, "as_image")
285
+ or drag_node.type in ("file", "group")
286
+ ):
277
287
  if modify:
278
288
  self.insert_sibling(drag_node)
279
289
  return True
@@ -27,19 +27,21 @@ Methods:
27
27
  bbox(transformed=True, with_stroke=False): Returns the bounding box of the image.
28
28
  """
29
29
 
30
- import numpy as np
31
30
  import threading
32
31
  import time
33
32
  from copy import copy
34
33
  from math import ceil, floor
35
34
 
36
- from meerk40t.core.node.node import Node
35
+ import numpy as np
36
+
37
37
  from meerk40t.core.node.mixins import LabelDisplay, Suppressable
38
+ from meerk40t.core.node.node import Node
38
39
  from meerk40t.core.units import UNITS_PER_INCH, UNITS_PER_MM
39
40
  from meerk40t.image.imagetools import RasterScripts
40
41
  from meerk40t.svgelements import Matrix, Path, Polygon
41
42
  from meerk40t.tools.geomstr import Geomstr
42
43
 
44
+
43
45
  class ImageNode(Node, LabelDisplay, Suppressable):
44
46
  """
45
47
  ImageNode is the bootstrapped node type for the 'elem image' type.
@@ -153,7 +155,12 @@ class ImageNode(Node, LabelDisplay, Suppressable):
153
155
  self._process_image_failed = False
154
156
 
155
157
  self.message = None
156
- if (self.operations or self.dither or self.prevent_crop or self.keyhole_reference) and startup:
158
+ if (
159
+ self.operations
160
+ or self.dither
161
+ or self.prevent_crop
162
+ or self.keyhole_reference
163
+ ) and startup:
157
164
  step = self._default_units / self.dpi
158
165
  step_x = step
159
166
  step_y = step
@@ -186,7 +193,6 @@ class ImageNode(Node, LabelDisplay, Suppressable):
186
193
  time.sleep(0.05)
187
194
  counter += 1
188
195
  if self._processed_image is None:
189
-
190
196
  step = self._default_units / self.dpi
191
197
  step_x = step
192
198
  step_y = step
@@ -320,18 +326,24 @@ class ImageNode(Node, LabelDisplay, Suppressable):
320
326
  return default_map
321
327
 
322
328
  def can_drop(self, drag_node):
329
+ if self.is_a_child_of(drag_node):
330
+ return False
323
331
  # Dragging element into element.
324
332
  return bool(
325
- hasattr(drag_node, "as_geometry") or
326
- hasattr(drag_node, "as_image") or
327
- drag_node.type in ("op image", "op raster", "file", "group")
333
+ hasattr(drag_node, "as_geometry")
334
+ or hasattr(drag_node, "as_image")
335
+ or drag_node.type in ("op image", "op raster", "file", "group")
328
336
  )
329
337
 
330
338
  def drop(self, drag_node, modify=True, flag=False):
331
339
  # Dragging element into element.
332
340
  if not self.can_drop(drag_node):
333
341
  return False
334
- if hasattr(drag_node, "as_geometry") or hasattr(drag_node, "as_image") or drag_node.type in ("file", "group"):
342
+ if (
343
+ hasattr(drag_node, "as_geometry")
344
+ or hasattr(drag_node, "as_image")
345
+ or drag_node.type in ("file", "group")
346
+ ):
335
347
  if modify:
336
348
  self.insert_sibling(drag_node)
337
349
  return True
@@ -418,12 +430,18 @@ class ImageNode(Node, LabelDisplay, Suppressable):
418
430
  # Unset cache.
419
431
  self._cache = None
420
432
  else:
421
- if self._keyhole_reference is not None and self._keyhole_geometry is None:
433
+ if (
434
+ self._keyhole_reference is not None
435
+ and self._keyhole_geometry is None
436
+ ):
422
437
  get_keyhole_geometry()
423
438
 
424
439
  # We need to have a thread per image, so we need to provide a node specific thread_name!
425
440
  self._update_thread = context.threaded(
426
- self._process_image_thread, result=clear, daemon=True, thread_name=f"image_update_{self.id}_{str(time.perf_counter())}"
441
+ self._process_image_thread,
442
+ result=clear,
443
+ daemon=True,
444
+ thread_name=f"image_update_{self.id}_{str(time.perf_counter())}",
427
445
  )
428
446
 
429
447
  def _process_image_thread(self):
@@ -460,6 +478,7 @@ class ImageNode(Node, LabelDisplay, Suppressable):
460
478
  """
461
479
 
462
480
  from PIL import Image, ImageDraw
481
+
463
482
  while self._processing:
464
483
  time.sleep(0.05)
465
484
 
@@ -491,6 +510,7 @@ class ImageNode(Node, LabelDisplay, Suppressable):
491
510
  @property
492
511
  def opaque_image(self):
493
512
  from PIL import Image
513
+
494
514
  img = self.image
495
515
  if img is not None and img.mode == "RGBA":
496
516
  r, g, b, a = img.split()
@@ -503,6 +523,7 @@ class ImageNode(Node, LabelDisplay, Suppressable):
503
523
  # Convert image to L type.
504
524
  if image.mode == "I":
505
525
  from PIL import Image
526
+
506
527
  # Load the 32-bit signed grayscale image
507
528
  img = np.array(image, dtype=np.int32)
508
529
 
@@ -510,7 +531,9 @@ class ImageNode(Node, LabelDisplay, Suppressable):
510
531
  # img = img.reshape((image.width, image.height))
511
532
 
512
533
  # Normalize the image to the range 0-255
513
- img_normalized = ((img - img.min()) / (img.max() - img.min()) * 255).astype(np.uint8)
534
+ img_normalized = ((img - img.min()) / (img.max() - img.min()) * 255).astype(
535
+ np.uint8
536
+ )
514
537
 
515
538
  # Convert the NumPy array to a Pillow Image
516
539
  img_pil = Image.fromarray(img_normalized)
@@ -684,7 +707,9 @@ class ImageNode(Node, LabelDisplay, Suppressable):
684
707
  pass
685
708
  elif name == "contrast":
686
709
  try:
687
- if op["enable"] and (op["contrast"] is not None and op["brightness"] is not None):
710
+ if op["enable"] and (
711
+ op["contrast"] is not None and op["brightness"] is not None
712
+ ):
688
713
  contrast = ImageEnhance.Contrast(image)
689
714
  c = (op["contrast"] + 128.0) / 128.0
690
715
  image = contrast.enhance(c)
@@ -924,7 +949,9 @@ class ImageNode(Node, LabelDisplay, Suppressable):
924
949
  try:
925
950
  image = ImageOps.invert(image)
926
951
  except OSError as e:
927
- print (f"Image inversion crashed: {e}\nMode: {image.mode}, {image.width}x{image.height} pixel")
952
+ print(
953
+ f"Image inversion crashed: {e}\nMode: {image.mode}, {image.width}x{image.height} pixel"
954
+ )
928
955
 
929
956
  # Find rejection mask of white pixels. (already inverted)
930
957
  reject_mask = image.point(lambda e: 0 if e == 255 else 255)
@@ -950,7 +977,10 @@ class ImageNode(Node, LabelDisplay, Suppressable):
950
977
  image = self.image
951
978
  if self._keyhole_geometry is not None:
952
979
  # Let's check whether the keyhole dimensions match
953
- if self._keyhole_image is not None and (self._keyhole_image.width != image.width or self._keyhole_image.height != image.height):
980
+ if self._keyhole_image is not None and (
981
+ self._keyhole_image.width != image.width
982
+ or self._keyhole_image.height != image.height
983
+ ):
954
984
  self._keyhole_image = None
955
985
  if self._keyhole_image is None:
956
986
  actualized_matrix = self._actualized_matrix
@@ -973,19 +1003,21 @@ class ImageNode(Node, LabelDisplay, Suppressable):
973
1003
  # Let's simplify things, if we don't have any overlap then we don't need to do something
974
1004
  # if x0 > bounds[2] or x2 < bounds [0] or y0 > bounds[3] or y2 < bounds[1]:
975
1005
  # continue
976
- geom_points = list(geom.as_interpolated_points(int(UNITS_PER_MM/10)))
1006
+ geom_points = list(
1007
+ geom.as_interpolated_points(int(UNITS_PER_MM / 10))
1008
+ )
977
1009
  points = list()
978
1010
  for pt in geom_points:
979
1011
  if pt is None:
980
1012
  continue
981
1013
  gx = pt.real
982
1014
  gy = pt.imag
983
- x = int(maskimage.width * (gx - x0) / i_wd )
984
- y = int(maskimage.height * (gy - y0) / i_ht )
985
- points.append( (x, y) )
1015
+ x = int(maskimage.width * (gx - x0) / i_wd)
1016
+ y = int(maskimage.height * (gy - y0) / i_ht)
1017
+ points.append((x, y))
986
1018
 
987
1019
  # print (points)
988
- draw.polygon( points, fill="white", outline="white")
1020
+ draw.polygon(points, fill="white", outline="white")
989
1021
  self._keyhole_image = maskimage
990
1022
  # For debug purposes...
991
1023
  # maskimage.save("C:\\temp\\maskimage.png")
@@ -2,8 +2,8 @@ from copy import copy
2
2
 
3
3
  from meerk40t.core.node.mixins import (
4
4
  FunctionalParameter,
5
- Stroked,
6
5
  LabelDisplay,
6
+ Stroked,
7
7
  Suppressable,
8
8
  )
9
9
  from meerk40t.core.node.node import Fillrule, Linecap, Linejoin, Node
@@ -150,12 +150,16 @@ class LineNode(Node, Stroked, FunctionalParameter, LabelDisplay, Suppressable):
150
150
  numtabs = 4
151
151
  numtabs = 0
152
152
  if tablen and numtabs:
153
- path = Geomstr.wobble_tab(path, tablen, resolution, numtabs, unit_factor=unit_factor)
153
+ path = Geomstr.wobble_tab(
154
+ path, tablen, resolution, numtabs, unit_factor=unit_factor
155
+ )
154
156
  # Is there a dash/dot pattern to apply?
155
157
  dashlen = self.stroke_dash
156
158
  irrelevant = 50
157
159
  if dashlen:
158
- path = Geomstr.wobble_dash(path, dashlen, resolution, irrelevant, unit_factor=unit_factor)
160
+ path = Geomstr.wobble_dash(
161
+ path, dashlen, resolution, irrelevant, unit_factor=unit_factor
162
+ )
159
163
  return path
160
164
 
161
165
  def scaled(self, sx, sy, ox, oy, interim=False):
@@ -235,19 +239,25 @@ class LineNode(Node, Stroked, FunctionalParameter, LabelDisplay, Suppressable):
235
239
  return default_map
236
240
 
237
241
  def can_drop(self, drag_node):
242
+ if self.is_a_child_of(drag_node):
243
+ return False
238
244
  # Dragging element into element.
239
245
  return bool(
240
- hasattr(drag_node, "as_geometry") or
241
- hasattr(drag_node, "as_image") or
242
- (drag_node.type.startswith("op ") and drag_node.type != "op dots") or
243
- drag_node.type in ("file", "group")
246
+ hasattr(drag_node, "as_geometry")
247
+ or hasattr(drag_node, "as_image")
248
+ or (drag_node.type.startswith("op ") and drag_node.type != "op dots")
249
+ or drag_node.type in ("file", "group")
244
250
  )
245
251
 
246
252
  def drop(self, drag_node, modify=True, flag=False):
247
253
  # Dragging element into element.
248
254
  if not self.can_drop(drag_node):
249
255
  return False
250
- if hasattr(drag_node, "as_geometry") or hasattr(drag_node, "as_image") or drag_node.type in ("file", "group"):
256
+ if (
257
+ hasattr(drag_node, "as_geometry")
258
+ or hasattr(drag_node, "as_image")
259
+ or drag_node.type in ("file", "group")
260
+ ):
251
261
  if modify:
252
262
  self.insert_sibling(drag_node)
253
263
  return True
@@ -2,8 +2,8 @@ from copy import copy
2
2
 
3
3
  from meerk40t.core.node.mixins import (
4
4
  FunctionalParameter,
5
- Stroked,
6
5
  LabelDisplay,
6
+ Stroked,
7
7
  Suppressable,
8
8
  )
9
9
  from meerk40t.core.node.node import Fillrule, Linecap, Linejoin, Node
@@ -122,12 +122,16 @@ class PathNode(Node, Stroked, FunctionalParameter, LabelDisplay, Suppressable):
122
122
  tablen = self.mktablength
123
123
  numtabs = self.mktabpositions
124
124
  if tablen and numtabs:
125
- path = Geomstr.wobble_tab(path, tablen, resolution, numtabs, unit_factor=unit_factor)
125
+ path = Geomstr.wobble_tab(
126
+ path, tablen, resolution, numtabs, unit_factor=unit_factor
127
+ )
126
128
  # Is there a dash/dot pattern to apply?
127
129
  dashlen = self.stroke_dash
128
130
  irrelevant = 50
129
131
  if dashlen:
130
- path = Geomstr.wobble_dash(path, dashlen, resolution, irrelevant, unit_factor=unit_factor)
132
+ path = Geomstr.wobble_dash(
133
+ path, dashlen, resolution, irrelevant, unit_factor=unit_factor
134
+ )
131
135
  return path
132
136
 
133
137
  def scaled(self, sx, sy, ox, oy, interim=False):
@@ -201,19 +205,25 @@ class PathNode(Node, Stroked, FunctionalParameter, LabelDisplay, Suppressable):
201
205
  return default_map
202
206
 
203
207
  def can_drop(self, drag_node):
208
+ if self.is_a_child_of(drag_node):
209
+ return False
204
210
  # Dragging element into element.
205
211
  return bool(
206
- hasattr(drag_node, "as_geometry") or
207
- hasattr(drag_node, "as_image") or
208
- (drag_node.type.startswith("op ") and drag_node.type != "op dots") or
209
- drag_node.type in ("file", "group")
212
+ hasattr(drag_node, "as_geometry")
213
+ or hasattr(drag_node, "as_image")
214
+ or (drag_node.type.startswith("op ") and drag_node.type != "op dots")
215
+ or drag_node.type in ("file", "group")
210
216
  )
211
217
 
212
218
  def drop(self, drag_node, modify=True, flag=False):
213
219
  # Dragging element into element.
214
220
  if not self.can_drop(drag_node):
215
221
  return False
216
- if hasattr(drag_node, "as_geometry") or hasattr(drag_node, "as_image") or drag_node.type in ("file", "group"):
222
+ if (
223
+ hasattr(drag_node, "as_geometry")
224
+ or hasattr(drag_node, "as_image")
225
+ or drag_node.type in ("file", "group")
226
+ ):
217
227
  if modify:
218
228
  self.insert_sibling(drag_node)
219
229
  return True
@@ -85,18 +85,24 @@ class PointNode(Node, FunctionalParameter, LabelDisplay, Suppressable):
85
85
  return default_map
86
86
 
87
87
  def can_drop(self, drag_node):
88
+ if self.is_a_child_of(drag_node):
89
+ return False
88
90
  # Dragging element into element.
89
91
  return bool(
90
- hasattr(drag_node, "as_geometry") or
91
- hasattr(drag_node, "as_image") or
92
- drag_node.type in ("op dots", "file", "group")
92
+ hasattr(drag_node, "as_geometry")
93
+ or hasattr(drag_node, "as_image")
94
+ or drag_node.type in ("op dots", "file", "group")
93
95
  )
94
96
 
95
97
  def drop(self, drag_node, modify=True, flag=False):
96
98
  # Dragging element into element.
97
99
  if not self.can_drop(drag_node):
98
100
  return False
99
- if hasattr(drag_node, "as_geometry") or hasattr(drag_node, "as_image") or drag_node.type in ("file", "group"):
101
+ if (
102
+ hasattr(drag_node, "as_geometry")
103
+ or hasattr(drag_node, "as_image")
104
+ or drag_node.type in ("file", "group")
105
+ ):
100
106
  if modify:
101
107
  self.insert_sibling(drag_node)
102
108
  return True
@@ -2,8 +2,8 @@ from copy import copy
2
2
 
3
3
  from meerk40t.core.node.mixins import (
4
4
  FunctionalParameter,
5
- Stroked,
6
5
  LabelDisplay,
6
+ Stroked,
7
7
  Suppressable,
8
8
  )
9
9
  from meerk40t.core.node.node import Fillrule, Linecap, Linejoin, Node
@@ -18,9 +18,7 @@ from meerk40t.svgelements import (
18
18
  from meerk40t.tools.geomstr import Geomstr
19
19
 
20
20
 
21
- class PolylineNode(
22
- Node, Stroked, FunctionalParameter, LabelDisplay, Suppressable
23
- ):
21
+ class PolylineNode(Node, Stroked, FunctionalParameter, LabelDisplay, Suppressable):
24
22
  """
25
23
  PolylineNode is the bootstrapped node type for the 'elem polyline' type.
26
24
  """
@@ -152,12 +150,16 @@ class PolylineNode(
152
150
  tablen = self.mktablength
153
151
  numtabs = self.mktabpositions
154
152
  if tablen and numtabs:
155
- path = Geomstr.wobble_tab(path, tablen, resolution, numtabs, unit_factor=unit_factor)
153
+ path = Geomstr.wobble_tab(
154
+ path, tablen, resolution, numtabs, unit_factor=unit_factor
155
+ )
156
156
  # Is there a dash/dot pattern to apply?
157
157
  dashlen = self.stroke_dash
158
158
  irrelevant = 50
159
159
  if dashlen:
160
- path = Geomstr.wobble_dash(path, dashlen, resolution, irrelevant, unit_factor=unit_factor)
160
+ path = Geomstr.wobble_dash(
161
+ path, dashlen, resolution, irrelevant, unit_factor=unit_factor
162
+ )
161
163
  return path
162
164
 
163
165
  def scaled(self, sx, sy, ox, oy, interim=False):
@@ -232,19 +234,25 @@ class PolylineNode(
232
234
  return default_map
233
235
 
234
236
  def can_drop(self, drag_node):
237
+ if self.is_a_child_of(drag_node):
238
+ return False
235
239
  # Dragging element into element.
236
240
  return bool(
237
- hasattr(drag_node, "as_geometry") or
238
- hasattr(drag_node, "as_image") or
239
- (drag_node.type.startswith("op ") and drag_node.type != "op dots") or
240
- drag_node.type in ("file", "group")
241
+ hasattr(drag_node, "as_geometry")
242
+ or hasattr(drag_node, "as_image")
243
+ or (drag_node.type.startswith("op ") and drag_node.type != "op dots")
244
+ or drag_node.type in ("file", "group")
241
245
  )
242
246
 
243
247
  def drop(self, drag_node, modify=True, flag=False):
244
248
  # Dragging element into element.
245
249
  if not self.can_drop(drag_node):
246
250
  return False
247
- if hasattr(drag_node, "as_geometry") or hasattr(drag_node, "as_image") or drag_node.type in ("file", "group"):
251
+ if (
252
+ hasattr(drag_node, "as_geometry")
253
+ or hasattr(drag_node, "as_image")
254
+ or drag_node.type in ("file", "group")
255
+ ):
248
256
  if modify:
249
257
  self.insert_sibling(drag_node)
250
258
  return True
@@ -2,8 +2,8 @@ from copy import copy
2
2
 
3
3
  from meerk40t.core.node.mixins import (
4
4
  FunctionalParameter,
5
- Stroked,
6
5
  LabelDisplay,
6
+ Stroked,
7
7
  Suppressable,
8
8
  )
9
9
  from meerk40t.core.node.node import Fillrule, Linejoin, Node
@@ -157,12 +157,16 @@ class RectNode(Node, Stroked, FunctionalParameter, LabelDisplay, Suppressable):
157
157
  tablen = self.mktablength
158
158
  numtabs = self.mktabpositions
159
159
  if tablen and numtabs:
160
- path = Geomstr.wobble_tab(path, tablen, resolution, numtabs, unit_factor=unit_factor)
160
+ path = Geomstr.wobble_tab(
161
+ path, tablen, resolution, numtabs, unit_factor=unit_factor
162
+ )
161
163
  # Is there a dash/dot pattern to apply?
162
164
  dashlen = self.stroke_dash
163
165
  irrelevant = 50
164
166
  if dashlen:
165
- path = Geomstr.wobble_dash(path, dashlen, resolution, irrelevant, unit_factor=unit_factor)
167
+ path = Geomstr.wobble_dash(
168
+ path, dashlen, resolution, irrelevant, unit_factor=unit_factor
169
+ )
166
170
  return path
167
171
 
168
172
  def scaled(self, sx, sy, ox, oy, interim=False):
@@ -241,18 +245,24 @@ class RectNode(Node, Stroked, FunctionalParameter, LabelDisplay, Suppressable):
241
245
 
242
246
  def can_drop(self, drag_node):
243
247
  # Dragging element into element.
248
+ if self.is_a_child_of(drag_node):
249
+ return False
244
250
  return bool(
245
- hasattr(drag_node, "as_geometry") or
246
- hasattr(drag_node, "as_image") or
247
- (drag_node.type.startswith("op ") and drag_node.type != "op dots") or
248
- drag_node.type in ("file", "group")
251
+ hasattr(drag_node, "as_geometry")
252
+ or hasattr(drag_node, "as_image")
253
+ or (drag_node.type.startswith("op ") and drag_node.type != "op dots")
254
+ or drag_node.type in ("file", "group")
249
255
  )
250
256
 
251
257
  def drop(self, drag_node, modify=True, flag=False):
252
258
  # Dragging element into element.
253
259
  if not self.can_drop(drag_node):
254
260
  return False
255
- if hasattr(drag_node, "as_geometry") or hasattr(drag_node, "as_image") or drag_node.type in ("file", "group"):
261
+ if (
262
+ hasattr(drag_node, "as_geometry")
263
+ or hasattr(drag_node, "as_image")
264
+ or drag_node.type in ("file", "group")
265
+ ):
256
266
  if modify:
257
267
  self.insert_sibling(drag_node)
258
268
  return True
@@ -4,8 +4,8 @@ from math import tau
4
4
 
5
5
  from meerk40t.core.node.mixins import (
6
6
  FunctionalParameter,
7
- Stroked,
8
7
  LabelDisplay,
8
+ Stroked,
9
9
  Suppressable,
10
10
  )
11
11
  from meerk40t.core.node.node import Node
@@ -196,18 +196,24 @@ class TextNode(Node, Stroked, FunctionalParameter, LabelDisplay, Suppressable):
196
196
  return default_map
197
197
 
198
198
  def can_drop(self, drag_node):
199
+ if self.is_a_child_of(drag_node):
200
+ return False
199
201
  # Dragging element into element.
200
202
  return bool(
201
- hasattr(drag_node, "as_geometry") or
202
- hasattr(drag_node, "as_image") or
203
- drag_node.type in ("op raster", "file", "group")
203
+ hasattr(drag_node, "as_geometry")
204
+ or hasattr(drag_node, "as_image")
205
+ or drag_node.type in ("op raster", "file", "group")
204
206
  )
205
207
 
206
208
  def drop(self, drag_node, modify=True, flag=False):
207
209
  # Dragging element into element.
208
210
  if not self.can_drop(drag_node):
209
211
  return False
210
- if hasattr(drag_node, "as_geometry") or hasattr(drag_node, "as_image") or drag_node.type in ("file", "group"):
212
+ if (
213
+ hasattr(drag_node, "as_geometry")
214
+ or hasattr(drag_node, "as_image")
215
+ or drag_node.type in ("file", "group")
216
+ ):
211
217
  if modify:
212
218
  self.insert_sibling(drag_node)
213
219
  return True
@@ -25,21 +25,15 @@ class FileNode(Node):
25
25
  default_map["filename"] = s
26
26
  return default_map
27
27
 
28
- def is_a_child_of(self, node):
29
- candidate = self
30
- while candidate is not None:
31
- if candidate is node:
32
- return True
33
- candidate = candidate.parent
34
28
  return False
35
-
29
+
36
30
  def can_drop(self, drag_node):
37
31
  if self.is_a_child_of(drag_node):
38
32
  return False
39
33
  if drag_node.type == "group":
40
34
  return True
41
35
  return False
42
-
36
+
43
37
  def drop(self, drag_node, modify=True, flag=False):
44
38
  # Do not allow dragging onto children
45
39
  if not self.can_drop(drag_node):
@@ -1,5 +1,5 @@
1
- from meerk40t.core.node.node import Node
2
1
  from meerk40t.core.node.mixins import LabelDisplay
2
+ from meerk40t.core.node.node import Node
3
3
 
4
4
 
5
5
  class GroupNode(Node, LabelDisplay):
@@ -76,18 +76,14 @@ class GroupNode(Node, LabelDisplay):
76
76
  default_map["id"] = str(self.id)
77
77
  return default_map
78
78
 
79
- def is_a_child_of(self, node):
80
- candidate = self
81
- while candidate is not None:
82
- if candidate is node:
83
- return True
84
- candidate = candidate.parent
85
- return False
86
-
87
79
  def can_drop(self, drag_node):
88
80
  if self.is_a_child_of(drag_node):
89
81
  return False
90
- if hasattr(drag_node, "as_geometry") or hasattr(drag_node, "as_image") or drag_node.type == "group":
82
+ if (
83
+ hasattr(drag_node, "as_geometry")
84
+ or hasattr(drag_node, "as_image")
85
+ or drag_node.type == "group"
86
+ ):
91
87
  # Move a group
92
88
  return True
93
89
  elif drag_node.type.startswith("op"):
@@ -121,7 +117,11 @@ class GroupNode(Node, LabelDisplay):
121
117
  if result and modify:
122
118
  # changed = []
123
119
  for e in self.flat():
124
- if hasattr(drag_node, "color") and drag_node.color is not None and hasattr(e, "stroke"):
120
+ if (
121
+ hasattr(drag_node, "color")
122
+ and drag_node.color is not None
123
+ and hasattr(e, "stroke")
124
+ ):
125
125
  e.stroke = drag_node.color
126
126
  # changed.append(e)
127
127
  for ref in old_references: