- in Corner Marker Tool, will no longer update the current object with the marker geometry but create a new Gerber object - in Join Excellon functionality made sure that the new Combo Exellon object will have copied the data from source objects and not just references, therefore will survive the delete of its parents - updated Turkish translation (by Mehmet Kaya) - updated all the languages except Turkish
677 lines
26 KiB
Python
677 lines
26 KiB
Python
# ##########################################################
|
|
# FlatCAM: 2D Post-processing for Manufacturing #
|
|
# File Author: Marius Adrian Stanciu (c) #
|
|
# Date: 5/17/2020 #
|
|
# MIT Licence #
|
|
# ##########################################################
|
|
|
|
from PyQt5 import QtWidgets, QtCore, QtGui
|
|
|
|
from appTool import AppTool
|
|
from appGUI.GUIElements import FCDoubleSpinner, FCCheckBox, FCComboBox, FCButton, RadioSet, FCLabel
|
|
|
|
from shapely.geometry import MultiPolygon, LineString, Point
|
|
from shapely.ops import unary_union
|
|
|
|
from copy import deepcopy
|
|
import logging
|
|
|
|
import gettext
|
|
import appTranslation as fcTranslate
|
|
import builtins
|
|
|
|
fcTranslate.apply_language('strings')
|
|
if '_' not in builtins.__dict__:
|
|
_ = gettext.gettext
|
|
|
|
log = logging.getLogger('base')
|
|
|
|
|
|
class ToolCorners(AppTool):
|
|
|
|
def __init__(self, app):
|
|
AppTool.__init__(self, app)
|
|
|
|
self.app = app
|
|
self.canvas = self.app.plotcanvas
|
|
|
|
self.decimals = self.app.decimals
|
|
self.units = ''
|
|
|
|
# here we store the locations of the selected corners
|
|
self.points = {}
|
|
|
|
# #############################################################################
|
|
# ######################### Tool GUI ##########################################
|
|
# #############################################################################
|
|
self.ui = CornersUI(layout=self.layout, app=self.app)
|
|
self.toolName = self.ui.toolName
|
|
|
|
# Objects involved in Copper thieving
|
|
self.grb_object = None
|
|
|
|
# store the flattened geometry here:
|
|
self.flat_geometry = []
|
|
|
|
# Tool properties
|
|
self.fid_dia = None
|
|
|
|
self.grb_steps_per_circle = self.app.defaults["gerber_circle_steps"]
|
|
|
|
# SIGNALS
|
|
self.ui.add_marker_button.clicked.connect(self.add_markers)
|
|
self.ui.toggle_all_cb.toggled.connect(self.on_toggle_all)
|
|
self.ui.drill_button.clicked.connect(self.on_create_drill_object)
|
|
|
|
def run(self, toggle=True):
|
|
self.app.defaults.report_usage("ToolCorners()")
|
|
|
|
if toggle:
|
|
# if the splitter is hidden, display it, else hide it but only if the current widget is the same
|
|
if self.app.ui.splitter.sizes()[0] == 0:
|
|
self.app.ui.splitter.setSizes([1, 1])
|
|
else:
|
|
try:
|
|
if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
|
|
# if tab is populated with the tool but it does not have the focus, focus on it
|
|
if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
|
|
# focus on Tool Tab
|
|
self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
|
|
else:
|
|
self.app.ui.splitter.setSizes([0, 1])
|
|
except AttributeError:
|
|
pass
|
|
else:
|
|
if self.app.ui.splitter.sizes()[0] == 0:
|
|
self.app.ui.splitter.setSizes([1, 1])
|
|
|
|
AppTool.run(self)
|
|
|
|
self.set_tool_ui()
|
|
|
|
self.app.ui.notebook.setTabText(2, _("Corners Tool"))
|
|
|
|
def install(self, icon=None, separator=None, **kwargs):
|
|
AppTool.install(self, icon, separator, shortcut='Alt+M', **kwargs)
|
|
|
|
def set_tool_ui(self):
|
|
self.units = self.app.defaults['units']
|
|
self.ui.thick_entry.set_value(self.app.defaults["tools_corners_thickness"])
|
|
self.ui.l_entry.set_value(float(self.app.defaults["tools_corners_length"]))
|
|
self.ui.margin_entry.set_value(float(self.app.defaults["tools_corners_margin"]))
|
|
self.ui.toggle_all_cb.set_value(False)
|
|
self.ui.type_radio.set_value(self.app.defaults["tools_corners_type"])
|
|
self.ui.drill_dia_entry.set_value(self.app.defaults["tools_corners_drill_dia"])
|
|
|
|
def on_toggle_all(self, val):
|
|
self.ui.bl_cb.set_value(val)
|
|
self.ui.br_cb.set_value(val)
|
|
self.ui.tl_cb.set_value(val)
|
|
self.ui.tr_cb.set_value(val)
|
|
|
|
def add_markers(self):
|
|
self.app.call_source = "corners_tool"
|
|
tl_state = self.ui.tl_cb.get_value()
|
|
tr_state = self.ui.tr_cb.get_value()
|
|
bl_state = self.ui.bl_cb.get_value()
|
|
br_state = self.ui.br_cb.get_value()
|
|
|
|
# get the Gerber object on which the corner marker will be inserted
|
|
selection_index = self.ui.object_combo.currentIndex()
|
|
model_index = self.app.collection.index(selection_index, 0, self.ui.object_combo.rootModelIndex())
|
|
|
|
try:
|
|
self.grb_object = model_index.internalPointer().obj
|
|
except Exception as e:
|
|
log.debug("ToolCorners.add_markers() --> %s" % str(e))
|
|
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
|
|
self.app.call_source = "app"
|
|
return
|
|
|
|
xmin, ymin, xmax, ymax = self.grb_object.bounds()
|
|
self.points = {}
|
|
if tl_state:
|
|
self.points['tl'] = (xmin, ymax)
|
|
if tr_state:
|
|
self.points['tr'] = (xmax, ymax)
|
|
if bl_state:
|
|
self.points['bl'] = (xmin, ymin)
|
|
if br_state:
|
|
self.points['br'] = (xmax, ymin)
|
|
|
|
ret_val = self.add_corners_geo(self.points, g_obj=self.grb_object)
|
|
self.app.call_source = "app"
|
|
if ret_val == 'fail':
|
|
self.app.call_source = "app"
|
|
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
|
|
return
|
|
|
|
self.on_exit(ret_val)
|
|
|
|
def add_corners_geo(self, points_storage, g_obj):
|
|
"""
|
|
Add geometry to the solid_geometry of the copper Gerber object
|
|
|
|
:param points_storage: a dictionary holding the points where to add corners
|
|
:param g_obj: the Gerber object where to add the geometry
|
|
:return: None
|
|
"""
|
|
|
|
marker_type = self.ui.type_radio.get_value()
|
|
line_thickness = self.ui.thick_entry.get_value()
|
|
margin = self.ui.margin_entry.get_value()
|
|
line_length = self.ui.l_entry.get_value()
|
|
|
|
geo_list = []
|
|
|
|
if not points_storage:
|
|
self.app.inform.emit("[ERROR_NOTCL] %s." % _("Please select at least a location"))
|
|
return 'fail'
|
|
|
|
for key in points_storage:
|
|
if key == 'tl':
|
|
pt = points_storage[key]
|
|
x = pt[0] - margin - line_thickness / 2.0
|
|
y = pt[1] + margin + line_thickness / 2.0
|
|
if marker_type == 's':
|
|
line_geo_hor = LineString([
|
|
(x, y), (x + line_length, y)
|
|
])
|
|
line_geo_vert = LineString([
|
|
(x, y), (x, y - line_length)
|
|
])
|
|
else:
|
|
line_geo_hor = LineString([
|
|
(x - line_length, y), (x + line_length, y)
|
|
])
|
|
line_geo_vert = LineString([
|
|
(x, y + line_length), (x, y - line_length)
|
|
])
|
|
geo_list.append(line_geo_hor)
|
|
geo_list.append(line_geo_vert)
|
|
if key == 'tr':
|
|
pt = points_storage[key]
|
|
x = pt[0] + margin + line_thickness / 2.0
|
|
y = pt[1] + margin + line_thickness / 2.0
|
|
if marker_type == 's':
|
|
line_geo_hor = LineString([
|
|
(x, y), (x - line_length, y)
|
|
])
|
|
line_geo_vert = LineString([
|
|
(x, y), (x, y - line_length)
|
|
])
|
|
else:
|
|
line_geo_hor = LineString([
|
|
(x + line_length, y), (x - line_length, y)
|
|
])
|
|
line_geo_vert = LineString([
|
|
(x, y + line_length), (x, y - line_length)
|
|
])
|
|
geo_list.append(line_geo_hor)
|
|
geo_list.append(line_geo_vert)
|
|
if key == 'bl':
|
|
pt = points_storage[key]
|
|
x = pt[0] - margin - line_thickness / 2.0
|
|
y = pt[1] - margin - line_thickness / 2.0
|
|
if marker_type == 's':
|
|
line_geo_hor = LineString([
|
|
(x, y), (x + line_length, y)
|
|
])
|
|
line_geo_vert = LineString([
|
|
(x, y), (x, y + line_length)
|
|
])
|
|
else:
|
|
line_geo_hor = LineString([
|
|
(x - line_length, y), (x + line_length, y)
|
|
])
|
|
line_geo_vert = LineString([
|
|
(x, y - line_length), (x, y + line_length)
|
|
])
|
|
geo_list.append(line_geo_hor)
|
|
geo_list.append(line_geo_vert)
|
|
if key == 'br':
|
|
pt = points_storage[key]
|
|
x = pt[0] + margin + line_thickness / 2.0
|
|
y = pt[1] - margin - line_thickness / 2.0
|
|
if marker_type == 's':
|
|
line_geo_hor = LineString([
|
|
(x, y), (x - line_length, y)
|
|
])
|
|
line_geo_vert = LineString([
|
|
(x, y), (x, y + line_length)
|
|
])
|
|
else:
|
|
line_geo_hor = LineString([
|
|
(x + line_length, y), (x - line_length, y)
|
|
])
|
|
line_geo_vert = LineString([
|
|
(x, y - line_length), (x, y + line_length)
|
|
])
|
|
geo_list.append(line_geo_hor)
|
|
geo_list.append(line_geo_vert)
|
|
|
|
new_apertures = deepcopy(g_obj.apertures)
|
|
|
|
aperture_found = None
|
|
for ap_id, ap_val in new_apertures.items():
|
|
if ap_val['type'] == 'C' and ap_val['size'] == line_thickness:
|
|
aperture_found = ap_id
|
|
break
|
|
|
|
geo_buff_list = []
|
|
if aperture_found:
|
|
for geo in geo_list:
|
|
geo_buff = geo.buffer(line_thickness / 2.0, resolution=self.grb_steps_per_circle, join_style=2)
|
|
geo_buff_list.append(geo_buff)
|
|
|
|
dict_el = {}
|
|
dict_el['follow'] = geo
|
|
dict_el['solid'] = geo_buff
|
|
new_apertures[aperture_found]['geometry'].append(deepcopy(dict_el))
|
|
else:
|
|
ap_keys = list(new_apertures.keys())
|
|
if ap_keys:
|
|
new_apid = str(int(max(ap_keys)) + 1)
|
|
else:
|
|
new_apid = '10'
|
|
|
|
new_apertures[new_apid] = {}
|
|
new_apertures[new_apid]['type'] = 'C'
|
|
new_apertures[new_apid]['size'] = line_thickness
|
|
new_apertures[new_apid]['geometry'] = []
|
|
|
|
for geo in geo_list:
|
|
geo_buff = geo.buffer(line_thickness / 2.0, resolution=self.grb_steps_per_circle, join_style=3)
|
|
geo_buff_list.append(geo_buff)
|
|
|
|
dict_el = {'follow': geo, 'solid': geo_buff}
|
|
new_apertures[new_apid]['geometry'].append(deepcopy(dict_el))
|
|
|
|
s_list = []
|
|
if g_obj.solid_geometry:
|
|
try:
|
|
for poly in g_obj.solid_geometry:
|
|
s_list.append(poly)
|
|
except TypeError:
|
|
s_list.append(g_obj.solid_geometry)
|
|
|
|
geo_buff_list = MultiPolygon(geo_buff_list)
|
|
geo_buff_list = geo_buff_list.buffer(0)
|
|
try:
|
|
for poly in geo_buff_list:
|
|
s_list.append(poly)
|
|
except TypeError:
|
|
s_list.append(geo_buff_list)
|
|
|
|
outname = '%s_%s' % (str(self.grb_object.options['name']), 'corners')
|
|
|
|
def initialize(grb_obj, app_obj):
|
|
grb_obj.multitool = False
|
|
grb_obj.multigeo = False
|
|
grb_obj.follow = False
|
|
grb_obj.apertures = new_apertures
|
|
grb_obj.solid_geometry = unary_union(s_list)
|
|
|
|
grb_obj.source_file = app_obj.f_handlers.export_gerber(obj_name=outname, filename=None, local_use=grb_obj,
|
|
use_thread=False)
|
|
|
|
ret = self.app.app_obj.new_object('gerber', outname, initialize, plot=True)
|
|
|
|
return ret
|
|
|
|
def on_create_drill_object(self):
|
|
self.app.call_source = "corners_tool"
|
|
|
|
tooldia = self.ui.drill_dia_entry.get_value()
|
|
|
|
if tooldia == 0:
|
|
self.app.inform.emit('[WARNING_NOTCL] %s %s' % (_("Cancelled."), _("The tool diameter is zero.")))
|
|
return
|
|
|
|
line_thickness = self.ui.thick_entry.get_value()
|
|
margin = self.ui.margin_entry.get_value()
|
|
tl_state = self.ui.tl_cb.get_value()
|
|
tr_state = self.ui.tr_cb.get_value()
|
|
bl_state = self.ui.bl_cb.get_value()
|
|
br_state = self.ui.br_cb.get_value()
|
|
|
|
if not tl_state and not tr_state and not bl_state and not br_state:
|
|
self.app.inform.emit("[ERROR_NOTCL] %s." % _("Please select at least a location"))
|
|
|
|
# get the Gerber object on which the corner marker will be inserted
|
|
selection_index = self.ui.object_combo.currentIndex()
|
|
model_index = self.app.collection.index(selection_index, 0, self.ui.object_combo.rootModelIndex())
|
|
|
|
try:
|
|
self.grb_object = model_index.internalPointer().obj
|
|
except Exception as e:
|
|
log.debug("ToolCorners.add_markers() --> %s" % str(e))
|
|
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
|
|
self.app.call_source = "app"
|
|
return
|
|
|
|
xmin, ymin, xmax, ymax = self.grb_object.bounds()
|
|
|
|
# list of (x,y) tuples. Store here the drill coordinates
|
|
drill_list = []
|
|
|
|
if tl_state:
|
|
x = xmin - margin - line_thickness / 2.0
|
|
y = ymax + margin + line_thickness / 2.0
|
|
drill_list.append(
|
|
Point((x, y))
|
|
)
|
|
|
|
if tr_state:
|
|
x = xmax + margin + line_thickness / 2.0
|
|
y = ymax + margin + line_thickness / 2.0
|
|
drill_list.append(
|
|
Point((x, y))
|
|
)
|
|
|
|
if bl_state:
|
|
x = xmin - margin - line_thickness / 2.0
|
|
y = ymin - margin - line_thickness / 2.0
|
|
drill_list.append(
|
|
Point((x, y))
|
|
)
|
|
|
|
if br_state:
|
|
x = xmax + margin + line_thickness / 2.0
|
|
y = ymin - margin - line_thickness / 2.0
|
|
drill_list.append(
|
|
Point((x, y))
|
|
)
|
|
|
|
tools = {1: {}}
|
|
tools[1]["tooldia"] = tooldia
|
|
tools[1]['drills'] = drill_list
|
|
tools[1]['solid_geometry'] = []
|
|
|
|
def obj_init(obj_inst, app_inst):
|
|
obj_inst.tools = deepcopy(tools)
|
|
obj_inst.create_geometry()
|
|
obj_inst.source_file = app_inst.f_handlers.export_excellon(obj_name=obj_inst.options['name'],
|
|
local_use=obj_inst,
|
|
filename=None,
|
|
use_thread=False)
|
|
|
|
outname = '%s_%s' % (str(self.grb_object.options['name']), 'corner_drills')
|
|
|
|
ret_val = self.app.app_obj.new_object("excellon", outname, obj_init)
|
|
|
|
self.app.call_source = "app"
|
|
|
|
if not ret_val == 'fail':
|
|
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
|
|
else:
|
|
self.app.inform.emit('[success] %s' % _("Excellon object with corner drills created."))
|
|
|
|
def replot(self, obj, run_thread=True):
|
|
def worker_task():
|
|
with self.app.proc_container.new('%s...' % _("Plotting")):
|
|
obj.plot()
|
|
self.app.app_obj.object_plotted.emit(obj)
|
|
|
|
if run_thread:
|
|
self.app.worker_task.emit({'fcn': worker_task, 'params': []})
|
|
else:
|
|
worker_task()
|
|
|
|
def on_exit(self, corner_gerber_obj):
|
|
# plot the object
|
|
try:
|
|
self.replot(obj=corner_gerber_obj)
|
|
except (AttributeError, TypeError):
|
|
return
|
|
|
|
# update the bounding box values
|
|
try:
|
|
a, b, c, d = self.grb_object.bounds()
|
|
self.grb_object.options['xmin'] = a
|
|
self.grb_object.options['ymin'] = b
|
|
self.grb_object.options['xmax'] = c
|
|
self.grb_object.options['ymax'] = d
|
|
except Exception as e:
|
|
log.debug("ToolCorners.on_exit() copper_obj bounds error --> %s" % str(e))
|
|
|
|
self.app.call_source = "app"
|
|
self.app.inform.emit('[success] %s' % _("A Gerber object with corner markers was created."))
|
|
|
|
|
|
class CornersUI:
|
|
|
|
toolName = _("Corner Markers Tool")
|
|
|
|
def __init__(self, layout, app):
|
|
self.app = app
|
|
self.decimals = self.app.decimals
|
|
self.layout = layout
|
|
|
|
# ## Title
|
|
title_label = FCLabel("%s" % self.toolName)
|
|
title_label.setStyleSheet("""
|
|
QLabel
|
|
{
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
}
|
|
""")
|
|
self.layout.addWidget(title_label)
|
|
self.layout.addWidget(FCLabel(""))
|
|
|
|
# Gerber object #
|
|
self.object_label = FCLabel('<b>%s:</b>' % _("GERBER"))
|
|
self.object_label.setToolTip(
|
|
_("The Gerber object to which will be added corner markers.")
|
|
)
|
|
self.object_combo = FCComboBox()
|
|
self.object_combo.setModel(self.app.collection)
|
|
self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
|
self.object_combo.is_last = True
|
|
self.object_combo.obj_type = "Gerber"
|
|
|
|
self.layout.addWidget(self.object_label)
|
|
self.layout.addWidget(self.object_combo)
|
|
|
|
separator_line = QtWidgets.QFrame()
|
|
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
|
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
|
self.layout.addWidget(separator_line)
|
|
|
|
self.points_label = FCLabel('<b>%s:</b>' % _('Locations'))
|
|
self.points_label.setToolTip(
|
|
_("Locations where to place corner markers.")
|
|
)
|
|
self.layout.addWidget(self.points_label)
|
|
|
|
# ## Grid Layout
|
|
grid_loc = QtWidgets.QGridLayout()
|
|
self.layout.addLayout(grid_loc)
|
|
|
|
# TOP LEFT
|
|
self.tl_cb = FCCheckBox(_("Top Left"))
|
|
grid_loc.addWidget(self.tl_cb, 0, 0)
|
|
|
|
# TOP RIGHT
|
|
self.tr_cb = FCCheckBox(_("Top Right"))
|
|
grid_loc.addWidget(self.tr_cb, 0, 1)
|
|
|
|
# BOTTOM LEFT
|
|
self.bl_cb = FCCheckBox(_("Bottom Left"))
|
|
grid_loc.addWidget(self.bl_cb, 1, 0)
|
|
|
|
# BOTTOM RIGHT
|
|
self.br_cb = FCCheckBox(_("Bottom Right"))
|
|
grid_loc.addWidget(self.br_cb, 1, 1)
|
|
|
|
separator_line = QtWidgets.QFrame()
|
|
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
|
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
|
self.layout.addWidget(separator_line)
|
|
|
|
# Toggle ALL
|
|
self.toggle_all_cb = FCCheckBox(_("Toggle ALL"))
|
|
self.layout.addWidget(self.toggle_all_cb)
|
|
|
|
separator_line = QtWidgets.QFrame()
|
|
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
|
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
|
self.layout.addWidget(separator_line)
|
|
|
|
# ## Grid Layout
|
|
grid_lay = QtWidgets.QGridLayout()
|
|
self.layout.addLayout(grid_lay)
|
|
grid_lay.setColumnStretch(0, 0)
|
|
grid_lay.setColumnStretch(1, 1)
|
|
|
|
self.param_label = FCLabel('<b>%s:</b>' % _('Parameters'))
|
|
self.param_label.setToolTip(
|
|
_("Parameters used for this tool.")
|
|
)
|
|
grid_lay.addWidget(self.param_label, 0, 0, 1, 2)
|
|
|
|
# Type of Marker
|
|
self.type_label = FCLabel('%s:' % _("Type"))
|
|
self.type_label.setToolTip(
|
|
_("Shape of the marker.")
|
|
)
|
|
|
|
self.type_radio = RadioSet([
|
|
{"label": _("Semi-Cross"), "value": "s"},
|
|
{"label": _("Cross"), "value": "c"},
|
|
])
|
|
|
|
grid_lay.addWidget(self.type_label, 2, 0)
|
|
grid_lay.addWidget(self.type_radio, 2, 1)
|
|
|
|
# Thickness #
|
|
self.thick_label = FCLabel('%s:' % _("Thickness"))
|
|
self.thick_label.setToolTip(
|
|
_("The thickness of the line that makes the corner marker.")
|
|
)
|
|
self.thick_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
|
self.thick_entry.set_range(0.0000, 10.0000)
|
|
self.thick_entry.set_precision(self.decimals)
|
|
self.thick_entry.setWrapping(True)
|
|
self.thick_entry.setSingleStep(10 ** -self.decimals)
|
|
|
|
grid_lay.addWidget(self.thick_label, 4, 0)
|
|
grid_lay.addWidget(self.thick_entry, 4, 1)
|
|
|
|
# Length #
|
|
self.l_label = FCLabel('%s:' % _("Length"))
|
|
self.l_label.setToolTip(
|
|
_("The length of the line that makes the corner marker.")
|
|
)
|
|
self.l_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
|
self.l_entry.set_range(-10000.0000, 10000.0000)
|
|
self.l_entry.set_precision(self.decimals)
|
|
self.l_entry.setSingleStep(10 ** -self.decimals)
|
|
|
|
grid_lay.addWidget(self.l_label, 6, 0)
|
|
grid_lay.addWidget(self.l_entry, 6, 1)
|
|
|
|
# Margin #
|
|
self.margin_label = FCLabel('%s:' % _("Margin"))
|
|
self.margin_label.setToolTip(
|
|
_("Bounding box margin.")
|
|
)
|
|
self.margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
|
self.margin_entry.set_range(-10000.0000, 10000.0000)
|
|
self.margin_entry.set_precision(self.decimals)
|
|
self.margin_entry.setSingleStep(0.1)
|
|
|
|
grid_lay.addWidget(self.margin_label, 8, 0)
|
|
grid_lay.addWidget(self.margin_entry, 8, 1)
|
|
|
|
# separator_line_2 = QtWidgets.QFrame()
|
|
# separator_line_2.setFrameShape(QtWidgets.QFrame.HLine)
|
|
# separator_line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
|
|
# grid_lay.addWidget(separator_line_2, 10, 0, 1, 2)
|
|
|
|
# ## Insert Corner Marker
|
|
self.add_marker_button = FCButton(_("Add Marker"))
|
|
self.add_marker_button.setIcon(QtGui.QIcon(self.app.resource_location + '/corners_32.png'))
|
|
self.add_marker_button.setToolTip(
|
|
_("Will add corner markers to the selected Gerber file.")
|
|
)
|
|
self.add_marker_button.setStyleSheet("""
|
|
QPushButton
|
|
{
|
|
font-weight: bold;
|
|
}
|
|
""")
|
|
grid_lay.addWidget(self.add_marker_button, 12, 0, 1, 2)
|
|
|
|
separator_line_2 = QtWidgets.QFrame()
|
|
separator_line_2.setFrameShape(QtWidgets.QFrame.HLine)
|
|
separator_line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
|
|
grid_lay.addWidget(separator_line_2, 14, 0, 1, 2)
|
|
|
|
# Drill is corners
|
|
self.drills_label = FCLabel('<b>%s:</b>' % _('Drills in Corners'))
|
|
grid_lay.addWidget(self.drills_label, 16, 0, 1, 2)
|
|
|
|
# Drill Tooldia #
|
|
self.drill_dia_label = FCLabel('%s:' % _("Tool Dia"))
|
|
self.drill_dia_label.setToolTip(
|
|
'%s.' % _("Drill Diameter")
|
|
)
|
|
self.drill_dia_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
|
self.drill_dia_entry.set_range(0.0000, 100.0000)
|
|
self.drill_dia_entry.set_precision(self.decimals)
|
|
self.drill_dia_entry.setWrapping(True)
|
|
|
|
grid_lay.addWidget(self.drill_dia_label, 18, 0)
|
|
grid_lay.addWidget(self.drill_dia_entry, 18, 1)
|
|
|
|
# ## Create an Excellon object
|
|
self.drill_button = FCButton(_("Create Excellon Object"))
|
|
self.drill_button.setIcon(QtGui.QIcon(self.app.resource_location + '/drill32.png'))
|
|
self.drill_button.setToolTip(
|
|
_("Will add drill holes in the center of the markers.")
|
|
)
|
|
self.drill_button.setStyleSheet("""
|
|
QPushButton
|
|
{
|
|
font-weight: bold;
|
|
}
|
|
""")
|
|
grid_lay.addWidget(self.drill_button, 20, 0, 1, 2)
|
|
|
|
self.layout.addStretch()
|
|
|
|
# ## Reset Tool
|
|
self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
|
|
self.reset_button.setIcon(QtGui.QIcon(self.app.resource_location + '/reset32.png'))
|
|
self.reset_button.setToolTip(
|
|
_("Will reset the tool parameters.")
|
|
)
|
|
self.reset_button.setStyleSheet("""
|
|
QPushButton
|
|
{
|
|
font-weight: bold;
|
|
}
|
|
""")
|
|
self.layout.addWidget(self.reset_button)
|
|
|
|
# #################################### FINSIHED GUI ###########################
|
|
# #############################################################################
|
|
|
|
def confirmation_message(self, accepted, minval, maxval):
|
|
if accepted is False:
|
|
self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' % (_("Edited value is out of range"),
|
|
self.decimals,
|
|
minval,
|
|
self.decimals,
|
|
maxval), False)
|
|
else:
|
|
self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
|
|
|
|
def confirmation_message_int(self, accepted, minval, maxval):
|
|
if accepted is False:
|
|
self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%d, %d]' %
|
|
(_("Edited value is out of range"), minval, maxval), False)
|
|
else:
|
|
self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False) |