Explorar el Código

- in CNCJob UI Autolevelling - autolevelling is made to be not available for cnc code generated with Roland or HPGL preprocessors
- in CNCJob UI Autolevelling - added a save dialog for the probing GCode
- added a new GUI element, a DoubleSlider
- in CNCJob UI Autolevelling - GRBL controller - Control: trying to add DoubleSlider + DoubleSpinner combo controls

Marius Stanciu hace 5 años
padre
commit
26ac43bd2e
Se han modificado 4 ficheros con 184 adiciones y 28 borrados
  1. 7 0
      CHANGELOG.md
  2. 116 1
      appGUI/GUIElements.py
  3. 2 2
      appGUI/ObjectUI.py
  4. 59 25
      appObjects/FlatCAMCNCJob.py

+ 7 - 0
CHANGELOG.md

@@ -7,6 +7,13 @@ CHANGELOG for FlatCAM beta
 
 =================================================
 
+23.08.2020
+
+- in CNCJob UI Autolevelling - autolevelling is made to be not available for cnc code generated with Roland or HPGL preprocessors
+- in CNCJob UI Autolevelling - added a save dialog for the probing GCode
+- added a new GUI element, a DoubleSlider
+- in CNCJob UI Autolevelling - GRBL controller - Control: trying to add DoubleSlider + DoubleSpinner combo controls
+
 21.08.2020
 
 - in CNCJob UI Autolevelling - GRBL controller - Control: added a Origin button; changed the UI to have rounded rectangles 

+ 116 - 1
appGUI/GUIElements.py

@@ -12,7 +12,7 @@
 # ##########################################################
 
 from PyQt5 import QtGui, QtCore, QtWidgets
-from PyQt5.QtCore import Qt, pyqtSlot, QSettings
+from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal, QSettings
 from PyQt5.QtWidgets import QTextEdit, QCompleter, QAction
 from PyQt5.QtGui import QKeySequence, QTextCursor
 
@@ -923,6 +923,116 @@ class FCSpinner(QtWidgets.QSpinBox):
     #     return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())
 
 
+class FCDoubleSlider(QtWidgets.QSlider):
+    # frome here: https://stackoverflow.com/questions/42820380/use-float-for-qslider
+
+    # create our our signal that we can connect to if necessary
+    doubleValueChanged = pyqtSignal(float)
+
+    def __init__(self, decimals=3, orientation='horizontal', *args, **kargs):
+        if orientation == 'horizontal':
+            super(FCDoubleSlider, self).__init__(QtCore.Qt.Horizontal, *args, **kargs)
+        else:
+            super(FCDoubleSlider, self).__init__(QtCore.Qt.Vertical, *args, **kargs)
+
+        self._multi = 10 ** decimals
+
+        self.valueChanged.connect(self.emitDoubleValueChanged)
+
+    def emitDoubleValueChanged(self):
+        value = float(super(FCDoubleSlider, self).value()) / self._multi
+        self.doubleValueChanged.emit(value)
+
+    def value(self):
+        return float(super(FCDoubleSlider, self).value()) / self._multi
+
+    def setMinimum(self, value):
+        return super(FCDoubleSlider, self).setMinimum(value * self._multi)
+
+    def setMaximum(self, value):
+        return super(FCDoubleSlider, self).setMaximum(value * self._multi)
+
+    def setSingleStep(self, value):
+        return super(FCDoubleSlider, self).setSingleStep(value * self._multi)
+
+    def singleStep(self):
+        return float(super(FCDoubleSlider, self).singleStep()) / self._multi
+
+    def set_value(self, value):
+        super(FCDoubleSlider, self).setValue(int(value * self._multi))
+
+    def set_range(self, min, max):
+        self.blockSignals(True)
+        self.setRange(min, max)
+        self.blockSignals(False)
+
+
+class FCSliderWithDoubleSpinner(QtWidgets.QFrame):
+
+    def __init__(self, min=0, max=9999.9999, step=1, precision=4, orientation='horizontal', **kwargs):
+        super().__init__(**kwargs)
+
+        self.slider = FCDoubleSlider(orientation=orientation)
+        self.slider.setMinimum(min)
+        self.slider.setMaximum(max)
+        self.slider.setSingleStep(step)
+        self.slider.set_range(min, max)
+
+        self.spinner = FCDoubleSpinner()
+        self.spinner.set_range(min, max)
+        self.spinner.set_precision(precision)
+
+        self.spinner.set_step(step)
+        self.spinner.setMinimumWidth(70)
+
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
+        self.spinner.setSizePolicy(sizePolicy)
+
+        self.layout = QtWidgets.QHBoxLayout()
+        self.layout.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
+        self.layout.setContentsMargins(0, 0, 0, 0)
+        self.layout.addWidget(self.slider)
+        self.layout.addWidget(self.spinner)
+        self.setLayout(self.layout)
+
+        self.slider.doubleValueChanged.connect(self._on_slider)
+        self.spinner.valueChanged.connect(self._on_spinner)
+
+        self.valueChanged = self.spinner.valueChanged
+
+    def set_precision(self, prec):
+        self.spinner.set_precision(prec)
+
+    def setSingleStep(self, step):
+        self.spinner.set_step(step)
+
+    def set_range(self, min, max):
+        self.spinner.set_range(min, max)
+        self.slider.set_range(min, max)
+
+    def set_minimum(self, min):
+        self.slider.setMinimum(min)
+        self.spinner.setMinimum(min)
+
+    def set_maximum(self, max):
+        self.slider.setMaximum(max)
+        self.spinner.setMaximum(max)
+
+    def get_value(self) -> float:
+        return self.spinner.get_value()
+
+    def set_value(self, value: float):
+        self.spinner.set_value(value)
+
+    def _on_spinner(self):
+        spinner_value = self.spinner.value()
+        self.slider.set_value(spinner_value)
+
+    def _on_slider(self):
+        slider_value = self.slider.value()
+        self.spinner.set_value(slider_value)
+
+
 class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
 
     returnPressed = QtCore.pyqtSignal()
