- 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
This commit is contained in:
Marius Stanciu
2020-08-23 15:20:12 +03:00
parent 5c960debf5
commit 26ac43bd2e
4 changed files with 184 additions and 28 deletions

View File

@@ -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 21.08.2020
- in CNCJob UI Autolevelling - GRBL controller - Control: added a Origin button; changed the UI to have rounded rectangles - in CNCJob UI Autolevelling - GRBL controller - Control: added a Origin button; changed the UI to have rounded rectangles

View File

@@ -12,7 +12,7 @@
# ########################################################## # ##########################################################
from PyQt5 import QtGui, QtCore, QtWidgets 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.QtWidgets import QTextEdit, QCompleter, QAction
from PyQt5.QtGui import QKeySequence, QTextCursor from PyQt5.QtGui import QKeySequence, QTextCursor
@@ -923,6 +923,116 @@ class FCSpinner(QtWidgets.QSpinBox):
# return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height()) # 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): class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
returnPressed = QtCore.pyqtSignal() returnPressed = QtCore.pyqtSignal()
@@ -1056,6 +1166,11 @@ class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
self.setRange(min_val, max_val) 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): # def sizeHint(self):
# default_hint_size = super(FCDoubleSpinner, self).sizeHint() # default_hint_size = super(FCDoubleSpinner, self).sizeHint()
# return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height()) # return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())

View File

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

View File

@@ -201,6 +201,8 @@ class CNCJobObject(FlatCAMObj, CNCjob):
self.solid_geo = None self.solid_geo = None
self.grbl_ser_port = None self.grbl_ser_port = None
self.pressed_button = None
# Attributes to be included in serialization # Attributes to be included in serialization
# Always append to it because it carries contents # Always append to it because it carries contents
# from predecessors. # from predecessors.
@@ -568,27 +570,13 @@ class CNCJobObject(FlatCAMObj, CNCjob):
self.ui.grbl_command_entry.returnPressed.connect(self.on_send_grbl_command) self.ui.grbl_command_entry.returnPressed.connect(self.on_send_grbl_command)
# Jog # Jog
self.ui.jog_wdg.jog_up_button.clicked.connect( self.ui.jog_wdg.jog_up_button.clicked.connect(lambda: self.on_jog(direction='yplus'))
lambda: self.on_jog(direction='yplus', step=self.ui.jog_step_entry.get_value(), self.ui.jog_wdg.jog_down_button.clicked.connect(lambda: self.on_jog(direction='yminus'))
feedrate=self.ui.jog_fr_entry.get_value())) self.ui.jog_wdg.jog_right_button.clicked.connect(lambda: self.on_jog(direction='xplus'))
self.ui.jog_wdg.jog_down_button.clicked.connect( self.ui.jog_wdg.jog_left_button.clicked.connect(lambda: self.on_jog(direction='xminus'))
lambda: self.on_jog(direction='yminus', step=self.ui.jog_step_entry.get_value(), self.ui.jog_wdg.jog_z_up_button.clicked.connect(lambda: self.on_jog(direction='zplus'))
feedrate=self.ui.jog_fr_entry.get_value())) self.ui.jog_wdg.jog_z_down_button.clicked.connect(lambda: self.on_jog(direction='zminus'))
self.ui.jog_wdg.jog_right_button.clicked.connect( self.ui.jog_wdg.jog_origin_button.clicked.connect(lambda: self.on_jog(direction='origin'))
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()))
# Zero # Zero
self.ui.zero_axs_wdg.grbl_zerox_button.clicked.connect(lambda: self.on_grbl_zero(axis='x')) 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(_( self.ui.level.setText(_(
'<span style="color:red;"><b>Advanced</b></span>' '<span style="color:red;"><b>Advanced</b></span>'
)) ))
self.ui.sal_cb.show() if 'Roland' in self.pp_excellon_name or 'Roland' in self.pp_geometry_name or 'hpgl' in \
self.ui.sal_cb.set_value(self.app.defaults["cncjob_al_status"]) 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 preamble = self.append_snippet
postamble = self.prepend_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) self.app.shell_message("GRBL Parameter: %s = %s" % (str(param), str(result)), show=True)
return result 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: if direction is None:
return return
cmd = '' 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': if direction == 'xplus':
cmd = "$J=G91 %s X%s F%s" % ({'IN': 'G20', 'MM': 'G21'}[self.units], str(step), str(feedrate)) cmd = "$J=G91 %s X%s F%s" % ({'IN': 'G20', 'MM': 'G21'}[self.units], str(step), str(feedrate))
if direction == 'xminus': if direction == 'xminus':
@@ -1349,6 +1345,44 @@ class CNCJobObject(FlatCAMObj, CNCjob):
controller = self.ui.al_controller_combo.get_value() controller = self.ui.al_controller_combo.get_value()
self.probing_gcode_text = self.probing_gcode(coords, pr_travel, probe_fr, pr_depth, controller) 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): def on_view_probing_gcode(self):
self.app.proc_container.view.set_busy(_("Loading...")) self.app.proc_container.view.set_busy(_("Loading..."))
@@ -1415,7 +1449,7 @@ class CNCJobObject(FlatCAMObj, CNCjob):
filename = str(filename) filename = str(filename)
if filename == '': if filename == '':
self.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled.")) self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled."))
else: else:
self.app.worker_task.emit({'fcn': self.import_height_map, 'params': [filename]}) self.app.worker_task.emit({'fcn': self.import_height_map, 'params': [filename]})