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
@@ -1,12 +1,13 @@
1
1
  # import threading
2
2
  from copy import copy
3
- from PIL import Image, ImageOps, ImageEnhance
3
+
4
4
  import numpy as np
5
5
  import wx
6
- from meerk40t.kernel.kernel import Job
7
- from meerk40t.core.node.node import Node
6
+ from PIL import Image, ImageEnhance, ImageOps
7
+
8
8
  from meerk40t.core.node.elem_image import ImageNode
9
9
  from meerk40t.core.node.elem_path import PathNode
10
+ from meerk40t.core.node.node import Node
10
11
  from meerk40t.core.units import UNITS_PER_INCH
11
12
 
12
13
  # from meerk40t.gui.icons import icon_ignore
@@ -30,7 +31,8 @@ from meerk40t.gui.wxutils import (
30
31
  wxStaticText,
31
32
  )
32
33
  from meerk40t.image.imagetools import img_to_polygons, img_to_rectangles
33
- from meerk40t.svgelements import Matrix, Color
34
+ from meerk40t.kernel.kernel import Job
35
+ from meerk40t.svgelements import Color, Matrix
34
36
 
35
37
  _ = wx.GetTranslation
36
38
 
@@ -46,7 +48,15 @@ class ContourPanel(wx.Panel):
46
48
  def accepts(node):
47
49
  return hasattr(node, "as_image")
48
50
 
49
- def __init__(self, *args, context=None, node=None, simplified=False, direct_mode=False, **kwds):
51
+ def __init__(
52
+ self,
53
+ *args,
54
+ context=None,
55
+ node=None,
56
+ simplified=False,
57
+ direct_mode=False,
58
+ **kwds,
59
+ ):
50
60
  # begin wxGlade: LayerSettingPanel.__init__
51
61
  kwds["style"] = kwds.get("style", 0)
52
62
  wx.Panel.__init__(self, *args, **kwds)
@@ -74,42 +84,49 @@ class ContourPanel(wx.Panel):
74
84
  if simplified:
75
85
  self.check_original.Hide()
76
86
 
77
- self.text_minimum = TextCtrl(
78
- self, wx.ID_ANY, "", limited=True, check="float"
79
- )
80
- self.text_maximum = TextCtrl(
81
- self, wx.ID_ANY, "", limited=True, check="float"
82
- )
87
+ self.text_minimum = TextCtrl(self, wx.ID_ANY, "", limited=True, check="float")
88
+ self.text_maximum = TextCtrl(self, wx.ID_ANY, "", limited=True, check="float")
83
89
  self.check_inner = wxCheckBox(self, wx.ID_ANY, _("Ignore inner"))
84
90
  self.radio_simplify = wxRadioBox(
85
- self, wx.ID_ANY,
91
+ self,
92
+ wx.ID_ANY,
86
93
  label=_("Contour simplification"),
87
- choices = (_("None"), _("Visvalingam"), _("Douglas-Peucker"))
94
+ choices=(_("None"), _("Visvalingam"), _("Douglas-Peucker")),
88
95
  )
89
96
  self.radio_method = wxRadioBox(
90
- self, wx.ID_ANY,
97
+ self,
98
+ wx.ID_ANY,
91
99
  label=_("Detection Method"),
92
- choices = (_("Polygons"), _("Bounding rectangles"))
100
+ choices=(_("Polygons"), _("Bounding rectangles")),
93
101
  )
94
102
 
95
103
  self.check_auto = wxCheckBox(self, wx.ID_ANY, _("Automatic update"))
96
104
  self.button_update = wxButton(self, wx.ID_ANY, _("Update"))
97
105
  self.button_create = wxButton(self, wx.ID_ANY, _("Generate contours"))
98
- self.button_create_placement = wxButton(self, wx.ID_ANY, _("Generate placements"))
106
+ self.button_create_placement = wxButton(
107
+ self, wx.ID_ANY, _("Generate placements")
108
+ )
99
109
  placement_choices = (
100
110
  _("Edge (prefer short side)"),
101
111
  _("Edge (prefer long side)"),
102
112
  _("Center (unrotated)"),
103
113
  _("Center (rotated)"),
104
114
  )
