diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 03dbbfa7..bdee778f 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -1050,6 +1050,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
if apid in self.aperture_macros:
self.apertures_macros.pop(apid)
+ self.on_mark_cb_click_table()
+
def on_scale_aperture_click(self, signal):
try:
factor = self.ui.scale_aperture_entry.get_value()
@@ -1089,7 +1091,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
try:
buff_value = self.ui.buffer_aperture_entry.get_value()
except Exception as e:
- log.debug("FlatCAMGerber.on_scale_aperture_click() --> %s" % str(e))
+ log.debug("FlatCAMGerber.on_buffer_aperture_click() --> %s" % str(e))
self.app.inform.emit(_(
"[ERROR_NOTCL] The aperture buffer value is missing or wrong format."
))
@@ -1106,7 +1108,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
if not self.ui.apertures_table.selectedItems():
self.app.inform.emit(_(
- "[WARNING_NOTCL] No aperture to scale. Select at least one aperture and try again."
+ "[WARNING_NOTCL] No aperture to buffer. Select at least one aperture and try again."
))
return
@@ -1114,7 +1116,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
try:
apid = self.ui.apertures_table.item(x.row(), 1).text()
except Exception as e:
- log.debug("FlatCAMGerber.on_scale_aperture_click() --> %s" % str(e))
+ log.debug("FlatCAMGerber.on_buffer_aperture_click() --> %s" % str(e))
self.apertures[apid]['solid_geometry'] = buffer_recursion(self.apertures[apid]['solid_geometry'])
diff --git a/README.md b/README.md
index fa5bc237..eaf4841a 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+9.04.2019
+
+- Gerber Editor: added buffer and scale tools
+
7.04.2019
- default values for Jump To function is jumping to origin (0, 0)
diff --git a/flatcamEditors/FlatCAMGrbEditor.py b/flatcamEditors/FlatCAMGrbEditor.py
index 5e339a7a..e394528f 100644
--- a/flatcamEditors/FlatCAMGrbEditor.py
+++ b/flatcamEditors/FlatCAMGrbEditor.py
@@ -11,9 +11,11 @@ import threading, time
import copy
from camlib import *
-from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, LengthEntry, RadioSet, SpinBoxDelegate
+from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, LengthEntry, RadioSet, \
+ SpinBoxDelegate, EvalEntry
from flatcamEditors.FlatCAMGeoEditor import FCShapeTool, DrawTool, DrawToolShape, DrawToolUtilityShape, FlatCAMGeoEditor
from FlatCAMObj import FlatCAMGerber
+from FlatCAMTool import FlatCAMTool
import gettext
import FlatCAMTranslation as fcTranslate
@@ -24,6 +26,171 @@ if '_' not in builtins.__dict__:
_ = gettext.gettext
+# class ScaleGrbTool(FlatCAMTool):
+# """
+# Simple input for buffer distance.
+# """
+#
+# toolName = _("Scale")
+#
+# def __init__(self, app, draw_app):
+# FlatCAMTool.__init__(self, app)
+#
+# self.draw_app = draw_app
+#
+# # Title
+# title_label = QtWidgets.QLabel("{name} {tooln} ".format(name=_("Editor"), tooln=self.toolName))
+# title_label.setStyleSheet("""
+# QLabel
+# {
+# font-size: 16px;
+# font-weight: bold;
+# }
+# """)
+# self.layout.addWidget(title_label)
+#
+# # this way I can hide/show the frame
+# self.scale_tool_frame = QtWidgets.QFrame()
+# self.scale_tool_frame.setContentsMargins(0, 0, 0, 0)
+# self.layout.addWidget(self.scale_tool_frame)
+# self.scale_tools_box = QtWidgets.QVBoxLayout()
+# self.scale_tools_box.setContentsMargins(0, 0, 0, 0)
+# self.scale_tool_frame.setLayout(self.scale_tools_box)
+#
+# # Form Layout
+# form_layout = QtWidgets.QFormLayout()
+# self.scale_tools_box.addLayout(form_layout)
+#
+# # Buffer distance
+# self.scale_factor_entry = FCEntry()
+# form_layout.addRow(_("Scale Factor:"), self.scale_factor_entry)
+#
+# # Buttons
+# hlay1 = QtWidgets.QHBoxLayout()
+# self.scale_tools_box.addLayout(hlay1)
+#
+# self.scale_button = QtWidgets.QPushButton(_("Scale"))
+# hlay1.addWidget(self.scale_button)
+#
+# self.layout.addStretch()
+#
+# # Signals
+# self.scale_button.clicked.connect(self.on_scale)
+#
+# # Init GUI
+# self.scale_factor_entry.set_value(1)
+#
+# def run(self):
+# self.app.report_usage("Gerber Editor ToolScale()")
+# FlatCAMTool.run(self)
+#
+# # if the splitter us hidden, display it
+# if self.app.ui.splitter.sizes()[0] == 0:
+# self.app.ui.splitter.setSizes([1, 1])
+#
+# self.app.ui.notebook.setTabText(2, _("Scale Tool"))
+#
+# def on_scale(self):
+# if not self.draw_app.selected:
+# self.app.inform.emit(_("[WARNING_NOTCL] Scale cancelled. No aperture selected."))
+# return
+#
+# try:
+# buffer_distance = float(self.buff_tool.buffer_distance_entry.get_value())
+# except ValueError:
+# # try to convert comma to decimal point. if it's still not working error message and return
+# try:
+# buffer_distance = float(self.buff_tool.buffer_distance_entry.get_value().replace(',', '.'))
+# self.buff_tool.buffer_distance_entry.set_value(buffer_distance)
+# except ValueError:
+# self.app.inform.emit(_("[WARNING_NOTCL] Buffer distance value is missing or wrong format. "
+# "Add it and retry."))
+# return
+# # the cb index start from 0 but the join styles for the buffer start from 1 therefore the adjustment
+# # I populated the combobox such that the index coincide with the join styles value (whcih is really an INT)
+# join_style = self.buff_tool.buffer_corner_cb.currentIndex() + 1
+# self.draw_app.buffer(buffer_distance, join_style)
+# self.app.ui.notebook.setTabText(2, _("Tools"))
+# self.draw_app.app.ui.splitter.setSizes([0, 1])
+#
+# self.deactivate()
+# self.app.inform.emit(_("[success] Done. Scale Tool completed."))
+
+
+class FCScale(FCShapeTool):
+ def __init__(self, draw_app):
+ FCShapeTool.__init__(self, draw_app)
+ self.name = 'scale'
+
+ # self.shape_buffer = self.draw_app.shape_buffer
+ self.draw_app = draw_app
+ self.app = draw_app.app
+
+ self.start_msg = _("Scale the selected Gerber apertures ...")
+ self.origin = (0, 0)
+
+ if self.draw_app.app.ui.splitter.sizes()[0] == 0:
+ self.draw_app.app.ui.splitter.setSizes([1, 1])
+ self.activate()
+
+ def activate(self):
+ self.draw_app.hide_tool('all')
+ self.draw_app.scale_tool_frame.show()
+
+ try:
+ self.draw_app.scale_button.clicked.disconnect()
+ except TypeError:
+ pass
+ self.draw_app.scale_button.clicked.connect(self.on_scale_click)
+
+ def deactivate(self):
+ self.draw_app.scale_button.clicked.disconnect()
+ self.complete = True
+ self.draw_app.select_tool("select")
+ self.draw_app.hide_tool(self.name)
+
+ def on_scale_click(self):
+ self.draw_app.on_scale()
+ self.deactivate()
+
+
+class FCBuffer(FCShapeTool):
+ def __init__(self, draw_app):
+ FCShapeTool.__init__(self, draw_app)
+ self.name = 'buffer'
+
+ # self.shape_buffer = self.draw_app.shape_buffer
+ self.draw_app = draw_app
+ self.app = draw_app.app
+
+ self.start_msg = _("Buffer the selected apertures ...")
+ self.origin = (0, 0)
+
+ if self.draw_app.app.ui.splitter.sizes()[0] == 0:
+ self.draw_app.app.ui.splitter.setSizes([1, 1])
+ self.activate()
+
+ def activate(self):
+ self.draw_app.hide_tool('all')
+ self.draw_app.buffer_tool_frame.show()
+
+ try:
+ self.draw_app.buffer_button.clicked.disconnect()
+ except TypeError:
+ pass
+ self.draw_app.buffer_button.clicked.connect(self.on_buffer_click)
+
+ def deactivate(self):
+ self.draw_app.buffer_button.clicked.disconnect()
+ self.complete = True
+ self.draw_app.select_tool("select")
+ self.draw_app.hide_tool(self.name)
+
+ def on_buffer_click(self):
+ self.draw_app.on_buffer()
+ self.deactivate()
+
+
class FCApertureResize(FCShapeTool):
def __init__(self, draw_app):
DrawTool.__init__(self, draw_app)
@@ -255,7 +422,7 @@ class FCApertureCopy(FCApertureMove):
class FCApertureSelect(DrawTool):
def __init__(self, grb_editor_app):
DrawTool.__init__(self, grb_editor_app)
- self.name = 'drill_select'
+ self.name = 'select'
self.grb_editor_app = grb_editor_app
self.storage = self.grb_editor_app.storage_dict
@@ -264,8 +431,8 @@ class FCApertureSelect(DrawTool):
# here we store all shapes that were selected
self.sel_storage = []
- self.grb_editor_app.resize_frame.hide()
- self.grb_editor_app.array_frame.hide()
+ self.grb_editor_app.hide_tool('all')
+ self.grb_editor_app.hide_tool('select')
def click(self, point):
key_modifier = QtWidgets.QApplication.keyboardModifiers()
@@ -281,60 +448,60 @@ class FCApertureSelect(DrawTool):
self.grb_editor_app.selected = []
def click_release(self, point):
- self.select_shapes(point)
+ # self.select_shapes(point)
return ""
- def select_shapes(self, pos):
- self.grb_editor_app.apertures_table.clearSelection()
-
- for storage in self.grb_editor_app.storage_dict:
- for shape in self.grb_editor_app.storage_dict[storage]['solid_geometry']:
- if Point(pos).within(shape.geo):
- self.sel_storage.append(shape)
- xmin, ymin, xmax, ymax = self.bounds(self.sel_storage)
-
- if pos[0] < xmin or pos[0] > xmax or pos[1] < ymin or pos[1] > ymax:
- self.grb_editor_app.selected = []
- else:
- key_modifier = QtWidgets.QApplication.keyboardModifiers()
- if self.grb_editor_app.app.defaults["global_mselect_key"] == 'Control':
- # if CONTROL key is pressed then we add to the selected list the current shape but if it's already
- # in the selected list, we removed it. Therefore first click selects, second deselects.
- if key_modifier == Qt.ControlModifier:
- if closest_shape in self.grb_editor_app.selected:
- self.grb_editor_app.selected.remove(closest_shape)
- else:
- self.grb_editor_app.selected.append(closest_shape)
- else:
- self.grb_editor_app.selected = []
- self.grb_editor_app.selected.append(closest_shape)
- else:
- if key_modifier == Qt.ShiftModifier:
- if closest_shape in self.grb_editor_app.selected:
- self.grb_editor_app.selected.remove(closest_shape)
- else:
- self.grb_editor_app.selected.append(closest_shape)
- else:
- self.grb_editor_app.selected = []
- self.grb_editor_app.selected.append(closest_shape)
-
- # select the aperture of the selected shape in the tool table
- for storage in self.grb_editor_app.storage_dict:
- for shape_s in self.grb_editor_app.selected:
- if shape_s in self.grb_editor_app.storage_dict[storage]:
- for key in self.grb_editor_app.tool2tooldia:
- if self.grb_editor_app.tool2tooldia[key] == storage:
- item = self.grb_editor_app.apertures_table.item((key - 1), 1)
- self.grb_editor_app.apertures_table.setCurrentItem(item)
- # item.setSelected(True)
- # self.grb_editor_app.apertures_table.selectItem(key - 1)
- # midx = self.grb_editor_app.apertures_table.model().index((key - 1), 0)
- # self.grb_editor_app.apertures_table.setCurrentIndex(midx)
- self.draw_app.last_tool_selected = key
- # delete whatever is in selection storage, there is no longer need for those shapes
- self.sel_storage = []
-
- return ""
+ # def select_shapes(self, pos):
+ # self.grb_editor_app.apertures_table.clearSelection()
+ #
+ # for storage in self.grb_editor_app.storage_dict:
+ # for shape in self.grb_editor_app.storage_dict[storage]['solid_geometry']:
+ # if Point(pos).within(shape.geo):
+ # self.sel_storage.append(shape)
+ # xmin, ymin, xmax, ymax = self.bounds(self.sel_storage)
+ #
+ # if pos[0] < xmin or pos[0] > xmax or pos[1] < ymin or pos[1] > ymax:
+ # self.grb_editor_app.selected = []
+ # else:
+ # key_modifier = QtWidgets.QApplication.keyboardModifiers()
+ # if self.grb_editor_app.app.defaults["global_mselect_key"] == 'Control':
+ # # if CONTROL key is pressed then we add to the selected list the current shape but if it's already
+ # # in the selected list, we removed it. Therefore first click selects, second deselects.
+ # if key_modifier == Qt.ControlModifier:
+ # if closest_shape in self.grb_editor_app.selected:
+ # self.grb_editor_app.selected.remove(closest_shape)
+ # else:
+ # self.grb_editor_app.selected.append(closest_shape)
+ # else:
+ # self.grb_editor_app.selected = []
+ # self.grb_editor_app.selected.append(closest_shape)
+ # else:
+ # if key_modifier == Qt.ShiftModifier:
+ # if closest_shape in self.grb_editor_app.selected:
+ # self.grb_editor_app.selected.remove(closest_shape)
+ # else:
+ # self.grb_editor_app.selected.append(closest_shape)
+ # else:
+ # self.grb_editor_app.selected = []
+ # self.grb_editor_app.selected.append(closest_shape)
+ #
+ # # select the aperture of the selected shape in the tool table
+ # for storage in self.grb_editor_app.storage_dict:
+ # for shape_s in self.grb_editor_app.selected:
+ # if shape_s in self.grb_editor_app.storage_dict[storage]:
+ # for key in self.grb_editor_app.tool2tooldia:
+ # if self.grb_editor_app.tool2tooldia[key] == storage:
+ # item = self.grb_editor_app.apertures_table.item((key - 1), 1)
+ # self.grb_editor_app.apertures_table.setCurrentItem(item)
+ # # item.setSelected(True)
+ # # self.grb_editor_app.apertures_table.selectItem(key - 1)
+ # # midx = self.grb_editor_app.apertures_table.model().index((key - 1), 0)
+ # # self.grb_editor_app.apertures_table.setCurrentIndex(midx)
+ # self.draw_app.last_tool_selected = key
+ # # delete whatever is in selection storage, there is no longer need for those shapes
+ # self.sel_storage = []
+ #
+ # return ""
class FlatCAMGrbEditor(QtCore.QObject):
@@ -385,27 +552,19 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.custom_box = QtWidgets.QVBoxLayout()
layout.addLayout(self.custom_box)
- # add a frame and inside add a vertical box layout. Inside this vbox layout I add all the Drills widgets
- # this way I can hide/show the frame
- self.apertures_frame = QtWidgets.QFrame()
- self.apertures_frame.setContentsMargins(0, 0, 0, 0)
- self.custom_box.addWidget(self.apertures_frame)
- self.apertures_box = QtWidgets.QVBoxLayout()
- self.apertures_box.setContentsMargins(0, 0, 0, 0)
- self.apertures_frame.setLayout(self.apertures_box)
#### Gerber Apertures ####
self.apertures_table_label = QtWidgets.QLabel(_('Apertures:'))
self.apertures_table_label.setToolTip(
_("Apertures Table for the Gerber Object.")
)
- self.apertures_box.addWidget(self.apertures_table_label)
+ self.custom_box.addWidget(self.apertures_table_label)
self.apertures_table = FCTable()
# delegate = SpinBoxDelegate(units=self.units)
# self.apertures_table.setItemDelegateForColumn(1, delegate)
- self.apertures_box.addWidget(self.apertures_table)
+ self.custom_box.addWidget(self.apertures_table)
self.apertures_table.setColumnCount(5)
self.apertures_table.setHorizontalHeaderLabels(['#', _('Code'), _('Type'), _('Size'), _('Dim')])
@@ -425,227 +584,187 @@ class FlatCAMGrbEditor(QtCore.QObject):
" - (dia, nVertices) for P type"))
self.empty_label = QtWidgets.QLabel('')
- self.apertures_box.addWidget(self.empty_label)
+ self.custom_box.addWidget(self.empty_label)
- #### Add a new Tool ####
- self.addaperture_label = QtWidgets.QLabel('%s' % _('Add/Delete Aperture'))
- self.addaperture_label.setToolTip(
- _("Add/Delete an aperture to the aperture list")
- )
- self.apertures_box.addWidget(self.addaperture_label)
+ # add a frame and inside add a vertical box layout. Inside this vbox layout I add all the Apertures widgets
+ # this way I can hide/show the frame
+ self.apertures_frame = QtWidgets.QFrame()
+ self.apertures_frame.setContentsMargins(0, 0, 0, 0)
+ self.custom_box.addWidget(self.apertures_frame)
+ self.apertures_box = QtWidgets.QVBoxLayout()
+ self.apertures_box.setContentsMargins(0, 0, 0, 0)
+ self.apertures_frame.setLayout(self.apertures_box)
+
+ #### Add/Delete an new Aperture ####
grid1 = QtWidgets.QGridLayout()
self.apertures_box.addLayout(grid1)
- addaperture_entry_lbl = QtWidgets.QLabel(_('Aperture Size:'))
- addaperture_entry_lbl.setToolTip(
+ apcode_lbl = QtWidgets.QLabel(_('Aperture Code:'))
+ apcode_lbl.setToolTip(
+ _("Code for the new aperture")
+ )
+ grid1.addWidget(apcode_lbl, 1, 0)
+
+ self.apcodeentry = FCEntry()
+ self.apcodeentry.setValidator(QtGui.QIntValidator(0,999))
+ grid1.addWidget(self.apcodeentry, 1, 1)
+
+ apsize_lbl = QtWidgets.QLabel(_('Aperture Size:'))
+ apsize_lbl.setToolTip(
_("Size for the new aperture")
)
- grid1.addWidget(addaperture_entry_lbl, 0, 0)
+ grid1.addWidget(apsize_lbl, 2, 0)
- hlay = QtWidgets.QHBoxLayout()
- self.addtool_entry = FCEntry()
- self.addtool_entry.setValidator(QtGui.QDoubleValidator(0.0001, 99.9999, 4))
- hlay.addWidget(self.addtool_entry)
+ self.apsize_entry = FCEntry()
+ self.apsize_entry.setValidator(QtGui.QDoubleValidator(0.0001, 99.9999, 4))
+ grid1.addWidget(self.apsize_entry, 2, 1)
- self.addaperture_btn = QtWidgets.QPushButton(_('Add Aperture'))
+ aptype_lbl = QtWidgets.QLabel(_('Aperture Type:'))
+ aptype_lbl.setToolTip(
+ _("Select the type of new aperture. Can be:\n"
+ "C = circular\n"
+ "R = rectangular")
+ )
+ grid1.addWidget(aptype_lbl, 3, 0)
+
+ self.aptype_cb = FCComboBox()
+ self.aptype_cb.addItems(['C', 'R'])
+ grid1.addWidget(self.aptype_cb, 3, 1)
+
+ self.apdim_lbl = QtWidgets.QLabel(_('Aperture Dim:'))
+ self.apdim_lbl.setToolTip(
+ _("Dimensions for the new aperture.\n"
+ "Active only for rectangular apertures (type R).\n"
+ "The format is (width, height)")
+ )
+ grid1.addWidget(self.apdim_lbl, 4, 0)
+
+ self.apdim_entry = EvalEntry()
+ grid1.addWidget(self.apdim_entry, 4, 1)
+
+ apadd_lbl = QtWidgets.QLabel('%s' % _('Add Aperture:'))
+ apadd_lbl.setToolTip(
+ _("Add an aperture to the aperture list")
+ )
+ grid1.addWidget(apadd_lbl, 5, 0)
+
+ self.addaperture_btn = QtWidgets.QPushButton(_('Go'))
self.addaperture_btn.setToolTip(
_( "Add a new aperture to the aperture list")
)
- self.addaperture_btn.setFixedWidth(80)
- hlay.addWidget(self.addaperture_btn)
- grid1.addLayout(hlay, 0, 1)
+ grid1.addWidget(self.addaperture_btn, 5, 1)
- grid2 = QtWidgets.QGridLayout()
- self.apertures_box.addLayout(grid2)
+ apdelete_lbl = QtWidgets.QLabel('%s' % _('Del Aperture:'))
+ apdelete_lbl.setToolTip(
+ _( "Delete a aperture in the aperture list")
+ )
+ grid1.addWidget(apdelete_lbl, 6, 0)
- self.delaperture_btn = QtWidgets.QPushButton(_('Delete Aperture'))
+ self.delaperture_btn = QtWidgets.QPushButton(_('Go'))
self.delaperture_btn.setToolTip(
_( "Delete a aperture in the aperture list")
)
- grid2.addWidget(self.delaperture_btn, 0, 1)
+ grid1.addWidget(self.delaperture_btn, 6, 1)
- # add a frame and inside add a vertical box layout. Inside this vbox layout I add all the aperture widgets
- # this way I can hide/show the frame
- self.resize_frame = QtWidgets.QFrame()
- self.resize_frame.setContentsMargins(0, 0, 0, 0)
- self.apertures_box.addWidget(self.resize_frame)
- self.resize_box = QtWidgets.QVBoxLayout()
- self.resize_box.setContentsMargins(0, 0, 0, 0)
- self.resize_frame.setLayout(self.resize_box)
+ ### BUFFER TOOL ###
- #### Resize a aperture ####
- self.emptyresize_label = QtWidgets.QLabel('')
- self.resize_box.addWidget(self.emptyresize_label)
+ self.buffer_tool_frame = QtWidgets.QFrame()
+ self.buffer_tool_frame.setContentsMargins(0, 0, 0, 0)
+ self.custom_box.addWidget(self.buffer_tool_frame)
+ self.buffer_tools_box = QtWidgets.QVBoxLayout()
+ self.buffer_tools_box.setContentsMargins(0, 0, 0, 0)
+ self.buffer_tool_frame.setLayout(self.buffer_tools_box)
+ self.buffer_tool_frame.hide()
- self.apertureresize_label = QtWidgets.QLabel('%s' % _("Resize Aperture"))
- self.apertureresize_label.setToolTip(
- _("Resize a aperture or a selection of apertures.")
+ # Title
+ buf_title_lbl = QtWidgets.QLabel('%s' % _('Buffer Aperture:'))
+ buf_title_lbl.setToolTip(
+ _("Buffer a aperture in the aperture list")
)
- self.resize_box.addWidget(self.apertureresize_label)
+ self.buffer_tools_box.addWidget(buf_title_lbl)
- grid3 = QtWidgets.QGridLayout()
- self.resize_box.addLayout(grid3)
+ # Form Layout
+ buf_form_layout = QtWidgets.QFormLayout()
+ self.buffer_tools_box.addLayout(buf_form_layout)
- res_entry_lbl = QtWidgets.QLabel(_('Resize Dia:'))
- res_entry_lbl.setToolTip(
- _( "Size to resize to.")
+ # Buffer distance
+ self.buffer_distance_entry = FCEntry()
+ buf_form_layout.addRow(_("Buffer distance:"), self.buffer_distance_entry)
+ self.buffer_corner_lbl = QtWidgets.QLabel(_("Buffer corner:"))
+ self.buffer_corner_lbl.setToolTip(
+ _("There are 3 types of corners:\n"
+ " - 'Round': the corner is rounded.\n"
+ " - 'Square:' the corner is met in a sharp angle.\n"
+ " - 'Beveled:' the corner is a line that directly connects the features meeting in the corner")
)
- grid3.addWidget(res_entry_lbl, 0, 0)
+ self.buffer_corner_cb = FCComboBox()
+ self.buffer_corner_cb.addItem(_("Round"))
+ self.buffer_corner_cb.addItem(_("Square"))
+ self.buffer_corner_cb.addItem(_("Beveled"))
+ buf_form_layout.addRow(self.buffer_corner_lbl, self.buffer_corner_cb)
- hlay2 = QtWidgets.QHBoxLayout()
- self.resdrill_entry = LengthEntry()
- hlay2.addWidget(self.resdrill_entry)
+ # Buttons
+ hlay_buf = QtWidgets.QHBoxLayout()
+ self.buffer_tools_box.addLayout(hlay_buf)
- self.resize_btn = QtWidgets.QPushButton(_('Resize'))
- self.resize_btn.setToolTip(
- _("Resize drill(s)")
+ self.buffer_button = QtWidgets.QPushButton(_("Buffer"))
+ hlay_buf.addWidget(self.buffer_button)
+
+ ### SCALE TOOL ###
+
+ self.scale_tool_frame = QtWidgets.QFrame()
+ self.scale_tool_frame.setContentsMargins(0, 0, 0, 0)
+ self.custom_box.addWidget(self.scale_tool_frame)
+ self.scale_tools_box = QtWidgets.QVBoxLayout()
+ self.scale_tools_box.setContentsMargins(0, 0, 0, 0)
+ self.scale_tool_frame.setLayout(self.scale_tools_box)
+ self.scale_tool_frame.hide()
+
+ # Title
+ scale_title_lbl = QtWidgets.QLabel('%s' % _('Scale Aperture:'))
+ scale_title_lbl.setToolTip(
+ _("Scale a aperture in the aperture list")
)
- self.resize_btn.setFixedWidth(80)
- hlay2.addWidget(self.resize_btn)
- grid3.addLayout(hlay2, 0, 1)
+ self.scale_tools_box.addWidget(scale_title_lbl)
- self.resize_frame.hide()
+ # Form Layout
+ scale_form_layout = QtWidgets.QFormLayout()
+ self.scale_tools_box.addLayout(scale_form_layout)
- # add a frame and inside add a vertical box layout. Inside this vbox layout I add
- # all the add drill array widgets
- # this way I can hide/show the frame
- self.array_frame = QtWidgets.QFrame()
- self.array_frame.setContentsMargins(0, 0, 0, 0)
- self.apertures_box.addWidget(self.array_frame)
- self.array_box = QtWidgets.QVBoxLayout()
- self.array_box.setContentsMargins(0, 0, 0, 0)
- self.array_frame.setLayout(self.array_box)
-
- #### Add DRILL Array ####
- self.emptyarray_label = QtWidgets.QLabel('')
- self.array_box.addWidget(self.emptyarray_label)
-
- self.drillarray_label = QtWidgets.QLabel('%s' % _("Add Drill Array"))
- self.drillarray_label.setToolTip(
- _("Add an array of drills (linear or circular array)")
+ self.scale_factor_lbl = QtWidgets.QLabel(_("Scale factor:"))
+ self.scale_factor_lbl.setToolTip(
+ _("The factor by which to scale the selected aperture.\n"
+ "Values can be between 0.0000 and 999.9999")
)
- self.array_box.addWidget(self.drillarray_label)
+ self.scale_factor_entry = FCEntry()
+ self.scale_factor_entry.setValidator(QtGui.QDoubleValidator(0.0000, 999.9999, 4))
+ scale_form_layout.addRow(self.scale_factor_lbl, self.scale_factor_entry)
- self.array_type_combo = FCComboBox()
- self.array_type_combo.setToolTip(
- _( "Select the type of drills array to create.\n"
- "It can be Linear X(Y) or Circular")
- )
- self.array_type_combo.addItem(_("Linear"))
- self.array_type_combo.addItem(_("Circular"))
+ # Buttons
+ hlay_scale = QtWidgets.QHBoxLayout()
+ self.scale_tools_box.addLayout(hlay_scale)
- self.array_box.addWidget(self.array_type_combo)
+ self.scale_button = QtWidgets.QPushButton(_("Scale"))
+ hlay_scale.addWidget(self.scale_button)
- self.array_form = QtWidgets.QFormLayout()
- self.array_box.addLayout(self.array_form)
- self.drill_array_size_label = QtWidgets.QLabel(_('Nr of drills:'))
- self.drill_array_size_label.setToolTip(
- _("Specify how many drills to be in the array.")
- )
- self.drill_array_size_label.setFixedWidth(100)
-
- self.drill_array_size_entry = LengthEntry()
- self.array_form.addRow(self.drill_array_size_label, self.drill_array_size_entry)
-
- self.array_linear_frame = QtWidgets.QFrame()
- self.array_linear_frame.setContentsMargins(0, 0, 0, 0)
- self.array_box.addWidget(self.array_linear_frame)
- self.linear_box = QtWidgets.QVBoxLayout()
- self.linear_box.setContentsMargins(0, 0, 0, 0)
- self.array_linear_frame.setLayout(self.linear_box)
-
- self.linear_form = QtWidgets.QFormLayout()
- self.linear_box.addLayout(self.linear_form)
-
- self.drill_axis_label = QtWidgets.QLabel(_('Direction:'))
- self.drill_axis_label.setToolTip(
- _("Direction on which the linear array is oriented:\n"
- "- 'X' - horizontal axis \n"
- "- 'Y' - vertical axis or \n"
- "- 'Angle' - a custom angle for the array inclination")
- )
- self.drill_axis_label.setFixedWidth(100)
-
- self.drill_axis_radio = RadioSet([{'label': 'X', 'value': 'X'},
- {'label': 'Y', 'value': 'Y'},
- {'label': _('Angle'), 'value': 'A'}])
- self.drill_axis_radio.set_value('X')
- self.linear_form.addRow(self.drill_axis_label, self.drill_axis_radio)
-
- self.drill_pitch_label = QtWidgets.QLabel(_('Pitch:'))
- self.drill_pitch_label.setToolTip(
- _("Pitch = Distance between elements of the array.")
- )
- self.drill_pitch_label.setFixedWidth(100)
-
- self.drill_pitch_entry = LengthEntry()
- self.linear_form.addRow(self.drill_pitch_label, self.drill_pitch_entry)
-
- self.linear_angle_label = QtWidgets.QLabel(_('Angle:'))
- self.linear_angle_label.setToolTip(
- _( "Angle at which the linear array is placed.\n"
- "The precision is of max 2 decimals.\n"
- "Min value is: -359.99 degrees.\n"
- "Max value is: 360.00 degrees.")
- )
- self.linear_angle_label.setFixedWidth(100)
-
- self.linear_angle_spinner = FCDoubleSpinner()
- self.linear_angle_spinner.set_precision(2)
- self.linear_angle_spinner.setRange(-359.99, 360.00)
- self.linear_form.addRow(self.linear_angle_label, self.linear_angle_spinner)
-
- self.array_circular_frame = QtWidgets.QFrame()
- self.array_circular_frame.setContentsMargins(0, 0, 0, 0)
- self.array_box.addWidget(self.array_circular_frame)
- self.circular_box = QtWidgets.QVBoxLayout()
- self.circular_box.setContentsMargins(0, 0, 0, 0)
- self.array_circular_frame.setLayout(self.circular_box)
-
- self.drill_direction_label = QtWidgets.QLabel(_('Direction:'))
- self.drill_direction_label.setToolTip(
- _( "Direction for circular array."
- "Can be CW = clockwise or CCW = counter clockwise.")
- )
- self.drill_direction_label.setFixedWidth(100)
-
- self.circular_form = QtWidgets.QFormLayout()
- self.circular_box.addLayout(self.circular_form)
-
- self.drill_direction_radio = RadioSet([{'label': 'CW', 'value': 'CW'},
- {'label': 'CCW.', 'value': 'CCW'}])
- self.drill_direction_radio.set_value('CW')
- self.circular_form.addRow(self.drill_direction_label, self.drill_direction_radio)
-
- self.drill_angle_label = QtWidgets.QLabel(_('Angle:'))
- self.drill_angle_label.setToolTip(
- _("Angle at which each element in circular array is placed.")
- )
- self.drill_angle_label.setFixedWidth(100)
-
- self.drill_angle_entry = LengthEntry()
- self.circular_form.addRow(self.drill_angle_label, self.drill_angle_entry)
-
- self.array_circular_frame.hide()
-
- self.linear_angle_spinner.hide()
- self.linear_angle_label.hide()
-
- self.array_frame.hide()
- self.apertures_box.addStretch()
+ self.custom_box.addStretch()
## Toolbar events and properties
self.tools_gerber = {
- "select": {"button": self.app.ui.select_drill_btn,
+ "select": {"button": self.app.ui.grb_select_btn,
"constructor": FCApertureSelect},
- "drill_resize": {"button": self.app.ui.resize_drill_btn,
- "constructor": FCApertureResize},
- "drill_copy": {"button": self.app.ui.copy_drill_btn,
- "constructor": FCApertureCopy},
- "drill_move": {"button": self.app.ui.move_drill_btn,
- "constructor": FCApertureMove},
+ "aperture_buffer": {"button": self.app.ui.aperture_buffer_btn,
+ "constructor": FCBuffer},
+ "aperture_scale": {"button": self.app.ui.aperture_scale_btn,
+ "constructor": FCScale},
+ # "aperture_resize": {"button": self.app.ui.resize_aperture_btn,
+ # "constructor": FCApertureResize},
+ # "ap_geometry_copy": {"button": self.app.ui.copy_ap_geometry_btn,
+ # "constructor": FCApertureCopy},
+ # "ap_geometry_move": {"button": self.app.ui.move_drill_btn,
+ # "constructor": FCApertureMove},
}
### Data
@@ -654,9 +773,6 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.storage_dict = {}
self.current_storage = []
- # build the data from the Excellon point into a dictionary
- # {tool_dia: [geometry_in_points]}
- self.points_edit = {}
self.sorted_apid =[]
self.new_apertures = {}
@@ -682,33 +798,35 @@ class FlatCAMGrbEditor(QtCore.QObject):
# this var will store the state of the toolbar before starting the editor
self.toolbar_old_state = False
+ # Signals
+ self.buffer_button.clicked.connect(self.on_buffer)
+ self.scale_button.clicked.connect(self.on_scale)
+
self.app.ui.delete_drill_btn.triggered.connect(self.on_delete_btn)
self.name_entry.returnPressed.connect(self.on_name_activate)
+
+ self.aptype_cb.currentIndexChanged[str].connect(self.on_aptype_changed)
+
self.addaperture_btn.clicked.connect(self.on_aperture_add)
- # self.addtool_entry.editingFinished.connect(self.on_tool_add)
self.delaperture_btn.clicked.connect(self.on_aperture_delete)
self.apertures_table.selectionModel().currentChanged.connect(self.on_row_selected)
- self.array_type_combo.currentIndexChanged.connect(self.on_array_type_combo)
- self.drill_axis_radio.activated_custom.connect(self.on_linear_angle_radio)
+ self.app.ui.grb_resize_aperture_menuitem.triggered.connect(self.exc_resize_drills)
+ self.app.ui.grb_copy_menuitem.triggered.connect(self.exc_copy_drills)
+ self.app.ui.grb_delete_menuitem.triggered.connect(self.on_delete_btn)
-
- self.app.ui.exc_resize_drill_menuitem.triggered.connect(self.exc_resize_drills)
- self.app.ui.exc_copy_drill_menuitem.triggered.connect(self.exc_copy_drills)
- self.app.ui.exc_delete_drill_menuitem.triggered.connect(self.on_delete_btn)
-
- self.app.ui.exc_move_drill_menuitem.triggered.connect(self.exc_move_drills)
+ self.app.ui.grb_move_menuitem.triggered.connect(self.exc_move_drills)
# Init GUI
- self.drill_array_size_entry.set_value(5)
- self.drill_pitch_entry.set_value(2.54)
- self.drill_angle_entry.set_value(12)
- self.drill_direction_radio.set_value('CW')
- self.drill_axis_radio.set_value('X')
+ self.apdim_lbl.hide()
+ self.apdim_entry.hide()
self.gerber_obj = None
self.gerber_obj_options = {}
+ self.buffer_distance_entry.set_value(0.01)
+ self.scale_factor_entry.set_value(1.0)
+
# VisPy Visuals
self.shapes = self.app.plotcanvas.new_shape_collection(layers=1)
self.tool_shape = self.app.plotcanvas.new_shape_collection(layers=1)
@@ -813,9 +931,9 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.name_entry.set_value(self.edited_obj_name)
if self.units == "IN":
- self.addtool_entry.set_value(0.039)
+ self.apsize_entry.set_value(0.039)
else:
- self.addtool_entry.set_value(1.00)
+ self.apsize_entry.set_value(1.00)
self.apertures_row = 0
aper_no = self.apertures_row + 1
@@ -942,7 +1060,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
ap_id = apid
else:
try:
- ap_id = str(self.addtool_entry.get_value())
+ ap_id = str(self.apsize_entry.get_value())
except ValueError:
return
@@ -1083,6 +1201,14 @@ class FlatCAMGrbEditor(QtCore.QObject):
def on_name_activate(self):
self.edited_obj_name = self.name_entry.get_value()
+ def on_aptype_changed(self, current_text):
+ if current_text == 'R':
+ self.apdim_lbl.show()
+ self.apdim_entry.show()
+ else:
+ self.apdim_lbl.hide()
+ self.apdim_entry.hide()
+
def activate(self):
self.connect_canvas_event_handlers()
@@ -1384,6 +1510,10 @@ class FlatCAMGrbEditor(QtCore.QObject):
else:
grb_obj.options[k] = deepcopy(v)
+ grb_obj.source_file = []
+ grb_obj.multigeo = False
+ grb_obj.follow = False
+
try:
grb_obj.create_geometry()
except KeyError:
@@ -2003,14 +2133,6 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.linear_angle_spinner.hide()
self.linear_angle_label.hide()
- def exc_add_drill(self):
- self.select_tool('add')
- return
-
- def exc_add_drill_array(self):
- self.select_tool('add_array')
- return
-
def exc_resize_drills(self):
self.select_tool('resize')
return
@@ -2021,4 +2143,111 @@ class FlatCAMGrbEditor(QtCore.QObject):
def exc_move_drills(self):
self.select_tool('move')
- return
\ No newline at end of file
+ return
+
+ def on_buffer(self):
+ buff_value = 0.01
+ log.debug("FlatCAMGrbEditor.on_buffer()")
+
+ try:
+ buff_value = float(self.buffer_distance_entry.get_value())
+ except ValueError:
+ # try to convert comma to decimal point. if it's still not working error message and return
+ try:
+ buff_value = float(self.buffer_distance_entry.get_value().replace(',', '.'))
+ self.buffer_distance_entry.set_value(buff_value)
+ except ValueError:
+ self.app.inform.emit(_("[WARNING_NOTCL] Buffer distance value is missing or wrong format. "
+ "Add it and retry."))
+ return
+ # the cb index start from 0 but the join styles for the buffer start from 1 therefore the adjustment
+ # I populated the combobox such that the index coincide with the join styles value (whcih is really an INT)
+ join_style = self.buffer_corner_cb.currentIndex() + 1
+
+ def buffer_recursion(geom):
+ if type(geom) == list or type(geom) is MultiPolygon:
+ geoms = list()
+ for local_geom in geom:
+ geoms.append(buffer_recursion(local_geom))
+ return geoms
+ else:
+ return DrawToolShape(geom.geo.buffer(buff_value, join_style=join_style))
+
+ if not self.apertures_table.selectedItems():
+ self.app.inform.emit(_(
+ "[WARNING_NOTCL] No aperture to buffer. Select at least one aperture and try again."
+ ))
+ return
+
+ for x in self.apertures_table.selectedItems():
+ try:
+ apid = self.apertures_table.item(x.row(), 1).text()
+
+ temp_storage = deepcopy(buffer_recursion(self.storage_dict[apid]['solid_geometry']))
+ self.storage_dict[apid]['solid_geometry'] = []
+ self.storage_dict[apid]['solid_geometry'] = temp_storage
+
+ except Exception as e:
+ log.debug("FlatCAMGrbEditor.buffer() --> %s" % str(e))
+
+ self.plot_all()
+ self.app.inform.emit(_("[success] Done. Buffer Tool completed."))
+
+ def on_scale(self):
+ scale_factor = 1.0
+ log.debug("FlatCAMGrbEditor.on_scale()")
+
+ try:
+ scale_factor = float(self.scale_factor_entry.get_value())
+ except ValueError:
+ # try to convert comma to decimal point. if it's still not working error message and return
+ try:
+ scale_factor = float(self.scale_factor_entry.get_value().replace(',', '.'))
+ self.scale_factor_entry.set_value(scale_factor)
+ except ValueError:
+ self.app.inform.emit(_("[WARNING_NOTCL] Scale factor value is missing or wrong format. "
+ "Add it and retry."))
+ return
+
+ def scale_recursion(geom):
+ if type(geom) == list or type(geom) is MultiPolygon:
+ geoms = list()
+ for local_geom in geom:
+ geoms.append(scale_recursion(local_geom))
+ return geoms
+ else:
+ return DrawToolShape(affinity.scale(geom.geo, scale_factor, scale_factor, origin='center'))
+
+ if not self.apertures_table.selectedItems():
+ self.app.inform.emit(_(
+ "[WARNING_NOTCL] No aperture to scale. Select at least one aperture and try again."
+ ))
+ return
+
+ for x in self.apertures_table.selectedItems():
+ try:
+ apid = self.apertures_table.item(x.row(), 1).text()
+
+ temp_storage = deepcopy(scale_recursion(self.storage_dict[apid]['solid_geometry']))
+ self.storage_dict[apid]['solid_geometry'] = []
+ self.storage_dict[apid]['solid_geometry'] = temp_storage
+
+ except Exception as e:
+ log.debug("FlatCAMGrbEditor.on_scale() --> %s" % str(e))
+
+ self.plot_all()
+ self.app.inform.emit(_("[success] Done. Scale Tool completed."))
+
+ def hide_tool(self, tool_name):
+ # self.app.ui.notebook.setTabText(2, _("Tools"))
+
+ if tool_name == 'all':
+ self.apertures_frame.hide()
+ if tool_name == 'select':
+ self.apertures_frame.show()
+ if tool_name == 'buffer' or tool_name == 'all':
+ self.buffer_tool_frame.hide()
+ if tool_name == 'scale' or tool_name == 'all':
+ self.scale_tool_frame.hide()
+
+ self.app.ui.notebook.setCurrentWidget(self.app.ui.selected_tab)
\ No newline at end of file
diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py
index edf16075..2551d18b 100644
--- a/flatcamGUI/FlatCAMGUI.py
+++ b/flatcamGUI/FlatCAMGUI.py
@@ -670,6 +670,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
### Gerber Editor Toolbar ###
self.grb_select_btn = self.grb_edit_toolbar.addAction(QtGui.QIcon('share/pointer32.png'), _("Select"))
+ self.aperture_buffer_btn = self.grb_edit_toolbar.addAction(QtGui.QIcon('share/buffer16-2.png'), _('Buffer'))
+ self.aperture_scale_btn = self.grb_edit_toolbar.addAction(QtGui.QIcon('share/scale32.png'), _('Scale'))
### Snap Toolbar ###
@@ -2398,9 +2400,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.app.grb_editor.delete_utility_geometry()
- self.app.grb_editor.replot()
- # self.select_btn.setChecked(True)
- # self.on_tool_select('select')
+ self.app.grb_editor.plot_all()
self.app.grb_editor.select_tool('select')
return
diff --git a/share/scale32.png b/share/scale32.png
new file mode 100644
index 00000000..e6ded178
Binary files /dev/null and b/share/scale32.png differ