Jelajahi Sumber

Merged marius_stanciu/flatcam_beta/Beta_8.993 into Beta

Marius Stanciu 5 tahun lalu
induk
melakukan
b7fb18984e

+ 2 - 1
CHANGELOG.md

@@ -10,7 +10,8 @@ CHANGELOG for FlatCAM beta
 9.05.2020
 
 - modified the GUI for Exclusion areas; now the shapes are displayed in a Table where they can be selected and deleted. Modification applied for Geometry Objects only (for now).
-- fixed and error when converting units, error that acted when in those fields that accept lists of tools only one tool was added
+- fixed an error when converting units, error that acted when in those fields that accept lists of tools only one tool was added
+- finished the GUI for exclusion areas both in the Excellon and Geometry Objects. Need to think if to make it visible only in Advanced Mode
 
 8.05.2020
 

+ 5 - 0
flatcamGUI/GUIElements.py

@@ -2232,6 +2232,7 @@ class OptionalHideInputSection:
 class FCTable(QtWidgets.QTableWidget):
 
     drag_drop_sig = QtCore.pyqtSignal()
+    lost_focus = QtCore.pyqtSignal()
 
     def __init__(self, drag_drop=False, protected_rows=None, parent=None):
         super(FCTable, self).__init__(parent)
@@ -2295,6 +2296,10 @@ class FCTable(QtWidgets.QTableWidget):
         else:
             QtWidgets.QTableWidget.mousePressEvent(self, event)
 
+    def focusOutEvent(self, event):
+        self.lost_focus.emit()
+        super().focusOutEvent(event)
+
     def setupContextMenu(self):
         self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
 

+ 73 - 44
flatcamGUI/ObjectUI.py

@@ -1292,6 +1292,10 @@ class ExcellonObjectUI(ObjectUI):
         self.grid5.addWidget(pp_geo_label, 16, 0)
         self.grid5.addWidget(self.pp_geo_name_cb, 16, 1)
 
+        # ------------------------------------------------------------------------------------------------------------
+        # ------------------------- EXCLUSION AREAS ------------------------------------------------------------------
+        # ------------------------------------------------------------------------------------------------------------
+
         # Exclusion Areas
         self.exclusion_cb = FCCheckBox('%s' % _("Add exclusion areas"))
         self.exclusion_cb.setToolTip(
@@ -1301,48 +1305,39 @@ class ExcellonObjectUI(ObjectUI):
                 "is forbidden."
             )
         )
-        self.grid5.addWidget(self.exclusion_cb, 17, 0, 1, 2)
+        self.grid5.addWidget(self.exclusion_cb, 20, 0, 1, 2)
 
-        # ------------------------------------------------------------------------------------------------------------
-        # ------------------------- EXCLUSION AREAS ------------------------------------------------------------------
-        # ------------------------------------------------------------------------------------------------------------
         self.exclusion_frame = QtWidgets.QFrame()
         self.exclusion_frame.setContentsMargins(0, 0, 0, 0)
-        self.grid5.addWidget(self.exclusion_frame, 18, 0, 1, 2)
+        self.grid5.addWidget(self.exclusion_frame, 22, 0, 1, 2)
 
         self.exclusion_box = QtWidgets.QVBoxLayout()
         self.exclusion_box.setContentsMargins(0, 0, 0, 0)
         self.exclusion_frame.setLayout(self.exclusion_box)
 
-        h_lay = QtWidgets.QHBoxLayout()
-        self.exclusion_box.addLayout(h_lay)
-
-        # Button Add Area
-        self.add_area_button = QtWidgets.QPushButton(_('Add area'))
-        self.add_area_button.setToolTip(_("Add an Exclusion Area."))
-        h_lay.addWidget(self.add_area_button)
-
-        # Button Delete Area
-        self.delete_area_button = QtWidgets.QPushButton(_('Clear areas'))
-        self.delete_area_button.setToolTip(_("Delete all exclusion areas."))
-        h_lay.addWidget(self.delete_area_button)
+        self.exclusion_table = FCTable()
+        self.exclusion_box.addWidget(self.exclusion_table)
+        self.exclusion_table.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
 
