From 2deba3a8f991156014976851868ee9e1dd7eb239 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Sat, 22 Aug 2020 03:34:45 +0300 Subject: [PATCH] - in CNCJob UI Autolevelling - GRBL controller - added handlers for the Zeroing and for Homing and for Pause/Resume; some UI optimizations --- CHANGELOG.md | 1 + appGUI/GUIElements.py | 139 ++++++++++++++++++++++++++++++------ appGUI/ObjectUI.py | 49 ++++++++++--- appObjects/FlatCAMCNCJob.py | 49 ++++++++++++- 4 files changed, 207 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34fb22e0..2fe73a41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ CHANGELOG for FlatCAM beta - 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 feedrate and step size controls and added them in Preferences +- in CNCJob UI Autolevelling - GRBL controller - added handlers for the Zeroing and for Homing and for Pause/Resume; some UI optimizations 19.08.2020 diff --git a/appGUI/GUIElements.py b/appGUI/GUIElements.py index 5c377792..e8da1143 100644 --- a/appGUI/GUIElements.py +++ b/appGUI/GUIElements.py @@ -3252,7 +3252,7 @@ class FCDock(QtWidgets.QDockWidget): class FCJog(QtWidgets.QFrame): - def __init__(self, title, app, *args, **kwargs): + def __init__(self, app, *args, **kwargs): super(FCJog, self).__init__(*args, **kwargs) self.app = app @@ -3263,16 +3263,9 @@ class FCJog(QtWidgets.QFrame): grbl_jog_grid = QtWidgets.QGridLayout() grbl_jog_grid.setAlignment(QtCore.Qt.AlignCenter) grbl_jog_grid.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize) - self.setLayout(grbl_jog_grid) + grbl_jog_grid.setContentsMargins(2, 4, 2, 4) - jog_title_label = FCLabel(title) - jog_title_label.setStyleSheet(""" - FCLabel - { - font-weight: bold; - } - """) - grbl_jog_grid.addWidget(jog_title_label, 0, 0, 1, 4) + self.setLayout(grbl_jog_grid) # JOG Y Up self.jog_up_button = QtWidgets.QToolButton() @@ -3338,7 +3331,7 @@ class FCJog(QtWidgets.QFrame): class FCZeroAxes(QtWidgets.QFrame): - def __init__(self, title, app, *args, **kwargs): + def __init__(self, app, *args, **kwargs): super(FCZeroAxes, self).__init__(*args, **kwargs) self.app = app @@ -3347,20 +3340,12 @@ class FCZeroAxes(QtWidgets.QFrame): # Zero the axes grbl_zero_grid = QtWidgets.QGridLayout() + grbl_zero_grid.setContentsMargins(2, 4, 2, 4) grbl_zero_grid.setColumnStretch(0, 0) grbl_zero_grid.setColumnStretch(1, 0) - grbl_zero_grid.setRowStretch(4, 1) + # grbl_zero_grid.setRowStretch(4, 1) self.setLayout(grbl_zero_grid) - zero_title_label = FCLabel(title) - zero_title_label.setStyleSheet(""" - FCLabel - { - font-weight: bold; - } - """) - grbl_zero_grid.addWidget(zero_title_label, 0, 0, 1, 2) - # Zero X axis self.grbl_zerox_button = QtWidgets.QToolButton() self.grbl_zerox_button.setText(_("X")) @@ -3384,6 +3369,11 @@ class FCZeroAxes(QtWidgets.QFrame): _("Zero the CNC Z axes at current position.") ) grbl_zero_grid.addWidget(self.grbl_zeroz_button, 3, 0) + self.grbl_homing_button = QtWidgets.QToolButton() + self.grbl_homing_button.setText(_("Do Home")) + self.grbl_homing_button.setToolTip( + _("Perform a homing cycle on all axis.")) + grbl_zero_grid.addWidget(self.grbl_homing_button, 4, 0, 1, 2) # Zeroo all axes self.grbl_zero_all_button = QtWidgets.QToolButton() self.grbl_zero_all_button.setText(_("All")) @@ -3394,6 +3384,113 @@ class FCZeroAxes(QtWidgets.QFrame): ) grbl_zero_grid.addWidget(self.grbl_zero_all_button, 1, 1, 3, 1) + +class RotatedToolButton(QtWidgets.QToolButton): + def __init__(self, orientation = "east", *args, **kwargs): + super(RotatedToolButton,self).__init__(*args, **kwargs) + self.orientation = orientation + + def paintEvent(self, event): + painter = QtWidgets.QStylePainter(self) + if self.orientation == "east": + painter.rotate(270) + painter.translate(-1 * self.height(), 0) + if self.orientation == "west": + painter.rotate(90) + painter.translate(0, -1 * self.width()) + painter.drawControl(QtWidgets.QStyle.CE_PushButton, self.getSyleOptions()) + + def minimumSizeHint(self): + size = super(RotatedToolButton, self).minimumSizeHint() + size.transpose() + return size + + def sizeHint(self): + size = super(RotatedToolButton, self).sizeHint() + size.transpose() + return size + + def getSyleOptions(self): + options = QtWidgets.QStyleOptionButton() + options.initFrom(self) + size = options.rect.size() + size.transpose() + options.rect.setSize(size) + options.features = QtWidgets.QStyleOptionButton.None_ + # if self.isFlat(): + # options.features |= QtWidgets.QStyleOptionButton.Flat + if self.menu(): + options.features |= QtWidgets.QStyleOptionButton.HasMenu + # if self.autoDefault() or self.isDefault(): + # options.features |= QtWidgets.QStyleOptionButton.AutoDefaultButton + # if self.isDefault(): + # options.features |= QtWidgets.QStyleOptionButton.DefaultButton + if self.isDown() or (self.menu() and self.menu().isVisible()): + options.state |= QtWidgets.QStyle.State_Sunken + if self.isChecked(): + options.state |= QtWidgets.QStyle.State_On + # if not self.isFlat() and not self.isDown(): + # options.state |= QtWidgets.QStyle.State_Raised + + options.text = self.text() + options.icon = self.icon() + options.iconSize = self.iconSize() + return options + + +class RotatedButton(QtWidgets.QPushButton): + def __init__(self, orientation = "west", *args, **kwargs): + super(RotatedButton,self).__init__(*args, **kwargs) + self.orientation = orientation + + def paintEvent(self, event): + painter = QtWidgets.QStylePainter(self) + if self.orientation == "east": + painter.rotate(270) + painter.translate(-1 * self.height(), 0) + if self.orientation == "west": + painter.rotate(90) + painter.translate(0, -1 * self.width()) + painter.drawControl(QtWidgets.QStyle.CE_PushButton, self.getSyleOptions()) + + def minimumSizeHint(self): + size = super(RotatedButton, self).minimumSizeHint() + size.transpose() + return size + + def sizeHint(self): + size = super(RotatedButton, self).sizeHint() + size.transpose() + return size + + def getSyleOptions(self): + options = QtWidgets.QStyleOptionButton() + options.initFrom(self) + size = options.rect.size() + size.transpose() + options.rect.setSize(size) + options.features = QtWidgets.QStyleOptionButton.None_ + if self.isFlat(): + options.features |= QtWidgets.QStyleOptionButton.Flat + if self.menu(): + options.features |= QtWidgets.QStyleOptionButton.HasMenu + if self.autoDefault() or self.isDefault(): + options.features |= QtWidgets.QStyleOptionButton.AutoDefaultButton + if self.isDefault(): + options.features |= QtWidgets.QStyleOptionButton.DefaultButton + if self.isDown() or (self.menu() and self.menu().isVisible()): + options.state |= QtWidgets.QStyle.State_Sunken + if self.isChecked(): + options.state |= QtWidgets.QStyle.State_On + if not self.isFlat() and not self.isDown(): + options.state |= QtWidgets.QStyle.State_Raised + + options.text = self.text() + options.icon = self.icon() + options.iconSize = self.iconSize() + return options + + class FlatCAMActivityView(QtWidgets.QWidget): """ This class create and control the activity icon displayed in the App status bar diff --git a/appGUI/ObjectUI.py b/appGUI/ObjectUI.py index 2cdd4c50..fc1d1ec3 100644 --- a/appGUI/ObjectUI.py +++ b/appGUI/ObjectUI.py @@ -2199,7 +2199,8 @@ class CNCObjectUI(ObjectUI): # ############################################################################################################# grbl_ctrl_grid = QtWidgets.QGridLayout() grbl_ctrl_grid.setColumnStretch(0, 0) - grbl_ctrl_grid.setColumnStretch(1, 0) + grbl_ctrl_grid.setColumnStretch(1, 1) + grbl_ctrl_grid.setColumnStretch(2, 0) self.gr_ctrl_tab_layout.addLayout(grbl_ctrl_grid) grbl_ctrl2_grid = QtWidgets.QGridLayout() @@ -2209,18 +2210,35 @@ class CNCObjectUI(ObjectUI): self.gr_ctrl_tab_layout.addStretch(1) - self.jog_wdg = FCJog(_("Jog"), self.app) - self.jog_wdg.setContentsMargins(2, 2, 2, 2) + jog_title_label = FCLabel(_("Jog")) + jog_title_label.setStyleSheet(""" + FCLabel + { + font-weight: bold; + } + """) + + zero_title_label = FCLabel(_("Zero Axes")) + zero_title_label.setStyleSheet(""" + FCLabel + { + font-weight: bold; + } + """) + + grbl_ctrl_grid.addWidget(jog_title_label, 0, 0) + grbl_ctrl_grid.addWidget(zero_title_label, 0, 2) + + self.jog_wdg = FCJog(self.app) self.jog_wdg.setStyleSheet(""" FCJog { border: 1px solid lightgray; - border-radius: 5px + border-radius: 5px; } """) - self.zero_axs_wdg = FCZeroAxes(_("Zero Axes"), self.app) - self.zero_axs_wdg.setContentsMargins(2, 2, 2, 2) + self.zero_axs_wdg = FCZeroAxes(self.app) self.zero_axs_wdg.setStyleSheet(""" FCZeroAxes { @@ -2228,8 +2246,23 @@ class CNCObjectUI(ObjectUI): border-radius: 5px } """) - grbl_ctrl_grid.addWidget(self.jog_wdg, 0, 0) - grbl_ctrl_grid.addWidget(self.zero_axs_wdg, 0, 1) + grbl_ctrl_grid.addWidget(self.jog_wdg, 2, 0) + grbl_ctrl_grid.addWidget(self.zero_axs_wdg, 2, 2) + + self.pause_resume_button = RotatedToolButton() + self.pause_resume_button.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.pause_resume_button.setText(_("Pause/Resume")) + self.pause_resume_button.setCheckable(True) + + pause_frame = QtWidgets.QFrame() + pause_frame.setContentsMargins(0, 0, 0, 0) + pause_frame.setSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Expanding) + pause_hlay = QtWidgets.QHBoxLayout() + pause_hlay.setContentsMargins(0, 0, 0, 0) + + pause_hlay.addWidget(self.pause_resume_button) + pause_frame.setLayout(pause_hlay) + grbl_ctrl_grid.addWidget(pause_frame, 2, 1) # JOG Step self.jog_step_label = FCLabel('%s:' % _("Step")) diff --git a/appObjects/FlatCAMCNCJob.py b/appObjects/FlatCAMCNCJob.py index b1c37560..d66a49b1 100644 --- a/appObjects/FlatCAMCNCJob.py +++ b/appObjects/FlatCAMCNCJob.py @@ -567,7 +567,7 @@ class CNCJobObject(FlatCAMObj, CNCjob): self.ui.grbl_send_button.clicked.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( lambda: self.on_jog(direction='yplus', step=self.ui.jog_step_entry.get_value(), feedrate=self.ui.jog_fr_entry.get_value())) @@ -590,6 +590,13 @@ class CNCJobObject(FlatCAMObj, CNCjob): lambda: self.on_jog(direction='origin', travelz=float(self.app.defaults["cncjob_al_grbl_travelz"]), feedrate=self.ui.jog_fr_entry.get_value())) + # Zero + self.ui.zero_axs_wdg.grbl_zerox_button.clicked.connect(lambda: self.on_grbl_zero(axis='x')) + self.ui.zero_axs_wdg.grbl_zeroy_button.clicked.connect(lambda: self.on_grbl_zero(axis='y')) + self.ui.zero_axs_wdg.grbl_zeroz_button.clicked.connect(lambda: self.on_grbl_zero(axis='z')) + self.ui.zero_axs_wdg.grbl_zero_all_button.clicked.connect(lambda: self.on_grbl_zero(axis='all')) + self.ui.zero_axs_wdg.grbl_homing_button.clicked.connect(self.on_grbl_homing) + # Sender self.ui.grbl_report_button.clicked.connect(lambda: self.send_grbl_command(command='?')) self.ui.grbl_get_param_button.clicked.connect( @@ -597,6 +604,8 @@ class CNCJobObject(FlatCAMObj, CNCjob): self.ui.view_h_gcode_button.clicked.connect(self.on_view_probing_gcode) self.ui.h_gcode_button.clicked.connect(self.on_generate_probing_gcode) self.ui.import_heights_button.clicked.connect(self.on_import_height_map) + self.ui.pause_resume_button.clicked.connect(self.on_grbl_pause_resume) + self.build_al_table_sig.connect(self.build_al_table) # self.ui.tc_variable_combo.currentIndexChanged[str].connect(self.on_cnc_custom_parameters) @@ -697,7 +706,7 @@ class CNCJobObject(FlatCAMObj, CNCjob): for x in range(rows): new_y += dy new_x = xmin - for x in range(cols): + for y in range(cols): new_x += dx formatted_point = ( self.app.dec_format(new_x, self.app.decimals), @@ -1173,12 +1182,48 @@ class CNCJobObject(FlatCAMObj, CNCjob): self.send_grbl_command(command=cmd, echo=False) + def on_grbl_zero(self, axis): + current_mode = self.get_grbl_parameter('10') + cmd = '$10=0' + self.send_grbl_command(command=cmd, echo=False) + + if axis == 'x': + cmd = 'G10 L2 P1 X0' + elif axis == 'y': + cmd = 'G10 L2 P1 Y0' + elif axis == 'z': + cmd = 'G10 L2 P1 Z0' + else: + # all + cmd = 'G10 L2 P1 X0 Y0 Z0' + self.send_grbl_command(command=cmd, echo=False) + + # restore previous mode + cmd = '$10=%d' % int(current_mode) + self.send_grbl_command(command=cmd, echo=False) + + def on_grbl_homing(self): + cmd = '$H' + self.wake_grbl() + self.send_grbl_command(command=cmd) + self.app.inform.emit("%s" % _("GRBL is doing a home cycle.")) + def on_grbl_reset(self): cmd = '\x18' self.wake_grbl() self.send_grbl_command(command=cmd) self.app.inform.emit("%s" % _("GRBL software reset was sent.")) + def on_grbl_pause_resume(self, checked): + if checked is False: + cmd = '~' + self.send_grbl_command(command=cmd) + self.app.inform.emit("%s" % _("GRBL resumed.")) + else: + cmd = '!' + self.send_grbl_command(command=cmd) + self.app.inform.emit("%s" % _("GRBL paused.")) + def probing_gcode(self, coords, pr_travel, probe_fr, pr_depth, controller): """