diff --git a/CHANGELOG.md b/CHANGELOG.md
index ed70bce2..5996bf6b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,9 +16,10 @@ 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
+- in Tools: Image, InvertGerber, Optimal, PcbWizard - moved the Tool UI in its own class
- Tool Isolation - made sure that the app can load from Tools Database only tools marked for Isolation tool
- Tool Isolation - on Tool start it will attempt to load the Preferences set tools by diameter from Tools Database. If it can't find one there it will add a default tool.
+- in Tools: Transform, SUb, RulesCheck, DistanceMin, Distance - moved the Tool UI in its own class
26.08.2020
diff --git a/appTools/ToolDistance.py b/appTools/ToolDistance.py
index ac48f9ce..24a7cd8d 100644
--- a/appTools/ToolDistance.py
+++ b/appTools/ToolDistance.py
@@ -9,7 +9,7 @@ from PyQt5 import QtWidgets, QtCore
from appTool import AppTool
from appGUI.VisPyVisuals import *
-from appGUI.GUIElements import FCEntry, FCButton, FCCheckBox
+from appGUI.GUIElements import FCEntry, FCButton, FCCheckBox, FCLabel
from shapely.geometry import Point, MultiLineString, Polygon
@@ -32,8 +32,6 @@ log = logging.getLogger('base')
class Distance(AppTool):
- toolName = _("Distance Tool")
-
def __init__(self, app):
AppTool.__init__(self, app)
@@ -43,107 +41,11 @@ class Distance(AppTool):
self.canvas = self.app.plotcanvas
self.units = self.app.defaults['units'].lower()
- # ## Title
- title_label = QtWidgets.QLabel("%s
" % self.toolName)
- self.layout.addWidget(title_label)
-
- # ## Form Layout
- grid0 = QtWidgets.QGridLayout()
- grid0.setColumnStretch(0, 0)
- grid0.setColumnStretch(1, 1)
- self.layout.addLayout(grid0)
-
- self.units_label = QtWidgets.QLabel('%s:' % _("Units"))
- self.units_label.setToolTip(_("Those are the units in which the distance is measured."))
- self.units_value = QtWidgets.QLabel("%s" % str({'mm': _("METRIC (mm)"), 'in': _("INCH (in)")}[self.units]))
- self.units_value.setDisabled(True)
-
- grid0.addWidget(self.units_label, 0, 0)
- grid0.addWidget(self.units_value, 0, 1)
-
- self.snap_center_cb = FCCheckBox(_("Snap to center"))
- self.snap_center_cb.setToolTip(
- _("Mouse cursor will snap to the center of the pad/drill\n"
- "when it is hovering over the geometry of the pad/drill.")
- )
- grid0.addWidget(self.snap_center_cb, 1, 0, 1, 2)
-
- separator_line = QtWidgets.QFrame()
- separator_line.setFrameShape(QtWidgets.QFrame.HLine)
- separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid0.addWidget(separator_line, 2, 0, 1, 2)
-
- self.start_label = QtWidgets.QLabel("%s:" % _('Start Coords'))
- self.start_label.setToolTip(_("This is measuring Start point coordinates."))
-
- self.start_entry = FCEntry()
- self.start_entry.setReadOnly(True)
- self.start_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
- self.start_entry.setToolTip(_("This is measuring Start point coordinates."))
-
- grid0.addWidget(self.start_label, 3, 0)
- grid0.addWidget(self.start_entry, 3, 1)
-
- self.stop_label = QtWidgets.QLabel("%s:" % _('Stop Coords'))
- self.stop_label.setToolTip(_("This is the measuring Stop point coordinates."))
-
- self.stop_entry = FCEntry()
- self.stop_entry.setReadOnly(True)
- self.stop_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
- self.stop_entry.setToolTip(_("This is the measuring Stop point coordinates."))
-
- grid0.addWidget(self.stop_label, 4, 0)
- grid0.addWidget(self.stop_entry, 4, 1)
-
- self.distance_x_label = QtWidgets.QLabel('%s:' % _("Dx"))
- self.distance_x_label.setToolTip(_("This is the distance measured over the X axis."))
-
- self.distance_x_entry = FCEntry()
- self.distance_x_entry.setReadOnly(True)
- self.distance_x_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
- self.distance_x_entry.setToolTip(_("This is the distance measured over the X axis."))
-
- grid0.addWidget(self.distance_x_label, 5, 0)
- grid0.addWidget(self.distance_x_entry, 5, 1)
-
- self.distance_y_label = QtWidgets.QLabel('%s:' % _("Dy"))
- self.distance_y_label.setToolTip(_("This is the distance measured over the Y axis."))
-
- self.distance_y_entry = FCEntry()
- self.distance_y_entry.setReadOnly(True)
- self.distance_y_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
- self.distance_y_entry.setToolTip(_("This is the distance measured over the Y axis."))
-
- grid0.addWidget(self.distance_y_label, 6, 0)
- grid0.addWidget(self.distance_y_entry, 6, 1)
-
- self.angle_label = QtWidgets.QLabel('%s:' % _("Angle"))
- self.angle_label.setToolTip(_("This is orientation angle of the measuring line."))
-
- self.angle_entry = FCEntry()
- self.angle_entry.setReadOnly(True)
- self.angle_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
- self.angle_entry.setToolTip(_("This is orientation angle of the measuring line."))
-
- grid0.addWidget(self.angle_label, 7, 0)
- grid0.addWidget(self.angle_entry, 7, 1)
-
- self.total_distance_label = QtWidgets.QLabel("%s:" % _('DISTANCE'))
- self.total_distance_label.setToolTip(_("This is the point to point Euclidian distance."))
-
- self.total_distance_entry = FCEntry()
- self.total_distance_entry.setReadOnly(True)
- self.total_distance_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
- self.total_distance_entry.setToolTip(_("This is the point to point Euclidian distance."))
-
- grid0.addWidget(self.total_distance_label, 8, 0)
- grid0.addWidget(self.total_distance_entry, 8, 1)
-
- self.measure_btn = FCButton(_("Measure"))
- # self.measure_btn.setFixedWidth(70)
- self.layout.addWidget(self.measure_btn)
-
- self.layout.addStretch()
+ # #############################################################################
+ # ######################### Tool GUI ##########################################
+ # #############################################################################
+ self.ui = DistUI(layout=self.layout, app=self.app)
+ self.toolName = self.ui.toolName
# store here the first click and second click of the measurement process
self.points = []
@@ -178,8 +80,9 @@ class Distance(AppTool):
else:
from appGUI.PlotCanvasLegacy import ShapeCollectionLegacy
self.sel_shapes = ShapeCollectionLegacy(obj=self, app=self.app, name='measurement')
-
- self.measure_btn.clicked.connect(self.activate_measure_tool)
+
+ # Signals
+ self.ui.measure_btn.clicked.connect(self.activate_measure_tool)
def run(self, toggle=False):
self.app.defaults.report_usage("ToolDistance()")
@@ -224,27 +127,27 @@ class Distance(AppTool):
self.app.command_active = "Distance"
# initial view of the layout
- self.start_entry.set_value('(0, 0)')
- self.stop_entry.set_value('(0, 0)')
+ self.ui.start_entry.set_value('(0, 0)')
+ self.ui.stop_entry.set_value('(0, 0)')
- self.distance_x_entry.set_value('0.0')
- self.distance_y_entry.set_value('0.0')
- self.angle_entry.set_value('0.0')
- self.total_distance_entry.set_value('0.0')
+ self.ui.distance_x_entry.set_value('0.0')
+ self.ui.distance_y_entry.set_value('0.0')
+ self.ui.angle_entry.set_value('0.0')
+ self.ui.total_distance_entry.set_value('0.0')
- self.snap_center_cb.set_value(self.app.defaults['tools_dist_snap_center'])
+ self.ui.snap_center_cb.set_value(self.app.defaults['tools_dist_snap_center'])
# snap center works only for Gerber and Execellon Editor's
if self.original_call_source == 'exc_editor' or self.original_call_source == 'grb_editor':
- self.snap_center_cb.show()
+ self.ui.snap_center_cb.show()
snap_center = self.app.defaults['tools_dist_snap_center']
self.on_snap_toggled(snap_center)
- self.snap_center_cb.toggled.connect(self.on_snap_toggled)
+ self.ui.snap_center_cb.toggled.connect(self.on_snap_toggled)
else:
- self.snap_center_cb.hide()
+ self.ui.snap_center_cb.hide()
try:
- self.snap_center_cb.toggled.disconnect(self.on_snap_toggled)
+ self.ui.snap_center_cb.toggled.disconnect(self.on_snap_toggled)
except (TypeError, AttributeError):
pass
@@ -270,8 +173,8 @@ class Distance(AppTool):
self.active = True
# disable the measuring button
- self.measure_btn.setDisabled(True)
- self.measure_btn.setText('%s...' % _("Working"))
+ self.ui.measure_btn.setDisabled(True)
+ self.ui.measure_btn.setText('%s...' % _("Working"))
self.clicked_meas = 0
self.original_call_source = copy(self.app.call_source)
@@ -335,8 +238,8 @@ class Distance(AppTool):
self.points = []
# disable the measuring button
- self.measure_btn.setDisabled(False)
- self.measure_btn.setText(_("Measure"))
+ self.ui.measure_btn.setDisabled(False)
+ self.ui.measure_btn.setText(_("Measure"))
self.app.call_source = copy(self.original_call_source)
if self.original_call_source == 'app':
@@ -406,7 +309,7 @@ class Distance(AppTool):
if event.button == 1:
pos_canvas = self.canvas.translate_coords(event_pos)
- if self.snap_center_cb.get_value() is False:
+ if self.ui.snap_center_cb.get_value() is False:
# if GRID is active we need to get the snapped positions
if self.app.grid_status():
pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1])
@@ -490,14 +393,14 @@ class Distance(AppTool):
def calculate_distance(self, pos):
if len(self.points) == 1:
- self.start_entry.set_value("(%.*f, %.*f)" % (self.decimals, pos[0], self.decimals, pos[1]))
+ self.ui.start_entry.set_value("(%.*f, %.*f)" % (self.decimals, pos[0], self.decimals, pos[1]))
self.app.inform.emit(_("MEASURING: Click on the Destination point ..."))
elif len(self.points) == 2:
# self.app.app_cursor.enabled = False
dx = self.points[1][0] - self.points[0][0]
dy = self.points[1][1] - self.points[0][1]
d = math.sqrt(dx ** 2 + dy ** 2)
- self.stop_entry.set_value("(%.*f, %.*f)" % (self.decimals, pos[0], self.decimals, pos[1]))
+ self.ui.stop_entry.set_value("(%.*f, %.*f)" % (self.decimals, pos[0], self.decimals, pos[1]))
self.app.inform.emit("{tx1}: {tx2} D(x) = {d_x} | D(y) = {d_y} | {tx3} = {d_z}".format(
tx1=_("MEASURING"),
@@ -508,18 +411,18 @@ class Distance(AppTool):
d_z='%*f' % (self.decimals, abs(d)))
)
- self.distance_x_entry.set_value('%.*f' % (self.decimals, abs(dx)))
- self.distance_y_entry.set_value('%.*f' % (self.decimals, abs(dy)))
+ self.ui.distance_x_entry.set_value('%.*f' % (self.decimals, abs(dx)))
+ self.ui.distance_y_entry.set_value('%.*f' % (self.decimals, abs(dy)))
try:
angle = math.degrees(math.atan2(dy, dx))
if angle < 0:
angle += 360
- self.angle_entry.set_value('%.*f' % (self.decimals, angle))
+ self.ui.angle_entry.set_value('%.*f' % (self.decimals, angle))
except Exception:
pass
- self.total_distance_entry.set_value('%.*f' % (self.decimals, abs(d)))
+ self.ui.total_distance_entry.set_value('%.*f' % (self.decimals, abs(d)))
self.app.ui.rel_position_label.setText(
"Dx: {} Dy: {} ".format(
'%.*f' % (self.decimals, pos[0]), '%.*f' % (self.decimals, pos[1])
@@ -587,7 +490,7 @@ class Distance(AppTool):
angle = math.degrees(math.atan2(dy, dx))
if angle < 0:
angle += 360
- self.angle_entry.set_value('%.*f' % (self.decimals, angle))
+ self.ui.angle_entry.set_value('%.*f' % (self.decimals, angle))
except Exception as e:
log.debug("Distance.on_mouse_move_meas() -> update utility geometry -> %s" % str(e))
pass
@@ -635,4 +538,134 @@ class Distance(AppTool):
# def set_meas_units(self, units):
# self.meas.units_label.setText("[" + self.app.options["units"].lower() + "]")
-# end of file
+
+class DistUI:
+
+ toolName = _("Distance Tool")
+
+ def __init__(self, layout, app):
+ self.app = app
+ self.decimals = self.app.decimals
+ self.layout = layout
+
+ # ## Title
+ title_label = FCLabel("%s
" % self.toolName)
+ self.layout.addWidget(title_label)
+
+ # ## Form Layout
+ grid0 = QtWidgets.QGridLayout()
+ grid0.setColumnStretch(0, 0)
+ grid0.setColumnStretch(1, 1)
+ self.layout.addLayout(grid0)
+
+ self.units_label = FCLabel('%s:' % _("Units"))
+ self.units_label.setToolTip(_("Those are the units in which the distance is measured."))
+ self.units_value = FCLabel("%s" % str({'mm': _("METRIC (mm)"), 'in': _("INCH (in)")}[self.units]))
+ self.units_value.setDisabled(True)
+
+ grid0.addWidget(self.units_label, 0, 0)
+ grid0.addWidget(self.units_value, 0, 1)
+
+ self.snap_center_cb = FCCheckBox(_("Snap to center"))
+ self.snap_center_cb.setToolTip(
+ _("Mouse cursor will snap to the center of the pad/drill\n"
+ "when it is hovering over the geometry of the pad/drill.")
+ )
+ grid0.addWidget(self.snap_center_cb, 1, 0, 1, 2)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 2, 0, 1, 2)
+
+ self.start_label = FCLabel("%s:" % _('Start Coords'))
+ self.start_label.setToolTip(_("This is measuring Start point coordinates."))
+
+ self.start_entry = FCEntry()
+ self.start_entry.setReadOnly(True)
+ self.start_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
+ self.start_entry.setToolTip(_("This is measuring Start point coordinates."))
+
+ grid0.addWidget(self.start_label, 3, 0)
+ grid0.addWidget(self.start_entry, 3, 1)
+
+ self.stop_label = FCLabel("%s:" % _('Stop Coords'))
+ self.stop_label.setToolTip(_("This is the measuring Stop point coordinates."))
+
+ self.stop_entry = FCEntry()
+ self.stop_entry.setReadOnly(True)
+ self.stop_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
+ self.stop_entry.setToolTip(_("This is the measuring Stop point coordinates."))
+
+ grid0.addWidget(self.stop_label, 4, 0)
+ grid0.addWidget(self.stop_entry, 4, 1)
+
+ self.distance_x_label = FCLabel('%s:' % _("Dx"))
+ self.distance_x_label.setToolTip(_("This is the distance measured over the X axis."))
+
+ self.distance_x_entry = FCEntry()
+ self.distance_x_entry.setReadOnly(True)
+ self.distance_x_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
+ self.distance_x_entry.setToolTip(_("This is the distance measured over the X axis."))
+
+ grid0.addWidget(self.distance_x_label, 5, 0)
+ grid0.addWidget(self.distance_x_entry, 5, 1)
+
+ self.distance_y_label = FCLabel('%s:' % _("Dy"))
+ self.distance_y_label.setToolTip(_("This is the distance measured over the Y axis."))
+
+ self.distance_y_entry = FCEntry()
+ self.distance_y_entry.setReadOnly(True)
+ self.distance_y_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
+ self.distance_y_entry.setToolTip(_("This is the distance measured over the Y axis."))
+
+ grid0.addWidget(self.distance_y_label, 6, 0)
+ grid0.addWidget(self.distance_y_entry, 6, 1)
+
+ self.angle_label = FCLabel('%s:' % _("Angle"))
+ self.angle_label.setToolTip(_("This is orientation angle of the measuring line."))
+
+ self.angle_entry = FCEntry()
+ self.angle_entry.setReadOnly(True)
+ self.angle_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
+ self.angle_entry.setToolTip(_("This is orientation angle of the measuring line."))
+
+ grid0.addWidget(self.angle_label, 7, 0)
+ grid0.addWidget(self.angle_entry, 7, 1)
+
+ self.total_distance_label = FCLabel("%s:" % _('DISTANCE'))
+ self.total_distance_label.setToolTip(_("This is the point to point Euclidian distance."))
+
+ self.total_distance_entry = FCEntry()
+ self.total_distance_entry.setReadOnly(True)
+ self.total_distance_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
+ self.total_distance_entry.setToolTip(_("This is the point to point Euclidian distance."))
+
+ grid0.addWidget(self.total_distance_label, 8, 0)
+ grid0.addWidget(self.total_distance_entry, 8, 1)
+
+ self.measure_btn = FCButton(_("Measure"))
+ # self.measure_btn.setFixedWidth(70)
+ self.layout.addWidget(self.measure_btn)
+
+ self.layout.addStretch()
+
+ # #################################### 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/ToolDistanceMin.py b/appTools/ToolDistanceMin.py
index 3beaf244..b21725e5 100644
--- a/appTools/ToolDistanceMin.py
+++ b/appTools/ToolDistanceMin.py
@@ -28,8 +28,6 @@ log = logging.getLogger('base')
class DistanceMin(AppTool):
- toolName = _("Minimum Distance Tool")
-
def __init__(self, app):
AppTool.__init__(self, app)
@@ -38,7 +36,196 @@ class DistanceMin(AppTool):
self.units = self.app.defaults['units'].lower()
self.decimals = self.app.decimals
- # ## Title
+ # #############################################################################
+ # ######################### Tool GUI ##########################################
+ # #############################################################################
+ self.ui = DistMinUI(layout=self.layout, app=self.app)
+ self.toolName = self.ui.toolName
+
+ self.h_point = (0, 0)
+
+ self.ui.measure_btn.clicked.connect(self.activate_measure_tool)
+ self.ui.jump_hp_btn.clicked.connect(self.on_jump_to_half_point)
+
+ def run(self, toggle=False):
+ self.app.defaults.report_usage("ToolDistanceMin()")
+
+ if self.app.tool_tab_locked is True:
+ return
+
+ self.app.ui.notebook.setTabText(2, _("Minimum Distance Tool"))
+
+ # if the splitter is hidden, display it
+ if self.app.ui.splitter.sizes()[0] == 0:
+ self.app.ui.splitter.setSizes([1, 1])
+
+ if toggle:
+ pass
+
+ self.set_tool_ui()
+ self.app.inform.emit('MEASURING: %s' %
+ _("Select two objects and no more, to measure the distance between them ..."))
+
+ def install(self, icon=None, separator=None, **kwargs):
+ AppTool.install(self, icon, separator, shortcut='Shift+M', **kwargs)
+
+ def set_tool_ui(self):
+ # Remove anything else in the appGUI
+ self.app.ui.tool_scroll_area.takeWidget()
+
+ # Put oneself in the appGUI
+ self.app.ui.tool_scroll_area.setWidget(self)
+
+ # Switch notebook to tool page
+ self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
+
+ self.units = self.app.defaults['units'].lower()
+
+ # initial view of the layout
+ self.ui.start_entry.set_value('(0, 0)')
+ self.ui.stop_entry.set_value('(0, 0)')
+
+ self.ui.distance_x_entry.set_value('0.0')
+ self.ui.distance_y_entry.set_value('0.0')
+ self.ui.angle_entry.set_value('0.0')
+ self.ui.total_distance_entry.set_value('0.0')
+ self.ui.half_point_entry.set_value('(0, 0)')
+
+ self.ui.jump_hp_btn.setDisabled(True)
+
+ log.debug("Minimum Distance Tool --> tool initialized")
+
+ def activate_measure_tool(self):
+ # ENABLE the Measuring TOOL
+ self.ui.jump_hp_btn.setDisabled(False)
+
+ self.units = self.app.defaults['units'].lower()
+
+ if self.app.call_source == 'app':
+ selected_objs = self.app.collection.get_selected()
+ if len(selected_objs) != 2:
+ self.app.inform.emit('[WARNING_NOTCL] %s %s' %
+ (_("Select two objects and no more. Currently the selection has objects: "),
+ str(len(selected_objs))))
+ return
+ else:
+ if isinstance(selected_objs[0].solid_geometry, list):
+ try:
+ selected_objs[0].solid_geometry = MultiPolygon(selected_objs[0].solid_geometry)
+ except Exception:
+ selected_objs[0].solid_geometry = cascaded_union(selected_objs[0].solid_geometry)
+
+ try:
+ selected_objs[1].solid_geometry = MultiPolygon(selected_objs[1].solid_geometry)
+ except Exception:
+ selected_objs[1].solid_geometry = cascaded_union(selected_objs[1].solid_geometry)
+
+ first_pos, last_pos = nearest_points(selected_objs[0].solid_geometry, selected_objs[1].solid_geometry)
+
+ elif self.app.call_source == 'geo_editor':
+ selected_objs = self.app.geo_editor.selected
+ if len(selected_objs) != 2:
+ self.app.inform.emit('[WARNING_NOTCL] %s %s' %
+ (_("Select two objects and no more. Currently the selection has objects: "),
+ str(len(selected_objs))))
+ return
+ else:
+ first_pos, last_pos = nearest_points(selected_objs[0].geo, selected_objs[1].geo)
+ elif self.app.call_source == 'exc_editor':
+ selected_objs = self.app.exc_editor.selected
+ if len(selected_objs) != 2:
+ self.app.inform.emit('[WARNING_NOTCL] %s %s' %
+ (_("Select two objects and no more. Currently the selection has objects: "),
+ str(len(selected_objs))))
+ return
+ else:
+ # the objects are really MultiLinesStrings made out of 2 lines in cross shape
+ xmin, ymin, xmax, ymax = selected_objs[0].geo.bounds
+ first_geo_radius = (xmax - xmin) / 2
+ first_geo_center = Point(xmin + first_geo_radius, ymin + first_geo_radius)
+ first_geo = first_geo_center.buffer(first_geo_radius)
+
+ # the objects are really MultiLinesStrings made out of 2 lines in cross shape
+ xmin, ymin, xmax, ymax = selected_objs[1].geo.bounds
+ last_geo_radius = (xmax - xmin) / 2
+ last_geo_center = Point(xmin + last_geo_radius, ymin + last_geo_radius)
+ last_geo = last_geo_center.buffer(last_geo_radius)
+
+ first_pos, last_pos = nearest_points(first_geo, last_geo)
+ elif self.app.call_source == 'grb_editor':
+ selected_objs = self.app.grb_editor.selected
+ if len(selected_objs) != 2:
+ self.app.inform.emit('[WARNING_NOTCL] %s %s' %
+ (_("Select two objects and no more. Currently the selection has objects: "),
+ str(len(selected_objs))))
+ return
+ else:
+ first_pos, last_pos = nearest_points(selected_objs[0].geo['solid'], selected_objs[1].geo['solid'])
+ else:
+ first_pos, last_pos = 0, 0
+
+ self.ui.start_entry.set_value("(%.*f, %.*f)" % (self.decimals, first_pos.x, self.decimals, first_pos.y))
+ self.ui.stop_entry.set_value("(%.*f, %.*f)" % (self.decimals, last_pos.x, self.decimals, last_pos.y))
+
+ dx = first_pos.x - last_pos.x
+ dy = first_pos.y - last_pos.y
+
+ self.ui.distance_x_entry.set_value('%.*f' % (self.decimals, abs(dx)))
+ self.ui.distance_y_entry.set_value('%.*f' % (self.decimals, abs(dy)))
+
+ try:
+ angle = math.degrees(math.atan(dy / dx))
+ self.ui.angle_entry.set_value('%.*f' % (self.decimals, angle))
+ except Exception:
+ pass
+
+ d = math.sqrt(dx ** 2 + dy ** 2)
+ self.ui.total_distance_entry.set_value('%.*f' % (self.decimals, abs(d)))
+
+ self.h_point = (min(first_pos.x, last_pos.x) + (abs(dx) / 2), min(first_pos.y, last_pos.y) + (abs(dy) / 2))
+ if d != 0:
+ self.ui.half_point_entry.set_value(
+ "(%.*f, %.*f)" % (self.decimals, self.h_point[0], self.decimals, self.h_point[1])
+ )
+ else:
+ self.ui.half_point_entry.set_value(
+ "(%.*f, %.*f)" % (self.decimals, 0.0, self.decimals, 0.0)
+ )
+
+ if d != 0:
+ self.app.inform.emit("{tx1}: {tx2} D(x) = {d_x} | D(y) = {d_y} | {tx3} = {d_z}".format(
+ tx1=_("MEASURING"),
+ tx2=_("Result"),
+ tx3=_("Distance"),
+ d_x='%*f' % (self.decimals, abs(dx)),
+ d_y='%*f' % (self.decimals, abs(dy)),
+ d_z='%*f' % (self.decimals, abs(d)))
+ )
+ else:
+ self.app.inform.emit('[WARNING_NOTCL] %s: %s' %
+ (_("Objects intersects or touch at"),
+ "(%.*f, %.*f)" % (self.decimals, self.h_point[0], self.decimals, self.h_point[1])))
+
+ def on_jump_to_half_point(self):
+ self.app.on_jump_to(custom_location=self.h_point)
+ self.app.inform.emit('[success] %s: %s' %
+ (_("Jumped to the half point between the two selected objects"),
+ "(%.*f, %.*f)" % (self.decimals, self.h_point[0], self.decimals, self.h_point[1])))
+
+ # def set_meas_units(self, units):
+ # self.meas.units_label.setText("[" + self.app.options["units"].lower() + "]")
+
+
+class DistMinUI:
+
+ toolName = _("Minimum Distance Tool")
+
+ def __init__(self, layout, app):
+ self.app = app
+ self.decimals = self.app.decimals
+ self.layout = layout
+
+# ## Title
title_label = QtWidgets.QLabel("%s
" % self.toolName)
self.layout.addWidget(title_label)
@@ -57,7 +244,7 @@ class DistanceMin(AppTool):
self.stop_label = QtWidgets.QLabel("%s:" % _('Second object point'))
self.stop_label.setToolTip(_("This is second object point coordinates.\n"
- "This is the end point for measuring distance."))
+ "This is the end point for measuring distance."))
self.distance_x_label = QtWidgets.QLabel('%s:' % _("Dx"))
self.distance_x_label.setToolTip(_("This is the distance measured over the X axis."))
@@ -84,7 +271,7 @@ class DistanceMin(AppTool):
self.stop_entry.setReadOnly(True)
self.stop_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.stop_entry.setToolTip(_("This is second object point coordinates.\n"
- "This is the end point for measuring distance."))
+ "This is the end point for measuring distance."))
self.distance_x_entry = FCEntry()
self.distance_x_entry.setReadOnly(True)
@@ -128,178 +315,22 @@ class DistanceMin(AppTool):
form_layout.addRow(self.half_point_label, self.half_point_entry)
self.layout.addStretch()
+ # #################################### FINSIHED GUI ###########################
+ # #############################################################################
- self.h_point = (0, 0)
-
- self.measure_btn.clicked.connect(self.activate_measure_tool)
- self.jump_hp_btn.clicked.connect(self.on_jump_to_half_point)
-
- def run(self, toggle=False):
- self.app.defaults.report_usage("ToolDistanceMin()")
-
- if self.app.tool_tab_locked is True:
- return
-
- self.app.ui.notebook.setTabText(2, _("Minimum Distance Tool"))
-
- # if the splitter is hidden, display it
- if self.app.ui.splitter.sizes()[0] == 0:
- self.app.ui.splitter.setSizes([1, 1])
-
- if toggle:
- pass
-
- self.set_tool_ui()
- self.app.inform.emit('MEASURING: %s' %
- _("Select two objects and no more, to measure the distance between them ..."))
-
- def install(self, icon=None, separator=None, **kwargs):
- AppTool.install(self, icon, separator, shortcut='Shift+M', **kwargs)
-
- def set_tool_ui(self):
- # Remove anything else in the appGUI
- self.app.ui.tool_scroll_area.takeWidget()
-
- # Put oneself in the appGUI
- self.app.ui.tool_scroll_area.setWidget(self)
-
- # Switch notebook to tool page
- self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
-
- self.units = self.app.defaults['units'].lower()
-
- # initial view of the layout
- self.start_entry.set_value('(0, 0)')
- self.stop_entry.set_value('(0, 0)')
-
- self.distance_x_entry.set_value('0.0')
- self.distance_y_entry.set_value('0.0')
- self.angle_entry.set_value('0.0')
- self.total_distance_entry.set_value('0.0')
- self.half_point_entry.set_value('(0, 0)')
-
- self.jump_hp_btn.setDisabled(True)
-
- log.debug("Minimum Distance Tool --> tool initialized")
-
- def activate_measure_tool(self):
- # ENABLE the Measuring TOOL
- self.jump_hp_btn.setDisabled(False)
-
- self.units = self.app.defaults['units'].lower()
-
- if self.app.call_source == 'app':
- selected_objs = self.app.collection.get_selected()
- if len(selected_objs) != 2:
- self.app.inform.emit('[WARNING_NOTCL] %s %s' %
- (_("Select two objects and no more. Currently the selection has objects: "),
- str(len(selected_objs))))
- return
- else:
- if isinstance(selected_objs[0].solid_geometry, list):
- try:
- selected_objs[0].solid_geometry = MultiPolygon(selected_objs[0].solid_geometry)
- except Exception:
- selected_objs[0].solid_geometry = cascaded_union(selected_objs[0].solid_geometry)
-
- try:
- selected_objs[1].solid_geometry = MultiPolygon(selected_objs[1].solid_geometry)
- except Exception:
- selected_objs[1].solid_geometry = cascaded_union(selected_objs[1].solid_geometry)
-
- first_pos, last_pos = nearest_points(selected_objs[0].solid_geometry, selected_objs[1].solid_geometry)
-
- elif self.app.call_source == 'geo_editor':
- selected_objs = self.app.geo_editor.selected
- if len(selected_objs) != 2:
- self.app.inform.emit('[WARNING_NOTCL] %s %s' %
- (_("Select two objects and no more. Currently the selection has objects: "),
- str(len(selected_objs))))
- return
- else:
- first_pos, last_pos = nearest_points(selected_objs[0].geo, selected_objs[1].geo)
- elif self.app.call_source == 'exc_editor':
- selected_objs = self.app.exc_editor.selected
- if len(selected_objs) != 2:
- self.app.inform.emit('[WARNING_NOTCL] %s %s' %
- (_("Select two objects and no more. Currently the selection has objects: "),
- str(len(selected_objs))))
- return
- else:
- # the objects are really MultiLinesStrings made out of 2 lines in cross shape
- xmin, ymin, xmax, ymax = selected_objs[0].geo.bounds
- first_geo_radius = (xmax - xmin) / 2
- first_geo_center = Point(xmin + first_geo_radius, ymin + first_geo_radius)
- first_geo = first_geo_center.buffer(first_geo_radius)
-
- # the objects are really MultiLinesStrings made out of 2 lines in cross shape
- xmin, ymin, xmax, ymax = selected_objs[1].geo.bounds
- last_geo_radius = (xmax - xmin) / 2
- last_geo_center = Point(xmin + last_geo_radius, ymin + last_geo_radius)
- last_geo = last_geo_center.buffer(last_geo_radius)
-
- first_pos, last_pos = nearest_points(first_geo, last_geo)
- elif self.app.call_source == 'grb_editor':
- selected_objs = self.app.grb_editor.selected
- if len(selected_objs) != 2:
- self.app.inform.emit('[WARNING_NOTCL] %s %s' %
- (_("Select two objects and no more. Currently the selection has objects: "),
- str(len(selected_objs))))
- return
- else:
- first_pos, last_pos = nearest_points(selected_objs[0].geo['solid'], selected_objs[1].geo['solid'])
+ 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:
- first_pos, last_pos = 0, 0
+ self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
- self.start_entry.set_value("(%.*f, %.*f)" % (self.decimals, first_pos.x, self.decimals, first_pos.y))
- self.stop_entry.set_value("(%.*f, %.*f)" % (self.decimals, last_pos.x, self.decimals, last_pos.y))
-
- dx = first_pos.x - last_pos.x
- dy = first_pos.y - last_pos.y
-
- self.distance_x_entry.set_value('%.*f' % (self.decimals, abs(dx)))
- self.distance_y_entry.set_value('%.*f' % (self.decimals, abs(dy)))
-
- try:
- angle = math.degrees(math.atan(dy / dx))
- self.angle_entry.set_value('%.*f' % (self.decimals, angle))
- except Exception as e:
- pass
-
- d = math.sqrt(dx ** 2 + dy ** 2)
- self.total_distance_entry.set_value('%.*f' % (self.decimals, abs(d)))
-
- self.h_point = (min(first_pos.x, last_pos.x) + (abs(dx) / 2), min(first_pos.y, last_pos.y) + (abs(dy) / 2))
- if d != 0:
- self.half_point_entry.set_value(
- "(%.*f, %.*f)" % (self.decimals, self.h_point[0], self.decimals, self.h_point[1])
- )
+ 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.half_point_entry.set_value(
- "(%.*f, %.*f)" % (self.decimals, 0.0, self.decimals, 0.0)
- )
-
- if d != 0:
- self.app.inform.emit("{tx1}: {tx2} D(x) = {d_x} | D(y) = {d_y} | {tx3} = {d_z}".format(
- tx1=_("MEASURING"),
- tx2=_("Result"),
- tx3=_("Distance"),
- d_x='%*f' % (self.decimals, abs(dx)),
- d_y='%*f' % (self.decimals, abs(dy)),
- d_z='%*f' % (self.decimals, abs(d)))
- )
- else:
- self.app.inform.emit('[WARNING_NOTCL] %s: %s' %
- (_("Objects intersects or touch at"),
- "(%.*f, %.*f)" % (self.decimals, self.h_point[0], self.decimals, self.h_point[1])))
-
- def on_jump_to_half_point(self):
- self.app.on_jump_to(custom_location=self.h_point)
- self.app.inform.emit('[success] %s: %s' %
- (_("Jumped to the half point between the two selected objects"),
- "(%.*f, %.*f)" % (self.decimals, self.h_point[0], self.decimals, self.h_point[1])))
-
- def set_meas_units(self, units):
- self.meas.units_label.setText("[" + self.app.options["units"].lower() + "]")
-
-# end of file
+ self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
diff --git a/appTools/ToolRulesCheck.py b/appTools/ToolRulesCheck.py
index c43eb033..ff105265 100644
--- a/appTools/ToolRulesCheck.py
+++ b/appTools/ToolRulesCheck.py
@@ -8,7 +8,7 @@
from PyQt5 import QtWidgets, QtGui
from appTool import AppTool
-from appGUI.GUIElements import FCDoubleSpinner, FCCheckBox, OptionalInputSection, FCComboBox
+from appGUI.GUIElements import FCDoubleSpinner, FCCheckBox, OptionalInputSection, FCComboBox, FCLabel, FCButton
from copy import deepcopy
from appPool import *
@@ -30,8 +30,6 @@ log = logging.getLogger('base')
class RulesCheck(AppTool):
- toolName = _("Check Rules")
-
tool_finished = QtCore.pyqtSignal(list)
def __init__(self, app):
@@ -39,517 +37,37 @@ class RulesCheck(AppTool):
AppTool.__init__(self, app)
- # ## 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
- self.grid_layout = QtWidgets.QGridLayout()
- self.layout.addLayout(self.grid_layout)
-
- self.grid_layout.setColumnStretch(0, 0)
- self.grid_layout.setColumnStretch(1, 3)
- self.grid_layout.setColumnStretch(2, 0)
-
- self.gerber_title_lbl = QtWidgets.QLabel('%s:' % _("GERBER"))
- self.gerber_title_lbl.setToolTip(
- _("Gerber objects for which to check rules.")
- )
-
- self.all_obj_cb = FCCheckBox()
-
- self.grid_layout.addWidget(self.gerber_title_lbl, 0, 0, 1, 2)
- self.grid_layout.addWidget(self.all_obj_cb, 0, 2)
-
- # Copper Top object
- self.copper_t_object = FCComboBox()
- self.copper_t_object.setModel(self.app.collection)
- self.copper_t_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.copper_t_object.is_last = True
- self.copper_t_object.obj_type = "Gerber"
-
- self.copper_t_object_lbl = QtWidgets.QLabel('%s:' % _("Top"))
- self.copper_t_object_lbl.setToolTip(
- _("The Top Gerber Copper object for which rules are checked.")
- )
-
- self.copper_t_cb = FCCheckBox()
-
- self.grid_layout.addWidget(self.copper_t_object_lbl, 1, 0)
- self.grid_layout.addWidget(self.copper_t_object, 1, 1)
- self.grid_layout.addWidget(self.copper_t_cb, 1, 2)
-
- # Copper Bottom object
- self.copper_b_object = FCComboBox()
- self.copper_b_object.setModel(self.app.collection)
- self.copper_b_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.copper_b_object.is_last = True
- self.copper_b_object.obj_type = "Gerber"
-
- self.copper_b_object_lbl = QtWidgets.QLabel('%s:' % _("Bottom"))
- self.copper_b_object_lbl.setToolTip(
- _("The Bottom Gerber Copper object for which rules are checked.")
- )
-
- self.copper_b_cb = FCCheckBox()
-
- self.grid_layout.addWidget(self.copper_b_object_lbl, 2, 0)
- self.grid_layout.addWidget(self.copper_b_object, 2, 1)
- self.grid_layout.addWidget(self.copper_b_cb, 2, 2)
-
- # SolderMask Top object
- self.sm_t_object = FCComboBox()
- self.sm_t_object.setModel(self.app.collection)
- self.sm_t_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.sm_t_object.is_last = True
- self.sm_t_object.obj_type = "Gerber"
-
- self.sm_t_object_lbl = QtWidgets.QLabel('%s:' % _("SM Top"))
- self.sm_t_object_lbl.setToolTip(
- _("The Top Gerber Solder Mask object for which rules are checked.")
- )
-
- self.sm_t_cb = FCCheckBox()
-
- self.grid_layout.addWidget(self.sm_t_object_lbl, 3, 0)
- self.grid_layout.addWidget(self.sm_t_object, 3, 1)
- self.grid_layout.addWidget(self.sm_t_cb, 3, 2)
-
- # SolderMask Bottom object
- self.sm_b_object = FCComboBox()
- self.sm_b_object.setModel(self.app.collection)
- self.sm_b_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.sm_b_object.is_last = True
- self.sm_b_object.obj_type = "Gerber"
-
- self.sm_b_object_lbl = QtWidgets.QLabel('%s:' % _("SM Bottom"))
- self.sm_b_object_lbl.setToolTip(
- _("The Bottom Gerber Solder Mask object for which rules are checked.")
- )
-
- self.sm_b_cb = FCCheckBox()
-
- self.grid_layout.addWidget(self.sm_b_object_lbl, 4, 0)
- self.grid_layout.addWidget(self.sm_b_object, 4, 1)
- self.grid_layout.addWidget(self.sm_b_cb, 4, 2)
-
- # SilkScreen Top object
- self.ss_t_object = FCComboBox()
- self.ss_t_object.setModel(self.app.collection)
- self.ss_t_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.ss_t_object.is_last = True
- self.ss_t_object.obj_type = "Gerber"
-
- self.ss_t_object_lbl = QtWidgets.QLabel('%s:' % _("Silk Top"))
- self.ss_t_object_lbl.setToolTip(
- _("The Top Gerber Silkscreen object for which rules are checked.")
- )
-
- self.ss_t_cb = FCCheckBox()
-
- self.grid_layout.addWidget(self.ss_t_object_lbl, 5, 0)
- self.grid_layout.addWidget(self.ss_t_object, 5, 1)
- self.grid_layout.addWidget(self.ss_t_cb, 5, 2)
-
- # SilkScreen Bottom object
- self.ss_b_object = FCComboBox()
- self.ss_b_object.setModel(self.app.collection)
- self.ss_b_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.ss_b_object.is_last = True
- self.ss_b_object.obj_type = "Gerber"
-
- self.ss_b_object_lbl = QtWidgets.QLabel('%s:' % _("Silk Bottom"))
- self.ss_b_object_lbl.setToolTip(
- _("The Bottom Gerber Silkscreen object for which rules are checked.")
- )
-
- self.ss_b_cb = FCCheckBox()
-
- self.grid_layout.addWidget(self.ss_b_object_lbl, 6, 0)
- self.grid_layout.addWidget(self.ss_b_object, 6, 1)
- self.grid_layout.addWidget(self.ss_b_cb, 6, 2)
-
- # Outline object
- self.outline_object = FCComboBox()
- self.outline_object.setModel(self.app.collection)
- self.outline_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.outline_object.is_last = True
- self.outline_object.obj_type = "Gerber"
-
- self.outline_object_lbl = QtWidgets.QLabel('%s:' % _("Outline"))
- self.outline_object_lbl.setToolTip(
- _("The Gerber Outline (Cutout) object for which rules are checked.")
- )
-
- self.out_cb = FCCheckBox()
-
- self.grid_layout.addWidget(self.outline_object_lbl, 7, 0)
- self.grid_layout.addWidget(self.outline_object, 7, 1)
- self.grid_layout.addWidget(self.out_cb, 7, 2)
-
- self.grid_layout.addWidget(QtWidgets.QLabel(""), 8, 0, 1, 3)
-
- self.excellon_title_lbl = QtWidgets.QLabel('%s:' % _("EXCELLON"))
- self.excellon_title_lbl.setToolTip(
- _("Excellon objects for which to check rules.")
- )
-
- self.grid_layout.addWidget(self.excellon_title_lbl, 9, 0, 1, 3)
-
- # Excellon 1 object
- self.e1_object = FCComboBox()
- self.e1_object.setModel(self.app.collection)
- self.e1_object.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
- self.e1_object.is_last = True
- self.e1_object.obj_type = "Excellon"
-
- self.e1_object_lbl = QtWidgets.QLabel('%s:' % _("Excellon 1"))
- self.e1_object_lbl.setToolTip(
- _("Excellon object for which to check rules.\n"
- "Holds the plated holes or a general Excellon file content.")
- )
-
- self.e1_cb = FCCheckBox()
-
- self.grid_layout.addWidget(self.e1_object_lbl, 10, 0)
- self.grid_layout.addWidget(self.e1_object, 10, 1)
- self.grid_layout.addWidget(self.e1_cb, 10, 2)
-
- # Excellon 2 object
- self.e2_object = FCComboBox()
- self.e2_object.setModel(self.app.collection)
- self.e2_object.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
- self.e2_object.is_last = True
- self.e2_object.obj_type = "Excellon"
-
- self.e2_object_lbl = QtWidgets.QLabel('%s:' % _("Excellon 2"))
- self.e2_object_lbl.setToolTip(
- _("Excellon object for which to check rules.\n"
- "Holds the non-plated holes.")
- )
-
- self.e2_cb = FCCheckBox()
-
- self.grid_layout.addWidget(self.e2_object_lbl, 11, 0)
- self.grid_layout.addWidget(self.e2_object, 11, 1)
- self.grid_layout.addWidget(self.e2_cb, 11, 2)
-
- self.grid_layout.addWidget(QtWidgets.QLabel(""), 12, 0, 1, 3)
-
- # Control All
- self.all_cb = FCCheckBox('%s' % _("All Rules"))
- self.all_cb.setToolTip(
- _("This check/uncheck all the rules below.")
- )
- self.all_cb.setStyleSheet(
- """
- QCheckBox {font-weight: bold; color: green}
- """
- )
- self.layout.addWidget(self.all_cb)
-
- # Form Layout
- self.form_layout_1 = QtWidgets.QFormLayout()
- self.layout.addLayout(self.form_layout_1)
-
- self.form_layout_1.addRow(QtWidgets.QLabel(""))
-
- # Trace size
- self.trace_size_cb = FCCheckBox('%s:' % _("Trace Size"))
- self.trace_size_cb.setToolTip(
- _("This checks if the minimum size for traces is met.")
- )
- self.form_layout_1.addRow(self.trace_size_cb)
-
- # Trace size value
- self.trace_size_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.trace_size_entry.set_range(0.00001, 999.99999)
- self.trace_size_entry.set_precision(self.decimals)
- self.trace_size_entry.setSingleStep(0.1)
-
- self.trace_size_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
- self.trace_size_lbl.setToolTip(
- _("Minimum acceptable trace size.")
- )
- self.form_layout_1.addRow(self.trace_size_lbl, self.trace_size_entry)
-
- self.ts = OptionalInputSection(self.trace_size_cb, [self.trace_size_lbl, self.trace_size_entry])
-
- # Copper2copper clearance
- self.clearance_copper2copper_cb = FCCheckBox('%s:' % _("Copper to Copper clearance"))
- self.clearance_copper2copper_cb.setToolTip(
- _("This checks if the minimum clearance between copper\n"
- "features is met.")
- )
- self.form_layout_1.addRow(self.clearance_copper2copper_cb)
-
- # Copper2copper clearance value
- self.clearance_copper2copper_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.clearance_copper2copper_entry.set_range(0.00001, 999.99999)
- self.clearance_copper2copper_entry.set_precision(self.decimals)
- self.clearance_copper2copper_entry.setSingleStep(0.1)
-
- self.clearance_copper2copper_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
- self.clearance_copper2copper_lbl.setToolTip(
- _("Minimum acceptable clearance value.")
- )
- self.form_layout_1.addRow(self.clearance_copper2copper_lbl, self.clearance_copper2copper_entry)
-
- self.c2c = OptionalInputSection(
- self.clearance_copper2copper_cb, [self.clearance_copper2copper_lbl, self.clearance_copper2copper_entry])
-
- # Copper2outline clearance
- self.clearance_copper2ol_cb = FCCheckBox('%s:' % _("Copper to Outline clearance"))
- self.clearance_copper2ol_cb.setToolTip(
- _("This checks if the minimum clearance between copper\n"
- "features and the outline is met.")
- )
- self.form_layout_1.addRow(self.clearance_copper2ol_cb)
-
- # Copper2outline clearance value
- self.clearance_copper2ol_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.clearance_copper2ol_entry.set_range(0.00001, 999.99999)
- self.clearance_copper2ol_entry.set_precision(self.decimals)
- self.clearance_copper2ol_entry.setSingleStep(0.1)
-
- self.clearance_copper2ol_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
- self.clearance_copper2ol_lbl.setToolTip(
- _("Minimum acceptable clearance value.")
- )
- self.form_layout_1.addRow(self.clearance_copper2ol_lbl, self.clearance_copper2ol_entry)
-
- self.c2ol = OptionalInputSection(
- self.clearance_copper2ol_cb, [self.clearance_copper2ol_lbl, self.clearance_copper2ol_entry])
-
- # Silkscreen2silkscreen clearance
- self.clearance_silk2silk_cb = FCCheckBox('%s:' % _("Silk to Silk Clearance"))
- self.clearance_silk2silk_cb.setToolTip(
- _("This checks if the minimum clearance between silkscreen\n"
- "features and silkscreen features is met.")
- )
- self.form_layout_1.addRow(self.clearance_silk2silk_cb)
-
- # Copper2silkscreen clearance value
- self.clearance_silk2silk_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.clearance_silk2silk_entry.set_range(0.00001, 999.99999)
- self.clearance_silk2silk_entry.set_precision(self.decimals)
- self.clearance_silk2silk_entry.setSingleStep(0.1)
-
- self.clearance_silk2silk_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
- self.clearance_silk2silk_lbl.setToolTip(
- _("Minimum acceptable clearance value.")
- )
- self.form_layout_1.addRow(self.clearance_silk2silk_lbl, self.clearance_silk2silk_entry)
-
- self.s2s = OptionalInputSection(
- self.clearance_silk2silk_cb, [self.clearance_silk2silk_lbl, self.clearance_silk2silk_entry])
-
- # Silkscreen2soldermask clearance
- self.clearance_silk2sm_cb = FCCheckBox('%s:' % _("Silk to Solder Mask Clearance"))
- self.clearance_silk2sm_cb.setToolTip(
- _("This checks if the minimum clearance between silkscreen\n"
- "features and soldermask features is met.")
- )
- self.form_layout_1.addRow(self.clearance_silk2sm_cb)
-
- # Silkscreen2soldermask clearance value
- self.clearance_silk2sm_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.clearance_silk2sm_entry.set_range(0.00001, 999.99999)
- self.clearance_silk2sm_entry.set_precision(self.decimals)
- self.clearance_silk2sm_entry.setSingleStep(0.1)
-
- self.clearance_silk2sm_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
- self.clearance_silk2sm_lbl.setToolTip(
- _("Minimum acceptable clearance value.")
- )
- self.form_layout_1.addRow(self.clearance_silk2sm_lbl, self.clearance_silk2sm_entry)
-
- self.s2sm = OptionalInputSection(
- self.clearance_silk2sm_cb, [self.clearance_silk2sm_lbl, self.clearance_silk2sm_entry])
-
- # Silk2outline clearance
- self.clearance_silk2ol_cb = FCCheckBox('%s:' % _("Silk to Outline Clearance"))
- self.clearance_silk2ol_cb.setToolTip(
- _("This checks if the minimum clearance between silk\n"
- "features and the outline is met.")
- )
- self.form_layout_1.addRow(self.clearance_silk2ol_cb)
-
- # Silk2outline clearance value
- self.clearance_silk2ol_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.clearance_silk2ol_entry.set_range(0.00001, 999.99999)
- self.clearance_silk2ol_entry.set_precision(self.decimals)
- self.clearance_silk2ol_entry.setSingleStep(0.1)
-
- self.clearance_silk2ol_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
- self.clearance_silk2ol_lbl.setToolTip(
- _("Minimum acceptable clearance value.")
- )
- self.form_layout_1.addRow(self.clearance_silk2ol_lbl, self.clearance_silk2ol_entry)
-
- self.s2ol = OptionalInputSection(
- self.clearance_silk2ol_cb, [self.clearance_silk2ol_lbl, self.clearance_silk2ol_entry])
-
- # Soldermask2soldermask clearance
- self.clearance_sm2sm_cb = FCCheckBox('%s:' % _("Minimum Solder Mask Sliver"))
- self.clearance_sm2sm_cb.setToolTip(
- _("This checks if the minimum clearance between soldermask\n"
- "features and soldermask features is met.")
- )
- self.form_layout_1.addRow(self.clearance_sm2sm_cb)
-
- # Soldermask2soldermask clearance value
- self.clearance_sm2sm_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.clearance_sm2sm_entry.set_range(0.00001, 999.99999)
- self.clearance_sm2sm_entry.set_precision(self.decimals)
- self.clearance_sm2sm_entry.setSingleStep(0.1)
-
- self.clearance_sm2sm_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
- self.clearance_sm2sm_lbl.setToolTip(
- _("Minimum acceptable clearance value.")
- )
- self.form_layout_1.addRow(self.clearance_sm2sm_lbl, self.clearance_sm2sm_entry)
-
- self.sm2sm = OptionalInputSection(
- self.clearance_sm2sm_cb, [self.clearance_sm2sm_lbl, self.clearance_sm2sm_entry])
-
- # Ring integrity check
- self.ring_integrity_cb = FCCheckBox('%s:' % _("Minimum Annular Ring"))
- self.ring_integrity_cb.setToolTip(
- _("This checks if the minimum copper ring left by drilling\n"
- "a hole into a pad is met.")
- )
- self.form_layout_1.addRow(self.ring_integrity_cb)
-
- # Ring integrity value
- self.ring_integrity_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.ring_integrity_entry.set_range(0.00001, 999.99999)
- self.ring_integrity_entry.set_precision(self.decimals)
- self.ring_integrity_entry.setSingleStep(0.1)
-
- self.ring_integrity_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
- self.ring_integrity_lbl.setToolTip(
- _("Minimum acceptable ring value.")
- )
- self.form_layout_1.addRow(self.ring_integrity_lbl, self.ring_integrity_entry)
-
- self.anr = OptionalInputSection(
- self.ring_integrity_cb, [self.ring_integrity_lbl, self.ring_integrity_entry])
-
- self.form_layout_1.addRow(QtWidgets.QLabel(""))
-
- # Hole2Hole clearance
- self.clearance_d2d_cb = FCCheckBox('%s:' % _("Hole to Hole Clearance"))
- self.clearance_d2d_cb.setToolTip(
- _("This checks if the minimum clearance between a drill hole\n"
- "and another drill hole is met.")
- )
- self.form_layout_1.addRow(self.clearance_d2d_cb)
-
- # Hole2Hole clearance value
- self.clearance_d2d_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.clearance_d2d_entry.set_range(0.00001, 999.99999)
- self.clearance_d2d_entry.set_precision(self.decimals)
- self.clearance_d2d_entry.setSingleStep(0.1)
-
- self.clearance_d2d_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
- self.clearance_d2d_lbl.setToolTip(
- _("Minimum acceptable clearance value.")
- )
- self.form_layout_1.addRow(self.clearance_d2d_lbl, self.clearance_d2d_entry)
-
- self.d2d = OptionalInputSection(
- self.clearance_d2d_cb, [self.clearance_d2d_lbl, self.clearance_d2d_entry])
-
- # Drill holes size check
- self.drill_size_cb = FCCheckBox('%s:' % _("Hole Size"))
- self.drill_size_cb.setToolTip(
- _("This checks if the drill holes\n"
- "sizes are above the threshold.")
- )
- self.form_layout_1.addRow(self.drill_size_cb)
-
- # Drile holes value
- self.drill_size_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.drill_size_entry.set_range(0.00001, 999.99999)
- self.drill_size_entry.set_precision(self.decimals)
- self.drill_size_entry.setSingleStep(0.1)
-
- self.drill_size_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
- self.drill_size_lbl.setToolTip(
- _("Minimum acceptable drill size.")
- )
- self.form_layout_1.addRow(self.drill_size_lbl, self.drill_size_entry)
-
- self.ds = OptionalInputSection(
- self.drill_size_cb, [self.drill_size_lbl, self.drill_size_entry])
-
- # Buttons
- hlay_2 = QtWidgets.QHBoxLayout()
- self.layout.addLayout(hlay_2)
-
- # hlay_2.addStretch()
- self.run_button = QtWidgets.QPushButton(_("Run Rules Check"))
- self.run_button.setToolTip(
- _("Panelize the specified object around the specified box.\n"
- "In other words it creates multiple copies of the source object,\n"
- "arranged in a 2D array of rows and columns.")
- )
- self.run_button.setStyleSheet("""
- QPushButton
- {
- font-weight: bold;
- }
- """)
- hlay_2.addWidget(self.run_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)
+ # #############################################################################
+ # ######################### Tool GUI ##########################################
+ # #############################################################################
+ self.ui = RulesUI(layout=self.layout, app=self.app)
+ self.toolName = self.ui.toolName
# #######################################################
# ################ SIGNALS ##############################
# #######################################################
- self.copper_t_cb.stateChanged.connect(lambda st: self.copper_t_object.setDisabled(not st))
- self.copper_b_cb.stateChanged.connect(lambda st: self.copper_b_object.setDisabled(not st))
+ self.ui.copper_t_cb.stateChanged.connect(lambda st: self.ui.copper_t_object.setDisabled(not st))
+ self.ui.copper_b_cb.stateChanged.connect(lambda st: self.ui.copper_b_object.setDisabled(not st))
- self.sm_t_cb.stateChanged.connect(lambda st: self.sm_t_object.setDisabled(not st))
- self.sm_b_cb.stateChanged.connect(lambda st: self.sm_b_object.setDisabled(not st))
+ self.ui.sm_t_cb.stateChanged.connect(lambda st: self.ui.sm_t_object.setDisabled(not st))
+ self.ui.sm_b_cb.stateChanged.connect(lambda st: self.ui.sm_b_object.setDisabled(not st))
- self.ss_t_cb.stateChanged.connect(lambda st: self.ss_t_object.setDisabled(not st))
- self.ss_b_cb.stateChanged.connect(lambda st: self.ss_b_object.setDisabled(not st))
+ self.ui.ss_t_cb.stateChanged.connect(lambda st: self.ui.ss_t_object.setDisabled(not st))
+ self.ui.ss_b_cb.stateChanged.connect(lambda st: self.ui.ss_b_object.setDisabled(not st))
- self.out_cb.stateChanged.connect(lambda st: self.outline_object.setDisabled(not st))
+ self.ui.out_cb.stateChanged.connect(lambda st: self.ui.outline_object.setDisabled(not st))
- self.e1_cb.stateChanged.connect(lambda st: self.e1_object.setDisabled(not st))
- self.e2_cb.stateChanged.connect(lambda st: self.e2_object.setDisabled(not st))
+ self.ui.e1_cb.stateChanged.connect(lambda st: self.ui.e1_object.setDisabled(not st))
+ self.ui.e2_cb.stateChanged.connect(lambda st: self.ui.e2_object.setDisabled(not st))
- self.all_obj_cb.stateChanged.connect(self.on_all_objects_cb_changed)
- self.all_cb.stateChanged.connect(self.on_all_cb_changed)
- self.run_button.clicked.connect(self.execute)
- # self.app.collection.rowsInserted.connect(self.on_object_loaded)
+ self.ui.all_obj_cb.stateChanged.connect(self.ui.on_all_objects_cb_changed)
+ self.ui.all_cb.stateChanged.connect(self.ui.on_all_cb_changed)
+ self.ui.run_button.clicked.connect(self.execute)
+ self.ui.reset_button.clicked.connect(self.set_tool_ui)
+
+ # Custom Signals
self.tool_finished.connect(self.on_tool_finished)
- self.reset_button.clicked.connect(self.set_tool_ui)
# list to hold the temporary objects
self.objs = []
@@ -569,26 +87,6 @@ class RulesCheck(AppTool):
# def on_object_loaded(self, index, row):
# print(index.internalPointer().child_items[row].obj.options['name'], index.data())
- def on_all_cb_changed(self, state):
- cb_items = [self.form_layout_1.itemAt(i).widget() for i in range(self.form_layout_1.count())
- if isinstance(self.form_layout_1.itemAt(i).widget(), FCCheckBox)]
-
- for cb in cb_items:
- if state:
- cb.setChecked(True)
- else:
- cb.setChecked(False)
-
- def on_all_objects_cb_changed(self, state):
- cb_items = [self.grid_layout.itemAt(i).widget() for i in range(self.grid_layout.count())
- if isinstance(self.grid_layout.itemAt(i).widget(), FCCheckBox)]
-
- for cb in cb_items:
- if state:
- cb.setChecked(True)
- else:
- cb.setChecked(False)
-
def run(self, toggle=True):
self.app.defaults.report_usage("ToolRulesCheck()")
@@ -622,40 +120,40 @@ class RulesCheck(AppTool):
def set_tool_ui(self):
# all object combobox default as disabled
- self.copper_t_object.setDisabled(True)
- self.copper_b_object.setDisabled(True)
+ self.ui.copper_t_object.setDisabled(True)
+ self.ui.copper_b_object.setDisabled(True)
- self.sm_t_object.setDisabled(True)
- self.sm_b_object.setDisabled(True)
+ self.ui.sm_t_object.setDisabled(True)
+ self.ui.sm_b_object.setDisabled(True)
- self.ss_t_object.setDisabled(True)
- self.ss_b_object.setDisabled(True)
+ self.ui.ss_t_object.setDisabled(True)
+ self.ui.ss_b_object.setDisabled(True)
- self.outline_object.setDisabled(True)
+ self.ui.outline_object.setDisabled(True)
- self.e1_object.setDisabled(True)
- self.e2_object.setDisabled(True)
+ self.ui.e1_object.setDisabled(True)
+ self.ui.e2_object.setDisabled(True)
- self.trace_size_cb.set_value(self.app.defaults["tools_cr_trace_size"])
- self.trace_size_entry.set_value(float(self.app.defaults["tools_cr_trace_size_val"]))
- self.clearance_copper2copper_cb.set_value(self.app.defaults["tools_cr_c2c"])
- self.clearance_copper2copper_entry.set_value(float(self.app.defaults["tools_cr_c2c_val"]))
- self.clearance_copper2ol_cb.set_value(self.app.defaults["tools_cr_c2o"])
- self.clearance_copper2ol_entry.set_value(float(self.app.defaults["tools_cr_c2o_val"]))
- self.clearance_silk2silk_cb.set_value(self.app.defaults["tools_cr_s2s"])
- self.clearance_silk2silk_entry.set_value(float(self.app.defaults["tools_cr_s2s_val"]))
- self.clearance_silk2sm_cb.set_value(self.app.defaults["tools_cr_s2sm"])
- self.clearance_silk2sm_entry.set_value(float(self.app.defaults["tools_cr_s2sm_val"]))
- self.clearance_silk2ol_cb.set_value(self.app.defaults["tools_cr_s2o"])
- self.clearance_silk2ol_entry.set_value(float(self.app.defaults["tools_cr_s2o_val"]))
- self.clearance_sm2sm_cb.set_value(self.app.defaults["tools_cr_sm2sm"])
- self.clearance_sm2sm_entry.set_value(float(self.app.defaults["tools_cr_sm2sm_val"]))
- self.ring_integrity_cb.set_value(self.app.defaults["tools_cr_ri"])
- self.ring_integrity_entry.set_value(float(self.app.defaults["tools_cr_ri_val"]))
- self.clearance_d2d_cb.set_value(self.app.defaults["tools_cr_h2h"])
- self.clearance_d2d_entry.set_value(float(self.app.defaults["tools_cr_h2h_val"]))
- self.drill_size_cb.set_value(self.app.defaults["tools_cr_dh"])
- self.drill_size_entry.set_value(float(self.app.defaults["tools_cr_dh_val"]))
+ self.ui.trace_size_cb.set_value(self.app.defaults["tools_cr_trace_size"])
+ self.ui.trace_size_entry.set_value(float(self.app.defaults["tools_cr_trace_size_val"]))
+ self.ui.clearance_copper2copper_cb.set_value(self.app.defaults["tools_cr_c2c"])
+ self.ui.clearance_copper2copper_entry.set_value(float(self.app.defaults["tools_cr_c2c_val"]))
+ self.ui.clearance_copper2ol_cb.set_value(self.app.defaults["tools_cr_c2o"])
+ self.ui.clearance_copper2ol_entry.set_value(float(self.app.defaults["tools_cr_c2o_val"]))
+ self.ui.clearance_silk2silk_cb.set_value(self.app.defaults["tools_cr_s2s"])
+ self.ui.clearance_silk2silk_entry.set_value(float(self.app.defaults["tools_cr_s2s_val"]))
+ self.ui.clearance_silk2sm_cb.set_value(self.app.defaults["tools_cr_s2sm"])
+ self.ui.clearance_silk2sm_entry.set_value(float(self.app.defaults["tools_cr_s2sm_val"]))
+ self.ui.clearance_silk2ol_cb.set_value(self.app.defaults["tools_cr_s2o"])
+ self.ui.clearance_silk2ol_entry.set_value(float(self.app.defaults["tools_cr_s2o_val"]))
+ self.ui.clearance_sm2sm_cb.set_value(self.app.defaults["tools_cr_sm2sm"])
+ self.ui.clearance_sm2sm_entry.set_value(float(self.app.defaults["tools_cr_sm2sm_val"]))
+ self.ui.ring_integrity_cb.set_value(self.app.defaults["tools_cr_ri"])
+ self.ui.ring_integrity_entry.set_value(float(self.app.defaults["tools_cr_ri_val"]))
+ self.ui.clearance_d2d_cb.set_value(self.app.defaults["tools_cr_h2h"])
+ self.ui.clearance_d2d_entry.set_value(float(self.app.defaults["tools_cr_h2h_val"]))
+ self.ui.drill_size_cb.set_value(self.app.defaults["tools_cr_dh"])
+ self.ui.drill_size_entry.set_value(float(self.app.defaults["tools_cr_dh_val"]))
self.reset_fields()
@@ -1128,30 +626,30 @@ class RulesCheck(AppTool):
self.app.proc_container.new(_("Working..."))
# RULE: Check Trace Size
- if self.trace_size_cb.get_value():
+ if self.ui.trace_size_cb.get_value():
copper_list = []
- copper_name_1 = self.copper_t_object.currentText()
- if copper_name_1 != '' and self.copper_t_cb.get_value():
+ copper_name_1 = self.ui.copper_t_object.currentText()
+ if copper_name_1 != '' and self.ui.copper_t_cb.get_value():
elem_dict = {}
elem_dict['name'] = deepcopy(copper_name_1)
elem_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_name_1).apertures)
copper_list.append(elem_dict)
- copper_name_2 = self.copper_b_object.currentText()
- if copper_name_2 != '' and self.copper_b_cb.get_value():
+ copper_name_2 = self.ui.copper_b_object.currentText()
+ if copper_name_2 != '' and self.ui.copper_b_cb.get_value():
elem_dict = {}
elem_dict['name'] = deepcopy(copper_name_2)
elem_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_name_2).apertures)
copper_list.append(elem_dict)
- trace_size = float(self.trace_size_entry.get_value())
+ trace_size = float(self.ui.trace_size_entry.get_value())
self.results.append(self.pool.apply_async(self.check_traces_size, args=(copper_list, trace_size)))
# RULE: Check Copper to Copper Clearance
- if self.clearance_copper2copper_cb.get_value():
+ if self.ui.clearance_copper2copper_cb.get_value():
try:
- copper_copper_clearance = float(self.clearance_copper2copper_entry.get_value())
+ copper_copper_clearance = float(self.ui.clearance_copper2copper_entry.get_value())
except Exception as e:
log.debug("RulesCheck.execute.worker_job() --> %s" % str(e))
self.app.inform.emit('[ERROR_NOTCL] %s. %s' % (
@@ -1160,7 +658,7 @@ class RulesCheck(AppTool):
return
if self.copper_t_cb.get_value():
- copper_t_obj = self.copper_t_object.currentText()
+ copper_t_obj = self.ui.copper_t_object.currentText()
copper_t_dict = {}
if copper_t_obj != '':
@@ -1171,8 +669,8 @@ class RulesCheck(AppTool):
args=(copper_t_dict,
copper_copper_clearance,
_("TOP -> Copper to Copper clearance"))))
- if self.copper_b_cb.get_value():
- copper_b_obj = self.copper_b_object.currentText()
+ if self.ui.copper_b_cb.get_value():
+ copper_b_obj = self.ui.copper_b_object.currentText()
copper_b_dict = {}
if copper_b_obj != '':
copper_b_dict['name'] = deepcopy(copper_b_obj)
@@ -1183,35 +681,35 @@ class RulesCheck(AppTool):
copper_copper_clearance,
_("BOTTOM -> Copper to Copper clearance"))))
- if self.copper_t_cb.get_value() is False and self.copper_b_cb.get_value() is False:
+ if self.ui.copper_t_cb.get_value() is False and self.ui.copper_b_cb.get_value() is False:
self.app.inform.emit('[ERROR_NOTCL] %s. %s' % (
_("Copper to Copper clearance"),
_("At least one Gerber object has to be selected for this rule but none is selected.")))
return
# RULE: Check Copper to Outline Clearance
- if self.clearance_copper2ol_cb.get_value() and self.out_cb.get_value():
+ if self.ui.clearance_copper2ol_cb.get_value() and self.ui.out_cb.get_value():
top_dict = {}
bottom_dict = {}
outline_dict = {}
- copper_top = self.copper_t_object.currentText()
- if copper_top != '' and self.copper_t_cb.get_value():
+ copper_top = self.ui.copper_t_object.currentText()
+ if copper_top != '' and self.ui.copper_t_cb.get_value():
top_dict['name'] = deepcopy(copper_top)
top_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_top).apertures)
- copper_bottom = self.copper_b_object.currentText()
- if copper_bottom != '' and self.copper_b_cb.get_value():
+ copper_bottom = self.ui.copper_b_object.currentText()
+ if copper_bottom != '' and self.ui.copper_b_cb.get_value():
bottom_dict['name'] = deepcopy(copper_bottom)
bottom_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_bottom).apertures)
- copper_outline = self.outline_object.currentText()
- if copper_outline != '' and self.out_cb.get_value():
+ copper_outline = self.ui.outline_object.currentText()
+ if copper_outline != '' and self.ui.out_cb.get_value():
outline_dict['name'] = deepcopy(copper_outline)
outline_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_outline).apertures)
try:
- copper_outline_clearance = float(self.clearance_copper2ol_entry.get_value())
+ copper_outline_clearance = float(self.ui.clearance_copper2ol_entry.get_value())
except Exception as e:
log.debug("RulesCheck.execute.worker_job() --> %s" % str(e))
self.app.inform.emit('[ERROR_NOTCL] %s. %s' % (
@@ -1244,11 +742,11 @@ class RulesCheck(AppTool):
_("Copper to Outline clearance"))))
# RULE: Check Silk to Silk Clearance
- if self.clearance_silk2silk_cb.get_value():
+ if self.ui.clearance_silk2silk_cb.get_value():
silk_dict = {}
try:
- silk_silk_clearance = float(self.clearance_silk2silk_entry.get_value())
+ silk_silk_clearance = float(self.ui.clearance_silk2silk_entry.get_value())
except Exception as e:
log.debug("RulesCheck.execute.worker_job() --> %s" % str(e))
self.app.inform.emit('[ERROR_NOTCL] %s. %s' % (
@@ -1257,7 +755,7 @@ class RulesCheck(AppTool):
return
if self.ss_t_cb.get_value():
- silk_obj = self.ss_t_object.currentText()
+ silk_obj = self.ui.ss_t_object.currentText()
if silk_obj != '':
silk_dict['name'] = deepcopy(silk_obj)
silk_dict['apertures'] = deepcopy(self.app.collection.get_by_name(silk_obj).apertures)
@@ -1266,8 +764,8 @@ class RulesCheck(AppTool):
args=(silk_dict,
silk_silk_clearance,
_("TOP -> Silk to Silk clearance"))))
- if self.ss_b_cb.get_value():
- silk_obj = self.ss_b_object.currentText()
+ if self.ui.ss_b_cb.get_value():
+ silk_obj = self.ui.ss_b_object.currentText()
if silk_obj != '':
silk_dict['name'] = deepcopy(silk_obj)
silk_dict['apertures'] = deepcopy(self.app.collection.get_by_name(silk_obj).apertures)
@@ -1277,14 +775,14 @@ class RulesCheck(AppTool):
silk_silk_clearance,
_("BOTTOM -> Silk to Silk clearance"))))
- if self.ss_t_cb.get_value() is False and self.ss_b_cb.get_value() is False:
+ if self.ui.ss_t_cb.get_value() is False and self.ui.ss_b_cb.get_value() is False:
self.app.inform.emit('[ERROR_NOTCL] %s. %s' % (
_("Silk to Silk clearance"),
_("At least one Gerber object has to be selected for this rule but none is selected.")))
return
# RULE: Check Silk to Solder Mask Clearance
- if self.clearance_silk2sm_cb.get_value():
+ if self.ui.clearance_silk2sm_cb.get_value():
silk_t_dict = {}
sm_t_dict = {}
silk_b_dict = {}
@@ -1295,32 +793,32 @@ class RulesCheck(AppTool):
top_sm = False
bottom_sm = False
- silk_top = self.ss_t_object.currentText()
- if silk_top != '' and self.ss_t_cb.get_value():
+ silk_top = self.ui.ss_t_object.currentText()
+ if silk_top != '' and self.ui.ss_t_cb.get_value():
silk_t_dict['name'] = deepcopy(silk_top)
silk_t_dict['apertures'] = deepcopy(self.app.collection.get_by_name(silk_top).apertures)
top_ss = True
- silk_bottom = self.ss_b_object.currentText()
- if silk_bottom != '' and self.ss_b_cb.get_value():
+ silk_bottom = self.ui.ss_b_object.currentText()
+ if silk_bottom != '' and self.ui.ss_b_cb.get_value():
silk_b_dict['name'] = deepcopy(silk_bottom)
silk_b_dict['apertures'] = deepcopy(self.app.collection.get_by_name(silk_bottom).apertures)
bottom_ss = True
- sm_top = self.sm_t_object.currentText()
- if sm_top != '' and self.sm_t_cb.get_value():
+ sm_top = self.ui.sm_t_object.currentText()
+ if sm_top != '' and self.ui.sm_t_cb.get_value():
sm_t_dict['name'] = deepcopy(sm_top)
sm_t_dict['apertures'] = deepcopy(self.app.collection.get_by_name(sm_top).apertures)
top_sm = True
- sm_bottom = self.sm_b_object.currentText()
- if sm_bottom != '' and self.sm_b_cb.get_value():
+ sm_bottom = self.ui.sm_b_object.currentText()
+ if sm_bottom != '' and self.ui.sm_b_cb.get_value():
sm_b_dict['name'] = deepcopy(sm_bottom)
sm_b_dict['apertures'] = deepcopy(self.app.collection.get_by_name(sm_bottom).apertures)
bottom_sm = True
try:
- silk_sm_clearance = float(self.clearance_silk2sm_entry.get_value())
+ silk_sm_clearance = float(self.ui.clearance_silk2sm_entry.get_value())
except Exception as e:
log.debug("RulesCheck.execute.worker_job() --> %s" % str(e))
self.app.inform.emit('[ERROR_NOTCL] %s. %s' % (
@@ -1353,28 +851,28 @@ class RulesCheck(AppTool):
return
# RULE: Check Silk to Outline Clearance
- if self.clearance_silk2ol_cb.get_value():
+ if self.ui.clearance_silk2ol_cb.get_value():
top_dict = {}
bottom_dict = {}
outline_dict = {}
- silk_top = self.ss_t_object.currentText()
- if silk_top != '' and self.ss_t_cb.get_value():
+ silk_top = self.ui.ss_t_object.currentText()
+ if silk_top != '' and self.ui.ss_t_cb.get_value():
top_dict['name'] = deepcopy(silk_top)
top_dict['apertures'] = deepcopy(self.app.collection.get_by_name(silk_top).apertures)
- silk_bottom = self.ss_b_object.currentText()
- if silk_bottom != '' and self.ss_b_cb.get_value():
+ silk_bottom = self.ui.ss_b_object.currentText()
+ if silk_bottom != '' and self.ui.ss_b_cb.get_value():
bottom_dict['name'] = deepcopy(silk_bottom)
bottom_dict['apertures'] = deepcopy(self.app.collection.get_by_name(silk_bottom).apertures)
- copper_outline = self.outline_object.currentText()
- if copper_outline != '' and self.out_cb.get_value():
+ copper_outline = self.ui.outline_object.currentText()
+ if copper_outline != '' and self.ui.out_cb.get_value():
outline_dict['name'] = deepcopy(copper_outline)
outline_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_outline).apertures)
try:
- copper_outline_clearance = float(self.clearance_copper2ol_entry.get_value())
+ copper_outline_clearance = float(self.ui.clearance_copper2ol_entry.get_value())
except Exception as e:
log.debug("RulesCheck.execute.worker_job() --> %s" % str(e))
self.app.inform.emit('[ERROR_NOTCL] %s. %s' % (
@@ -1408,11 +906,11 @@ class RulesCheck(AppTool):
_("Silk to Outline Clearance"))))
# RULE: Check Minimum Solder Mask Sliver
- if self.clearance_silk2silk_cb.get_value():
+ if self.ui.clearance_silk2silk_cb.get_value():
sm_dict = {}
try:
- sm_sm_clearance = float(self.clearance_sm2sm_entry.get_value())
+ sm_sm_clearance = float(self.ui.clearance_sm2sm_entry.get_value())
except Exception as e:
log.debug("RulesCheck.execute.worker_job() --> %s" % str(e))
self.app.inform.emit('[ERROR_NOTCL] %s. %s' % (
@@ -1420,8 +918,8 @@ class RulesCheck(AppTool):
_("Value is not valid.")))
return
- if self.sm_t_cb.get_value():
- solder_obj = self.sm_t_object.currentText()
+ if self.ui.sm_t_cb.get_value():
+ solder_obj = self.ui.sm_t_object.currentText()
if solder_obj != '':
sm_dict['name'] = deepcopy(solder_obj)
sm_dict['apertures'] = deepcopy(self.app.collection.get_by_name(solder_obj).apertures)
@@ -1430,8 +928,8 @@ class RulesCheck(AppTool):
args=(sm_dict,
sm_sm_clearance,
_("TOP -> Minimum Solder Mask Sliver"))))
- if self.sm_b_cb.get_value():
- solder_obj = self.sm_b_object.currentText()
+ if self.ui.sm_b_cb.get_value():
+ solder_obj = self.ui.sm_b_object.currentText()
if solder_obj != '':
sm_dict['name'] = deepcopy(solder_obj)
sm_dict['apertures'] = deepcopy(self.app.collection.get_by_name(solder_obj).apertures)
@@ -1441,43 +939,43 @@ class RulesCheck(AppTool):
sm_sm_clearance,
_("BOTTOM -> Minimum Solder Mask Sliver"))))
- if self.sm_t_cb.get_value() is False and self.sm_b_cb.get_value() is False:
+ if self.ui.sm_t_cb.get_value() is False and self.ui.sm_b_cb.get_value() is False:
self.app.inform.emit('[ERROR_NOTCL] %s. %s' % (
_("Minimum Solder Mask Sliver"),
_("At least one Gerber object has to be selected for this rule but none is selected.")))
return
# RULE: Check Minimum Annular Ring
- if self.ring_integrity_cb.get_value():
+ if self.ui.ring_integrity_cb.get_value():
top_dict = {}
bottom_dict = {}
exc_1_dict = {}
exc_2_dict = {}
- copper_top = self.copper_t_object.currentText()
- if copper_top != '' and self.copper_t_cb.get_value():
+ copper_top = self.ui.copper_t_object.currentText()
+ if copper_top != '' and self.ui.copper_t_cb.get_value():
top_dict['name'] = deepcopy(copper_top)
top_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_top).apertures)
- copper_bottom = self.copper_b_object.currentText()
- if copper_bottom != '' and self.copper_b_cb.get_value():
+ copper_bottom = self.ui.copper_b_object.currentText()
+ if copper_bottom != '' and self.ui.copper_b_cb.get_value():
bottom_dict['name'] = deepcopy(copper_bottom)
bottom_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_bottom).apertures)
- excellon_1 = self.e1_object.currentText()
- if excellon_1 != '' and self.e1_cb.get_value():
+ excellon_1 = self.ui.e1_object.currentText()
+ if excellon_1 != '' and self.ui.e1_cb.get_value():
exc_1_dict['name'] = deepcopy(excellon_1)
exc_1_dict['tools'] = deepcopy(
self.app.collection.get_by_name(excellon_1).tools)
- excellon_2 = self.e2_object.currentText()
- if excellon_2 != '' and self.e2_cb.get_value():
+ excellon_2 = self.ui.e2_object.currentText()
+ if excellon_2 != '' and self.ui.e2_cb.get_value():
exc_2_dict['name'] = deepcopy(excellon_2)
exc_2_dict['tools'] = deepcopy(
self.app.collection.get_by_name(excellon_2).tools)
try:
- ring_val = float(self.ring_integrity_entry.get_value())
+ ring_val = float(self.ui.ring_integrity_entry.get_value())
except Exception as e:
log.debug("RulesCheck.execute.worker_job() --> %s" % str(e))
self.app.inform.emit('[ERROR_NOTCL] %s. %s' % (
@@ -1513,43 +1011,43 @@ class RulesCheck(AppTool):
_("Minimum Annular Ring"))))
# RULE: Check Hole to Hole Clearance
- if self.clearance_d2d_cb.get_value():
+ if self.ui.clearance_d2d_cb.get_value():
exc_list = []
- exc_name_1 = self.e1_object.currentText()
- if exc_name_1 != '' and self.e1_cb.get_value():
+ exc_name_1 = self.ui.e1_object.currentText()
+ if exc_name_1 != '' and self.ui.e1_cb.get_value():
elem_dict = {}
elem_dict['name'] = deepcopy(exc_name_1)
elem_dict['tools'] = deepcopy(self.app.collection.get_by_name(exc_name_1).tools)
exc_list.append(elem_dict)
- exc_name_2 = self.e2_object.currentText()
- if exc_name_2 != '' and self.e2_cb.get_value():
+ exc_name_2 = self.ui.e2_object.currentText()
+ if exc_name_2 != '' and self.ui.e2_cb.get_value():
elem_dict = {}
elem_dict['name'] = deepcopy(exc_name_2)
elem_dict['tools'] = deepcopy(self.app.collection.get_by_name(exc_name_2).tools)
exc_list.append(elem_dict)
- hole_clearance = float(self.clearance_d2d_entry.get_value())
+ hole_clearance = float(self.ui.clearance_d2d_entry.get_value())
self.results.append(self.pool.apply_async(self.check_holes_clearance, args=(exc_list, hole_clearance)))
# RULE: Check Holes Size
- if self.drill_size_cb.get_value():
+ if self.ui.drill_size_cb.get_value():
exc_list = []
- exc_name_1 = self.e1_object.currentText()
- if exc_name_1 != '' and self.e1_cb.get_value():
+ exc_name_1 = self.ui.e1_object.currentText()
+ if exc_name_1 != '' and self.ui.e1_cb.get_value():
elem_dict = {}
elem_dict['name'] = deepcopy(exc_name_1)
elem_dict['tools'] = deepcopy(self.app.collection.get_by_name(exc_name_1).tools)
exc_list.append(elem_dict)
- exc_name_2 = self.e2_object.currentText()
- if exc_name_2 != '' and self.e2_cb.get_value():
+ exc_name_2 = self.ui.e2_object.currentText()
+ if exc_name_2 != '' and self.ui.e2_cb.get_value():
elem_dict = {}
elem_dict['name'] = deepcopy(exc_name_2)
elem_dict['tools'] = deepcopy(self.app.collection.get_by_name(exc_name_2).tools)
exc_list.append(elem_dict)
- drill_size = float(self.drill_size_entry.get_value())
+ drill_size = float(self.ui.drill_size_entry.get_value())
self.results.append(self.pool.apply_async(self.check_holes_size, args=(exc_list, drill_size)))
output = []
@@ -1632,3 +1130,539 @@ class RulesCheck(AppTool):
# self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
# self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
pass
+
+
+class RulesUI:
+
+ toolName = _("Check Rules")
+
+ 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)
+
+ # Form Layout
+ self.grid_layout = QtWidgets.QGridLayout()
+ self.layout.addLayout(self.grid_layout)
+
+ self.grid_layout.setColumnStretch(0, 0)
+ self.grid_layout.setColumnStretch(1, 3)
+ self.grid_layout.setColumnStretch(2, 0)
+
+ self.gerber_title_lbl = FCLabel('%s:' % _("GERBER"))
+ self.gerber_title_lbl.setToolTip(
+ _("Gerber objects for which to check rules.")
+ )
+
+ self.all_obj_cb = FCCheckBox()
+
+ self.grid_layout.addWidget(self.gerber_title_lbl, 0, 0, 1, 2)
+ self.grid_layout.addWidget(self.all_obj_cb, 0, 2)
+
+ # Copper Top object
+ self.copper_t_object = FCComboBox()
+ self.copper_t_object.setModel(self.app.collection)
+ self.copper_t_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.copper_t_object.is_last = True
+ self.copper_t_object.obj_type = "Gerber"
+
+ self.copper_t_object_lbl = FCLabel('%s:' % _("Top"))
+ self.copper_t_object_lbl.setToolTip(
+ _("The Top Gerber Copper object for which rules are checked.")
+ )
+
+ self.copper_t_cb = FCCheckBox()
+
+ self.grid_layout.addWidget(self.copper_t_object_lbl, 1, 0)
+ self.grid_layout.addWidget(self.copper_t_object, 1, 1)
+ self.grid_layout.addWidget(self.copper_t_cb, 1, 2)
+
+ # Copper Bottom object
+ self.copper_b_object = FCComboBox()
+ self.copper_b_object.setModel(self.app.collection)
+ self.copper_b_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.copper_b_object.is_last = True
+ self.copper_b_object.obj_type = "Gerber"
+
+ self.copper_b_object_lbl = FCLabel('%s:' % _("Bottom"))
+ self.copper_b_object_lbl.setToolTip(
+ _("The Bottom Gerber Copper object for which rules are checked.")
+ )
+
+ self.copper_b_cb = FCCheckBox()
+
+ self.grid_layout.addWidget(self.copper_b_object_lbl, 2, 0)
+ self.grid_layout.addWidget(self.copper_b_object, 2, 1)
+ self.grid_layout.addWidget(self.copper_b_cb, 2, 2)
+
+ # SolderMask Top object
+ self.sm_t_object = FCComboBox()
+ self.sm_t_object.setModel(self.app.collection)
+ self.sm_t_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.sm_t_object.is_last = True
+ self.sm_t_object.obj_type = "Gerber"
+
+ self.sm_t_object_lbl = FCLabel('%s:' % _("SM Top"))
+ self.sm_t_object_lbl.setToolTip(
+ _("The Top Gerber Solder Mask object for which rules are checked.")
+ )
+
+ self.sm_t_cb = FCCheckBox()
+
+ self.grid_layout.addWidget(self.sm_t_object_lbl, 3, 0)
+ self.grid_layout.addWidget(self.sm_t_object, 3, 1)
+ self.grid_layout.addWidget(self.sm_t_cb, 3, 2)
+
+ # SolderMask Bottom object
+ self.sm_b_object = FCComboBox()
+ self.sm_b_object.setModel(self.app.collection)
+ self.sm_b_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.sm_b_object.is_last = True
+ self.sm_b_object.obj_type = "Gerber"
+
+ self.sm_b_object_lbl = FCLabel('%s:' % _("SM Bottom"))
+ self.sm_b_object_lbl.setToolTip(
+ _("The Bottom Gerber Solder Mask object for which rules are checked.")
+ )
+
+ self.sm_b_cb = FCCheckBox()
+
+ self.grid_layout.addWidget(self.sm_b_object_lbl, 4, 0)
+ self.grid_layout.addWidget(self.sm_b_object, 4, 1)
+ self.grid_layout.addWidget(self.sm_b_cb, 4, 2)
+
+ # SilkScreen Top object
+ self.ss_t_object = FCComboBox()
+ self.ss_t_object.setModel(self.app.collection)
+ self.ss_t_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.ss_t_object.is_last = True
+ self.ss_t_object.obj_type = "Gerber"
+
+ self.ss_t_object_lbl = FCLabel('%s:' % _("Silk Top"))
+ self.ss_t_object_lbl.setToolTip(
+ _("The Top Gerber Silkscreen object for which rules are checked.")
+ )
+
+ self.ss_t_cb = FCCheckBox()
+
+ self.grid_layout.addWidget(self.ss_t_object_lbl, 5, 0)
+ self.grid_layout.addWidget(self.ss_t_object, 5, 1)
+ self.grid_layout.addWidget(self.ss_t_cb, 5, 2)
+
+ # SilkScreen Bottom object
+ self.ss_b_object = FCComboBox()
+ self.ss_b_object.setModel(self.app.collection)
+ self.ss_b_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.ss_b_object.is_last = True
+ self.ss_b_object.obj_type = "Gerber"
+
+ self.ss_b_object_lbl = FCLabel('%s:' % _("Silk Bottom"))
+ self.ss_b_object_lbl.setToolTip(
+ _("The Bottom Gerber Silkscreen object for which rules are checked.")
+ )
+
+ self.ss_b_cb = FCCheckBox()
+
+ self.grid_layout.addWidget(self.ss_b_object_lbl, 6, 0)
+ self.grid_layout.addWidget(self.ss_b_object, 6, 1)
+ self.grid_layout.addWidget(self.ss_b_cb, 6, 2)
+
+ # Outline object
+ self.outline_object = FCComboBox()
+ self.outline_object.setModel(self.app.collection)
+ self.outline_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.outline_object.is_last = True
+ self.outline_object.obj_type = "Gerber"
+
+ self.outline_object_lbl = FCLabel('%s:' % _("Outline"))
+ self.outline_object_lbl.setToolTip(
+ _("The Gerber Outline (Cutout) object for which rules are checked.")
+ )
+
+ self.out_cb = FCCheckBox()
+
+ self.grid_layout.addWidget(self.outline_object_lbl, 7, 0)
+ self.grid_layout.addWidget(self.outline_object, 7, 1)
+ self.grid_layout.addWidget(self.out_cb, 7, 2)
+
+ self.grid_layout.addWidget(FCLabel(""), 8, 0, 1, 3)
+
+ self.excellon_title_lbl = FCLabel('%s:' % _("EXCELLON"))
+ self.excellon_title_lbl.setToolTip(
+ _("Excellon objects for which to check rules.")
+ )
+
+ self.grid_layout.addWidget(self.excellon_title_lbl, 9, 0, 1, 3)
+
+ # Excellon 1 object
+ self.e1_object = FCComboBox()
+ self.e1_object.setModel(self.app.collection)
+ self.e1_object.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
+ self.e1_object.is_last = True
+ self.e1_object.obj_type = "Excellon"
+
+ self.e1_object_lbl = FCLabel('%s:' % _("Excellon 1"))
+ self.e1_object_lbl.setToolTip(
+ _("Excellon object for which to check rules.\n"
+ "Holds the plated holes or a general Excellon file content.")
+ )
+
+ self.e1_cb = FCCheckBox()
+
+ self.grid_layout.addWidget(self.e1_object_lbl, 10, 0)
+ self.grid_layout.addWidget(self.e1_object, 10, 1)
+ self.grid_layout.addWidget(self.e1_cb, 10, 2)
+
+ # Excellon 2 object
+ self.e2_object = FCComboBox()
+ self.e2_object.setModel(self.app.collection)
+ self.e2_object.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
+ self.e2_object.is_last = True
+ self.e2_object.obj_type = "Excellon"
+
+ self.e2_object_lbl = FCLabel('%s:' % _("Excellon 2"))
+ self.e2_object_lbl.setToolTip(
+ _("Excellon object for which to check rules.\n"
+ "Holds the non-plated holes.")
+ )
+
+ self.e2_cb = FCCheckBox()
+
+ self.grid_layout.addWidget(self.e2_object_lbl, 11, 0)
+ self.grid_layout.addWidget(self.e2_object, 11, 1)
+ self.grid_layout.addWidget(self.e2_cb, 11, 2)
+
+ self.grid_layout.addWidget(FCLabel(""), 12, 0, 1, 3)
+
+ # Control All
+ self.all_cb = FCCheckBox('%s' % _("All Rules"))
+ self.all_cb.setToolTip(
+ _("This check/uncheck all the rules below.")
+ )
+ self.all_cb.setStyleSheet(
+ """
+ QCheckBox {font-weight: bold; color: green}
+ """
+ )
+ self.layout.addWidget(self.all_cb)
+
+ # Form Layout
+ self.form_layout_1 = QtWidgets.QFormLayout()
+ self.layout.addLayout(self.form_layout_1)
+
+ self.form_layout_1.addRow(FCLabel(""))
+
+ # Trace size
+ self.trace_size_cb = FCCheckBox('%s:' % _("Trace Size"))
+ self.trace_size_cb.setToolTip(
+ _("This checks if the minimum size for traces is met.")
+ )
+ self.form_layout_1.addRow(self.trace_size_cb)
+
+ # Trace size value
+ self.trace_size_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.trace_size_entry.set_range(0.00001, 999.99999)
+ self.trace_size_entry.set_precision(self.decimals)
+ self.trace_size_entry.setSingleStep(0.1)
+
+ self.trace_size_lbl = FCLabel('%s:' % _("Min value"))
+ self.trace_size_lbl.setToolTip(
+ _("Minimum acceptable trace size.")
+ )
+ self.form_layout_1.addRow(self.trace_size_lbl, self.trace_size_entry)
+
+ self.ts = OptionalInputSection(self.trace_size_cb, [self.trace_size_lbl, self.trace_size_entry])
+
+ # Copper2copper clearance
+ self.clearance_copper2copper_cb = FCCheckBox('%s:' % _("Copper to Copper clearance"))
+ self.clearance_copper2copper_cb.setToolTip(
+ _("This checks if the minimum clearance between copper\n"
+ "features is met.")
+ )
+ self.form_layout_1.addRow(self.clearance_copper2copper_cb)
+
+ # Copper2copper clearance value
+ self.clearance_copper2copper_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.clearance_copper2copper_entry.set_range(0.00001, 999.99999)
+ self.clearance_copper2copper_entry.set_precision(self.decimals)
+ self.clearance_copper2copper_entry.setSingleStep(0.1)
+
+ self.clearance_copper2copper_lbl = FCLabel('%s:' % _("Min value"))
+ self.clearance_copper2copper_lbl.setToolTip(
+ _("Minimum acceptable clearance value.")
+ )
+ self.form_layout_1.addRow(self.clearance_copper2copper_lbl, self.clearance_copper2copper_entry)
+
+ self.c2c = OptionalInputSection(
+ self.clearance_copper2copper_cb, [self.clearance_copper2copper_lbl, self.clearance_copper2copper_entry])
+
+ # Copper2outline clearance
+ self.clearance_copper2ol_cb = FCCheckBox('%s:' % _("Copper to Outline clearance"))
+ self.clearance_copper2ol_cb.setToolTip(
+ _("This checks if the minimum clearance between copper\n"
+ "features and the outline is met.")
+ )
+ self.form_layout_1.addRow(self.clearance_copper2ol_cb)
+
+ # Copper2outline clearance value
+ self.clearance_copper2ol_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.clearance_copper2ol_entry.set_range(0.00001, 999.99999)
+ self.clearance_copper2ol_entry.set_precision(self.decimals)
+ self.clearance_copper2ol_entry.setSingleStep(0.1)
+
+ self.clearance_copper2ol_lbl = FCLabel('%s:' % _("Min value"))
+ self.clearance_copper2ol_lbl.setToolTip(
+ _("Minimum acceptable clearance value.")
+ )
+ self.form_layout_1.addRow(self.clearance_copper2ol_lbl, self.clearance_copper2ol_entry)
+
+ self.c2ol = OptionalInputSection(
+ self.clearance_copper2ol_cb, [self.clearance_copper2ol_lbl, self.clearance_copper2ol_entry])
+
+ # Silkscreen2silkscreen clearance
+ self.clearance_silk2silk_cb = FCCheckBox('%s:' % _("Silk to Silk Clearance"))
+ self.clearance_silk2silk_cb.setToolTip(
+ _("This checks if the minimum clearance between silkscreen\n"
+ "features and silkscreen features is met.")
+ )
+ self.form_layout_1.addRow(self.clearance_silk2silk_cb)
+
+ # Copper2silkscreen clearance value
+ self.clearance_silk2silk_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.clearance_silk2silk_entry.set_range(0.00001, 999.99999)
+ self.clearance_silk2silk_entry.set_precision(self.decimals)
+ self.clearance_silk2silk_entry.setSingleStep(0.1)
+
+ self.clearance_silk2silk_lbl = FCLabel('%s:' % _("Min value"))
+ self.clearance_silk2silk_lbl.setToolTip(
+ _("Minimum acceptable clearance value.")
+ )
+ self.form_layout_1.addRow(self.clearance_silk2silk_lbl, self.clearance_silk2silk_entry)
+
+ self.s2s = OptionalInputSection(
+ self.clearance_silk2silk_cb, [self.clearance_silk2silk_lbl, self.clearance_silk2silk_entry])
+
+ # Silkscreen2soldermask clearance
+ self.clearance_silk2sm_cb = FCCheckBox('%s:' % _("Silk to Solder Mask Clearance"))
+ self.clearance_silk2sm_cb.setToolTip(
+ _("This checks if the minimum clearance between silkscreen\n"
+ "features and soldermask features is met.")
+ )
+ self.form_layout_1.addRow(self.clearance_silk2sm_cb)
+
+ # Silkscreen2soldermask clearance value
+ self.clearance_silk2sm_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.clearance_silk2sm_entry.set_range(0.00001, 999.99999)
+ self.clearance_silk2sm_entry.set_precision(self.decimals)
+ self.clearance_silk2sm_entry.setSingleStep(0.1)
+
+ self.clearance_silk2sm_lbl = FCLabel('%s:' % _("Min value"))
+ self.clearance_silk2sm_lbl.setToolTip(
+ _("Minimum acceptable clearance value.")
+ )
+ self.form_layout_1.addRow(self.clearance_silk2sm_lbl, self.clearance_silk2sm_entry)
+
+ self.s2sm = OptionalInputSection(
+ self.clearance_silk2sm_cb, [self.clearance_silk2sm_lbl, self.clearance_silk2sm_entry])
+
+ # Silk2outline clearance
+ self.clearance_silk2ol_cb = FCCheckBox('%s:' % _("Silk to Outline Clearance"))
+ self.clearance_silk2ol_cb.setToolTip(
+ _("This checks if the minimum clearance between silk\n"
+ "features and the outline is met.")
+ )
+ self.form_layout_1.addRow(self.clearance_silk2ol_cb)
+
+ # Silk2outline clearance value
+ self.clearance_silk2ol_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.clearance_silk2ol_entry.set_range(0.00001, 999.99999)
+ self.clearance_silk2ol_entry.set_precision(self.decimals)
+ self.clearance_silk2ol_entry.setSingleStep(0.1)
+
+ self.clearance_silk2ol_lbl = FCLabel('%s:' % _("Min value"))
+ self.clearance_silk2ol_lbl.setToolTip(
+ _("Minimum acceptable clearance value.")
+ )
+ self.form_layout_1.addRow(self.clearance_silk2ol_lbl, self.clearance_silk2ol_entry)
+
+ self.s2ol = OptionalInputSection(
+ self.clearance_silk2ol_cb, [self.clearance_silk2ol_lbl, self.clearance_silk2ol_entry])
+
+ # Soldermask2soldermask clearance
+ self.clearance_sm2sm_cb = FCCheckBox('%s:' % _("Minimum Solder Mask Sliver"))
+ self.clearance_sm2sm_cb.setToolTip(
+ _("This checks if the minimum clearance between soldermask\n"
+ "features and soldermask features is met.")
+ )
+ self.form_layout_1.addRow(self.clearance_sm2sm_cb)
+
+ # Soldermask2soldermask clearance value
+ self.clearance_sm2sm_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.clearance_sm2sm_entry.set_range(0.00001, 999.99999)
+ self.clearance_sm2sm_entry.set_precision(self.decimals)
+ self.clearance_sm2sm_entry.setSingleStep(0.1)
+
+ self.clearance_sm2sm_lbl = FCLabel('%s:' % _("Min value"))
+ self.clearance_sm2sm_lbl.setToolTip(
+ _("Minimum acceptable clearance value.")
+ )
+ self.form_layout_1.addRow(self.clearance_sm2sm_lbl, self.clearance_sm2sm_entry)
+
+ self.sm2sm = OptionalInputSection(
+ self.clearance_sm2sm_cb, [self.clearance_sm2sm_lbl, self.clearance_sm2sm_entry])
+
+ # Ring integrity check
+ self.ring_integrity_cb = FCCheckBox('%s:' % _("Minimum Annular Ring"))
+ self.ring_integrity_cb.setToolTip(
+ _("This checks if the minimum copper ring left by drilling\n"
+ "a hole into a pad is met.")
+ )
+ self.form_layout_1.addRow(self.ring_integrity_cb)
+
+ # Ring integrity value
+ self.ring_integrity_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.ring_integrity_entry.set_range(0.00001, 999.99999)
+ self.ring_integrity_entry.set_precision(self.decimals)
+ self.ring_integrity_entry.setSingleStep(0.1)
+
+ self.ring_integrity_lbl = FCLabel('%s:' % _("Min value"))
+ self.ring_integrity_lbl.setToolTip(
+ _("Minimum acceptable ring value.")
+ )
+ self.form_layout_1.addRow(self.ring_integrity_lbl, self.ring_integrity_entry)
+
+ self.anr = OptionalInputSection(
+ self.ring_integrity_cb, [self.ring_integrity_lbl, self.ring_integrity_entry])
+
+ self.form_layout_1.addRow(FCLabel(""))
+
+ # Hole2Hole clearance
+ self.clearance_d2d_cb = FCCheckBox('%s:' % _("Hole to Hole Clearance"))
+ self.clearance_d2d_cb.setToolTip(
+ _("This checks if the minimum clearance between a drill hole\n"
+ "and another drill hole is met.")
+ )
+ self.form_layout_1.addRow(self.clearance_d2d_cb)
+
+ # Hole2Hole clearance value
+ self.clearance_d2d_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.clearance_d2d_entry.set_range(0.00001, 999.99999)
+ self.clearance_d2d_entry.set_precision(self.decimals)
+ self.clearance_d2d_entry.setSingleStep(0.1)
+
+ self.clearance_d2d_lbl = FCLabel('%s:' % _("Min value"))
+ self.clearance_d2d_lbl.setToolTip(
+ _("Minimum acceptable clearance value.")
+ )
+ self.form_layout_1.addRow(self.clearance_d2d_lbl, self.clearance_d2d_entry)
+
+ self.d2d = OptionalInputSection(
+ self.clearance_d2d_cb, [self.clearance_d2d_lbl, self.clearance_d2d_entry])
+
+ # Drill holes size check
+ self.drill_size_cb = FCCheckBox('%s:' % _("Hole Size"))
+ self.drill_size_cb.setToolTip(
+ _("This checks if the drill holes\n"
+ "sizes are above the threshold.")
+ )
+ self.form_layout_1.addRow(self.drill_size_cb)
+
+ # Drile holes value
+ self.drill_size_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.drill_size_entry.set_range(0.00001, 999.99999)
+ self.drill_size_entry.set_precision(self.decimals)
+ self.drill_size_entry.setSingleStep(0.1)
+
+ self.drill_size_lbl = FCLabel('%s:' % _("Min value"))
+ self.drill_size_lbl.setToolTip(
+ _("Minimum acceptable drill size.")
+ )
+ self.form_layout_1.addRow(self.drill_size_lbl, self.drill_size_entry)
+
+ self.ds = OptionalInputSection(
+ self.drill_size_cb, [self.drill_size_lbl, self.drill_size_entry])
+
+ # Buttons
+ hlay_2 = QtWidgets.QHBoxLayout()
+ self.layout.addLayout(hlay_2)
+
+ # hlay_2.addStretch()
+ self.run_button = FCButton(_("Run Rules Check"))
+ self.run_button.setToolTip(
+ _("Panelize the specified object around the specified box.\n"
+ "In other words it creates multiple copies of the source object,\n"
+ "arranged in a 2D array of rows and columns.")
+ )
+ self.run_button.setStyleSheet("""
+ QPushButton
+ {
+ font-weight: bold;
+ }
+ """)
+ hlay_2.addWidget(self.run_button)
+
+ self.layout.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.layout.addWidget(self.reset_button)
+
+ # #################################### FINSIHED GUI ###########################
+ # #############################################################################
+ def on_all_cb_changed(self, state):
+ cb_items = [self.form_layout_1.itemAt(i).widget() for i in range(self.form_layout_1.count())
+ if isinstance(self.form_layout_1.itemAt(i).widget(), FCCheckBox)]
+
+ for cb in cb_items:
+ if state:
+ cb.setChecked(True)
+ else:
+ cb.setChecked(False)
+
+ def on_all_objects_cb_changed(self, state):
+ cb_items = [self.grid_layout.itemAt(i).widget() for i in range(self.grid_layout.count())
+ if isinstance(self.grid_layout.itemAt(i).widget(), FCCheckBox)]
+
+ for cb in cb_items:
+ if state:
+ cb.setChecked(True)
+ else:
+ cb.setChecked(False)
+
+ 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/ToolSub.py b/appTools/ToolSub.py
index 5101b12e..cb35383d 100644
--- a/appTools/ToolSub.py
+++ b/appTools/ToolSub.py
@@ -37,159 +37,17 @@ class ToolSub(AppTool):
# meaning geometry that was deformed
aperture_processing_finished = QtCore.pyqtSignal(str, list)
- toolName = _("Subtract 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)
-
- # Title
- title_label = QtWidgets.QLabel("%s" % self.toolName)
- title_label.setStyleSheet("""
- QLabel
- {
- font-size: 16px;
- font-weight: bold;
- }
- """)
- self.tools_box.addWidget(title_label)
-
- # Form Layout
- form_layout = QtWidgets.QFormLayout()
- self.tools_box.addLayout(form_layout)
-
- self.gerber_title = QtWidgets.QLabel("%s" % _("GERBER"))
- form_layout.addRow(self.gerber_title)
-
- # Target Gerber Object
- self.target_gerber_combo = FCComboBox()
- self.target_gerber_combo.setModel(self.app.collection)
- self.target_gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- # self.target_gerber_combo.setCurrentIndex(1)
- self.target_gerber_combo.is_last = True
- self.target_gerber_combo.obj_type = "Gerber"
-
- self.target_gerber_label = QtWidgets.QLabel('%s:' % _("Target"))
- self.target_gerber_label.setToolTip(
- _("Gerber object from which to subtract\n"
- "the subtractor Gerber object.")
- )
-
- form_layout.addRow(self.target_gerber_label, self.target_gerber_combo)
-
- # Substractor Gerber Object
- self.sub_gerber_combo = FCComboBox()
- self.sub_gerber_combo.setModel(self.app.collection)
- self.sub_gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.sub_gerber_combo.is_last = True
- self.sub_gerber_combo.obj_type = "Gerber"
-
- self.sub_gerber_label = QtWidgets.QLabel('%s:' % _("Subtractor"))
- self.sub_gerber_label.setToolTip(
- _("Gerber object that will be subtracted\n"
- "from the target Gerber object.")
- )
- e_lab_1 = QtWidgets.QLabel('')
-
- form_layout.addRow(self.sub_gerber_label, self.sub_gerber_combo)
-
- self.intersect_btn = FCButton(_('Subtract Gerber'))
- self.intersect_btn.setToolTip(
- _("Will remove the area occupied by the subtractor\n"
- "Gerber from the Target Gerber.\n"
- "Can be used to remove the overlapping silkscreen\n"
- "over the soldermask.")
- )
- self.intersect_btn.setStyleSheet("""
- QPushButton
- {
- font-weight: bold;
- }
- """)
- self.tools_box.addWidget(self.intersect_btn)
- self.tools_box.addWidget(e_lab_1)
-
- # Form Layout
- form_geo_layout = QtWidgets.QFormLayout()
- self.tools_box.addLayout(form_geo_layout)
-
- self.geo_title = QtWidgets.QLabel("%s" % _("GEOMETRY"))
- form_geo_layout.addRow(self.geo_title)
-
- # Target Geometry Object
- self.target_geo_combo = FCComboBox()
- self.target_geo_combo.setModel(self.app.collection)
- self.target_geo_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
- # self.target_geo_combo.setCurrentIndex(1)
- self.target_geo_combo.is_last = True
- self.target_geo_combo.obj_type = "Geometry"
-
- self.target_geo_label = QtWidgets.QLabel('%s:' % _("Target"))
- self.target_geo_label.setToolTip(
- _("Geometry object from which to subtract\n"
- "the subtractor Geometry object.")
- )
-
- form_geo_layout.addRow(self.target_geo_label, self.target_geo_combo)
-
- # Substractor Geometry Object
- self.sub_geo_combo = FCComboBox()
- self.sub_geo_combo.setModel(self.app.collection)
- self.sub_geo_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
- self.sub_geo_combo.is_last = True
- self.sub_geo_combo.obj_type = "Geometry"
-
- self.sub_geo_label = QtWidgets.QLabel('%s:' % _("Subtractor"))
- self.sub_geo_label.setToolTip(
- _("Geometry object that will be subtracted\n"
- "from the target Geometry object.")
- )
- e_lab_1 = QtWidgets.QLabel('')
-
- form_geo_layout.addRow(self.sub_geo_label, self.sub_geo_combo)
-
- self.close_paths_cb = FCCheckBox(_("Close paths"))
- self.close_paths_cb.setToolTip(_("Checking this will close the paths cut by the Geometry subtractor object."))
- self.tools_box.addWidget(self.close_paths_cb)
-
- self.intersect_geo_btn = FCButton(_('Subtract Geometry'))
- self.intersect_geo_btn.setToolTip(
- _("Will remove the area occupied by the subtractor\n"
- "Geometry from the Target Geometry.")
- )
- self.intersect_geo_btn.setStyleSheet("""
- QPushButton
- {
- font-weight: bold;
- }
- """)
- self.tools_box.addWidget(self.intersect_geo_btn)
- self.tools_box.addWidget(e_lab_1)
-
- 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)
+ # #############################################################################
+ # ######################### Tool GUI ##########################################
+ # #############################################################################
+ self.ui = SubUI(layout=self.layout, app=self.app)
+ self.toolName = self.ui.toolName
# QTimer for periodic check
self.check_thread = QtCore.QTimer()
@@ -228,11 +86,14 @@ class ToolSub(AppTool):
self.pool = self.app.pool
self.results = []
- self.intersect_btn.clicked.connect(self.on_grb_intersection_click)
- self.intersect_geo_btn.clicked.connect(self.on_geo_intersection_click)
+ # Signals
+ self.ui.intersect_btn.clicked.connect(self.on_grb_intersection_click)
+ self.ui.intersect_geo_btn.clicked.connect(self.on_geo_intersection_click)
+ self.ui.reset_button.clicked.connect(self.set_tool_ui)
+
+ # Custom Signals
self.job_finished.connect(self.on_job_finished)
self.aperture_processing_finished.connect(self.new_gerber_object)
- self.reset_button.clicked.connect(self.set_tool_ui)
def install(self, icon=None, separator=None, **kwargs):
AppTool.install(self, icon, separator, shortcut='Alt+W', **kwargs)
@@ -270,8 +131,8 @@ class ToolSub(AppTool):
self.new_solid_geometry = []
self.target_options.clear()
- self.tools_frame.show()
- self.close_paths_cb.setChecked(self.app.defaults["tools_sub_close_paths"])
+ self.ui.tools_frame.show()
+ self.ui.close_paths_cb.setChecked(self.app.defaults["tools_sub_close_paths"])
def on_grb_intersection_click(self):
# reset previous values
@@ -281,7 +142,7 @@ class ToolSub(AppTool):
self.sub_type = "gerber"
- self.target_grb_obj_name = self.target_gerber_combo.currentText()
+ self.target_grb_obj_name = self.ui.target_gerber_combo.currentText()
if self.target_grb_obj_name == '':
self.app.inform.emit('[ERROR_NOTCL] %s' % _("No Target object loaded."))
return
@@ -296,7 +157,7 @@ class ToolSub(AppTool):
self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), self.obj_name))
return "Could not retrieve object: %s" % self.target_grb_obj_name
- self.sub_grb_obj_name = self.sub_gerber_combo.currentText()
+ self.sub_grb_obj_name = self.ui.sub_gerber_combo.currentText()
if self.sub_grb_obj_name == '':
self.app.inform.emit('[ERROR_NOTCL] %s' % _("No Subtractor object loaded."))
return
@@ -485,10 +346,9 @@ class ToolSub(AppTool):
self.sub_type = "geo"
- self.target_geo_obj_name = self.target_geo_combo.currentText()
+ self.target_geo_obj_name = self.ui.target_geo_combo.currentText()
if self.target_geo_obj_name == '':
- self.app.inform.emit('[ERROR_NOTCL] %s' %
- _("No Target object loaded."))
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _("No Target object loaded."))
return
# Get target object.
@@ -496,14 +356,12 @@ class ToolSub(AppTool):
self.target_geo_obj = self.app.collection.get_by_name(self.target_geo_obj_name)
except Exception as e:
log.debug("ToolSub.on_geo_intersection_click() --> %s" % str(e))
- self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
- (_("Could not retrieve object"), self.target_geo_obj_name))
+ self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), self.target_geo_obj_name))
return "Could not retrieve object: %s" % self.target_grb_obj_name
- self.sub_geo_obj_name = self.sub_geo_combo.currentText()
+ self.sub_geo_obj_name = self.ui.sub_geo_combo.currentText()
if self.sub_geo_obj_name == '':
- self.app.inform.emit('[ERROR_NOTCL] %s' %
- _("No Subtractor object loaded."))
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _("No Subtractor object loaded."))
return
# Get substractor object.
@@ -511,8 +369,7 @@ class ToolSub(AppTool):
self.sub_geo_obj = self.app.collection.get_by_name(self.sub_geo_obj_name)
except Exception as e:
log.debug("ToolSub.on_geo_intersection_click() --> %s" % str(e))
- self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
- (_("Could not retrieve object"), self.sub_geo_obj_name))
+ self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), self.sub_geo_obj_name))
return "Could not retrieve object: %s" % self.sub_geo_obj_name
if self.sub_geo_obj.multigeo:
@@ -529,11 +386,8 @@ class ToolSub(AppTool):
# crate the new_tools dict structure
for tool in self.target_geo_obj.tools:
self.new_tools[tool] = {}
- for key in self.target_geo_obj.tools[tool]:
- if key == 'solid_geometry':
- self.new_tools[tool][key] = []
- else:
- self.new_tools[tool][key] = deepcopy(self.target_geo_obj.tools[tool][key])
+ for key, v in self.target_geo_obj.tools[tool]:
+ self.new_tools[tool][key] = [] if key == 'solid_geometry' else deepcopy(v)
# add the promises
if self.target_geo_obj.multigeo:
@@ -550,12 +404,10 @@ class ToolSub(AppTool):
if self.target_geo_obj.multigeo:
for tool in self.target_geo_obj.tools:
geo = self.target_geo_obj.tools[tool]['solid_geometry']
- self.app.worker_task.emit({'fcn': self.toolgeo_intersection,
- 'params': [tool, geo]})
+ self.app.worker_task.emit({'fcn': self.toolgeo_intersection, 'params': [tool, geo]})
else:
geo = self.target_geo_obj.solid_geometry
- self.app.worker_task.emit({'fcn': self.toolgeo_intersection,
- 'params': ["single", geo]})
+ self.app.worker_task.emit({'fcn': self.toolgeo_intersection, 'params': ["single", geo]})
def toolgeo_intersection(self, tool, geo):
new_geometry = []
@@ -568,7 +420,7 @@ class ToolSub(AppTool):
with self.app.proc_container.new(text):
# resulting paths are closed resulting into Polygons
- if self.close_paths_cb.isChecked():
+ if self.ui.close_paths_cb.isChecked():
new_geo = (cascaded_union(geo)).difference(self.sub_union)
if new_geo:
if not new_geo.is_empty:
@@ -663,14 +515,12 @@ class ToolSub(AppTool):
with self.app.proc_container.new(_("Generating new object ...")):
ret = self.app.app_obj.new_object('geometry', outname, obj_init, autoselected=False)
if ret == 'fail':
- self.app.inform.emit('[ERROR_NOTCL] %s' %
- _('Generating new object failed.'))
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _('Generating new object failed.'))
return
# Register recent file
self.app.file_opened.emit('geometry', outname)
# GUI feedback
- self.app.inform.emit('[success] %s: %s' %
- (_("Created"), outname))
+ self.app.inform.emit('[success] %s: %s' % (_("Created"), outname))
# cleanup
self.new_tools.clear()
@@ -732,13 +582,12 @@ class ToolSub(AppTool):
"""
if succcess is True:
if self.sub_type == "gerber":
- outname = self.target_gerber_combo.currentText() + '_sub'
+ outname = self.ui.target_gerber_combo.currentText() + '_sub'
# intersection jobs finished, start the creation of solid_geometry
- self.app.worker_task.emit({'fcn': self.new_gerber_object,
- 'params': [outname]})
+ self.app.worker_task.emit({'fcn': self.new_gerber_object, 'params': [outname]})
else:
- outname = self.target_geo_combo.currentText() + '_sub'
+ outname = self.ui.target_geo_combo.currentText() + '_sub'
# intersection jobs finished, start the creation of solid_geometry
self.app.worker_task.emit({'fcn': self.new_geo_object, 'params': [outname]})
@@ -746,13 +595,189 @@ class ToolSub(AppTool):
self.app.inform.emit('[ERROR_NOTCL] %s' % _('Generating new object failed.'))
def reset_fields(self):
- self.target_gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.sub_gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.ui.target_gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.ui.sub_gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.target_geo_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
- self.sub_geo_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
+ self.ui.target_geo_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
+ self.ui.sub_geo_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
@staticmethod
def poly2rings(poly):
return [poly.exterior] + [interior for interior in poly.interiors]
-# end of file
+
+
+class SubUI:
+
+ toolName = _("Subtract Tool")
+
+ 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;
+ }
+ """)
+ self.layout.addWidget(title_label)
+ self.layout.addWidget(QtWidgets.QLabel(""))
+
+ 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)
+
+ # Form Layout
+ form_layout = QtWidgets.QFormLayout()
+ self.tools_box.addLayout(form_layout)
+
+ self.gerber_title = QtWidgets.QLabel("%s" % _("GERBER"))
+ form_layout.addRow(self.gerber_title)
+
+ # Target Gerber Object
+ self.target_gerber_combo = FCComboBox()
+ self.target_gerber_combo.setModel(self.app.collection)
+ self.target_gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ # self.target_gerber_combo.setCurrentIndex(1)
+ self.target_gerber_combo.is_last = True
+ self.target_gerber_combo.obj_type = "Gerber"
+
+ self.target_gerber_label = QtWidgets.QLabel('%s:' % _("Target"))
+ self.target_gerber_label.setToolTip(
+ _("Gerber object from which to subtract\n"
+ "the subtractor Gerber object.")
+ )
+
+ form_layout.addRow(self.target_gerber_label, self.target_gerber_combo)
+
+ # Substractor Gerber Object
+ self.sub_gerber_combo = FCComboBox()
+ self.sub_gerber_combo.setModel(self.app.collection)
+ self.sub_gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.sub_gerber_combo.is_last = True
+ self.sub_gerber_combo.obj_type = "Gerber"
+
+ self.sub_gerber_label = QtWidgets.QLabel('%s:' % _("Subtractor"))
+ self.sub_gerber_label.setToolTip(
+ _("Gerber object that will be subtracted\n"
+ "from the target Gerber object.")
+ )
+ e_lab_1 = QtWidgets.QLabel('')
+
+ form_layout.addRow(self.sub_gerber_label, self.sub_gerber_combo)
+
+ self.intersect_btn = FCButton(_('Subtract Gerber'))
+ self.intersect_btn.setToolTip(
+ _("Will remove the area occupied by the subtractor\n"
+ "Gerber from the Target Gerber.\n"
+ "Can be used to remove the overlapping silkscreen\n"
+ "over the soldermask.")
+ )
+ self.intersect_btn.setStyleSheet("""
+ QPushButton
+ {
+ font-weight: bold;
+ }
+ """)
+ self.tools_box.addWidget(self.intersect_btn)
+ self.tools_box.addWidget(e_lab_1)
+
+ # Form Layout
+ form_geo_layout = QtWidgets.QFormLayout()
+ self.tools_box.addLayout(form_geo_layout)
+
+ self.geo_title = QtWidgets.QLabel("%s" % _("GEOMETRY"))
+ form_geo_layout.addRow(self.geo_title)
+
+ # Target Geometry Object
+ self.target_geo_combo = FCComboBox()
+ self.target_geo_combo.setModel(self.app.collection)
+ self.target_geo_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
+ # self.target_geo_combo.setCurrentIndex(1)
+ self.target_geo_combo.is_last = True
+ self.target_geo_combo.obj_type = "Geometry"
+
+ self.target_geo_label = QtWidgets.QLabel('%s:' % _("Target"))
+ self.target_geo_label.setToolTip(
+ _("Geometry object from which to subtract\n"
+ "the subtractor Geometry object.")
+ )
+
+ form_geo_layout.addRow(self.target_geo_label, self.target_geo_combo)
+
+ # Substractor Geometry Object
+ self.sub_geo_combo = FCComboBox()
+ self.sub_geo_combo.setModel(self.app.collection)
+ self.sub_geo_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
+ self.sub_geo_combo.is_last = True
+ self.sub_geo_combo.obj_type = "Geometry"
+
+ self.sub_geo_label = QtWidgets.QLabel('%s:' % _("Subtractor"))
+ self.sub_geo_label.setToolTip(
+ _("Geometry object that will be subtracted\n"
+ "from the target Geometry object.")
+ )
+ e_lab_1 = QtWidgets.QLabel('')
+
+ form_geo_layout.addRow(self.sub_geo_label, self.sub_geo_combo)
+
+ self.close_paths_cb = FCCheckBox(_("Close paths"))
+ self.close_paths_cb.setToolTip(_("Checking this will close the paths cut by the Geometry subtractor object."))
+ self.tools_box.addWidget(self.close_paths_cb)
+
+ self.intersect_geo_btn = FCButton(_('Subtract Geometry'))
+ self.intersect_geo_btn.setToolTip(
+ _("Will remove the area occupied by the subtractor\n"
+ "Geometry from the Target Geometry.")
+ )
+ self.intersect_geo_btn.setStyleSheet("""
+ QPushButton
+ {
+ font-weight: bold;
+ }
+ """)
+ self.tools_box.addWidget(self.intersect_geo_btn)
+ self.tools_box.addWidget(e_lab_1)
+
+ 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)
+
+ # #################################### 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/ToolTransform.py b/appTools/ToolTransform.py
index ec61e416..dbc48f85 100644
--- a/appTools/ToolTransform.py
+++ b/appTools/ToolTransform.py
@@ -7,8 +7,8 @@
from PyQt5 import QtWidgets, QtGui, QtCore
from appTool import AppTool
-from appGUI.GUIElements import FCDoubleSpinner, FCCheckBox, FCButton, OptionalInputSection, FCEntry, FCComboBox, \
- NumericalEvalTupleEntry
+from appGUI.GUIElements import FCDoubleSpinner, FCCheckBox, FCButton, OptionalInputSection, FCComboBox, \
+ NumericalEvalTupleEntry, FCLabel
import numpy as np
@@ -23,449 +23,39 @@ if '_' not in builtins.__dict__:
class ToolTransform(AppTool):
- toolName = _("Object Transform")
- rotateName = _("Rotate")
- skewName = _("Skew/Shear")
- scaleName = _("Scale")
- flipName = _("Mirror (Flip)")
- offsetName = _("Offset")
- bufferName = _("Buffer")
-
def __init__(self, app):
AppTool.__init__(self, app)
self.decimals = self.app.decimals
- # ## 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(''))
-
- # ## Layout
- grid0 = QtWidgets.QGridLayout()
- self.layout.addLayout(grid0)
- grid0.setColumnStretch(0, 0)
- grid0.setColumnStretch(1, 1)
- grid0.setColumnStretch(2, 0)
-
- grid0.addWidget(QtWidgets.QLabel(''))
-
- # Reference
- ref_label = QtWidgets.QLabel('%s:' % _("Reference"))
- ref_label.setToolTip(
- _("The reference point for Rotate, Skew, Scale, Mirror.\n"
- "Can be:\n"
- "- Origin -> it is the 0, 0 point\n"
- "- Selection -> the center of the bounding box of the selected objects\n"
- "- Point -> a custom point defined by X,Y coordinates\n"
- "- Object -> the center of the bounding box of a specific object")
- )
- self.ref_combo = FCComboBox()
- self.ref_items = [_("Origin"), _("Selection"), _("Point"), _("Object")]
- self.ref_combo.addItems(self.ref_items)
-
- grid0.addWidget(ref_label, 0, 0)
- grid0.addWidget(self.ref_combo, 0, 1, 1, 2)
-
- self.point_label = QtWidgets.QLabel('%s:' % _("Value"))
- self.point_label.setToolTip(
- _("A point of reference in format X,Y.")
- )
- self.point_entry = NumericalEvalTupleEntry()
-
- grid0.addWidget(self.point_label, 1, 0)
- grid0.addWidget(self.point_entry, 1, 1, 1, 2)
-
- self.point_button = FCButton(_("Add"))
- self.point_button.setToolTip(
- _("Add point coordinates from clipboard.")
- )
- grid0.addWidget(self.point_button, 2, 0, 1, 3)
-
- # Type of object to be used as reference
- self.type_object_label = QtWidgets.QLabel('%s:' % _("Type"))
- self.type_object_label.setToolTip(
- _("The type of object used as reference.")
- )
-
- self.type_obj_combo = FCComboBox()
- self.type_obj_combo.addItem(_("Gerber"))
- self.type_obj_combo.addItem(_("Excellon"))
- self.type_obj_combo.addItem(_("Geometry"))
-
- self.type_obj_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
- self.type_obj_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/drill16.png"))
- self.type_obj_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
-
- grid0.addWidget(self.type_object_label, 3, 0)
- grid0.addWidget(self.type_obj_combo, 3, 1, 1, 2)
-
- # Object to be used as reference
- self.object_combo = FCComboBox()
- self.object_combo.setModel(self.app.collection)
- self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.object_combo.is_last = True
-
- self.object_combo.setToolTip(
- _("The object used as reference.\n"
- "The used point is the center of it's bounding box.")
- )
- grid0.addWidget(self.object_combo, 4, 0, 1, 3)
-
- separator_line = QtWidgets.QFrame()
- separator_line.setFrameShape(QtWidgets.QFrame.HLine)
- separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid0.addWidget(separator_line, 5, 0, 1, 3)
-
- # ## Rotate Title
- rotate_title_label = QtWidgets.QLabel("%s" % self.rotateName)
- grid0.addWidget(rotate_title_label, 6, 0, 1, 3)
-
- self.rotate_label = QtWidgets.QLabel('%s:' % _("Angle"))
- self.rotate_label.setToolTip(
- _("Angle for Rotation action, in degrees.\n"
- "Float number between -360 and 359.\n"
- "Positive numbers for CW motion.\n"
- "Negative numbers for CCW motion.")
- )
-
- self.rotate_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.rotate_entry.set_precision(self.decimals)
- self.rotate_entry.setSingleStep(45)
- self.rotate_entry.setWrapping(True)
- self.rotate_entry.set_range(-360, 360)
-
- # self.rotate_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
-
- self.rotate_button = FCButton(_("Rotate"))
- self.rotate_button.setToolTip(
- _("Rotate the selected object(s).\n"
- "The point of reference is the middle of\n"
- "the bounding box for all selected objects.")
- )
- self.rotate_button.setMinimumWidth(90)
-
- grid0.addWidget(self.rotate_label, 7, 0)
- grid0.addWidget(self.rotate_entry, 7, 1)
- grid0.addWidget(self.rotate_button, 7, 2)
-
- separator_line = QtWidgets.QFrame()
- separator_line.setFrameShape(QtWidgets.QFrame.HLine)
- separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid0.addWidget(separator_line, 8, 0, 1, 3)
-
- # ## Skew Title
- skew_title_label = QtWidgets.QLabel("%s" % self.skewName)
- grid0.addWidget(skew_title_label, 9, 0, 1, 2)
-
- self.skew_link_cb = FCCheckBox()
- self.skew_link_cb.setText(_("Link"))
- self.skew_link_cb.setToolTip(
- _("Link the Y entry to X entry and copy its content.")
- )
-
- grid0.addWidget(self.skew_link_cb, 9, 2)
-
- self.skewx_label = QtWidgets.QLabel('%s:' % _("X angle"))
- self.skewx_label.setToolTip(
- _("Angle for Skew action, in degrees.\n"
- "Float number between -360 and 360.")
- )
- self.skewx_entry = FCDoubleSpinner(callback=self.confirmation_message)
- # self.skewx_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
- self.skewx_entry.set_precision(self.decimals)
- self.skewx_entry.set_range(-360, 360)
-
- self.skewx_button = FCButton(_("Skew X"))
- self.skewx_button.setToolTip(
- _("Skew/shear the selected object(s).\n"
- "The point of reference is the middle of\n"
- "the bounding box for all selected objects."))
- self.skewx_button.setMinimumWidth(90)
-
- grid0.addWidget(self.skewx_label, 10, 0)
- grid0.addWidget(self.skewx_entry, 10, 1)
- grid0.addWidget(self.skewx_button, 10, 2)
-
- self.skewy_label = QtWidgets.QLabel('%s:' % _("Y angle"))
- self.skewy_label.setToolTip(
- _("Angle for Skew action, in degrees.\n"
- "Float number between -360 and 360.")
- )
- self.skewy_entry = FCDoubleSpinner(callback=self.confirmation_message)
- # self.skewy_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
- self.skewy_entry.set_precision(self.decimals)
- self.skewy_entry.set_range(-360, 360)
-
- self.skewy_button = FCButton(_("Skew Y"))
- self.skewy_button.setToolTip(
- _("Skew/shear the selected object(s).\n"
- "The point of reference is the middle of\n"
- "the bounding box for all selected objects."))
- self.skewy_button.setMinimumWidth(90)
-
- grid0.addWidget(self.skewy_label, 12, 0)
- grid0.addWidget(self.skewy_entry, 12, 1)
- grid0.addWidget(self.skewy_button, 12, 2)
-
- self.ois_sk = OptionalInputSection(self.skew_link_cb, [self.skewy_label, self.skewy_entry, self.skewy_button],
- logic=False)
-
- separator_line = QtWidgets.QFrame()
- separator_line.setFrameShape(QtWidgets.QFrame.HLine)
- separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid0.addWidget(separator_line, 14, 0, 1, 3)
-
- # ## Scale Title
- scale_title_label = QtWidgets.QLabel("%s" % self.scaleName)
- grid0.addWidget(scale_title_label, 15, 0, 1, 2)
-
- self.scale_link_cb = FCCheckBox()
- self.scale_link_cb.setText(_("Link"))
- self.scale_link_cb.setToolTip(
- _("Link the Y entry to X entry and copy its content.")
- )
-
- grid0.addWidget(self.scale_link_cb, 15, 2)
-
- self.scalex_label = QtWidgets.QLabel('%s:' % _("X factor"))
- self.scalex_label.setToolTip(
- _("Factor for scaling on X axis.")
- )
- self.scalex_entry = FCDoubleSpinner(callback=self.confirmation_message)
- # self.scalex_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
- self.scalex_entry.set_precision(self.decimals)
- self.scalex_entry.setMinimum(-1e6)
-
- self.scalex_button = FCButton(_("Scale X"))
- self.scalex_button.setToolTip(
- _("Scale the selected object(s).\n"
- "The point of reference depends on \n"
- "the Scale reference checkbox state."))
- self.scalex_button.setMinimumWidth(90)
-
- grid0.addWidget(self.scalex_label, 17, 0)
- grid0.addWidget(self.scalex_entry, 17, 1)
- grid0.addWidget(self.scalex_button, 17, 2)
-
- self.scaley_label = QtWidgets.QLabel('%s:' % _("Y factor"))
- self.scaley_label.setToolTip(
- _("Factor for scaling on Y axis.")
- )
- self.scaley_entry = FCDoubleSpinner(callback=self.confirmation_message)
- # self.scaley_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
- self.scaley_entry.set_precision(self.decimals)
- self.scaley_entry.setMinimum(-1e6)
-
- self.scaley_button = FCButton(_("Scale Y"))
- self.scaley_button.setToolTip(
- _("Scale the selected object(s).\n"
- "The point of reference depends on \n"
- "the Scale reference checkbox state."))
- self.scaley_button.setMinimumWidth(90)
-
- grid0.addWidget(self.scaley_label, 19, 0)
- grid0.addWidget(self.scaley_entry, 19, 1)
- grid0.addWidget(self.scaley_button, 19, 2)
-
- self.ois_s = OptionalInputSection(self.scale_link_cb,
- [
- self.scaley_label,
- self.scaley_entry,
- self.scaley_button
- ], logic=False)
-
- separator_line = QtWidgets.QFrame()
- separator_line.setFrameShape(QtWidgets.QFrame.HLine)
- separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid0.addWidget(separator_line, 21, 0, 1, 3)
-
- # ## Flip Title
- flip_title_label = QtWidgets.QLabel("%s" % self.flipName)
- grid0.addWidget(flip_title_label, 23, 0, 1, 3)
-
- self.flipx_button = FCButton(_("Flip on X"))
- self.flipx_button.setToolTip(
- _("Flip the selected object(s) over the X axis.")
- )
-
- self.flipy_button = FCButton(_("Flip on Y"))
- self.flipy_button.setToolTip(
- _("Flip the selected object(s) over the X axis.")
- )
-
- hlay0 = QtWidgets.QHBoxLayout()
- grid0.addLayout(hlay0, 25, 0, 1, 3)
-
- hlay0.addWidget(self.flipx_button)
- hlay0.addWidget(self.flipy_button)
-
- separator_line = QtWidgets.QFrame()
- separator_line.setFrameShape(QtWidgets.QFrame.HLine)
- separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid0.addWidget(separator_line, 27, 0, 1, 3)
-
- # ## Offset Title
- offset_title_label = QtWidgets.QLabel("%s" % self.offsetName)
- grid0.addWidget(offset_title_label, 29, 0, 1, 3)
-
- self.offx_label = QtWidgets.QLabel('%s:' % _("X val"))
- self.offx_label.setToolTip(
- _("Distance to offset on X axis. In current units.")
- )
- self.offx_entry = FCDoubleSpinner(callback=self.confirmation_message)
- # self.offx_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
- self.offx_entry.set_precision(self.decimals)
- self.offx_entry.setMinimum(-1e6)
-
- self.offx_button = FCButton(_("Offset X"))
- self.offx_button.setToolTip(
- _("Offset the selected object(s).\n"
- "The point of reference is the middle of\n"
- "the bounding box for all selected objects.\n"))
- self.offx_button.setMinimumWidth(90)
-
- grid0.addWidget(self.offx_label, 31, 0)
- grid0.addWidget(self.offx_entry, 31, 1)
- grid0.addWidget(self.offx_button, 31, 2)
-
- self.offy_label = QtWidgets.QLabel('%s:' % _("Y val"))
- self.offy_label.setToolTip(
- _("Distance to offset on Y axis. In current units.")
- )
- self.offy_entry = FCDoubleSpinner(callback=self.confirmation_message)
- # self.offy_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
- self.offy_entry.set_precision(self.decimals)
- self.offy_entry.setMinimum(-1e6)
-
- self.offy_button = FCButton(_("Offset Y"))
- self.offy_button.setToolTip(
- _("Offset the selected object(s).\n"
- "The point of reference is the middle of\n"
- "the bounding box for all selected objects.\n"))
- self.offy_button.setMinimumWidth(90)
-
- grid0.addWidget(self.offy_label, 32, 0)
- grid0.addWidget(self.offy_entry, 32, 1)
- grid0.addWidget(self.offy_button, 32, 2)
-
- separator_line = QtWidgets.QFrame()
- separator_line.setFrameShape(QtWidgets.QFrame.HLine)
- separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid0.addWidget(separator_line, 34, 0, 1, 3)
-
- # ## Buffer Title
- buffer_title_label = QtWidgets.QLabel("%s" % self.bufferName)
- grid0.addWidget(buffer_title_label, 35, 0, 1, 2)
-
- self.buffer_rounded_cb = FCCheckBox('%s' % _("Rounded"))
- self.buffer_rounded_cb.setToolTip(
- _("If checked then the buffer will surround the buffered shape,\n"
- "every corner will be rounded.\n"
- "If not checked then the buffer will follow the exact geometry\n"
- "of the buffered shape.")
- )
-
- grid0.addWidget(self.buffer_rounded_cb, 35, 2)
-
- self.buffer_label = QtWidgets.QLabel('%s:' % _("Distance"))
- self.buffer_label.setToolTip(
- _("A positive value will create the effect of dilation,\n"
- "while a negative value will create the effect of erosion.\n"
- "Each geometry element of the object will be increased\n"
- "or decreased with the 'distance'.")
- )
-
- self.buffer_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.buffer_entry.set_precision(self.decimals)
- self.buffer_entry.setSingleStep(0.1)
- self.buffer_entry.setWrapping(True)
- self.buffer_entry.set_range(-9999.9999, 9999.9999)
-
- self.buffer_button = FCButton(_("Buffer D"))
- self.buffer_button.setToolTip(
- _("Create the buffer effect on each geometry,\n"
- "element from the selected object, using the distance.")
- )
- self.buffer_button.setMinimumWidth(90)
-
- grid0.addWidget(self.buffer_label, 37, 0)
- grid0.addWidget(self.buffer_entry, 37, 1)
- grid0.addWidget(self.buffer_button, 37, 2)
-
- self.buffer_factor_label = QtWidgets.QLabel('%s:' % _("Value"))
- self.buffer_factor_label.setToolTip(
- _("A positive value will create the effect of dilation,\n"
- "while a negative value will create the effect of erosion.\n"
- "Each geometry element of the object will be increased\n"
- "or decreased to fit the 'Value'. Value is a percentage\n"
- "of the initial dimension.")
- )
-
- self.buffer_factor_entry = FCDoubleSpinner(callback=self.confirmation_message, suffix='%')
- self.buffer_factor_entry.set_range(-100.0000, 1000.0000)
- self.buffer_factor_entry.set_precision(self.decimals)
- self.buffer_factor_entry.setWrapping(True)
- self.buffer_factor_entry.setSingleStep(1)
-
- self.buffer_factor_button = FCButton(_("Buffer F"))
- self.buffer_factor_button.setToolTip(
- _("Create the buffer effect on each geometry,\n"
- "element from the selected object, using the factor.")
- )
- self.buffer_factor_button.setMinimumWidth(90)
-
- grid0.addWidget(self.buffer_factor_label, 38, 0)
- grid0.addWidget(self.buffer_factor_entry, 38, 1)
- grid0.addWidget(self.buffer_factor_button, 38, 2)
-
- grid0.addWidget(QtWidgets.QLabel(''), 42, 0, 1, 3)
-
- 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)
-
+ # #############################################################################
+ # ######################### Tool GUI ##########################################
+ # #############################################################################
+ self.ui = TransformUI(layout=self.layout, app=self.app)
+ self.toolName = self.ui.toolName
+
# ## Signals
- self.ref_combo.currentIndexChanged.connect(self.on_reference_changed)
- self.type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
- self.point_button.clicked.connect(self.on_add_coords)
+ self.ui.ref_combo.currentIndexChanged.connect(self.ui.on_reference_changed)
+ self.ui.type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
+ self.ui.point_button.clicked.connect(self.on_add_coords)
- self.rotate_button.clicked.connect(self.on_rotate)
+ self.ui.rotate_button.clicked.connect(self.on_rotate)
- self.skewx_button.clicked.connect(self.on_skewx)
- self.skewy_button.clicked.connect(self.on_skewy)
+ self.ui.skewx_button.clicked.connect(self.on_skewx)
+ self.ui.skewy_button.clicked.connect(self.on_skewy)
- self.scalex_button.clicked.connect(self.on_scalex)
- self.scaley_button.clicked.connect(self.on_scaley)
+ self.ui.scalex_button.clicked.connect(self.on_scalex)
+ self.ui.scaley_button.clicked.connect(self.on_scaley)
- self.offx_button.clicked.connect(self.on_offx)
- self.offy_button.clicked.connect(self.on_offy)
+ self.ui.offx_button.clicked.connect(self.on_offx)
+ self.ui.offy_button.clicked.connect(self.on_offy)
- self.flipx_button.clicked.connect(self.on_flipx)
- self.flipy_button.clicked.connect(self.on_flipy)
+ self.ui.flipx_button.clicked.connect(self.on_flipx)
+ self.ui.flipy_button.clicked.connect(self.on_flipy)
- self.buffer_button.clicked.connect(self.on_buffer_by_distance)
- self.buffer_factor_button.clicked.connect(self.on_buffer_by_factor)
+ self.ui.buffer_button.clicked.connect(self.on_buffer_by_distance)
+ self.ui.buffer_factor_button.clicked.connect(self.on_buffer_by_factor)
- self.reset_button.clicked.connect(self.set_tool_ui)
+ self.ui.reset_button.clicked.connect(self.set_tool_ui)
def run(self, toggle=True):
self.app.defaults.report_usage("ToolTransform()")
@@ -500,70 +90,44 @@ class ToolTransform(AppTool):
def set_tool_ui(self):
# ## Initialize form
- self.ref_combo.set_value(self.app.defaults["tools_transform_reference"])
- self.type_obj_combo.set_value(self.app.defaults["tools_transform_ref_object"])
- self.point_entry.set_value(self.app.defaults["tools_transform_ref_point"])
- self.rotate_entry.set_value(self.app.defaults["tools_transform_rotate"])
+ self.ui.ref_combo.set_value(self.app.defaults["tools_transform_reference"])
+ self.ui.type_obj_combo.set_value(self.app.defaults["tools_transform_ref_object"])
+ self.ui.point_entry.set_value(self.app.defaults["tools_transform_ref_point"])
+ self.ui.rotate_entry.set_value(self.app.defaults["tools_transform_rotate"])
- self.skewx_entry.set_value(self.app.defaults["tools_transform_skew_x"])
- self.skewy_entry.set_value(self.app.defaults["tools_transform_skew_y"])
- self.skew_link_cb.set_value(self.app.defaults["tools_transform_skew_link"])
+ self.ui.skewx_entry.set_value(self.app.defaults["tools_transform_skew_x"])
+ self.ui.skewy_entry.set_value(self.app.defaults["tools_transform_skew_y"])
+ self.ui.skew_link_cb.set_value(self.app.defaults["tools_transform_skew_link"])
- self.scalex_entry.set_value(self.app.defaults["tools_transform_scale_x"])
- self.scaley_entry.set_value(self.app.defaults["tools_transform_scale_y"])
- self.scale_link_cb.set_value(self.app.defaults["tools_transform_scale_link"])
+ self.ui.scalex_entry.set_value(self.app.defaults["tools_transform_scale_x"])
+ self.ui.scaley_entry.set_value(self.app.defaults["tools_transform_scale_y"])
+ self.ui.scale_link_cb.set_value(self.app.defaults["tools_transform_scale_link"])
- self.offx_entry.set_value(self.app.defaults["tools_transform_offset_x"])
- self.offy_entry.set_value(self.app.defaults["tools_transform_offset_y"])
+ self.ui.offx_entry.set_value(self.app.defaults["tools_transform_offset_x"])
+ self.ui.offy_entry.set_value(self.app.defaults["tools_transform_offset_y"])
- self.buffer_entry.set_value(self.app.defaults["tools_transform_buffer_dis"])
- self.buffer_factor_entry.set_value(self.app.defaults["tools_transform_buffer_factor"])
- self.buffer_rounded_cb.set_value(self.app.defaults["tools_transform_buffer_corner"])
+ self.ui.buffer_entry.set_value(self.app.defaults["tools_transform_buffer_dis"])
+ self.ui.buffer_factor_entry.set_value(self.app.defaults["tools_transform_buffer_factor"])
+ self.ui.buffer_rounded_cb.set_value(self.app.defaults["tools_transform_buffer_corner"])
# initial state is hidden
- self.point_label.hide()
- self.point_entry.hide()
- self.point_button.hide()
+ self.ui.point_label.hide()
+ self.ui.point_entry.hide()
+ self.ui.point_button.hide()
- self.type_object_label.hide()
- self.type_obj_combo.hide()
- self.object_combo.hide()
+ self.ui.type_object_label.hide()
+ self.ui.type_obj_combo.hide()
+ self.ui.object_combo.hide()
def on_type_obj_index_changed(self, index):
- self.object_combo.setRootModelIndex(self.app.collection.index(index, 0, QtCore.QModelIndex()))
- self.object_combo.setCurrentIndex(0)
- self.object_combo.obj_type = {
+ self.ui.object_combo.setRootModelIndex(self.app.collection.index(index, 0, QtCore.QModelIndex()))
+ self.ui.object_combo.setCurrentIndex(0)
+ self.ui.object_combo.obj_type = {
_("Gerber"): "Gerber", _("Excellon"): "Excellon", _("Geometry"): "Geometry"
- }[self.type_obj_combo.get_value()]
-
- def on_reference_changed(self, index):
- if index == 0 or index == 1: # "Origin" or "Selection" reference
- self.point_label.hide()
- self.point_entry.hide()
- self.point_button.hide()
-
- self.type_object_label.hide()
- self.type_obj_combo.hide()
- self.object_combo.hide()
- elif index == 2: # "Point" reference
- self.point_label.show()
- self.point_entry.show()
- self.point_button.show()
-
- self.type_object_label.hide()
- self.type_obj_combo.hide()
- self.object_combo.hide()
- else: # "Object" reference
- self.point_label.hide()
- self.point_entry.hide()
- self.point_button.hide()
-
- self.type_object_label.show()
- self.type_obj_combo.show()
- self.object_combo.show()
+ }[self.ui.type_obj_combo.get_value()]
def on_calculate_reference(self):
- ref_val = self.ref_combo.currentIndex()
+ ref_val = self.ui.ref_combo.currentIndex()
if ref_val == 0: # "Origin" reference
return 0, 0
@@ -578,7 +142,7 @@ class ToolTransform(AppTool):
self.app.inform.emit('[ERROR_NOTCL] %s' % _("No object selected."))
return "fail"
elif ref_val == 2: # "Point" reference
- point_val = self.point_entry.get_value()
+ point_val = self.uipoint_entry.get_value()
try:
px, py = eval('{}'.format(point_val))
return px, py
@@ -586,7 +150,7 @@ class ToolTransform(AppTool):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Incorrect format for Point value. Needs format X,Y"))
return "fail"
else: # "Object" reference
- obj_name = self.object_combo.get_value()
+ obj_name = self.ui.object_combo.get_value()
ref_obj = self.app.collection.get_by_name(obj_name)
xmin, ymin, xmax, ymax = ref_obj.bounds()
px = (xmax + xmin) * 0.5
@@ -595,10 +159,10 @@ class ToolTransform(AppTool):
def on_add_coords(self):
val = self.app.clipboard.text()
- self.point_entry.set_value(val)
+ self.ui.point_entry.set_value(val)
def on_rotate(self):
- value = float(self.rotate_entry.get_value())
+ value = float(self.ui.rotate_entry.get_value())
if value == 0:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Rotate transformation can not be done for a value of 0."))
return
@@ -622,12 +186,12 @@ class ToolTransform(AppTool):
self.app.worker_task.emit({'fcn': self.on_flip, 'params': [axis, point]})
def on_skewx(self):
- xvalue = float(self.skewx_entry.get_value())
+ xvalue = float(self.ui.skewx_entry.get_value())
if xvalue == 0:
return
- if self.skew_link_cb.get_value():
+ if self.ui.skew_link_cb.get_value():
yvalue = xvalue
else:
yvalue = 0
@@ -641,7 +205,7 @@ class ToolTransform(AppTool):
def on_skewy(self):
xvalue = 0
- yvalue = float(self.skewy_entry.get_value())
+ yvalue = float(self.ui.skewy_entry.get_value())
if yvalue == 0:
return
@@ -654,14 +218,14 @@ class ToolTransform(AppTool):
self.app.worker_task.emit({'fcn': self.on_skew, 'params': [axis, xvalue, yvalue, point]})
def on_scalex(self):
- xvalue = float(self.scalex_entry.get_value())
+ xvalue = float(self.ui.scalex_entry.get_value())
if xvalue == 0 or xvalue == 1:
self.app.inform.emit('[WARNING_NOTCL] %s' %
_("Scale transformation can not be done for a factor of 0 or 1."))
return
- if self.scale_link_cb.get_value():
+ if self.ui.scale_link_cb.get_value():
yvalue = xvalue
else:
yvalue = 1
@@ -675,7 +239,7 @@ class ToolTransform(AppTool):
def on_scaley(self):
xvalue = 1
- yvalue = float(self.scaley_entry.get_value())
+ yvalue = float(self.ui.scaley_entry.get_value())
if yvalue == 0 or yvalue == 1:
self.app.inform.emit('[WARNING_NOTCL] %s' %
@@ -690,7 +254,7 @@ class ToolTransform(AppTool):
self.app.worker_task.emit({'fcn': self.on_scale, 'params': [axis, xvalue, yvalue, point]})
def on_offx(self):
- value = float(self.offx_entry.get_value())
+ value = float(self.ui.offx_entry.get_value())
if value == 0:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Offset transformation can not be done for a value of 0."))
return
@@ -699,7 +263,7 @@ class ToolTransform(AppTool):
self.app.worker_task.emit({'fcn': self.on_offset, 'params': [axis, value]})
def on_offy(self):
- value = float(self.offy_entry.get_value())
+ value = float(self.ui.offy_entry.get_value())
if value == 0:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Offset transformation can not be done for a value of 0."))
return
@@ -708,14 +272,14 @@ class ToolTransform(AppTool):
self.app.worker_task.emit({'fcn': self.on_offset, 'params': [axis, value]})
def on_buffer_by_distance(self):
- value = self.buffer_entry.get_value()
- join = 1 if self.buffer_rounded_cb.get_value() else 2
+ value = self.ui.buffer_entry.get_value()
+ join = 1 if self.ui.buffer_rounded_cb.get_value() else 2
self.app.worker_task.emit({'fcn': self.on_buffer_action, 'params': [value, join]})
def on_buffer_by_factor(self):
- value = 1 + self.buffer_factor_entry.get_value() / 100.0
- join = 1 if self.buffer_rounded_cb.get_value() else 2
+ value = 1 + self.ui.buffer_factor_entry.get_value() / 100.0
+ join = 1 if self.ui.buffer_rounded_cb.get_value() else 2
# tell the buffer method to use the factor
factor = True
@@ -876,8 +440,7 @@ class ToolTransform(AppTool):
self.app.inform.emit('[success] %s %s %s...' % (_('Offset on the'), str(axis), _('axis done')))
except Exception as e:
- self.app.inform.emit('[ERROR_NOTCL] %s: %s.' %
- (_("Action was not executed, due of"), str(e)))
+ self.app.inform.emit('[ERROR_NOTCL] %s: %s.' % (_("Action was not executed, due of"), str(e)))
return
def on_buffer_action(self, value, join, factor=None):
@@ -912,8 +475,7 @@ class ToolTransform(AppTool):
except Exception as e:
self.app.log.debug("ToolTransform.on_buffer_action() --> %s" % str(e))
- self.app.inform.emit('[ERROR_NOTCL] %s: %s.' %
- (_("Action was not executed, due of"), str(e)))
+ self.app.inform.emit('[ERROR_NOTCL] %s: %s.' % (_("Action was not executed, due of"), str(e)))
return
@staticmethod
@@ -944,4 +506,472 @@ class ToolTransform(AppTool):
return bounds_rec(obj_list)
-# end of file
+
+class TransformUI:
+
+ toolName = _("Object Transform")
+ rotateName = _("Rotate")
+ skewName = _("Skew/Shear")
+ scaleName = _("Scale")
+ flipName = _("Mirror (Flip)")
+ offsetName = _("Offset")
+ bufferName = _("Buffer")
+
+ 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(""))
+
+ # ## Layout
+ grid0 = QtWidgets.QGridLayout()
+ self.layout.addLayout(grid0)
+ grid0.setColumnStretch(0, 0)
+ grid0.setColumnStretch(1, 1)
+ grid0.setColumnStretch(2, 0)
+
+ grid0.addWidget(FCLabel(''))
+
+ # Reference
+ ref_label = FCLabel('%s:' % _("Reference"))
+ ref_label.setToolTip(
+ _("The reference point for Rotate, Skew, Scale, Mirror.\n"
+ "Can be:\n"
+ "- Origin -> it is the 0, 0 point\n"
+ "- Selection -> the center of the bounding box of the selected objects\n"
+ "- Point -> a custom point defined by X,Y coordinates\n"
+ "- Object -> the center of the bounding box of a specific object")
+ )
+ self.ref_combo = FCComboBox()
+ self.ref_items = [_("Origin"), _("Selection"), _("Point"), _("Object")]
+ self.ref_combo.addItems(self.ref_items)
+
+ grid0.addWidget(ref_label, 0, 0)
+ grid0.addWidget(self.ref_combo, 0, 1, 1, 2)
+
+ self.point_label = FCLabel('%s:' % _("Value"))
+ self.point_label.setToolTip(
+ _("A point of reference in format X,Y.")
+ )
+ self.point_entry = NumericalEvalTupleEntry()
+
+ grid0.addWidget(self.point_label, 1, 0)
+ grid0.addWidget(self.point_entry, 1, 1, 1, 2)
+
+ self.point_button = FCButton(_("Add"))
+ self.point_button.setToolTip(
+ _("Add point coordinates from clipboard.")
+ )
+ grid0.addWidget(self.point_button, 2, 0, 1, 3)
+
+ # Type of object to be used as reference
+ self.type_object_label = FCLabel('%s:' % _("Type"))
+ self.type_object_label.setToolTip(
+ _("The type of object used as reference.")
+ )
+
+ self.type_obj_combo = FCComboBox()
+ self.type_obj_combo.addItem(_("Gerber"))
+ self.type_obj_combo.addItem(_("Excellon"))
+ self.type_obj_combo.addItem(_("Geometry"))
+
+ self.type_obj_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
+ self.type_obj_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/drill16.png"))
+ self.type_obj_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
+
+ grid0.addWidget(self.type_object_label, 3, 0)
+ grid0.addWidget(self.type_obj_combo, 3, 1, 1, 2)
+
+ # Object to be used as reference
+ self.object_combo = FCComboBox()
+ self.object_combo.setModel(self.app.collection)
+ self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.object_combo.is_last = True
+
+ self.object_combo.setToolTip(
+ _("The object used as reference.\n"
+ "The used point is the center of it's bounding box.")
+ )
+ grid0.addWidget(self.object_combo, 4, 0, 1, 3)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 5, 0, 1, 3)
+
+ # ## Rotate Title
+ rotate_title_label = FCLabel("%s" % self.rotateName)
+ grid0.addWidget(rotate_title_label, 6, 0, 1, 3)
+
+ self.rotate_label = FCLabel('%s:' % _("Angle"))
+ self.rotate_label.setToolTip(
+ _("Angle for Rotation action, in degrees.\n"
+ "Float number between -360 and 359.\n"
+ "Positive numbers for CW motion.\n"
+ "Negative numbers for CCW motion.")
+ )
+
+ self.rotate_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.rotate_entry.set_precision(self.decimals)
+ self.rotate_entry.setSingleStep(45)
+ self.rotate_entry.setWrapping(True)
+ self.rotate_entry.set_range(-360, 360)
+
+ # self.rotate_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
+
+ self.rotate_button = FCButton(_("Rotate"))
+ self.rotate_button.setToolTip(
+ _("Rotate the selected object(s).\n"
+ "The point of reference is the middle of\n"
+ "the bounding box for all selected objects.")
+ )
+ self.rotate_button.setMinimumWidth(90)
+
+ grid0.addWidget(self.rotate_label, 7, 0)
+ grid0.addWidget(self.rotate_entry, 7, 1)
+ grid0.addWidget(self.rotate_button, 7, 2)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 8, 0, 1, 3)
+
+ # ## Skew Title
+ skew_title_label = FCLabel("%s" % self.skewName)
+ grid0.addWidget(skew_title_label, 9, 0, 1, 2)
+
+ self.skew_link_cb = FCCheckBox()
+ self.skew_link_cb.setText(_("Link"))
+ self.skew_link_cb.setToolTip(
+ _("Link the Y entry to X entry and copy its content.")
+ )
+
+ grid0.addWidget(self.skew_link_cb, 9, 2)
+
+ self.skewx_label = FCLabel('%s:' % _("X angle"))
+ self.skewx_label.setToolTip(
+ _("Angle for Skew action, in degrees.\n"
+ "Float number between -360 and 360.")
+ )
+ self.skewx_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ # self.skewx_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
+ self.skewx_entry.set_precision(self.decimals)
+ self.skewx_entry.set_range(-360, 360)
+
+ self.skewx_button = FCButton(_("Skew X"))
+ self.skewx_button.setToolTip(
+ _("Skew/shear the selected object(s).\n"
+ "The point of reference is the middle of\n"
+ "the bounding box for all selected objects."))
+ self.skewx_button.setMinimumWidth(90)
+
+ grid0.addWidget(self.skewx_label, 10, 0)
+ grid0.addWidget(self.skewx_entry, 10, 1)
+ grid0.addWidget(self.skewx_button, 10, 2)
+
+ self.skewy_label = FCLabel('%s:' % _("Y angle"))
+ self.skewy_label.setToolTip(
+ _("Angle for Skew action, in degrees.\n"
+ "Float number between -360 and 360.")
+ )
+ self.skewy_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ # self.skewy_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
+ self.skewy_entry.set_precision(self.decimals)
+ self.skewy_entry.set_range(-360, 360)
+
+ self.skewy_button = FCButton(_("Skew Y"))
+ self.skewy_button.setToolTip(
+ _("Skew/shear the selected object(s).\n"
+ "The point of reference is the middle of\n"
+ "the bounding box for all selected objects."))
+ self.skewy_button.setMinimumWidth(90)
+
+ grid0.addWidget(self.skewy_label, 12, 0)
+ grid0.addWidget(self.skewy_entry, 12, 1)
+ grid0.addWidget(self.skewy_button, 12, 2)
+
+ self.ois_sk = OptionalInputSection(self.skew_link_cb, [self.skewy_label, self.skewy_entry, self.skewy_button],
+ logic=False)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 14, 0, 1, 3)
+
+ # ## Scale Title
+ scale_title_label = FCLabel("%s" % self.scaleName)
+ grid0.addWidget(scale_title_label, 15, 0, 1, 2)
+
+ self.scale_link_cb = FCCheckBox()
+ self.scale_link_cb.setText(_("Link"))
+ self.scale_link_cb.setToolTip(
+ _("Link the Y entry to X entry and copy its content.")
+ )
+
+ grid0.addWidget(self.scale_link_cb, 15, 2)
+
+ self.scalex_label = FCLabel('%s:' % _("X factor"))
+ self.scalex_label.setToolTip(
+ _("Factor for scaling on X axis.")
+ )
+ self.scalex_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ # self.scalex_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
+ self.scalex_entry.set_precision(self.decimals)
+ self.scalex_entry.setMinimum(-1e6)
+
+ self.scalex_button = FCButton(_("Scale X"))
+ self.scalex_button.setToolTip(
+ _("Scale the selected object(s).\n"
+ "The point of reference depends on \n"
+ "the Scale reference checkbox state."))
+ self.scalex_button.setMinimumWidth(90)
+
+ grid0.addWidget(self.scalex_label, 17, 0)
+ grid0.addWidget(self.scalex_entry, 17, 1)
+ grid0.addWidget(self.scalex_button, 17, 2)
+
+ self.scaley_label = FCLabel('%s:' % _("Y factor"))
+ self.scaley_label.setToolTip(
+ _("Factor for scaling on Y axis.")
+ )
+ self.scaley_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ # self.scaley_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
+ self.scaley_entry.set_precision(self.decimals)
+ self.scaley_entry.setMinimum(-1e6)
+
+ self.scaley_button = FCButton(_("Scale Y"))
+ self.scaley_button.setToolTip(
+ _("Scale the selected object(s).\n"
+ "The point of reference depends on \n"
+ "the Scale reference checkbox state."))
+ self.scaley_button.setMinimumWidth(90)
+
+ grid0.addWidget(self.scaley_label, 19, 0)
+ grid0.addWidget(self.scaley_entry, 19, 1)
+ grid0.addWidget(self.scaley_button, 19, 2)
+
+ self.ois_s = OptionalInputSection(self.scale_link_cb,
+ [
+ self.scaley_label,
+ self.scaley_entry,
+ self.scaley_button
+ ], logic=False)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 21, 0, 1, 3)
+
+ # ## Flip Title
+ flip_title_label = FCLabel("%s" % self.flipName)
+ grid0.addWidget(flip_title_label, 23, 0, 1, 3)
+
+ self.flipx_button = FCButton(_("Flip on X"))
+ self.flipx_button.setToolTip(
+ _("Flip the selected object(s) over the X axis.")
+ )
+
+ self.flipy_button = FCButton(_("Flip on Y"))
+ self.flipy_button.setToolTip(
+ _("Flip the selected object(s) over the X axis.")
+ )
+
+ hlay0 = QtWidgets.QHBoxLayout()
+ grid0.addLayout(hlay0, 25, 0, 1, 3)
+
+ hlay0.addWidget(self.flipx_button)
+ hlay0.addWidget(self.flipy_button)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 27, 0, 1, 3)
+
+ # ## Offset Title
+ offset_title_label = FCLabel("%s" % self.offsetName)
+ grid0.addWidget(offset_title_label, 29, 0, 1, 3)
+
+ self.offx_label = FCLabel('%s:' % _("X val"))
+ self.offx_label.setToolTip(
+ _("Distance to offset on X axis. In current units.")
+ )
+ self.offx_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ # self.offx_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
+ self.offx_entry.set_precision(self.decimals)
+ self.offx_entry.setMinimum(-1e6)
+
+ self.offx_button = FCButton(_("Offset X"))
+ self.offx_button.setToolTip(
+ _("Offset the selected object(s).\n"
+ "The point of reference is the middle of\n"
+ "the bounding box for all selected objects.\n"))
+ self.offx_button.setMinimumWidth(90)
+
+ grid0.addWidget(self.offx_label, 31, 0)
+ grid0.addWidget(self.offx_entry, 31, 1)
+ grid0.addWidget(self.offx_button, 31, 2)
+
+ self.offy_label = FCLabel('%s:' % _("Y val"))
+ self.offy_label.setToolTip(
+ _("Distance to offset on Y axis. In current units.")
+ )
+ self.offy_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ # self.offy_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
+ self.offy_entry.set_precision(self.decimals)
+ self.offy_entry.setMinimum(-1e6)
+
+ self.offy_button = FCButton(_("Offset Y"))
+ self.offy_button.setToolTip(
+ _("Offset the selected object(s).\n"
+ "The point of reference is the middle of\n"
+ "the bounding box for all selected objects.\n"))
+ self.offy_button.setMinimumWidth(90)
+
+ grid0.addWidget(self.offy_label, 32, 0)
+ grid0.addWidget(self.offy_entry, 32, 1)
+ grid0.addWidget(self.offy_button, 32, 2)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 34, 0, 1, 3)
+
+ # ## Buffer Title
+ buffer_title_label = FCLabel("%s" % self.bufferName)
+ grid0.addWidget(buffer_title_label, 35, 0, 1, 2)
+
+ self.buffer_rounded_cb = FCCheckBox('%s' % _("Rounded"))
+ self.buffer_rounded_cb.setToolTip(
+ _("If checked then the buffer will surround the buffered shape,\n"
+ "every corner will be rounded.\n"
+ "If not checked then the buffer will follow the exact geometry\n"
+ "of the buffered shape.")
+ )
+
+ grid0.addWidget(self.buffer_rounded_cb, 35, 2)
+
+ self.buffer_label = FCLabel('%s:' % _("Distance"))
+ self.buffer_label.setToolTip(
+ _("A positive value will create the effect of dilation,\n"
+ "while a negative value will create the effect of erosion.\n"
+ "Each geometry element of the object will be increased\n"
+ "or decreased with the 'distance'.")
+ )
+
+ self.buffer_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.buffer_entry.set_precision(self.decimals)
+ self.buffer_entry.setSingleStep(0.1)
+ self.buffer_entry.setWrapping(True)
+ self.buffer_entry.set_range(-9999.9999, 9999.9999)
+
+ self.buffer_button = FCButton(_("Buffer D"))
+ self.buffer_button.setToolTip(
+ _("Create the buffer effect on each geometry,\n"
+ "element from the selected object, using the distance.")
+ )
+ self.buffer_button.setMinimumWidth(90)
+
+ grid0.addWidget(self.buffer_label, 37, 0)
+ grid0.addWidget(self.buffer_entry, 37, 1)
+ grid0.addWidget(self.buffer_button, 37, 2)
+
+ self.buffer_factor_label = FCLabel('%s:' % _("Value"))
+ self.buffer_factor_label.setToolTip(
+ _("A positive value will create the effect of dilation,\n"
+ "while a negative value will create the effect of erosion.\n"
+ "Each geometry element of the object will be increased\n"
+ "or decreased to fit the 'Value'. Value is a percentage\n"
+ "of the initial dimension.")
+ )
+
+ self.buffer_factor_entry = FCDoubleSpinner(callback=self.confirmation_message, suffix='%')
+ self.buffer_factor_entry.set_range(-100.0000, 1000.0000)
+ self.buffer_factor_entry.set_precision(self.decimals)
+ self.buffer_factor_entry.setWrapping(True)
+ self.buffer_factor_entry.setSingleStep(1)
+
+ self.buffer_factor_button = FCButton(_("Buffer F"))
+ self.buffer_factor_button.setToolTip(
+ _("Create the buffer effect on each geometry,\n"
+ "element from the selected object, using the factor.")
+ )
+ self.buffer_factor_button.setMinimumWidth(90)
+
+ grid0.addWidget(self.buffer_factor_label, 38, 0)
+ grid0.addWidget(self.buffer_factor_entry, 38, 1)
+ grid0.addWidget(self.buffer_factor_button, 38, 2)
+
+ grid0.addWidget(FCLabel(''), 42, 0, 1, 3)
+
+ self.layout.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.layout.addWidget(self.reset_button)
+
+ # #################################### FINSIHED GUI ###########################
+ # #############################################################################
+
+ def on_reference_changed(self, index):
+ if index == 0 or index == 1: # "Origin" or "Selection" reference
+ self.point_label.hide()
+ self.point_entry.hide()
+ self.point_button.hide()
+
+ self.type_object_label.hide()
+ self.type_obj_combo.hide()
+ self.object_combo.hide()
+ elif index == 2: # "Point" reference
+ self.point_label.show()
+ self.point_entry.show()
+ self.point_button.show()
+
+ self.type_object_label.hide()
+ self.type_obj_combo.hide()
+ self.object_combo.hide()
+ else: # "Object" reference
+ self.point_label.hide()
+ self.point_entry.hide()
+ self.point_button.hide()
+
+ self.type_object_label.show()
+ self.type_obj_combo.show()
+ self.object_combo.show()
+
+ 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)