- in Tools: Film, Image, InvertGerber, Optimal, PcbWizard - moved the Tool UI in its own class

This commit is contained in:
Marius Stanciu
2020-08-27 21:37:00 +03:00
parent b3a22f3d0a
commit c45444a772
6 changed files with 823 additions and 716 deletions

View File

@@ -16,6 +16,7 @@ CHANGELOG for FlatCAM beta
- in Tool Cutout: modified the UI in preparation for adding the Mouse Bites feature
- Turkish translation strings were updated by the translator, Mehmet Kaya
- Film Tool - moved the Tool UI in its own class
- in Tools: Film, Image, InvertGerber, Optimal, PcbWizard - moved the Tool UI in its own class
26.08.2020

View File

@@ -9,7 +9,7 @@ from PyQt5 import QtCore, QtWidgets, QtGui
from appTool import AppTool
from appGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, \
OptionalHideInputSection, FCComboBox, FCFileSaveDialog
OptionalHideInputSection, FCComboBox, FCFileSaveDialog, FCButton, FCLabel
from copy import deepcopy
import logging
@@ -759,7 +759,7 @@ class FilmUI:
self.layout = layout
# ## Title
title_label = QtWidgets.QLabel("%s" % self.toolName)
title_label = FCLabel("%s" % self.toolName)
title_label.setStyleSheet("""
QLabel
{
@@ -768,7 +768,7 @@ class FilmUI:
}
""")
self.layout.addWidget(title_label)
self.layout.addWidget(QtWidgets.QLabel(""))
self.layout.addWidget(FCLabel(""))
# Form Layout
grid0 = QtWidgets.QGridLayout()
@@ -781,7 +781,7 @@ class FilmUI:
self.tf_type_obj_combo = RadioSet([{'label': _('Gerber'), 'value': 'grb'},
{'label': _('Geometry'), 'value': 'geo'}])
self.tf_type_obj_combo_label = QtWidgets.QLabel('<b>%s</b>:' % _("Object"))
self.tf_type_obj_combo_label = FCLabel('<b>%s</b>:' % _("Object"))
self.tf_type_obj_combo_label.setToolTip(
_("Specify the type of object for which to create the film.\n"
"The object can be of type: Gerber or Geometry.\n"
@@ -804,7 +804,7 @@ class FilmUI:
self.tf_type_box_combo = RadioSet([{'label': _('Gerber'), 'value': 'grb'},
{'label': _('Geometry'), 'value': 'geo'}])
self.tf_type_box_combo_label = QtWidgets.QLabel(_("Box Type:"))
self.tf_type_box_combo_label = FCLabel(_("Box Type:"))
self.tf_type_box_combo_label.setToolTip(
_("Specify the type of object to be used as an container for\n"
"film creation. It can be: Gerber or Geometry type."
@@ -827,7 +827,7 @@ class FilmUI:
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
grid0.addWidget(separator_line, 4, 0, 1, 2)
self.film_adj_label = QtWidgets.QLabel('<b>%s</b>' % _("Film Adjustments"))
self.film_adj_label = FCLabel('<b>%s</b>' % _("Film Adjustments"))
self.film_adj_label.setToolTip(
_("Sometime the printers will distort the print shape, especially the Laser types.\n"
"This section provide the tools to compensate for the print distortions.")
@@ -848,7 +848,7 @@ class FilmUI:
)
grid0.addWidget(self.film_scale_cb, 6, 0, 1, 2)
self.film_scalex_label = QtWidgets.QLabel('%s:' % _("X factor"))
self.film_scalex_label = FCLabel('%s:' % _("X factor"))
self.film_scalex_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.film_scalex_entry.set_range(-999.9999, 999.9999)
self.film_scalex_entry.set_precision(self.decimals)
@@ -857,7 +857,7 @@ class FilmUI:
grid0.addWidget(self.film_scalex_label, 7, 0)
grid0.addWidget(self.film_scalex_entry, 7, 1)
self.film_scaley_label = QtWidgets.QLabel('%s:' % _("Y factor"))
self.film_scaley_label = FCLabel('%s:' % _("Y factor"))
self.film_scaley_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.film_scaley_entry.set_range(-999.9999, 999.9999)
self.film_scaley_entry.set_precision(self.decimals)
@@ -892,7 +892,7 @@ class FilmUI:
)
grid0.addWidget(self.film_skew_cb, 10, 0, 1, 2)
self.film_skewx_label = QtWidgets.QLabel('%s:' % _("X angle"))
self.film_skewx_label = FCLabel('%s:' % _("X angle"))
self.film_skewx_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.film_skewx_entry.set_range(-999.9999, 999.9999)
self.film_skewx_entry.set_precision(self.decimals)
@@ -901,7 +901,7 @@ class FilmUI:
grid0.addWidget(self.film_skewx_label, 11, 0)
grid0.addWidget(self.film_skewx_entry, 11, 1)
self.film_skewy_label = QtWidgets.QLabel('%s:' % _("Y angle"))
self.film_skewy_label = FCLabel('%s:' % _("Y angle"))
self.film_skewy_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.film_skewy_entry.set_range(-999.9999, 999.9999)
self.film_skewy_entry.set_precision(self.decimals)
@@ -910,7 +910,7 @@ class FilmUI:
grid0.addWidget(self.film_skewy_label, 12, 0)
grid0.addWidget(self.film_skewy_entry, 12, 1)
self.film_skew_ref_label = QtWidgets.QLabel('%s:' % _("Reference"))
self.film_skew_ref_label = FCLabel('%s:' % _("Reference"))
self.film_skew_ref_label.setToolTip(
_("The reference point to be used as origin for the skew.\n"
"It can be one of the four points of the geometry bounding box.")
@@ -957,7 +957,7 @@ class FilmUI:
{'label': _('Y'), 'value': 'y'},
{'label': _('Both'), 'value': 'both'}],
stretch=False)
self.film_mirror_axis_label = QtWidgets.QLabel('%s:' % _("Mirror axis"))
self.film_mirror_axis_label = FCLabel('%s:' % _("Mirror axis"))
grid0.addWidget(self.film_mirror_axis_label, 16, 0)
grid0.addWidget(self.film_mirror_axis, 16, 1)
@@ -973,7 +973,7 @@ class FilmUI:
separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
grid0.addWidget(separator_line2, 17, 0, 1, 2)
self.film_param_label = QtWidgets.QLabel('<b>%s</b>' % _("Film Parameters"))
self.film_param_label = FCLabel('<b>%s</b>' % _("Film Parameters"))
grid0.addWidget(self.film_param_label, 18, 0, 1, 2)
@@ -983,7 +983,7 @@ class FilmUI:
self.film_scale_stroke_entry.setSingleStep(0.01)
self.film_scale_stroke_entry.set_precision(self.decimals)
self.film_scale_stroke_label = QtWidgets.QLabel('%s:' % _("Scale Stroke"))
self.film_scale_stroke_label = FCLabel('%s:' % _("Scale Stroke"))
self.film_scale_stroke_label.setToolTip(
_("Scale the line stroke thickness of each feature in the SVG file.\n"
"It means that the line that envelope each SVG feature will be thicker or thinner,\n"
@@ -996,7 +996,7 @@ class FilmUI:
self.film_type = RadioSet([{'label': _('Positive'), 'value': 'pos'},
{'label': _('Negative'), 'value': 'neg'}],
stretch=False)
self.film_type_label = QtWidgets.QLabel(_("Film Type:"))
self.film_type_label = FCLabel(_("Film Type:"))
self.film_type_label.setToolTip(
_("Generate a Positive black film or a Negative film.\n"
"Positive means that it will print the features\n"
@@ -1014,7 +1014,7 @@ class FilmUI:
self.boundary_entry.setSingleStep(0.01)
self.boundary_entry.set_precision(self.decimals)
self.boundary_label = QtWidgets.QLabel('%s:' % _("Border"))
self.boundary_label = FCLabel('%s:' % _("Border"))
self.boundary_label.setToolTip(
_("Specify a border around the object.\n"
"Only for negative film.\n"
@@ -1051,7 +1051,7 @@ class FilmUI:
self.ois_p = OptionalHideInputSection(self.punch_cb, [self.punch_frame])
self.source_label = QtWidgets.QLabel('%s:' % _("Source"))
self.source_label = FCLabel('%s:' % _("Source"))
self.source_label.setToolTip(
_("The punch hole source can be:\n"
"- Excellon -> an Excellon holes center will serve as reference.\n"
@@ -1063,7 +1063,7 @@ class FilmUI:
punch_grid.addWidget(self.source_label, 0, 0)
punch_grid.addWidget(self.source_punch, 0, 1)
self.exc_label = QtWidgets.QLabel('%s:' % _("Excellon Obj"))
self.exc_label = FCLabel('%s:' % _("Excellon Obj"))
self.exc_label.setToolTip(
_("Remove the geometry of Excellon from the Film to create the holes in pads.")
)
@@ -1079,7 +1079,7 @@ class FilmUI:
self.exc_label.hide()
self.exc_combo.hide()
self.punch_size_label = QtWidgets.QLabel('%s:' % _("Punch Size"))
self.punch_size_label = FCLabel('%s:' % _("Punch Size"))
self.punch_size_label.setToolTip(_("The value here will control how big is the punch hole in the pads."))
self.punch_size_spinner = FCDoubleSpinner(callback=self.confirmation_message)
self.punch_size_spinner.set_range(0, 999.9999)
@@ -1108,7 +1108,7 @@ class FilmUI:
{'label': _('PDF'), 'value': 'pdf'}
], stretch=False)
self.file_type_label = QtWidgets.QLabel(_("Film Type:"))
self.file_type_label = FCLabel(_("Film Type:"))
self.file_type_label.setToolTip(
_("The file type of the saved film. Can be:\n"
"- 'SVG' -> open-source vectorial format\n"
@@ -1119,7 +1119,7 @@ class FilmUI:
grid1.addWidget(self.file_type_radio, 1, 1)
# Page orientation
self.orientation_label = QtWidgets.QLabel('%s:' % _("Page Orientation"))
self.orientation_label = FCLabel('%s:' % _("Page Orientation"))
self.orientation_label.setToolTip(_("Can be:\n"
"- Portrait\n"
"- Landscape"))
@@ -1132,7 +1132,7 @@ class FilmUI:
grid1.addWidget(self.orientation_radio, 2, 1)
# Page Size
self.pagesize_label = QtWidgets.QLabel('%s:' % _("Page Size"))
self.pagesize_label = FCLabel('%s:' % _("Page Size"))
self.pagesize_label.setToolTip(_("A selection of standard ISO 216 page sizes."))
self.pagesize_combo = FCComboBox()
@@ -1200,7 +1200,8 @@ class FilmUI:
self.on_film_type(val='hide')
# Buttons
self.film_object_button = QtWidgets.QPushButton(_("Save Film"))
self.film_object_button = FCButton(_("Save Film"))
self.film_object_button.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as.png'))
self.film_object_button.setToolTip(
_("Create a Film for the selected object, within\n"
"the specified box. Does not create a new \n "
@@ -1218,7 +1219,7 @@ class FilmUI:
self.layout.addStretch()
# ## Reset Tool
self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
self.reset_button = FCButton(_("Reset Tool"))
self.reset_button.setIcon(QtGui.QIcon(self.app.resource_location + '/reset32.png'))
self.reset_button.setToolTip(
_("Will reset the tool parameters.")

View File

@@ -21,23 +21,165 @@ if '_' not in builtins.__dict__:
class ToolImage(AppTool):
toolName = _("Image as Object")
def __init__(self, app):
AppTool.__init__(self, app)
self.app = app
self.decimals = self.app.decimals
# Title
title_label = QtWidgets.QLabel("%s" % _('Image to PCB'))
# #############################################################################
# ######################### Tool GUI ##########################################
# #############################################################################
self.ui = ImageUI(layout=self.layout, app=self.app)
self.toolName = self.ui.toolName
# ## Signals
self.ui.import_button.clicked.connect(self.on_file_importimage)
self.ui.image_type.activated_custom.connect(self.ui.on_image_type)
def run(self, toggle=True):
self.app.defaults.report_usage("ToolImage()")
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, _("Image Tool"))
def install(self, icon=None, separator=None, **kwargs):
AppTool.install(self, icon, separator, **kwargs)
def set_tool_ui(self):
# ## Initialize form
self.ui.dpi_entry.set_value(96)
self.ui.image_type.set_value('black')
self.ui.mask_bw_entry.set_value(250)
self.ui.mask_r_entry.set_value(250)
self.ui.mask_g_entry.set_value(250)
self.ui.mask_b_entry.set_value(250)
def on_file_importimage(self):
"""
Callback for menu item File->Import IMAGE.
:param type_of_obj: to import the IMAGE as Geometry or as Gerber
:type type_of_obj: str
:return: None
"""
mask = []
self.app.log.debug("on_file_importimage()")
_filter = "Image Files(*.BMP *.PNG *.JPG *.JPEG);;" \
"Bitmap File (*.BMP);;" \
"PNG File (*.PNG);;" \
"Jpeg File (*.JPG);;" \
"All Files (*.*)"
try:
filename, _f = QtWidgets.QFileDialog.getOpenFileName(caption=_("Import IMAGE"),
directory=self.app.get_last_folder(), filter=_filter)
except TypeError:
filename, _f = QtWidgets.QFileDialog.getOpenFileName(caption=_("Import IMAGE"), filter=filter)
filename = str(filename)
type_obj = self.ui.tf_type_obj_combo.get_value()
dpi = self.ui.dpi_entry.get_value()
mode = self.ui.image_type.get_value()
mask = [
self.ui.mask_bw_entry.get_value(),
self.ui.mask_r_entry.get_value(),
self.ui.mask_g_entry.get_value(),
self.ui.mask_b_entry.get_value()
]
if filename == "":
self.app.inform.emit(_("Cancelled."))
else:
self.app.worker_task.emit({'fcn': self.import_image,
'params': [filename, type_obj, dpi, mode, mask]})
def import_image(self, filename, o_type=_("Gerber"), dpi=96, mode='black', mask=None, outname=None):
"""
Adds a new Geometry Object to the projects and populates
it with shapes extracted from the SVG file.
:param filename: Path to the SVG file.
:param o_type: type of FlatCAM objeect
:param dpi: dot per inch
:param mode: black or color
:param mask: dictate the level of detail
:param outname: name for the resulting file
:return:
"""
self.app.defaults.report_usage("import_image()")
if mask is None:
mask = [250, 250, 250, 250]
if o_type is None or o_type == _("Geometry"):
obj_type = "geometry"
elif o_type == _("Gerber"):
obj_type = "gerber"
else:
self.app.inform.emit('[ERROR_NOTCL] %s' %
_("Not supported type is picked as parameter. "
"Only Geometry and Gerber are supported"))
return
def obj_init(geo_obj, app_obj):
geo_obj.import_image(filename, units=units, dpi=dpi, mode=mode, mask=mask)
geo_obj.multigeo = False
with self.app.proc_container.new(_("Importing Image")) as proc:
# Object name
name = outname or filename.split('/')[-1].split('\\')[-1]
units = self.app.defaults['units']
self.app.app_obj.new_object(obj_type, name, obj_init)
# Register recent file
self.app.file_opened.emit("image", filename)
# GUI feedback
self.app.inform.emit('[success] %s: %s' % (_("Opened"), filename))
class ImageUI:
toolName = _("Image as Object")
def __init__(self, layout, app):
self.app = app
self.decimals = self.app.decimals
self.layout = layout
# ## Title
title_label = QtWidgets.QLabel("%s" % self.toolName)
title_label.setStyleSheet("""
QLabel
{
font-size: 16px;
font-weight: bold;
}
""")
QLabel
{
font-size: 16px;
font-weight: bold;
}
""")
self.layout.addWidget(title_label)
# Form Layout
@@ -53,8 +195,8 @@ class ToolImage(AppTool):
self.tf_type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
self.tf_type_obj_combo_label.setToolTip(
_("Specify the type of object to create from the image.\n"
"It can be of type: Gerber or Geometry.")
_("Specify the type of object to create from the image.\n"
"It can be of type: Gerber or Geometry.")
)
ti_form_layout.addRow(self.tf_type_obj_combo_label, self.tf_type_obj_combo)
@@ -63,7 +205,7 @@ class ToolImage(AppTool):
self.dpi_entry = FCSpinner(callback=self.confirmation_message_int)
self.dpi_entry.set_range(0, 99999)
self.dpi_label = QtWidgets.QLabel('%s:' % _("DPI value"))
self.dpi_label.setToolTip(_("Specify a DPI value for the image.") )
self.dpi_label.setToolTip(_("Specify a DPI value for the image."))
ti_form_layout.addRow(self.dpi_label, self.dpi_entry)
self.emty_lbl = QtWidgets.QLabel("")
@@ -150,48 +292,8 @@ class ToolImage(AppTool):
self.on_image_type(val=False)
# ## Signals
self.import_button.clicked.connect(self.on_file_importimage)
self.image_type.activated_custom.connect(self.on_image_type)
def run(self, toggle=True):
self.app.defaults.report_usage("ToolImage()")
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, _("Image Tool"))
def install(self, icon=None, separator=None, **kwargs):
AppTool.install(self, icon, separator, **kwargs)
def set_tool_ui(self):
# ## Initialize form
self.dpi_entry.set_value(96)
self.image_type.set_value('black')
self.mask_bw_entry.set_value(250)
self.mask_r_entry.set_value(250)
self.mask_g_entry.set_value(250)
self.mask_b_entry.set_value(250)
# #################################### FINSIHED GUI ###########################
# #############################################################################
def on_image_type(self, val):
if val == 'color':
@@ -215,83 +317,19 @@ class ToolImage(AppTool):
self.mask_bw_label.setDisabled(False)
self.mask_bw_entry.setDisabled(False)
def on_file_importimage(self):
"""
Callback for menu item File->Import IMAGE.
:param type_of_obj: to import the IMAGE as Geometry or as Gerber
:type type_of_obj: str
:return: None
"""
mask = []
self.app.log.debug("on_file_importimage()")
_filter = "Image Files(*.BMP *.PNG *.JPG *.JPEG);;" \
"Bitmap File (*.BMP);;" \
"PNG File (*.PNG);;" \
"Jpeg File (*.JPG);;" \
"All Files (*.*)"
try:
filename, _f = QtWidgets.QFileDialog.getOpenFileName(caption=_("Import IMAGE"),
directory=self.app.get_last_folder(), filter=_filter)
except TypeError:
filename, _f = QtWidgets.QFileDialog.getOpenFileName(caption=_("Import IMAGE"), filter=filter)
filename = str(filename)
type_obj = self.tf_type_obj_combo.get_value()
dpi = self.dpi_entry.get_value()
mode = self.image_type.get_value()
mask = [self.mask_bw_entry.get_value(), self.mask_r_entry.get_value(), self.mask_g_entry.get_value(),
self.mask_b_entry.get_value()]
if filename == "":
self.app.inform.emit(_("Cancelled."))
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.worker_task.emit({'fcn': self.import_image,
'params': [filename, type_obj, dpi, mode, mask]})
self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
def import_image(self, filename, o_type=_("Gerber"), dpi=96, mode='black', mask=None, outname=None):
"""
Adds a new Geometry Object to the projects and populates
it with shapes extracted from the SVG file.
:param filename: Path to the SVG file.
:param o_type: type of FlatCAM objeect
:param dpi: dot per inch
:param mode: black or color
:param mask: dictate the level of detail
:param outname: name for the resulting file
:return:
"""
self.app.defaults.report_usage("import_image()")
if mask is None:
mask = [250, 250, 250, 250]
if o_type is None or o_type == _("Geometry"):
obj_type = "geometry"
elif o_type == _("Gerber"):
obj_type = "gerber"
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.emit('[ERROR_NOTCL] %s' %
_("Not supported type is picked as parameter. "
"Only Geometry and Gerber are supported"))
return
def obj_init(geo_obj, app_obj):
geo_obj.import_image(filename, units=units, dpi=dpi, mode=mode, mask=mask)
geo_obj.multigeo = False
with self.app.proc_container.new(_("Importing Image")) as proc:
# Object name
name = outname or filename.split('/')[-1].split('\\')[-1]
units = self.app.defaults['units']
self.app.app_obj.new_object(obj_type, name, obj_init)
# Register recent file
self.app.file_opened.emit("image", filename)
# GUI feedback
self.app.inform.emit('[success] %s: %s' % (_("Opened"), filename))
self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)

View File

@@ -8,7 +8,7 @@
from PyQt5 import QtWidgets, QtCore, QtGui
from appTool import AppTool
from appGUI.GUIElements import FCButton, FCDoubleSpinner, RadioSet, FCComboBox
from appGUI.GUIElements import FCButton, FCDoubleSpinner, RadioSet, FCComboBox, FCLabel
from shapely.geometry import box
@@ -28,133 +28,20 @@ log = logging.getLogger('base')
class ToolInvertGerber(AppTool):
toolName = _("Invert Gerber Tool")
def __init__(self, app):
self.app = app
self.decimals = self.app.decimals
AppTool.__init__(self, app)
self.tools_frame = QtWidgets.QFrame()
self.tools_frame.setContentsMargins(0, 0, 0, 0)
self.layout.addWidget(self.tools_frame)
self.tools_box = QtWidgets.QVBoxLayout()
self.tools_box.setContentsMargins(0, 0, 0, 0)
self.tools_frame.setLayout(self.tools_box)
# #############################################################################
# ######################### Tool GUI ##########################################
# #############################################################################
self.ui = InvertUI(layout=self.layout, app=self.app)
self.toolName = self.ui.toolName
# Title
title_label = QtWidgets.QLabel("%s" % self.toolName)
title_label.setStyleSheet("""
QLabel
{
font-size: 16px;
font-weight: bold;
}
""")
self.tools_box.addWidget(title_label)
# Grid Layout
grid0 = QtWidgets.QGridLayout()
grid0.setColumnStretch(0, 0)
grid0.setColumnStretch(1, 1)
self.tools_box.addLayout(grid0)
grid0.addWidget(QtWidgets.QLabel(''), 0, 0, 1, 2)
# Target Gerber Object
self.gerber_combo = FCComboBox()
self.gerber_combo.setModel(self.app.collection)
self.gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.gerber_combo.is_last = True
self.gerber_combo.obj_type = "Gerber"
self.gerber_label = QtWidgets.QLabel('<b>%s:</b>' % _("GERBER"))
self.gerber_label.setToolTip(
_("Gerber object that will be inverted.")
)
grid0.addWidget(self.gerber_label, 1, 0, 1, 2)
grid0.addWidget(self.gerber_combo, 2, 0, 1, 2)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
grid0.addWidget(separator_line, 3, 0, 1, 2)
self.param_label = QtWidgets.QLabel("<b>%s:</b>" % _("Parameters"))
self.param_label.setToolTip('%s.' % _("Parameters for this tool"))
grid0.addWidget(self.param_label, 4, 0, 1, 2)
# Margin
self.margin_label = QtWidgets.QLabel('%s:' % _('Margin'))
self.margin_label.setToolTip(
_("Distance by which to avoid\n"
"the edges of the Gerber object.")
)
self.margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.margin_entry.set_precision(self.decimals)
self.margin_entry.set_range(0.0000, 9999.9999)
self.margin_entry.setObjectName(_("Margin"))
grid0.addWidget(self.margin_label, 5, 0, 1, 2)
grid0.addWidget(self.margin_entry, 6, 0, 1, 2)
self.join_label = QtWidgets.QLabel('%s:' % _("Lines Join Style"))
self.join_label.setToolTip(
_("The way that the lines in the object outline will be joined.\n"
"Can be:\n"
"- rounded -> an arc is added between two joining lines\n"
"- square -> the lines meet in 90 degrees angle\n"
"- bevel -> the lines are joined by a third line")
)
self.join_radio = RadioSet([
{'label': 'Rounded', 'value': 'r'},
{'label': 'Square', 'value': 's'},
{'label': 'Bevel', 'value': 'b'}
], orientation='vertical', stretch=False)
grid0.addWidget(self.join_label, 7, 0, 1, 2)
grid0.addWidget(self.join_radio, 8, 0, 1, 2)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
grid0.addWidget(separator_line, 9, 0, 1, 2)
self.invert_btn = FCButton(_('Invert Gerber'))
self.invert_btn.setToolTip(
_("Will invert the Gerber object: areas that have copper\n"
"will be empty of copper and previous empty area will be\n"
"filled with copper.")
)
self.invert_btn.setStyleSheet("""
QPushButton
{
font-weight: bold;
}
""")
grid0.addWidget(self.invert_btn, 10, 0, 1, 2)
self.tools_box.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.tools_box.addWidget(self.reset_button)
self.invert_btn.clicked.connect(self.on_grb_invert)
self.reset_button.clicked.connect(self.set_tool_ui)
self.ui.invert_btn.clicked.connect(self.on_grb_invert)
self.ui.reset_button.clicked.connect(self.set_tool_ui)
def install(self, icon=None, separator=None, **kwargs):
AppTool.install(self, icon, separator, shortcut='', **kwargs)
@@ -188,20 +75,20 @@ class ToolInvertGerber(AppTool):
self.app.ui.notebook.setTabText(2, _("Invert Tool"))
def set_tool_ui(self):
self.margin_entry.set_value(float(self.app.defaults["tools_invert_margin"]))
self.join_radio.set_value(self.app.defaults["tools_invert_join_style"])
self.ui.margin_entry.set_value(float(self.app.defaults["tools_invert_margin"]))
self.ui.join_radio.set_value(self.app.defaults["tools_invert_join_style"])
def on_grb_invert(self):
margin = self.margin_entry.get_value()
margin = self.ui.margin_entry.get_value()
if round(margin, self.decimals) == 0.0:
margin = 1E-10
join_style = {'r': 1, 'b': 3, 's': 2}[self.join_radio.get_value()]
join_style = {'r': 1, 'b': 3, 's': 2}[self.ui.join_radio.get_value()]
if join_style is None:
join_style = 'r'
grb_circle_steps = int(self.app.defaults["gerber_circle_steps"])
obj_name = self.gerber_combo.currentText()
obj_name = self.ui.gerber_combo.currentText()
outname = obj_name + "_inverted"
@@ -243,32 +130,6 @@ class ToolInvertGerber(AppTool):
new_apertures = {}
# for apid, val in grb_obj.apertures.items():
# new_apertures[apid] = {}
# for key in val:
# if key == 'geometry':
# new_apertures[apid]['geometry'] = []
# for elem in val['geometry']:
# geo_elem = {}
# if 'follow' in elem:
# try:
# geo_elem['clear'] = elem['follow'].buffer(val['size'] / 2.0).exterior
# except AttributeError:
# # TODO should test if width or height is bigger
# geo_elem['clear'] = elem['follow'].buffer(val['width'] / 2.0).exterior
# if 'clear' in elem:
# if isinstance(elem['clear'], Polygon):
# try:
# geo_elem['solid'] = elem['clear'].buffer(val['size'] / 2.0, grb_circle_steps)
# except AttributeError:
# # TODO should test if width or height is bigger
# geo_elem['solid'] = elem['clear'].buffer(val['width'] / 2.0, grb_circle_steps)
# else:
# geo_elem['follow'] = elem['clear']
# new_apertures[apid]['geometry'].append(deepcopy(geo_elem))
# else:
# new_apertures[apid][key] = deepcopy(val[key])
if '0' not in new_apertures:
new_apertures['0'] = {}
new_apertures['0']['type'] = 'C'
@@ -302,9 +163,155 @@ class ToolInvertGerber(AppTool):
self.app.app_obj.new_object('gerber', outname, init_func)
def reset_fields(self):
self.gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.ui.gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
@staticmethod
def poly2rings(poly):
return [poly.exterior] + [interior for interior in poly.interiors]
# end of file
class InvertUI:
toolName = _("Invert Gerber 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(""))
self.tools_frame = QtWidgets.QFrame()
self.tools_frame.setContentsMargins(0, 0, 0, 0)
self.layout.addWidget(self.tools_frame)
self.tools_box = QtWidgets.QVBoxLayout()
self.tools_box.setContentsMargins(0, 0, 0, 0)
self.tools_frame.setLayout(self.tools_box)
# Grid Layout
grid0 = QtWidgets.QGridLayout()
grid0.setColumnStretch(0, 0)
grid0.setColumnStretch(1, 1)
self.tools_box.addLayout(grid0)
# Target Gerber Object
self.gerber_combo = FCComboBox()
self.gerber_combo.setModel(self.app.collection)
self.gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.gerber_combo.is_last = True
self.gerber_combo.obj_type = "Gerber"
self.gerber_label = FCLabel('<b>%s:</b>' % _("GERBER"))
self.gerber_label.setToolTip(
_("Gerber object that will be inverted.")
)
grid0.addWidget(self.gerber_label, 1, 0, 1, 2)
grid0.addWidget(self.gerber_combo, 2, 0, 1, 2)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
grid0.addWidget(separator_line, 3, 0, 1, 2)
self.param_label = FCLabel("<b>%s:</b>" % _("Parameters"))
self.param_label.setToolTip('%s.' % _("Parameters for this tool"))
grid0.addWidget(self.param_label, 4, 0, 1, 2)
# Margin
self.margin_label = FCLabel('%s:' % _('Margin'))
self.margin_label.setToolTip(
_("Distance by which to avoid\n"
"the edges of the Gerber object.")
)
self.margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.margin_entry.set_precision(self.decimals)
self.margin_entry.set_range(0.0000, 9999.9999)
self.margin_entry.setObjectName(_("Margin"))
grid0.addWidget(self.margin_label, 5, 0, 1, 2)
grid0.addWidget(self.margin_entry, 6, 0, 1, 2)
self.join_label = FCLabel('%s:' % _("Lines Join Style"))
self.join_label.setToolTip(
_("The way that the lines in the object outline will be joined.\n"
"Can be:\n"
"- rounded -> an arc is added between two joining lines\n"
"- square -> the lines meet in 90 degrees angle\n"
"- bevel -> the lines are joined by a third line")
)
self.join_radio = RadioSet([
{'label': 'Rounded', 'value': 'r'},
{'label': 'Square', 'value': 's'},
{'label': 'Bevel', 'value': 'b'}
], orientation='vertical', stretch=False)
grid0.addWidget(self.join_label, 7, 0, 1, 2)
grid0.addWidget(self.join_radio, 8, 0, 1, 2)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
grid0.addWidget(separator_line, 9, 0, 1, 2)
self.invert_btn = FCButton(_('Invert Gerber'))
self.invert_btn.setToolTip(
_("Will invert the Gerber object: areas that have copper\n"
"will be empty of copper and previous empty area will be\n"
"filled with copper.")
)
self.invert_btn.setStyleSheet("""
QPushButton
{
font-weight: bold;
}
""")
grid0.addWidget(self.invert_btn, 10, 0, 1, 2)
self.tools_box.addStretch()
# ## Reset Tool
self.reset_button = FCButton(_("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.tools_box.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)

View File

@@ -30,8 +30,6 @@ log = logging.getLogger('base')
class ToolOptimal(AppTool):
toolName = _("Optimal Tool")
update_text = QtCore.pyqtSignal(list)
update_sec_distances = QtCore.pyqtSignal(dict)
@@ -41,222 +39,11 @@ class ToolOptimal(AppTool):
self.units = self.app.defaults['units'].upper()
self.decimals = self.app.decimals
# ############################################################################
# ############################ GUI creation ##################################
# ## Title
title_label = QtWidgets.QLabel("%s" % self.toolName)
title_label.setStyleSheet(
"""
QLabel
{
font-size: 16px;
font-weight: bold;
}
""")
self.layout.addWidget(title_label)
# ## Form Layout
form_lay = QtWidgets.QFormLayout()
self.layout.addLayout(form_lay)
form_lay.addRow(QtWidgets.QLabel(""))
# ## Gerber Object to mirror
self.gerber_object_combo = FCComboBox()
self.gerber_object_combo.setModel(self.app.collection)
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.gerber_object_combo.is_last = True
self.gerber_object_combo.obj_type = "Gerber"
self.gerber_object_label = QtWidgets.QLabel("<b>%s:</b>" % _("GERBER"))
self.gerber_object_label.setToolTip(
"Gerber object for which to find the minimum distance between copper features."
)
form_lay.addRow(self.gerber_object_label)
form_lay.addRow(self.gerber_object_combo)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
form_lay.addRow(separator_line)
# Precision = nr of decimals
self.precision_label = QtWidgets.QLabel('%s:' % _("Precision"))
self.precision_label.setToolTip(_("Number of decimals kept for found distances."))
self.precision_spinner = FCSpinner(callback=self.confirmation_message_int)
self.precision_spinner.set_range(2, 10)
self.precision_spinner.setWrapping(True)
form_lay.addRow(self.precision_label, self.precision_spinner)
# Results Title
self.title_res_label = QtWidgets.QLabel('<b>%s:</b>' % _("Minimum distance"))
self.title_res_label.setToolTip(_("Display minimum distance between copper features."))
form_lay.addRow(self.title_res_label)
# Result value
self.result_label = QtWidgets.QLabel('%s:' % _("Determined"))
self.result_entry = FCEntry()
self.result_entry.setReadOnly(True)
self.units_lbl = QtWidgets.QLabel(self.units.lower())
self.units_lbl.setDisabled(True)
hlay = QtWidgets.QHBoxLayout()
hlay.addWidget(self.result_entry)
hlay.addWidget(self.units_lbl)
form_lay.addRow(self.result_label, hlay)
# Frequency of minimum encounter
self.freq_label = QtWidgets.QLabel('%s:' % _("Occurring"))
self.freq_label.setToolTip(_("How many times this minimum is found."))
self.freq_entry = FCEntry()
self.freq_entry.setReadOnly(True)
form_lay.addRow(self.freq_label, self.freq_entry)
# Control if to display the locations of where the minimum was found
self.locations_cb = FCCheckBox(_("Minimum points coordinates"))
self.locations_cb.setToolTip(_("Coordinates for points where minimum distance was found."))
form_lay.addRow(self.locations_cb)
# Locations where minimum was found
self.locations_textb = FCTextArea(parent=self)
self.locations_textb.setPlaceholderText(
_("Coordinates for points where minimum distance was found.")
)
self.locations_textb.setReadOnly(True)
stylesheet = """
QTextEdit { selection-background-color:blue;
selection-color:white;
}
"""
self.locations_textb.setStyleSheet(stylesheet)
form_lay.addRow(self.locations_textb)
# Jump button
self.locate_button = QtWidgets.QPushButton(_("Jump to selected position"))
self.locate_button.setToolTip(
_("Select a position in the Locations text box and then\n"
"click this button.")
)
self.locate_button.setMinimumWidth(60)
self.locate_button.setDisabled(True)
form_lay.addRow(self.locate_button)
# Other distances in Gerber
self.title_second_res_label = QtWidgets.QLabel('<b>%s:</b>' % _("Other distances"))
self.title_second_res_label.setToolTip(_("Will display other distances in the Gerber file ordered from\n"
"the minimum to the maximum, not including the absolute minimum."))
form_lay.addRow(self.title_second_res_label)
# Control if to display the locations of where the minimum was found
self.sec_locations_cb = FCCheckBox(_("Other distances points coordinates"))
self.sec_locations_cb.setToolTip(_("Other distances and the coordinates for points\n"
"where the distance was found."))
form_lay.addRow(self.sec_locations_cb)
# this way I can hide/show the frame
self.sec_locations_frame = QtWidgets.QFrame()
self.sec_locations_frame.setContentsMargins(0, 0, 0, 0)
self.layout.addWidget(self.sec_locations_frame)
self.distances_box = QtWidgets.QVBoxLayout()
self.distances_box.setContentsMargins(0, 0, 0, 0)
self.sec_locations_frame.setLayout(self.distances_box)
# Other Distances label
self.distances_label = QtWidgets.QLabel('%s' % _("Gerber distances"))
self.distances_label.setToolTip(_("Other distances and the coordinates for points\n"
"where the distance was found."))
self.distances_box.addWidget(self.distances_label)
# Other distances
self.distances_textb = FCTextArea(parent=self)
self.distances_textb.setPlaceholderText(
_("Other distances and the coordinates for points\n"
"where the distance was found.")
)
self.distances_textb.setReadOnly(True)
stylesheet = """
QTextEdit { selection-background-color:blue;
selection-color:white;
}
"""
self.distances_textb.setStyleSheet(stylesheet)
self.distances_box.addWidget(self.distances_textb)
self.distances_box.addWidget(QtWidgets.QLabel(''))
# Other Locations label
self.locations_label = QtWidgets.QLabel('%s' % _("Points coordinates"))
self.locations_label.setToolTip(_("Other distances and the coordinates for points\n"
"where the distance was found."))
self.distances_box.addWidget(self.locations_label)
# Locations where minimum was found
self.locations_sec_textb = FCTextArea(parent=self)
self.locations_sec_textb.setPlaceholderText(
_("Other distances and the coordinates for points\n"
"where the distance was found.")
)
self.locations_sec_textb.setReadOnly(True)
stylesheet = """
QTextEdit { selection-background-color:blue;
selection-color:white;
}
"""
self.locations_sec_textb.setStyleSheet(stylesheet)
self.distances_box.addWidget(self.locations_sec_textb)
# Jump button
self.locate_sec_button = QtWidgets.QPushButton(_("Jump to selected position"))
self.locate_sec_button.setToolTip(
_("Select a position in the Locations text box and then\n"
"click this button.")
)
self.locate_sec_button.setMinimumWidth(60)
self.locate_sec_button.setDisabled(True)
self.distances_box.addWidget(self.locate_sec_button)
# GO button
self.calculate_button = QtWidgets.QPushButton(_("Find Minimum"))
self.calculate_button.setToolTip(
_("Calculate the minimum distance between copper features,\n"
"this will allow the determination of the right tool to\n"
"use for isolation or copper clearing.")
)
self.calculate_button.setStyleSheet("""
QPushButton
{
font-weight: bold;
}
""")
self.calculate_button.setMinimumWidth(60)
self.layout.addWidget(self.calculate_button)
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)
self.loc_ois = OptionalHideInputSection(self.locations_cb, [self.locations_textb, self.locate_button])
self.sec_loc_ois = OptionalHideInputSection(self.sec_locations_cb, [self.sec_locations_frame])
# ################## Finished GUI creation ###################################
# ############################################################################
# #############################################################################
# ######################### Tool GUI ##########################################
# #############################################################################
self.ui = OptimalUI(layout=self.layout, app=self.app)
self.toolName = self.ui.toolName
# this is the line selected in the textbox with the locations of the minimum
self.selected_text = ''
@@ -271,17 +58,17 @@ class ToolOptimal(AppTool):
# ############################################################################
# ############################ Signals #######################################
# ############################################################################
self.calculate_button.clicked.connect(self.find_minimum_distance)
self.locate_button.clicked.connect(self.on_locate_position)
self.update_text.connect(self.on_update_text)
self.locations_textb.cursorPositionChanged.connect(self.on_textbox_clicked)
self.ui.calculate_button.clicked.connect(self.find_minimum_distance)
self.ui.locate_button.clicked.connect(self.on_locate_position)
self.ui.update_text.connect(self.on_update_text)
self.ui.locations_textb.cursorPositionChanged.connect(self.on_textbox_clicked)
self.locate_sec_button.clicked.connect(self.on_locate_sec_position)
self.update_sec_distances.connect(self.on_update_sec_distances_txt)
self.distances_textb.cursorPositionChanged.connect(self.on_distances_textb_clicked)
self.locations_sec_textb.cursorPositionChanged.connect(self.on_locations_sec_clicked)
self.ui.locate_sec_button.clicked.connect(self.on_locate_sec_position)
self.ui.update_sec_distances.connect(self.on_update_sec_distances_txt)
self.ui.distances_textb.cursorPositionChanged.connect(self.on_distances_textb_clicked)
self.ui.locations_sec_textb.cursorPositionChanged.connect(self.on_locations_sec_clicked)
self.reset_button.clicked.connect(self.set_tool_ui)
self.ui.reset_button.clicked.connect(self.set_tool_ui)
def install(self, icon=None, separator=None, **kwargs):
AppTool.install(self, icon, separator, shortcut='Alt+O', **kwargs)
@@ -314,13 +101,13 @@ class ToolOptimal(AppTool):
self.app.ui.notebook.setTabText(2, _("Optimal Tool"))
def set_tool_ui(self):
self.result_entry.set_value(0.0)
self.freq_entry.set_value('0')
self.ui.result_entry.set_value(0.0)
self.ui.freq_entry.set_value('0')
self.precision_spinner.set_value(int(self.app.defaults["tools_opt_precision"]))
self.locations_textb.clear()
self.ui.precision_spinner.set_value(int(self.app.defaults["tools_opt_precision"]))
self.ui.locations_textb.clear()
# new cursor - select all document
cursor = self.locations_textb.textCursor()
cursor = self.ui.locations_textb.textCursor()
cursor.select(QtGui.QTextCursor.Document)
# clear previous selection highlight
@@ -328,20 +115,20 @@ class ToolOptimal(AppTool):
tmp.clearBackground()
cursor.setBlockFormat(tmp)
self.locations_textb.setVisible(False)
self.locate_button.setVisible(False)
self.ui.locations_textb.setVisible(False)
self.ui.locate_button.setVisible(False)
self.result_entry.set_value(0.0)
self.freq_entry.set_value('0')
self.ui.result_entry.set_value(0.0)
self.ui.freq_entry.set_value('0')
self.reset_fields()
def find_minimum_distance(self):
self.units = self.app.defaults['units'].upper()
self.decimals = int(self.precision_spinner.get_value())
self.decimals = int(self.ui.precision_spinner.get_value())
selection_index = self.gerber_object_combo.currentIndex()
selection_index = self.ui.gerber_object_combo.currentIndex()
model_index = self.app.collection.index(selection_index, 0, self.gerber_object_combo.rootModelIndex())
model_index = self.app.collection.index(selection_index, 0, self.ui.gerber_object_combo.rootModelIndex())
try:
fcobj = model_index.internalPointer().obj
except Exception as e:
@@ -426,17 +213,16 @@ class ToolOptimal(AppTool):
old_disp_number = disp_number
idx += 1
app_obj.inform.emit(
_("Optimal Tool. Finding the minimum distance."))
app_obj.inform.emit(_("Optimal Tool. Finding the minimum distance."))
min_list = list(self.min_dict.keys())
min_dist = min(min_list)
min_dist_string = '%.*f' % (self.decimals, float(min_dist))
self.result_entry.set_value(min_dist_string)
self.ui.result_entry.set_value(min_dist_string)
freq = len(self.min_dict[min_dist])
freq = '%d' % int(freq)
self.freq_entry.set_value(freq)
self.ui.freq_entry.set_value(freq)
min_locations = self.min_dict.pop(min_dist)
@@ -484,12 +270,12 @@ class ToolOptimal(AppTool):
for loc in data:
if loc:
txt += '%s, %s\n' % (str(loc[0]), str(loc[1]))
self.locations_textb.setPlainText(txt)
self.locate_button.setDisabled(False)
self.ui.locations_textb.setPlainText(txt)
self.ui.locate_button.setDisabled(False)
def on_textbox_clicked(self):
# new cursor - select all document
cursor = self.locations_textb.textCursor()
cursor = self.ui.locations_textb.textCursor()
cursor.select(QtGui.QTextCursor.Document)
# clear previous selection highlight
@@ -498,7 +284,7 @@ class ToolOptimal(AppTool):
cursor.setBlockFormat(tmp)
# new cursor - select the current line
cursor = self.locations_textb.textCursor()
cursor = self.ui.locations_textb.textCursor()
cursor.select(QtGui.QTextCursor.LineUnderCursor)
# highlight the current selected line
@@ -513,12 +299,12 @@ class ToolOptimal(AppTool):
txt = ''
for loc in distance_list:
txt += '%s\n' % str(loc)
self.distances_textb.setPlainText(txt)
self.locate_sec_button.setDisabled(False)
self.ui.distances_textb.setPlainText(txt)
self.ui.locate_sec_button.setDisabled(False)
def on_distances_textb_clicked(self):
# new cursor - select all document
cursor = self.distances_textb.textCursor()
cursor = self.ui.distances_textb.textCursor()
cursor.select(QtGui.QTextCursor.Document)
# clear previous selection highlight
@@ -527,7 +313,7 @@ class ToolOptimal(AppTool):
cursor.setBlockFormat(tmp)
# new cursor - select the current line
cursor = self.distances_textb.textCursor()
cursor = self.ui.distances_textb.textCursor()
cursor.select(QtGui.QTextCursor.LineUnderCursor)
# highlight the current selected line
@@ -545,11 +331,11 @@ class ToolOptimal(AppTool):
for loc in distance_list:
if loc:
txt += '%s, %s\n' % (str(loc[0]), str(loc[1]))
self.locations_sec_textb.setPlainText(txt)
self.ui.locations_sec_textb.setPlainText(txt)
def on_locations_sec_clicked(self):
# new cursor - select all document
cursor = self.locations_sec_textb.textCursor()
cursor = self.ui.locations_sec_textb.textCursor()
cursor.select(QtGui.QTextCursor.Document)
# clear previous selection highlight
@@ -558,7 +344,7 @@ class ToolOptimal(AppTool):
cursor.setBlockFormat(tmp)
# new cursor - select the current line
cursor = self.locations_sec_textb.textCursor()
cursor = self.ui.locations_sec_textb.textCursor()
cursor.select(QtGui.QTextCursor.LineUnderCursor)
# highlight the current selected line
@@ -593,5 +379,247 @@ class ToolOptimal(AppTool):
return
def reset_fields(self):
self.ui.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.ui.gerber_object_combo.setCurrentIndex(0)
class OptimalUI:
toolName = _("Optimal Tool")
def __init__(self, layout, app):
self.app = app
self.decimals = self.app.decimals
self.layout = layout
self.units = self.app.defaults['units'].upper()
# ## Title
title_label = QtWidgets.QLabel("%s" % self.toolName)
title_label.setStyleSheet("""
QLabel
{
font-size: 16px;
font-weight: bold;
}
""")
self.layout.addWidget(title_label)
self.layout.addWidget(QtWidgets.QLabel(""))
# ## Form Layout
form_lay = QtWidgets.QFormLayout()
self.layout.addLayout(form_lay)
# ## Gerber Object to mirror
self.gerber_object_combo = FCComboBox()
self.gerber_object_combo.setModel(self.app.collection)
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.gerber_object_combo.setCurrentIndex(0)
self.gerber_object_combo.is_last = True
self.gerber_object_combo.obj_type = "Gerber"
self.gerber_object_label = QtWidgets.QLabel("<b>%s:</b>" % _("GERBER"))
self.gerber_object_label.setToolTip(
"Gerber object for which to find the minimum distance between copper features."
)
form_lay.addRow(self.gerber_object_label)
form_lay.addRow(self.gerber_object_combo)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
form_lay.addRow(separator_line)
# Precision = nr of decimals
self.precision_label = QtWidgets.QLabel('%s:' % _("Precision"))
self.precision_label.setToolTip(_("Number of decimals kept for found distances."))
self.precision_spinner = FCSpinner(callback=self.confirmation_message_int)
self.precision_spinner.set_range(2, 10)
self.precision_spinner.setWrapping(True)
form_lay.addRow(self.precision_label, self.precision_spinner)
# Results Title
self.title_res_label = QtWidgets.QLabel('<b>%s:</b>' % _("Minimum distance"))
self.title_res_label.setToolTip(_("Display minimum distance between copper features."))
form_lay.addRow(self.title_res_label)
# Result value
self.result_label = QtWidgets.QLabel('%s:' % _("Determined"))
self.result_entry = FCEntry()
self.result_entry.setReadOnly(True)
self.units_lbl = QtWidgets.QLabel(self.units.lower())
self.units_lbl.setDisabled(True)
hlay = QtWidgets.QHBoxLayout()
hlay.addWidget(self.result_entry)
hlay.addWidget(self.units_lbl)
form_lay.addRow(self.result_label, hlay)
# Frequency of minimum encounter
self.freq_label = QtWidgets.QLabel('%s:' % _("Occurring"))
self.freq_label.setToolTip(_("How many times this minimum is found."))
self.freq_entry = FCEntry()
self.freq_entry.setReadOnly(True)
form_lay.addRow(self.freq_label, self.freq_entry)
# Control if to display the locations of where the minimum was found
self.locations_cb = FCCheckBox(_("Minimum points coordinates"))
self.locations_cb.setToolTip(_("Coordinates for points where minimum distance was found."))
form_lay.addRow(self.locations_cb)
# Locations where minimum was found
self.locations_textb = FCTextArea(parent=self)
self.locations_textb.setPlaceholderText(
_("Coordinates for points where minimum distance was found.")
)
self.locations_textb.setReadOnly(True)
stylesheet = """
QTextEdit { selection-background-color:blue;
selection-color:white;
}
"""
self.locations_textb.setStyleSheet(stylesheet)
form_lay.addRow(self.locations_textb)
# Jump button
self.locate_button = QtWidgets.QPushButton(_("Jump to selected position"))
self.locate_button.setToolTip(
_("Select a position in the Locations text box and then\n"
"click this button.")
)
self.locate_button.setMinimumWidth(60)
self.locate_button.setDisabled(True)
form_lay.addRow(self.locate_button)
# Other distances in Gerber
self.title_second_res_label = QtWidgets.QLabel('<b>%s:</b>' % _("Other distances"))
self.title_second_res_label.setToolTip(_("Will display other distances in the Gerber file ordered from\n"
"the minimum to the maximum, not including the absolute minimum."))
form_lay.addRow(self.title_second_res_label)
# Control if to display the locations of where the minimum was found
self.sec_locations_cb = FCCheckBox(_("Other distances points coordinates"))
self.sec_locations_cb.setToolTip(_("Other distances and the coordinates for points\n"
"where the distance was found."))
form_lay.addRow(self.sec_locations_cb)
# this way I can hide/show the frame
self.sec_locations_frame = QtWidgets.QFrame()
self.sec_locations_frame.setContentsMargins(0, 0, 0, 0)
self.layout.addWidget(self.sec_locations_frame)
self.distances_box = QtWidgets.QVBoxLayout()
self.distances_box.setContentsMargins(0, 0, 0, 0)
self.sec_locations_frame.setLayout(self.distances_box)
# Other Distances label
self.distances_label = QtWidgets.QLabel('%s' % _("Gerber distances"))
self.distances_label.setToolTip(_("Other distances and the coordinates for points\n"
"where the distance was found."))
self.distances_box.addWidget(self.distances_label)
# Other distances
self.distances_textb = FCTextArea(parent=self)
self.distances_textb.setPlaceholderText(
_("Other distances and the coordinates for points\n"
"where the distance was found.")
)
self.distances_textb.setReadOnly(True)
stylesheet = """
QTextEdit { selection-background-color:blue;
selection-color:white;
}
"""
self.distances_textb.setStyleSheet(stylesheet)
self.distances_box.addWidget(self.distances_textb)
self.distances_box.addWidget(QtWidgets.QLabel(''))
# Other Locations label
self.locations_label = QtWidgets.QLabel('%s' % _("Points coordinates"))
self.locations_label.setToolTip(_("Other distances and the coordinates for points\n"
"where the distance was found."))
self.distances_box.addWidget(self.locations_label)
# Locations where minimum was found
self.locations_sec_textb = FCTextArea(parent=self)
self.locations_sec_textb.setPlaceholderText(
_("Other distances and the coordinates for points\n"
"where the distance was found.")
)
self.locations_sec_textb.setReadOnly(True)
stylesheet = """
QTextEdit { selection-background-color:blue;
selection-color:white;
}
"""
self.locations_sec_textb.setStyleSheet(stylesheet)
self.distances_box.addWidget(self.locations_sec_textb)
# Jump button
self.locate_sec_button = QtWidgets.QPushButton(_("Jump to selected position"))
self.locate_sec_button.setToolTip(
_("Select a position in the Locations text box and then\n"
"click this button.")
)
self.locate_sec_button.setMinimumWidth(60)
self.locate_sec_button.setDisabled(True)
self.distances_box.addWidget(self.locate_sec_button)
# GO button
self.calculate_button = QtWidgets.QPushButton(_("Find Minimum"))
self.calculate_button.setToolTip(
_("Calculate the minimum distance between copper features,\n"
"this will allow the determination of the right tool to\n"
"use for isolation or copper clearing.")
)
self.calculate_button.setStyleSheet("""
QPushButton
{
font-weight: bold;
}
""")
self.calculate_button.setMinimumWidth(60)
self.layout.addWidget(self.calculate_button)
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)
self.loc_ois = OptionalHideInputSection(self.locations_cb, [self.locations_textb, self.locate_button])
self.sec_loc_ois = OptionalHideInputSection(self.sec_locations_cb, [self.sec_locations_frame])
# #################################### 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)

View File

@@ -8,7 +8,7 @@
from PyQt5 import QtWidgets, QtCore
from appTool import AppTool
from appGUI.GUIElements import RadioSet, FCSpinner, FCButton, FCTable
from appGUI.GUIElements import RadioSet, FCSpinner, FCButton, FCTable, FCLabel
import re
import os
@@ -28,121 +28,17 @@ class PcbWizard(AppTool):
file_loaded = QtCore.pyqtSignal(str, str)
toolName = _("PcbWizard Import Tool")
def __init__(self, app):
AppTool.__init__(self, app)
self.app = app
self.decimals = self.app.decimals
# Title
title_label = QtWidgets.QLabel("%s" % _('Import 2-file Excellon'))
title_label.setStyleSheet("""
QLabel
{
font-size: 16px;
font-weight: bold;
}
""")
self.layout.addWidget(title_label)
self.layout.addWidget(QtWidgets.QLabel(""))
self.layout.addWidget(QtWidgets.QLabel("<b>%s:</b>" % _("Load files")))
# Form Layout
form_layout = QtWidgets.QFormLayout()
self.layout.addLayout(form_layout)
self.excellon_label = QtWidgets.QLabel('%s:' % _("Excellon file"))
self.excellon_label.setToolTip(
_("Load the Excellon file.\n"
"Usually it has a .DRL extension")
)
self.excellon_brn = FCButton(_("Open"))
form_layout.addRow(self.excellon_label, self.excellon_brn)
self.inf_label = QtWidgets.QLabel('%s:' % _("INF file"))
self.inf_label.setToolTip(
_("Load the INF file.")
)
self.inf_btn = FCButton(_("Open"))
form_layout.addRow(self.inf_label, self.inf_btn)
self.tools_table = FCTable()
self.layout.addWidget(self.tools_table)
self.tools_table.setColumnCount(2)
self.tools_table.setHorizontalHeaderLabels(['#Tool', _('Diameter')])
self.tools_table.horizontalHeaderItem(0).setToolTip(
_("Tool Number"))
self.tools_table.horizontalHeaderItem(1).setToolTip(
_("Tool diameter in file units."))
# start with apertures table hidden
self.tools_table.setVisible(False)
self.layout.addWidget(QtWidgets.QLabel(""))
self.layout.addWidget(QtWidgets.QLabel("<b>%s:</b>" % _("Excellon format")))
# Form Layout
form_layout1 = QtWidgets.QFormLayout()
self.layout.addLayout(form_layout1)
# Integral part of the coordinates
self.int_entry = FCSpinner(callback=self.confirmation_message_int)
self.int_entry.set_range(1, 10)
self.int_label = QtWidgets.QLabel('%s:' % _("Int. digits"))
self.int_label.setToolTip(
_("The number of digits for the integral part of the coordinates.")
)
form_layout1.addRow(self.int_label, self.int_entry)
# Fractional part of the coordinates
self.frac_entry = FCSpinner(callback=self.confirmation_message_int)
self.frac_entry.set_range(1, 10)
self.frac_label = QtWidgets.QLabel('%s:' % _("Frac. digits"))
self.frac_label.setToolTip(
_("The number of digits for the fractional part of the coordinates.")
)
form_layout1.addRow(self.frac_label, self.frac_entry)
# Zeros suppression for coordinates
self.zeros_radio = RadioSet([{'label': _('LZ'), 'value': 'LZ'},
{'label': _('TZ'), 'value': 'TZ'},
{'label': _('No Suppression'), 'value': 'D'}])
self.zeros_label = QtWidgets.QLabel('%s:' % _("Zeros supp."))
self.zeros_label.setToolTip(
_("The type of zeros suppression used.\n"
"Can be of type:\n"
"- LZ = leading zeros are kept\n"
"- TZ = trailing zeros are kept\n"
"- No Suppression = no zero suppression")
)
form_layout1.addRow(self.zeros_label, self.zeros_radio)
# Units type
self.units_radio = RadioSet([{'label': _('INCH'), 'value': 'INCH'},
{'label': _('MM'), 'value': 'METRIC'}])
self.units_label = QtWidgets.QLabel("<b>%s:</b>" % _('Units'))
self.units_label.setToolTip(
_("The type of units that the coordinates and tool\n"
"diameters are using. Can be INCH or MM.")
)
form_layout1.addRow(self.units_label, self.units_radio)
# Buttons
self.import_button = QtWidgets.QPushButton(_("Import Excellon"))
self.import_button.setToolTip(
_("Import in FlatCAM an Excellon file\n"
"that store it's information's in 2 files.\n"
"One usually has .DRL extension while\n"
"the other has .INF extension.")
)
self.layout.addWidget(self.import_button)
self.layout.addStretch()
# #############################################################################
# ######################### Tool GUI ##########################################
# #############################################################################
self.ui = WizardUI(layout=self.layout, app=self.app)
self.toolName = self.ui.toolName
self.excellon_loaded = False
self.inf_loaded = False
@@ -151,13 +47,13 @@ class PcbWizard(AppTool):
self.modified_excellon_file = ''
# ## Signals
self.excellon_brn.clicked.connect(self.on_load_excellon_click)
self.inf_btn.clicked.connect(self.on_load_inf_click)
self.import_button.clicked.connect(lambda: self.on_import_excellon(
self.ui.excellon_brn.clicked.connect(self.on_load_excellon_click)
self.ui.inf_btn.clicked.connect(self.on_load_inf_click)
self.ui.import_button.clicked.connect(lambda: self.on_import_excellon(
excellon_fileobj=self.modified_excellon_file))
self.file_loaded.connect(self.on_file_loaded)
self.units_radio.activated_custom.connect(self.on_units_change)
self.ui.units_radio.activated_custom.connect(self.ui.on_units_change)
self.units = 'INCH'
self.zeros = 'LZ'
@@ -211,10 +107,10 @@ class PcbWizard(AppTool):
self.tools_from_inf = {}
# ## Initialize form
self.int_entry.set_value(self.integral)
self.frac_entry.set_value(self.fractional)
self.zeros_radio.set_value(self.zeros)
self.units_radio.set_value(self.units)
self.ui.int_entry.set_value(self.integral)
self.ui.frac_entry.set_value(self.fractional)
self.ui.zeros_radio.set_value(self.zeros)
self.ui.units_radio.set_value(self.units)
self.excellon_loaded = False
self.inf_loaded = False
@@ -227,57 +123,49 @@ class PcbWizard(AppTool):
sorted_tools = []
if not self.tools_from_inf:
self.tools_table.setVisible(False)
self.ui.tools_table.setVisible(False)
else:
sort = []
for k, v in list(self.tools_from_inf.items()):
sort.append(int(k))
sorted_tools = sorted(sort)
n = len(sorted_tools)
self.tools_table.setRowCount(n)
self.ui.tools_table.setRowCount(n)
tool_row = 0
for tool in sorted_tools:
tool_id_item = QtWidgets.QTableWidgetItem('%d' % int(tool))
tool_id_item.setFlags(QtCore.Qt.ItemIsEnabled)
self.tools_table.setItem(tool_row, 0, tool_id_item) # Tool name/id
self.ui.tools_table.setItem(tool_row, 0, tool_id_item) # Tool name/id
tool_dia_item = QtWidgets.QTableWidgetItem(str(self.tools_from_inf[tool]))
tool_dia_item.setFlags(QtCore.Qt.ItemIsEnabled)
self.tools_table.setItem(tool_row, 1, tool_dia_item)
self.ui.tools_table.setItem(tool_row, 1, tool_dia_item)
tool_row += 1
self.tools_table.resizeColumnsToContents()
self.tools_table.resizeRowsToContents()
self.ui.tools_table.resizeColumnsToContents()
self.ui.tools_table.resizeRowsToContents()
vertical_header = self.tools_table.verticalHeader()
vertical_header = self.ui.tools_table.verticalHeader()
vertical_header.hide()
self.tools_table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.ui.tools_table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
horizontal_header = self.tools_table.horizontalHeader()
horizontal_header = self.ui.tools_table.horizontalHeader()
# horizontal_header.setMinimumSectionSize(10)
# horizontal_header.setDefaultSectionSize(70)
horizontal_header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
self.tools_table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.tools_table.setSortingEnabled(False)
self.tools_table.setMinimumHeight(self.tools_table.getHeight())
self.tools_table.setMaximumHeight(self.tools_table.getHeight())
self.ui.tools_table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.ui.tools_table.setSortingEnabled(False)
self.ui.tools_table.setMinimumHeight(self.ui.tools_table.getHeight())
self.ui.tools_table.setMaximumHeight(self.ui.tools_table.getHeight())
def update_params(self):
self.units = self.units_radio.get_value()
self.zeros = self.zeros_radio.get_value()
self.integral = self.int_entry.get_value()
self.fractional = self.frac_entry.get_value()
def on_units_change(self, val):
if val == 'INCH':
self.int_entry.set_value(2)
self.frac_entry.set_value(4)
else:
self.int_entry.set_value(3)
self.frac_entry.set_value(3)
self.units = self.ui.units_radio.get_value()
self.zeros = self.ui.zeros_radio.get_value()
self.integral = self.ui.int_entry.get_value()
self.fractional = self.ui.frac_entry.get_value()
def on_load_excellon_click(self):
"""
@@ -357,9 +245,9 @@ class PcbWizard(AppTool):
self.units = 'INCH'
else:
self.units = 'METRIC'
self.units_radio.set_value(self.units)
self.int_entry.set_value(self.integral)
self.frac_entry.set_value(self.fractional)
self.ui.units_radio.set_value(self.units)
self.ui.int_entry.set_value(self.integral)
self.ui.frac_entry.set_value(self.fractional)
if not self.tools_from_inf:
self.app.inform.emit('[ERROR] %s' %
@@ -382,14 +270,12 @@ class PcbWizard(AppTool):
if signal == 'inf':
self.inf_loaded = True
self.tools_table.setVisible(True)
self.app.inform.emit('[success] %s' %
_("PcbWizard .INF file loaded."))
self.ui.tools_table.setVisible(True)
self.app.inform.emit('[success] %s' % _("PcbWizard .INF file loaded."))
elif signal == 'excellon':
self.excellon_loaded = True
self.outname = os.path.split(str(filename))[1]
self.app.inform.emit('[success] %s' %
_("Main PcbWizard Excellon file loaded."))
self.app.inform.emit('[success] %s' % _("Main PcbWizard Excellon file loaded."))
if self.excellon_loaded and self.inf_loaded:
self.update_params()
@@ -467,3 +353,149 @@ class PcbWizard(AppTool):
self.app.inform.emit('[WARNING_NOTCL] %s' % _('Excellon merging is in progress. Please wait...'))
else:
self.app.inform.emit('[ERROR_NOTCL] %s' % _('The imported Excellon file is empty.'))
class WizardUI:
toolName = _("PcbWizard Import 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(""))
self.layout.addWidget(FCLabel("<b>%s:</b>" % _("Load files")))
# Form Layout
form_layout = QtWidgets.QFormLayout()
self.layout.addLayout(form_layout)
self.excellon_label = FCLabel('%s:' % _("Excellon file"))
self.excellon_label.setToolTip(
_("Load the Excellon file.\n"
"Usually it has a .DRL extension")
)
self.excellon_brn = FCButton(_("Open"))
form_layout.addRow(self.excellon_label, self.excellon_brn)
self.inf_label = FCLabel('%s:' % _("INF file"))
self.inf_label.setToolTip(
_("Load the INF file.")
)
self.inf_btn = FCButton(_("Open"))
form_layout.addRow(self.inf_label, self.inf_btn)
self.tools_table = FCTable()
self.layout.addWidget(self.tools_table)
self.tools_table.setColumnCount(2)
self.tools_table.setHorizontalHeaderLabels(['#Tool', _('Diameter')])
self.tools_table.horizontalHeaderItem(0).setToolTip(
_("Tool Number"))
self.tools_table.horizontalHeaderItem(1).setToolTip(
_("Tool diameter in file units."))
# start with apertures table hidden
self.tools_table.setVisible(False)
self.layout.addWidget(FCLabel(""))
self.layout.addWidget(FCLabel("<b>%s:</b>" % _("Excellon format")))
# Form Layout
form_layout1 = QtWidgets.QFormLayout()
self.layout.addLayout(form_layout1)
# Integral part of the coordinates
self.int_entry = FCSpinner(callback=self.confirmation_message_int)
self.int_entry.set_range(1, 10)
self.int_label = FCLabel('%s:' % _("Int. digits"))
self.int_label.setToolTip(
_("The number of digits for the integral part of the coordinates.")
)
form_layout1.addRow(self.int_label, self.int_entry)
# Fractional part of the coordinates
self.frac_entry = FCSpinner(callback=self.confirmation_message_int)
self.frac_entry.set_range(1, 10)
self.frac_label = FCLabel('%s:' % _("Frac. digits"))
self.frac_label.setToolTip(
_("The number of digits for the fractional part of the coordinates.")
)
form_layout1.addRow(self.frac_label, self.frac_entry)
# Zeros suppression for coordinates
self.zeros_radio = RadioSet([{'label': _('LZ'), 'value': 'LZ'},
{'label': _('TZ'), 'value': 'TZ'},
{'label': _('No Suppression'), 'value': 'D'}])
self.zeros_label = FCLabel('%s:' % _("Zeros supp."))
self.zeros_label.setToolTip(
_("The type of zeros suppression used.\n"
"Can be of type:\n"
"- LZ = leading zeros are kept\n"
"- TZ = trailing zeros are kept\n"
"- No Suppression = no zero suppression")
)
form_layout1.addRow(self.zeros_label, self.zeros_radio)
# Units type
self.units_radio = RadioSet([{'label': _('INCH'), 'value': 'INCH'},
{'label': _('MM'), 'value': 'METRIC'}])
self.units_label = FCLabel("<b>%s:</b>" % _('Units'))
self.units_label.setToolTip(
_("The type of units that the coordinates and tool\n"
"diameters are using. Can be INCH or MM.")
)
form_layout1.addRow(self.units_label, self.units_radio)
# Buttons
self.import_button = QtWidgets.QPushButton(_("Import Excellon"))
self.import_button.setToolTip(
_("Import in FlatCAM an Excellon file\n"
"that store it's information's in 2 files.\n"
"One usually has .DRL extension while\n"
"the other has .INF extension.")
)
self.layout.addWidget(self.import_button)
self.layout.addStretch()
# #################################### FINSIHED GUI ###########################
# #############################################################################
def on_units_change(self, val):
if val == 'INCH':
self.int_entry.set_value(2)
self.frac_entry.set_value(4)
else:
self.int_entry.set_value(3)
self.frac_entry.set_value(3)
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)