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
@@ -163,19 +163,25 @@ class ImageProcessedNode(Node):
163
163
  return default_map
164
164
 
165
165
  def can_drop(self, drag_node):
166
+ if self.is_a_child_of(drag_node):
167
+ return False
166
168
  # Dragging element into element.
167
169
  return bool(
168
- hasattr(drag_node, "as_geometry") or
169
- hasattr(drag_node, "as_image") or
170
- (drag_node.type.startswith("op ") and drag_node.type != "op dots") or
171
- drag_node.type in ("file", "group")
170
+ hasattr(drag_node, "as_geometry")
171
+ or hasattr(drag_node, "as_image")
172
+ or (drag_node.type.startswith("op ") and drag_node.type != "op dots")
173
+ or drag_node.type in ("file", "group")
172
174
  )
173
175
 
174
176
  def drop(self, drag_node, modify=True, flag=False):
175
177
  # Dragging element into element.
176
178
  if not self.can_drop(drag_node):
177
179
  return False
178
- if hasattr(drag_node, "as_geometry") or hasattr(drag_node, "as_image") or drag_node.type in ("file", "group"):
180
+ if (
181
+ hasattr(drag_node, "as_geometry")
182
+ or hasattr(drag_node, "as_image")
183
+ or drag_node.type in ("file", "group")
184
+ ):
179
185
  if modify:
180
186
  self.insert_sibling(drag_node)
181
187
  return True
@@ -92,19 +92,25 @@ class ImageRasterNode(Node):
92
92
  return default_map
93
93
 
94
94
  def can_drop(self, drag_node):
95
+ if self.is_a_child_of(drag_node):
96
+ return False
95
97
  # Dragging element into element.
96
98
  return bool(
97
- hasattr(drag_node, "as_geometry") or
98
- hasattr(drag_node, "as_image") or
99
- (drag_node.type.startswith("op ") and drag_node.type != "op dots") or
100
- drag_node.type in ("file", "group")
99
+ hasattr(drag_node, "as_geometry")
100
+ or hasattr(drag_node, "as_image")
101
+ or (drag_node.type.startswith("op ") and drag_node.type != "op dots")
102
+ or drag_node.type in ("file", "group")
101
103
  )
102
104
 
103
105
  def drop(self, drag_node, modify=True, flag=False):
104
106
  # Dragging element into element.
105
107
  if not self.can_drop(drag_node):
106
108
  return False
107
- if hasattr(drag_node, "as_geometry") or hasattr(drag_node, "as_image") or drag_node.type in ("file", "group"):
109
+ if (
110
+ hasattr(drag_node, "as_geometry")
111
+ or hasattr(drag_node, "as_image")
112
+ or drag_node.type in ("file", "group")
113
+ ):
108
114
  if modify:
109
115
  self.insert_sibling(drag_node)
110
116
  return True
@@ -193,7 +193,7 @@ class Node:
193
193
  def targeted(self, value):
194
194
  self._target = value
195
195
  self.notify_targeted(self)
196
-
196
+
197
197
  @property
198
198
  def expanded(self):
199
199
  return self._expanded
@@ -457,17 +457,23 @@ class Node:
457
457
 
458
458
  def restore_tree(self, tree_data):
459
459
  # Takes a backup and reapplies it again to the tree
460
- # Caveat: we can't just simply take the backup and load it into the tree,
461
- # although it is already a perfectly independent copy.
460
+ # Caveat: we can't just simply take the backup and load it into the tree,
461
+ # although it is already a perfectly independent copy.
462
462
  # self._children.extend(tree_data)
463
- # If loaded directly as above then this stored state will be used
464
- # as the basis for further modifications consequently changing the
463
+ # If loaded directly as above then this stored state will be used
464
+ # as the basis for further modifications consequently changing the
465
465
  # original data (as it is still the original structure) used in the undostack.
466
466
  # tree_data contains the copied branch nodes