-        grid_l = QtWidgets.QGridLayout()
-        grid_l.setColumnStretch(0, 0)
-        grid_l.setColumnStretch(1, 1)
-        self.exclusion_box.addLayout(grid_l)
+        self.exclusion_table.setColumnCount(4)
+        self.exclusion_table.setColumnWidth(0, 20)
+        self.exclusion_table.setHorizontalHeaderLabels(['#', _('Object'), _('Strategy'), _('Over Z')])
 
-        # Area Selection shape
-        self.area_shape_label = QtWidgets.QLabel('%s:' % _("Shape"))
-        self.area_shape_label.setToolTip(
-            _("The kind of selection shape used for area selection.")
-        )
+        self.exclusion_table.horizontalHeaderItem(0).setToolTip(_("This is the Area ID."))
+        self.exclusion_table.horizontalHeaderItem(1).setToolTip(
+            _("Type of the object where the exclusion area was added."))
+        self.exclusion_table.horizontalHeaderItem(2).setToolTip(
+            _("The strategy used for exclusion area. Go around the exclusion areas or over it."))
+        self.exclusion_table.horizontalHeaderItem(3).setToolTip(
+            _("If the strategy is to go over the area then this is the height at which the tool will go to avoid the "
+              "exclusion area."))
 
-        self.area_shape_radio = RadioSet([{'label': _("Square"), 'value': 'square'},
-                                          {'label': _("Polygon"), 'value': 'polygon'}])
+        self.exclusion_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
 
-        grid_l.addWidget(self.area_shape_label, 0, 0)
-        grid_l.addWidget(self.area_shape_radio, 0, 1)
+        grid_a1 = QtWidgets.QGridLayout()
+        grid_a1.setColumnStretch(0, 0)
+        grid_a1.setColumnStretch(1, 1)
+        self.exclusion_box.addLayout(grid_a1)
 
         # Chose Strategy
         self.strategy_label = FCLabel('%s:' % _("Strategy"))
@@ -1353,8 +1348,8 @@ class ExcellonObjectUI(ObjectUI):
         self.strategy_radio = RadioSet([{'label': _('Over'), 'value': 'over'},
                                         {'label': _('Around'), 'value': 'around'}])
 
-        grid_l.addWidget(self.strategy_label, 1, 0)
-        grid_l.addWidget(self.strategy_radio, 1, 1)
+        grid_a1.addWidget(self.strategy_label, 1, 0)
+        grid_a1.addWidget(self.strategy_radio, 1, 1)
 
         # Over Z
         self.over_z_label = FCLabel('%s:' % _("Over Z"))
@@ -1364,17 +1359,45 @@ class ExcellonObjectUI(ObjectUI):
         self.over_z_entry.set_range(0.000, 9999.9999)
         self.over_z_entry.set_precision(self.decimals)
 
-        grid_l.addWidget(self.over_z_label, 2, 0)
-        grid_l.addWidget(self.over_z_entry, 2, 1)
+        grid_a1.addWidget(self.over_z_label, 2, 0)
+        grid_a1.addWidget(self.over_z_entry, 2, 1)
 
+        # Button Add Area
+        self.add_area_button = QtWidgets.QPushButton(_('Add area:'))
+        self.add_area_button.setToolTip(_("Add an Exclusion Area."))
+
+        # Area Selection shape
+        self.area_shape_radio = RadioSet([{'label': _("Square"), 'value': 'square'},
+                                          {'label': _("Polygon"), 'value': 'polygon'}])
+        self.area_shape_radio.setToolTip(
+            _("The kind of selection shape used for area selection.")
+        )
+
+        grid_a1.addWidget(self.add_area_button, 4, 0)
+        grid_a1.addWidget(self.area_shape_radio, 4, 1)
+
+        h_lay_1 = QtWidgets.QHBoxLayout()
+        self.exclusion_box.addLayout(h_lay_1)
+
+        # Button Delete All Areas
+        self.delete_area_button = QtWidgets.QPushButton(_('Delete All'))
+        self.delete_area_button.setToolTip(_("Delete all exclusion areas."))
+
+        # Button Delete Selected Areas
+        self.delete_sel_area_button = QtWidgets.QPushButton(_('Delete Selected'))
+        self.delete_sel_area_button.setToolTip(_("Delete all exclusion areas that are selected in the table."))
+
+        h_lay_1.addWidget(self.delete_area_button)
+        h_lay_1.addWidget(self.delete_sel_area_button)
+
+        self.ois_exclusion_exc = OptionalHideInputSection(self.exclusion_cb, [self.exclusion_frame])
         # -------------------------- EXCLUSION AREAS END -------------------------------------------------------------
         # ------------------------------------------------------------------------------------------------------------
