meerk40t 0.9.7051__py2.py3-none-any.whl → 0.9.7910__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 (69) hide show
  1. meerk40t/balormk/controller.py +3 -3
  2. meerk40t/balormk/device.py +7 -0
  3. meerk40t/balormk/driver.py +23 -14
  4. meerk40t/balormk/galvo_commands.py +18 -3
  5. meerk40t/balormk/gui/balorconfig.py +6 -0
  6. meerk40t/balormk/livelightjob.py +36 -14
  7. meerk40t/camera/camera.py +1 -0
  8. meerk40t/camera/gui/camerapanel.py +154 -58
  9. meerk40t/camera/plugin.py +46 -5
  10. meerk40t/core/elements/branches.py +90 -20
  11. meerk40t/core/elements/elements.py +59 -37
  12. meerk40t/core/elements/trace.py +10 -6
  13. meerk40t/core/node/node.py +2 -0
  14. meerk40t/core/plotplanner.py +7 -4
  15. meerk40t/device/gui/defaultactions.py +78 -14
  16. meerk40t/dxf/dxf_io.py +42 -0
  17. meerk40t/grbl/controller.py +245 -35
  18. meerk40t/grbl/device.py +102 -26
  19. meerk40t/grbl/driver.py +8 -2
  20. meerk40t/grbl/gui/grblconfiguration.py +6 -0
  21. meerk40t/grbl/gui/grblcontroller.py +1 -1
  22. meerk40t/gui/about.py +7 -0
  23. meerk40t/gui/choicepropertypanel.py +20 -30
  24. meerk40t/gui/devicepanel.py +27 -16
  25. meerk40t/gui/help_assets/help_assets.py +126 -2
  26. meerk40t/gui/icons.py +15 -0
  27. meerk40t/gui/laserpanel.py +102 -54
  28. meerk40t/gui/materialtest.py +10 -0
  29. meerk40t/gui/mkdebug.py +268 -9
  30. meerk40t/gui/navigationpanels.py +74 -8
  31. meerk40t/gui/propertypanels/operationpropertymain.py +185 -91
  32. meerk40t/gui/scenewidgets/elementswidget.py +7 -1
  33. meerk40t/gui/scenewidgets/selectionwidget.py +24 -9
  34. meerk40t/gui/simulation.py +1 -1
  35. meerk40t/gui/statusbarwidgets/shapepropwidget.py +50 -40
  36. meerk40t/gui/statusbarwidgets/statusbar.py +2 -2
  37. meerk40t/gui/toolwidgets/toolmeasure.py +1 -1
  38. meerk40t/gui/toolwidgets/toolnodeedit.py +4 -1
  39. meerk40t/gui/toolwidgets/tooltabedit.py +9 -7
  40. meerk40t/gui/wxmeerk40t.py +45 -15
  41. meerk40t/gui/wxmmain.py +23 -9
  42. meerk40t/gui/wxmribbon.py +36 -0
  43. meerk40t/gui/wxutils.py +66 -42
  44. meerk40t/kernel/inhibitor.py +120 -0
  45. meerk40t/kernel/kernel.py +38 -0
  46. meerk40t/lihuiyu/controller.py +33 -3
  47. meerk40t/lihuiyu/device.py +99 -4
  48. meerk40t/lihuiyu/driver.py +65 -5
  49. meerk40t/lihuiyu/gui/lhycontrollergui.py +69 -24
  50. meerk40t/lihuiyu/gui/lhydrivergui.py +6 -0
  51. meerk40t/lihuiyu/laserspeed.py +17 -10
  52. meerk40t/lihuiyu/parser.py +23 -0
  53. meerk40t/main.py +2 -2
  54. meerk40t/moshi/gui/moshidrivergui.py +7 -0
  55. meerk40t/newly/controller.py +3 -2
  56. meerk40t/newly/device.py +23 -2
  57. meerk40t/newly/driver.py +8 -3
  58. meerk40t/newly/gui/newlyconfig.py +7 -0
  59. meerk40t/ruida/gui/ruidaconfig.py +7 -0
  60. meerk40t/tools/geomstr.py +142 -49
  61. meerk40t/tools/rasterplotter.py +0 -5
  62. meerk40t/tools/ttfparser.py +921 -168
  63. {meerk40t-0.9.7051.dist-info → meerk40t-0.9.7910.dist-info}/METADATA +1 -1
  64. {meerk40t-0.9.7051.dist-info → meerk40t-0.9.7910.dist-info}/RECORD +69 -68
  65. {meerk40t-0.9.7051.dist-info → meerk40t-0.9.7910.dist-info}/LICENSE +0 -0
  66. {meerk40t-0.9.7051.dist-info → meerk40t-0.9.7910.dist-info}/WHEEL +0 -0
  67. {meerk40t-0.9.7051.dist-info → meerk40t-0.9.7910.dist-info}/entry_points.txt +0 -0
  68. {meerk40t-0.9.7051.dist-info → meerk40t-0.9.7910.dist-info}/top_level.txt +0 -0
  69. {meerk40t-0.9.7051.dist-info → meerk40t-0.9.7910.dist-info}/zip-safe +0 -0
