- in Tools: Film, Image, InvertGerber, Optimal, PcbWizard - moved the Tool UI in its own class
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user