105
- self.combo_placement = wxComboBox(self, wx.ID_ANY, choices=placement_choices, style=wx.CB_DROPDOWN | wx.CB_READONLY)
115
+ self.combo_placement = wxComboBox(
116
+ self,
117
+ wx.ID_ANY,
118
+ choices=placement_choices,
119
+ style=wx.CB_DROPDOWN | wx.CB_READONLY,
120
+ )
106
121
 
107
122
  self.bitmap_preview = wxStaticBitmap(self, wx.ID_ANY)
108
123
  self.label_info = wxStaticText(self, wx.ID_ANY)
109
124
  self.list_contours = wxListCtrl(
110
- self, wx.ID_ANY,
125
+ self,
126
+ wx.ID_ANY,
111
127
  style=wx.LC_HRULES | wx.LC_REPORT | wx.LC_VRULES | wx.LC_SINGLE_SEL,
112
- context=self.context, list_name="list_contours",
128
+ context=self.context,
129
+ list_name="list_contours",
113
130
  )
114
131
  self.update_job = Job(
115
132
  process=self.refresh_preview_job,
@@ -142,8 +159,12 @@ class ContourPanel(wx.Panel):
142
159
  self.check_invert.Bind(wx.EVT_CHECKBOX, self.on_control_update)
143
160
  self.check_inner.Bind(wx.EVT_CHECKBOX, self.on_control_update)
144
161
  self.check_enable_contrast.Bind(wx.EVT_CHECKBOX, self.on_control_update)
145
- self.slider_contrast_brightness.Bind(wx.EVT_SLIDER, self.on_slider_contrast_brightness)
146
- self.slider_contrast_contrast.Bind(wx.EVT_SLIDER, self.on_slider_contrast_contrast)
162
+ self.slider_contrast_brightness.Bind(
163
+ wx.EVT_SLIDER, self.on_slider_contrast_brightness
164
+ )
165
+ self.slider_contrast_contrast.Bind(
166
+ wx.EVT_SLIDER, self.on_slider_contrast_contrast
167
+ )
147
168
  self.radio_method.Bind(wx.EVT_RADIOBOX, self.on_control_update)
148
169
  self.radio_simplify.Bind(wx.EVT_RADIOBOX, self.on_control_update)
149
170
  self.text_minimum.SetActionRoutine(self.on_control_update)
@@ -164,9 +185,7 @@ class ContourPanel(wx.Panel):
164
185
  sizer_right.Add(self.bitmap_preview, 4, wx.EXPAND, 0)
165
186
  sizer_right.Add(self.list_contours, 1, wx.EXPAND, 0)
166
187
 
167
- sizer_param_picture = StaticBoxSizer(
168
- self, wx.ID_ANY, _("Image:"), wx.VERTICAL
169
- )
188
+ sizer_param_picture = StaticBoxSizer(self, wx.ID_ANY, _("Image:"), wx.VERTICAL)
170
189
  sizer_contrast = StaticBoxSizer(self, wx.ID_ANY, _("Contrast"), wx.VERTICAL)
171
190
 
172
191
  sizer_contrast_main = wx.BoxSizer(wx.HORIZONTAL)
@@ -243,25 +262,57 @@ class ContourPanel(wx.Panel):
243
262
  def __do_defaults(self):
244
263
  self.check_auto.SetValue(self.auto_update)
245
264
  self.button_update.Enable(not self.auto_update)
246
- last_val = self.context.setting(int, "contour_placement", 1) # Long side is default preference
265
+ last_val = self.context.setting(
266
+ int, "contour_placement", 1
267
+ ) # Long side is default preference
247
268
  if last_val < 0 or last_val >= self.combo_placement.GetCount():
248
269
  last_val = 0
249
270
  self.combo_placement.SetSelection(last_val)
250
271
 
251
272
  def __set_properties(self):
252
- self.button_create.SetToolTip(_("Creates the recognized contour elements / placements"))
273
+ self.check_invert.SetToolTip(_("Invert the image before processing"))
274
+ self.check_original.SetToolTip(
275
+ _("Use the original image instead of the dithered one")
276
+ )
277
+ self.check_auto.SetToolTip(_("Automatically update the preview"))
278
+ self.button_update.SetToolTip(_("Update the preview"))
279
+ self.button_create.SetToolTip(_("Creates the recognized contour elements"))
280
+ self.button_create_placement.SetToolTip(
281
+ _("Creates the corresponding placements")
282
+ )
283
+ self.combo_placement.SetToolTip(_("Select the placement position"))
253
284
  self.check_enable_contrast.SetToolTip(_("Enable Contrast"))
254
285
  self.check_enable_contrast.SetValue(False)
255
286
  self.button_reset_contrast.SetToolTip(_("Reset Contrast"))
256
287
  self.slider_contrast_contrast.SetToolTip(_("Contrast amount"))
257
- self.text_contrast_contrast.SetToolTip(_("Contrast the lights and darks by how much?"))
288
+ self.text_contrast_contrast.SetToolTip(
289
+ _("Contrast the lights and darks by how much?")
290
+ )
258
291
  self.slider_contrast_brightness.SetToolTip(_("Brightness amount"))
259
- self.text_contrast_brightness.SetToolTip(_("Make the image how much more bright?"))
260
- self.text_minimum.SetToolTip(_("What is the minimal size of objects (as percentage of the overall area)?"))
261
- self.text_maximum.SetToolTip(_("What is the maximal size of objects (as percentage of the overall area)?"))
262
- self.check_inner.SetToolTip(_("Do you want to recognize objects inside of another object?"))
263
- self.radio_method.SetToolTip(_("Do you want to create the contour itself or the minimal rectangle enclosing it?"))
264
- self.radio_simplify.SetToolTip(_("Shall we try to reduce the number of points for the created contour?"))
292
+ self.text_contrast_brightness.SetToolTip(
293
+ _("Make the image how much more bright?")
294
+ )
295
+ self.text_minimum.SetToolTip(
296
+ _(
297
+ "What is the minimal size of objects (as percentage of the overall area)?"
298
+ )
299
+ )
300
+ self.text_maximum.SetToolTip(
301
+ _(
302
+ "What is the maximal size of objects (as percentage of the overall area)?"
303
+ )
304
+ )
305
+ self.check_inner.SetToolTip(
306
+ _("Do you want to recognize objects inside of another object?")
307
+ )
308
+ self.radio_method.SetToolTip(
309
+ _(
310
+ "Do you want to create the contour itself or the minimal rectangle enclosing it?"
311
+ )
312
+ )
313
+ self.radio_simplify.SetToolTip(
314
+ _("Shall we try to reduce the number of points for the created contour?")
315
+ )
265
316
 
266
317
  self.slider_contrast_brightness.SetMaxSize(wx.Size(200, -1))
267
318
  self.slider_contrast_contrast.SetMaxSize(wx.Size(200, -1))
@@ -321,14 +372,11 @@ class ContourPanel(wx.Panel):
321
372
  self.reset_contrast()
322
373
  self.on_control_update(None)
323
374
 
324
- def on_slider_contrast_contrast(
325
- self, event=None
326
- ):
375
+ def on_slider_contrast_contrast(self, event=None):
327
376
  contrast = int(self.slider_contrast_contrast.GetValue())
328
377
  self.text_contrast_contrast.SetValue(str(contrast))
329
378
  if event and (
330
- not self.context.process_while_sliding
331
- and wx.GetMouseState().LeftIsDown()
379
+ not self.context.process_while_sliding and wx.GetMouseState().LeftIsDown()
332
380
  ):
333
381
  event.Skip()
334
382
  return
@@ -339,8 +387,7 @@ class ContourPanel(wx.Panel):
339
387
  brightness = int(self.slider_contrast_brightness.GetValue())
340
388
  self.text_contrast_brightness.SetValue(str(brightness))
341
389
  if event and (
342
- not self.context.process_while_sliding
343
- and wx.GetMouseState().LeftIsDown()
390
+ not self.context.process_while_sliding and wx.GetMouseState().LeftIsDown()
344
391
  ):
345
392
  event.Skip()
346
393
  return
@@ -357,7 +404,7 @@ class ContourPanel(wx.Panel):
357
404
  def on_creation(self, event):
358
405
  for idx, (geom, area) in enumerate(self.contours):
359
406
  node = PathNode(
360
- geometry = geom,
407
+ geometry=geom,
361
408
  stroke=Color("blue"),
362
409
  label=f"Contour {self.node.display_label()} #{idx+1}",
363
410
  )
@@ -366,7 +413,6 @@ class ContourPanel(wx.Panel):
366
413
  self.context.elements.signal("refresh_scene", "Scene")
367
414
 
368
415
  def on_creation_placement(self, event):
369
-
370
416
  def get_place_parameters(geom, method):
371
417
  points = list(geom.as_points())
372
418
  nx = None
@@ -391,21 +437,21 @@ class ContourPanel(wx.Panel):
391
437
  side2 = geom.distance(points[1], points[2])
392
438
  if method in (0, 1):
393
439
  if method == 0:
394
- # If the preference is for a long side then our reference point is pt0 if side1 is long and pt1 if side1 is short
440
+ # If the preference is for a long side then our reference point is pt0 if side1 is long and pt1 if side1 is short
395
441
  refidx = 0 if side1 < side2 else 1
396
442
  else:
397
443
  # If the preference is for a short side then our reference point is pt1 if side1 is long and pt0 if side1 is short
398
444
  refidx = 1 if side1 < side2 else 0
399
445
  ref_x = points[refidx].real
400
446
  ref_y = points[refidx].imag
401
- rotation_angle = geom.angle(points[refidx], points[refidx+1])
447
+ rotation_angle = geom.angle(points[refidx], points[refidx + 1])
402
448
  place_corner = 0
403
- elif method == 2: # center - unrotated
449
+ elif method == 2: # center - unrotated
404
450
  ref_x = (nx + mx) / 2
405
451
  ref_y = (ny + my) / 2
406
452
  rotation_angle = 0
407
453
  place_corner = 4
408
- elif method == 3: # center - rotated
454
+ elif method == 3: # center - rotated
409
455
  ref_x = (nx + mx) / 2
410
456
  ref_y = (ny + my) / 2
411
457
  rotation_angle = geom.angle(points[0], points[1])
@@ -416,14 +462,16 @@ class ContourPanel(wx.Panel):
416
462
  if method < 0:
417
463
  return
418
464
  for idx, (geom, area) in enumerate(self.contours):
419
- ref_x, ref_y, rotation_angle, place_corner = get_place_parameters(geom, method)
465
+ ref_x, ref_y, rotation_angle, place_corner = get_place_parameters(
466
+ geom, method
467
+ )
420
468
  self.context.elements.op_branch.add(
421
469
  type="place point",
422
470
  label=f"Contour #{idx+1}",
423
471
  x=ref_x,
424
472
  y=ref_y,
425
473
  rotation=rotation_angle,
426
- corner=place_corner
474
+ corner=place_corner,
427
475
  )
428
476
 
429
477
  self.context.elements.signal("refresh_scene")
@@ -535,6 +583,7 @@ class ContourPanel(wx.Panel):
535
583
 
536
584
  def calculate_contours(self):
537
585
  import time
586
+
538
587
  self.contours.clear()
539
588
  if self.image is None:
540
589
  return
@@ -557,15 +606,18 @@ class ContourPanel(wx.Panel):
557
606
  ignoreinner=self.parameters["cnt_ignoreinner"],
558
607
  needs_invert=True,
559
608
  )