@@ -1,7 +1,7 @@
1
1
  import wx
2
2
 
3
3
  from meerk40t.core.elements.element_types import elem_nodes
4
- from meerk40t.core.units import Length, UNITS_PER_PIXEL
4
+ from meerk40t.core.units import UNITS_PER_PIXEL, Length
5
5
  from meerk40t.gui.icons import (
6
6
  icon_cap_butt,
7
7
  icon_cap_round,
@@ -41,38 +41,40 @@ class LinecapWidget(StatusBarWidget):
41
41
  )
42
42
  )
43
43
  self.btn_cap_butt = wxStaticBitmap(
44
- self.parent, id=wx.ID_ANY, size=wx.Size(self.height, -1), style=wx.BORDER_RAISED
44
+ self.parent,
45
+ id=wx.ID_ANY,
46
+ size=wx.Size(self.height, -1),
47
+ style=wx.BORDER_RAISED,
45
48
  )
46
- isize = int(max(20, self.parent.available_height - 4) * self.context.root.bitmap_correction_scale)
47
-
48
- self.btn_cap_butt.SetBitmap(
49
- icon_cap_butt.GetBitmap(
50
- resize=isize, buffer=1
51
- )
49
+ isize = int(
50
+ max(20, self.parent.available_height - 4)
51
+ * self.context.root.bitmap_correction_scale
52
52
  )
53
+
54
+ self.btn_cap_butt.SetBitmap(icon_cap_butt.GetBitmap(resize=isize, buffer=1))
53
55
  self.btn_cap_butt.SetMaxSize(wx.Size(50, -1))
54
56
  self.btn_cap_butt.SetToolTip(_("Set the end of the lines to a butt-shape"))
55
57
  self.btn_cap_butt.Bind(wx.EVT_LEFT_DOWN, self.on_cap_butt)
56
58
 
57
59
  self.btn_cap_round = wxStaticBitmap(
58
- self.parent, id=wx.ID_ANY, size=wx.Size(self.height, -1), style=wx.BORDER_RAISED
59
- )
60
- self.btn_cap_round.SetBitmap(
61
- icon_cap_round.GetBitmap(
62
- resize=isize, buffer=1
63
- )
60
+ self.parent,
61
+ id=wx.ID_ANY,
62
+ size=wx.Size(self.height, -1),
63
+ style=wx.BORDER_RAISED,
64
64
  )
65
+ self.btn_cap_round.SetBitmap(icon_cap_round.GetBitmap(resize=isize, buffer=1))
65
66
  self.btn_cap_round.SetMaxSize(wx.Size(50, -1))
66
67
  self.btn_cap_round.SetToolTip(_("Set the end of the lines to a round-shape"))
67
68
  self.btn_cap_round.Bind(wx.EVT_LEFT_DOWN, self.on_cap_round)
68
69
 
69
70
  self.btn_cap_square = wxStaticBitmap(
70
- self.parent, id=wx.ID_ANY, size=wx.Size(self.height, -1), style=wx.BORDER_RAISED
71
+ self.parent,
72
+ id=wx.ID_ANY,
73
+ size=wx.Size(self.height, -1),
74
+ style=wx.BORDER_RAISED,
71
75
  )
72
76
 
73
- self.btn_cap_square.SetBitmap(
74
- icon_cap_square.GetBitmap(resize=isize, buffer=1)
75
- )
77
+ self.btn_cap_square.SetBitmap(icon_cap_square.GetBitmap(resize=isize, buffer=1))
76
78
  self.btn_cap_square.SetMaxSize(wx.Size(50, -1))
77
79
  self.btn_cap_square.SetToolTip(_("Set the end of the lines to a square-shape"))
78
80
  self.btn_cap_square.Bind(wx.EVT_LEFT_DOWN, self.on_cap_square)
@@ -116,16 +118,14 @@ class LinejoinWidget(StatusBarWidget):
116
118
  )
117
119
  )
118
120
  isize = int(
119
- max(20, self.parent.available_height - 4) *
120
- self.context.root.bitmap_correction_scale
121
+ max(20, self.parent.available_height - 4)
122
+ * self.context.root.bitmap_correction_scale
121
123
  )