@@ -1056,6 +1166,11 @@ class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
 
         self.setRange(min_val, max_val)
 
+    def set_step(self, p_int):
+        self.blockSignals(True)
+        self.setSingleStep(p_int)
+        self.blockSignals(False)
+
     # def sizeHint(self):
     #     default_hint_size = super(FCDoubleSpinner, self).sizeHint()
     #     return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())

+ 2 - 2
appGUI/ObjectUI.py

@@ -2278,7 +2278,7 @@ class CNCObjectUI(ObjectUI):
             _("Each jog action will move the axes with this value.")
         )
 
-        self.jog_step_entry = FCDoubleSpinner()
+        self.jog_step_entry = FCSliderWithDoubleSpinner()
         self.jog_step_entry.set_precision(self.decimals)
         self.jog_step_entry.setSingleStep(0.1)
         self.jog_step_entry.set_range(0, 99999.9999)
@@ -2292,7 +2292,7 @@ class CNCObjectUI(ObjectUI):
             _("Feedrate when jogging.")
         )
 
-        self.jog_fr_entry = FCDoubleSpinner()
+        self.jog_fr_entry = FCSliderWithDoubleSpinner()
         self.jog_fr_entry.set_precision(self.decimals)
         self.jog_fr_entry.setSingleStep(10)
         self.jog_fr_entry.set_range(0, 99999.9999)

+ 59 - 25
appObjects/FlatCAMCNCJob.py

@@ -201,6 +201,8 @@ class CNCJobObject(FlatCAMObj, CNCjob):
         self.solid_geo = None
         self.grbl_ser_port = None
 
+        self.pressed_button = None
+
         # Attributes to be included in serialization
         # Always append to it because it carries contents
         # from predecessors.
@@ -568,27 +570,13 @@ class CNCJobObject(FlatCAMObj, CNCjob):
         self.ui.grbl_command_entry.returnPressed.connect(self.on_send_grbl_command)
 
         # Jog
-        self.ui.jog_wdg.jog_up_button.clicked.connect(
-            lambda: self.on_jog(direction='yplus', step=self.ui.jog_step_entry.get_value(),
-                                feedrate=self.ui.jog_fr_entry.get_value()))
-        self.ui.jog_wdg.jog_down_button.clicked.connect(
-            lambda: self.on_jog(direction='yminus', step=self.ui.jog_step_entry.get_value(),
-                                feedrate=self.ui.jog_fr_entry.get_value()))
-        self.ui.jog_wdg.jog_right_button.clicked.connect(
-            lambda: self.on_jog(direction='xplus', step=self.ui.jog_step_entry.get_value(),
-                                feedrate=self.ui.jog_fr_entry.get_value()))
-        self.ui.jog_wdg.jog_left_button.clicked.connect(
-            lambda: self.on_jog(direction='xminus', step=self.ui.jog_step_entry.get_value(),
-                                feedrate=self.ui.jog_fr_entry.get_value()))
-        self.ui.jog_wdg.jog_z_up_button.clicked.connect(
-            lambda: self.on_jog(direction='zplus', step=self.ui.jog_step_entry.get_value(),
-                                feedrate=self.ui.jog_fr_entry.get_value()))
-        self.ui.jog_wdg.jog_z_down_button.clicked.connect(
-            lambda: self.on_jog(direction='zminus', step=self.ui.jog_step_entry.get_value(),
-                                feedrate=self.ui.jog_fr_entry.get_value()))
-        self.ui.jog_wdg.jog_origin_button.clicked.connect(
-            lambda: self.on_jog(direction='origin', travelz=float(self.app.defaults["cncjob_al_grbl_travelz"]),
-                                feedrate=self.ui.jog_fr_entry.get_value()))
+        self.ui.jog_wdg.jog_up_button.clicked.connect(lambda: self.on_jog(direction='yplus'))
+        self.ui.jog_wdg.jog_down_button.clicked.connect(lambda: self.on_jog(direction='yminus'))
+        self.ui.jog_wdg.jog_right_button.clicked.connect(lambda: self.on_jog(direction='xplus'))
+        self.ui.jog_wdg.jog_left_button.clicked.connect(lambda: self.on_jog(direction='xminus'))
+        self.ui.jog_wdg.jog_z_up_button.clicked.connect(lambda: self.on_jog(direction='zplus'))
+        self.ui.jog_wdg.jog_z_down_button.clicked.connect(lambda: self.on_jog(direction='zminus'))
+        self.ui.jog_wdg.jog_origin_button.clicked.connect(lambda: self.on_jog(direction='origin'))
 
         # Zero
         self.ui.zero_axs_wdg.grbl_zerox_button.clicked.connect(lambda: self.on_grbl_zero(axis='x'))
