- 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
|
- in Tool Cutout: modified the UI in preparation for adding the Mouse Bites feature
|
||||||
- Turkish translation strings were updated by the translator, Mehmet Kaya
|
- Turkish translation strings were updated by the translator, Mehmet Kaya
|
||||||
- Film Tool - moved the Tool UI in its own class
|
- 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
|
26.08.2020
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from PyQt5 import QtCore, QtWidgets, QtGui
|
|||||||
|
|
||||||
from appTool import AppTool
|
from appTool import AppTool
|
||||||
from appGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, \
|
from appGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, \
|
||||||
OptionalHideInputSection, FCComboBox, FCFileSaveDialog
|
OptionalHideInputSection, FCComboBox, FCFileSaveDialog, FCButton, FCLabel
|
||||||
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
import logging
|
import logging
|
||||||
@@ -759,7 +759,7 @@ class FilmUI:
|
|||||||
self.layout = layout
|
self.layout = layout
|
||||||
|
|
||||||
# ## Title
|
# ## Title
|
||||||
title_label = QtWidgets.QLabel("%s" % self.toolName)
|
title_label = FCLabel("%s" % self.toolName)
|
||||||
title_label.setStyleSheet("""
|
title_label.setStyleSheet("""
|
||||||
QLabel
|
QLabel
|
||||||
{
|
{
|
||||||
@@ -768,7 +768,7 @@ class FilmUI:
|
|||||||
}
|
}
|
||||||
""")
|
""")
|
||||||
self.layout.addWidget(title_label)
|
self.layout.addWidget(title_label)
|
||||||
self.layout.addWidget(QtWidgets.QLabel(""))
|
self.layout.addWidget(FCLabel(""))
|
||||||
|
|
||||||
# Form Layout
|
# Form Layout
|
||||||
grid0 = QtWidgets.QGridLayout()
|
grid0 = QtWidgets.QGridLayout()
|
||||||
@@ -781,7 +781,7 @@ class FilmUI:
|
|||||||
self.tf_type_obj_combo = RadioSet([{'label': _('Gerber'), 'value': 'grb'},
|
self.tf_type_obj_combo = RadioSet([{'label': _('Gerber'), 'value': 'grb'},
|
||||||
{'label': _('Geometry'), 'value': 'geo'}])
|
{'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(
|
self.tf_type_obj_combo_label.setToolTip(
|
||||||
_("Specify the type of object for which to create the film.\n"
|
_("Specify the type of object for which to create the film.\n"
|
||||||
"The object can be of type: Gerber or Geometry.\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'},
|
self.tf_type_box_combo = RadioSet([{'label': _('Gerber'), 'value': 'grb'},
|
||||||
{'label': _('Geometry'), 'value': 'geo'}])
|
{'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(
|
self.tf_type_box_combo_label.setToolTip(
|
||||||
_("Specify the type of object to be used as an container for\n"
|
_("Specify the type of object to be used as an container for\n"
|
||||||
"film creation. It can be: Gerber or Geometry type."
|
"film creation. It can be: Gerber or Geometry type."
|
||||||
@@ -827,7 +827,7 @@ class FilmUI:
|
|||||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||||
grid0.addWidget(separator_line, 4, 0, 1, 2)
|
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(
|
self.film_adj_label.setToolTip(
|
||||||
_("Sometime the printers will distort the print shape, especially the Laser types.\n"
|
_("Sometime the printers will distort the print shape, especially the Laser types.\n"
|
||||||
"This section provide the tools to compensate for the print distortions.")
|
"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)
|
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 = FCDoubleSpinner(callback=self.confirmation_message)
|
||||||
self.film_scalex_entry.set_range(-999.9999, 999.9999)
|
self.film_scalex_entry.set_range(-999.9999, 999.9999)
|
||||||
self.film_scalex_entry.set_precision(self.decimals)
|
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_label, 7, 0)
|
||||||
grid0.addWidget(self.film_scalex_entry, 7, 1)
|
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 = FCDoubleSpinner(callback=self.confirmation_message)
|
||||||
self.film_scaley_entry.set_range(-999.9999, 999.9999)
|
self.film_scaley_entry.set_range(-999.9999, 999.9999)
|
||||||
self.film_scaley_entry.set_precision(self.decimals)
|
self.film_scaley_entry.set_precision(self.decimals)
|
||||||
@@ -892,7 +892,7 @@ class FilmUI:
|
|||||||
)
|
)
|
||||||
grid0.addWidget(self.film_skew_cb, 10, 0, 1, 2)
|
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 = FCDoubleSpinner(callback=self.confirmation_message)
|
||||||
self.film_skewx_entry.set_range(-999.9999, 999.9999)
|
self.film_skewx_entry.set_range(-999.9999, 999.9999)
|
||||||
self.film_skewx_entry.set_precision(self.decimals)
|
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_label, 11, 0)
|
||||||
grid0.addWidget(self.film_skewx_entry, 11, 1)
|
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 = FCDoubleSpinner(callback=self.confirmation_message)
|
||||||
self.film_skewy_entry.set_range(-999.9999, 999.9999)
|
self.film_skewy_entry.set_range(-999.9999, 999.9999)
|
||||||
self.film_skewy_entry.set_precision(self.decimals)
|
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_label, 12, 0)
|
||||||
grid0.addWidget(self.film_skewy_entry, 12, 1)
|
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(
|
self.film_skew_ref_label.setToolTip(
|
||||||
_("The reference point to be used as origin for the skew.\n"
|
_("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.")
|
"It can be one of the four points of the geometry bounding box.")
|
||||||
@@ -957,7 +957,7 @@ class FilmUI:
|
|||||||
{'label': _('Y'), 'value': 'y'},
|
{'label': _('Y'), 'value': 'y'},
|
||||||
{'label': _('Both'), 'value': 'both'}],
|
{'label': _('Both'), 'value': 'both'}],
|
||||||
stretch=False)
|
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_label, 16, 0)
|
||||||
grid0.addWidget(self.film_mirror_axis, 16, 1)
|
grid0.addWidget(self.film_mirror_axis, 16, 1)
|
||||||
@@ -973,7 +973,7 @@ class FilmUI:
|
|||||||
separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
|
separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||||
grid0.addWidget(separator_line2, 17, 0, 1, 2)
|
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)
|
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.setSingleStep(0.01)
|
||||||
self.film_scale_stroke_entry.set_precision(self.decimals)
|
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(
|
self.film_scale_stroke_label.setToolTip(
|
||||||
_("Scale the line stroke thickness of each feature in the SVG file.\n"
|
_("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"
|
"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'},
|
self.film_type = RadioSet([{'label': _('Positive'), 'value': 'pos'},
|
||||||
{'label': _('Negative'), 'value': 'neg'}],
|
{'label': _('Negative'), 'value': 'neg'}],
|
||||||
stretch=False)
|
stretch=False)
|
||||||
self.film_type_label = QtWidgets.QLabel(_("Film Type:"))
|
self.film_type_label = FCLabel(_("Film Type:"))
|
||||||
self.film_type_label.setToolTip(
|
self.film_type_label.setToolTip(
|
||||||
_("Generate a Positive black film or a Negative film.\n"
|
_("Generate a Positive black film or a Negative film.\n"
|
||||||
"Positive means that it will print the features\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.setSingleStep(0.01)
|
||||||
self.boundary_entry.set_precision(self.decimals)
|
self.boundary_entry.set_precision(self.decimals)
|
||||||
|
|
||||||
self.boundary_label = QtWidgets.QLabel('%s:' % _("Border"))
|
self.boundary_label = FCLabel('%s:' % _("Border"))
|
||||||
self.boundary_label.setToolTip(
|
self.boundary_label.setToolTip(
|
||||||
_("Specify a border around the object.\n"
|
_("Specify a border around the object.\n"
|
||||||
"Only for negative film.\n"
|
"Only for negative film.\n"
|
||||||
@@ -1051,7 +1051,7 @@ class FilmUI:
|
|||||||
|
|
||||||
self.ois_p = OptionalHideInputSection(self.punch_cb, [self.punch_frame])
|
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(
|
self.source_label.setToolTip(
|
||||||
_("The punch hole source can be:\n"
|
_("The punch hole source can be:\n"
|
||||||
"- Excellon -> an Excellon holes center will serve as reference.\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_label, 0, 0)
|
||||||
punch_grid.addWidget(self.source_punch, 0, 1)
|
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(
|
self.exc_label.setToolTip(
|
||||||
_("Remove the geometry of Excellon from the Film to create the holes in pads.")
|
_("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_label.hide()
|
||||||
self.exc_combo.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_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 = FCDoubleSpinner(callback=self.confirmation_message)
|
||||||
self.punch_size_spinner.set_range(0, 999.9999)
|
self.punch_size_spinner.set_range(0, 999.9999)
|
||||||
@@ -1108,7 +1108,7 @@ class FilmUI:
|
|||||||
{'label': _('PDF'), 'value': 'pdf'}
|
{'label': _('PDF'), 'value': 'pdf'}
|
||||||
], stretch=False)
|
], stretch=False)
|
||||||
|
|
||||||
self.file_type_label = QtWidgets.QLabel(_("Film Type:"))
|
self.file_type_label = FCLabel(_("Film Type:"))
|
||||||
self.file_type_label.setToolTip(
|
self.file_type_label.setToolTip(
|
||||||
_("The file type of the saved film. Can be:\n"
|
_("The file type of the saved film. Can be:\n"
|
||||||
"- 'SVG' -> open-source vectorial format\n"
|
"- 'SVG' -> open-source vectorial format\n"
|
||||||
@@ -1119,7 +1119,7 @@ class FilmUI:
|
|||||||
grid1.addWidget(self.file_type_radio, 1, 1)
|
grid1.addWidget(self.file_type_radio, 1, 1)
|
||||||
|
|
||||||
# Page orientation
|
# Page orientation
|
||||||
self.orientation_label = QtWidgets.QLabel('%s:' % _("Page Orientation"))
|
self.orientation_label = FCLabel('%s:' % _("Page Orientation"))
|
||||||
self.orientation_label.setToolTip(_("Can be:\n"
|
self.orientation_label.setToolTip(_("Can be:\n"
|
||||||
"- Portrait\n"
|
"- Portrait\n"
|
||||||
"- Landscape"))
|
"- Landscape"))
|
||||||
@@ -1132,7 +1132,7 @@ class FilmUI:
|
|||||||
grid1.addWidget(self.orientation_radio, 2, 1)
|
grid1.addWidget(self.orientation_radio, 2, 1)
|
||||||
|
|
||||||
# Page Size
|
# 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_label.setToolTip(_("A selection of standard ISO 216 page sizes."))
|
||||||
|
|
||||||
self.pagesize_combo = FCComboBox()
|
self.pagesize_combo = FCComboBox()
|
||||||
@@ -1200,7 +1200,8 @@ class FilmUI:
|
|||||||
self.on_film_type(val='hide')
|
self.on_film_type(val='hide')
|
||||||
|
|
||||||
# Buttons
|
# 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(
|
self.film_object_button.setToolTip(
|
||||||
_("Create a Film for the selected object, within\n"
|
_("Create a Film for the selected object, within\n"
|
||||||
"the specified box. Does not create a new \n "
|
"the specified box. Does not create a new \n "
|
||||||
@@ -1218,7 +1219,7 @@ class FilmUI:
|
|||||||
self.layout.addStretch()
|
self.layout.addStretch()
|
||||||
|
|
||||||
# ## Reset Tool
|
# ## 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.setIcon(QtGui.QIcon(self.app.resource_location + '/reset32.png'))
|
||||||
self.reset_button.setToolTip(
|
self.reset_button.setToolTip(
|
||||||
_("Will reset the tool parameters.")
|
_("Will reset the tool parameters.")
|
||||||
|
|||||||
@@ -21,23 +21,165 @@ if '_' not in builtins.__dict__:
|
|||||||
|
|
||||||
class ToolImage(AppTool):
|
class ToolImage(AppTool):
|
||||||
|
|
||||||
toolName = _("Image as Object")
|
|
||||||
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
AppTool.__init__(self, app)
|
AppTool.__init__(self, app)
|
||||||
|
|
||||||
self.app = app
|
self.app = app
|
||||||
self.decimals = self.app.decimals
|
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("""
|
title_label.setStyleSheet("""
|
||||||
QLabel
|
QLabel
|
||||||
{
|
{
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
""")
|
""")
|
||||||
self.layout.addWidget(title_label)
|
self.layout.addWidget(title_label)
|
||||||
|
|
||||||
# Form Layout
|
# 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 = QtWidgets.QLabel('%s:' % _("Object Type"))
|
||||||
self.tf_type_obj_combo_label.setToolTip(
|
self.tf_type_obj_combo_label.setToolTip(
|
||||||
_("Specify the type of object to create from the image.\n"
|
_("Specify the type of object to create from the image.\n"
|
||||||
"It can be of type: Gerber or Geometry.")
|
"It can be of type: Gerber or Geometry.")
|
||||||
|
|
||||||
)
|
)
|
||||||
ti_form_layout.addRow(self.tf_type_obj_combo_label, self.tf_type_obj_combo)
|
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 = FCSpinner(callback=self.confirmation_message_int)
|
||||||
self.dpi_entry.set_range(0, 99999)
|
self.dpi_entry.set_range(0, 99999)
|
||||||
self.dpi_label = QtWidgets.QLabel('%s:' % _("DPI value"))
|
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)
|
ti_form_layout.addRow(self.dpi_label, self.dpi_entry)
|
||||||
|
|
||||||
self.emty_lbl = QtWidgets.QLabel("")
|
self.emty_lbl = QtWidgets.QLabel("")
|
||||||
@@ -150,48 +292,8 @@ class ToolImage(AppTool):
|
|||||||
|
|
||||||
self.on_image_type(val=False)
|
self.on_image_type(val=False)
|
||||||
|
|
||||||
# ## Signals
|
# #################################### FINSIHED GUI ###########################
|
||||||
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)
|
|
||||||
|
|
||||||
def on_image_type(self, val):
|
def on_image_type(self, val):
|
||||||
if val == 'color':
|
if val == 'color':
|
||||||
@@ -215,83 +317,19 @@ class ToolImage(AppTool):
|
|||||||
self.mask_bw_label.setDisabled(False)
|
self.mask_bw_label.setDisabled(False)
|
||||||
self.mask_bw_entry.setDisabled(False)
|
self.mask_bw_entry.setDisabled(False)
|
||||||
|
|
||||||
def on_file_importimage(self):
|
def confirmation_message(self, accepted, minval, maxval):
|
||||||
"""
|
if accepted is False:
|
||||||
Callback for menu item File->Import IMAGE.
|
self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' % (_("Edited value is out of range"),
|
||||||
:param type_of_obj: to import the IMAGE as Geometry or as Gerber
|
self.decimals,
|
||||||
:type type_of_obj: str
|
minval,
|
||||||
:return: None
|
self.decimals,
|
||||||
"""
|
maxval), False)
|
||||||
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."))
|
|
||||||
else:
|
else:
|
||||||
self.app.worker_task.emit({'fcn': self.import_image,
|
self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
|
||||||
'params': [filename, type_obj, dpi, mode, mask]})
|
|
||||||
|
|
||||||
def import_image(self, filename, o_type=_("Gerber"), dpi=96, mode='black', mask=None, outname=None):
|
def confirmation_message_int(self, accepted, minval, maxval):
|
||||||
"""
|
if accepted is False:
|
||||||
Adds a new Geometry Object to the projects and populates
|
self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%d, %d]' %
|
||||||
it with shapes extracted from the SVG file.
|
(_("Edited value is out of range"), minval, maxval), False)
|
||||||
|
|
||||||
: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:
|
else:
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
|
||||||
_("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))
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
from PyQt5 import QtWidgets, QtCore, QtGui
|
from PyQt5 import QtWidgets, QtCore, QtGui
|
||||||
|
|
||||||
from appTool import AppTool
|
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
|
from shapely.geometry import box
|
||||||
|
|
||||||
@@ -28,133 +28,20 @@ log = logging.getLogger('base')
|
|||||||
|
|
||||||
class ToolInvertGerber(AppTool):
|
class ToolInvertGerber(AppTool):
|
||||||
|
|
||||||
toolName = _("Invert Gerber Tool")
|
|
||||||
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
self.app = app
|
self.app = app
|
||||||
self.decimals = self.app.decimals
|
self.decimals = self.app.decimals
|
||||||
|
|
||||||
AppTool.__init__(self, app)
|
AppTool.__init__(self, app)
|
||||||
|
|
||||||
self.tools_frame = QtWidgets.QFrame()
|
# #############################################################################
|
||||||
self.tools_frame.setContentsMargins(0, 0, 0, 0)
|
# ######################### Tool GUI ##########################################
|
||||||
self.layout.addWidget(self.tools_frame)
|
# #############################################################################
|
||||||
self.tools_box = QtWidgets.QVBoxLayout()
|
self.ui = InvertUI(layout=self.layout, app=self.app)
|
||||||
self.tools_box.setContentsMargins(0, 0, 0, 0)
|
self.toolName = self.ui.toolName
|
||||||
self.tools_frame.setLayout(self.tools_box)
|
|
||||||
|
|
||||||
# Title
|
self.ui.invert_btn.clicked.connect(self.on_grb_invert)
|
||||||
title_label = QtWidgets.QLabel("%s" % self.toolName)
|
self.ui.reset_button.clicked.connect(self.set_tool_ui)
|
||||||
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)
|
|
||||||
|
|
||||||
def install(self, icon=None, separator=None, **kwargs):
|
def install(self, icon=None, separator=None, **kwargs):
|
||||||
AppTool.install(self, icon, separator, shortcut='', **kwargs)
|
AppTool.install(self, icon, separator, shortcut='', **kwargs)
|
||||||
@@ -188,20 +75,20 @@ class ToolInvertGerber(AppTool):
|
|||||||
self.app.ui.notebook.setTabText(2, _("Invert Tool"))
|
self.app.ui.notebook.setTabText(2, _("Invert Tool"))
|
||||||
|
|
||||||
def set_tool_ui(self):
|
def set_tool_ui(self):
|
||||||
self.margin_entry.set_value(float(self.app.defaults["tools_invert_margin"]))
|
self.ui.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.join_radio.set_value(self.app.defaults["tools_invert_join_style"])
|
||||||
|
|
||||||
def on_grb_invert(self):
|
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:
|
if round(margin, self.decimals) == 0.0:
|
||||||
margin = 1E-10
|
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:
|
if join_style is None:
|
||||||
join_style = 'r'
|
join_style = 'r'
|
||||||
|
|
||||||
grb_circle_steps = int(self.app.defaults["gerber_circle_steps"])
|
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"
|
outname = obj_name + "_inverted"
|
||||||
|
|
||||||
@@ -243,32 +130,6 @@ class ToolInvertGerber(AppTool):
|
|||||||
|
|
||||||
new_apertures = {}
|
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:
|
if '0' not in new_apertures:
|
||||||
new_apertures['0'] = {}
|
new_apertures['0'] = {}
|
||||||
new_apertures['0']['type'] = 'C'
|
new_apertures['0']['type'] = 'C'
|
||||||
@@ -302,9 +163,155 @@ class ToolInvertGerber(AppTool):
|
|||||||
self.app.app_obj.new_object('gerber', outname, init_func)
|
self.app.app_obj.new_object('gerber', outname, init_func)
|
||||||
|
|
||||||
def reset_fields(self):
|
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
|
@staticmethod
|
||||||
def poly2rings(poly):
|
def poly2rings(poly):
|
||||||
return [poly.exterior] + [interior for interior in poly.interiors]
|
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):
|
class ToolOptimal(AppTool):
|
||||||
|
|
||||||
toolName = _("Optimal Tool")
|
|
||||||
|
|
||||||
update_text = QtCore.pyqtSignal(list)
|
update_text = QtCore.pyqtSignal(list)
|
||||||
update_sec_distances = QtCore.pyqtSignal(dict)
|
update_sec_distances = QtCore.pyqtSignal(dict)
|
||||||
|
|
||||||
@@ -41,222 +39,11 @@ class ToolOptimal(AppTool):
|
|||||||
self.units = self.app.defaults['units'].upper()
|
self.units = self.app.defaults['units'].upper()
|
||||||
self.decimals = self.app.decimals
|
self.decimals = self.app.decimals
|
||||||
|
|
||||||
# ############################################################################
|
# #############################################################################
|
||||||
# ############################ GUI creation ##################################
|
# ######################### Tool GUI ##########################################
|
||||||
# ## Title
|
# #############################################################################
|
||||||
title_label = QtWidgets.QLabel("%s" % self.toolName)
|
self.ui = OptimalUI(layout=self.layout, app=self.app)
|
||||||
title_label.setStyleSheet(
|
self.toolName = self.ui.toolName
|
||||||
"""
|
|
||||||
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 ###################################
|
|
||||||
# ############################################################################
|
|
||||||
|
|
||||||
# this is the line selected in the textbox with the locations of the minimum
|
# this is the line selected in the textbox with the locations of the minimum
|
||||||
self.selected_text = ''
|
self.selected_text = ''
|
||||||
@@ -271,17 +58,17 @@ class ToolOptimal(AppTool):
|
|||||||
# ############################################################################
|
# ############################################################################
|
||||||
# ############################ Signals #######################################
|
# ############################ Signals #######################################
|
||||||
# ############################################################################
|
# ############################################################################
|
||||||
self.calculate_button.clicked.connect(self.find_minimum_distance)
|
self.ui.calculate_button.clicked.connect(self.find_minimum_distance)
|
||||||
self.locate_button.clicked.connect(self.on_locate_position)
|
self.ui.locate_button.clicked.connect(self.on_locate_position)
|
||||||
self.update_text.connect(self.on_update_text)
|
self.ui.update_text.connect(self.on_update_text)
|
||||||
self.locations_textb.cursorPositionChanged.connect(self.on_textbox_clicked)
|
self.ui.locations_textb.cursorPositionChanged.connect(self.on_textbox_clicked)
|
||||||
|
|
||||||
self.locate_sec_button.clicked.connect(self.on_locate_sec_position)
|
self.ui.locate_sec_button.clicked.connect(self.on_locate_sec_position)
|
||||||
self.update_sec_distances.connect(self.on_update_sec_distances_txt)
|
self.ui.update_sec_distances.connect(self.on_update_sec_distances_txt)
|
||||||
self.distances_textb.cursorPositionChanged.connect(self.on_distances_textb_clicked)
|
self.ui.distances_textb.cursorPositionChanged.connect(self.on_distances_textb_clicked)
|
||||||
self.locations_sec_textb.cursorPositionChanged.connect(self.on_locations_sec_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):
|
def install(self, icon=None, separator=None, **kwargs):
|
||||||
AppTool.install(self, icon, separator, shortcut='Alt+O', **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"))
|
self.app.ui.notebook.setTabText(2, _("Optimal Tool"))
|
||||||
|
|
||||||
def set_tool_ui(self):
|
def set_tool_ui(self):
|
||||||
self.result_entry.set_value(0.0)
|
self.ui.result_entry.set_value(0.0)
|
||||||
self.freq_entry.set_value('0')
|
self.ui.freq_entry.set_value('0')
|
||||||
|
|
||||||
self.precision_spinner.set_value(int(self.app.defaults["tools_opt_precision"]))
|
self.ui.precision_spinner.set_value(int(self.app.defaults["tools_opt_precision"]))
|
||||||
self.locations_textb.clear()
|
self.ui.locations_textb.clear()
|
||||||
# new cursor - select all document
|
# new cursor - select all document
|
||||||
cursor = self.locations_textb.textCursor()
|
cursor = self.ui.locations_textb.textCursor()
|
||||||
cursor.select(QtGui.QTextCursor.Document)
|
cursor.select(QtGui.QTextCursor.Document)
|
||||||
|
|
||||||
# clear previous selection highlight
|
# clear previous selection highlight
|
||||||
@@ -328,20 +115,20 @@ class ToolOptimal(AppTool):
|
|||||||
tmp.clearBackground()
|
tmp.clearBackground()
|
||||||
cursor.setBlockFormat(tmp)
|
cursor.setBlockFormat(tmp)
|
||||||
|
|
||||||
self.locations_textb.setVisible(False)
|
self.ui.locations_textb.setVisible(False)
|
||||||
self.locate_button.setVisible(False)
|
self.ui.locate_button.setVisible(False)
|
||||||
|
|
||||||
self.result_entry.set_value(0.0)
|
self.ui.result_entry.set_value(0.0)
|
||||||
self.freq_entry.set_value('0')
|
self.ui.freq_entry.set_value('0')
|
||||||
self.reset_fields()
|
self.reset_fields()
|
||||||
|
|
||||||
def find_minimum_distance(self):
|
def find_minimum_distance(self):
|
||||||
self.units = self.app.defaults['units'].upper()
|
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:
|
try:
|
||||||
fcobj = model_index.internalPointer().obj
|
fcobj = model_index.internalPointer().obj
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -426,17 +213,16 @@ class ToolOptimal(AppTool):
|
|||||||
old_disp_number = disp_number
|
old_disp_number = disp_number
|
||||||
idx += 1
|
idx += 1
|
||||||
|
|
||||||
app_obj.inform.emit(
|
app_obj.inform.emit(_("Optimal Tool. Finding the minimum distance."))
|
||||||
_("Optimal Tool. Finding the minimum distance."))
|
|
||||||
|
|
||||||
min_list = list(self.min_dict.keys())
|
min_list = list(self.min_dict.keys())
|
||||||
min_dist = min(min_list)
|
min_dist = min(min_list)
|
||||||
min_dist_string = '%.*f' % (self.decimals, float(min_dist))
|
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 = len(self.min_dict[min_dist])
|
||||||
freq = '%d' % int(freq)
|
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)
|
min_locations = self.min_dict.pop(min_dist)
|
||||||
|
|
||||||
@@ -484,12 +270,12 @@ class ToolOptimal(AppTool):
|
|||||||
for loc in data:
|
for loc in data:
|
||||||
if loc:
|
if loc:
|
||||||
txt += '%s, %s\n' % (str(loc[0]), str(loc[1]))
|
txt += '%s, %s\n' % (str(loc[0]), str(loc[1]))
|
||||||
self.locations_textb.setPlainText(txt)
|
self.ui.locations_textb.setPlainText(txt)
|
||||||
self.locate_button.setDisabled(False)
|
self.ui.locate_button.setDisabled(False)
|
||||||
|
|
||||||
def on_textbox_clicked(self):
|
def on_textbox_clicked(self):
|
||||||
# new cursor - select all document
|
# new cursor - select all document
|
||||||
cursor = self.locations_textb.textCursor()
|
cursor = self.ui.locations_textb.textCursor()
|
||||||
cursor.select(QtGui.QTextCursor.Document)
|
cursor.select(QtGui.QTextCursor.Document)
|
||||||
|
|
||||||
# clear previous selection highlight
|
# clear previous selection highlight
|
||||||
@@ -498,7 +284,7 @@ class ToolOptimal(AppTool):
|
|||||||
cursor.setBlockFormat(tmp)
|
cursor.setBlockFormat(tmp)
|
||||||
|
|
||||||
# new cursor - select the current line
|
# new cursor - select the current line
|
||||||
cursor = self.locations_textb.textCursor()
|
cursor = self.ui.locations_textb.textCursor()
|
||||||
cursor.select(QtGui.QTextCursor.LineUnderCursor)
|
cursor.select(QtGui.QTextCursor.LineUnderCursor)
|
||||||
|
|
||||||
# highlight the current selected line
|
# highlight the current selected line
|
||||||
@@ -513,12 +299,12 @@ class ToolOptimal(AppTool):
|
|||||||
txt = ''
|
txt = ''
|
||||||
for loc in distance_list:
|
for loc in distance_list:
|
||||||
txt += '%s\n' % str(loc)
|
txt += '%s\n' % str(loc)
|
||||||
self.distances_textb.setPlainText(txt)
|
self.ui.distances_textb.setPlainText(txt)
|
||||||
self.locate_sec_button.setDisabled(False)
|
self.ui.locate_sec_button.setDisabled(False)
|
||||||
|
|
||||||
def on_distances_textb_clicked(self):
|
def on_distances_textb_clicked(self):
|
||||||
# new cursor - select all document
|
# new cursor - select all document
|
||||||
cursor = self.distances_textb.textCursor()
|
cursor = self.ui.distances_textb.textCursor()
|
||||||
cursor.select(QtGui.QTextCursor.Document)
|
cursor.select(QtGui.QTextCursor.Document)
|
||||||
|
|
||||||
# clear previous selection highlight
|
# clear previous selection highlight
|
||||||
@@ -527,7 +313,7 @@ class ToolOptimal(AppTool):
|
|||||||
cursor.setBlockFormat(tmp)
|
cursor.setBlockFormat(tmp)
|
||||||
|
|
||||||
# new cursor - select the current line
|
# new cursor - select the current line
|
||||||
cursor = self.distances_textb.textCursor()
|
cursor = self.ui.distances_textb.textCursor()
|
||||||
cursor.select(QtGui.QTextCursor.LineUnderCursor)
|
cursor.select(QtGui.QTextCursor.LineUnderCursor)
|
||||||
|
|
||||||
# highlight the current selected line
|
# highlight the current selected line
|
||||||
@@ -545,11 +331,11 @@ class ToolOptimal(AppTool):
|
|||||||
for loc in distance_list:
|
for loc in distance_list:
|
||||||
if loc:
|
if loc:
|
||||||
txt += '%s, %s\n' % (str(loc[0]), str(loc[1]))
|
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):
|
def on_locations_sec_clicked(self):
|
||||||
# new cursor - select all document
|
# new cursor - select all document
|
||||||
cursor = self.locations_sec_textb.textCursor()
|
cursor = self.ui.locations_sec_textb.textCursor()
|
||||||
cursor.select(QtGui.QTextCursor.Document)
|
cursor.select(QtGui.QTextCursor.Document)
|
||||||
|
|
||||||
# clear previous selection highlight
|
# clear previous selection highlight
|
||||||
@@ -558,7 +344,7 @@ class ToolOptimal(AppTool):
|
|||||||
cursor.setBlockFormat(tmp)
|
cursor.setBlockFormat(tmp)
|
||||||
|
|
||||||
# new cursor - select the current line
|
# new cursor - select the current line
|
||||||
cursor = self.locations_sec_textb.textCursor()
|
cursor = self.ui.locations_sec_textb.textCursor()
|
||||||
cursor.select(QtGui.QTextCursor.LineUnderCursor)
|
cursor.select(QtGui.QTextCursor.LineUnderCursor)
|
||||||
|
|
||||||
# highlight the current selected line
|
# highlight the current selected line
|
||||||
@@ -593,5 +379,247 @@ class ToolOptimal(AppTool):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def reset_fields(self):
|
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.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 PyQt5 import QtWidgets, QtCore
|
||||||
|
|
||||||
from appTool import AppTool
|
from appTool import AppTool
|
||||||
from appGUI.GUIElements import RadioSet, FCSpinner, FCButton, FCTable
|
from appGUI.GUIElements import RadioSet, FCSpinner, FCButton, FCTable, FCLabel
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
@@ -28,121 +28,17 @@ class PcbWizard(AppTool):
|
|||||||
|
|
||||||
file_loaded = QtCore.pyqtSignal(str, str)
|
file_loaded = QtCore.pyqtSignal(str, str)
|
||||||
|
|
||||||
toolName = _("PcbWizard Import Tool")
|
|
||||||
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
AppTool.__init__(self, app)
|
AppTool.__init__(self, app)
|
||||||
|
|
||||||
self.app = app
|
self.app = app
|
||||||
self.decimals = self.app.decimals
|
self.decimals = self.app.decimals
|
||||||
|
|
||||||
# Title
|
# #############################################################################
|
||||||
title_label = QtWidgets.QLabel("%s" % _('Import 2-file Excellon'))
|
# ######################### Tool GUI ##########################################
|
||||||
title_label.setStyleSheet("""
|
# #############################################################################
|
||||||
QLabel
|
self.ui = WizardUI(layout=self.layout, app=self.app)
|
||||||
{
|
self.toolName = self.ui.toolName
|
||||||
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()
|
|
||||||
|
|
||||||
self.excellon_loaded = False
|
self.excellon_loaded = False
|
||||||
self.inf_loaded = False
|
self.inf_loaded = False
|
||||||
@@ -151,13 +47,13 @@ class PcbWizard(AppTool):
|
|||||||
self.modified_excellon_file = ''
|
self.modified_excellon_file = ''
|
||||||
|
|
||||||
# ## Signals
|
# ## Signals
|
||||||
self.excellon_brn.clicked.connect(self.on_load_excellon_click)
|
self.ui.excellon_brn.clicked.connect(self.on_load_excellon_click)
|
||||||
self.inf_btn.clicked.connect(self.on_load_inf_click)
|
self.ui.inf_btn.clicked.connect(self.on_load_inf_click)
|
||||||
self.import_button.clicked.connect(lambda: self.on_import_excellon(
|
self.ui.import_button.clicked.connect(lambda: self.on_import_excellon(
|
||||||
excellon_fileobj=self.modified_excellon_file))
|
excellon_fileobj=self.modified_excellon_file))
|
||||||
|
|
||||||
self.file_loaded.connect(self.on_file_loaded)
|
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.units = 'INCH'
|
||||||
self.zeros = 'LZ'
|
self.zeros = 'LZ'
|
||||||
@@ -211,10 +107,10 @@ class PcbWizard(AppTool):
|
|||||||
self.tools_from_inf = {}
|
self.tools_from_inf = {}
|
||||||
|
|
||||||
# ## Initialize form
|
# ## Initialize form
|
||||||
self.int_entry.set_value(self.integral)
|
self.ui.int_entry.set_value(self.integral)
|
||||||
self.frac_entry.set_value(self.fractional)
|
self.ui.frac_entry.set_value(self.fractional)
|
||||||
self.zeros_radio.set_value(self.zeros)
|
self.ui.zeros_radio.set_value(self.zeros)
|
||||||
self.units_radio.set_value(self.units)
|
self.ui.units_radio.set_value(self.units)
|
||||||
|
|
||||||
self.excellon_loaded = False
|
self.excellon_loaded = False
|
||||||
self.inf_loaded = False
|
self.inf_loaded = False
|
||||||
@@ -227,57 +123,49 @@ class PcbWizard(AppTool):
|
|||||||
sorted_tools = []
|
sorted_tools = []
|
||||||
|
|
||||||
if not self.tools_from_inf:
|
if not self.tools_from_inf:
|
||||||
self.tools_table.setVisible(False)
|
self.ui.tools_table.setVisible(False)
|
||||||
else:
|
else:
|
||||||
sort = []
|
sort = []
|
||||||
for k, v in list(self.tools_from_inf.items()):
|
for k, v in list(self.tools_from_inf.items()):
|
||||||
sort.append(int(k))
|
sort.append(int(k))
|
||||||
sorted_tools = sorted(sort)
|
sorted_tools = sorted(sort)
|
||||||
n = len(sorted_tools)
|
n = len(sorted_tools)
|
||||||
self.tools_table.setRowCount(n)
|
self.ui.tools_table.setRowCount(n)
|
||||||
|
|
||||||
tool_row = 0
|
tool_row = 0
|
||||||
for tool in sorted_tools:
|
for tool in sorted_tools:
|
||||||
tool_id_item = QtWidgets.QTableWidgetItem('%d' % int(tool))
|
tool_id_item = QtWidgets.QTableWidgetItem('%d' % int(tool))
|
||||||
tool_id_item.setFlags(QtCore.Qt.ItemIsEnabled)
|
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 = QtWidgets.QTableWidgetItem(str(self.tools_from_inf[tool]))
|
||||||
tool_dia_item.setFlags(QtCore.Qt.ItemIsEnabled)
|
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
|
tool_row += 1
|
||||||
|
|
||||||
self.tools_table.resizeColumnsToContents()
|
self.ui.tools_table.resizeColumnsToContents()
|
||||||
self.tools_table.resizeRowsToContents()
|
self.ui.tools_table.resizeRowsToContents()
|
||||||
|
|
||||||
vertical_header = self.tools_table.verticalHeader()
|
vertical_header = self.ui.tools_table.verticalHeader()
|
||||||
vertical_header.hide()
|
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.setMinimumSectionSize(10)
|
||||||
# horizontal_header.setDefaultSectionSize(70)
|
# horizontal_header.setDefaultSectionSize(70)
|
||||||
horizontal_header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
|
horizontal_header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
|
||||||
horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
|
horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
|
||||||
|
|
||||||
self.tools_table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
self.ui.tools_table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
||||||
self.tools_table.setSortingEnabled(False)
|
self.ui.tools_table.setSortingEnabled(False)
|
||||||
self.tools_table.setMinimumHeight(self.tools_table.getHeight())
|
self.ui.tools_table.setMinimumHeight(self.ui.tools_table.getHeight())
|
||||||
self.tools_table.setMaximumHeight(self.tools_table.getHeight())
|
self.ui.tools_table.setMaximumHeight(self.ui.tools_table.getHeight())
|
||||||
|
|
||||||
def update_params(self):
|
def update_params(self):
|
||||||
self.units = self.units_radio.get_value()
|
self.units = self.ui.units_radio.get_value()
|
||||||
self.zeros = self.zeros_radio.get_value()
|
self.zeros = self.ui.zeros_radio.get_value()
|
||||||
self.integral = self.int_entry.get_value()
|
self.integral = self.ui.int_entry.get_value()
|
||||||
self.fractional = self.frac_entry.get_value()
|
self.fractional = self.ui.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)
|
|
||||||
|
|
||||||
def on_load_excellon_click(self):
|
def on_load_excellon_click(self):
|
||||||
"""
|
"""
|
||||||
@@ -357,9 +245,9 @@ class PcbWizard(AppTool):
|
|||||||
self.units = 'INCH'
|
self.units = 'INCH'
|
||||||
else:
|
else:
|
||||||
self.units = 'METRIC'
|
self.units = 'METRIC'
|
||||||
self.units_radio.set_value(self.units)
|
self.ui.units_radio.set_value(self.units)
|
||||||
self.int_entry.set_value(self.integral)
|
self.ui.int_entry.set_value(self.integral)
|
||||||
self.frac_entry.set_value(self.fractional)
|
self.ui.frac_entry.set_value(self.fractional)
|
||||||
|
|
||||||
if not self.tools_from_inf:
|
if not self.tools_from_inf:
|
||||||
self.app.inform.emit('[ERROR] %s' %
|
self.app.inform.emit('[ERROR] %s' %
|
||||||
@@ -382,14 +270,12 @@ class PcbWizard(AppTool):
|
|||||||
|
|
||||||
if signal == 'inf':
|
if signal == 'inf':
|
||||||
self.inf_loaded = True
|
self.inf_loaded = True
|
||||||
self.tools_table.setVisible(True)
|
self.ui.tools_table.setVisible(True)
|
||||||
self.app.inform.emit('[success] %s' %
|
self.app.inform.emit('[success] %s' % _("PcbWizard .INF file loaded."))
|
||||||
_("PcbWizard .INF file loaded."))
|
|
||||||
elif signal == 'excellon':
|
elif signal == 'excellon':
|
||||||
self.excellon_loaded = True
|
self.excellon_loaded = True
|
||||||
self.outname = os.path.split(str(filename))[1]
|
self.outname = os.path.split(str(filename))[1]
|
||||||
self.app.inform.emit('[success] %s' %
|
self.app.inform.emit('[success] %s' % _("Main PcbWizard Excellon file loaded."))
|
||||||
_("Main PcbWizard Excellon file loaded."))
|
|
||||||
|
|
||||||
if self.excellon_loaded and self.inf_loaded:
|
if self.excellon_loaded and self.inf_loaded:
|
||||||
self.update_params()
|
self.update_params()
|
||||||
@@ -467,3 +353,149 @@ class PcbWizard(AppTool):
|
|||||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _('Excellon merging is in progress. Please wait...'))
|
self.app.inform.emit('[WARNING_NOTCL] %s' % _('Excellon merging is in progress. Please wait...'))
|
||||||
else:
|
else:
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s' % _('The imported Excellon file is empty.'))
|
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