122
124
  self.btn_join_bevel = wxStaticBitmap(
123
125
  self.parent, id=wx.ID_ANY, size=wx.Size(25, -1), style=wx.BORDER_RAISED
124
126
  )
125
127
 
126
- self.btn_join_bevel.SetBitmap(
127
- icon_join_bevel.GetBitmap(resize=isize, buffer=1)
128
- )
128
+ self.btn_join_bevel.SetBitmap(icon_join_bevel.GetBitmap(resize=isize, buffer=1))
129
129
  self.btn_join_bevel.SetMaxSize(wx.Size(50, -1))
130
130
  self.btn_join_bevel.SetToolTip(_("Set the join of the lines to a bevel-shape"))
131
131
  self.btn_join_bevel.Bind(wx.EVT_LEFT_DOWN, self.on_join_bevel)
@@ -133,9 +133,7 @@ class LinejoinWidget(StatusBarWidget):
133
133
  self.btn_join_round = wxStaticBitmap(
134
134
  self.parent, id=wx.ID_ANY, size=wx.Size(25, -1), style=wx.BORDER_RAISED
135
135
  )
136
- self.btn_join_round.SetBitmap(
137
- icon_join_round.GetBitmap(resize=isize, buffer=1)
138
- )
136
+ self.btn_join_round.SetBitmap(icon_join_round.GetBitmap(resize=isize, buffer=1))
139
137
  self.btn_join_round.SetMaxSize(wx.Size(50, -1))
140
138
  self.btn_join_round.SetToolTip(_("Set the join of lines to a round-shape"))
141
139
  self.btn_join_round.Bind(wx.EVT_LEFT_DOWN, self.on_join_round)
@@ -143,9 +141,7 @@ class LinejoinWidget(StatusBarWidget):
143
141
  self.btn_join_miter = wxStaticBitmap(
144
142
  self.parent, id=wx.ID_ANY, size=wx.Size(25, -1), style=wx.BORDER_RAISED
145
143
  )
146
- self.btn_join_miter.SetBitmap(
147
- icon_join_miter.GetBitmap(resize=isize, buffer=1)
148
- )
144
+ self.btn_join_miter.SetBitmap(icon_join_miter.GetBitmap(resize=isize, buffer=1))
149
145
  self.btn_join_miter.SetMaxSize(wx.Size(50, -1))
150
146
  self.btn_join_miter.SetToolTip(_("Set the join of lines to a miter-shape"))
151
147
  self.btn_join_miter.Bind(wx.EVT_LEFT_DOWN, self.on_join_miter)
@@ -207,12 +203,15 @@ class FillruleWidget(StatusBarWidget):
207
203
  )
208
204
  )
209
205
  isize = int(
210
- max(20, self.parent.available_height - 4) *
211
- self.context.root.bitmap_correction_scale
206
+ max(20, self.parent.available_height - 4)
207
+ * self.context.root.bitmap_correction_scale
212
208
  )
213
209
 
214
210
  self.btn_fill_nonzero = wxStaticBitmap(
215
- self.parent, id=wx.ID_ANY, size=wx.Size(self.height, -1), style=wx.BORDER_RAISED
211
+ self.parent,
212
+ id=wx.ID_ANY,
213
+ size=wx.Size(self.height, -1),
214
+ style=wx.BORDER_RAISED,
216
215
  )
217
216
  self.btn_fill_nonzero.SetMaxSize(wx.Size(50, -1))