-        self.ois_exclusion_geo = OptionalHideInputSection(self.exclusion_cb, [self.exclusion_frame])
 
         separator_line = QtWidgets.QFrame()
         separator_line.setFrameShape(QtWidgets.QFrame.HLine)
         separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
-        self.grid5.addWidget(separator_line, 19, 0, 1, 2)
+        self.grid5.addWidget(separator_line, 25, 0, 1, 2)
 
         # #################################################################
         # ################# GRID LAYOUT 6   ###############################
@@ -1391,7 +1414,7 @@ class ExcellonObjectUI(ObjectUI):
                 "for custom selection of tools."
             ))
 
-        self.grid6.addWidget(QtWidgets.QLabel(''), 1, 0, 1, 3)
+        # self.grid6.addWidget(QtWidgets.QLabel(''), 1, 0, 1, 3)
         self.grid6.addWidget(warning_lbl, 2, 0, 1, 3)
 
         self.generate_cnc_button = QtWidgets.QPushButton(_('Generate CNCJob object'))
@@ -2103,6 +2126,10 @@ class GeometryObjectUI(ObjectUI):
 
         # grid4.addWidget(QtWidgets.QLabel(''), 12, 0, 1, 2)
 
+        # ------------------------------------------------------------------------------------------------------------
+        # ------------------------- EXCLUSION AREAS ------------------------------------------------------------------
+        # ------------------------------------------------------------------------------------------------------------
+
         # Exclusion Areas
         self.exclusion_cb = FCCheckBox('%s' % _("Add exclusion areas"))
         self.exclusion_cb.setToolTip(
@@ -2114,9 +2141,6 @@ class GeometryObjectUI(ObjectUI):
         )
         grid4.addWidget(self.exclusion_cb, 12, 0, 1, 2)
 
-        # ------------------------------------------------------------------------------------------------------------
-        # ------------------------- EXCLUSION AREAS ------------------------------------------------------------------
-        # ------------------------------------------------------------------------------------------------------------
         self.exclusion_frame = QtWidgets.QFrame()
         self.exclusion_frame.setContentsMargins(0, 0, 0, 0)
         grid4.addWidget(self.exclusion_frame, 14, 0, 1, 2)
@@ -2173,7 +2197,7 @@ class GeometryObjectUI(ObjectUI):
         grid_a1.addWidget(self.over_z_entry, 2, 1)
 
         # Button Add Area
-        self.add_area_button = QtWidgets.QPushButton(_('Add area'))
+        self.add_area_button = QtWidgets.QPushButton(_('Add area:'))
         self.add_area_button.setToolTip(_("Add an Exclusion Area."))
 
         # Area Selection shape
@@ -2190,7 +2214,7 @@ class GeometryObjectUI(ObjectUI):
         self.exclusion_box.addLayout(h_lay_1)
 
         # Button Delete All Areas
-        self.delete_area_button = QtWidgets.QPushButton(_('Clear areas'))
+        self.delete_area_button = QtWidgets.QPushButton(_('Delete All'))
         self.delete_area_button.setToolTip(_("Delete all exclusion areas."))
 
         # Button Delete Selected Areas
@@ -2200,9 +2224,14 @@ class GeometryObjectUI(ObjectUI):
         h_lay_1.addWidget(self.delete_area_button)
         h_lay_1.addWidget(self.delete_sel_area_button)
 
+        self.ois_exclusion_geo = OptionalHideInputSection(self.exclusion_cb, [self.exclusion_frame])
         # -------------------------- EXCLUSION AREAS END -------------------------------------------------------------
         # ------------------------------------------------------------------------------------------------------------
