diff --git a/CHANGELOG.md b/CHANGELOG.md index a0d03843..5875eff1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,12 +27,14 @@ CHANGELOG for FlatCAM beta - fixed Tcl command Paint - temporary fix for comboboxes not finding the the value in the items when setting themselves with a value by defaulting to the first item in the list - fix in Tool Subtract where there was a typo +- upgraded the punch Gerber Tool +- updated the Turkish translation strings (by Mehmet Kaya) 27.10.2020 - created custom classes derived from TextEdit and from LineEdit where I overloaded the context menu and I made all the other classes that were inheriting from them to inherit from those new classes - minor fix in ToolsDB2UI -- updated the Turkuish translation strings (by Mehmet Kaya) +- updated the Turkish translation strings (by Mehmet Kaya) - fixed a bug in conversion of any to Gerber in the section of Excellon conversion - some PEP8 fixes - fixed a bug due of recent chagnes in FileMenuHandlers class diff --git a/appObjects/FlatCAMGerber.py b/appObjects/FlatCAMGerber.py index 84fdb795..f7de5282 100644 --- a/appObjects/FlatCAMGerber.py +++ b/appObjects/FlatCAMGerber.py @@ -212,7 +212,7 @@ class GerberObject(FlatCAMObj, Gerber): self.apertures_row = 0 aper_no = self.apertures_row + 1 sort = [] - for k, v in list(self.apertures.items()): + for k in list(self.apertures.keys()): sort.append(int(k)) sorted_apertures = sorted(sort) diff --git a/appTools/ToolPunchGerber.py b/appTools/ToolPunchGerber.py index 060cac96..eab09f7b 100644 --- a/appTools/ToolPunchGerber.py +++ b/appTools/ToolPunchGerber.py @@ -8,7 +8,7 @@ from PyQt5 import QtCore, QtWidgets, QtGui from appTool import AppTool -from appGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, FCComboBox +from appGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, FCComboBox, FCTable from copy import deepcopy import logging @@ -45,6 +45,8 @@ class ToolPunchGerber(AppTool): self.ui.reset_button.clicked.connect(self.set_tool_ui) self.ui.punch_object_button.clicked.connect(self.on_generate_object) + self.ui.gerber_object_combo.currentIndexChanged.connect(self.build_tool_ui) + self.ui.circular_cb.stateChanged.connect( lambda state: self.ui.circular_ring_entry.setDisabled(False) if state else @@ -97,6 +99,7 @@ class ToolPunchGerber(AppTool): AppTool.run(self) self.set_tool_ui() + self.build_tool_ui() self.app.ui.notebook.setTabText(2, _("Punch Tool")) @@ -106,6 +109,7 @@ class ToolPunchGerber(AppTool): def set_tool_ui(self): self.reset_fields() + self.ui_disconnect() self.ui_connect() self.ui.method_punch.set_value(self.app.defaults["tools_punch_hole_type"]) self.ui.select_all_cb.set_value(False) @@ -126,6 +130,69 @@ class ToolPunchGerber(AppTool): self.ui.factor_entry.set_value(float(self.app.defaults["tools_punch_hole_prop_factor"])) + def build_tool_ui(self): + # get the Gerber file who is the source of the punched Gerber + selection_index = self.ui.gerber_object_combo.currentIndex() + model_index = self.app.collection.index(selection_index, 0, self.ui.gerber_object_combo.rootModelIndex()) + obj = None + + try: + obj = model_index.internalPointer().obj + sort = [int(k) for k in obj.apertures.keys()] + sorted_apertures = sorted(sort) + except Exception: + # no object loaded + sorted_apertures = [] + + n = len(sorted_apertures) + self.ui.apertures_table.setRowCount(n) + + row = 0 + for ap_code in sorted_apertures: + ap_code = str(ap_code) + + ap_code_item = QtWidgets.QTableWidgetItem(ap_code) + ap_code_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + + ap_type_item = QtWidgets.QTableWidgetItem(str(obj.apertures[ap_code]['type'])) + ap_type_item.setFlags(QtCore.Qt.ItemIsEnabled) + + try: + if obj.apertures[ap_code]['size'] is not None: + size_val = self.app.dec_format(float(obj.apertures[ap_code]['size']), self.decimals) + ap_size_item = QtWidgets.QTableWidgetItem(str(size_val)) + else: + ap_size_item = QtWidgets.QTableWidgetItem('') + except KeyError: + ap_size_item = QtWidgets.QTableWidgetItem('') + ap_size_item.setFlags(QtCore.Qt.ItemIsEnabled) + + self.ui.apertures_table.setItem(row, 0, ap_code_item) # Aperture Code + self.ui.apertures_table.setItem(row, 1, ap_type_item) # Aperture Type + self.ui.apertures_table.setItem(row, 2, ap_size_item) # Aperture Dimensions + + # increment row + row += 1 + + self.ui.apertures_table.resizeColumnsToContents() + self.ui.apertures_table.resizeRowsToContents() + + vertical_header = self.ui.apertures_table.verticalHeader() + 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.ResizeToContents) + horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents) + horizontal_header.setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch) + + 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.apertures_table.setMaximumHeight(self.ui.apertures_table.getHeight()) + def on_select_all(self, state): self.ui_disconnect() if state: @@ -143,29 +210,29 @@ class ToolPunchGerber(AppTool): self.ui_connect() def on_method(self, val): - self.ui.exc_label.setEnabled(False) - self.ui.exc_combo.setEnabled(False) - self.ui.fixed_label.setEnabled(False) - self.ui.dia_label.setEnabled(False) - self.ui.dia_entry.setEnabled(False) - self.ui.ring_frame.setEnabled(False) - self.ui.prop_label.setEnabled(False) - self.ui.factor_label.setEnabled(False) - self.ui.factor_entry.setEnabled(False) + self.ui.exc_label.hide() + self.ui.exc_combo.hide() + self.ui.fixed_label.hide() + self.ui.dia_label.hide() + self.ui.dia_entry.hide() + self.ui.ring_frame.hide() + self.ui.prop_label.hide() + self.ui.factor_label.hide() + self.ui.factor_entry.hide() if val == 'exc': - self.ui.exc_label.setEnabled(True) - self.ui.exc_combo.setEnabled(True) + self.ui.exc_label.show() + self.ui.exc_combo.show() elif val == 'fixed': - self.ui.fixed_label.setEnabled(True) - self.ui.dia_label.setEnabled(True) - self.ui.dia_entry.setEnabled(True) + self.ui.fixed_label.show() + self.ui.dia_label.show() + self.ui.dia_entry.show() elif val == 'ring': - self.ui.ring_frame.setEnabled(True) + self.ui.ring_frame.show() elif val == 'prop': - self.ui.prop_label.setEnabled(True) - self.ui.factor_label.setEnabled(True) - self.ui.factor_entry.setEnabled(True) + self.ui.prop_label.show() + self.ui.factor_label.show() + self.ui.factor_entry.show() def ui_connect(self): self.ui.select_all_cb.stateChanged.connect(self.on_select_all) @@ -192,97 +259,114 @@ class ToolPunchGerber(AppTool): outname = name + "_punched" punch_method = self.ui.method_punch.get_value() + if punch_method == 'exc': + self.on_excellon_method(grb_obj, outname) + elif punch_method == 'fixed': + self.on_fixed_method(grb_obj, outname) + elif punch_method == 'ring': + self.on_ring_method(grb_obj, outname) + elif punch_method == 'prop': + self.on_proportional_method(grb_obj, outname) + + def on_excellon_method(self, grb_obj, outname): + # get the Excellon file whose geometry will create the punch holes + selection_index = self.ui.exc_combo.currentIndex() + model_index = self.app.collection.index(selection_index, 0, self.ui.exc_combo.rootModelIndex()) + + try: + exc_obj = model_index.internalPointer().obj + except Exception: + self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Excellon object loaded ...")) + return new_options = {} for opt in grb_obj.options: new_options[opt] = deepcopy(grb_obj.options[opt]) - if punch_method == 'exc': + # this is the punching geometry + exc_solid_geometry = MultiPolygon(exc_obj.solid_geometry) + if isinstance(grb_obj.solid_geometry, list): + grb_solid_geometry = MultiPolygon(grb_obj.solid_geometry) + else: + grb_solid_geometry = grb_obj.solid_geometry - # get the Excellon file whose geometry will create the punch holes - selection_index = self.ui.exc_combo.currentIndex() - model_index = self.app.collection.index(selection_index, 0, self.ui.exc_combo.rootModelIndex()) + # create the punched Gerber solid_geometry + punched_solid_geometry = grb_solid_geometry.difference(exc_solid_geometry) - try: - exc_obj = model_index.internalPointer().obj - except Exception: - self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Excellon object loaded ...")) - return + # update the gerber apertures to include the clear geometry so it can be exported successfully + new_apertures = deepcopy(grb_obj.apertures) + new_apertures_items = new_apertures.items() - # this is the punching geometry - exc_solid_geometry = MultiPolygon(exc_obj.solid_geometry) - if isinstance(grb_obj.solid_geometry, list): - grb_solid_geometry = MultiPolygon(grb_obj.solid_geometry) - else: - grb_solid_geometry = grb_obj.solid_geometry + # find maximum aperture id + new_apid = max([int(x) for x, __ in new_apertures_items]) - # create the punched Gerber solid_geometry - punched_solid_geometry = grb_solid_geometry.difference(exc_solid_geometry) + # store here the clear geometry, the key is the drill size + holes_apertures = {} - # update the gerber apertures to include the clear geometry so it can be exported successfully - new_apertures = deepcopy(grb_obj.apertures) - new_apertures_items = new_apertures.items() + for apid, val in new_apertures_items: + for elem in val['geometry']: + # make it work only for Gerber Flashes who are Points in 'follow' + if 'solid' in elem and isinstance(elem['follow'], Point): + for tool in exc_obj.tools: + clear_apid_size = exc_obj.tools[tool]['tooldia'] - # find maximum aperture id - new_apid = max([int(x) for x, __ in new_apertures_items]) + if 'drills' in exc_obj.tools[tool]['drills']: + for drill_pt in exc_obj.tools[tool]['drills']: + # since there may be drills that do not drill into a pad we test only for + # drills in a pad + if drill_pt.within(elem['solid']): + geo_elem = {} + geo_elem['clear'] = drill_pt - # store here the clear geometry, the key is the drill size - holes_apertures = {} + if clear_apid_size not in holes_apertures: + holes_apertures[clear_apid_size] = {} + holes_apertures[clear_apid_size]['type'] = 'C' + holes_apertures[clear_apid_size]['size'] = clear_apid_size + holes_apertures[clear_apid_size]['geometry'] = [] - for apid, val in new_apertures_items: - for elem in val['geometry']: - # make it work only for Gerber Flashes who are Points in 'follow' - if 'solid' in elem and isinstance(elem['follow'], Point): - for tool in exc_obj.tools: - clear_apid_size = exc_obj.tools[tool]['tooldia'] + holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem)) - if 'drills' in exc_obj.tools[tool]['drills']: - for drill_pt in exc_obj.tools[tool]['drills']: - # since there may be drills that do not drill into a pad we test only for - # drills in a pad - if drill_pt.within(elem['solid']): - geo_elem = {} - geo_elem['clear'] = drill_pt + # add the clear geometry to new apertures; it's easier than to test if there are apertures with the same + # size and add there the clear geometry + for hole_size, ap_val in holes_apertures.items(): + new_apid += 1 + new_apertures[str(new_apid)] = deepcopy(ap_val) - if clear_apid_size not in holes_apertures: - holes_apertures[clear_apid_size] = {} - holes_apertures[clear_apid_size]['type'] = 'C' - holes_apertures[clear_apid_size]['size'] = clear_apid_size - holes_apertures[clear_apid_size]['geometry'] = [] + def init_func(new_obj, app_obj): + new_obj.options.update(new_options) + new_obj.options['name'] = outname + new_obj.fill_color = deepcopy(grb_obj.fill_color) + new_obj.outline_color = deepcopy(grb_obj.outline_color) - holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem)) + new_obj.apertures = deepcopy(new_apertures) - # add the clear geometry to new apertures; it's easier than to test if there are apertures with the same - # size and add there the clear geometry - for hole_size, ap_val in holes_apertures.items(): - new_apid += 1 - new_apertures[str(new_apid)] = deepcopy(ap_val) + new_obj.solid_geometry = deepcopy(punched_solid_geometry) + new_obj.source_file = self.app.f_handlers.export_gerber(obj_name=outname, filename=None, + local_use=new_obj, use_thread=False) - def init_func(new_obj, app_obj): - new_obj.options.update(new_options) - new_obj.options['name'] = outname - new_obj.fill_color = deepcopy(grb_obj.fill_color) - new_obj.outline_color = deepcopy(grb_obj.outline_color) + self.app.app_obj.new_object('gerber', outname, init_func) - new_obj.apertures = deepcopy(new_apertures) + def on_fixed_method(self, grb_obj, outname): + punch_size = float(self.ui.dia_entry.get_value()) + if punch_size == 0.0: + self.app.inform.emit('[WARNING_NOTCL] %s' % _("The value of the fixed diameter is 0.0. Aborting.")) + return 'fail' - new_obj.solid_geometry = deepcopy(punched_solid_geometry) - new_obj.source_file = self.app.f_handlers.export_gerber(obj_name=outname, filename=None, - local_use=new_obj, use_thread=False) + fail_msg = _("Could not generate punched hole Gerber because the punch hole size is bigger than" + " some of the apertures in the Gerber object.") - self.app.app_obj.new_object('gerber', outname, init_func) - elif punch_method == 'fixed': - punch_size = float(self.ui.dia_entry.get_value()) + new_options = {} + for opt in grb_obj.options: + new_options[opt] = deepcopy(grb_obj.options[opt]) - if punch_size == 0.0: - self.app.inform.emit('[WARNING_NOTCL] %s' % _("The value of the fixed diameter is 0.0. Aborting.")) - return 'fail' + # selected codes in thre apertures UI table + sel_apid = [] + for it in self.ui.apertures_table.selectedItems(): + sel_apid.append(it.text()) - fail_msg = _("Could not generate punched hole Gerber because the punch hole size is bigger than" - " some of the apertures in the Gerber object.") - - punching_geo = [] - for apid in grb_obj.apertures: + punching_geo = [] + for apid in grb_obj.apertures: + if apid in sel_apid: if grb_obj.apertures[apid]['type'] == 'C' and self.ui.circular_cb.get_value(): for elem in grb_obj.apertures[apid]['geometry']: if 'follow' in elem: @@ -332,103 +416,112 @@ class ToolPunchGerber(AppTool): return 'fail' punching_geo.append(elem['follow'].buffer(punch_size / 2)) - punching_geo = MultiPolygon(punching_geo) - if isinstance(grb_obj.solid_geometry, list): - temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry) - else: - temp_solid_geometry = grb_obj.solid_geometry - punched_solid_geometry = temp_solid_geometry.difference(punching_geo) + punching_geo = MultiPolygon(punching_geo) + if isinstance(grb_obj.solid_geometry, list): + temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry) + else: + temp_solid_geometry = grb_obj.solid_geometry + punched_solid_geometry = temp_solid_geometry.difference(punching_geo) - if punched_solid_geometry == temp_solid_geometry: - self.app.inform.emit('[WARNING_NOTCL] %s' % - _("Could not generate punched hole Gerber because the newly created object " - "geometry is the same as the one in the source object geometry...")) - return 'fail' + if punched_solid_geometry == temp_solid_geometry: + self.app.inform.emit('[WARNING_NOTCL] %s' % + _("Could not generate punched hole Gerber because the newly created object " + "geometry is the same as the one in the source object geometry...")) + return 'fail' - # update the gerber apertures to include the clear geometry so it can be exported successfully - new_apertures = deepcopy(grb_obj.apertures) - new_apertures_items = new_apertures.items() + # update the gerber apertures to include the clear geometry so it can be exported successfully + new_apertures = deepcopy(grb_obj.apertures) + new_apertures_items = new_apertures.items() - # find maximum aperture id - new_apid = max([int(x) for x, __ in new_apertures_items]) + # find maximum aperture id + new_apid = max([int(x) for x, __ in new_apertures_items]) - # store here the clear geometry, the key is the drill size - holes_apertures = {} + # store here the clear geometry, the key is the drill size + holes_apertures = {} - for apid, val in new_apertures_items: - for elem in val['geometry']: - # make it work only for Gerber Flashes who are Points in 'follow' - if 'solid' in elem and isinstance(elem['follow'], Point): - for geo in punching_geo: - clear_apid_size = punch_size + for apid, val in new_apertures_items: + for elem in val['geometry']: + # make it work only for Gerber Flashes who are Points in 'follow' + if 'solid' in elem and isinstance(elem['follow'], Point): + for geo in punching_geo: + clear_apid_size = punch_size - # since there may be drills that do not drill into a pad we test only for drills in a pad - if geo.within(elem['solid']): - geo_elem = {} - geo_elem['clear'] = geo.centroid + # since there may be drills that do not drill into a pad we test only for drills in a pad + if geo.within(elem['solid']): + geo_elem = {} + geo_elem['clear'] = geo.centroid - if clear_apid_size not in holes_apertures: - holes_apertures[clear_apid_size] = {} - holes_apertures[clear_apid_size]['type'] = 'C' - holes_apertures[clear_apid_size]['size'] = clear_apid_size - holes_apertures[clear_apid_size]['geometry'] = [] + if clear_apid_size not in holes_apertures: + holes_apertures[clear_apid_size] = {} + holes_apertures[clear_apid_size]['type'] = 'C' + holes_apertures[clear_apid_size]['size'] = clear_apid_size + holes_apertures[clear_apid_size]['geometry'] = [] - holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem)) + holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem)) - # add the clear geometry to new apertures; it's easier than to test if there are apertures with the same - # size and add there the clear geometry - for hole_size, ap_val in holes_apertures.items(): - new_apid += 1 - new_apertures[str(new_apid)] = deepcopy(ap_val) + # add the clear geometry to new apertures; it's easier than to test if there are apertures with the same + # size and add there the clear geometry + for hole_size, ap_val in holes_apertures.items(): + new_apid += 1 + new_apertures[str(new_apid)] = deepcopy(ap_val) - def init_func(new_obj, app_obj): - new_obj.options.update(new_options) - new_obj.options['name'] = outname - new_obj.fill_color = deepcopy(grb_obj.fill_color) - new_obj.outline_color = deepcopy(grb_obj.outline_color) + def init_func(new_obj, app_obj): + new_obj.options.update(new_options) + new_obj.options['name'] = outname + new_obj.fill_color = deepcopy(grb_obj.fill_color) + new_obj.outline_color = deepcopy(grb_obj.outline_color) - new_obj.apertures = deepcopy(new_apertures) + new_obj.apertures = deepcopy(new_apertures) - new_obj.solid_geometry = deepcopy(punched_solid_geometry) - new_obj.source_file = self.app.f_handlers.export_gerber(obj_name=outname, filename=None, - local_use=new_obj, use_thread=False) + new_obj.solid_geometry = deepcopy(punched_solid_geometry) + new_obj.source_file = self.app.f_handlers.export_gerber(obj_name=outname, filename=None, + local_use=new_obj, use_thread=False) - self.app.app_obj.new_object('gerber', outname, init_func) - elif punch_method == 'ring': - circ_r_val = self.ui.circular_ring_entry.get_value() - oblong_r_val = self.ui.oblong_ring_entry.get_value() - square_r_val = self.ui.square_ring_entry.get_value() - rect_r_val = self.ui.rectangular_ring_entry.get_value() - other_r_val = self.ui.other_ring_entry.get_value() + self.app.app_obj.new_object('gerber', outname, init_func) - dia = None + def on_ring_method(self, grb_obj, outname): + circ_r_val = self.ui.circular_ring_entry.get_value() + oblong_r_val = self.ui.oblong_ring_entry.get_value() + square_r_val = self.ui.square_ring_entry.get_value() + rect_r_val = self.ui.rectangular_ring_entry.get_value() + other_r_val = self.ui.other_ring_entry.get_value() + dia = None - if isinstance(grb_obj.solid_geometry, list): - temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry) - else: - temp_solid_geometry = grb_obj.solid_geometry + new_options = {} + for opt in grb_obj.options: + new_options[opt] = deepcopy(grb_obj.options[opt]) - punched_solid_geometry = temp_solid_geometry + if isinstance(grb_obj.solid_geometry, list): + temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry) + else: + temp_solid_geometry = grb_obj.solid_geometry - new_apertures = deepcopy(grb_obj.apertures) - new_apertures_items = new_apertures.items() + punched_solid_geometry = temp_solid_geometry - # find maximum aperture id - new_apid = max([int(x) for x, __ in new_apertures_items]) + new_apertures = deepcopy(grb_obj.apertures) + new_apertures_items = new_apertures.items() - # store here the clear geometry, the key is the new aperture size - holes_apertures = {} + # find maximum aperture id + new_apid = max([int(x) for x, __ in new_apertures_items]) - for apid, apid_value in grb_obj.apertures.items(): - ap_type = apid_value['type'] - punching_geo = [] + # selected codes in the apertures UI table + sel_apid = [] + for it in self.ui.apertures_table.selectedItems(): + sel_apid.append(it.text()) + # store here the clear geometry, the key is the new aperture size + holes_apertures = {} + + for apid, apid_value in grb_obj.apertures.items(): + ap_type = apid_value['type'] + punching_geo = [] + + if apid in sel_apid: if ap_type == 'C' and self.ui.circular_cb.get_value(): dia = float(apid_value['size']) - (2 * circ_r_val) for elem in apid_value['geometry']: if 'follow' in elem and isinstance(elem['follow'], Point): punching_geo.append(elem['follow'].buffer(dia / 2)) - elif ap_type == 'O' and self.ui.oblong_cb.get_value(): width = float(apid_value['width']) height = float(apid_value['height']) @@ -442,7 +535,6 @@ class ToolPunchGerber(AppTool): if 'follow' in elem: if isinstance(elem['follow'], Point): punching_geo.append(elem['follow'].buffer(dia / 2)) - elif ap_type == 'R': width = float(apid_value['width']) height = float(apid_value['height']) @@ -466,7 +558,6 @@ class ToolPunchGerber(AppTool): if 'follow' in elem: if isinstance(elem['follow'], Point): punching_geo.append(elem['follow'].buffer(dia / 2)) - elif self.ui.other_cb.get_value(): try: dia = float(apid_value['size']) - (2 * other_r_val) @@ -486,88 +577,95 @@ class ToolPunchGerber(AppTool): if isinstance(elem['follow'], Point): punching_geo.append(elem['follow'].buffer(dia / 2)) - # if dia is None then none of the above applied so we skip the following - if dia is None: - continue + # if dia is None then none of the above applied so we skip the following + if dia is None: + continue - punching_geo = MultiPolygon(punching_geo) + punching_geo = MultiPolygon(punching_geo) - if punching_geo is None or punching_geo.is_empty: - continue + if punching_geo is None or punching_geo.is_empty: + continue - punched_solid_geometry = punched_solid_geometry.difference(punching_geo) + punched_solid_geometry = punched_solid_geometry.difference(punching_geo) - # update the gerber apertures to include the clear geometry so it can be exported successfully - for elem in apid_value['geometry']: - # make it work only for Gerber Flashes who are Points in 'follow' - if 'solid' in elem and isinstance(elem['follow'], Point): - clear_apid_size = dia - for geo in punching_geo: + # update the gerber apertures to include the clear geometry so it can be exported successfully + for elem in apid_value['geometry']: + # make it work only for Gerber Flashes who are Points in 'follow' + if 'solid' in elem and isinstance(elem['follow'], Point): + clear_apid_size = dia + for geo in punching_geo: - # since there may be drills that do not drill into a pad we test only for geos in a pad - if geo.within(elem['solid']): - geo_elem = {} - geo_elem['clear'] = geo.centroid + # since there may be drills that do not drill into a pad we test only for geos in a pad + if geo.within(elem['solid']): + geo_elem = {} + geo_elem['clear'] = geo.centroid - if clear_apid_size not in holes_apertures: - holes_apertures[clear_apid_size] = {} - holes_apertures[clear_apid_size]['type'] = 'C' - holes_apertures[clear_apid_size]['size'] = clear_apid_size - holes_apertures[clear_apid_size]['geometry'] = [] + if clear_apid_size not in holes_apertures: + holes_apertures[clear_apid_size] = {} + holes_apertures[clear_apid_size]['type'] = 'C' + holes_apertures[clear_apid_size]['size'] = clear_apid_size + holes_apertures[clear_apid_size]['geometry'] = [] - holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem)) + holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem)) - # add the clear geometry to new apertures; it's easier than to test if there are apertures with the same - # size and add there the clear geometry - for hole_size, ap_val in holes_apertures.items(): - new_apid += 1 - new_apertures[str(new_apid)] = deepcopy(ap_val) + # add the clear geometry to new apertures; it's easier than to test if there are apertures with the same + # size and add there the clear geometry + for hole_size, ap_val in holes_apertures.items(): + new_apid += 1 + new_apertures[str(new_apid)] = deepcopy(ap_val) - def init_func(new_obj, app_obj): - new_obj.options.update(new_options) - new_obj.options['name'] = outname - new_obj.fill_color = deepcopy(grb_obj.fill_color) - new_obj.outline_color = deepcopy(grb_obj.outline_color) + def init_func(new_obj, app_obj): + new_obj.options.update(new_options) + new_obj.options['name'] = outname + new_obj.fill_color = deepcopy(grb_obj.fill_color) + new_obj.outline_color = deepcopy(grb_obj.outline_color) - new_obj.apertures = deepcopy(new_apertures) + new_obj.apertures = deepcopy(new_apertures) - new_obj.solid_geometry = deepcopy(punched_solid_geometry) - new_obj.source_file = self.app.f_handlers.export_gerber(obj_name=outname, filename=None, - local_use=new_obj, use_thread=False) + new_obj.solid_geometry = deepcopy(punched_solid_geometry) + new_obj.source_file = self.app.f_handlers.export_gerber(obj_name=outname, filename=None, + local_use=new_obj, use_thread=False) - self.app.app_obj.new_object('gerber', outname, init_func) + self.app.app_obj.new_object('gerber', outname, init_func) - elif punch_method == 'prop': - prop_factor = self.ui.factor_entry.get_value() / 100.0 + def on_proportional_method(self, grb_obj, outname): + prop_factor = self.ui.factor_entry.get_value() / 100.0 + dia = None + new_options = {} + for opt in grb_obj.options: + new_options[opt] = deepcopy(grb_obj.options[opt]) - dia = None + if isinstance(grb_obj.solid_geometry, list): + temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry) + else: + temp_solid_geometry = grb_obj.solid_geometry - if isinstance(grb_obj.solid_geometry, list): - temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry) - else: - temp_solid_geometry = grb_obj.solid_geometry + punched_solid_geometry = temp_solid_geometry - punched_solid_geometry = temp_solid_geometry + new_apertures = deepcopy(grb_obj.apertures) + new_apertures_items = new_apertures.items() - new_apertures = deepcopy(grb_obj.apertures) - new_apertures_items = new_apertures.items() + # find maximum aperture id + new_apid = max([int(x) for x, __ in new_apertures_items]) - # find maximum aperture id - new_apid = max([int(x) for x, __ in new_apertures_items]) + # selected codes in the apertures UI table + sel_apid = [] + for it in self.ui.apertures_table.selectedItems(): + sel_apid.append(it.text()) - # store here the clear geometry, the key is the new aperture size - holes_apertures = {} + # store here the clear geometry, the key is the new aperture size + holes_apertures = {} - for apid, apid_value in grb_obj.apertures.items(): - ap_type = apid_value['type'] - punching_geo = [] + for apid, apid_value in grb_obj.apertures.items(): + ap_type = apid_value['type'] + punching_geo = [] + if apid in sel_apid: if ap_type == 'C' and self.ui.circular_cb.get_value(): dia = float(apid_value['size']) * prop_factor for elem in apid_value['geometry']: if 'follow' in elem and isinstance(elem['follow'], Point): punching_geo.append(elem['follow'].buffer(dia / 2)) - elif ap_type == 'O' and self.ui.oblong_cb.get_value(): width = float(apid_value['width']) height = float(apid_value['height']) @@ -581,7 +679,6 @@ class ToolPunchGerber(AppTool): if 'follow' in elem: if isinstance(elem['follow'], Point): punching_geo.append(elem['follow'].buffer(dia / 2)) - elif ap_type == 'R': width = float(apid_value['width']) height = float(apid_value['height']) @@ -605,7 +702,6 @@ class ToolPunchGerber(AppTool): if 'follow' in elem: if isinstance(elem['follow'], Point): punching_geo.append(elem['follow'].buffer(dia / 2)) - elif self.ui.other_cb.get_value(): try: dia = float(apid_value['size']) * prop_factor @@ -625,56 +721,56 @@ class ToolPunchGerber(AppTool): if isinstance(elem['follow'], Point): punching_geo.append(elem['follow'].buffer(dia / 2)) - # if dia is None then none of the above applied so we skip the following - if dia is None: - continue + # if dia is None then none of the above applied so we skip the following + if dia is None: + continue - punching_geo = MultiPolygon(punching_geo) + punching_geo = MultiPolygon(punching_geo) - if punching_geo is None or punching_geo.is_empty: - continue + if punching_geo is None or punching_geo.is_empty: + continue - punched_solid_geometry = punched_solid_geometry.difference(punching_geo) + punched_solid_geometry = punched_solid_geometry.difference(punching_geo) - # update the gerber apertures to include the clear geometry so it can be exported successfully - for elem in apid_value['geometry']: - # make it work only for Gerber Flashes who are Points in 'follow' - if 'solid' in elem and isinstance(elem['follow'], Point): - clear_apid_size = dia - for geo in punching_geo: + # update the gerber apertures to include the clear geometry so it can be exported successfully + for elem in apid_value['geometry']: + # make it work only for Gerber Flashes who are Points in 'follow' + if 'solid' in elem and isinstance(elem['follow'], Point): + clear_apid_size = dia + for geo in punching_geo: - # since there may be drills that do not drill into a pad we test only for geos in a pad - if geo.within(elem['solid']): - geo_elem = {} - geo_elem['clear'] = geo.centroid + # since there may be drills that do not drill into a pad we test only for geos in a pad + if geo.within(elem['solid']): + geo_elem = {} + geo_elem['clear'] = geo.centroid - if clear_apid_size not in holes_apertures: - holes_apertures[clear_apid_size] = {} - holes_apertures[clear_apid_size]['type'] = 'C' - holes_apertures[clear_apid_size]['size'] = clear_apid_size - holes_apertures[clear_apid_size]['geometry'] = [] + if clear_apid_size not in holes_apertures: + holes_apertures[clear_apid_size] = {} + holes_apertures[clear_apid_size]['type'] = 'C' + holes_apertures[clear_apid_size]['size'] = clear_apid_size + holes_apertures[clear_apid_size]['geometry'] = [] - holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem)) + holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem)) - # add the clear geometry to new apertures; it's easier than to test if there are apertures with the same - # size and add there the clear geometry - for hole_size, ap_val in holes_apertures.items(): - new_apid += 1 - new_apertures[str(new_apid)] = deepcopy(ap_val) + # add the clear geometry to new apertures; it's easier than to test if there are apertures with the same + # size and add there the clear geometry + for hole_size, ap_val in holes_apertures.items(): + new_apid += 1 + new_apertures[str(new_apid)] = deepcopy(ap_val) - def init_func(new_obj, app_obj): - new_obj.options.update(new_options) - new_obj.options['name'] = outname - new_obj.fill_color = deepcopy(grb_obj.fill_color) - new_obj.outline_color = deepcopy(grb_obj.outline_color) + def init_func(new_obj, app_obj): + new_obj.options.update(new_options) + new_obj.options['name'] = outname + new_obj.fill_color = deepcopy(grb_obj.fill_color) + new_obj.outline_color = deepcopy(grb_obj.outline_color) - new_obj.apertures = deepcopy(new_apertures) + new_obj.apertures = deepcopy(new_apertures) - new_obj.solid_geometry = deepcopy(punched_solid_geometry) - new_obj.source_file = self.app.f_handlers.export_gerber(obj_name=outname, filename=None, - local_use=new_obj, use_thread=False) + new_obj.solid_geometry = deepcopy(punched_solid_geometry) + new_obj.source_file = self.app.f_handlers.export_gerber(obj_name=outname, filename=None, + local_use=new_obj, use_thread=False) - self.app.app_obj.new_object('gerber', outname, init_func) + self.app.app_obj.new_object('gerber', outname, init_func) def reset_fields(self): self.ui.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex())) @@ -738,9 +834,18 @@ class PunchUI: grid_lay.addWidget(self.padt_label, 3, 0, 1, 2) + pad_all_grid = QtWidgets.QGridLayout() + pad_all_grid.setColumnStretch(0, 0) + pad_all_grid.setColumnStretch(1, 1) + grid_lay.addLayout(pad_all_grid, 5, 0, 1, 2) + + pad_grid = QtWidgets.QGridLayout() + pad_grid.setColumnStretch(0, 0) + pad_all_grid.addLayout(pad_grid, 0, 0) + # Select all self.select_all_cb = FCCheckBox('%s' % _("ALL")) - grid_lay.addWidget(self.select_all_cb) + pad_grid.addWidget(self.select_all_cb, 0, 0) # Circular Aperture Selection self.circular_cb = FCCheckBox('%s' % _("Circular")) @@ -748,7 +853,7 @@ class PunchUI: _("Process Circular Pads.") ) - grid_lay.addWidget(self.circular_cb, 5, 0, 1, 2) + pad_grid.addWidget(self.circular_cb, 1, 0) # Oblong Aperture Selection self.oblong_cb = FCCheckBox('%s' % _("Oblong")) @@ -756,7 +861,7 @@ class PunchUI: _("Process Oblong Pads.") ) - grid_lay.addWidget(self.oblong_cb, 6, 0, 1, 2) + pad_grid.addWidget(self.oblong_cb, 2, 0) # Square Aperture Selection self.square_cb = FCCheckBox('%s' % _("Square")) @@ -764,7 +869,7 @@ class PunchUI: _("Process Square Pads.") ) - grid_lay.addWidget(self.square_cb, 7, 0, 1, 2) + pad_grid.addWidget(self.square_cb, 3, 0) # Rectangular Aperture Selection self.rectangular_cb = FCCheckBox('%s' % _("Rectangular")) @@ -772,7 +877,7 @@ class PunchUI: _("Process Rectangular Pads.") ) - grid_lay.addWidget(self.rectangular_cb, 8, 0, 1, 2) + pad_grid.addWidget(self.rectangular_cb, 4, 0) # Others type of Apertures Selection self.other_cb = FCCheckBox('%s' % _("Others")) @@ -780,7 +885,29 @@ class PunchUI: _("Process pads not in the categories above.") ) - grid_lay.addWidget(self.other_cb, 9, 0, 1, 2) + pad_grid.addWidget(self.other_cb, 5, 0) + + # Aperture Table + self.apertures_table = FCTable() + pad_all_grid.addWidget(self.apertures_table, 0, 1) + + self.apertures_table.setColumnCount(3) + self.apertures_table.setHorizontalHeaderLabels([_('Code'), _('Type'), _('Size')]) + self.apertures_table.setSortingEnabled(False) + self.apertures_table.setRowCount(0) + self.apertures_table.resizeColumnsToContents() + self.apertures_table.resizeRowsToContents() + + self.apertures_table.horizontalHeaderItem(0).setToolTip( + _("Aperture Code")) + self.apertures_table.horizontalHeaderItem(1).setToolTip( + _("Type of aperture: circular, rectangle, macros etc")) + self.apertures_table.horizontalHeaderItem(2).setToolTip( + _("Aperture Size:")) + + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred) + self.apertures_table.setSizePolicy(sizePolicy) + self.apertures_table.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection) separator_line = QtWidgets.QFrame() separator_line.setFrameShape(QtWidgets.QFrame.HLine) @@ -832,11 +959,6 @@ class PunchUI: grid0.addWidget(self.exc_label, 3, 0, 1, 2) grid0.addWidget(self.exc_combo, 4, 0, 1, 2) - separator_line = QtWidgets.QFrame() - separator_line.setFrameShape(QtWidgets.QFrame.HLine) - separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) - grid0.addWidget(separator_line, 5, 0, 1, 2) - # Fixed Dia self.fixed_label = QtWidgets.QLabel('%s' % _("Fixed Diameter")) grid0.addWidget(self.fixed_label, 6, 0, 1, 2) @@ -854,11 +976,9 @@ class PunchUI: grid0.addWidget(self.dia_label, 8, 0) grid0.addWidget(self.dia_entry, 8, 1) - separator_line = QtWidgets.QFrame() - separator_line.setFrameShape(QtWidgets.QFrame.HLine) - separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) - grid0.addWidget(separator_line, 9, 0, 1, 2) - + # ############################################################################################################# + # RING FRAME + # ############################################################################################################# self.ring_frame = QtWidgets.QFrame() self.ring_frame.setContentsMargins(0, 0, 0, 0) grid0.addWidget(self.ring_frame, 10, 0, 1, 2) @@ -946,11 +1066,7 @@ class PunchUI: self.grid1.addWidget(self.other_ring_label, 7, 0) self.grid1.addWidget(self.other_ring_entry, 7, 1) - - separator_line = QtWidgets.QFrame() - separator_line.setFrameShape(QtWidgets.QFrame.HLine) - separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) - grid0.addWidget(separator_line, 11, 0, 1, 2) + # ############################################################################################################# # Proportional value self.prop_label = QtWidgets.QLabel('%s' % _("Proportional Diameter")) @@ -1012,10 +1128,10 @@ class PunchUI: self.rectangular_ring_entry.setEnabled(False) self.other_ring_entry.setEnabled(False) - self.dia_entry.setDisabled(True) - self.dia_label.setDisabled(True) - self.factor_label.setDisabled(True) - self.factor_entry.setDisabled(True) + self.dia_entry.hide() + self.dia_label.hide() + self.factor_label.hide() + self.factor_entry.hide() # #################################### FINSIHED GUI ########################### # ############################################################################# diff --git a/locale/tr/LC_MESSAGES/strings.mo b/locale/tr/LC_MESSAGES/strings.mo index a9456957..4a39bc60 100644 Binary files a/locale/tr/LC_MESSAGES/strings.mo and b/locale/tr/LC_MESSAGES/strings.mo differ diff --git a/locale/tr/LC_MESSAGES/strings.po b/locale/tr/LC_MESSAGES/strings.po index a16bb3d1..e19c4010 100644 --- a/locale/tr/LC_MESSAGES/strings.po +++ b/locale/tr/LC_MESSAGES/strings.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: 2020-10-28 10:58+0200\n" -"PO-Revision-Date: 2020-10-28 10:58+0200\n" +"PO-Revision-Date: 2020-10-28 15:13+0300\n" "Last-Translator: \n" "Language-Team: \n" "Language: tr_TR\n" @@ -89,10 +89,8 @@ msgid "Bookmark added." msgstr "Yer işareti eklendi." #: Bookmark.py:243 app_Main.py:3207 app_Main.py:3249 -#, fuzzy -#| msgid "Backup" msgid "Backup Site" -msgstr "Yedekleme" +msgstr "Alternatif Web Sayfası" #: Bookmark.py:244 msgid "This bookmark can not be removed" @@ -4986,7 +4984,7 @@ msgstr "Gerber Özellikleri" #: appGUI/MainGUI.py:610 msgid "Shortcuts List" -msgstr "" +msgstr "Klavye Kısayol Listesi" #: appGUI/MainGUI.py:610 appGUI/MainGUI.py:4398 msgid "F3" @@ -13722,11 +13720,11 @@ msgstr "Hatanın nedeni" #: appObjects/ObjectCollection.py:1195 msgid "All objects are selected." -msgstr "Hatanın nedeni." +msgstr "Nesnelerin Tümü Seçildi." #: appObjects/ObjectCollection.py:1205 msgid "Objects selection is cleared." -msgstr "Nesnelerin seçimi temizlendi." +msgstr "Nesnelerin seçimi kaldırıldı." #: appParsers/ParseExcellon.py:292 msgid "This is GCODE mark" @@ -18536,20 +18534,18 @@ msgid "" "If you can't get any informations about the application\n" "use the YouTube channel link from the Help menu." msgstr "" -"Aşağıdaki durumlarda bu girişe başka bir\n" -"sitede izin verilecektir:\n" +"Bu giriş, aşağıdaki durumlarda başka bir web sayfasına yönlendirecektir:\n" "\n" -"1. FlatCAM.org web sitesi çalışmıyor\n" -"2. Birisi FlatCAM projesini çatalladı ve \n" -"kendi web sitesine işaret etmek istiyor\n" +"1. FlatCAM.org sayfası kapandığında\n" +"2. Birisi FlatCAM projesini kopyaladığında ve sizi kendi web sayfasına \n" +"yönlendirmek istediğinde\n" "\n" -"Uygulama'in beta sürümü hakkında herhangi\n" -"bir bilgi alamıyorsanız, Yardım menüsündeki\n" -"YouTube kanalı bağlantısını kullanın." +"Uygulama hakkında bilgi alamazsanız, Yardım menüsünden \n" +"\"YouTube Kanalı\" bağlantısını kullanın." #: app_Main.py:3294 msgid "Alternative website" -msgstr "Alternatif web sitesi" +msgstr "Alternatif Web Sayfası" #: app_Main.py:3636 msgid "Selected Excellon file extensions registered with FlatCAM."