218
217
  self.btn_fill_nonzero.SetBitmap(
@@ -222,7 +221,10 @@ class FillruleWidget(StatusBarWidget):
222
221
  self.btn_fill_nonzero.Bind(wx.EVT_LEFT_DOWN, self.on_fill_nonzero)
223
222
 
224
223
  self.btn_fill_evenodd = wxStaticBitmap(
225
- self.parent, id=wx.ID_ANY, size=wx.Size(self.height, -1), style=wx.BORDER_RAISED
224
+ self.parent,
225
+ id=wx.ID_ANY,
226
+ size=wx.Size(self.height, -1),
227
+ style=wx.BORDER_RAISED,
226
228
  )
227
229
  self.btn_fill_evenodd.SetBitmap(
228
230
  icon_fill_evenodd.GetBitmap(resize=isize, buffer=1)
@@ -289,18 +291,27 @@ class PositionWidget(StatusBarWidget):
289
291
  self.parent, wx.ID_ANY, label=self.units[self.unit_index]
290
292
  )
291
293
  icon_size = int(
292
- max(20, self.parent.available_height - 4) *
293
- self.context.root.bitmap_correction_scale
294
+ max(20, self.parent.available_height - 8)
295
+ * self.context.root.bitmap_correction_scale
294
296
  )
295
297
 
296
- self.button_lock_ratio = wxStaticBitmap(self.parent, id=wx.ID_ANY, size=wx.Size(icon_size, -1), style=wx.BORDER_RAISED)
298
+ self.button_lock_ratio = wxStaticBitmap(
299
+ self.parent,
300
+ id=wx.ID_ANY,
301
+ size=wx.Size(icon_size, -1),
302
+ style=wx.BORDER_RAISED,
303
+ )
297
304
  self.bitmap_locked = icons8_lock.GetBitmap(resize=icon_size, use_theme=False)
298
- self.bitmap_unlocked = icons8_unlock.GetBitmap(resize=icon_size, use_theme=False)
305
+ self.bitmap_unlocked = icons8_unlock.GetBitmap(
306
+ resize=icon_size, use_theme=False
307
+ )
299
308
 
300
309
  self.offset_index = 0 # 0 to 8 tl tc tr cl cc cr bl bc br
301
310
  self.offset_x = 0.0
302
311
  self.offset_y = 0.0
303
- self.button_param = wxStaticBitmap(self.parent, id=wx.ID_ANY, size=wx.Size(icon_size, -1), style=wx.BORDER_RAISED)
312
+ self.button_param = wxStaticBitmap(
313
+ self.parent, id=wx.ID_ANY, size=wx.Size(icon_size, -1), style=wx.BORDER_NONE
314
+ )
304
315
  self.pos_bitmaps = self.calculate_icons(icon_size)
305
316
  self.button_param.SetBitmap(self.pos_bitmaps[self.offset_index])
306
317
 
@@ -369,8 +380,7 @@ class PositionWidget(StatusBarWidget):
369
380
  )
370
381
 
371
382
  self._lock_ratio = True
372
- self.lock_ratio = self.context.lock_active
373
-
383
+ self.lock_ratio = self.context.lock_active
374
384
 
375
385
  @property
376
386
  def units_name(self):
@@ -1,7 +1,7 @@
1
1
  import wx
2
2
 
3
3
  from meerk40t.gui.icons import icons8_circled_right
4
- from meerk40t.gui.wxutils import wxStaticBitmap, dip_size
4
+ from meerk40t.gui.wxutils import dip_size, wxStaticBitmap
5
5
 
6
6
  _ = wx.GetTranslation
7
7
 
@@ -61,7 +61,7 @@ class CustomStatusBar(wx.StatusBar):
61
61
  @property
62
62
  def available_height(self):
63
63
  sb_size = self.GetSize()
64
- return sb_size[1]
64
+ return max(1, sb_size[1] - 2)
65
65
 
66
66
  def Clear(self):
67
67
  """
@@ -40,7 +40,7 @@ class MeasureTool(PointListTool):
40
40
  return
41
41
  mat_fact = get_gc_scale(gc)
42
42
  try:
43
- font_size = 10.0 / mat_fact
43
+ font_size = 10.0 * self.magnification / mat_fact
44
44
  except ZeroDivisionError:
45
45
  font_size = 5000
46
46
  if font_size > 1e8:
@@ -907,7 +907,10 @@ class EditTool(ToolWidget):
907
907
  path.approximate_arcs_with_cubics()
908
908
  except AttributeError:
909
909
  return
910
- newnode = node.replace_node(path=path, type="elem path")
910
+ try:
911
+ newnode = node.replace_node(path=path, type="elem path")
912
+ except ValueError:
913
+ return
911
914
  for item in oldstuff:
912
915
  setattr(newnode, item[0], item[1])
913
916
  newnode.altered()
@@ -11,7 +11,7 @@ from meerk40t.gui.scene.sceneconst import (
11
11
  RESPONSE_DROP,
12
12
  )
13
13
  from meerk40t.gui.toolwidgets.toolwidget import ToolWidget
14
- from meerk40t.gui.wxutils import get_gc_scale
14
+ from meerk40t.gui.wxutils import get_gc_scale, dip_size
15
15
 
16
16
  _ = wx.GetTranslation
17
17
 
@@ -35,6 +35,7 @@ class SimpleSlider:
35
35
  trailer = ""
36
36
  self.trailer = trailer
37
37
  self.no_value_display = False
38
+ self.magnification = dip_size(scene.gui, 100, 100)[1] / 100
38
39
 
39
40
  @property
40
41
  def value(self):
@@ -77,7 +78,7 @@ class SimpleSlider:
77
78
  """
78
79
  gc.PushState()