467
-
467
+
468
468
  self._children.clear()
469
469
  links = {id(self): (self, None)}
470
- attrib_list = ("_selected", "_emphasized", "_emphasized_time", "_highlighted", "_expanded")
470
+ attrib_list = (
471
+ "_selected",
472
+ "_emphasized",
473
+ "_emphasized_time",
474
+ "_highlighted",
475
+ "_expanded",
476
+ )
471
477
  for c in tree_data:
472
478
  c._build_copy_nodes(links=links)
473
479
  node_copy = copy(c)
@@ -528,12 +534,23 @@ class Node:
528
534
  """
529
535
  if links is None:
530
536
  links = {id(self): (self, None)}
531
- attrib_list = ("_selected", "_emphasized", "_emphasized_time", "_highlighted", "_expanded")
537
+ attrib_list = (
538
+ "_selected",
539
+ "_emphasized",
540
+ "_emphasized_time",
541
+ "_highlighted",
542
+ "_expanded",
543
+ "_translated_text",
544
+ )
532
545
  for c in self._children:
533
546
  c._build_copy_nodes(links=links)
534
547
  node_copy = copy(c)
535
548
  for att in attrib_list:
536
- if getattr(node_copy, att) != getattr(c, att):
549
+ if not hasattr(c, att):
550
+ continue
551
+ if not hasattr(node_copy, att) or getattr(node_copy, att) != getattr(
552
+ c, att
553
+ ):
537
554
  # print (f"Strange {att} not identical, fixing")
538
555
  setattr(node_copy, att, getattr(c, att))
539
556
  node_copy._root = self._root
@@ -583,7 +600,7 @@ class Node:
583
600
  result = "<invalid pattern>"
584
601
  return result
585
602
 
586
- def default_map(self, default_map=None): # , skip_label=False
603
+ def default_map(self, default_map=None): # , skip_label=False
587
604
  if default_map is None:
588
605
  default_map = self._default_map
589
606
  default_map["id"] = str(self.id) if self.id is not None else "-"
@@ -817,7 +834,9 @@ class Node:
817
834
  node = self
818
835
  self._parent.notify_modified(node=node, **kwargs)
819
836
 
820
- def notify_translated(self, node=None, dx=0, dy=0, invalidate=False, interim=False, **kwargs):
837
+ def notify_translated(
838
+ self, node=None, dx=0, dy=0, invalidate=False, interim=False, **kwargs
839
+ ):
821
840
  if invalidate:
822
841
  self.set_dirty_bounds()
823
842
  if self._parent is not None:
@@ -829,7 +848,15 @@ class Node:
829
848
  )
830
849
 
831
850
  def notify_scaled(
832
- self, node=None, sx=1, sy=1, ox=0, oy=0, invalidate=False, interim=False, **kwargs
851
+ self,
852
+ node=None,
853
+ sx=1,
854
+ sy=1,
855
+ ox=0,
856
+ oy=0,
857
+ invalidate=False,
858
+ interim=False,
859
+ **kwargs,
833
860
  ):
834
861
  if invalidate:
835
862
  self.set_dirty_bounds()
@@ -838,7 +865,14 @@ class Node:
838
865
  node = self
839
866
  # Any change to position / size needs a recalculation of the bounds
840
867
  self._parent.notify_scaled(
841
- node=node, sx=sx, sy=sy, ox=ox, oy=oy, invalidate=True, interim=interim, **kwargs
868
+ node=node,
869
+ sx=sx,
870
+ sy=sy,
871
+ ox=ox,
872
+ oy=oy,
873
+ invalidate=True,
874
+ interim=interim,
875
+ **kwargs,
842
876
  )
843
877
 
844
878
  def notify_altered(self, node=None, **kwargs):
@@ -953,6 +987,7 @@ class Node:
953
987
  This is a special case of the modified call, we are scaling
954
988
  the node without fundamentally altering its properties
955
989
  """
