meerk40t 0.9.7040__py2.py3-none-any.whl → 0.9.7050__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.
- meerk40t/balormk/controller.py +10 -2
- meerk40t/core/cutplan.py +1 -36
- meerk40t/core/elements/shapes.py +7 -40
- meerk40t/core/node/blobnode.py +19 -4
- meerk40t/core/planner.py +25 -11
- meerk40t/grbl/device.py +15 -1
- meerk40t/grbl/driver.py +15 -5
- meerk40t/gui/laserpanel.py +19 -0
- meerk40t/gui/materialtest.py +474 -405
- meerk40t/gui/propertypanels/wobbleproperty.py +6 -2
- meerk40t/gui/spoolerpanel.py +27 -7
- meerk40t/gui/wxutils.py +226 -0
- meerk40t/kernel/kernel.py +28 -0
- meerk40t/main.py +14 -9
- meerk40t/ruida/loader.py +3 -1
- meerk40t/ruida/rdjob.py +48 -8
- meerk40t/tools/geomstr.py +93 -44
- meerk40t/tools/rasterplotter.py +6 -1
- {meerk40t-0.9.7040.dist-info → meerk40t-0.9.7050.dist-info}/METADATA +1 -1
- {meerk40t-0.9.7040.dist-info → meerk40t-0.9.7050.dist-info}/RECORD +25 -25
- {meerk40t-0.9.7040.dist-info → meerk40t-0.9.7050.dist-info}/LICENSE +0 -0
- {meerk40t-0.9.7040.dist-info → meerk40t-0.9.7050.dist-info}/WHEEL +0 -0
- {meerk40t-0.9.7040.dist-info → meerk40t-0.9.7050.dist-info}/entry_points.txt +0 -0
- {meerk40t-0.9.7040.dist-info → meerk40t-0.9.7050.dist-info}/top_level.txt +0 -0
- {meerk40t-0.9.7040.dist-info → meerk40t-0.9.7050.dist-info}/zip-safe +0 -0
@@ -4,12 +4,14 @@ from meerk40t.gui.wxutils import ScrolledPanel, StaticBoxSizer
|
|
4
4
|
|
5
5
|
from ...core.units import Length
|
6
6
|
from ..wxutils import TextCtrl, set_ctrl_value, wxCheckBox, wxComboBox
|
7
|
-
from .attributes import ColorPanel, IdPanel
|
7
|
+
from .attributes import AutoHidePanel, ColorPanel, IdPanel
|
8
8
|
|
9
9
|
_ = wx.GetTranslation
|
10
10
|
|
11
11
|
|
12
12
|
class WobblePropertyPanel(ScrolledPanel):
|
13
|
+
name = _("Wobble")
|
14
|
+
|
13
15
|
def __init__(self, *args, context=None, node=None, **kwds):
|
14
16
|
# super().__init__(parent)
|
15
17
|
kwds["style"] = kwds.get("style", 0) | wx.TAB_TRAVERSAL
|
@@ -62,7 +64,9 @@ class WobblePropertyPanel(ScrolledPanel):
|
|
62
64
|
main_sizer.Add(panel_id, 1, wx.EXPAND, 0)
|
63
65
|
self.panels.append(panel_id)
|
64
66
|
|
65
|
-
panel_hide = AutoHidePanel(
|
67
|
+
panel_hide = AutoHidePanel(
|
68
|
+
self, id=wx.ID_ANY, context=self.context, node=self.node
|
69
|
+
)
|
66
70
|
main_sizer.Add(panel_hide, 1, wx.EXPAND, 0)
|
67
71
|
self.panels.append(panel_hide)
|
68
72
|
|
meerk40t/gui/spoolerpanel.py
CHANGED
@@ -103,6 +103,8 @@ class SpoolerPanel(wx.Panel):
|
|
103
103
|
self.context.setting(int, "spooler_sash_position", 0)
|
104
104
|
self.context.setting(bool, "spool_history_clear_on_start", False)
|
105
105
|
self.context.setting(bool, "spool_ignore_helper_jobs", True)
|
106
|
+
self.context.setting(bool, "silent_mode", False)
|
107
|
+
self.context(f".silent {'on' if self.context.silent_mode else 'off'}\n")
|
106
108
|
|
107
109
|
self.splitter = wx.SplitterWindow(self, id=wx.ID_ANY, style=wx.SP_LIVE_UPDATE)
|
108
110
|
sty = wx.BORDER_SUNKEN
|
@@ -131,11 +133,20 @@ class SpoolerPanel(wx.Panel):
|
|
131
133
|
)
|
132
134
|
)
|
133
135
|
self.button_stop.SetBitmapFocus(
|
134
|
-
icons8_emergency_stop_button.GetBitmap(
|
136
|
+
icons8_emergency_stop_button.GetBitmap(
|
137
|
+
resize=0.5 * get_default_icon_size(self.context)
|
138
|
+
)
|
135
139
|
)
|
136
140
|
self.button_stop.SetBackgroundColour(self.context.themes.get("stop_bg"))
|
137
141
|
self.button_stop.SetForegroundColour(self.context.themes.get("stop_fg"))
|
138
142
|
self.button_stop.SetFocusColour(self.context.themes.get("stop_fg_focus"))
|
143
|
+
self.check_silent = wx.CheckBox(self.win_top, wx.ID_ANY)
|
144
|
+
self.check_silent.SetValue(self.context.silent_mode)
|
145
|
+
self.check_silent.SetToolTip(
|
146
|
+
_(
|
147
|
+
"If checked, the spooler will not emit any sound signals while processing jobs"
|
148
|
+
)
|
149
|
+
)
|
139
150
|
|
140
151
|
self.list_job_spool = wxListCtrl(
|
141
152
|
self.win_top,
|
@@ -145,9 +156,7 @@ class SpoolerPanel(wx.Panel):
|
|
145
156
|
list_name="list_spoolerjobs",
|
146
157
|
)
|
147
158
|
|
148
|
-
self.info_label = wxStaticText(
|
149
|
-
self.win_bottom, wx.ID_ANY, _("Completed jobs:")
|
150
|
-
)
|
159
|
+
self.info_label = wxStaticText(self.win_bottom, wx.ID_ANY, _("Completed jobs:"))
|
151
160
|
self.button_clear_history = wxButton(
|
152
161
|
self.win_bottom, wx.ID_ANY, _("Clear History")
|
153
162
|
)
|
@@ -184,7 +193,7 @@ class SpoolerPanel(wx.Panel):
|
|
184
193
|
self.Bind(
|
185
194
|
wx.EVT_LIST_ITEM_RIGHT_CLICK, self.on_item_rightclick, self.list_job_spool
|
186
195
|
)
|
187
|
-
|
196
|
+
self.Bind(wx.EVT_CHECKBOX, self.on_check_silent, self.check_silent)
|
188
197
|
self._last_invokation = 0
|
189
198
|
self.dirty = False
|
190
199
|
self.update_buffer_size = False
|
@@ -298,6 +307,7 @@ class SpoolerPanel(wx.Panel):
|
|
298
307
|
sizer_combo_cmds.Add(self.combo_device, 1, wx.ALIGN_CENTER_VERTICAL, 0)
|
299
308
|
sizer_combo_cmds.Add(self.button_pause, 0, wx.EXPAND, 0)
|
300
309
|
sizer_combo_cmds.Add(self.button_stop, 0, wx.EXPAND, 0)
|
310
|
+
sizer_combo_cmds.Add(self.check_silent, 0, wx.ALIGN_CENTER_VERTICAL, 0)
|
301
311
|
|
302
312
|
sizer_top.Add(sizer_combo_cmds, 0, wx.EXPAND, 0)
|
303
313
|
sizer_top.Add(self.list_job_spool, 4, wx.EXPAND, 0)
|
@@ -318,6 +328,10 @@ class SpoolerPanel(wx.Panel):
|
|
318
328
|
self.Layout()
|
319
329
|
# end wxGlade
|
320
330
|
|
331
|
+
def on_check_silent(self, event):
|
332
|
+
self.context.silent_mode = self.check_silent.GetValue()
|
333
|
+
self.context(f".silent {'on' if self.context.silent_mode else 'off'}\n")
|
334
|
+
|
321
335
|
def on_sash_changed(self, event):
|
322
336
|
position = self.splitter.GetSashPosition()
|
323
337
|
self.context.spooler_sash_position = position
|
@@ -760,7 +774,10 @@ class SpoolerPanel(wx.Panel):
|
|
760
774
|
info_s = f"{spool_obj.steps_done}/{spool_obj.steps_total}"
|
761
775
|
if hasattr(spooler, "driver"):
|
762
776
|
if hasattr(spooler.driver, "get_internal_queue_status"):
|
763
|
-
|
777
|
+
(
|
778
|
+
internal_current,
|
779
|
+
internal_total,
|
780
|
+
) = spooler.driver.get_internal_queue_status()
|
764
781
|
if internal_current != 0:
|
765
782
|
info_s += f" ({internal_current}/{internal_total})"
|
766
783
|
except AttributeError:
|
@@ -1113,7 +1130,10 @@ class SpoolerPanel(wx.Panel):
|
|
1113
1130
|
info_s = f"{spool_obj.steps_done}/{spool_obj.steps_total}"
|
1114
1131
|
if hasattr(spooler, "driver"):
|
1115
1132
|
if hasattr(spooler.driver, "get_internal_queue_status"):
|
1116
|
-
|
1133
|
+
(
|
1134
|
+
internal_current,
|
1135
|
+
internal_total,
|
1136
|
+
) = spooler.driver.get_internal_queue_status()
|
1117
1137
|
if internal_current != 0:
|
1118
1138
|
info_s += f" ({internal_current}/{internal_total})"
|
1119
1139
|
except AttributeError:
|
meerk40t/gui/wxutils.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
"""
|
2
2
|
Mixin functions for wxMeerk40t
|
3
3
|
"""
|
4
|
+
|
4
5
|
import platform
|
5
6
|
from typing import List
|
6
7
|
|
@@ -1250,6 +1251,9 @@ class StaticBoxSizer(wx.StaticBoxSizer):
|
|
1250
1251
|
def SetLabel(self, label):
|
1251
1252
|
self.sbox.SetLabel(label)
|
1252
1253
|
|
1254
|
+
def GetLabel(self):
|
1255
|
+
return self.sbox.GetLabel()
|
1256
|
+
|
1253
1257
|
def Refresh(self, *args):
|
1254
1258
|
self.sbox.Refresh(*args)
|
1255
1259
|
|
@@ -1582,6 +1586,7 @@ class wxRadioBox(StaticBoxSizer):
|
|
1582
1586
|
def Show(self, flag):
|
1583
1587
|
for ctrl in self._children + self._labels:
|
1584
1588
|
ctrl.Show(flag)
|
1589
|
+
super().Show(flag)
|
1585
1590
|
|
1586
1591
|
def Bind(self, event_type, routine):
|
1587
1592
|
self.parent.Bind(event_type, routine, self)
|
@@ -1622,6 +1627,227 @@ class wxListBox(wx.ListBox):
|
|
1622
1627
|
set_color_according_to_theme(self, "list_bg", "list_fg")
|
1623
1628
|
|
1624
1629
|
|
1630
|
+
class wxCheckListBox(StaticBoxSizer):
|
1631
|
+
"""
|
1632
|
+
This class recreates the functionality of a wx.CheckListBox, as this class has issues to properly refresh in nested sizers
|
1633
|
+
|
1634
|
+
Known Limitations:
|
1635
|
+
- This custom implementation may not fully replicate all native wx.CheckListBox behaviors.
|
1636
|
+
- Keyboard navigation (e.g., arrow keys, space/enter to toggle) may not work as expected.
|
1637
|
+
- Accessibility features such as screen reader support may be limited or unavailable.
|
1638
|
+
- If your application requires full accessibility or native keyboard handling, consider using the native wx.CheckListBox where possible.
|
1639
|
+
"""
|
1640
|
+
|
1641
|
+
def __init__(
|
1642
|
+
self,
|
1643
|
+
parent=None,
|
1644
|
+
id=None,
|
1645
|
+
label=None,
|
1646
|
+
choices=None,
|
1647
|
+
majorDimension=0,
|
1648
|
+
style=0,
|
1649
|
+
*args,
|
1650
|
+
**kwargs,
|
1651
|
+
):
|
1652
|
+
self.parent = parent
|
1653
|
+
self.choices = choices
|
1654
|
+
self._children = []
|
1655
|
+
self._tool_tip = None
|
1656
|
+
self._help = None
|
1657
|
+
super().__init__(
|
1658
|
+
parent=parent, id=wx.ID_ANY, label=label, orientation=wx.VERTICAL
|
1659
|
+
)
|
1660
|
+
self.majorDimension = majorDimension
|
1661
|
+
self.style = style
|
1662
|
+
self._build_controls()
|
1663
|
+
|
1664
|
+
def _build_controls(self):
|
1665
|
+
"""
|
1666
|
+
Build the controls for the CheckListBox.
|
1667
|
+
This method is called during initialization to create the checkboxes.
|
1668
|
+
"""
|
1669
|
+
if self.choices is None:
|
1670
|
+
self.choices = []
|
1671
|
+
if self.majorDimension == 0 or self.style == wx.RA_SPECIFY_ROWS:
|
1672
|
+
self.majorDimension = 1000
|
1673
|
+
container = None
|
1674
|
+
for idx, c in enumerate(self.choices):
|
1675
|
+
if idx % self.majorDimension == 0:
|
1676
|
+
container = wx.BoxSizer(wx.HORIZONTAL)
|
1677
|
+
self.Add(container, 0, wx.EXPAND, 0)
|
1678
|
+
check_option = wx.CheckBox(self.parent, wx.ID_ANY, label=c)
|
1679
|
+
container.Add(check_option, 1, wx.ALIGN_CENTER_VERTICAL, 0)
|
1680
|
+
self._children.append(check_option)
|
1681
|
+
|
1682
|
+
if platform.system() == "Linux":
|
1683
|
+
|
1684
|
+
def on_mouse_over_check(ctrl):
|
1685
|
+
def mouse(event=None):
|
1686
|
+
ctrl.SetToolTip(self._tool_tip)
|
1687
|
+
event.Skip()
|
1688
|
+
|
1689
|
+
return mouse
|
1690
|
+
|
1691
|
+
for ctrl in self._children:
|
1692
|
+
ctrl.Bind(wx.EVT_MOTION, on_mouse_over_check(ctrl))
|
1693
|
+
|
1694
|
+
for ctrl in self._children:
|
1695
|
+
ctrl.Bind(wx.EVT_CHECKBOX, self.on_check)
|
1696
|
+
ctrl.Bind(wx.EVT_RIGHT_DOWN, self.on_right_click)
|
1697
|
+
|
1698
|
+
for ctrl in self._children:
|
1699
|
+
set_color_according_to_theme(ctrl, "text_bg", "text_fg")
|
1700
|
+
|
1701
|
+
@property
|
1702
|
+
def Children(self):
|
1703
|
+
return self._children
|
1704
|
+
|
1705
|
+
def GetParent(self):
|
1706
|
+
return self.parent
|
1707
|
+
|
1708
|
+
def SetToolTip(self, tooltip):
|
1709
|
+
self._tool_tip = tooltip
|
1710
|
+
for ctrl in self._children:
|
1711
|
+
ctrl.SetToolTip(self._tool_tip)
|
1712
|
+
|
1713
|
+
def Disable(self):
|
1714
|
+
self.Enable(False)
|
1715
|
+
|
1716
|
+
def EnableItem(self, n, flag):
|
1717
|
+
if 0 <= n < len(self._children):
|
1718
|
+
self._children[n].Enable(flag)
|
1719
|
+
|
1720
|
+
def Enable(self, flag):
|
1721
|
+
for ctrl in self._children:
|
1722
|
+
ctrl.Enable(flag)
|
1723
|
+
|
1724
|
+
def Hide(self):
|
1725
|
+
self.Show(False)
|
1726
|
+
|
1727
|
+
def Show(self, flag):
|
1728
|
+
for ctrl in self._children:
|
1729
|
+
ctrl.Show(flag)
|
1730
|
+
self.ShowItems(flag)
|
1731
|
+
|
1732
|
+
# def Bind(self, event_type, routine):
|
1733
|
+
# self.parent.Bind(event_type, routine, self)
|
1734
|
+
|
1735
|
+
def on_check(self, orgevent):
|
1736
|
+
#
|
1737
|
+
event = orgevent.Clone()
|
1738
|
+
event.SetEventType(wx.wxEVT_CHECKLISTBOX)
|
1739
|
+
event.SetId(self.Id)
|
1740
|
+
event.SetEventObject(self)
|
1741
|
+
# event.Int = self.GetSelection()
|
1742
|
+
wx.PostEvent(self.parent, event)
|
1743
|
+
|
1744
|
+
def on_right_click(self, event):
|
1745
|
+
menu = wx.Menu()
|
1746
|
+
parent = self.parent
|
1747
|
+
item = menu.Append(wx.ID_ANY, _("Check all"), "")
|
1748
|
+
parent.Bind(
|
1749
|
+
wx.EVT_MENU,
|
1750
|
+
lambda e: self.SetCheckedItems(range(len(self._children))),
|
1751
|
+
id=item.GetId(),
|
1752
|
+
)
|
1753
|
+
item = menu.Append(wx.ID_ANY, _("Uncheck all"), "")
|
1754
|
+
parent.Bind(wx.EVT_MENU, lambda e: self.SetCheckedItems([]), id=item.GetId())
|
1755
|
+
item = menu.Append(wx.ID_ANY, _("Invert selection"), "")
|
1756
|
+
parent.Bind(
|
1757
|
+
wx.EVT_MENU,
|
1758
|
+
lambda e: self.SetCheckedItems(
|
1759
|
+
[
|
1760
|
+
i
|
1761
|
+
for i in range(len(self._children))
|
1762
|
+
if not self._children[i].GetValue()
|
1763
|
+
]
|
1764
|
+
),
|
1765
|
+
id=item.GetId(),
|
1766
|
+
)
|
1767
|
+
parent.PopupMenu(menu)
|
1768
|
+
menu.Destroy()
|
1769
|
+
|
1770
|
+
def SetForegroundColour(self, wc):
|
1771
|
+
for ctrl in self._children:
|
1772
|
+
ctrl.SetForegroundColour(wc)
|
1773
|
+
|
1774
|
+
def SetBackgroundColour(self, wc):
|
1775
|
+
for ctrl in self._children:
|
1776
|
+
ctrl.SetBackgroundColour(wc)
|
1777
|
+
|
1778
|
+
def SetHelpText(self, help):
|
1779
|
+
self._help = help
|
1780
|
+
|
1781
|
+
def GetHelpText(self):
|
1782
|
+
return self._help
|
1783
|
+
|
1784
|
+
def Clear(self) -> None:
|
1785
|
+
with wx.BusyCursor():
|
1786
|
+
for child in self._children:
|
1787
|
+
child.Destroy()
|
1788
|
+
self._children.clear()
|
1789
|
+
self.choices.clear()
|
1790
|
+
|
1791
|
+
def Check(self, item: int, check: bool = True) -> None:
|
1792
|
+
"""
|
1793
|
+
Check or uncheck an item in the CheckListBox.
|
1794
|
+
:param item: The index of the item to check or uncheck.
|
1795
|
+
:param check: True to check, False to uncheck.
|
1796
|
+
"""
|
1797
|
+
if 0 <= item < len(self._children):
|
1798
|
+
self._children[item].SetValue(check)
|
1799
|
+
|
1800
|
+
def GetCheckItems(self) -> list:
|
1801
|
+
"""
|
1802
|
+
Get a list of indices of checked items in the CheckListBox.
|
1803
|
+
:return: A list of indices of checked items.
|
1804
|
+
"""
|
1805
|
+
return [idx for idx, ctrl in enumerate(self._children) if ctrl.GetValue()]
|
1806
|
+
|
1807
|
+
def GetCheckedStrings(self) -> list:
|
1808
|
+
"""
|
1809
|
+
Get a list of strings of checked items in the CheckListBox.
|
1810
|
+
:return: A list of strings of checked items.
|
1811
|
+
"""
|
1812
|
+
return [self.choices[idx] for idx in self.GetCheckItems()]
|
1813
|
+
|
1814
|
+
def GetSelections(self) -> list:
|
1815
|
+
"""
|
1816
|
+
Get a list of indices of selected items in the CheckListBox.
|
1817
|
+
:return: A list of indices of selected items.
|
1818
|
+
"""
|
1819
|
+
return self.GetCheckItems()
|
1820
|
+
|
1821
|
+
def SetCheckedStrings(self, choices):
|
1822
|
+
"""
|
1823
|
+
Set the checked items in the CheckListBox based on a list of strings.
|
1824
|
+
:param choices: A list of strings to check.
|
1825
|
+
"""
|
1826
|
+
for idx, choice in enumerate(self.choices):
|
1827
|
+
if choice in choices:
|
1828
|
+
self.Check(idx, True)
|
1829
|
+
else:
|
1830
|
+
self.Check(idx, False)
|
1831
|
+
|
1832
|
+
def SetCheckedItems(self, choices):
|
1833
|
+
"""
|
1834
|
+
Set the checked items in the CheckListBox based on a list of indices.
|
1835
|
+
:param choices: A list of indices to check.
|
1836
|
+
"""
|
1837
|
+
for idx in range(len(self._children)):
|
1838
|
+
self.Check(idx, idx in choices)
|
1839
|
+
|
1840
|
+
def Set(self, choices):
|
1841
|
+
"""
|
1842
|
+
Set the choices for the CheckListBox.
|
1843
|
+
:param choices: A list of strings to set as choices.
|
1844
|
+
"""
|
1845
|
+
# print (f"Setting choices for {self.GetLabel()}: {choices}")
|
1846
|
+
self.Clear()
|
1847
|
+
self.choices = list(choices)
|
1848
|
+
self._build_controls()
|
1849
|
+
|
1850
|
+
|
1625
1851
|
##############
|
1626
1852
|
# GUI KEYSTROKE FUNCTIONS
|
1627
1853
|
##############
|
meerk40t/kernel/kernel.py
CHANGED
@@ -182,6 +182,7 @@ class Kernel(Settings):
|
|
182
182
|
|
183
183
|
self.os_information = self._get_environment()
|
184
184
|
self.show_aio_prompt = True
|
185
|
+
self.silent_mode = False
|
185
186
|
|
186
187
|
def __str__(self):
|
187
188
|
return f"Kernel({self.name}, {self.profile}, {self.version})"
|
@@ -2865,8 +2866,35 @@ class Kernel(Settings):
|
|
2865
2866
|
_("App: {name} {version}.").format(name=self.name, version=self.version)
|
2866
2867
|
)
|
2867
2868
|
|
2869
|
+
@self.console_command("silent", _("Set/unset silent mode"))
|
2870
|
+
def set_silent(channel, _, remainder=None, **kwargs):
|
2871
|
+
"""
|
2872
|
+
Set or unset silent mode. In silent mode no beeps will be played.
|
2873
|
+
"""
|
2874
|
+
if remainder is None:
|
2875
|
+
channel(
|
2876
|
+
_("Silent mode is currently {mode}.").format(
|
2877
|
+
mode="ON" if self.silent_mode else "OFF"
|
2878
|
+
)
|
2879
|
+
)
|
2880
|
+
return
|
2881
|
+
if remainder.lower() not in ("on", "off"):
|
2882
|
+
channel(_("Please specify 'on' or 'off' to set silent mode."))
|
2883
|
+
return
|
2884
|
+
if remainder.lower() == "on":
|
2885
|
+
self.silent_mode = True
|
2886
|
+
else:
|
2887
|
+
self.silent_mode = False
|
2888
|
+
if self.silent_mode:
|
2889
|
+
channel(_("Silent mode is now ON."))
|
2890
|
+
else:
|
2891
|
+
channel(_("Silent mode is now OFF."))
|
2892
|
+
|
2868
2893
|
@self.console_command("beep", _("Perform beep"))
|
2869
2894
|
def beep(channel, _, **kwargs):
|
2895
|
+
if self.silent_mode:
|
2896
|
+
channel(_("Silent mode is on, no beep will be played."))
|
2897
|
+
return
|
2870
2898
|
OS_NAME = self.os_information["OS_NAME"]
|
2871
2899
|
system_sound = {
|
2872
2900
|
"Windows": r"c:\Windows\Media\Sounds\Alarm01.wav",
|
meerk40t/main.py
CHANGED
@@ -11,7 +11,7 @@ import os.path
|
|
11
11
|
import sys
|
12
12
|
|
13
13
|
APPLICATION_NAME = "MeerK40t"
|
14
|
-
APPLICATION_VERSION = "0.9.
|
14
|
+
APPLICATION_VERSION = "0.9.7050"
|
15
15
|
|
16
16
|
if not getattr(sys, "frozen", False):
|
17
17
|
# If .git directory does not exist we are running from a package like pypi
|
@@ -229,19 +229,24 @@ def _exe(restarted, args):
|
|
229
229
|
server_mode = False
|
230
230
|
if command:
|
231
231
|
for c in command:
|
232
|
-
server_mode = server_mode or any(
|
233
|
-
|
234
|
-
|
235
|
-
|
232
|
+
server_mode = server_mode or any(
|
233
|
+
substring in c
|
234
|
+
for substring in (
|
235
|
+
"lhyserver",
|
236
|
+
"grblserver",
|
237
|
+
"ruidacontrol",
|
238
|
+
"grblcontrol",
|
239
|
+
"webserver",
|
240
|
+
)
|
241
|
+
)
|
242
|
+
nogui = (hasattr(kernel.args, "gui_suppress") and kernel.args.gui_suppress) or (
|
243
|
+
hasattr(kernel.args, "no_gui") and kernel.args.no_gui
|
236
244
|
)
|
237
245
|
for idx, attrib in enumerate(("mktablength", "mktabpositions")):
|
238
246
|
kernel.register(f"registered_mk_svg_parameters/tabs{idx}", attrib)
|
239
247
|
|
240
248
|
require_partial_mode = False
|
241
|
-
if (
|
242
|
-
(not console or nogui) and
|
243
|
-
(auto or daemon or server_mode)
|
244
|
-
):
|
249
|
+
if (not console or nogui) and (auto or daemon or server_mode):
|
245
250
|
require_partial_mode = True
|
246
251
|
# print (f"Auto: {auto}, Command: {command}, Console: {console}, daemon: {daemon}, nogui:{nogui}, Server: {server_mode} -> {require_partial_mode}")
|
247
252
|
kernel(partial=require_partial_mode)
|
meerk40t/ruida/loader.py
CHANGED
@@ -15,9 +15,11 @@ def data_viewer(data, data_type):
|
|
15
15
|
|
16
16
|
if not data:
|
17
17
|
return ""
|
18
|
+
magic = determine_magic_via_histogram(data)
|
18
19
|
return BlobNode.hex_view(
|
19
|
-
data=decode_bytes(data,
|
20
|
+
data=decode_bytes(data, magic),
|
20
21
|
data_type=data_type,
|
22
|
+
info = f', Magic={magic} (0x{magic:02x})'
|
21
23
|
)
|
22
24
|
|
23
25
|
|
meerk40t/ruida/rdjob.py
CHANGED
@@ -256,6 +256,8 @@ def encode_relcoord(coord):
|
|
256
256
|
|
257
257
|
|
258
258
|
def encode_color(color):
|
259
|
+
# Scewed on RDC 22.01
|
260
|
+
# Maybe 16bit color is used?
|
259
261
|
return encode32(int(color))
|
260
262
|
|
261
263
|
|
@@ -488,6 +490,7 @@ class RDJob:
|
|
488
490
|
self._stopped = True
|
489
491
|
self.enabled = True
|
490
492
|
self._estimate = 0
|
493
|
+
self.offset = 0
|
491
494
|
|
492
495
|
self.scale = UNITS_PER_uM
|
493
496
|
|
@@ -598,7 +601,8 @@ class RDJob:
|
|
598
601
|
command = self.buffer.pop(0)
|
599
602
|
try:
|
600
603
|
array = list(command)
|
601
|
-
self.process(array)
|
604
|
+
self.process(array, offset=self.offset)
|
605
|
+
self.offset += len(command)
|
602
606
|
except IndexError as e:
|
603
607
|
raise RuidaCommandError(
|
604
608
|
f"Could not process Ruida buffer, {self.buffer[:25]} with magic: {self.magic:02}"
|
@@ -701,7 +705,7 @@ class RDJob:
|
|
701
705
|
def set_color(self, color):
|
702
706
|
self.color = color
|
703
707
|
|
704
|
-
def process(self, array):
|
708
|
+
def process(self, array, offset=None):
|
705
709
|
"""
|
706
710
|
Parses an individual unswizzled ruida command, updating the emulator state.
|
707
711
|
|
@@ -976,7 +980,7 @@ class RDJob:
|
|
976
980
|
b = (c >> 16) & 0xFF
|
977
981
|
c = Color(red=r, blue=b, green=g)
|
978
982
|
self.set_color(c.hex)
|
979
|
-
desc = f"{part},
|
983
|
+
desc = f"Color Part {part}, {self.color}"
|
980
984
|
elif array[1] == 0x10:
|
981
985
|
value = array[2]
|
982
986
|
desc = f"EnExIO Start {value}"
|
@@ -1012,12 +1016,44 @@ class RDJob:
|
|
1012
1016
|
elif array[0] == 0xD8:
|
1013
1017
|
if array[1] == 0x00:
|
1014
1018
|
desc = "Start Process"
|
1015
|
-
|
1019
|
+
elif array[1] == 0x10:
|
1016
1020
|
desc = "Ref Point Mode 2, Machine Zero/Absolute Position"
|
1017
|
-
|
1021
|
+
elif array[1] == 0x11:
|
1018
1022
|
desc = "Ref Point Mode 1, Anchor Point"
|
1019
|
-
|
1023
|
+
elif array[1] == 0x12:
|
1020
1024
|
desc = "Ref Point Mode 0, Current Position"
|
1025
|
+
elif array[0] == 0xD9:
|
1026
|
+
if array[1] == 0x00:
|
1027
|
+
opts = array[2]
|
1028
|
+
value = abscoord(array[3:8])
|
1029
|
+
desc = f"Rapid move X ({value}μm)"
|
1030
|
+
elif array[1] == 0x01:
|
1031
|
+
opts = array[2]
|
1032
|
+
value = abscoord(array[3:8])
|
1033
|
+
desc = f"Rapid move Y ({value}μm)"
|
1034
|
+
elif array[1] == 0x02:
|
1035
|
+
opts = array[2]
|
1036
|
+
value = abscoord(array[3:8])
|
1037
|
+
desc = f"Rapid move Z ({value}μm)"
|
1038
|
+
elif array[1] == 0x03:
|
1039
|
+
opts = array[2]
|
1040
|
+
value = abscoord(array[3:8])
|
1041
|
+
desc = f"Rapid move U ({value}μm)"
|
1042
|
+
elif array[1] == 0x0F:
|
1043
|
+
opts = array[2]
|
1044
|
+
value = abscoord(array[3:8])
|
1045
|
+
desc = f"Rapid move Feed ({value}μm)"
|
1046
|
+
elif array[1] == 0x10:
|
1047
|
+
opts = array[2]
|
1048
|
+
x = abscoord(array[3:8])
|
1049
|
+
y = abscoord(array[8:13])
|
1050
|
+
desc = f"Rapid move XY ({x}μm, {y}μm)"
|
1051
|
+
elif array[1] == 0x30:
|
1052
|
+
opts = array[2]
|
1053
|
+
x = abscoord(array[3:7])
|
1054
|
+
y = abscoord(array[8:13])
|
1055
|
+
u = abscoord(array[13:18])
|
1056
|
+
desc = f"Rapid move XYU ({x}μm, {y}μm, {u}μm)"
|
1021
1057
|
elif array[0] == 0xDA:
|
1022
1058
|
mem = parse_mem(array[2:4])
|
1023
1059
|
if array[1] == 0x01:
|
@@ -1240,7 +1276,8 @@ class RDJob:
|
|
1240
1276
|
else:
|
1241
1277
|
desc = "Unknown Command!"
|
1242
1278
|
if self.channel:
|
1243
|
-
|
1279
|
+
prefix = f"{offset:06x}" if offset is not None else ''
|
1280
|
+
self.channel(f"{prefix}-**-> {str(bytes(array).hex())}\t({desc})")
|
1244
1281
|
|
1245
1282
|
def unswizzle(self, data):
|
1246
1283
|
return bytes([self.lut_unswizzle[b] for b in data])
|
@@ -1325,6 +1362,9 @@ class RDJob:
|
|
1325
1362
|
color = current_settings.get("line_color", 0)
|
1326
1363
|
frequency = current_settings.get("frequency")
|
1327
1364
|
|
1365
|
+
if color == 0:
|
1366
|
+
color = current_settings.get("color", color)
|
1367
|
+
|
1328
1368
|
self.speed_laser_1_part(part, speed)
|
1329
1369
|
if frequency:
|
1330
1370
|
self.frequency_part(0, part, frequency)
|
@@ -1670,7 +1710,7 @@ class RDJob:
|
|
1670
1710
|
self(LAYER_COLOR, encode_color(color), output=output)
|
1671
1711
|
|
1672
1712
|
def layer_color_part(self, part, color, output=None):
|
1673
|
-
self(
|
1713
|
+
self(LAYER_COLOR_PART, encode_part(part), encode_color(color), output=output)
|
1674
1714
|
|
1675
1715
|
def en_ex_io(self, value, output=None):
|
1676
1716
|
"""
|