609
+ if len(self.contours) == 0 or len(self.contours[0]) != 2:
610
+ self.label_info.SetLabel(_("No contours found."))
611
+ return
560
612
  for idx, (geom, area) in enumerate(self.contours):
561
613
  if method == 0:
562
614
  simple = self.parameters["cnt_simplify"]
563
615
  # We are on pixel level
564
616
  threshold = self.parameters["cnt_threshold"]
565
- if simple==1:
617
+ if simple == 1:
566
618
  # Let's try Visvalingam line simplification
567
619
  geom = geom.simplify_geometry(threshold=threshold)
568
- elif simple==2:
620
+ elif simple == 2:
569
621
  # Use Douglas-Peucker instead
570
622
  geom = geom.simplify(threshold)
571
623
  geom.transform(self.matrix)
@@ -573,10 +625,9 @@ class ContourPanel(wx.Panel):
573
625
 
574
626
  t_b = time.perf_counter()
575
627
 
576
- self.label_info.SetLabel (
628
+ self.label_info.SetLabel(
577
629
  _("Contours generated: {count} in {duration}").format(
578
- count=len(self.contours),
579
- duration=f"{t_b-t_a:.2f} sec"
630
+ count=len(self.contours), duration=f"{t_b-t_a:.2f} sec"
580
631
  )
581
632
  )
582
633
 
@@ -587,15 +638,14 @@ class ContourPanel(wx.Panel):
587
638
  self.display_contours(highlight_index=idx)
588
639
 
589
640
  def on_right_click(self, event):
590
-
591
641
  def compare_contour(operation, index, this_area, idx, area):
592
- if operation == 'this':
642
+ if operation == "this":
593
643
  return idx == index
594
- elif operation == 'others':
644
+ elif operation == "others":
595
645
  return idx != index
596
- elif operation == 'smaller':
646
+ elif operation == "smaller":
597
647
  return area < this_area
598
- elif operation == 'bigger':
648
+ elif operation == "bigger":
599
649
  return area > this_area
600
650
  return False
601
651
 
@@ -603,13 +653,15 @@ class ContourPanel(wx.Panel):
603
653
  def handler(event):
604
654
  this_area = self.contours[index][1]
605
655
  to_be_deleted = [
606
- idx for idx, (_, area) in enumerate(self.contours)
656
+ idx
657
+ for idx, (_, area) in enumerate(self.contours)
607
658
  if compare_contour(operation, index, this_area, idx, area)
608
659
  ]
609
660
  for idx in reversed(to_be_deleted):
610
661
  self.contours.pop(idx)
611
662
  self.populate_list()
612
663
  self.display_contours()
664
+
613
665
  return handler
614
666
 
615
667
  index = self.list_contours.GetFirstSelected()
@@ -617,10 +669,10 @@ class ContourPanel(wx.Panel):
617
669
  return
618
670
  menu = wx.Menu()
619
671
  operations = [
620
- ('this', _("Delete this contour")),
621
- ('others', _("Delete all others")),
622
- ('bigger', _("Delete all bigger")),
623
- ('smaller', _("Delete all smaller"))
672
+ ("this", _("Delete this contour")),
673
+ ("others", _("Delete all others")),
674
+ ("bigger", _("Delete all bigger")),
675
+ ("smaller", _("Delete all smaller")),
624
676
  ]
625
677
 
626
678
  for op, label in operations:
@@ -638,19 +690,21 @@ class ContourPanel(wx.Panel):
638
690
  )