990
+
956
991
  def apply_it(box):
957
992
  x0, y0, x1, y1 = box
958
993
  if sx != 1.0:
@@ -1220,7 +1255,9 @@ class Node:
1220
1255
  If the node exists elsewhere in the tree it will be removed from that location.
1221
1256
  """
1222
1257
  reference_sibling = self
1223
- source_siblings = None if new_sibling.parent is None else new_sibling.parent.children
1258
+ source_siblings = (
1259
+ None if new_sibling.parent is None else new_sibling.parent.children
1260
+ )
1224
1261
  destination_siblings = reference_sibling.parent.children
1225
1262
 
1226
1263
  if source_siblings:
@@ -1334,7 +1371,8 @@ class Node:
1334
1371
  if children:
1335
1372
  self.remove_all_children(fast=fast)
1336
1373
  if self._parent:
1337
- self._parent._children.remove(self)
1374
+ if self in self._parent._children:
1375
+ self._parent._children.remove(self)
1338
1376
  self._parent.set_dirty_bounds()
1339
1377
  if not fast:
1340
1378
  self.notify_detached(self)
@@ -1356,6 +1394,14 @@ class Node:
1356
1394
  child.remove_all_children(fast=fast, destroy=destroy)
1357
1395
  child.remove_node(fast=fast, destroy=destroy)
1358
1396
 
1397
+ def is_a_child_of(self, node):
1398
+ candidate = self
1399
+ while candidate is not None:
1400
+ if candidate is node:
1401
+ return True
1402
+ candidate = candidate.parent
1403
+ return False
1404
+
1359
1405
  def has_ancestor(self, type):
1360
1406
  """
1361
1407
  Return whether this node has an ancestor node that matches the given type, or matches the major type.
@@ -1394,7 +1440,9 @@ class Node:
1394
1440
  dest.insert_node(self, pos=pos)
1395
1441
 
1396
1442
  @staticmethod
1397
- def union_bounds(nodes, bounds=None, attr="bounds", ignore_locked=True, ignore_hidden=False):
1443
+ def union_bounds(
1444
+ nodes, bounds=None, attr="bounds", ignore_locked=True, ignore_hidden=False
1445
+ ):
1398
1446
  """
1399
1447
  Returns the union of the node list given, optionally unioned the given bounds value
1400
1448
 
@@ -54,5 +54,6 @@ class ReferenceNode(Node):
54
54
  return False
55
55
 
56
56
  def notify_destroyed(self, node=None, **kwargs):
57
- self.node._references.remove(self)
57
+ if self.node is not None and self in self.node._references:
58
+ self.node._references.remove(self)
58
59
  super().notify_destroyed()
meerk40t/core/svg_io.py CHANGED
@@ -124,7 +124,6 @@ def plugin(kernel, lifecycle=None):
124
124
  "page": "Input/Output",
125
125
  "section": "Input",
126
126
  },
127
-
128
127
  ]
129
128
  kernel.register_choices("preferences", choices)
130
129
  # The order is relevant as both loaders support SVG
@@ -237,7 +236,9 @@ class SVGWriter:
237
236
  if elements.last_file_autoexec is not None:
238
237
  subelement = SubElement(root, "autoexec")
239
238
  subelement.set("autoexec", str(elements.last_file_autoexec))
240
- subelement.set("autoexec-active", str(elements.last_file_autoexec_active))
239
+ subelement.set(
240
+ "autoexec-active", str(elements.last_file_autoexec_active)
241
+ )
241
242
 
242
243
  SVGWriter._write_tree(root, elements._tree, version)
243
244
 
@@ -279,7 +280,7 @@ class SVGWriter:
279
280
  if len(c.children) > 1:
280
281
  flag = False
281
282
  return flag
282
-
283
+
283
284
  if c.type == "elem ellipse":
284
285
  subelement = SubElement(xml_tree, SVG_TAG_ELLIPSE)
285
286
  subelement.set(SVG_ATTR_CENTER_X, str(c.cx))
@@ -632,7 +633,12 @@ class SVGWriter:
632
633
  pass
633
634
  # Node does not have settings, write object dict
634
635
  for key, value in node.__dict__.items():
635
- if not key or key.startswith("_") or key in saved_attributes or value is None:
636
+ if (
637
+ not key
638
+ or key.startswith("_")
639
+ or key in saved_attributes
640
+ or value is None
641
+ ):
636
642
  continue
637
643
  if key in (
638
644
  "references",
@@ -663,7 +669,8 @@ class SVGWriter:
663
669
  for c in node.children:
664
670
  if c.type == "reference":
665
671
  c = c.node # Contain direct reference not reference node reference.
666
- contains.append(c.id)
672
+ if c.id is not None: # Something strange happened here...
673
+ contains.append(c.id)
667
674
  if contains:
668
675
  subelement.set("references", " ".join(contains))
669
676
 
@@ -706,7 +713,13 @@ class SVGProcessor:
706
713
  Special care is taken to load MK specific objects like `note` and `operations`
707
714
  """
