diff --git a/FlatCAMApp.py b/FlatCAMApp.py index b3482219..155dc4f1 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -486,22 +486,25 @@ class App(QtCore.QObject): "excellon_editor_circ_dir": self.ui.excellon_defaults_form.excellon_editor_group.drill_circular_dir_radio, "excellon_editor_circ_angle": self.ui.excellon_defaults_form.excellon_editor_group.drill_circular_angle_entry, + # Excellon Slots "excellon_editor_slot_direction": self.ui.excellon_defaults_form.excellon_editor_group.slot_axis_radio, "excellon_editor_slot_angle": self.ui.excellon_defaults_form.excellon_editor_group.slot_angle_spinner, "excellon_editor_slot_length": self.ui.excellon_defaults_form.excellon_editor_group.slot_length_entry, - # Slots - # "excellon_editor_slot_array_size": - # self.ui.excellon_defaults_form.excellon_editor_group.drill_array_size_entry, - # "excellon_editor_slot_lin_dir": self.ui.excellon_defaults_form.excellon_editor_group.drill_axis_radio, - # "excellon_editor_slot_lin_pitch": self.ui.excellon_defaults_form.excellon_editor_group.drill_pitch_entry, - # "excellon_editor_slot_lin_angle": self.ui.excellon_defaults_form.excellon_editor_group.drill_angle_entry, - # "excellon_editor_slot_circ_dir": - # self.ui.excellon_defaults_form.excellon_editor_group.drill_circular_dir_radio, - # "excellon_editor_slot_circ_angle": - # self.ui.excellon_defaults_form.excellon_editor_group.drill_circular_angle_entry, + # Excellon Slots + "excellon_editor_slot_array_size": + self.ui.excellon_defaults_form.excellon_editor_group.slot_array_size_entry, + "excellon_editor_slot_lin_dir": self.ui.excellon_defaults_form.excellon_editor_group.slot_array_axis_radio, + "excellon_editor_slot_lin_pitch": + self.ui.excellon_defaults_form.excellon_editor_group.slot_array_pitch_entry, + "excellon_editor_slot_lin_angle": + self.ui.excellon_defaults_form.excellon_editor_group.slot_array_angle_entry, + "excellon_editor_slot_circ_dir": + self.ui.excellon_defaults_form.excellon_editor_group.slot_array_circular_dir_radio, + "excellon_editor_slot_circ_angle": + self.ui.excellon_defaults_form.excellon_editor_group.slot_array_circular_angle_entry, # Geometry General "geometry_plot": self.ui.geometry_defaults_form.geometry_gen_group.plot_cb, @@ -848,9 +851,17 @@ class App(QtCore.QObject): "excellon_editor_lin_angle": 0.0, "excellon_editor_circ_dir": 'CW', "excellon_editor_circ_angle": 12, + # Excellon Slots "excellon_editor_slot_direction": 'X', "excellon_editor_slot_angle": 0.0, "excellon_editor_slot_length": 5.0, + # Excellon Slot Array + "excellon_editor_slot_array_size": 5, + "excellon_editor_slot_lin_dir": 'X', + "excellon_editor_slot_lin_pitch": 0.1, + "excellon_editor_slot_lin_angle": 0.0, + "excellon_editor_slot_circ_dir": 'CW', + "excellon_editor_slot_circ_angle": 0.0, # Geometry General "geometry_plot": True, diff --git a/README.md b/README.md index 72e3a8c6..8f243356 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,10 @@ CAD program, and create G-Code for Isolation routing. - created a configuration file in the root/config/configuration.txt with a configuration line for portability. Set portable to True to run the app as portable - working on the Slots Array in Excellon Editor - building the GUI - added a failsafe path to the source folder from which to copy the VisPy data +- fixed the GUI for Slot Arrays in Excellon Editor +- finished the Slot Array tool in Excellon Editor +- added the key shortcut handlers for Add Slot and Add Slot Array tools in Excellon Editor +- started to work on the Resize tool for the case of Excellon slots in Excellon Editor 14.08.2019 diff --git a/flatcamEditors/FlatCAMExcEditor.py b/flatcamEditors/FlatCAMExcEditor.py index 536e65f6..a39ab4ea 100644 --- a/flatcamEditors/FlatCAMExcEditor.py +++ b/flatcamEditors/FlatCAMExcEditor.py @@ -730,8 +730,6 @@ class FCSlotArray(FCShapeTool): for pt in up_arc: geo.append(pt) geo.append(p4) - - return Polygon(geo) else: p1 = (point_x - self.half_width + self.half_height, point_y - self.half_height) p2 = (point_x + self.half_width - self.half_height, point_y - self.half_height) @@ -757,6 +755,11 @@ class FCSlotArray(FCShapeTool): for pt in left_arc: geo.append(pt) + # this function return one slot in the slot array and the following will rotate that one slot around it's + # center if the radio value is "A". + if self.draw_app.slot_axis_radio.get_value() == 'A': + return affinity.rotate(Polygon(geo), -slot_angle) + else: return Polygon(geo) def make(self): @@ -896,7 +899,19 @@ class FCDrillResize(FCShapeTool): # the number of drills displayed in column 2 is just a len(self.points_edit) therefore # deleting self.points_edit elements (doesn't matter who but just the number) # solved the display issue. - del self.draw_app.points_edit[sel_dia][0] + try: + del self.draw_app.points_edit[sel_dia][0] + except KeyError: + # if the exception happen here then we are not dealing with drills but with slots + # so we try for them + try: + del self.draw_app.slot_points_edit[sel_dia][0] + except KeyError: + # if the exception happen here then we are not dealing with slots neither + # therefore something else is not OK so we return + self.draw_app.app.inform.emit( + _("[ERROR_NOTCL] Cancelled.")) + return sel_shapes_to_be_deleted.append(select_shape) @@ -923,10 +938,10 @@ class FCDrillResize(FCShapeTool): self.draw_app.build_ui() self.draw_app.replot() - self.draw_app.app.inform.emit(_("[success] Done. Drill Resize completed.")) + self.draw_app.app.inform.emit(_("[success] Done. Drill/Slot Resize completed.")) else: - self.draw_app.app.inform.emit(_("[WARNING_NOTCL] Cancelled. No drills selected for resize ...")) + self.draw_app.app.inform.emit(_("[WARNING_NOTCL] Cancelled. No drills/slots selected for resize ...")) self.draw_app.resize_frame.hide() self.complete = True @@ -1126,7 +1141,7 @@ class FCDrillSelect(DrawTool): self.exc_editor_app.resize_frame.hide() self.exc_editor_app.array_frame.hide() self.exc_editor_app.slot_frame.hide() - # self.exc_editor_app.slot_array_frame.hide() + self.exc_editor_app.slot_array_frame.hide() def click(self, point): key_modifier = QtWidgets.QApplication.keyboardModifiers() @@ -1434,6 +1449,10 @@ class FlatCAMExcEditor(QtCore.QObject): self.resize_frame.hide() + # #################################### + # ### Add DRILL Array ################ + # #################################### + # add a frame and inside add a vertical box layout. Inside this vbox layout I add # all the add drill array widgets # this way I can hide/show the frame @@ -1444,15 +1463,14 @@ class FlatCAMExcEditor(QtCore.QObject): self.array_box.setContentsMargins(0, 0, 0, 0) self.array_frame.setLayout(self.array_box) - # ### Add DRILL Array ## ## self.emptyarray_label = QtWidgets.QLabel('') self.array_box.addWidget(self.emptyarray_label) - self.drillarray_label = QtWidgets.QLabel('%s' % _("Add Drill Array")) - self.drillarray_label.setToolTip( + self.drill_array_label = QtWidgets.QLabel('%s' % _("Add Drill Array")) + self.drill_array_label.setToolTip( _("Add an array of drills (linear or circular array)") ) - self.array_box.addWidget(self.drillarray_label) + self.array_box.addWidget(self.drill_array_label) self.array_type_combo = FCComboBox() self.array_type_combo.setToolTip( @@ -1576,9 +1594,10 @@ class FlatCAMExcEditor(QtCore.QObject): self.emptyarray_label = QtWidgets.QLabel('') self.slot_box.addWidget(self.emptyarray_label) - self.slot_label = QtWidgets.QLabel('%s' % _("Add Slot")) + self.slot_label = QtWidgets.QLabel('%s' % _("Slot Parameters")) self.slot_label.setToolTip( - _("Add slot (hole with oval shape)") + _("Parameters for adding a slot (hole with oval shape)\n" + "either single or as an part of an array.") ) self.slot_box.addWidget(self.slot_label) @@ -1646,25 +1665,15 @@ class FlatCAMExcEditor(QtCore.QObject): self.emptyarray_label = QtWidgets.QLabel('') self.slot_array_box.addWidget(self.emptyarray_label) - self.slot_array_label = QtWidgets.QLabel('%s' % _("Add SLOT Array")) + self.slot_array_label = QtWidgets.QLabel('%s' % _("Slot Array Parameters")) self.slot_array_label.setToolTip( - _("Add an array of slots (linear or circular array)") + _("Parameters for the array of slots (linear or circular array)") ) self.slot_array_box.addWidget(self.slot_array_label) self.l_form = QtWidgets.QFormLayout() self.slot_array_box.addLayout(self.l_form) - # Slot length in array - self.array_slot_length_label = QtWidgets.QLabel(_('Length:')) - self.array_slot_length_label.setToolTip( - _("Length = The length of the slot.") - ) - self.array_slot_length_label.setMinimumWidth(100) - - self.array_slot_length_entry = LengthEntry() - self.l_form.addRow(self.array_slot_length_label, self.array_slot_length_entry) - self.slot_array_type_combo = FCComboBox() self.slot_array_type_combo.setToolTip( _("Select the type of slot array to create.\n" @@ -1842,6 +1851,8 @@ class FlatCAMExcEditor(QtCore.QObject): self.drill_axis_radio.activated_custom.connect(self.on_linear_angle_radio) self.slot_axis_radio.activated_custom.connect(self.on_slot_angle_radio) + self.slot_array_axis_radio.activated_custom.connect(self.on_slot_array_linear_angle_radio) + self.app.ui.exc_add_array_drill_menuitem.triggered.connect(self.exc_add_drill_array) self.app.ui.exc_add_drill_menuitem.triggered.connect(self.exc_add_drill) @@ -2023,12 +2034,15 @@ class FlatCAMExcEditor(QtCore.QObject): self.slot_axis_radio.set_value(self.app.defaults['excellon_editor_slot_direction']) self.slot_angle_spinner.set_value(float(self.app.defaults['excellon_editor_slot_angle'])) - self.slot_array_size_entry.set_value(int(self.app.defaults['excellon_editor_array_size'])) - self.slot_array_axis_radio.set_value(self.app.defaults['excellon_editor_lin_dir']) - self.slot_array_pitch_entry.set_value(float(self.app.defaults['excellon_editor_lin_pitch'])) - self.slot_array_linear_angle_spinner.set_value(float(self.app.defaults['excellon_editor_lin_angle'])) - self.slot_array_direction_radio.set_value(self.app.defaults['excellon_editor_circ_dir']) - self.slot_array_angle_entry.set_value(float(self.app.defaults['excellon_editor_circ_angle'])) + self.slot_array_size_entry.set_value(int(self.app.defaults['excellon_editor_slot_array_size'])) + self.slot_array_axis_radio.set_value(self.app.defaults['excellon_editor_slot_lin_dir']) + self.slot_array_pitch_entry.set_value(float(self.app.defaults['excellon_editor_slot_lin_pitch'])) + self.slot_array_linear_angle_spinner.set_value(float(self.app.defaults['excellon_editor_slot_lin_angle'])) + self.slot_array_direction_radio.set_value(self.app.defaults['excellon_editor_slot_circ_dir']) + self.slot_array_angle_entry.set_value(float(self.app.defaults['excellon_editor_slot_circ_angle'])) + + self.slot_array_circular_frame.hide() + self.slot_array_linear_frame.show() def build_ui(self, first_run=None): @@ -3658,6 +3672,15 @@ class FlatCAMExcEditor(QtCore.QObject): self.linear_angle_spinner.hide() self.linear_angle_label.hide() + def on_slot_array_linear_angle_radio(self): + val = self.slot_array_axis_radio.get_value() + if val == 'A': + self.slot_array_linear_angle_spinner.show() + self.slot_array_linear_angle_label.show() + else: + self.slot_array_linear_angle_spinner.hide() + self.slot_array_linear_angle_label.hide() + def on_slot_angle_radio(self): val = self.slot_axis_radio.get_value() if val == 'A': diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py index f557fe9c..2d818519 100644 --- a/flatcamGUI/FlatCAMGUI.py +++ b/flatcamGUI/FlatCAMGUI.py @@ -3057,6 +3057,18 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.app.inform.emit(_("[WARNING_NOTCL] Cancelled. Nothing selected to move.")) return + # Add Array of Slote Hole Tool + if key == QtCore.Qt.Key_Q or key == 'Q': + self.app.exc_editor.launched_from_shortcuts = True + self.app.inform.emit("Click on target point.") + self.app.ui.add_slot_array_btn.setChecked(True) + + self.app.exc_editor.x = self.app.mouse[0] + self.app.exc_editor.y = self.app.mouse[1] + + self.app.exc_editor.select_tool('slot_array') + return + # Resize Tool if key == QtCore.Qt.Key_R or key == 'R': self.app.exc_editor.launched_from_shortcuts = True @@ -3090,6 +3102,18 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.app.on_zoom_fit(None) return + # Add Slot Hole Tool + if key == QtCore.Qt.Key_W or key == 'W': + self.app.exc_editor.launched_from_shortcuts = True + self.app.inform.emit(_("Click on target point.")) + self.app.ui.add_slot_btn.setChecked(True) + + self.app.exc_editor.x = self.app.mouse[0] + self.app.exc_editor.y = self.app.mouse[1] + + self.app.exc_editor.select_tool('slot_add') + return + # Propagate to tool response = None if self.app.exc_editor.active_tool is not None: @@ -5254,6 +5278,8 @@ class ExcellonEditorPrefGroupUI(OptionsGroupUI): grid0.addWidget(self.drill_circular_angle_label, 9, 0) grid0.addWidget(self.drill_circular_angle_entry, 9, 1) + # ##### SLOTS ##### + # ################# self.drill_array_circ_label = QtWidgets.QLabel(_('Slots:')) grid0.addWidget(self.drill_array_circ_label, 10, 0, 1, 2) @@ -5302,6 +5328,87 @@ class ExcellonEditorPrefGroupUI(OptionsGroupUI): grid0.addWidget(self.slot_angle_label, 13, 0) grid0.addWidget(self.slot_angle_spinner, 13, 1) + # #### SLOTS ARRAY ####### + # ######################## + + self.slot_array_linear_label = QtWidgets.QLabel(_('Linear Slot Array:')) + grid0.addWidget(self.slot_array_linear_label, 14, 0, 1, 2) + + # Number of slot holes in a drill array + self.slot_array_size_label = QtWidgets.QLabel(_('Nr of slots:')) + self.drill_array_size_label.setToolTip( + _("Specify how many slots to be in the array.") + ) + # self.slot_array_size_label.setMinimumWidth(100) + + self.slot_array_size_entry = LengthEntry() + + grid0.addWidget(self.slot_array_size_label, 15, 0) + grid0.addWidget(self.slot_array_size_entry, 15, 1) + + # Linear Slot Array direction + self.slot_array_axis_label = QtWidgets.QLabel(_('Linear Dir.:')) + self.slot_array_axis_label.setToolTip( + _("Direction on which the linear array is oriented:\n" + "- 'X' - horizontal axis \n" + "- 'Y' - vertical axis or \n" + "- 'Angle' - a custom angle for the array inclination") + ) + # self.slot_axis_label.setMinimumWidth(100) + self.slot_array_axis_radio = RadioSet([{'label': _('X'), 'value': 'X'}, + {'label': _('Y'), 'value': 'Y'}, + {'label': _('Angle'), 'value': 'A'}]) + + grid0.addWidget(self.slot_array_axis_label, 16, 0) + grid0.addWidget(self.slot_array_axis_radio, 16, 1) + + # Linear Slot Array pitch distance + self.slot_array_pitch_label = QtWidgets.QLabel(_('Pitch:')) + self.slot_array_pitch_label.setToolTip( + _("Pitch = Distance between elements of the array.") + ) + # self.drill_pitch_label.setMinimumWidth(100) + self.slot_array_pitch_entry = LengthEntry() + + grid0.addWidget(self.slot_array_pitch_label, 17, 0) + grid0.addWidget(self.slot_array_pitch_entry, 17, 1) + + # Linear Slot Array custom angle + self.slot_array_angle_label = QtWidgets.QLabel(_('Angle:')) + self.slot_array_angle_label.setToolTip( + _("Angle at which each element in circular array is placed.") + ) + self.slot_array_angle_entry = LengthEntry() + + grid0.addWidget(self.slot_array_angle_label, 18, 0) + grid0.addWidget(self.slot_array_angle_entry, 18, 1) + + self.slot_array_circ_label = QtWidgets.QLabel(_('Circular Slot Array:')) + grid0.addWidget(self.slot_array_circ_label, 19, 0, 1, 2) + + # Circular Slot Array direction + self.slot_array_circular_direction_label = QtWidgets.QLabel(_('Circular Dir.:')) + self.slot_array_circular_direction_label.setToolTip( + _("Direction for circular array.\n" + "Can be CW = clockwise or CCW = counter clockwise.") + ) + + self.slot_array_circular_dir_radio = RadioSet([{'label': _('CW'), 'value': 'CW'}, + {'label': _('CCW'), 'value': 'CCW'}]) + + grid0.addWidget(self.slot_array_circular_direction_label, 20, 0) + grid0.addWidget(self.slot_array_circular_dir_radio, 20, 1) + + # Circular Slot Array Angle + self.slot_array_circular_angle_label = QtWidgets.QLabel(_('Circ. Angle:')) + self.slot_array_circular_angle_label.setToolTip( + _("Angle at which each element in circular array is placed.") + ) + self.slot_array_circular_angle_entry = LengthEntry() + + grid0.addWidget(self.slot_array_circular_angle_label, 21, 0) + grid0.addWidget(self.slot_array_circular_angle_entry, 21, 1) + self.layout.addStretch()