639
691
  self.list_contours.SetItem(list_id, 1, f"{area:.2f}%")
640
692
 
641
- def display_contours(self, highlight_index = -1):
693
+ def display_contours(self, highlight_index=-1):
642
694
  if self.make_raster is None:
643
695
  return
644
696
  if self.image is None:
645
697
  self.bitmap_preview.SetBitmap(wx.NullBitmap)
646
698
  return
647
- copynode = ImageNode(image=self.image, matrix=self.matrix, dither=False, prevent_crop=True)
699
+ copynode = ImageNode(
700
+ image=self.image, matrix=self.matrix, dither=False, prevent_crop=True
701
+ )
648
702
  data = [copynode]
649
703
  for idx, (geom, area) in enumerate(self.contours):
650
704
  node = PathNode(
651
- geometry = geom,
652
- stroke=Color("red") if highlight_index==idx else Color("blue"),
653
- fill=Color("yellow") if highlight_index==idx else None,
705
+ geometry=geom,
706
+ stroke=Color("red") if highlight_index == idx else Color("blue"),
707
+ fill=Color("yellow") if highlight_index == idx else None,
654
708
  label=f"Contour {self.node.display_label()} #{idx+1} [{area:.2f}%]",
655
709
  )
656
710
  data.append(node)
@@ -678,6 +732,7 @@ class ContourPanel(wx.Panel):
678
732
  idx = self.list_contours.GetFirstSelected()
