diff --git a/FlatCAMObj.py b/FlatCAMObj.py index 16d417e5..375dc655 100644 --- a/FlatCAMObj.py +++ b/FlatCAMObj.py @@ -420,6 +420,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber): self.multigeo = False + self.apertures_row = 0 + # assert isinstance(self.ui, GerberObjectUI) # self.ui.plot_cb.stateChanged.connect(self.on_plot_cb_click) # self.ui.solid_cb.stateChanged.connect(self.on_solid_cb_click) @@ -472,6 +474,126 @@ class FlatCAMGerber(FlatCAMObj, Gerber): self.ui.generate_bb_button.clicked.connect(self.on_generatebb_button_click) self.ui.generate_noncopper_button.clicked.connect(self.on_generatenoncopper_button_click) + self.build_ui() + + def build_ui(self): + FlatCAMObj.build_ui(self) + + try: + # if connected, disconnect the signal from the slot on item_changed as it creates issues + self.ui.apertures_table.itemChanged.disconnect() + except: + pass + + n = len(self.apertures) + len(self.aperture_macros) + self.ui.apertures_table.setRowCount(n) + + self.apertures_row = 0 + aper_no = self.apertures_row + 1 + sort = [] + for k, v in list(self.apertures.items()): + sort.append(int(k)) + sorted_apertures = sorted(sort) + + sort = [] + for k, v in list(self.aperture_macros.items()): + sort.append(int(k)) + sorted_macros = sorted(sort) + + for ap_code in sorted_apertures: + ap_code = str(ap_code) + + ap_id_item = QtWidgets.QTableWidgetItem('%d' % int(self.apertures_row + 1)) + ap_id_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.ui.apertures_table.setItem(self.apertures_row, 0, ap_id_item) # Tool name/id + + ap_code_item = QtWidgets.QTableWidgetItem(ap_code) + ap_code_item.setFlags(QtCore.Qt.ItemIsEnabled) + + ap_type_item = QtWidgets.QTableWidgetItem(str(self.apertures[ap_code]['type'])) + ap_type_item.setFlags(QtCore.Qt.ItemIsEnabled) + + if str(self.apertures[ap_code]['type']) == 'R' or str(self.apertures[ap_code]['type']) == 'O': + ap_dim_item = QtWidgets.QTableWidgetItem( + '%.4f, %.4f' % (self.apertures[ap_code]['width'], self.apertures[ap_code]['height'])) + ap_dim_item.setFlags(QtCore.Qt.ItemIsEnabled) + elif str(self.apertures[ap_code]['type']) == 'P': + ap_dim_item = QtWidgets.QTableWidgetItem( + '%.4f, %.4f' % (self.apertures[ap_code]['diam'], self.apertures[ap_code]['nVertices'])) + ap_dim_item.setFlags(QtCore.Qt.ItemIsEnabled) + else: + ap_dim_item = QtWidgets.QTableWidgetItem('') + ap_dim_item.setFlags(QtCore.Qt.ItemIsEnabled) + + ap_size_item = QtWidgets.QTableWidgetItem('%.4f' % float(self.apertures[ap_code]['size'])) + ap_size_item.setFlags(QtCore.Qt.ItemIsEnabled) + + plot_item = FCCheckBox() + plot_item.setLayoutDirection(QtCore.Qt.RightToLeft) + if self.ui.plot_cb.isChecked(): + plot_item.setChecked(True) + + self.ui.apertures_table.setItem(self.apertures_row, 1, ap_code_item) # Aperture Code + self.ui.apertures_table.setItem(self.apertures_row, 2, ap_type_item) # Aperture Type + self.ui.apertures_table.setItem(self.apertures_row, 3, ap_size_item) # Aperture Dimensions + self.ui.apertures_table.setItem(self.apertures_row, 4, ap_dim_item) # Aperture Dimensions + + self.ui.apertures_table.setCellWidget(self.apertures_row, 5, plot_item) + + self.apertures_row += 1 + + for ap_code in sorted_macros: + ap_code = str(ap_code) + + ap_id_item = QtWidgets.QTableWidgetItem('%d' % int(self.apertures_row + 1)) + ap_id_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.ui.apertures_table.setItem(self.apertures_row, 0, ap_id_item) # Tool name/id + + ap_code_item = QtWidgets.QTableWidgetItem(ap_code) + + ap_type_item = QtWidgets.QTableWidgetItem('AM') + ap_type_item.setFlags(QtCore.Qt.ItemIsEnabled) + + plot_item = FCCheckBox() + plot_item.setLayoutDirection(QtCore.Qt.RightToLeft) + if self.ui.plot_cb.isChecked(): + plot_item.setChecked(True) + + self.ui.apertures_table.setItem(self.apertures_row, 1, ap_code_item) # Aperture Code + self.ui.apertures_table.setItem(self.apertures_row, 2, ap_type_item) # Aperture Type + self.ui.apertures_table.setCellWidget(self.apertures_row, 5, plot_item) + + self.apertures_row += 1 + + self.ui.apertures_table.selectColumn(0) + # + self.ui.apertures_table.resizeColumnsToContents() + self.ui.apertures_table.resizeRowsToContents() + + vertical_header = self.ui.apertures_table.verticalHeader() + # vertical_header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents) + vertical_header.hide() + self.ui.apertures_table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + + horizontal_header = self.ui.apertures_table.horizontalHeader() + horizontal_header.setMinimumSectionSize(10) + horizontal_header.setDefaultSectionSize(70) + horizontal_header.setSectionResizeMode(0, QtWidgets.QHeaderView.Fixed) + horizontal_header.resizeSection(0, 20) + horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents) + horizontal_header.setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeToContents) + horizontal_header.setSectionResizeMode(3, QtWidgets.QHeaderView.ResizeToContents) + horizontal_header.setSectionResizeMode(4, QtWidgets.QHeaderView.Stretch) + horizontal_header.setSectionResizeMode(5, QtWidgets.QHeaderView.Fixed) + horizontal_header.resizeSection(5, 17) + self.ui.apertures_table.setColumnWidth(5, 17) + + self.ui.apertures_table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.ui.apertures_table.setSortingEnabled(False) + self.ui.apertures_table.setMinimumHeight(self.ui.apertures_table.getHeight()) + + # self.ui_connect() + def on_generatenoncopper_button_click(self, *args): self.app.report_usage("gerber_on_generatenoncopper_button") diff --git a/ObjectUI.py b/ObjectUI.py index 8a306719..fea35b81 100644 --- a/ObjectUI.py +++ b/ObjectUI.py @@ -32,15 +32,6 @@ class ObjectUI(QtWidgets.QWidget): self.title_label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) self.title_box.addWidget(self.title_label, stretch=1) - ## Object name - self.name_box = QtWidgets.QHBoxLayout() - layout.addLayout(self.name_box) - name_label = QtWidgets.QLabel("Name:") - self.name_box.addWidget(name_label) - self.name_entry = FCEntry() - self.name_box.addWidget(self.name_entry) - self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus) - ## Box box for custom widgets # This gets populated in offspring implementations. self.custom_box = QtWidgets.QVBoxLayout() @@ -118,20 +109,12 @@ class GerberObjectUI(ObjectUI): ObjectUI.__init__(self, title='Gerber Object', parent=parent) # Plot options - self.plot_options_label = QtWidgets.QLabel("Plot Options:") - self.custom_box.addWidget(self.plot_options_label) - grid0 = QtWidgets.QGridLayout() grid0.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) self.custom_box.addLayout(grid0) - # Plot CB - self.plot_cb = FCCheckBox(label='Plot ') - self.plot_options_label.setToolTip( - "Plot (show) this object." - ) - self.plot_cb.setFixedWidth(50) - grid0.addWidget(self.plot_cb, 0, 0) + self.plot_options_label = QtWidgets.QLabel("Plot Options:") + grid0.addWidget(self.plot_options_label, 0, 0) # Solid CB self.solid_cb = FCCheckBox(label='Solid ') @@ -149,6 +132,59 @@ class GerberObjectUI(ObjectUI): self.multicolored_cb.setFixedWidth(55) grid0.addWidget(self.multicolored_cb, 0, 2) + ## Object name + self.name_hlay = QtWidgets.QHBoxLayout() + self.custom_box.addLayout(self.name_hlay) + name_label = QtWidgets.QLabel("Name:") + self.name_entry = FCEntry() + self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus) + self.name_hlay.addWidget(name_label) + self.name_hlay.addWidget(self.name_entry) + + hlay_plot = QtWidgets.QHBoxLayout() + self.custom_box.addLayout(hlay_plot) + + #### Gerber Apertures #### + self.apertures_table_label = QtWidgets.QLabel('Apertures Table') + self.apertures_table_label.setToolTip( + "Apertures in this Gerber object." + ) + hlay_plot.addWidget(self.apertures_table_label) + + # Plot CB + self.plot_cb = FCCheckBox('Plot Object') + self.plot_cb.setToolTip( + "Plot (show) this object." + ) + self.plot_cb.setLayoutDirection(QtCore.Qt.RightToLeft) + hlay_plot.addStretch() + hlay_plot.addWidget(self.plot_cb) + + self.apertures_table = FCTable() + self.custom_box.addWidget(self.apertures_table) + + self.apertures_table.setColumnCount(6) + self.apertures_table.setHorizontalHeaderLabels(['#', 'D', 'Type', 'Size', 'Dim', 'P']) + self.apertures_table.setSortingEnabled(False) + + self.apertures_table.horizontalHeaderItem(0).setToolTip( + "Index") + self.apertures_table.horizontalHeaderItem(1).setToolTip( + "Aperture Code") + self.apertures_table.horizontalHeaderItem(2).setToolTip( + "Type of aperture: circular, rectangle, macros etc") + self.apertures_table.horizontalHeaderItem(4).setToolTip( + "Aperture Size:") + self.apertures_table.horizontalHeaderItem(4).setToolTip( + "Aperture Dimensions:\n" + " - (width, height) for R, O type.\n" + " - (dia, nVertices) for P type") + self.apertures_table.horizontalHeaderItem(5).setToolTip( + "Toggle display of the aperture instances.") + + self.empty_label = QtWidgets.QLabel('') + self.custom_box.addWidget(self.empty_label) + # Isolation Routing self.isolation_routing_label = QtWidgets.QLabel("Isolation Routing:") self.isolation_routing_label.setToolTip( @@ -271,20 +307,23 @@ class GerberObjectUI(ObjectUI): self.ois_iso = OptionalInputSection(self.follow_cb, [self.generate_int_iso_button, self.generate_ext_iso_button], logic=False) + grid2 = QtWidgets.QGridLayout() + self.custom_box.addLayout(grid2) + ## Clear non-copper regions self.clearcopper_label = QtWidgets.QLabel("Clear non-copper:") self.clearcopper_label.setToolTip( "Create a Geometry object with\n" "toolpaths to cut all non-copper regions." ) - self.custom_box.addWidget(self.clearcopper_label) + grid2.addWidget(self.clearcopper_label, 0, 0) self.generate_ncc_button = QtWidgets.QPushButton('Non-Copper Clear Tool') self.generate_ncc_button.setToolTip( "Create the Geometry Object\n" "for non-copper routing." ) - self.custom_box.addWidget(self.generate_ncc_button) + grid2.addWidget(self.generate_ncc_button, 0, 1) ## Board cutout self.board_cutout_label = QtWidgets.QLabel("Board cutout:") @@ -293,14 +332,14 @@ class GerberObjectUI(ObjectUI): "the PCB and separate it from\n" "the original board." ) - self.custom_box.addWidget(self.board_cutout_label) + grid2.addWidget(self.board_cutout_label, 1, 0) self.generate_cutout_button = QtWidgets.QPushButton('Cutout Tool') self.generate_cutout_button.setToolTip( "Generate the geometry for\n" "the board cutout." ) - self.custom_box.addWidget(self.generate_cutout_button) + grid2.addWidget(self.generate_cutout_button, 1, 1) ## Non-copper regions self.noncopper_label = QtWidgets.QLabel("Non-copper regions:") @@ -382,18 +421,26 @@ class ExcellonObjectUI(ObjectUI): parent=parent) #### Plot options #### + hlay_plot = QtWidgets.QHBoxLayout() + self.custom_box.addLayout(hlay_plot) self.plot_options_label = QtWidgets.QLabel("Plot Options:") - self.custom_box.addWidget(self.plot_options_label) - - grid0 = QtWidgets.QGridLayout() - self.custom_box.addLayout(grid0) - self.solid_cb = FCCheckBox(label='Solid') self.solid_cb.setToolTip( "Solid circles." ) - grid0.addWidget(self.solid_cb, 0, 0) + hlay_plot.addWidget(self.plot_options_label) + hlay_plot.addStretch() + hlay_plot.addWidget(self.solid_cb) + + ## Object name + self.name_hlay = QtWidgets.QHBoxLayout() + self.custom_box.addLayout(self.name_hlay) + name_label = QtWidgets.QLabel("Name:") + self.name_entry = FCEntry() + self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus) + self.name_hlay.addWidget(name_label) + self.name_hlay.addWidget(self.name_entry) # add a frame and inside add a vertical box layout. Inside this vbox layout I add all the Drills widgets # this way I can hide/show the frame @@ -697,8 +744,17 @@ class GeometryObjectUI(ObjectUI): super(GeometryObjectUI, self).__init__(title='Geometry Object', icon_file='share/geometry32.png', parent=parent) # Plot options - # self.plot_options_label = QtWidgets.QLabel("Plot Options:") - # self.custom_box.addWidget(self.plot_options_label) + self.plot_options_label = QtWidgets.QLabel("Plot Options:") + self.custom_box.addWidget(self.plot_options_label) + + ## Object name + self.name_hlay = QtWidgets.QHBoxLayout() + self.custom_box.addLayout(self.name_hlay) + name_label = QtWidgets.QLabel("Name:") + self.name_entry = FCEntry() + self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus) + self.name_hlay.addWidget(name_label) + self.name_hlay.addWidget(self.name_entry) # add a frame and inside add a vertical box layout. Inside this vbox layout I add all the Tools widgets # this way I can hide/show the frame @@ -1147,6 +1203,15 @@ class CNCObjectUI(ObjectUI): {"label": "Cut", "value": "cut"} ], stretch=False) + ## Object name + self.name_hlay = QtWidgets.QHBoxLayout() + self.custom_box.addLayout(self.name_hlay) + name_label = QtWidgets.QLabel("Name:") + self.name_entry = FCEntry() + self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus) + self.name_hlay.addWidget(name_label) + self.name_hlay.addWidget(self.name_entry) + f_lay = QtWidgets.QGridLayout() f_lay.setColumnStretch(1, 1) f_lay.setColumnStretch(2, 1) diff --git a/README.md b/README.md index 61bba35b..3c02bbea 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,9 @@ CAD program, and create G-Code for Isolation routing. - added new parameter for Excellon Object in Preferences: Fast Retract. If the checkbox is checked then after reaching the drill depth, the drill bit will be raised out of the hole asap. - started to work on GUI forms simplification - changed the Preferences GUI for Geometry and Excellon Objects to make a difference between parameters that are changed often and those that are not. +- changed the layout in the Selected Tab UI +- started to add apertures table support +- finished Gerber aperture table display 12.02.2019 diff --git a/camlib.py b/camlib.py index 92646975..ed568ae1 100644 --- a/camlib.py +++ b/camlib.py @@ -1845,7 +1845,7 @@ class Gerber (Geometry): +-----------+-----------------------------------+ * ``aperture_macros`` (dictionary): Are predefined geometrical structures - that can be instanciated with different parameters in an aperture + that can be instantiated with different parameters in an aperture definition. See ``apertures`` above. The key is the name of the macro, and the macro itself, the value, is a ``Aperture_Macro`` object.