diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9f1aa078..1a067405 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ CHANGELOG for FlatCAM beta
- in Tool Cutout: modified the UI in preparation for adding the Mouse Bites feature
- Turkish translation strings were updated by the translator, Mehmet Kaya
- Film Tool - moved the Tool UI in its own class
+- in Tools: Film, Image, InvertGerber, Optimal, PcbWizard - moved the Tool UI in its own class
26.08.2020
diff --git a/appTools/ToolFilm.py b/appTools/ToolFilm.py
index ce62af61..c5831819 100644
--- a/appTools/ToolFilm.py
+++ b/appTools/ToolFilm.py
@@ -9,7 +9,7 @@ from PyQt5 import QtCore, QtWidgets, QtGui
from appTool import AppTool
from appGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, \
- OptionalHideInputSection, FCComboBox, FCFileSaveDialog
+ OptionalHideInputSection, FCComboBox, FCFileSaveDialog, FCButton, FCLabel
from copy import deepcopy
import logging
@@ -759,7 +759,7 @@ class FilmUI:
self.layout = layout
# ## Title
- title_label = QtWidgets.QLabel("%s" % self.toolName)
+ title_label = FCLabel("%s" % self.toolName)
title_label.setStyleSheet("""
QLabel
{
@@ -768,7 +768,7 @@ class FilmUI:
}
""")
self.layout.addWidget(title_label)
- self.layout.addWidget(QtWidgets.QLabel(""))
+ self.layout.addWidget(FCLabel(""))
# Form Layout
grid0 = QtWidgets.QGridLayout()
@@ -781,7 +781,7 @@ class FilmUI:
self.tf_type_obj_combo = RadioSet([{'label': _('Gerber'), 'value': 'grb'},
{'label': _('Geometry'), 'value': 'geo'}])
- self.tf_type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object"))
+ self.tf_type_obj_combo_label = FCLabel('%s:' % _("Object"))
self.tf_type_obj_combo_label.setToolTip(
_("Specify the type of object for which to create the film.\n"
"The object can be of type: Gerber or Geometry.\n"
@@ -804,7 +804,7 @@ class FilmUI:
self.tf_type_box_combo = RadioSet([{'label': _('Gerber'), 'value': 'grb'},
{'label': _('Geometry'), 'value': 'geo'}])
- self.tf_type_box_combo_label = QtWidgets.QLabel(_("Box Type:"))
+ self.tf_type_box_combo_label = FCLabel(_("Box Type:"))
self.tf_type_box_combo_label.setToolTip(
_("Specify the type of object to be used as an container for\n"
"film creation. It can be: Gerber or Geometry type."
@@ -827,7 +827,7 @@ class FilmUI:
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
grid0.addWidget(separator_line, 4, 0, 1, 2)
- self.film_adj_label = QtWidgets.QLabel('%s' % _("Film Adjustments"))
+ self.film_adj_label = FCLabel('%s' % _("Film Adjustments"))
self.film_adj_label.setToolTip(
_("Sometime the printers will distort the print shape, especially the Laser types.\n"
"This section provide the tools to compensate for the print distortions.")
@@ -848,7 +848,7 @@ class FilmUI:
)
grid0.addWidget(self.film_scale_cb, 6, 0, 1, 2)
- self.film_scalex_label = QtWidgets.QLabel('%s:' % _("X factor"))
+ self.film_scalex_label = FCLabel('%s:' % _("X factor"))
self.film_scalex_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.film_scalex_entry.set_range(-999.9999, 999.9999)
self.film_scalex_entry.set_precision(self.decimals)
@@ -857,7 +857,7 @@ class FilmUI:
grid0.addWidget(self.film_scalex_label, 7, 0)
grid0.addWidget(self.film_scalex_entry, 7, 1)
- self.film_scaley_label = QtWidgets.QLabel('%s:' % _("Y factor"))
+ self.film_scaley_label = FCLabel('%s:' % _("Y factor"))
self.film_scaley_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.film_scaley_entry.set_range(-999.9999, 999.9999)
self.film_scaley_entry.set_precision(self.decimals)
@@ -892,7 +892,7 @@ class FilmUI:
)
grid0.addWidget(self.film_skew_cb, 10, 0, 1, 2)
- self.film_skewx_label = QtWidgets.QLabel('%s:' % _("X angle"))
+ self.film_skewx_label = FCLabel('%s:' % _("X angle"))
self.film_skewx_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.film_skewx_entry.set_range(-999.9999, 999.9999)
self.film_skewx_entry.set_precision(self.decimals)
@@ -901,7 +901,7 @@ class FilmUI:
grid0.addWidget(self.film_skewx_label, 11, 0)
grid0.addWidget(self.film_skewx_entry, 11, 1)
- self.film_skewy_label = QtWidgets.QLabel('%s:' % _("Y angle"))
+ self.film_skewy_label = FCLabel('%s:' % _("Y angle"))
self.film_skewy_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.film_skewy_entry.set_range(-999.9999, 999.9999)
self.film_skewy_entry.set_precision(self.decimals)
@@ -910,7 +910,7 @@ class FilmUI:
grid0.addWidget(self.film_skewy_label, 12, 0)
grid0.addWidget(self.film_skewy_entry, 12, 1)
- self.film_skew_ref_label = QtWidgets.QLabel('%s:' % _("Reference"))
+ self.film_skew_ref_label = FCLabel('%s:' % _("Reference"))
self.film_skew_ref_label.setToolTip(
_("The reference point to be used as origin for the skew.\n"
"It can be one of the four points of the geometry bounding box.")
@@ -957,7 +957,7 @@ class FilmUI:
{'label': _('Y'), 'value': 'y'},
{'label': _('Both'), 'value': 'both'}],
stretch=False)
- self.film_mirror_axis_label = QtWidgets.QLabel('%s:' % _("Mirror axis"))
+ self.film_mirror_axis_label = FCLabel('%s:' % _("Mirror axis"))
grid0.addWidget(self.film_mirror_axis_label, 16, 0)
grid0.addWidget(self.film_mirror_axis, 16, 1)
@@ -973,7 +973,7 @@ class FilmUI:
separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
grid0.addWidget(separator_line2, 17, 0, 1, 2)
- self.film_param_label = QtWidgets.QLabel('%s' % _("Film Parameters"))
+ self.film_param_label = FCLabel('%s' % _("Film Parameters"))
grid0.addWidget(self.film_param_label, 18, 0, 1, 2)
@@ -983,7 +983,7 @@ class FilmUI:
self.film_scale_stroke_entry.setSingleStep(0.01)
self.film_scale_stroke_entry.set_precision(self.decimals)
- self.film_scale_stroke_label = QtWidgets.QLabel('%s:' % _("Scale Stroke"))
+ self.film_scale_stroke_label = FCLabel('%s:' % _("Scale Stroke"))
self.film_scale_stroke_label.setToolTip(
_("Scale the line stroke thickness of each feature in the SVG file.\n"
"It means that the line that envelope each SVG feature will be thicker or thinner,\n"
@@ -996,7 +996,7 @@ class FilmUI:
self.film_type = RadioSet([{'label': _('Positive'), 'value': 'pos'},
{'label': _('Negative'), 'value': 'neg'}],
stretch=False)
- self.film_type_label = QtWidgets.QLabel(_("Film Type:"))
+ self.film_type_label = FCLabel(_("Film Type:"))
self.film_type_label.setToolTip(
_("Generate a Positive black film or a Negative film.\n"
"Positive means that it will print the features\n"
@@ -1014,7 +1014,7 @@ class FilmUI:
self.boundary_entry.setSingleStep(0.01)
self.boundary_entry.set_precision(self.decimals)
- self.boundary_label = QtWidgets.QLabel('%s:' % _("Border"))
+ self.boundary_label = FCLabel('%s:' % _("Border"))
self.boundary_label.setToolTip(
_("Specify a border around the object.\n"
"Only for negative film.\n"
@@ -1051,7 +1051,7 @@ class FilmUI:
self.ois_p = OptionalHideInputSection(self.punch_cb, [self.punch_frame])
- self.source_label = QtWidgets.QLabel('%s:' % _("Source"))
+ self.source_label = FCLabel('%s:' % _("Source"))
self.source_label.setToolTip(
_("The punch hole source can be:\n"
"- Excellon -> an Excellon holes center will serve as reference.\n"
@@ -1063,7 +1063,7 @@ class FilmUI:
punch_grid.addWidget(self.source_label, 0, 0)
punch_grid.addWidget(self.source_punch, 0, 1)
- self.exc_label = QtWidgets.QLabel('%s:' % _("Excellon Obj"))
+ self.exc_label = FCLabel('%s:' % _("Excellon Obj"))
self.exc_label.setToolTip(
_("Remove the geometry of Excellon from the Film to create the holes in pads.")
)
@@ -1079,7 +1079,7 @@ class FilmUI:
self.exc_label.hide()
self.exc_combo.hide()
- self.punch_size_label = QtWidgets.QLabel('%s:' % _("Punch Size"))
+ self.punch_size_label = FCLabel('%s:' % _("Punch Size"))
self.punch_size_label.setToolTip(_("The value here will control how big is the punch hole in the pads."))
self.punch_size_spinner = FCDoubleSpinner(callback=self.confirmation_message)
self.punch_size_spinner.set_range(0, 999.9999)
@@ -1108,7 +1108,7 @@ class FilmUI:
{'label': _('PDF'), 'value': 'pdf'}
], stretch=False)
- self.file_type_label = QtWidgets.QLabel(_("Film Type:"))
+ self.file_type_label = FCLabel(_("Film Type:"))
self.file_type_label.setToolTip(
_("The file type of the saved film. Can be:\n"
"- 'SVG' -> open-source vectorial format\n"
@@ -1119,7 +1119,7 @@ class FilmUI:
grid1.addWidget(self.file_type_radio, 1, 1)
# Page orientation
- self.orientation_label = QtWidgets.QLabel('%s:' % _("Page Orientation"))
+ self.orientation_label = FCLabel('%s:' % _("Page Orientation"))
self.orientation_label.setToolTip(_("Can be:\n"
"- Portrait\n"
"- Landscape"))
@@ -1132,7 +1132,7 @@ class FilmUI:
grid1.addWidget(self.orientation_radio, 2, 1)
# Page Size
- self.pagesize_label = QtWidgets.QLabel('%s:' % _("Page Size"))
+ self.pagesize_label = FCLabel('%s:' % _("Page Size"))
self.pagesize_label.setToolTip(_("A selection of standard ISO 216 page sizes."))
self.pagesize_combo = FCComboBox()
@@ -1200,7 +1200,8 @@ class FilmUI:
self.on_film_type(val='hide')
# Buttons
- self.film_object_button = QtWidgets.QPushButton(_("Save Film"))
+ self.film_object_button = FCButton(_("Save Film"))
+ self.film_object_button.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as.png'))
self.film_object_button.setToolTip(
_("Create a Film for the selected object, within\n"
"the specified box. Does not create a new \n "
@@ -1218,7 +1219,7 @@ class FilmUI:
self.layout.addStretch()
# ## Reset Tool
- self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
+ self.reset_button = FCButton(_("Reset Tool"))
self.reset_button.setIcon(QtGui.QIcon(self.app.resource_location + '/reset32.png'))
self.reset_button.setToolTip(
_("Will reset the tool parameters.")
diff --git a/appTools/ToolImage.py b/appTools/ToolImage.py
index f29f1267..12728ff8 100644
--- a/appTools/ToolImage.py
+++ b/appTools/ToolImage.py
@@ -21,23 +21,165 @@ if '_' not in builtins.__dict__:
class ToolImage(AppTool):
- toolName = _("Image as Object")
-
def __init__(self, app):
AppTool.__init__(self, app)
self.app = app
self.decimals = self.app.decimals
- # Title
- title_label = QtWidgets.QLabel("%s" % _('Image to PCB'))
+ # #############################################################################
+ # ######################### Tool GUI ##########################################
+ # #############################################################################
+ self.ui = ImageUI(layout=self.layout, app=self.app)
+ self.toolName = self.ui.toolName
+
+ # ## Signals
+ self.ui.import_button.clicked.connect(self.on_file_importimage)
+ self.ui.image_type.activated_custom.connect(self.ui.on_image_type)
+
+ def run(self, toggle=True):
+ self.app.defaults.report_usage("ToolImage()")
+
+ if toggle:
+ # if the splitter is hidden, display it, else hide it but only if the current widget is the same
+ if self.app.ui.splitter.sizes()[0] == 0:
+ self.app.ui.splitter.setSizes([1, 1])
+ else:
+ try:
+ if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
+ # if tab is populated with the tool but it does not have the focus, focus on it
+ if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
+ # focus on Tool Tab
+ self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
+ else:
+ self.app.ui.splitter.setSizes([0, 1])
+ except AttributeError:
+ pass
+ else:
+ if self.app.ui.splitter.sizes()[0] == 0:
+ self.app.ui.splitter.setSizes([1, 1])
+
+ AppTool.run(self)
+ self.set_tool_ui()
+
+ self.app.ui.notebook.setTabText(2, _("Image Tool"))
+
+ def install(self, icon=None, separator=None, **kwargs):
+ AppTool.install(self, icon, separator, **kwargs)
+
+ def set_tool_ui(self):
+ # ## Initialize form
+ self.ui.dpi_entry.set_value(96)
+ self.ui.image_type.set_value('black')
+ self.ui.mask_bw_entry.set_value(250)
+ self.ui.mask_r_entry.set_value(250)
+ self.ui.mask_g_entry.set_value(250)
+ self.ui.mask_b_entry.set_value(250)
+
+ def on_file_importimage(self):
+ """
+ Callback for menu item File->Import IMAGE.
+ :param type_of_obj: to import the IMAGE as Geometry or as Gerber
+ :type type_of_obj: str
+ :return: None
+ """
+ mask = []
+ self.app.log.debug("on_file_importimage()")
+
+ _filter = "Image Files(*.BMP *.PNG *.JPG *.JPEG);;" \
+ "Bitmap File (*.BMP);;" \
+ "PNG File (*.PNG);;" \
+ "Jpeg File (*.JPG);;" \
+ "All Files (*.*)"
+ try:
+ filename, _f = QtWidgets.QFileDialog.getOpenFileName(caption=_("Import IMAGE"),
+ directory=self.app.get_last_folder(), filter=_filter)
+ except TypeError:
+ filename, _f = QtWidgets.QFileDialog.getOpenFileName(caption=_("Import IMAGE"), filter=filter)
+
+ filename = str(filename)
+ type_obj = self.ui.tf_type_obj_combo.get_value()
+ dpi = self.ui.dpi_entry.get_value()
+ mode = self.ui.image_type.get_value()
+ mask = [
+ self.ui.mask_bw_entry.get_value(),
+ self.ui.mask_r_entry.get_value(),
+ self.ui.mask_g_entry.get_value(),
+ self.ui.mask_b_entry.get_value()
+ ]
+
+ if filename == "":
+ self.app.inform.emit(_("Cancelled."))
+ else:
+ self.app.worker_task.emit({'fcn': self.import_image,
+ 'params': [filename, type_obj, dpi, mode, mask]})
+
+ def import_image(self, filename, o_type=_("Gerber"), dpi=96, mode='black', mask=None, outname=None):
+ """
+ Adds a new Geometry Object to the projects and populates
+ it with shapes extracted from the SVG file.
+
+ :param filename: Path to the SVG file.
+ :param o_type: type of FlatCAM objeect
+ :param dpi: dot per inch
+ :param mode: black or color
+ :param mask: dictate the level of detail
+ :param outname: name for the resulting file
+ :return:
+ """
+
+ self.app.defaults.report_usage("import_image()")
+
+ if mask is None:
+ mask = [250, 250, 250, 250]
+
+ if o_type is None or o_type == _("Geometry"):
+ obj_type = "geometry"
+ elif o_type == _("Gerber"):
+ obj_type = "gerber"
+ else:
+ self.app.inform.emit('[ERROR_NOTCL] %s' %
+ _("Not supported type is picked as parameter. "
+ "Only Geometry and Gerber are supported"))
+ return
+
+ def obj_init(geo_obj, app_obj):
+ geo_obj.import_image(filename, units=units, dpi=dpi, mode=mode, mask=mask)
+ geo_obj.multigeo = False
+
+ with self.app.proc_container.new(_("Importing Image")) as proc:
+
+ # Object name
+ name = outname or filename.split('/')[-1].split('\\')[-1]
+ units = self.app.defaults['units']
+
+ self.app.app_obj.new_object(obj_type, name, obj_init)
+
+ # Register recent file
+ self.app.file_opened.emit("image", filename)
+
+ # GUI feedback
+ self.app.inform.emit('[success] %s: %s' % (_("Opened"), filename))
+
+
+class ImageUI:
+
+ toolName = _("Image as Object")
+
+ def __init__(self, layout, app):
+ self.app = app
+ self.decimals = self.app.decimals
+ self.layout = layout
+
+ # ## Title
+ title_label = QtWidgets.QLabel("%s" % self.toolName)
title_label.setStyleSheet("""
- QLabel
- {
- font-size: 16px;
- font-weight: bold;
- }
- """)
+ QLabel
+ {
+ font-size: 16px;
+ font-weight: bold;
+ }
+ """)
self.layout.addWidget(title_label)
# Form Layout
@@ -53,8 +195,8 @@ class ToolImage(AppTool):
self.tf_type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
self.tf_type_obj_combo_label.setToolTip(
- _("Specify the type of object to create from the image.\n"
- "It can be of type: Gerber or Geometry.")
+ _("Specify the type of object to create from the image.\n"
+ "It can be of type: Gerber or Geometry.")
)
ti_form_layout.addRow(self.tf_type_obj_combo_label, self.tf_type_obj_combo)
@@ -63,7 +205,7 @@ class ToolImage(AppTool):
self.dpi_entry = FCSpinner(callback=self.confirmation_message_int)
self.dpi_entry.set_range(0, 99999)
self.dpi_label = QtWidgets.QLabel('%s:' % _("DPI value"))
- self.dpi_label.setToolTip(_("Specify a DPI value for the image.") )
+ self.dpi_label.setToolTip(_("Specify a DPI value for the image."))
ti_form_layout.addRow(self.dpi_label, self.dpi_entry)
self.emty_lbl = QtWidgets.QLabel("")
@@ -150,48 +292,8 @@ class ToolImage(AppTool):
self.on_image_type(val=False)
- # ## Signals
- self.import_button.clicked.connect(self.on_file_importimage)
- self.image_type.activated_custom.connect(self.on_image_type)
-
- def run(self, toggle=True):
- self.app.defaults.report_usage("ToolImage()")
-
- if toggle:
- # if the splitter is hidden, display it, else hide it but only if the current widget is the same
- if self.app.ui.splitter.sizes()[0] == 0:
- self.app.ui.splitter.setSizes([1, 1])
- else:
- try:
- if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
- # if tab is populated with the tool but it does not have the focus, focus on it
- if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
- # focus on Tool Tab
- self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
- else:
- self.app.ui.splitter.setSizes([0, 1])
- except AttributeError:
- pass
- else:
- if self.app.ui.splitter.sizes()[0] == 0:
- self.app.ui.splitter.setSizes([1, 1])
-
- AppTool.run(self)
- self.set_tool_ui()
-
- self.app.ui.notebook.setTabText(2, _("Image Tool"))
-
- def install(self, icon=None, separator=None, **kwargs):
- AppTool.install(self, icon, separator, **kwargs)
-
- def set_tool_ui(self):
- # ## Initialize form
- self.dpi_entry.set_value(96)
- self.image_type.set_value('black')
- self.mask_bw_entry.set_value(250)
- self.mask_r_entry.set_value(250)
- self.mask_g_entry.set_value(250)
- self.mask_b_entry.set_value(250)
+ # #################################### FINSIHED GUI ###########################
+ # #############################################################################
def on_image_type(self, val):
if val == 'color':
@@ -215,83 +317,19 @@ class ToolImage(AppTool):
self.mask_bw_label.setDisabled(False)
self.mask_bw_entry.setDisabled(False)
- def on_file_importimage(self):
- """
- Callback for menu item File->Import IMAGE.
- :param type_of_obj: to import the IMAGE as Geometry or as Gerber
- :type type_of_obj: str
- :return: None
- """
- mask = []
- self.app.log.debug("on_file_importimage()")
-
- _filter = "Image Files(*.BMP *.PNG *.JPG *.JPEG);;" \
- "Bitmap File (*.BMP);;" \
- "PNG File (*.PNG);;" \
- "Jpeg File (*.JPG);;" \
- "All Files (*.*)"
- try:
- filename, _f = QtWidgets.QFileDialog.getOpenFileName(caption=_("Import IMAGE"),
- directory=self.app.get_last_folder(), filter=_filter)
- except TypeError:
- filename, _f = QtWidgets.QFileDialog.getOpenFileName(caption=_("Import IMAGE"), filter=filter)
-
- filename = str(filename)
- type_obj = self.tf_type_obj_combo.get_value()
- dpi = self.dpi_entry.get_value()
- mode = self.image_type.get_value()
- mask = [self.mask_bw_entry.get_value(), self.mask_r_entry.get_value(), self.mask_g_entry.get_value(),
- self.mask_b_entry.get_value()]
-
- if filename == "":
- self.app.inform.emit(_("Cancelled."))
+ def confirmation_message(self, accepted, minval, maxval):
+ if accepted is False:
+ self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' % (_("Edited value is out of range"),
+ self.decimals,
+ minval,
+ self.decimals,
+ maxval), False)
else:
- self.app.worker_task.emit({'fcn': self.import_image,
- 'params': [filename, type_obj, dpi, mode, mask]})
+ self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
- def import_image(self, filename, o_type=_("Gerber"), dpi=96, mode='black', mask=None, outname=None):
- """
- Adds a new Geometry Object to the projects and populates
- it with shapes extracted from the SVG file.
-
- :param filename: Path to the SVG file.
- :param o_type: type of FlatCAM objeect
- :param dpi: dot per inch
- :param mode: black or color
- :param mask: dictate the level of detail
- :param outname: name for the resulting file
- :return:
- """
-
- self.app.defaults.report_usage("import_image()")
-
- if mask is None:
- mask = [250, 250, 250, 250]
-
- if o_type is None or o_type == _("Geometry"):
- obj_type = "geometry"
- elif o_type == _("Gerber"):
- obj_type = "gerber"
+ def confirmation_message_int(self, accepted, minval, maxval):
+ if accepted is False:
+ self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%d, %d]' %
+ (_("Edited value is out of range"), minval, maxval), False)
else:
- self.app.inform.emit('[ERROR_NOTCL] %s' %
- _("Not supported type is picked as parameter. "
- "Only Geometry and Gerber are supported"))
- return
-
- def obj_init(geo_obj, app_obj):
- geo_obj.import_image(filename, units=units, dpi=dpi, mode=mode, mask=mask)
- geo_obj.multigeo = False
-
- with self.app.proc_container.new(_("Importing Image")) as proc:
-
- # Object name
- name = outname or filename.split('/')[-1].split('\\')[-1]
- units = self.app.defaults['units']
-
- self.app.app_obj.new_object(obj_type, name, obj_init)
-
- # Register recent file
- self.app.file_opened.emit("image", filename)
-
- # GUI feedback
- self.app.inform.emit('[success] %s: %s' % (_("Opened"), filename))
+ self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
diff --git a/appTools/ToolInvertGerber.py b/appTools/ToolInvertGerber.py
index 985da1f8..395acc12 100644
--- a/appTools/ToolInvertGerber.py
+++ b/appTools/ToolInvertGerber.py
@@ -8,7 +8,7 @@
from PyQt5 import QtWidgets, QtCore, QtGui
from appTool import AppTool
-from appGUI.GUIElements import FCButton, FCDoubleSpinner, RadioSet, FCComboBox
+from appGUI.GUIElements import FCButton, FCDoubleSpinner, RadioSet, FCComboBox, FCLabel
from shapely.geometry import box
@@ -28,133 +28,20 @@ log = logging.getLogger('base')
class ToolInvertGerber(AppTool):
- toolName = _("Invert Gerber Tool")
-
def __init__(self, app):
self.app = app
self.decimals = self.app.decimals
AppTool.__init__(self, app)
- self.tools_frame = QtWidgets.QFrame()
- self.tools_frame.setContentsMargins(0, 0, 0, 0)
- self.layout.addWidget(self.tools_frame)
- self.tools_box = QtWidgets.QVBoxLayout()
- self.tools_box.setContentsMargins(0, 0, 0, 0)
- self.tools_frame.setLayout(self.tools_box)
+ # #############################################################################
+ # ######################### Tool GUI ##########################################
+ # #############################################################################
+ self.ui = InvertUI(layout=self.layout, app=self.app)
+ self.toolName = self.ui.toolName
- # Title
- title_label = QtWidgets.QLabel("%s" % self.toolName)
- title_label.setStyleSheet("""
- QLabel
- {
- font-size: 16px;
- font-weight: bold;
- }
- """)
- self.tools_box.addWidget(title_label)
-
- # Grid Layout
- grid0 = QtWidgets.QGridLayout()
- grid0.setColumnStretch(0, 0)
- grid0.setColumnStretch(1, 1)
- self.tools_box.addLayout(grid0)
-
- grid0.addWidget(QtWidgets.QLabel(''), 0, 0, 1, 2)
-
- # Target Gerber Object
- self.gerber_combo = FCComboBox()
- self.gerber_combo.setModel(self.app.collection)
- self.gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.gerber_combo.is_last = True
- self.gerber_combo.obj_type = "Gerber"
-
- self.gerber_label = QtWidgets.QLabel('%s:' % _("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("%s:" % _("Parameters"))
- self.param_label.setToolTip('%s.' % _("Parameters for this tool"))
-
- grid0.addWidget(self.param_label, 4, 0, 1, 2)
-
- # Margin
- self.margin_label = QtWidgets.QLabel('%s:' % _('Margin'))
- self.margin_label.setToolTip(
- _("Distance by which to avoid\n"
- "the edges of the Gerber object.")
- )
- self.margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.margin_entry.set_precision(self.decimals)
- self.margin_entry.set_range(0.0000, 9999.9999)
- self.margin_entry.setObjectName(_("Margin"))
-
- grid0.addWidget(self.margin_label, 5, 0, 1, 2)
- grid0.addWidget(self.margin_entry, 6, 0, 1, 2)
-
- self.join_label = QtWidgets.QLabel('%s:' % _("Lines Join Style"))
- self.join_label.setToolTip(
- _("The way that the lines in the object outline will be joined.\n"
- "Can be:\n"
- "- rounded -> an arc is added between two joining lines\n"
- "- square -> the lines meet in 90 degrees angle\n"
- "- bevel -> the lines are joined by a third line")
- )
- self.join_radio = RadioSet([
- {'label': 'Rounded', 'value': 'r'},
- {'label': 'Square', 'value': 's'},
- {'label': 'Bevel', 'value': 'b'}
- ], orientation='vertical', stretch=False)
-
- grid0.addWidget(self.join_label, 7, 0, 1, 2)
- grid0.addWidget(self.join_radio, 8, 0, 1, 2)
-
- separator_line = QtWidgets.QFrame()
- separator_line.setFrameShape(QtWidgets.QFrame.HLine)
- separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid0.addWidget(separator_line, 9, 0, 1, 2)
-
- self.invert_btn = FCButton(_('Invert Gerber'))
- self.invert_btn.setToolTip(
- _("Will invert the Gerber object: areas that have copper\n"
- "will be empty of copper and previous empty area will be\n"
- "filled with copper.")
- )
- self.invert_btn.setStyleSheet("""
- QPushButton
- {
- font-weight: bold;
- }
- """)
- grid0.addWidget(self.invert_btn, 10, 0, 1, 2)
-
- self.tools_box.addStretch()
-
- # ## Reset Tool
- self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
- self.reset_button.setIcon(QtGui.QIcon(self.app.resource_location + '/reset32.png'))
- self.reset_button.setToolTip(
- _("Will reset the tool parameters.")
- )
- self.reset_button.setStyleSheet("""
- QPushButton
- {
- font-weight: bold;
- }
- """)
- self.tools_box.addWidget(self.reset_button)
-
- self.invert_btn.clicked.connect(self.on_grb_invert)
- self.reset_button.clicked.connect(self.set_tool_ui)
+ self.ui.invert_btn.clicked.connect(self.on_grb_invert)
+ self.ui.reset_button.clicked.connect(self.set_tool_ui)
def install(self, icon=None, separator=None, **kwargs):
AppTool.install(self, icon, separator, shortcut='', **kwargs)
@@ -188,20 +75,20 @@ class ToolInvertGerber(AppTool):
self.app.ui.notebook.setTabText(2, _("Invert Tool"))
def set_tool_ui(self):
- self.margin_entry.set_value(float(self.app.defaults["tools_invert_margin"]))
- self.join_radio.set_value(self.app.defaults["tools_invert_join_style"])
+ self.ui.margin_entry.set_value(float(self.app.defaults["tools_invert_margin"]))
+ self.ui.join_radio.set_value(self.app.defaults["tools_invert_join_style"])
def on_grb_invert(self):
- margin = self.margin_entry.get_value()
+ margin = self.ui.margin_entry.get_value()
if round(margin, self.decimals) == 0.0:
margin = 1E-10
- join_style = {'r': 1, 'b': 3, 's': 2}[self.join_radio.get_value()]
+ join_style = {'r': 1, 'b': 3, 's': 2}[self.ui.join_radio.get_value()]
if join_style is None:
join_style = 'r'
grb_circle_steps = int(self.app.defaults["gerber_circle_steps"])
- obj_name = self.gerber_combo.currentText()
+ obj_name = self.ui.gerber_combo.currentText()
outname = obj_name + "_inverted"
@@ -243,32 +130,6 @@ class ToolInvertGerber(AppTool):
new_apertures = {}
- # for apid, val in grb_obj.apertures.items():
- # new_apertures[apid] = {}
- # for key in val:
- # if key == 'geometry':
- # new_apertures[apid]['geometry'] = []
- # for elem in val['geometry']:
- # geo_elem = {}
- # if 'follow' in elem:
- # try:
- # geo_elem['clear'] = elem['follow'].buffer(val['size'] / 2.0).exterior
- # except AttributeError:
- # # TODO should test if width or height is bigger
- # geo_elem['clear'] = elem['follow'].buffer(val['width'] / 2.0).exterior
- # if 'clear' in elem:
- # if isinstance(elem['clear'], Polygon):
- # try:
- # geo_elem['solid'] = elem['clear'].buffer(val['size'] / 2.0, grb_circle_steps)
- # except AttributeError:
- # # TODO should test if width or height is bigger
- # geo_elem['solid'] = elem['clear'].buffer(val['width'] / 2.0, grb_circle_steps)
- # else:
- # geo_elem['follow'] = elem['clear']
- # new_apertures[apid]['geometry'].append(deepcopy(geo_elem))
- # else:
- # new_apertures[apid][key] = deepcopy(val[key])
-
if '0' not in new_apertures:
new_apertures['0'] = {}
new_apertures['0']['type'] = 'C'
@@ -302,9 +163,155 @@ class ToolInvertGerber(AppTool):
self.app.app_obj.new_object('gerber', outname, init_func)
def reset_fields(self):
- self.gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.ui.gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
@staticmethod
def poly2rings(poly):
return [poly.exterior] + [interior for interior in poly.interiors]
-# end of file
+
+
+class InvertUI:
+
+ toolName = _("Invert Gerber Tool")
+
+ def __init__(self, layout, app):
+ self.app = app
+ self.decimals = self.app.decimals
+ self.layout = layout
+
+ # ## Title
+ title_label = FCLabel("%s" % self.toolName)
+ title_label.setStyleSheet("""
+ QLabel
+ {
+ font-size: 16px;
+ font-weight: bold;
+ }
+ """)
+ self.layout.addWidget(title_label)
+ self.layout.addWidget(FCLabel(""))
+
+ self.tools_frame = QtWidgets.QFrame()
+ self.tools_frame.setContentsMargins(0, 0, 0, 0)
+ self.layout.addWidget(self.tools_frame)
+
+ self.tools_box = QtWidgets.QVBoxLayout()
+ self.tools_box.setContentsMargins(0, 0, 0, 0)
+ self.tools_frame.setLayout(self.tools_box)
+
+ # Grid Layout
+ grid0 = QtWidgets.QGridLayout()
+ grid0.setColumnStretch(0, 0)
+ grid0.setColumnStretch(1, 1)
+ self.tools_box.addLayout(grid0)
+
+ # Target Gerber Object
+ self.gerber_combo = FCComboBox()
+ self.gerber_combo.setModel(self.app.collection)
+ self.gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.gerber_combo.is_last = True
+ self.gerber_combo.obj_type = "Gerber"
+
+ self.gerber_label = FCLabel('%s:' % _("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("%s:" % _("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)
\ No newline at end of file
diff --git a/appTools/ToolOptimal.py b/appTools/ToolOptimal.py
index b6582210..b17a8e63 100644
--- a/appTools/ToolOptimal.py
+++ b/appTools/ToolOptimal.py
@@ -30,8 +30,6 @@ log = logging.getLogger('base')
class ToolOptimal(AppTool):
- toolName = _("Optimal Tool")
-
update_text = QtCore.pyqtSignal(list)
update_sec_distances = QtCore.pyqtSignal(dict)
@@ -41,222 +39,11 @@ class ToolOptimal(AppTool):
self.units = self.app.defaults['units'].upper()
self.decimals = self.app.decimals
- # ############################################################################
- # ############################ GUI creation ##################################
- # ## Title
- title_label = QtWidgets.QLabel("%s" % self.toolName)
- title_label.setStyleSheet(
- """
- QLabel
- {
- font-size: 16px;
- font-weight: bold;
- }
- """)
- self.layout.addWidget(title_label)
-
- # ## Form Layout
- form_lay = QtWidgets.QFormLayout()
- self.layout.addLayout(form_lay)
-
- form_lay.addRow(QtWidgets.QLabel(""))
-
- # ## Gerber Object to mirror
- self.gerber_object_combo = FCComboBox()
- self.gerber_object_combo.setModel(self.app.collection)
- self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.gerber_object_combo.is_last = True
- self.gerber_object_combo.obj_type = "Gerber"
-
- self.gerber_object_label = QtWidgets.QLabel("%s:" % _("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('%s:' % _("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('%s:' % _("Other distances"))
- self.title_second_res_label.setToolTip(_("Will display other distances in the Gerber file ordered from\n"
- "the minimum to the maximum, not including the absolute minimum."))
- form_lay.addRow(self.title_second_res_label)
-
- # Control if to display the locations of where the minimum was found
- self.sec_locations_cb = FCCheckBox(_("Other distances points coordinates"))
- self.sec_locations_cb.setToolTip(_("Other distances and the coordinates for points\n"
- "where the distance was found."))
- form_lay.addRow(self.sec_locations_cb)
-
- # this way I can hide/show the frame
- self.sec_locations_frame = QtWidgets.QFrame()
- self.sec_locations_frame.setContentsMargins(0, 0, 0, 0)
- self.layout.addWidget(self.sec_locations_frame)
- self.distances_box = QtWidgets.QVBoxLayout()
- self.distances_box.setContentsMargins(0, 0, 0, 0)
- self.sec_locations_frame.setLayout(self.distances_box)
-
- # Other Distances label
- self.distances_label = QtWidgets.QLabel('%s' % _("Gerber distances"))
- self.distances_label.setToolTip(_("Other distances and the coordinates for points\n"
- "where the distance was found."))
- self.distances_box.addWidget(self.distances_label)
-
- # Other distances
- self.distances_textb = FCTextArea(parent=self)
- self.distances_textb.setPlaceholderText(
- _("Other distances and the coordinates for points\n"
- "where the distance was found.")
- )
- self.distances_textb.setReadOnly(True)
- stylesheet = """
- QTextEdit { selection-background-color:blue;
- selection-color:white;
- }
- """
-
- self.distances_textb.setStyleSheet(stylesheet)
- self.distances_box.addWidget(self.distances_textb)
-
- self.distances_box.addWidget(QtWidgets.QLabel(''))
-
- # Other Locations label
- self.locations_label = QtWidgets.QLabel('%s' % _("Points coordinates"))
- self.locations_label.setToolTip(_("Other distances and the coordinates for points\n"
- "where the distance was found."))
- self.distances_box.addWidget(self.locations_label)
-
- # Locations where minimum was found
- self.locations_sec_textb = FCTextArea(parent=self)
- self.locations_sec_textb.setPlaceholderText(
- _("Other distances and the coordinates for points\n"
- "where the distance was found.")
- )
- self.locations_sec_textb.setReadOnly(True)
- stylesheet = """
- QTextEdit { selection-background-color:blue;
- selection-color:white;
- }
- """
-
- self.locations_sec_textb.setStyleSheet(stylesheet)
- self.distances_box.addWidget(self.locations_sec_textb)
-
- # Jump button
- self.locate_sec_button = QtWidgets.QPushButton(_("Jump to selected position"))
- self.locate_sec_button.setToolTip(
- _("Select a position in the Locations text box and then\n"
- "click this button.")
- )
- self.locate_sec_button.setMinimumWidth(60)
- self.locate_sec_button.setDisabled(True)
- self.distances_box.addWidget(self.locate_sec_button)
-
- # GO button
- self.calculate_button = QtWidgets.QPushButton(_("Find Minimum"))
- self.calculate_button.setToolTip(
- _("Calculate the minimum distance between copper features,\n"
- "this will allow the determination of the right tool to\n"
- "use for isolation or copper clearing.")
- )
- self.calculate_button.setStyleSheet("""
- QPushButton
- {
- font-weight: bold;
- }
- """)
- self.calculate_button.setMinimumWidth(60)
- self.layout.addWidget(self.calculate_button)
-
- self.layout.addStretch()
-
- # ## Reset Tool
- self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
- self.reset_button.setIcon(QtGui.QIcon(self.app.resource_location + '/reset32.png'))
- self.reset_button.setToolTip(
- _("Will reset the tool parameters.")
- )
- self.reset_button.setStyleSheet("""
- QPushButton
- {
- font-weight: bold;
- }
- """)
- self.layout.addWidget(self.reset_button)
-
- self.loc_ois = OptionalHideInputSection(self.locations_cb, [self.locations_textb, self.locate_button])
- self.sec_loc_ois = OptionalHideInputSection(self.sec_locations_cb, [self.sec_locations_frame])
- # ################## Finished GUI creation ###################################
- # ############################################################################
+ # #############################################################################
+ # ######################### Tool GUI ##########################################
+ # #############################################################################
+ self.ui = OptimalUI(layout=self.layout, app=self.app)
+ self.toolName = self.ui.toolName
# this is the line selected in the textbox with the locations of the minimum
self.selected_text = ''
@@ -271,17 +58,17 @@ class ToolOptimal(AppTool):
# ############################################################################
# ############################ Signals #######################################
# ############################################################################
- self.calculate_button.clicked.connect(self.find_minimum_distance)
- self.locate_button.clicked.connect(self.on_locate_position)
- self.update_text.connect(self.on_update_text)
- self.locations_textb.cursorPositionChanged.connect(self.on_textbox_clicked)
+ self.ui.calculate_button.clicked.connect(self.find_minimum_distance)
+ self.ui.locate_button.clicked.connect(self.on_locate_position)
+ self.ui.update_text.connect(self.on_update_text)
+ self.ui.locations_textb.cursorPositionChanged.connect(self.on_textbox_clicked)
- self.locate_sec_button.clicked.connect(self.on_locate_sec_position)
- self.update_sec_distances.connect(self.on_update_sec_distances_txt)
- self.distances_textb.cursorPositionChanged.connect(self.on_distances_textb_clicked)
- self.locations_sec_textb.cursorPositionChanged.connect(self.on_locations_sec_clicked)
+ self.ui.locate_sec_button.clicked.connect(self.on_locate_sec_position)
+ self.ui.update_sec_distances.connect(self.on_update_sec_distances_txt)
+ self.ui.distances_textb.cursorPositionChanged.connect(self.on_distances_textb_clicked)
+ self.ui.locations_sec_textb.cursorPositionChanged.connect(self.on_locations_sec_clicked)
- self.reset_button.clicked.connect(self.set_tool_ui)
+ self.ui.reset_button.clicked.connect(self.set_tool_ui)
def install(self, icon=None, separator=None, **kwargs):
AppTool.install(self, icon, separator, shortcut='Alt+O', **kwargs)
@@ -314,13 +101,13 @@ class ToolOptimal(AppTool):
self.app.ui.notebook.setTabText(2, _("Optimal Tool"))
def set_tool_ui(self):
- self.result_entry.set_value(0.0)
- self.freq_entry.set_value('0')
+ self.ui.result_entry.set_value(0.0)
+ self.ui.freq_entry.set_value('0')
- self.precision_spinner.set_value(int(self.app.defaults["tools_opt_precision"]))
- self.locations_textb.clear()
+ self.ui.precision_spinner.set_value(int(self.app.defaults["tools_opt_precision"]))
+ self.ui.locations_textb.clear()
# new cursor - select all document
- cursor = self.locations_textb.textCursor()
+ cursor = self.ui.locations_textb.textCursor()
cursor.select(QtGui.QTextCursor.Document)
# clear previous selection highlight
@@ -328,20 +115,20 @@ class ToolOptimal(AppTool):
tmp.clearBackground()
cursor.setBlockFormat(tmp)
- self.locations_textb.setVisible(False)
- self.locate_button.setVisible(False)
+ self.ui.locations_textb.setVisible(False)
+ self.ui.locate_button.setVisible(False)
- self.result_entry.set_value(0.0)
- self.freq_entry.set_value('0')
+ self.ui.result_entry.set_value(0.0)
+ self.ui.freq_entry.set_value('0')
self.reset_fields()
def find_minimum_distance(self):
self.units = self.app.defaults['units'].upper()
- self.decimals = int(self.precision_spinner.get_value())
+ self.decimals = int(self.ui.precision_spinner.get_value())
- selection_index = self.gerber_object_combo.currentIndex()
+ selection_index = self.ui.gerber_object_combo.currentIndex()
- model_index = self.app.collection.index(selection_index, 0, self.gerber_object_combo.rootModelIndex())
+ model_index = self.app.collection.index(selection_index, 0, self.ui.gerber_object_combo.rootModelIndex())
try:
fcobj = model_index.internalPointer().obj
except Exception as e:
@@ -426,17 +213,16 @@ class ToolOptimal(AppTool):
old_disp_number = disp_number
idx += 1
- app_obj.inform.emit(
- _("Optimal Tool. Finding the minimum distance."))
+ app_obj.inform.emit(_("Optimal Tool. Finding the minimum distance."))
min_list = list(self.min_dict.keys())
min_dist = min(min_list)
min_dist_string = '%.*f' % (self.decimals, float(min_dist))
- self.result_entry.set_value(min_dist_string)
+ self.ui.result_entry.set_value(min_dist_string)
freq = len(self.min_dict[min_dist])
freq = '%d' % int(freq)
- self.freq_entry.set_value(freq)
+ self.ui.freq_entry.set_value(freq)
min_locations = self.min_dict.pop(min_dist)
@@ -484,12 +270,12 @@ class ToolOptimal(AppTool):
for loc in data:
if loc:
txt += '%s, %s\n' % (str(loc[0]), str(loc[1]))
- self.locations_textb.setPlainText(txt)
- self.locate_button.setDisabled(False)
+ self.ui.locations_textb.setPlainText(txt)
+ self.ui.locate_button.setDisabled(False)
def on_textbox_clicked(self):
# new cursor - select all document
- cursor = self.locations_textb.textCursor()
+ cursor = self.ui.locations_textb.textCursor()
cursor.select(QtGui.QTextCursor.Document)
# clear previous selection highlight
@@ -498,7 +284,7 @@ class ToolOptimal(AppTool):
cursor.setBlockFormat(tmp)
# new cursor - select the current line
- cursor = self.locations_textb.textCursor()
+ cursor = self.ui.locations_textb.textCursor()
cursor.select(QtGui.QTextCursor.LineUnderCursor)
# highlight the current selected line
@@ -513,12 +299,12 @@ class ToolOptimal(AppTool):
txt = ''
for loc in distance_list:
txt += '%s\n' % str(loc)
- self.distances_textb.setPlainText(txt)
- self.locate_sec_button.setDisabled(False)
+ self.ui.distances_textb.setPlainText(txt)
+ self.ui.locate_sec_button.setDisabled(False)
def on_distances_textb_clicked(self):
# new cursor - select all document
- cursor = self.distances_textb.textCursor()
+ cursor = self.ui.distances_textb.textCursor()
cursor.select(QtGui.QTextCursor.Document)
# clear previous selection highlight
@@ -527,7 +313,7 @@ class ToolOptimal(AppTool):
cursor.setBlockFormat(tmp)
# new cursor - select the current line
- cursor = self.distances_textb.textCursor()
+ cursor = self.ui.distances_textb.textCursor()
cursor.select(QtGui.QTextCursor.LineUnderCursor)
# highlight the current selected line
@@ -545,11 +331,11 @@ class ToolOptimal(AppTool):
for loc in distance_list:
if loc:
txt += '%s, %s\n' % (str(loc[0]), str(loc[1]))
- self.locations_sec_textb.setPlainText(txt)
+ self.ui.locations_sec_textb.setPlainText(txt)
def on_locations_sec_clicked(self):
# new cursor - select all document
- cursor = self.locations_sec_textb.textCursor()
+ cursor = self.ui.locations_sec_textb.textCursor()
cursor.select(QtGui.QTextCursor.Document)
# clear previous selection highlight
@@ -558,7 +344,7 @@ class ToolOptimal(AppTool):
cursor.setBlockFormat(tmp)
# new cursor - select the current line
- cursor = self.locations_sec_textb.textCursor()
+ cursor = self.ui.locations_sec_textb.textCursor()
cursor.select(QtGui.QTextCursor.LineUnderCursor)
# highlight the current selected line
@@ -593,5 +379,247 @@ class ToolOptimal(AppTool):
return
def reset_fields(self):
+ self.ui.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.ui.gerber_object_combo.setCurrentIndex(0)
+
+
+class OptimalUI:
+
+ toolName = _("Optimal Tool")
+
+ def __init__(self, layout, app):
+ self.app = app
+ self.decimals = self.app.decimals
+ self.layout = layout
+ self.units = self.app.defaults['units'].upper()
+
+ # ## Title
+ title_label = QtWidgets.QLabel("%s" % self.toolName)
+ title_label.setStyleSheet("""
+ QLabel
+ {
+ font-size: 16px;
+ font-weight: bold;
+ }
+ """)
+ self.layout.addWidget(title_label)
+ self.layout.addWidget(QtWidgets.QLabel(""))
+
+ # ## Form Layout
+ form_lay = QtWidgets.QFormLayout()
+ self.layout.addLayout(form_lay)
+
+ # ## Gerber Object to mirror
+ self.gerber_object_combo = FCComboBox()
+ self.gerber_object_combo.setModel(self.app.collection)
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.gerber_object_combo.setCurrentIndex(0)
+ self.gerber_object_combo.is_last = True
+ self.gerber_object_combo.obj_type = "Gerber"
+
+ self.gerber_object_label = QtWidgets.QLabel("%s:" % _("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('%s:' % _("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('%s:' % _("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)
diff --git a/appTools/ToolPcbWizard.py b/appTools/ToolPcbWizard.py
index 0cb93bd8..5d133a2f 100644
--- a/appTools/ToolPcbWizard.py
+++ b/appTools/ToolPcbWizard.py
@@ -8,7 +8,7 @@
from PyQt5 import QtWidgets, QtCore
from appTool import AppTool
-from appGUI.GUIElements import RadioSet, FCSpinner, FCButton, FCTable
+from appGUI.GUIElements import RadioSet, FCSpinner, FCButton, FCTable, FCLabel
import re
import os
@@ -28,121 +28,17 @@ class PcbWizard(AppTool):
file_loaded = QtCore.pyqtSignal(str, str)
- toolName = _("PcbWizard Import Tool")
-
def __init__(self, app):
AppTool.__init__(self, app)
self.app = app
self.decimals = self.app.decimals
- # Title
- title_label = QtWidgets.QLabel("%s" % _('Import 2-file Excellon'))
- title_label.setStyleSheet("""
- QLabel
- {
- font-size: 16px;
- font-weight: bold;
- }
- """)
- self.layout.addWidget(title_label)
-
- self.layout.addWidget(QtWidgets.QLabel(""))
- self.layout.addWidget(QtWidgets.QLabel("%s:" % _("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("%s:" % _("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("%s:" % _('Units'))
- self.units_label.setToolTip(
- _("The type of units that the coordinates and tool\n"
- "diameters are using. Can be INCH or MM.")
- )
- form_layout1.addRow(self.units_label, self.units_radio)
-
- # Buttons
-
- self.import_button = QtWidgets.QPushButton(_("Import Excellon"))
- self.import_button.setToolTip(
- _("Import in FlatCAM an Excellon file\n"
- "that store it's information's in 2 files.\n"
- "One usually has .DRL extension while\n"
- "the other has .INF extension.")
- )
- self.layout.addWidget(self.import_button)
-
- self.layout.addStretch()
+ # #############################################################################
+ # ######################### Tool GUI ##########################################
+ # #############################################################################
+ self.ui = WizardUI(layout=self.layout, app=self.app)
+ self.toolName = self.ui.toolName
self.excellon_loaded = False
self.inf_loaded = False
@@ -151,13 +47,13 @@ class PcbWizard(AppTool):
self.modified_excellon_file = ''
# ## Signals
- self.excellon_brn.clicked.connect(self.on_load_excellon_click)
- self.inf_btn.clicked.connect(self.on_load_inf_click)
- self.import_button.clicked.connect(lambda: self.on_import_excellon(
+ self.ui.excellon_brn.clicked.connect(self.on_load_excellon_click)
+ self.ui.inf_btn.clicked.connect(self.on_load_inf_click)
+ self.ui.import_button.clicked.connect(lambda: self.on_import_excellon(
excellon_fileobj=self.modified_excellon_file))
self.file_loaded.connect(self.on_file_loaded)
- self.units_radio.activated_custom.connect(self.on_units_change)
+ self.ui.units_radio.activated_custom.connect(self.ui.on_units_change)
self.units = 'INCH'
self.zeros = 'LZ'
@@ -211,10 +107,10 @@ class PcbWizard(AppTool):
self.tools_from_inf = {}
# ## Initialize form
- self.int_entry.set_value(self.integral)
- self.frac_entry.set_value(self.fractional)
- self.zeros_radio.set_value(self.zeros)
- self.units_radio.set_value(self.units)
+ self.ui.int_entry.set_value(self.integral)
+ self.ui.frac_entry.set_value(self.fractional)
+ self.ui.zeros_radio.set_value(self.zeros)
+ self.ui.units_radio.set_value(self.units)
self.excellon_loaded = False
self.inf_loaded = False
@@ -227,57 +123,49 @@ class PcbWizard(AppTool):
sorted_tools = []
if not self.tools_from_inf:
- self.tools_table.setVisible(False)
+ self.ui.tools_table.setVisible(False)
else:
sort = []
for k, v in list(self.tools_from_inf.items()):
sort.append(int(k))
sorted_tools = sorted(sort)
n = len(sorted_tools)
- self.tools_table.setRowCount(n)
+ self.ui.tools_table.setRowCount(n)
tool_row = 0
for tool in sorted_tools:
tool_id_item = QtWidgets.QTableWidgetItem('%d' % int(tool))
tool_id_item.setFlags(QtCore.Qt.ItemIsEnabled)
- self.tools_table.setItem(tool_row, 0, tool_id_item) # Tool name/id
+ self.ui.tools_table.setItem(tool_row, 0, tool_id_item) # Tool name/id
tool_dia_item = QtWidgets.QTableWidgetItem(str(self.tools_from_inf[tool]))
tool_dia_item.setFlags(QtCore.Qt.ItemIsEnabled)
- self.tools_table.setItem(tool_row, 1, tool_dia_item)
+ self.ui.tools_table.setItem(tool_row, 1, tool_dia_item)
tool_row += 1
- self.tools_table.resizeColumnsToContents()
- self.tools_table.resizeRowsToContents()
+ self.ui.tools_table.resizeColumnsToContents()
+ self.ui.tools_table.resizeRowsToContents()
- vertical_header = self.tools_table.verticalHeader()
+ vertical_header = self.ui.tools_table.verticalHeader()
vertical_header.hide()
- self.tools_table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+ self.ui.tools_table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
- horizontal_header = self.tools_table.horizontalHeader()
+ horizontal_header = self.ui.tools_table.horizontalHeader()
# horizontal_header.setMinimumSectionSize(10)
# horizontal_header.setDefaultSectionSize(70)
horizontal_header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
- self.tools_table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
- self.tools_table.setSortingEnabled(False)
- self.tools_table.setMinimumHeight(self.tools_table.getHeight())
- self.tools_table.setMaximumHeight(self.tools_table.getHeight())
+ self.ui.tools_table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+ self.ui.tools_table.setSortingEnabled(False)
+ self.ui.tools_table.setMinimumHeight(self.ui.tools_table.getHeight())
+ self.ui.tools_table.setMaximumHeight(self.ui.tools_table.getHeight())
def update_params(self):
- self.units = self.units_radio.get_value()
- self.zeros = self.zeros_radio.get_value()
- self.integral = self.int_entry.get_value()
- self.fractional = self.frac_entry.get_value()
-
- def on_units_change(self, val):
- if val == 'INCH':
- self.int_entry.set_value(2)
- self.frac_entry.set_value(4)
- else:
- self.int_entry.set_value(3)
- self.frac_entry.set_value(3)
+ self.units = self.ui.units_radio.get_value()
+ self.zeros = self.ui.zeros_radio.get_value()
+ self.integral = self.ui.int_entry.get_value()
+ self.fractional = self.ui.frac_entry.get_value()
def on_load_excellon_click(self):
"""
@@ -357,9 +245,9 @@ class PcbWizard(AppTool):
self.units = 'INCH'
else:
self.units = 'METRIC'
- self.units_radio.set_value(self.units)
- self.int_entry.set_value(self.integral)
- self.frac_entry.set_value(self.fractional)
+ self.ui.units_radio.set_value(self.units)
+ self.ui.int_entry.set_value(self.integral)
+ self.ui.frac_entry.set_value(self.fractional)
if not self.tools_from_inf:
self.app.inform.emit('[ERROR] %s' %
@@ -382,14 +270,12 @@ class PcbWizard(AppTool):
if signal == 'inf':
self.inf_loaded = True
- self.tools_table.setVisible(True)
- self.app.inform.emit('[success] %s' %
- _("PcbWizard .INF file loaded."))
+ self.ui.tools_table.setVisible(True)
+ self.app.inform.emit('[success] %s' % _("PcbWizard .INF file loaded."))
elif signal == 'excellon':
self.excellon_loaded = True
self.outname = os.path.split(str(filename))[1]
- self.app.inform.emit('[success] %s' %
- _("Main PcbWizard Excellon file loaded."))
+ self.app.inform.emit('[success] %s' % _("Main PcbWizard Excellon file loaded."))
if self.excellon_loaded and self.inf_loaded:
self.update_params()
@@ -467,3 +353,149 @@ class PcbWizard(AppTool):
self.app.inform.emit('[WARNING_NOTCL] %s' % _('Excellon merging is in progress. Please wait...'))
else:
self.app.inform.emit('[ERROR_NOTCL] %s' % _('The imported Excellon file is empty.'))
+
+
+class WizardUI:
+
+ toolName = _("PcbWizard Import Tool")
+
+ def __init__(self, layout, app):
+ self.app = app
+ self.decimals = self.app.decimals
+ self.layout = layout
+
+ # ## Title
+ title_label = FCLabel("%s" % self.toolName)
+ title_label.setStyleSheet("""
+ QLabel
+ {
+ font-size: 16px;
+ font-weight: bold;
+ }
+ """)
+ self.layout.addWidget(title_label)
+ self.layout.addWidget(FCLabel(""))
+
+ self.layout.addWidget(FCLabel("%s:" % _("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("%s:" % _("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("%s:" % _('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)