679
733
  self.display_contours(highlight_index=idx)
680
734
 
735
+
681
736
  class KeyholePanel(wx.Panel):
682
737
  name = _("Keyhole")
683
738
  priority = 5
@@ -702,9 +757,7 @@ class KeyholePanel(wx.Panel):
702
757
  def __do_layout(self):
703
758
  # begin wxGlade: PositionPanel.__do_layout
704
759
  sizer_main = wx.BoxSizer(wx.VERTICAL)
705
- sizer_release = StaticBoxSizer(
706
- self, wx.ID_ANY, _("Keyhole:"), wx.HORIZONTAL
707
- )
760
+ sizer_release = StaticBoxSizer(self, wx.ID_ANY, _("Keyhole:"), wx.HORIZONTAL)
708
761
  sizer_release.Add(self.button_release, 1, wx.ALIGN_CENTER_VERTICAL, 0)
709
762
 
710
763
  sizer_main.Add(sizer_release, 0, wx.EXPAND, 0)
@@ -715,9 +768,7 @@ class KeyholePanel(wx.Panel):
715
768
 
716
769
  def __set_properties(self):
717
770
  self.button_release.SetToolTip(
718
- _(
719
- "Remove the keyhole and show the complete image"
720
- )
771
+ _("Remove the keyhole and show the complete image")
721
772
  )