@@ -624,8 +612,12 @@ class CNCJobObject(FlatCAMObj, CNCjob):
             self.ui.level.setText(_(
                 '<span style="color:red;"><b>Advanced</b></span>'
             ))
-            self.ui.sal_cb.show()
-            self.ui.sal_cb.set_value(self.app.defaults["cncjob_al_status"])
+            if 'Roland' in self.pp_excellon_name or 'Roland' in self.pp_geometry_name or 'hpgl' in \
+                    self.pp_geometry_name:
+                pass
+            else:
+                self.ui.sal_cb.show()
+                self.ui.sal_cb.set_value(self.app.defaults["cncjob_al_status"])
 
         preamble = self.append_snippet
         postamble = self.prepend_snippet
@@ -1154,11 +1146,15 @@ class CNCJobObject(FlatCAMObj, CNCjob):
                 self.app.shell_message("GRBL Parameter: %s = %s" % (str(param), str(result)), show=True)
                 return result
 
-    def on_jog(self, direction=None, step=5.0, feedrate=1000.0, travelz=15.0):
+    def on_jog(self, direction=None):
         if direction is None:
             return
         cmd = ''
 
+        step = self.ui.jog_step_entry.get_value(),
+        feedrate = self.ui.jog_fr_entry.get_value()
+        travelz = float(self.app.defaults["cncjob_al_grbl_travelz"])
+
         if direction == 'xplus':
             cmd = "$J=G91 %s X%s F%s" % ({'IN': 'G20', 'MM': 'G21'}[self.units], str(step), str(feedrate))
         if direction == 'xminus':
@@ -1349,6 +1345,44 @@ class CNCJobObject(FlatCAMObj, CNCjob):
         controller = self.ui.al_controller_combo.get_value()
         self.probing_gcode_text = self.probing_gcode(coords, pr_travel, probe_fr, pr_depth, controller)
 
+        lines = StringIO(self.probing_gcode_text)
+
+        _filter_ = self.app.defaults['cncjob_save_filters']
+        name = "probing_gcode"
+        try:
+            dir_file_to_save = self.app.get_last_save_folder() + '/' + str(name)
+            filename, _f = FCFileSaveDialog.get_saved_filename(
+                caption=_("Export Code ..."),
+                directory=dir_file_to_save,
+                ext_filter=_filter_
+            )
+        except TypeError:
+            filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Export Code ..."), ext_filter=_filter_)
+
+        if filename == '':
+            self.app.inform.emit('[WARNING_NOTCL] %s' % _("Export cancelled ..."))
+            return
+        else:
+            try:
+                force_windows_line_endings = self.app.defaults['cncjob_line_ending']
+                if force_windows_line_endings and sys.platform != 'win32':
+                    with open(filename, 'w', newline='\r\n') as f:
+                        for line in lines:
+                            f.write(line)
+                else:
+                    with open(filename, 'w') as f:
+                        for line in lines:
+                            f.write(line)
+            except FileNotFoundError:
+                self.app.inform.emit('[WARNING_NOTCL] %s' % _("No such file or directory"))
+                return
+            except PermissionError:
+                self.app.inform.emit(
+                    '[WARNING] %s' % _("Permission denied, saving not possible.\n"
+                                       "Most likely another app is holding the file open and not accessible.")
+                )
+                return 'fail'
+
     def on_view_probing_gcode(self):
         self.app.proc_container.view.set_busy(_("Loading..."))
 
@@ -1415,7 +1449,7 @@ class CNCJobObject(FlatCAMObj, CNCjob):
         filename = str(filename)
 
         if filename == '':
-            self.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled."))
+            self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled."))
         else:
             self.app.worker_task.emit({'fcn': self.import_height_map, 'params': [filename]})