79
80
  s = math.sqrt(abs(self.scene.widget_root.scene_widget.matrix.determinant))
80
- offset = self.pt_offset / s
81
+ offset = self.pt_offset * self.magnification / s
81
82
 
82
83
  mypen = wx.Pen(wx.LIGHT_GREY)
83
84
  sx = get_gc_scale(gc)
@@ -119,7 +120,7 @@ class SimpleSlider:
119
120
  if not self.trailer.startswith("%"):
120
121
  symbol += " "
121
122
  symbol += _(self.trailer)
122
- font_size = 10 / s
123
+ font_size = 10 * self.magnification / s
123
124
  if font_size < 1.0:
124
125
  font_size = 1.0
125
126
  try:
@@ -146,7 +147,7 @@ class SimpleSlider:
146
147
 
147
148
  def hit(self, xpos, ypos):
148
149
  s = math.sqrt(abs(self.scene.widget_root.scene_widget.matrix.determinant))
149
- offset = self.pt_offset / s
150
+ offset = self.pt_offset * self.magnification / s
150
151
  inside = bool(abs(self.ptx - xpos) <= offset and abs(self.pty - ypos) <= offset)
151
152
  return inside
152
153
 
@@ -177,6 +178,7 @@ class TabEditTool(ToolWidget):
177
178
  slider = SimpleSlider(0, self.scene, minval, maxval, 0, 0, self.slider_size, info )
178
179
  slider.no_value_display = True
179
180
  self.sliders.append(slider)
181
+ self.magnification = dip_size(scene.gui, 100, 100)[1] / 100
180
182
 
181
183
  def reset(self):
182
184
  self.points.clear()
@@ -358,7 +360,7 @@ class TabEditTool(ToolWidget):
358
360
  if len(self.sliders) == 0:
359
361
  return
360
362
  s = math.sqrt(abs(self.scene.widget_root.scene_widget.matrix.determinant))
361
- offset = self.pt_offset / s
363
+ offset = self.pt_offset * self.magnification / s
362
364
  width = self.slider_size / s
363
365
  x = bb[0]
364
366
  y = bb[1]