722
773
 
723
774
  def pane_hide(self):
@@ -941,7 +992,6 @@ class CropPanel(wx.Panel):
941
992
  self.set_slider_limits("lrtb")
942
993
  self.context.elements.do_image_update(self.node, self.context)
943
994
 
944
-
945
995
  def on_check_enable_crop(self, event=None):
946
996
  flag = self.check_enable_crop.GetValue()
947
997
  if flag:
@@ -971,8 +1021,7 @@ class CropPanel(wx.Panel):
971
1021
 
972
1022
  def on_slider_left(self, event=None):
973
1023
  if event and (
974
- not self.context.process_while_sliding
975
- and wx.GetMouseState().LeftIsDown()
1024
+ not self.context.process_while_sliding and wx.GetMouseState().LeftIsDown()
976
1025
  ):
977
1026
  event.Skip()
978
1027
  return
@@ -980,8 +1029,7 @@ class CropPanel(wx.Panel):
980
1029
 
981
1030
  def on_slider_right(self, event=None):
982
1031
  if event and (
983
- not self.context.process_while_sliding
984
- and wx.GetMouseState().LeftIsDown()
1032
+ not self.context.process_while_sliding and wx.GetMouseState().LeftIsDown()
985
1033
  ):
986
1034
  event.Skip()
987
1035
  return
@@ -990,8 +1038,7 @@ class CropPanel(wx.Panel):
990
1038
  def on_slider_top(self, event=None):
991
1039
  # Wait until the user has stopped to move the slider
992
1040
  if event and (
993
- not self.context.process_while_sliding
994
- and wx.GetMouseState().LeftIsDown()
1041
+ not self.context.process_while_sliding and wx.GetMouseState().LeftIsDown()
995
1042
  ):
996
1043
  event.Skip()
997
1044
  return
@@ -999,8 +1046,7 @@ class CropPanel(wx.Panel):
999
1046
 
1000
1047
  def on_slider_bottom(self, event=None):
1001
1048
  if event and (
1002
- not self.context.process_while_sliding
1003
- and wx.GetMouseState().LeftIsDown()
1049
+ not self.context.process_while_sliding and wx.GetMouseState().LeftIsDown()
1004
1050
  ):
1005
1051
  event.Skip()
1006
1052
  return
@@ -1052,7 +1098,6 @@ class CropPanel(wx.Panel):
1052
1098
  else:
1053
1099
  self.text_bottom.SetValue(f"> {dvalue} px")
1054
1100
 
1055
-
1056
1101
  def _setbounds(self):
1057
1102
  if self.op is None:
1058
1103
  return
@@ -1137,6 +1182,7 @@ class CropPanel(wx.Panel):
1137
1182
  self.set_slider_limits("t")
1138
1183
  self._setbounds()
1139
1184
 
1185
+
1140
1186
  class ImageModificationPanel(ScrolledPanel):
1141
1187
  name = _("Modification")
1142
1188
  priority = 90
@@ -1167,7 +1213,8 @@ class ImageModificationPanel(ScrolledPanel):
1167
1213
  self,
1168
1214
  wx.ID_ANY,
1169
1215
  style=wx.LC_HRULES | wx.LC_REPORT | wx.LC_VRULES | wx.LC_SINGLE_SEL,
1170
- context=self.context, list_name="list_imageoperations",
1216
+ context=self.context,
1217
+ list_name="list_imageoperations",
1171
1218
  )
1172
1219
 
1173
1220
  self._do_layout()
@@ -1187,7 +1234,9 @@ class ImageModificationPanel(ScrolledPanel):
1187
1234
  )
1188
1235
  self.list_operations.resize_columns()
1189
1236
  sizer_main = wx.BoxSizer(wx.VERTICAL)