-        self.ois_exclusion_geo = OptionalHideInputSection(self.exclusion_cb, [self.exclusion_frame])
+
+        separator_line2 = QtWidgets.QFrame()
+        separator_line2.setFrameShape(QtWidgets.QFrame.HLine)
+        separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
+        grid4.addWidget(separator_line2, 15, 0, 1, 2)
 
         warning_lbl = QtWidgets.QLabel(
             _(
@@ -2210,7 +2239,7 @@ class GeometryObjectUI(ObjectUI):
                 "Click the # header to select all, or Ctrl + LMB\n"
                 "for custom selection of tools."
             ))
-        grid4.addWidget(warning_lbl, 15, 0, 1, 2)
+        grid4.addWidget(warning_lbl, 16, 0, 1, 2)
 
         # Button
         self.generate_cnc_button = QtWidgets.QPushButton(_('Generate CNCJob object'))

+ 161 - 0
flatcamObjects/FlatCAMExcellon.py

@@ -125,6 +125,10 @@ class ExcellonObject(FlatCAMObj, Excellon):
         self.outline_color = self.app.defaults['excellon_plot_line']
         self.alpha_level = 'bf'
 
+        # store here the state of the exclusion checkbox state to be restored after building the UI
+        # TODO add this in the sel.app.defaults dict and in Preferences
+        self.exclusion_area_cb_is_checked = False
+
         # Attributes to be included in serialization
         # Always append to it because it carries contents
         # from predecessors.
@@ -314,6 +318,15 @@ class ExcellonObject(FlatCAMObj, Excellon):
     def build_ui(self):
         FlatCAMObj.build_ui(self)
 
+        # Area Exception - exclusion shape added signal
+        # first disconnect it from any other object
+        try:
+            self.app.exc_areas.e_shape_modified.disconnect()
+        except (TypeError, AttributeError):
+            pass
+        # then connect it to the current build_ui() method
+        self.app.exc_areas.e_shape_modified.connect(self.update_exclusion_table)
+
         self.units = self.app.defaults['units'].upper()
 
         for row in range(self.ui.tools_table.rowCount()):
@@ -514,6 +527,58 @@ class ExcellonObject(FlatCAMObj, Excellon):
                 "<b>%s: <font color='#0000FF'>%s</font></b>" % (_('Parameters for'), _("Multiple Tools"))
             )
 
+        # Build Exclusion Areas section
+        e_len = len(self.app.exc_areas.exclusion_areas_storage)
+        self.ui.exclusion_table.setRowCount(e_len)
+
+        area_id = 0
+
+        for area in range(e_len):
+            area_id += 1
+
+            area_dict = self.app.exc_areas.exclusion_areas_storage[area]
+
+            area_id_item = QtWidgets.QTableWidgetItem('%d' % int(area_id))
+            area_id_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
+            self.ui.exclusion_table.setItem(area, 0, area_id_item)  # Area id
+
+            object_item = QtWidgets.QTableWidgetItem('%s' % area_dict["obj_type"])
+            object_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
+            self.ui.exclusion_table.setItem(area, 1, object_item)  # Origin Object
+
+            strategy_item = QtWidgets.QTableWidgetItem('%s' % area_dict["strategy"])
+            strategy_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
+            self.ui.exclusion_table.setItem(area, 2, strategy_item)  # Strategy
+
+            overz_item = QtWidgets.QTableWidgetItem('%s' % area_dict["overz"])
+            overz_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
+            self.ui.exclusion_table.setItem(area, 3, overz_item)  # Over Z
+
+        self.ui.exclusion_table.resizeColumnsToContents()
+        self.ui.exclusion_table.resizeRowsToContents()
+
+        area_vheader = self.ui.exclusion_table.verticalHeader()
+        area_vheader.hide()
+        self.ui.exclusion_table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+
+        area_hheader = self.ui.exclusion_table.horizontalHeader()
+        area_hheader.setMinimumSectionSize(10)
+        area_hheader.setDefaultSectionSize(70)
+
+        area_hheader.setSectionResizeMode(0, QtWidgets.QHeaderView.Fixed)
+        area_hheader.resizeSection(0, 20)
+        area_hheader.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
+        area_hheader.setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeToContents)
+        area_hheader.setSectionResizeMode(3, QtWidgets.QHeaderView.ResizeToContents)
+
+        # area_hheader.setStretchLastSection(True)
+        self.ui.exclusion_table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+
+        self.ui.exclusion_table.setColumnWidth(0, 20)
+
+        self.ui.exclusion_table.setMinimumHeight(self.ui.exclusion_table.getHeight())
+        self.ui.exclusion_table.setMaximumHeight(self.ui.exclusion_table.getHeight())
+
         self.ui_connect()
 
     def set_ui(self, ui):