708
715
 
709
- def __init__(self, elements, load_operations, load_hidden_to_regmarks = True, reuse_operations=True):
716
+ def __init__(
717
+ self,
718
+ elements,
719
+ load_operations,
720
+ load_hidden_to_regmarks=True,
721
+ reuse_operations=True,
722
+ ):
710
723
  self.elements = elements
711
724
 
712
725
  self.operation_list = list()
@@ -789,7 +802,7 @@ class SVGProcessor:
789
802
  self.elements.classify(self.element_list)
790
803
 
791
804
  def check_for_bound_information(self, node, element):
792
- # Do we have existing boundary information?
805
+ # Do we have existing boundary information?
793
806
  if "bounds" not in element.values:
794
807
  return False
795
808
  bbstr = element.values["bounds"]
@@ -816,15 +829,16 @@ class SVGProcessor:
816
829
  bbox[idx] = val
817
830
  except Exception:
818
831
  # Whatever it was, we don't continue...
819
- pass
832
+ pass
820
833
  node._paint_bounds = list(bbox)
821
834
  node._paint_bounds_dirty = False
822
835
  return True
823
836
 
824
- def check_for_mk_path_attributes(self, node, element):
837
+ def check_for_mk_path_attributes(self, node, element, skip=None):
825
838
  """
826
839
  Checks for some mk special parameters starting with mk. Especially mkparam, and uses this property to fill in
827
- the functional_parameter attribute for the node.
840
+ the functional_parameter attribute for the node. This can be skipped if needed (eg. for basic shapes) as this
841
+ is not needed for them.
828
842
 
829
843
  @param node:
830
844
  @param element:
@@ -833,7 +847,8 @@ class SVGProcessor:
833
847
  for prop in element.values:
834
848
  lc = element.values.get(prop)
835
849
  if prop.startswith("mk"):
836
- # print (f"Property: {prop} = [{type(lc).__name__}] {lc}")
850
+ if skip and prop in skip:
851
+ continue
837
852
  if lc is not None:
838
853
  setattr(node, prop, lc)
839
854
  # This needs to be done as some node types are not based on Parameters
@@ -975,7 +990,9 @@ class SVGProcessor:
975
990
  return tag_label
976
991
  return local_dict.get("label")
977
992
 
978
- def _parse_text(self, element, ident, label, lock, context_node, e_list, set_hidden):
993
+ def _parse_text(
994
+ self, element, ident, label, lock, context_node, e_list, set_hidden
995
+ ):
979
996
  """
980
997
  Parses an SVGText object, into an `elem text` node.
981
998
 
@@ -1024,7 +1041,9 @@ class SVGProcessor:
1024
1041
  self.check_for_bound_information(node, element)