1190
- sizer_script = StaticBoxSizer(self, wx.ID_ANY, _("Raster-Wizard"), wx.HORIZONTAL)
1237
+ sizer_script = StaticBoxSizer(
1238
+ self, wx.ID_ANY, _("Raster-Wizard"), wx.HORIZONTAL
1239
+ )
1191
1240
 
1192
1241
  sizer_script.Add(self.combo_scripts, 1, wx.EXPAND, 0)
1193
1242
  sizer_script.Add(self.button_apply, 0, wx.EXPAND, 0)
@@ -1385,6 +1434,7 @@ class ImageModificationPanel(ScrolledPanel):
1385
1434
  def signal(self, signalstr, myargs):
1386
1435
  return
1387
1436
 
1437
+
1388
1438
  class ImageVectorisationPanel(ScrolledPanel):
1389
1439
  name = _("Vectorisation")
1390
1440
  priority = 95
@@ -1785,6 +1835,7 @@ class ImageVectorisationPanel(ScrolledPanel):
1785
1835
  def signal(self, signalstr, myargs):
1786
1836
  return
1787
1837
 
1838
+
1788
1839
  class ImagePropertyPanel(ScrolledPanel):
1789
1840
  def __init__(self, *args, context=None, node=None, **kwargs):
1790
1841
  # begin wxGlade: ConsolePanel.__init__
@@ -1893,15 +1944,11 @@ class ImagePropertyPanel(ScrolledPanel):
1893
1944
  self.slider_grayscale_green = wx.Slider(
1894
1945
  self, wx.ID_ANY, 0, -1000, 1000, style=wx.SL_AUTOTICKS | wx.SL_HORIZONTAL
1895
1946
  )
1896
- self.text_grayscale_green = TextCtrl(
1897
- self, wx.ID_ANY, "", style=wx.TE_READONLY
1898
- )
1947
+ self.text_grayscale_green = TextCtrl(self, wx.ID_ANY, "", style=wx.TE_READONLY)
1899
1948
  self.slider_grayscale_blue = wx.Slider(
1900
1949
  self, wx.ID_ANY, 0, -1000, 1000, style=wx.SL_AUTOTICKS | wx.SL_HORIZONTAL
1901
1950
  )
1902
- self.text_grayscale_blue = TextCtrl(
1903
- self, wx.ID_ANY, "", style=wx.TE_READONLY
1904
- )
1951
+ self.text_grayscale_blue = TextCtrl(self, wx.ID_ANY, "", style=wx.TE_READONLY)
1905
1952
  self.slider_grayscale_lightness = wx.Slider(
1906
1953
  self, wx.ID_ANY, 500, 0, 1000, style=wx.SL_AUTOTICKS | wx.SL_HORIZONTAL
1907
1954
  )
@@ -1989,7 +2036,7 @@ class ImagePropertyPanel(ScrolledPanel):
1989
2036
  self.combo_dither.SetValue(node.dither_type)
1990
2037
  self.combo_dither.Enable(bool(node.dither))
1991
2038
  self.check_enable_depthmap.SetValue(node.is_depthmap)
1992
- resolutions =list((2**p for p in range(8, 1, -1)))
2039
+ resolutions = list((2**p for p in range(8, 1, -1)))
1993
2040
  try:
1994
2041
  idx = resolutions.index(node.depth_resolution)
1995
2042
  except (IndexError, AttributeError, ValueError) as e:
@@ -2002,8 +2049,9 @@ class ImagePropertyPanel(ScrolledPanel):
2002
2049
 
2003
2050
  def __set_properties(self):
2004
2051
  self.check_keep_size.SetToolTip(
2005
- _("Enabled: Keep size and amend internal resolution") + "\n" +
2006
- _("Disabled: Keep internal resolution and change size")
2052
+ _("Enabled: Keep size and amend internal resolution")
2053
+ + "\n"
2054
+ + _("Disabled: Keep internal resolution and change size")
2007
2055
  )
2008
2056
  self.check_prevent_crop.SetToolTip(_("Prevent final crop after all operations"))
2009
2057
  self.check_enable_dither.SetToolTip(_("Enable Dither"))
@@ -2022,20 +2070,27 @@ class ImagePropertyPanel(ScrolledPanel):
2022
2070
  self.text_grayscale_blue.SetToolTip(_("Blue Factor"))
2023
2071
  self.slider_grayscale_lightness.SetToolTip(_("Lightness control"))