@@ -632,14 +697,21 @@ class ExcellonObject(FlatCAMObj, Excellon):
 
         assert isinstance(self.ui, ExcellonObjectUI), \
             "Expected a ExcellonObjectUI, got %s" % type(self.ui)
+
         self.ui.plot_cb.stateChanged.connect(self.on_plot_cb_click)
         self.ui.solid_cb.stateChanged.connect(self.on_solid_cb_click)
         self.ui.generate_cnc_button.clicked.connect(self.on_create_cncjob_button_click)
         self.ui.generate_milling_button.clicked.connect(self.on_generate_milling_button_click)
         self.ui.generate_milling_slots_button.clicked.connect(self.on_generate_milling_slots_button_click)
 
+        # Exclusion areas signals
+        self.ui.exclusion_table.horizontalHeader().sectionClicked.connect(self.exclusion_table_toggle_all)
+        self.ui.exclusion_table.lost_focus.connect(self.clear_selection)
+        self.ui.exclusion_table.itemClicked.connect(self.draw_sel_shape)
         self.ui.add_area_button.clicked.connect(self.on_add_area_click)
         self.ui.delete_area_button.clicked.connect(self.on_clear_area_click)
+        self.ui.delete_sel_area_button.clicked.connect(self.on_delete_sel_areas)
+        self.ui.strategy_radio.activated_custom.connect(self.on_strategy)
 
         self.on_operation_type(val='drill')
         self.ui.operation_radio.activated_custom.connect(self.on_operation_type)
@@ -1487,7 +1559,96 @@ class ExcellonObject(FlatCAMObj, Excellon):
             solid_geo=solid_geo, obj_type=obj_type)
 
     def on_clear_area_click(self):
+        if not self.app.exc_areas.exclusion_areas_storage:
+            self.app.inform.emit("[WARNING_NOTCL] %s" % _("Delete failed. There are no exclusion areas to delete."))
+            return
+
         self.app.exc_areas.on_clear_area_click()