@@ -377,7 +379,7 @@ class TabEditTool(ToolWidget):
377
379
  """
378
380
  gc.PushState()
379
381
  s = math.sqrt(abs(self.scene.widget_root.scene_widget.matrix.determinant))
380
- offset = self.pt_offset / s
382
+ offset = self.pt_offset * self.magnification / s
381
383
  gc.SetPen(wx.RED_PEN)
382
384
  gc.SetBrush(wx.RED_BRUSH)
383
385
  for index, g in enumerate(self.points):
@@ -424,7 +426,7 @@ class TabEditTool(ToolWidget):
424
426
  return RESPONSE_CHAIN
425
427
  self.scene.pane.tool_active = True
426
428
  self.scene.pane.modif_active = True
427
- offset = self.pt_offset
429
+ offset = self.pt_offset * self.magnification
428
430
  s = math.sqrt(abs(self.scene.widget_root.scene_widget.matrix.determinant))
429
431
  offset /= s
430
432
  xp = space_pos[0]
@@ -7,6 +7,7 @@ from datetime import datetime
7
7
  import wx
8
8
  from wx import aui
9
9
 
10
+ from meerk40t.core.units import Length
10
11
  from meerk40t.gui.consolepanel import Console
11
12
  from meerk40t.gui.navigationpanels import Navigation
12
13
  from meerk40t.gui.spoolerpanel import JobSpooler
@@ -24,7 +25,6 @@ from meerk40t.gui.wxmscene import SceneWindow
24
25
  from meerk40t.gui.wxutils import TextCtrl, wxButton, wxStaticText
25
26
  from meerk40t.kernel import CommandSyntaxError, Module, get_safe_path
26
27
  from meerk40t.kernel.kernel import Job
27
- from meerk40t.core.units import Length
28
28
 
29
29
  from ..main import APPLICATION_NAME, APPLICATION_VERSION
30
30
  from ..tools.kerftest import KerfTool
@@ -35,6 +35,7 @@ from .autoexec import AutoExec
35
35
  from .bufferview import BufferView
36
36
  from .devicepanel import DeviceManager
37
37
  from .executejob import ExecuteJob
38
+ from .functionwrapper import ConsoleCommandUI
38
39
  from .hersheymanager import (
39
40
  HersheyFontManager,
40
41
  HersheyFontSelector,
@@ -90,7 +91,6 @@ from .propertypanels.wobbleproperty import WobblePropertyPanel
90
91
  from .simpleui import SimpleUI
91
92
  from .simulation import Simulation
92
93
  from .tips import Tips
93
- from .functionwrapper import ConsoleCommandUI
94
94
  from .wordlisteditor import WordlistEditor
95
95
  from .wxmmain import MeerK40t
96
96
 
@@ -108,6 +108,7 @@ The Transformations work in Windows/OSX/Linux for wxPython 4.0+ (and likely befo
108
108
 
109
109
  _ = wx.GetTranslation
110
110
 
111
+
111
112
  class ActionPanel(wx.Panel):
112
113
  def __init__(
113
114
  self,
@@ -410,6 +411,7 @@ supported_languages = (
410
411
  ("pt_BR", "português brasileiro", wx.LANGUAGE_PORTUGUESE_BRAZILIAN),
411
412
  ("ja", "日本", wx.LANGUAGE_JAPANESE),
412
413
  ("nl", "Nederlands", wx.LANGUAGE_DUTCH),
414
+ ("ru", "русский", wx.LANGUAGE_RUSSIAN),
413
415
  )
414
416
 
415
417
 
@@ -447,6 +449,8 @@ class wxMeerK40t(wx.App, Module):
447
449
  # Potential access denied.
448
450
  pass
449
451
  self.supported_languages = supported_languages
452
+ # for idx, (lang, name, wxlang) in enumerate(supported_languages):
453
+ # print (f"Language #{idx:02d} : {lang} - {name}")
450
454
  import meerk40t.gui.icons as icons
451
455
 
452
456
  self.timer = wx.Timer(self, id=wx.ID_ANY)
@@ -563,7 +567,11 @@ class wxMeerK40t(wx.App, Module):
563
567
  try:
564
568
  if self.context is not None:
565
569
  channel = self.context.kernel.channel("console")
566
- self.context.elements.load(os.path.realpath(filename), svg_ppi=self.context.elements.svg_ppi, channel=channel)
570
+ self.context.elements.load(
571
+ os.path.realpath(filename),
572
+ svg_ppi=self.context.elements.svg_ppi,
573
+ channel=channel,
574
+ )
567
575
  except AttributeError:
568
576
  pass
569
577
 
@@ -572,7 +580,11 @@ class wxMeerK40t(wx.App, Module):
572
580
  if self.context is not None:
573
581
  channel = self.context.kernel.channel("console")
574
582
  for filename in filenames:
575
- self.context.elements.load(os.path.realpath(filename), svg_ppi=self.context.elements.svg_ppi, channel=channel)
583
+ self.context.elements.load(
584
+ os.path.realpath(filename),
585
+ svg_ppi=self.context.elements.svg_ppi,
586
+ channel=channel,
587
+ )
576
588
  except AttributeError:
577
589
  pass
578
590
 
@@ -814,21 +826,35 @@ class wxMeerK40t(wx.App, Module):
814
826
  context.disable_tool_tips = True
815
827
  wx.ToolTip.Enable(not context.disable_tool_tips)
816
828
 
817
- @kernel.console_argument("func", type=str, help=_("Function to call interactively"))
818
- @kernel.console_command("gui", help=_("Provides a GUI wrapper around a console command"))
829
+ @kernel.console_argument(
830
+ "func", type=str, help=_("Function to call interactively")
831
+ )
832
+ @kernel.console_command(
833
+ "gui", help=_("Provides a GUI wrapper around a console command")
834
+ )
819
835
  def gui_func(command, channel, _, func=None, **kwargs):
820
836
  if func is None:
821
837
  channel(_("You need to provide a function name"))
822
838
  return
823
839
  if func in ("gui", "help", "?", "??", "quit", "shutdown", "exit"):
824
- channel (_("It does not make sense, to run '{command}' in a GUI").format(command=func))
840
+ channel(
841
+ _("It does not make sense, to run '{command}' in a GUI").format(
842
+ command=func
843
+ )
844
+ )
825
845
  return
826
846
  context = kernel.root
827
847
  try:
828
848
  parent = context.gui
829
849
  except AttributeError:
830
850
  parent = None
831
- dialog: wx.Dialog = ConsoleCommandUI(parent, wx.ID_ANY, title=_("Command {command}").format(command=func), context=context, command_string=func)
851
+ dialog: wx.Dialog = ConsoleCommandUI(
852
+ parent,
853
+ wx.ID_ANY,
854
+ title=_("Command {command}").format(command=func),
855
+ context=context,
856
+ command_string=func,
857
+ )
832
858
  res = dialog.ShowModal()
833
859
  if res == wx.ID_OK:
834
860
  dialog.accept_it()
@@ -859,7 +885,6 @@ class wxMeerK40t(wx.App, Module):
859
885
  channel(f"spx (screen) : {valuex.spx}")
860
886
  channel(f"inch : {valuex.inches}")
861
887
  channel(f"Device units : {float(valuex) / device.view.native_scale_x:.4f}")
862
-
863
888
 
864
889
  def module_open(self, *args, **kwargs):
865
890
  context = self.context
@@ -958,9 +983,7 @@ class wxMeerK40t(wx.App, Module):
958
983
  kernel.register(
959
984
  "property/ImageNode/ImageVectorisation", ImageVectorisationPanel
960
985
  )
961
- kernel.register(
962
- "property/ImageNode/ImageContour", ContourPanel
963
- )
986
+ kernel.register("property/ImageNode/ImageContour", ContourPanel)
964
987
 
965
988
  kernel.register("window/Console", Console)
966
989
  if (
@@ -1064,6 +1087,7 @@ class wxMeerK40t(wx.App, Module):
1064
1087
  register_panel_crash,
1065
1088
  register_panel_debugger,
1066
1089
  register_panel_icon,
1090
+ register_panel_plotter,
1067
1091
  register_panel_window,
1068
1092
  )
1069
1093
 
@@ -1072,6 +1096,7 @@ class wxMeerK40t(wx.App, Module):
1072
1096
  kernel.register("wxpane/debug_icons", register_panel_icon)
1073
1097
  kernel.register("wxpane/debug_shutdown", register_panel_crash)
1074
1098
  kernel.register("wxpane/debug_window", register_panel_window)
1099
+ kernel.register("wxpane/debug_plotter", register_panel_plotter)
1075
1100
 
1076
1101
  from meerk40t.gui.utilitywidgets.debugwidgets import register_widget_icon
1077
1102
 
@@ -1084,7 +1109,9 @@ class wxMeerK40t(wx.App, Module):
1084
1109
  wildcard = f"System-Sounds|*.aiff|{wildcard}"
1085
1110
  elif OS_NAME == "Linux":
1086
1111
  wildcard = f"System-Sounds|*.oga;*.wav;*.mp3|{wildcard}"
1087
- addon = "\n" + _("This uses the 'play' command that comes with the sox package,\nso you might need to install it with 'sudo apt install sox' first.")
1112
+ addon = "\n" + _(
1113
+ "This uses the 'play' command that comes with the sox package,\nso you might need to install it with 'sudo apt install sox' first."
1114
+ )
1088
1115
  system_sound = {
1089
1116
  "Windows": r"c:\Windows\Media\Alarm01.wav",
1090
1117
  "Darwin": "/System/Library/Sounds/Ping.aiff",
@@ -1110,9 +1137,12 @@ class wxMeerK40t(wx.App, Module):
1110
1137
  "style": "file",
1111
1138
  "wildcard": wildcard,
1112
1139
  "label": _("Soundfile"),
1113
- "tip": _("Define the soundfile MeerK40t will play when the 'beep' command is issued") + addon,
1140
+ "tip": _(
1141
+ "Define the soundfile MeerK40t will play when the 'beep' command is issued"
1142
+ )
1143
+ + addon,
1114
1144
  "page": "Start",
1115
- }
1145
+ },
1116
1146
  ]
1117
1147
  kernel.register_choices("preferences", choices)
1118
1148
 
meerk40t/gui/wxmmain.py CHANGED
@@ -1241,6 +1241,20 @@ class MeerK40t(MWindow):
1241
1241
  "page": "Scene",
1242
1242
  "section": "General",
1243
1243
  },
1244
+ {
1245
+ "attr": "file_selection",
1246
+ "object": context.root,
1247
+ "default": True,
1248
+ "type": bool,
1249
+ "label": _("Treat file selection as group selection"),
1250
+ "tip": _(
1251
+ "Active: Single click within the boundaries of the contained elements of a filenode selects all elements within the file"
1252
+ )
1253
+ + "\n"
1254
+ + _("Inactive: filenodes will not be used for selection"),
1255
+ "page": "Scene",
1256
+ "section": "General",
1257
+ },
1244
1258
  ]
1245
1259
  context.kernel.register_choices("preferences", choices)
1246
1260
 
@@ -3002,7 +3016,7 @@ class MeerK40t(MWindow):
3002
3016
 
3003
3017
  @context.console_command("dialog_gear", hidden=True)
3004
3018
  def gear(**kwargs):
3005
- dlg = wx.TextEntryDialog(gui, _("Enter Forced Gear"), _("Gear Entry"), "")
3019
+ dlg = wx.TextEntryDialog(gui, _("Enter Forced Gear"), _("Gear Entry"), "0")
3006
3020
  dlg.SetValue("")
3007
3021
 
3008
3022
  if dlg.ShowModal() == wx.ID_OK:
@@ -3545,6 +3559,7 @@ class MeerK40t(MWindow):
3545
3559
  if hasattr(context.kernel.busyinfo, "reparent"):
3546
3560
  context.kernel.busyinfo.reparent(self)
3547
3561
 
3562
+ @signal_listener("pane")
3548
3563
  @lookup_listener("pane")
3549
3564
  def dynamic_fill_pane_menu(self, new=None, old=None):
3550
3565
  def toggle_pane(pane_toggle):
@@ -3620,15 +3635,14 @@ class MeerK40t(MWindow):
3620
3635
  pane_name = pane.name
3621
3636
  except AttributeError:
3622
3637
  pane_name = suffix_path
3623
-
3624
- pane_caption = pane_name[0].upper() + pane_name[1:] + "."
3625
- try:
3638
+ pane_caption = ""
3639
+ src = "default"
3640
+ if hasattr(pane, "control") and hasattr(pane.control, "caption"):
3641
+ pane_caption = pane.control.caption
3642
+ elif hasattr(pane, "caption"):
3626
3643
  pane_caption = pane.caption
3627
- except AttributeError:
3628
- pass
3629
3644
  if not pane_caption:
3630
3645
  pane_caption = pane_name[0].upper() + pane_name[1:] + "."
3631
-
3632
3646
  menu_item = menu_context.Append(wx.ID_ANY, pane_caption, "", wx.ITEM_CHECK)
3633
3647
  menu_item.SetHelp(helptext)
3634
3648
  self.Bind(
@@ -5611,7 +5625,7 @@ class MeerK40t(MWindow):
5611
5625
  Zoom scene to bed size.
5612
5626
  """