1025
1042
  e_list.append(node)
1026
1043
 
1027
- def _parse_path(self, element, ident, label, lock, context_node, e_list, set_hidden):
1044
+ def _parse_path(
1045
+ self, element, ident, label, lock, context_node, e_list, set_hidden
1046
+ ):
1028
1047
  """
1029
1048
  Parses an SVG Path object.
1030
1049
 
@@ -1055,7 +1074,12 @@ class SVGProcessor:
1055
1074
  pass
1056
1075
  element.approximate_arcs_with_cubics()
1057
1076
  node = context_node.add(
1058
- path=element, type="elem path", id=ident, label=label, lock=lock, hidden=set_hidden
1077
+ path=element,
1078
+ type="elem path",
1079
+ id=ident,
1080
+ label=label,
1081
+ lock=lock,
1082
+ hidden=set_hidden,
1059
1083
  )
1060
1084
  self.check_for_label_display(node, element)
1061
1085
  self.check_for_line_attributes(node, element)
@@ -1064,7 +1088,9 @@ class SVGProcessor:
1064
1088
  self.check_for_bound_information(node, element)
1065
1089
  e_list.append(node)
1066
1090
 
1067
- def _parse_polyline(self, element, ident, label, lock, context_node, e_list, set_hidden):
1091
+ def _parse_polyline(
1092
+ self, element, ident, label, lock, context_node, e_list, set_hidden
1093
+ ):
1068
1094
  """
1069
1095
  Parses svg Polyline and Polygon objects into `elem polyline` nodes.
1070
1096
 
@@ -1089,7 +1115,7 @@ class SVGProcessor:
1089
1115
  self.check_for_label_display(node, element)
1090
1116
  self.check_for_line_attributes(node, element)
1091
1117
  self.check_for_fill_attributes(node, element)
1092
- self.check_for_mk_path_attributes(node, element)
1118
+ self.check_for_mk_path_attributes(node, element, skip=("mkparam",))
1093
1119
  if not self.check_for_bound_information(node, element) and self.precalc_bbox:
1094
1120
  # bounds will be done here, paintbounds won't...
1095
1121
  if element.transform.is_identity():
@@ -1113,7 +1139,9 @@ class SVGProcessor:
1113
1139
  node._points_dirty = False
1114
1140
  e_list.append(node)
1115
1141
 
1116
- def _parse_ellipse(self, element, ident, label, lock, context_node, e_list, set_hidden):
1142
+ def _parse_ellipse(
1143
+ self, element, ident, label, lock, context_node, e_list, set_hidden
1144
+ ):
1117
1145
  """
1118
1146
  Parses the SVG Circle, and Ellipse nodes into `elem ellipse` nodes.
1119
1147
 
@@ -1137,11 +1165,13 @@ class SVGProcessor:
1137
1165
  )
1138
1166
  self.check_for_label_display(node, element)
1139
1167
  self.check_for_line_attributes(node, element)
1140
- self.check_for_mk_path_attributes(node, element)
1168
+ self.check_for_mk_path_attributes(node, element, skip=("mkparam",))
1141
1169
  self.check_for_bound_information(node, element)
1142
1170
  e_list.append(node)
1143
1171
 
1144
- def _parse_rect(self, element, ident, label, lock, context_node, e_list, set_hidden):
1172
+ def _parse_rect(
1173
+ self, element, ident, label, lock, context_node, e_list, set_hidden
1174
+ ):
1145
1175
  """
1146
1176
  Parse SVG Rect objects into `elem rect` objects.
1147
1177
 
@@ -1165,7 +1195,7 @@ class SVGProcessor:
1165
1195
  )
1166
1196
  self.check_for_label_display(node, element)
1167
1197
  self.check_for_line_attributes(node, element)