+        self.app.exc_areas.e_shape_modified.emit()
+
+    def on_delete_sel_areas(self):
+        sel_model = self.ui.exclusion_table.selectionModel()
+        sel_indexes = sel_model.selectedIndexes()
+
+        # it will iterate over all indexes which means all items in all columns too but I'm interested only on rows
+        # so the duplicate rows will not be added
+        sel_rows = set()
+        for idx in sel_indexes:
+            sel_rows.add(idx.row())
+
+        if not sel_rows:
+            self.app.inform.emit("[WARNING_NOTCL] %s" % _("Delete failed. Nothing is selected."))
+            return
+
+        self.app.exc_areas.delete_sel_shapes(idxs=list(sel_rows))
+        self.app.exc_areas.e_shape_modified.emit()
+
+    def draw_sel_shape(self):
+        sel_model = self.ui.exclusion_table.selectionModel()
+        sel_indexes = sel_model.selectedIndexes()
+
+        # it will iterate over all indexes which means all items in all columns too but I'm interested only on rows
+        sel_rows = set()
+        for idx in sel_indexes:
+            sel_rows.add(idx.row())
+
+        self.delete_sel_shape()
+
+        if self.app.is_legacy is False:
+            face = self.app.defaults['global_sel_fill'][:-2] + str(hex(int(0.2 * 255)))[2:]
+            outline = self.app.defaults['global_sel_line'][:-2] + str(hex(int(0.8 * 255)))[2:]
+        else:
+            face = self.app.defaults['global_sel_fill'][:-2] + str(hex(int(0.4 * 255)))[2:]
+            outline = self.app.defaults['global_sel_line'][:-2] + str(hex(int(1.0 * 255)))[2:]
+
+        for row in sel_rows:
+            sel_rect = self.app.exc_areas.exclusion_areas_storage[row]['shape']
+            self.app.move_tool.sel_shapes.add(sel_rect, color=outline, face_color=face, update=True, layer=0,
+                                              tolerance=None)
+        if self.app.is_legacy is True:
+            self.app.move_tool.sel_shapes.redraw()
+
+    def clear_selection(self):
+        self.app.delete_selection_shape()
+        # self.ui.exclusion_table.clearSelection()
+
+    def delete_sel_shape(self):
+        self.app.delete_selection_shape()
+
+    def update_exclusion_table(self):
+        self.exclusion_area_cb_is_checked = True if self.ui.exclusion_cb.isChecked() else False
+
+        self.build_ui()
+        self.ui.exclusion_cb.set_value(self.exclusion_area_cb_is_checked)
+
+    def on_strategy(self, val):
+        if val == 'around':
+            self.ui.over_z_label.setDisabled(True)
+            self.ui.over_z_entry.setDisabled(True)
+        else:
+            self.ui.over_z_label.setDisabled(False)
+            self.ui.over_z_entry.setDisabled(False)
+
+    def exclusion_table_toggle_all(self):
+        """
+        will toggle the selection of all rows in Exclusion Areas table
+
+        :return:
+        """
+        sel_model = self.ui.exclusion_table.selectionModel()
+        sel_indexes = sel_model.selectedIndexes()
+
+        # it will iterate over all indexes which means all items in all columns too but I'm interested only on rows
+        sel_rows = set()
+        for idx in sel_indexes:
+            sel_rows.add(idx.row())
+
+        if sel_rows:
+            self.ui.exclusion_table.clearSelection()
+            self.delete_sel_shape()
+        else:
+            self.ui.exclusion_table.selectAll()
+            self.draw_sel_shape()
 
     def on_solid_cb_click(self, *args):
         if self.muted_ui:

+ 85 - 3
flatcamObjects/FlatCAMGeometry.py

@@ -150,6 +150,10 @@ class GeometryObject(FlatCAMObj, Geometry):
 
         self.param_fields = {}
 
+        # store here the state of the exclusion checkbox state to be restored after building the UI
+        # TODO add this in the sel.app.defaults dict and in Preferences
+        self.exclusion_area_cb_is_checked = False
+
         # Attributes to be included in serialization
         # Always append to it because it carries contents
         # from predecessors.
@@ -166,7 +170,7 @@ class GeometryObject(FlatCAMObj, Geometry):
         except (TypeError, AttributeError):
             pass
         # then connect it to the current build_ui() method
-        self.app.exc_areas.e_shape_modified.connect(self.build_ui)
+        self.app.exc_areas.e_shape_modified.connect(self.update_exclusion_table)
 
         self.units = self.app.defaults['units']
 
@@ -594,11 +598,14 @@ class GeometryObject(FlatCAMObj, Geometry):
         self.ui.apply_param_to_all.clicked.connect(self.on_apply_param_to_all_clicked)
         self.ui.cutz_entry.returnPressed.connect(self.on_cut_z_changed)
 
-        # Exclusion areas
-        self.ui.exclusion_table.horizontalHeader().sectionClicked.connect(self.ui.exclusion_table.selectAll)
+        # Exclusion areas signals
+        self.ui.exclusion_table.horizontalHeader().sectionClicked.connect(self.exclusion_table_toggle_all)
+        self.ui.exclusion_table.lost_focus.connect(self.clear_selection)
+        self.ui.exclusion_table.itemClicked.connect(self.draw_sel_shape)
         self.ui.add_area_button.clicked.connect(self.on_add_area_click)
         self.ui.delete_area_button.clicked.connect(self.on_clear_area_click)
         self.ui.delete_sel_area_button.clicked.connect(self.on_delete_sel_areas)
+        self.ui.strategy_radio.activated_custom.connect(self.on_strategy)
 
     def on_cut_z_changed(self):
         self.old_cutz = self.ui.cutz_entry.get_value()
@@ -2525,6 +2532,10 @@ class GeometryObject(FlatCAMObj, Geometry):
             solid_geo=solid_geo, obj_type=obj_type)
 
     def on_clear_area_click(self):