5613
5627
  zoom = self.context.zoom_margin
5614
- self.context(f"scene focus -a {-zoom}% {-zoom}% {zoom+100}% {zoom+100}%\n")
5628
+ self.context(f"scene focus -a {-zoom}% {-zoom}% {zoom + 100}% {zoom + 100}%\n")
5615
5629
 
5616
5630
  def update_statusbar(self, text):
5617
5631
  self.main_statusbar.SetStatusText(text, 0)
@@ -5701,7 +5715,7 @@ class MeerK40t(MWindow):
5701
5715
  return
5702
5716
  helptext = menuitem.GetHelp()
5703
5717
  if not helptext:
5704
- helptext = f'{menuitem.GetItemLabelText()} ({_("No help text")})'
5718
+ helptext = f"{menuitem.GetItemLabelText()} ({_('No help text')})"
5705
5719
  self.update_statusbar(helptext)
5706
5720
  except RuntimeError:
5707
5721
  pass
meerk40t/gui/wxmribbon.py CHANGED
@@ -678,6 +678,42 @@ class MKRibbonBarPanel(RibbonBarPanel):
678
678
  self.apply_enable_rules()
679
679
  self.redrawn()
680
680
 
681
+ @signal_listener("icon;label")
682
+ def on_label_update(self, origin, node=None, *args):
683
+ """
684
+ Signal to update the icon or label of a button.
685
+ This is used to update the icon or label of a button when it changes.
686
+ """
687
+ if node is None or len(args) == 0:
688
+ return
689
+ if not isinstance(node, (list, tuple)):
690
+ node = [node]
691
+ newlabel = None
692
+ newtooltip = None
693
+ if isinstance(args[0], (list, tuple)):
694
+ newlabel = args[0][0] if len(args[0]) > 0 else None
695
+ newtooltip = args[0][1] if len(args[0]) > 1 else None
696
+ else:
697
+ newlabel = args[0] # First argument is the new label
698
+ if newlabel is None and newtooltip is None:
699
+ return
700
+ for page in self.pages:
701
+ for panel in page.panels:
702
+ for button in panel.buttons:
703
+ if button.identifier in node:
704
+ button.label = newlabel if newlabel is not None else button.label
705
+ button.tip = (
706
+ newtooltip if newtooltip is not None else button.tip
707
+ )
708
+ if "multi" in button.button_dict:
709
+ for subbutton in button.button_dict["multi"]:
710
+ if subbutton["identifier"] in node:
711
+ if newlabel is not None:
712
+ subbutton["label"] = newlabel
713
+ if newtooltip is not None:
714
+ subbutton["tip"] = newtooltip
715
+ self.redrawn()
716
+
681
717
  @signal_listener("tool_changed")
682
718
  def on_tool_changed(self, origin, newtool=None, *args):
683
719
  # Signal provides a tuple with (togglegroup, id)