1168
- self.check_for_mk_path_attributes(node, element)
1198
+ self.check_for_mk_path_attributes(node, element, skip=("mkparam",))
1169
1199
  if not self.check_for_bound_information(node, element) and self.precalc_bbox:
1170
1200
  # bounds will be done here, paintbounds won't...
1171
1201
  points = (
@@ -1191,7 +1221,9 @@ class SVGProcessor:
1191
1221
  node._points_dirty = False
1192
1222
  e_list.append(node)
1193
1223
 
1194
- def _parse_line(self, element, ident, label, lock, context_node, e_list, set_hidden):
1224
+ def _parse_line(
1225
+ self, element, ident, label, lock, context_node, e_list, set_hidden
1226
+ ):
1195
1227
  """
1196
1228
  Parse SVG Line objects into `elem line`
1197
1229
 
@@ -1215,7 +1247,7 @@ class SVGProcessor:
1215
1247
  )
1216
1248
  self.check_for_label_display(node, element)
1217
1249
  self.check_for_line_attributes(node, element)
1218
- self.check_for_mk_path_attributes(node, element)
1250
+ self.check_for_mk_path_attributes(node, element, skip=("mkparam",))
1219
1251
  if not self.check_for_bound_information(node, element) and self.precalc_bbox:
1220
1252
  # bounds will be done here, paintbounds won't...
1221
1253
  points = (
@@ -1239,7 +1271,9 @@ class SVGProcessor:
1239
1271
  node._points_dirty = False
1240
1272
  e_list.append(node)
1241
1273
 
1242
- def _parse_image(self, element, ident, label, lock, context_node, e_list, set_hidden):
1274
+ def _parse_image(
1275
+ self, element, ident, label, lock, context_node, e_list, set_hidden
1276
+ ):
1243
1277
  """
1244
1278
  Parse SVG Image objects into either `image raster` or `elem image` objects, potentially other classes.
1245
1279
 
@@ -1516,7 +1550,6 @@ class SVGProcessor:
1516
1550
  if branch not in ("elements", "regmarks"):
1517
1551
  return
1518
1552
  if element.values.get("visibility") == "hidden" or display == "none":
1519
-
1520
1553
  if self.load_hidden_to_regmarks:
1521
1554
  if branch != "regmarks":
1522
1555
  self.parse(
@@ -1554,19 +1587,33 @@ class SVGProcessor:
1554
1587
  self.check_for_bound_information(node, element)
1555
1588
  e_list.append(node)
1556
1589
  elif isinstance(element, SVGText):
1557
- self._parse_text(element, ident, _label, _lock, context_node, e_list, set_hidden)
1590
+ self._parse_text(
1591
+ element, ident, _label, _lock, context_node, e_list, set_hidden
1592
+ )
1558
1593
  elif isinstance(element, Path):
1559
- self._parse_path(element, ident, _label, _lock, context_node, e_list, set_hidden)
1594
+ self._parse_path(
1595
+ element, ident, _label, _lock, context_node, e_list, set_hidden
1596
+ )
1560
1597
  elif isinstance(element, (Polygon, Polyline)):
1561
- self._parse_polyline(element, ident, _label, _lock, context_node, e_list, set_hidden)
1598
+ self._parse_polyline(
1599
+ element, ident, _label, _lock, context_node, e_list, set_hidden
1600
+ )
1562
1601
  elif isinstance(element, (Circle, Ellipse)):
1563
- self._parse_ellipse(element, ident, _label, _lock, context_node, e_list, set_hidden)
1602
+ self._parse_ellipse(
1603
+ element, ident, _label, _lock, context_node, e_list, set_hidden
1604
+ )
1564
1605
  elif isinstance(element, Rect):
1565
- self._parse_rect(element, ident, _label, _lock, context_node, e_list, set_hidden)
1606
+ self._parse_rect(
1607
+ element, ident, _label, _lock, context_node, e_list, set_hidden
1608
+ )
1566
1609
  elif isinstance(element, SimpleLine):
1567
- self._parse_line(element, ident, _label, _lock, context_node, e_list, set_hidden)
1610
+ self._parse_line(
1611
+ element, ident, _label, _lock, context_node, e_list, set_hidden
1612
+ )
1568
1613
  elif isinstance(element, SVGImage):
1569
- self._parse_image(element, ident, _label, _lock, context_node, e_list, set_hidden)
1614
+ self._parse_image(
1615
+ element, ident, _label, _lock, context_node, e_list, set_hidden
1616
+ )
1570
1617
  elif isinstance(element, SVG):
1571
1618
  # SVG is type of group, it must be processed before Group. Nothing special is done with the type.
1572
1619
  if self.reverse:
@@ -1708,7 +1755,9 @@ class SVGProcessor:
1708
1755
  file_node = context_node.add(type="file", filepath=self.pathname)
1709
1756
  for node in self.regmark_list:
1710
1757
  if node._parent is context_node:
1711
- if node.type == "group" and (node.id == "regmarks" or node.label == "regmarks"):
1758
+ if node.type == "group" and (
1759
+ node.id == "regmarks" or node.label == "regmarks"
1760
+ ):
1712
1761
  for n in list(node.children):
1713
1762
  file_node.append_child(n)
1714
1763
  node.remove_node() # Removing group/file node.
@@ -1740,6 +1789,7 @@ class SVGProcessor:
1740
1789
  if needs_update:
1741
1790
  self.elements.process_keyhole_updates(None)
1742
1791
 
1792
+
1743
1793
  class SVGLoader:
1744
1794
  """
1745
1795
  SVG loader - loading elements, regmarks and operations
@@ -1783,7 +1833,12 @@ class SVGLoader:
1783
1833
  reuse = elements_service.reuse_operations_on_load
1784
1834
  to_regmarks = elements_service.load_hidden_to_regmarks
1785
1835
  elements_service._loading_cleared = True
1786
- svg_processor = SVGProcessor(elements_service, load_operations=True, reuse_operations=reuse, load_hidden_to_regmarks=to_regmarks)
1836
+ svg_processor = SVGProcessor(
1837
+ elements_service,
1838
+ load_operations=True,
1839
+ reuse_operations=reuse,
1840
+ load_hidden_to_regmarks=to_regmarks,
1841
+ )
1787
1842
  svg_processor.process(svg, pathname)
1788
1843
  svg_processor.cleanup()
1789
1844
  return True
@@ -1830,7 +1885,9 @@ class SVGLoaderPlain:
1830
1885
  raise BadFileError(str(e)) from e
1831
1886
  elements_service._loading_cleared = True
1832
1887
  to_regmarks = elements_service.load_hidden_to_regmarks
1833
- svg_processor = SVGProcessor(elements_service, load_operations=False, load_hidden_to_regmarks=to_regmarks)
1888
+ svg_processor = SVGProcessor(
1889
+ elements_service, load_operations=False, load_hidden_to_regmarks=to_regmarks
1890
+ )
1834
1891
  svg_processor.process(svg, pathname)
1835
1892
  svg_processor.cleanup()
1836
1893
  return True
@@ -1,7 +1,7 @@
1
1
  from meerk40t.core.spoolers import Spooler
2
2
  from meerk40t.core.view import View
3
- from meerk40t.kernel import Service, signal_listener
4
3
  from meerk40t.device.devicechoices import get_effect_choices
4
+ from meerk40t.kernel import Service, signal_listener
5
5
 
6
6
  from .mixins import Status
7
7
 
@@ -161,3 +161,9 @@ class DummyDevice(Service, Status):
161
161
  @return: the location in device native units for the current known position.
162
162
  """
163
163
  return self.native_x, self.native_y
164
+
165
+ def location(self):
166
+ """
167
+ Provide information about the device interface
168
+ """
169
+ return "mock"