+        if not self.app.exc_areas.exclusion_areas_storage:
+            self.app.inform.emit("[WARNING_NOTCL] %s" % _("Delete failed. There are no exclusion areas to delete."))
+            return
+
         self.app.exc_areas.on_clear_area_click()
         self.app.exc_areas.e_shape_modified.emit()
 
@@ -2538,9 +2549,80 @@ class GeometryObject(FlatCAMObj, Geometry):
         for idx in sel_indexes:
             sel_rows.add(idx.row())
 
+        if not sel_rows:
+            self.app.inform.emit("[WARNING_NOTCL] %s" % _("Delete failed. Nothing is selected."))
+            return
+
         self.app.exc_areas.delete_sel_shapes(idxs=list(sel_rows))
         self.app.exc_areas.e_shape_modified.emit()
 
+    def draw_sel_shape(self):
+        sel_model = self.ui.exclusion_table.selectionModel()
+        sel_indexes = sel_model.selectedIndexes()
+
+        # it will iterate over all indexes which means all items in all columns too but I'm interested only on rows
+        sel_rows = set()
+        for idx in sel_indexes:
+            sel_rows.add(idx.row())
+
+        self.delete_sel_shape()
+
+        if self.app.is_legacy is False:
+            face = self.app.defaults['global_sel_fill'][:-2] + str(hex(int(0.2 * 255)))[2:]
+            outline = self.app.defaults['global_sel_line'][:-2] + str(hex(int(0.8 * 255)))[2:]
+        else:
+            face = self.app.defaults['global_sel_fill'][:-2] + str(hex(int(0.4 * 255)))[2:]
+            outline = self.app.defaults['global_sel_line'][:-2] + str(hex(int(1.0 * 255)))[2:]
+
+        for row in sel_rows:
+            sel_rect = self.app.exc_areas.exclusion_areas_storage[row]['shape']
+            self.app.move_tool.sel_shapes.add(sel_rect, color=outline, face_color=face, update=True, layer=0,
+                                              tolerance=None)
+        if self.app.is_legacy is True:
+            self.app.move_tool.sel_shapes.redraw()
+
+    def clear_selection(self):
+        self.app.delete_selection_shape()
+        # self.ui.exclusion_table.clearSelection()
+
+    def delete_sel_shape(self):
+        self.app.delete_selection_shape()
+
+    def update_exclusion_table(self):
+        self.exclusion_area_cb_is_checked = True if self.ui.exclusion_cb.isChecked() else False
+
+        self.build_ui()
+        self.ui.exclusion_cb.set_value(self.exclusion_area_cb_is_checked)
+
+    def on_strategy(self, val):
+        if val == 'around':
+            self.ui.over_z_label.setDisabled(True)
+            self.ui.over_z_entry.setDisabled(True)
+        else:
+            self.ui.over_z_label.setDisabled(False)
+            self.ui.over_z_entry.setDisabled(False)
+
+    def exclusion_table_toggle_all(self):
+        """
+        will toggle the selection of all rows in Exclusion Areas table
+
+        :return:
+        """
+        sel_model = self.ui.exclusion_table.selectionModel()
+        sel_indexes = sel_model.selectedIndexes()
+
+        # it will iterate over all indexes which means all items in all columns too but I'm interested only on rows
+        sel_rows = set()
+        for idx in sel_indexes:
+            sel_rows.add(idx.row())
+
+        if sel_rows:
+            self.ui.exclusion_table.clearSelection()
+            self.delete_sel_shape()
+        else:
+            self.ui.exclusion_table.selectAll()
+            self.draw_sel_shape()
+
     def plot_element(self, element, color=None, visible=None):
 
         if color is None:

+ 1 - 3
flatcamObjects/FlatCAMObj.py

@@ -186,11 +186,9 @@ class FlatCAMObj(QtCore.QObject):
 
     def build_ui(self):
         """
-        Sets up the UI/form for this object. Show the UI
-        in the App.
+        Sets up the UI/form for this object. Show the UI in the App.
 
         :return: None
-        :rtype: None
         """
 
         self.muted_ui = True