2024
2072
  self.text_grayscale_lightness.SetToolTip(_("Lightness"))
2025
- self.btn_reset_grayscale.SetToolTip(_("Reset the grayscale modifiers to standard values"))
2073
+ self.btn_reset_grayscale.SetToolTip(
2074
+ _("Reset the grayscale modifiers to standard values")
2075
+ )
2026
2076
 
2027
- DEPTH_FLAG_TOOLTIP = _("Do you want to treat this bitmap as depthmap where every greyscal-level corresponds to the amount of times this pixel will be burnt")
2077
+ DEPTH_FLAG_TOOLTIP = _(
2078
+ "Do you want to treat this bitmap as depthmap where every greyscal-level corresponds to the amount of times this pixel will be burnt"
2079
+ )
2028
2080
  self.check_enable_depthmap.SetToolTip(DEPTH_FLAG_TOOLTIP)
2029
2081
  self.check_enable_depthmap.SetValue(False)
2030
- DEPTH_RES_TOOLTIP =(
2031
- _("How many grayscales do you want to distinguish?") + "\n" +
2032
- _(
2082
+ DEPTH_RES_TOOLTIP = (
2083
+ _("How many grayscales do you want to distinguish?")
2084
+ + "\n"
2085
+ + _(
2033
2086
  "This operation will step through the image and process it per defined grayscale resolution."
2034
- ) + "\n" +
2035
- _(
2087
+ )
2088
+ + "\n"
2089
+ + _(
2036
2090
  "So for full resolution every grayscale level would be processed individually: a black line (or a white line if inverted) would be processed 255 times, a line with grayscale value 128 would be processed 128 times."
2037
- ) + "\n" +
2038
- _(
2091
+ )
2092
+ + "\n"
2093
+ + _(
2039
2094
  "You can define a coarser resolution e.g. 64: then very faint lines (grayscale 1-4) would be burned just once, very strong lines (level 252-255) would be burned 64 times."
2040
2095
  )
2041
2096
  )
@@ -2217,8 +2272,7 @@ class ImagePropertyPanel(ScrolledPanel):
2217
2272
  self, event=None
2218
2273
  ): # wxGlade: GrayscalePanel.<event_handler>
2219
2274
  if event and (
2220
- not self.context.process_while_sliding
2221
- and wx.GetMouseState().LeftIsDown()
2275
+ not self.context.process_while_sliding and wx.GetMouseState().LeftIsDown()
2222
2276
  ):
2223
2277
  event.Skip()
2224
2278
  return
meerk40t/gui/ribbon.py CHANGED
@@ -128,6 +128,7 @@ class Button:
128
128
  self.state_unpressed = None
129
129
  self.group = None
130
130
  self.toggle_attr = None
131
+ self.multi_autoexec = None
131
132
  self.identifier = None
132
133
  self.action = None
133
134
  self.action_right = None
@@ -155,6 +156,7 @@ class Button:
155
156
  rule_enabled=None,
156
157
  rule_visible=None,
157
158
  object=None,
159
+ multi_autoexec=None,
158
160
  **kwargs,
159
161
  ):
160
162
  """
@@ -205,6 +207,7 @@ class Button:
205
207
  self.action_right = action_right
206
208
  self.rule_enabled = rule_enabled
207
209
  self.rule_visible = rule_visible
210
+ self.multi_autoexec = multi_autoexec
208
211
  if object is not None:
209
212
  self.object = object
210
213
  else:
@@ -276,6 +279,7 @@ class Button:
276
279
  "rule_visible": self.rule_visible,
277
280
  "toggle_attr": self.toggle_attr,
278
281
  "object": self.object,
282
+ "multi_autoexec": self.multi_autoexec,
279
283
  }
280
284
  self._update_button_aspect(key, **kwargs)
281
285
 
@@ -438,7 +442,8 @@ class Button:
438
442
  self._restore_button_aspect(key_id)
439
443
  # self.ensure_realize()
440
444
  # And now execute it, provided it would be enabled...
441
- auto_execute = self.context.setting(bool, "button_multi_menu_execute", True)
445
+ auto_execute = False if self.multi_autoexec is None else self.multi_autoexec
446
+ auto_execute = auto_execute and self.context.setting(bool, "button_multi_menu_execute", True)
442
447
  if auto_execute:
443
448
  is_visible = True
444
449
  is_enabled = True