From 9505ecf80f37cde69f8be8424c9fc45534c072c7 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 9 Jan 2020 15:56:41 +0200
Subject: [PATCH 001/209] - working on new NCC tool
---
flatcamTools/ToolNonCopperClear.py | 186 +++++++++++------------------
1 file changed, 72 insertions(+), 114 deletions(-)
diff --git a/flatcamTools/ToolNonCopperClear.py b/flatcamTools/ToolNonCopperClear.py
index 9a6e047e..c97f0ac3 100644
--- a/flatcamTools/ToolNonCopperClear.py
+++ b/flatcamTools/ToolNonCopperClear.py
@@ -311,30 +311,35 @@ class NonCopperClear(FlatCAMTool, Gerber):
"with the diameter specified above.")
)
+ self.addtool_from_db_btn = QtWidgets.QPushButton(_('Add from DB'))
+ self.addtool_from_db_btn.setToolTip(
+ _("Add a new tool to the Tool Table\n"
+ "from the Tool DataBase.")
+ )
+
+ hlay.addWidget(self.addtool_btn)
+ hlay.addWidget(self.addtool_from_db_btn)
+
+ self.grid3.addLayout(hlay, 7, 0, 1, 2)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.grid3.addWidget(separator_line, 8, 0, 1, 2)
+
self.deltool_btn = QtWidgets.QPushButton(_('Delete'))
self.deltool_btn.setToolTip(
_("Delete a selection of tools in the Tool Table\n"
"by first selecting a row(s) in the Tool Table.")
)
+ self.grid3.addWidget(self.deltool_btn, 9, 0, 1, 2)
- hlay.addWidget(self.addtool_btn)
- hlay.addWidget(self.deltool_btn)
-
- self.grid3.addLayout(hlay, 7, 0, 1, 2)
-
- self.addtool_from_db_btn = QtWidgets.QPushButton(_('Add Tool from DataBase'))
- self.addtool_from_db_btn.setToolTip(
- _("Add a new tool to the Tool Table\n"
- "from the Tool DataBase.")
- )
- self.grid3.addWidget(self.addtool_from_db_btn, 8, 0, 1, 2)
-
- self.grid3.addWidget(QtWidgets.QLabel(''), 9, 0, 1, 2)
+ self.grid3.addWidget(QtWidgets.QLabel(''), 10, 0, 1, 2)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.grid3.addWidget(separator_line, 10, 0, 1, 2)
+ self.grid3.addWidget(separator_line, 11, 0, 1, 2)
self.tool_data_label = QtWidgets.QLabel(
"%s: %s %d" % (_('Parameters for'), _("Tool"), int(1)))
@@ -344,7 +349,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
"Each tool store it's own set of such data."
)
)
- self.grid3.addWidget(self.tool_data_label, 11, 0, 1, 2)
+ self.grid3.addWidget(self.tool_data_label, 12, 0, 1, 2)
# Overlap Entry
nccoverlabel = QtWidgets.QLabel('%s:' % _('Overlap Rate'))
@@ -364,8 +369,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.ncc_overlap_entry.setSingleStep(0.1)
self.ncc_overlap_entry.setObjectName(_("Overlap Rate"))
- self.grid3.addWidget(nccoverlabel, 12, 0)
- self.grid3.addWidget(self.ncc_overlap_entry, 12, 1)
+ self.grid3.addWidget(nccoverlabel, 13, 0)
+ self.grid3.addWidget(self.ncc_overlap_entry, 13, 1)
# Margin
nccmarginlabel = QtWidgets.QLabel('%s:' % _('Margin'))
@@ -377,8 +382,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.ncc_margin_entry.set_range(-9999.9999, 9999.9999)
self.ncc_margin_entry.setObjectName(_("Margin"))
- self.grid3.addWidget(nccmarginlabel, 13, 0)
- self.grid3.addWidget(self.ncc_margin_entry, 13, 1)
+ self.grid3.addWidget(nccmarginlabel, 14, 0)
+ self.grid3.addWidget(self.ncc_margin_entry, 14, 1)
# Method
methodlabel = QtWidgets.QLabel('%s:' % _('Method'))
@@ -395,8 +400,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
], orientation='vertical', stretch=False)
self.ncc_method_radio.setObjectName(_("Method"))
- self.grid3.addWidget(methodlabel, 14, 0)
- self.grid3.addWidget(self.ncc_method_radio, 14, 1)
+ self.grid3.addWidget(methodlabel, 15, 0)
+ self.grid3.addWidget(self.ncc_method_radio, 15, 1)
# Connect lines
self.ncc_connect_cb = FCCheckBox('%s' % _("Connect"))
@@ -406,7 +411,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
_("Draw lines between resulting\n"
"segments to minimize tool lifts.")
)
- self.grid3.addWidget(self.ncc_connect_cb, 15, 0, 1, 2)
+ self.grid3.addWidget(self.ncc_connect_cb, 16, 0, 1, 2)
# Contour
self.ncc_contour_cb = FCCheckBox('%s' % _("Contour"))
@@ -416,7 +421,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
_("Cut around the perimeter of the polygon\n"
"to trim rough edges.")
)
- self.grid3.addWidget(self.ncc_contour_cb, 16, 0, 1, 2)
+ self.grid3.addWidget(self.ncc_contour_cb, 17, 0, 1, 2)
# Rest Machining
self.ncc_rest_cb = FCCheckBox('%s' % _("Rest Machining"))
@@ -432,7 +437,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
"If not checked, use the standard algorithm.")
)
- self.grid3.addWidget(self.ncc_rest_cb, 17, 0, 1, 2)
+ self.grid3.addWidget(self.ncc_rest_cb, 18, 0, 1, 2)
# ## NCC Offset choice
self.ncc_choice_offset_cb = FCCheckBox('%s' % _("Offset"))
@@ -444,7 +449,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
"from the copper features.\n"
"The value can be between 0 and 10 FlatCAM units.")
)
- self.grid3.addWidget(self.ncc_choice_offset_cb, 18, 0, 1, 2)
+ self.grid3.addWidget(self.ncc_choice_offset_cb, 19, 0, 1, 2)
# ## NCC Offset value
self.ncc_offset_label = QtWidgets.QLabel('%s:' % _("Offset value"))
@@ -466,8 +471,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
else:
self.ncc_offset_spinner.setSingleStep(0.01)
- self.grid3.addWidget(self.ncc_offset_label, 19, 0)
- self.grid3.addWidget(self.ncc_offset_spinner, 19, 1)
+ self.grid3.addWidget(self.ncc_offset_label, 20, 0)
+ self.grid3.addWidget(self.ncc_offset_spinner, 20, 1)
self.ncc_offset_label.hide()
self.ncc_offset_spinner.hide()
@@ -486,11 +491,11 @@ class NonCopperClear(FlatCAMTool, Gerber):
"- 'Area Selection' - left mouse click to start selection of the area to be painted.\n"
"- 'Reference Object' - will do non copper clearing within the area specified by another object.")
)
- self.grid3.addWidget(self.reference_label, 20, 0)
- self.grid3.addWidget(self.reference_radio, 20, 1)
+ self.grid3.addWidget(self.reference_label, 21, 0)
+ self.grid3.addWidget(self.reference_radio, 21, 1)
form1 = QtWidgets.QFormLayout()
- self.grid3.addLayout(form1, 21, 0, 1, 2)
+ self.grid3.addLayout(form1, 22, 0, 1, 2)
self.box_combo_type_label = QtWidgets.QLabel('%s:' % _("Ref. Type"))
self.box_combo_type_label.setToolTip(
@@ -521,14 +526,14 @@ class NonCopperClear(FlatCAMTool, Gerber):
separator_line2 = QtWidgets.QFrame()
separator_line2.setFrameShape(QtWidgets.QFrame.HLine)
separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.grid3.addWidget(separator_line2, 22, 0, 1, 2)
+ self.grid3.addWidget(separator_line2, 23, 0, 1, 2)
self.apply_param_to_all = FCButton(_("Apply parameters to all tools"))
self.apply_param_to_all.setToolTip(
_("The parameters in the current form will be applied\n"
"on all the tools from the Tool Table.")
)
- self.grid3.addWidget(self.apply_param_to_all, 23, 0, 1, 2)
+ self.grid3.addWidget(self.apply_param_to_all, 24, 0, 1, 2)
self.generate_ncc_button = QtWidgets.QPushButton(_('Generate Geometry'))
self.generate_ncc_button.setToolTip(
@@ -564,11 +569,16 @@ class NonCopperClear(FlatCAMTool, Gerber):
# #############################################################################
self.tools_table.setupContextMenu()
self.tools_table.addContextMenu(
- "Add", self.on_add_tool_by_key, icon=QtGui.QIcon(self.app.resource_location + "/plus16.png"))
+ _("Add"), self.on_add_tool_by_key, icon=QtGui.QIcon(self.app.resource_location + "/plus16.png")
+ )
self.tools_table.addContextMenu(
- "Delete", lambda:
+ _("Add from DB"), self.on_add_tool_by_key, icon=QtGui.QIcon(self.app.resource_location + "/plus16.png")
+ )
+ self.tools_table.addContextMenu(
+ _("Delete"), lambda:
self.on_tool_delete(rows_to_delete=None, all_tools=None),
- icon=QtGui.QIcon(self.app.resource_location + "/delete32.png"))
+ icon=QtGui.QIcon(self.app.resource_location + "/delete32.png")
+ )
# #############################################################################
# ########################## VARIABLES ########################################
@@ -1070,20 +1080,21 @@ class NonCopperClear(FlatCAMTool, Gerber):
current_widget = self.form_fields[opt]
if isinstance(current_widget, FCCheckBox):
try:
- current_widget.stateChanged.disconnect(self.form_to_storage)
+ current_widget.stateChanged.disconnect()
except (TypeError, ValueError):
pass
if isinstance(current_widget, RadioSet):
try:
- current_widget.activated_custom.disconnect(self.form_to_storage)
+ current_widget.activated_custom.disconnect()
except (TypeError, ValueError):
pass
elif isinstance(current_widget, FCDoubleSpinner):
try:
- current_widget.returnPressed.disconnect(self.form_to_storage)
+ current_widget.returnPressed.disconnect()
except (TypeError, ValueError):
pass
+ # then reconnect
for opt in self.form_fields:
current_widget = self.form_fields[opt]
if isinstance(current_widget, FCCheckBox):
@@ -1093,6 +1104,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
elif isinstance(current_widget, FCDoubleSpinner):
current_widget.returnPressed.connect(self.form_to_storage)
+ self.ncc_choice_offset_cb.stateChanged.connect(self.on_offset_choice)
+ self.ncc_rest_cb.stateChanged.connect(self.on_rest_machining_check)
+ self.ncc_order_radio.activated_custom[str].connect(self.on_order_changed)
+
def ui_disconnect(self):
try:
# if connected, disconnect the signal from the slot on item_changed as it creates issues
@@ -1416,18 +1431,17 @@ class NonCopperClear(FlatCAMTool, Gerber):
# init values for the next usage
self.reset_usage()
+
self.app.report_usage("on_paint_button_click")
self.overlap = float(self.ncc_overlap_entry.get_value()) / 100.0
-
self.grb_circle_steps = int(self.app.defaults["gerber_circle_steps"])
-
self.connect = self.ncc_connect_cb.get_value()
self.contour = self.ncc_contour_cb.get_value()
self.has_offset = self.ncc_choice_offset_cb.isChecked()
self.rest = self.ncc_rest_cb.get_value()
-
self.obj_name = self.object_combo.currentText()
+
# Get source object.
try:
self.ncc_obj = self.app.collection.get_by_name(self.obj_name)
@@ -1523,11 +1537,11 @@ class NonCopperClear(FlatCAMTool, Gerber):
def on_mouse_release(self, event):
if self.app.is_legacy is False:
event_pos = event.pos
- event_is_dragging = event.is_dragging
+ # event_is_dragging = event.is_dragging
right_button = 2
else:
event_pos = (event.xdata, event.ydata)
- event_is_dragging = self.app.plotcanvas.is_dragging
+ # event_is_dragging = self.app.plotcanvas.is_dragging
right_button = 3
event_pos = self.app.plotcanvas.translate_coords(event_pos)
@@ -1539,13 +1553,13 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click the end point of the paint area."))
self.cursor_pos = self.app.plotcanvas.translate_coords(event_pos)
- if self.app.grid_status() == True:
+ if self.app.grid_status():
self.cursor_pos = self.app.geo_editor.snap(event_pos[0], event_pos[1])
else:
self.app.inform.emit(_("Zone added. Click to start adding next zone or right click to finish."))
self.app.delete_selection_shape()
- if self.app.grid_status() == True:
+ if self.app.grid_status():
curr_pos = self.app.geo_editor.snap(event_pos[0], event_pos[1])
else:
curr_pos = (event_pos[0], event_pos[1])
@@ -1566,7 +1580,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.first_click = False
return
- elif event.button == right_button and self.mouse_is_dragging == False:
+ elif event.button == right_button and self.mouse_is_dragging is False:
self.first_click = False
self.delete_tool_selection_shape()
@@ -1606,11 +1620,11 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.is_legacy is False:
event_pos = event.pos
event_is_dragging = event.is_dragging
- right_button = 2
+ # right_button = 2
else:
event_pos = (event.xdata, event.ydata)
event_is_dragging = self.app.plotcanvas.is_dragging
- right_button = 3
+ # right_button = 3
curr_pos = self.app.plotcanvas.translate_coords(event_pos)
@@ -1621,7 +1635,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.mouse_is_dragging = False
# update the cursor position
- if self.app.grid_status() == True:
+ if self.app.grid_status():
# Update cursor
curr_pos = self.app.geo_editor.snap(curr_pos[0], curr_pos[1])
@@ -1651,17 +1665,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
sel_obj=None,
ncctooldia=None,
isotooldia=None,
- margin=None,
- has_offset=None,
- offset=None,
- select_method=None,
outname=None,
- overlap=None,
- connect=None,
- contour=None,
order=None,
- method=None,
- rest=None,
tools_storage=None,
plot=True,
run_threaded=True):
@@ -1671,18 +1676,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
:param ncc_obj: ncc cleared object
:param ncctooldia: a tuple or single element made out of diameters of the tools to be used to ncc clear
:param isotooldia: a tuple or single element made out of diameters of the tools to be used for isolation
- :param overlap: value by which the paths will overlap
- :param order: if the tools are ordered and how
- :param select_method: if to do ncc on the whole object, on an defined area or on an area defined by
- another object
- :param has_offset: True if an offset is needed
- :param offset: distance from the copper features where the copper clearing is stopping
- :param margin: a border around cleared area
:param outname: name of the resulting object
- :param connect: Connect lines to avoid tool lifts.
- :param contour: Paint around the edges.
- :param method: choice out of 'seed', 'normal', 'lines'
- :param rest: True if to use rest-machining
:param tools_storage: whether to use the current tools_storage self.ncc_tools or a different one.
Usage of the different one is related to when this function is called from a TcL command.
:param plot: if True after the job is finished the result will be plotted, else it will not.
@@ -1701,25 +1695,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
# #####################################################################
units = self.app.defaults['units']
-
- log.debug("NCC Tool started. Reading parameters.")
- self.app.inform.emit(_("NCC Tool started. Reading parameters."))
-
- ncc_method = method if method else self.ncc_method_radio.get_value()
-
- if margin is not None:
- ncc_margin = margin
- else:
- ncc_margin = float(self.ncc_margin_entry.get_value())
-
- if select_method is not None:
- ncc_select = select_method
- else:
- ncc_select = self.reference_radio.get_value()
-
- overlap = overlap if overlap is not None else float(self.app.defaults["tools_nccoverlap"]) / 100.0
- connect = connect if connect else self.app.defaults["tools_nccconnect"]
- contour = contour if contour else self.app.defaults["tools_ncccontour"]
order = order if order else self.ncc_order_radio.get_value()
# determine if to use the progressive plotting
@@ -1733,17 +1708,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
else:
tools_storage = self.ncc_tools
- ncc_offset = 0.0
- if has_offset is True:
- if offset is not None:
- ncc_offset = offset
- else:
- try:
- ncc_offset = float(self.ncc_offset_spinner.get_value())
- except ValueError:
- self.app.inform.emit('[ERROR_NOTCL] %s' % _("Wrong value format entered, use a number."))
- return
-
# ######################################################################################################
# # Read the tooldia parameter and create a sorted list out them - they may be more than one diameter ##
# ######################################################################################################
@@ -1843,11 +1807,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
# set the name for the future Geometry object
# I do it here because it is also stored inside the gen_clear_area() and gen_clear_area_rest() methods
# ########################################################################################################
- rest_machining_choice = rest if rest is not None else self.app.defaults["tools_nccrest"]
- if rest_machining_choice is True:
- name = outname if outname is not None else self.obj_name + "_ncc_rm"
- else:
- name = outname if outname is not None else self.obj_name + "_ncc"
+ name = outname if outname is not None else self.obj_name + "_ncc"
# ##########################################################################################
# Initializes the new geometry object ######################################################
@@ -2026,7 +1986,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if has_offset is True:
app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
sol_geo = sol_geo.buffer(distance=ncc_offset)
- app_obj.inform.emit('[success] %s ...' % _("Buffering finished"))
+ app_obj.inform.emit('[success] %s ...' % _("Buffering finished"))
empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
if empty == 'fail':
return 'fail'
@@ -2071,7 +2031,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
area = empty.buffer(-offset)
try:
area = area.difference(cleared)
- except Exception as e:
+ except Exception:
continue
# Transform area to MultiPolygon
@@ -2330,7 +2290,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if has_offset is True:
app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
sol_geo = sol_geo.buffer(distance=ncc_offset)
- app_obj.inform.emit('[success] %s ...' % _("Buffering finished"))
+ app_obj.inform.emit('[success] %s ...' % _("Buffering finished"))
empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
if empty == 'fail':
return 'fail'
@@ -2407,7 +2367,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
new_geo = line_elem.intersection(bounding_box)
if new_geo and not new_geo.is_empty:
new_geometry.append(new_geo)
- except Exception as e:
+ except Exception:
pass
# a MultiLineString geometry element will show that the isolation is broken for this tool
@@ -2516,7 +2476,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
# variables to display the percentage of work done
geo_len = len(area.geoms)
- disp_number = 0
old_disp_number = 0
log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
@@ -3065,7 +3024,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if has_offset is True:
app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
sol_geo = sol_geo.buffer(distance=ncc_offset)
- app_obj.inform.emit('[success] %s ...' % _("Buffering finished"))
+ app_obj.inform.emit('[success] %s ...' % _("Buffering finished"))
empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
if empty == 'fail':
return 'fail'
@@ -3110,7 +3069,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
area = empty.buffer(-offset)
try:
area = area.difference(cleared)
- except Exception as e:
+ except Exception:
continue
# Transform area to MultiPolygon
@@ -3332,7 +3291,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if has_offset is True:
app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
sol_geo = sol_geo.buffer(distance=ncc_offset)
- app_obj.inform.emit('[success] %s ...' % _("Buffering finished"))
+ app_obj.inform.emit('[success] %s ...' % _("Buffering finished"))
empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
if empty == 'fail':
return 'fail'
@@ -3500,7 +3459,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
raise FlatCAMApp.GracefulException
try:
area = area.difference(poly)
- except Exception as e:
+ except Exception:
pass
cleared_by_last_tool[:] = []
@@ -3518,7 +3477,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
# variables to display the percentage of work done
geo_len = len(area.geoms)
- disp_number = 0
old_disp_number = 0
log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
From 7d0a792085137f3db6158f41e77eb93c941d3fd3 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 10 Jan 2020 14:55:32 +0200
Subject: [PATCH 002/209] - small changes
---
FlatCAMApp.py | 3 ++-
flatcamGUI/PreferencesUI.py | 22 ++++------------------
flatcamGUI/VisPyCanvas.py | 23 ++---------------------
3 files changed, 8 insertions(+), 40 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index e41567d2..6d26bfe3 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -8465,7 +8465,7 @@ class App(QtCore.QObject):
self.draw_moving_selection_shape(self.pos, pos, color=self.defaults['global_alt_sel_line'],
face_color=self.defaults['global_alt_sel_fill'])
self.selection_type = False
- elif dx > 0:
+ elif dx >= 0:
self.draw_moving_selection_shape(self.pos, pos)
self.selection_type = True
else:
@@ -8862,6 +8862,7 @@ class App(QtCore.QObject):
pt4 = (float(sel_obj.options['xmin']), float(sel_obj.options['ymax']))
sel_rect = Polygon([pt1, pt2, pt3, pt4])
+
if self.defaults['units'].upper() == 'MM':
sel_rect = sel_rect.buffer(-0.1)
sel_rect = sel_rect.buffer(0.2)
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index 365fd17e..b84a514b 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -333,7 +333,8 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
# Theme selection
self.theme_label = QtWidgets.QLabel('%s:' % _('Theme'))
self.theme_label.setToolTip(
- _("Select a theme for FlatCAM.")
+ _("Select a theme for FlatCAM.\n"
+ "It will theme the plot area.")
)
self.theme_radio = RadioSet([
@@ -356,6 +357,7 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
self.theme_button = FCButton(_("Apply Theme"))
self.theme_button.setToolTip(
_("Select a theme for FlatCAM.\n"
+ "It will theme the plot area.\n"
"The application will restart after change.")
)
grid0.addWidget(self.theme_button, 2, 0, 1, 3)
@@ -1587,14 +1589,6 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
"After change, it will be applied at next App start.")
)
self.worker_number_sb = FCSpinner()
- self.worker_number_sb.setToolTip(
- _("The number of Qthreads made available to the App.\n"
- "A bigger number may finish the jobs more quickly but\n"
- "depending on your computer speed, may make the App\n"
- "unresponsive. Can have a value between 2 and 16.\n"
- "Default value is 2.\n"
- "After change, it will be applied at next App start.")
- )
self.worker_number_sb.set_range(2, 16)
grid0.addWidget(self.worker_number_label, 25, 0)
@@ -1604,21 +1598,13 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
tol_label = QtWidgets.QLabel('%s:' % _("Geo Tolerance"))
tol_label.setToolTip(_(
"This value can counter the effect of the Circle Steps\n"
- "parameter. Default value is 0.01.\n"
+ "parameter. Default value is 0.005.\n"
"A lower value will increase the detail both in image\n"
"and in Gcode for the circles, with a higher cost in\n"
"performance. Higher value will provide more\n"
"performance at the expense of level of detail."
))
self.tol_entry = FCDoubleSpinner()
- self.tol_entry.setToolTip(_(
- "This value can counter the effect of the Circle Steps\n"
- "parameter. Default value is 0.01.\n"
- "A lower value will increase the detail both in image\n"
- "and in Gcode for the circles, with a higher cost in\n"
- "performance. Higher value will provide more\n"
- "performance at the expense of level of detail."
- ))
self.tol_entry.setSingleStep(0.001)
self.tol_entry.set_precision(6)
diff --git a/flatcamGUI/VisPyCanvas.py b/flatcamGUI/VisPyCanvas.py
index f7a9c552..7d7efe13 100644
--- a/flatcamGUI/VisPyCanvas.py
+++ b/flatcamGUI/VisPyCanvas.py
@@ -24,24 +24,16 @@ black = Color("#000000")
class VisPyCanvas(scene.SceneCanvas):
def __init__(self, config=None):
- print("vp_1")
- try:
- # scene.SceneCanvas.__init__(self, keys=None, config=config)
- super().__init__(config=config, keys=None)
- except Exception as e:
- print("VisPyCanvas.__init__() -> %s" % str(e))
-
- print("vp_2")
+ # scene.SceneCanvas.__init__(self, keys=None, config=config)
+ super().__init__(config=config, keys=None)
self.unfreeze()
- print("vp_3")
settings = QSettings("Open Source", "FlatCAM")
if settings.contains("axis_font_size"):
a_fsize = settings.value('axis_font_size', type=int)
else:
a_fsize = 8
- print("vp_4")
if settings.contains("theme"):
theme = settings.value('theme', type=str)
@@ -59,8 +51,6 @@ class VisPyCanvas(scene.SceneCanvas):
# back_color = Color('#272822') # darker
# back_color = Color('#3c3f41') # lighter
- print("vp_5")
-
self.central_widget.bgcolor = back_color
self.central_widget.border_color = back_color
@@ -70,8 +60,6 @@ class VisPyCanvas(scene.SceneCanvas):
top_padding = self.grid_widget.add_widget(row=0, col=0, col_span=2)
top_padding.height_max = 0
- print("vp_6")
-
self.yaxis = scene.AxisWidget(
orientation='left', axis_color=tick_color, text_color=tick_color, font_size=a_fsize, axis_width=1
)
@@ -89,13 +77,9 @@ class VisPyCanvas(scene.SceneCanvas):
# right_padding.width_max = 24
right_padding.width_max = 0
- print("vp_7")
-
view = self.grid_widget.add_view(row=1, col=1, border_color=tick_color, bgcolor=theme_color)
view.camera = Camera(aspect=1, rect=(-25, -25, 150, 150))
- print("vp_8")
-
# Following function was removed from 'prepare_draw()' of 'Grid' class by patch,
# it is necessary to call manually
self.grid_widget._update_child_widget_dim()
@@ -118,10 +102,7 @@ class VisPyCanvas(scene.SceneCanvas):
else:
self.grid = scene.GridLines(parent=self.view.scene, color='#dededeff')
- print("vp_9")
-
self.grid.set_gl_state(depth_test=False)
- print("vp_10")
self.freeze()
From fc31bb573d8af5d194e1f2db32d376711897b354 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 10 Jan 2020 15:56:23 +0200
Subject: [PATCH 003/209] - working on a new tool: Extract Drills Tool who will
create a Excellon object out of the apertures of a Gerber object
---
README.md | 4 +
flatcamTools/ToolExtractDrills.py | 264 ++++++++++++++++++++++++++++++
flatcamTools/__init__.py | 5 +-
3 files changed, 271 insertions(+), 2 deletions(-)
create mode 100644 flatcamTools/ToolExtractDrills.py
diff --git a/README.md b/README.md
index db7ea631..454d3bac 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+10.02.2019
+
+- working on a new tool: Extract Drills Tool who will create a Excellon object out of the apertures of a Gerber object
+
8.01.2019
- working in NCC Tool
diff --git a/flatcamTools/ToolExtractDrills.py b/flatcamTools/ToolExtractDrills.py
new file mode 100644
index 00000000..be2002a8
--- /dev/null
+++ b/flatcamTools/ToolExtractDrills.py
@@ -0,0 +1,264 @@
+
+from PyQt5 import QtWidgets, QtCore
+
+from FlatCAMTool import FlatCAMTool
+from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, EvalEntry, FCEntry
+from FlatCAMObj import FlatCAMGerber, FlatCAMExcellon, FlatCAMGeometry
+
+from numpy import Inf
+
+from shapely.geometry import Point
+from shapely import affinity
+
+import logging
+import gettext
+import FlatCAMTranslation as fcTranslate
+import builtins
+
+fcTranslate.apply_language('strings')
+if '_' not in builtins.__dict__:
+ _ = gettext.gettext
+
+log = logging.getLogger('base')
+
+
+class ToolExtractDrills(FlatCAMTool):
+
+ toolName = _("Extract Drills")
+
+ def __init__(self, app):
+ FlatCAMTool.__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.empty_lb = QtWidgets.QLabel("")
+ self.layout.addWidget(self.empty_lb)
+
+ # ## Grid Layout
+ grid_lay = QtWidgets.QGridLayout()
+ self.layout.addLayout(grid_lay)
+ grid_lay.setColumnStretch(0, 1)
+ grid_lay.setColumnStretch(1, 0)
+
+ # ## Gerber Object
+ self.gerber_object_combo = QtWidgets.QComboBox()
+ self.gerber_object_combo.setModel(self.app.collection)
+ self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.gerber_object_combo.setCurrentIndex(1)
+
+ self.grb_label = QtWidgets.QLabel("%s:" % _("GERBER"))
+ self.grb_label.setToolTip('%s.' % _("Gerber from which to extract drill holes"))
+
+ self.mirror_gerber_button.setStyleSheet("""
+ QPushButton
+ {
+ font-weight: bold;
+ }
+ """)
+ self.mirror_gerber_button.setMinimumWidth(60)
+
+ # grid_lay.addRow("Bottom Layer:", self.object_combo)
+ grid_lay.addWidget(self.grb_label, 0, 0)
+ grid_lay.addWidget(self.gerber_object_combo, 1, 0)
+
+ # ## Grid Layout
+ grid_lay1 = QtWidgets.QGridLayout()
+ self.layout.addLayout(grid_lay1)
+
+ # ## Axis
+ self.hole_size_radio = RadioSet([{'label': _("Fixed"), 'value': 'fixed'},
+ {'label': _("Proportional"), 'value': 'prop'}])
+ self.hole_size_label = QtWidgets.QLabel('%s:' % _("Hole Size"))
+ self.hole_size_label.setToolTip(
+ _("The type of hole size. Can be:\n"
+ "- Fixed -> all holes will have a set size\n"
+ "- Proprotional -> each hole will havea a variable size\n"
+ "such as to preserve a set annular ring"))
+
+ grid_lay1.addWidget(self.hole_size_label, 3, 0)
+ grid_lay1.addWidget(self.hole_size_radio, 3, 1)
+
+ self.layout.addWidget(QtWidgets.QLabel(''))
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.layout.addWidget(separator_line)
+
+ grid1 = QtWidgets.QGridLayout()
+ self.layout.addLayout(grid1)
+ grid1.setColumnStretch(0, 0)
+ grid1.setColumnStretch(1, 1)
+
+ # Diameter value
+ self.dia_entry = FCDoubleSpinner()
+ self.dia_entry.set_precision(self.decimals)
+ self.dia_entry.set_range(0.0000, 9999.9999)
+
+ self.dia_label = QtWidgets.QLabel('%s:' % _("Diameter"))
+ self.dia_label.setToolTip(
+ _("Fixed hole diameter.")
+ )
+
+ grid1.addWidget(self.dia_label, 1, 0)
+ grid1.addWidget(self.dia_entry, 1, 1)
+
+ # Annular Ring value
+ self.ring_entry = FCDoubleSpinner()
+ self.ring_entry.set_precision(self.decimals)
+ self.ring_entry.set_range(0.0000, 9999.9999)
+
+ self.ring_label = QtWidgets.QLabel('%s:' % _("Annular Ring"))
+ self.ring_label.setToolTip(
+ _("The size of annular ring.\n"
+ "The copper sliver between the drill hole exterior\n"
+ "and the margin of the copper pad.")
+ )
+
+ grid1.addWidget(self.ring_label, 2, 0)
+ grid1.addWidget(self.ring_entry, 2, 1)
+
+ # Calculate Bounding box
+ self.e_drills_button = QtWidgets.QPushButton(_("Extract Drills"))
+ self.e_drills_button.setToolTip(
+ _("Extract drills from a given Gerber file.")
+ )
+ self.e_drills_button.setStyleSheet("""
+ QPushButton
+ {
+ font-weight: bold;
+ }
+ """)
+ self.layout.addWidget(self.e_drills_button)
+
+ self.layout.addStretch()
+
+ # ## Reset Tool
+ self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
+ self.reset_button.setToolTip(
+ _("Will reset the tool parameters.")
+ )
+ self.reset_button.setStyleSheet("""
+ QPushButton
+ {
+ font-weight: bold;
+ }
+ """)
+ self.layout.addWidget(self.reset_button)
+
+ # ## Signals
+ self.hole_size_radio.activated_custom(self.on_hole_size_toggle)
+ self.e_drills_button.clicked.connect(self.on_extract_drills_click)
+ self.reset_button.clicked.connect(self.set_tool_ui)
+
+ self.tools = list()
+ self.drills = dict()
+
+ def install(self, icon=None, separator=None, **kwargs):
+ FlatCAMTool.install(self, icon, separator, shortcut='ALT+D', **kwargs)
+
+ def run(self, toggle=True):
+ self.app.report_usage("Extract Drills()")
+
+ if toggle:
+ # if the splitter is hidden, display it, else hide it but only if the current widget is the same
+ if self.app.ui.splitter.sizes()[0] == 0:
+ self.app.ui.splitter.setSizes([1, 1])
+ else:
+ try:
+ if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
+ # if tab is populated with the tool but it does not have the focus, focus on it
+ if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
+ # focus on Tool Tab
+ self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
+ else:
+ self.app.ui.splitter.setSizes([0, 1])
+ except AttributeError:
+ pass
+ else:
+ if self.app.ui.splitter.sizes()[0] == 0:
+ self.app.ui.splitter.setSizes([1, 1])
+
+ FlatCAMTool.run(self)
+ self.set_tool_ui()
+
+ self.app.ui.notebook.setTabText(2, _("Extract Drills Tool"))
+
+ def set_tool_ui(self):
+ self.reset_fields()
+
+ self.hole_size_radio.set_value(self.app.defaults["tools_edrills_hole_type"])
+
+ self.dia_entry.set_value(float(self.app.defaults["tools_edrills_hole_fixed_dia"]))
+ self.ring_entry.set_value(float(self.app.defaults["tools_edrills_hole_ring"]))
+
+ def on_extract_drills_click(self):
+ selection_index = self.gerber_object_combo.currentIndex()
+ # fcobj = self.app.collection.object_list[selection_index]
+ model_index = self.app.collection.index(selection_index, 0, self.gerber_object_combo.rootModelIndex())
+ try:
+ fcobj = model_index.internalPointer().obj
+ except Exception as e:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
+ return
+
+ if not isinstance(fcobj, FlatCAMGerber):
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _("Only Gerber, Excellon and Geometry objects can be mirrored."))
+ return
+
+ axis = self.mirror_axis.get_value()
+ mode = self.axis_location.get_value()
+
+ if mode == "point":
+ try:
+ px, py = self.point_entry.get_value()
+ except TypeError:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("'Point' coordinates missing. "
+ "Using Origin (0, 0) as mirroring reference."))
+ px, py = (0, 0)
+
+ else:
+ selection_index_box = self.box_combo.currentIndex()
+ model_index_box = self.app.collection.index(selection_index_box, 0, self.box_combo.rootModelIndex())
+ try:
+ bb_obj = model_index_box.internalPointer().obj
+ except Exception as e:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Box object loaded ..."))
+ return
+
+ xmin, ymin, xmax, ymax = bb_obj.bounds()
+ px = 0.5 * (xmin + xmax)
+ py = 0.5 * (ymin + ymax)
+
+ fcobj.mirror(axis, [px, py])
+ self.app.object_changed.emit(fcobj)
+ fcobj.plot()
+ self.app.inform.emit('[success] Gerber %s %s...' % (str(fcobj.options['name']), _("was mirrored")))
+
+ def on_hole_size_toggle(self, val):
+ if val == "fixed":
+ self.dia_entry.show()
+ self.dia_label.show()
+
+ self.ring_label.hide()
+ self.ring_entry.hide()
+ else:
+ self.dia_entry.hide()
+ self.dia_label.hide()
+
+ self.ring_label.show()
+ self.ring_entry.show()
+
+ def reset_fields(self):
+ self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.gerber_object_combo.setCurrentIndex(0)
diff --git a/flatcamTools/__init__.py b/flatcamTools/__init__.py
index d986974e..be389e70 100644
--- a/flatcamTools/__init__.py
+++ b/flatcamTools/__init__.py
@@ -1,6 +1,5 @@
import sys
-
from flatcamTools.ToolCalculators import ToolCalculator
from flatcamTools.ToolCalibration import ToolCalibration
from flatcamTools.ToolCutOut import CutOut
@@ -17,10 +16,10 @@ from flatcamTools.ToolDistanceMin import DistanceMin
from flatcamTools.ToolMove import ToolMove
from flatcamTools.ToolNonCopperClear import NonCopperClear
+from flatcamTools.ToolPaint import ToolPaint
from flatcamTools.ToolOptimal import ToolOptimal
-from flatcamTools.ToolPaint import ToolPaint
from flatcamTools.ToolPanelize import Panelize
from flatcamTools.ToolPcbWizard import PcbWizard
from flatcamTools.ToolPDF import ToolPDF
@@ -32,6 +31,8 @@ from flatcamTools.ToolRulesCheck import RulesCheck
from flatcamTools.ToolCopperThieving import ToolCopperThieving
from flatcamTools.ToolFiducials import ToolFiducials
+from flatcamTools.ToolExtractDrills import ToolExtractDrills
+
from flatcamTools.ToolShell import FCShell
from flatcamTools.ToolSolderPaste import SolderPaste
from flatcamTools.ToolSub import ToolSub
From f2ccb48c98ada313ce1eccb515fde86f39f2d04a Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 10 Jan 2020 16:56:29 +0200
Subject: [PATCH 004/209] - finished the GUI in the Extract Drills Tool
---
FlatCAMApp.py | 28 +++++---
README.md | 1 +
flatcamTools/ToolExtractDrills.py | 115 +++++++++++++-----------------
3 files changed, 70 insertions(+), 74 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 6d26bfe3..3815287c 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -954,6 +954,11 @@ class App(QtCore.QObject):
"tools_cal_toolchange_xy": '',
"tools_cal_sec_point": 'tl',
+ # Drills Extraction Tool
+ "tools_edrills_hole_type": 'fixed',
+ "tools_edrills_hole_fixed_dia": 0.5,
+ "tools_edrills_hole_ring": 0.2,
+
# Utilities
# file associations
"fa_excellon": 'drd, drl, exc, ncd, tap, xln',
@@ -2464,12 +2469,13 @@ class App(QtCore.QObject):
self.qrcode_tool = None
self.copper_thieving_tool = None
self.fiducial_tool = None
+ self.edrills_tool = None
# always install tools only after the shell is initialized because the self.inform.emit() depends on shell
try:
self.install_tools()
- except AttributeError:
- pass
+ except AttributeError as e:
+ log.debug("App.__init__() install tools() --> %s" % str(e))
# ##################################################################################
# ########################### SETUP RECENT ITEMS ###################################
@@ -3017,13 +3023,6 @@ class App(QtCore.QObject):
:return: None
"""
- self.dblsidedtool = DblSidedTool(self)
- self.dblsidedtool.install(icon=QtGui.QIcon(self.resource_location + '/doubleside16.png'), separator=True)
-
- self.cal_exc_tool = ToolCalibration(self)
- self.cal_exc_tool.install(icon=QtGui.QIcon(self.resource_location + '/calibrate_16.png'), pos=self.ui.menutool,
- before=self.dblsidedtool.menuAction,
- separator=False)
self.distance_tool = Distance(self)
self.distance_tool.install(icon=QtGui.QIcon(self.resource_location + '/distance16.png'), pos=self.ui.menuedit,
before=self.ui.menueditorigin,
@@ -3035,6 +3034,17 @@ class App(QtCore.QObject):
before=self.ui.menueditorigin,
separator=True)
+ self.dblsidedtool = DblSidedTool(self)
+ self.dblsidedtool.install(icon=QtGui.QIcon(self.resource_location + '/doubleside16.png'), separator=False)
+
+ self.cal_exc_tool = ToolCalibration(self)
+ self.cal_exc_tool.install(icon=QtGui.QIcon(self.resource_location + '/calibrate_16.png'), pos=self.ui.menutool,
+ before=self.dblsidedtool.menuAction,
+ separator=False)
+
+ self.edrills_tool = ToolExtractDrills(self)
+ self.edrills_tool.install(icon=QtGui.QIcon(self.resource_location + '/drill16.png'), separator=True)
+
self.panelize_tool = Panelize(self)
self.panelize_tool.install(icon=QtGui.QIcon(self.resource_location + '/panelize16.png'))
diff --git a/README.md b/README.md
index 454d3bac..9093667b 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
10.02.2019
- working on a new tool: Extract Drills Tool who will create a Excellon object out of the apertures of a Gerber object
+- finished the GUI in the Extract Drills Tool
8.01.2019
diff --git a/flatcamTools/ToolExtractDrills.py b/flatcamTools/ToolExtractDrills.py
index be2002a8..7f47ab3e 100644
--- a/flatcamTools/ToolExtractDrills.py
+++ b/flatcamTools/ToolExtractDrills.py
@@ -59,21 +59,15 @@ class ToolExtractDrills(FlatCAMTool):
self.grb_label = QtWidgets.QLabel("%s:" % _("GERBER"))
self.grb_label.setToolTip('%s.' % _("Gerber from which to extract drill holes"))
- self.mirror_gerber_button.setStyleSheet("""
- QPushButton
- {
- font-weight: bold;
- }
- """)
- self.mirror_gerber_button.setMinimumWidth(60)
-
# grid_lay.addRow("Bottom Layer:", self.object_combo)
grid_lay.addWidget(self.grb_label, 0, 0)
grid_lay.addWidget(self.gerber_object_combo, 1, 0)
# ## Grid Layout
- grid_lay1 = QtWidgets.QGridLayout()
- self.layout.addLayout(grid_lay1)
+ grid1 = QtWidgets.QGridLayout()
+ self.layout.addLayout(grid1)
+ grid1.setColumnStretch(0, 0)
+ grid1.setColumnStretch(1, 1)
# ## Axis
self.hole_size_radio = RadioSet([{'label': _("Fixed"), 'value': 'fixed'},
@@ -85,20 +79,15 @@ class ToolExtractDrills(FlatCAMTool):
"- Proprotional -> each hole will havea a variable size\n"
"such as to preserve a set annular ring"))
- grid_lay1.addWidget(self.hole_size_label, 3, 0)
- grid_lay1.addWidget(self.hole_size_radio, 3, 1)
+ grid1.addWidget(self.hole_size_label, 3, 0)
+ grid1.addWidget(self.hole_size_radio, 3, 1)
- self.layout.addWidget(QtWidgets.QLabel(''))
+ # grid_lay1.addWidget(QtWidgets.QLabel(''))
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.layout.addWidget(separator_line)
-
- grid1 = QtWidgets.QGridLayout()
- self.layout.addLayout(grid1)
- grid1.setColumnStretch(0, 0)
- grid1.setColumnStretch(1, 1)
+ grid1.addWidget(separator_line, 5, 0, 1, 2)
# Diameter value
self.dia_entry = FCDoubleSpinner()
@@ -110,8 +99,8 @@ class ToolExtractDrills(FlatCAMTool):
_("Fixed hole diameter.")
)
- grid1.addWidget(self.dia_label, 1, 0)
- grid1.addWidget(self.dia_entry, 1, 1)
+ grid1.addWidget(self.dia_label, 7, 0)
+ grid1.addWidget(self.dia_entry, 7, 1)
# Annular Ring value
self.ring_entry = FCDoubleSpinner()
@@ -125,8 +114,8 @@ class ToolExtractDrills(FlatCAMTool):
"and the margin of the copper pad.")
)
- grid1.addWidget(self.ring_label, 2, 0)
- grid1.addWidget(self.ring_entry, 2, 1)
+ grid1.addWidget(self.ring_label, 8, 0)
+ grid1.addWidget(self.ring_entry, 8, 1)
# Calculate Bounding box
self.e_drills_button = QtWidgets.QPushButton(_("Extract Drills"))
@@ -157,7 +146,7 @@ class ToolExtractDrills(FlatCAMTool):
self.layout.addWidget(self.reset_button)
# ## Signals
- self.hole_size_radio.activated_custom(self.on_hole_size_toggle)
+ self.hole_size_radio.activated_custom.connect(self.on_hole_size_toggle)
self.e_drills_button.clicked.connect(self.on_extract_drills_click)
self.reset_button.clicked.connect(self.set_tool_ui)
@@ -165,7 +154,7 @@ class ToolExtractDrills(FlatCAMTool):
self.drills = dict()
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+D', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='ALT+E', **kwargs)
def run(self, toggle=True):
self.app.report_usage("Extract Drills()")
@@ -204,60 +193,56 @@ class ToolExtractDrills(FlatCAMTool):
def on_extract_drills_click(self):
selection_index = self.gerber_object_combo.currentIndex()
- # fcobj = self.app.collection.object_list[selection_index]
model_index = self.app.collection.index(selection_index, 0, self.gerber_object_combo.rootModelIndex())
+
try:
fcobj = model_index.internalPointer().obj
except Exception as e:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
return
- if not isinstance(fcobj, FlatCAMGerber):
- self.app.inform.emit('[ERROR_NOTCL] %s' % _("Only Gerber, Excellon and Geometry objects can be mirrored."))
- return
-
- axis = self.mirror_axis.get_value()
- mode = self.axis_location.get_value()
-
- if mode == "point":
- try:
- px, py = self.point_entry.get_value()
- except TypeError:
- self.app.inform.emit('[WARNING_NOTCL] %s' % _("'Point' coordinates missing. "
- "Using Origin (0, 0) as mirroring reference."))
- px, py = (0, 0)
-
- else:
- selection_index_box = self.box_combo.currentIndex()
- model_index_box = self.app.collection.index(selection_index_box, 0, self.box_combo.rootModelIndex())
- try:
- bb_obj = model_index_box.internalPointer().obj
- except Exception as e:
- self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Box object loaded ..."))
- return
-
- xmin, ymin, xmax, ymax = bb_obj.bounds()
- px = 0.5 * (xmin + xmax)
- py = 0.5 * (ymin + ymax)
-
- fcobj.mirror(axis, [px, py])
- self.app.object_changed.emit(fcobj)
- fcobj.plot()
+ # axis = self.mirror_axis.get_value()
+ # mode = self.axis_location.get_value()
+ #
+ # if mode == "point":
+ # try:
+ # px, py = self.point_entry.get_value()
+ # except TypeError:
+ # self.app.inform.emit('[WARNING_NOTCL] %s' % _("'Point' coordinates missing. "
+ # "Using Origin (0, 0) as mirroring reference."))
+ # px, py = (0, 0)
+ #
+ # else:
+ # selection_index_box = self.box_combo.currentIndex()
+ # model_index_box = self.app.collection.index(selection_index_box, 0, self.box_combo.rootModelIndex())
+ # try:
+ # bb_obj = model_index_box.internalPointer().obj
+ # except Exception as e:
+ # self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Box object loaded ..."))
+ # return
+ #
+ # xmin, ymin, xmax, ymax = bb_obj.bounds()
+ # px = 0.5 * (xmin + xmax)
+ # py = 0.5 * (ymin + ymax)
+ #
+ # fcobj.mirror(axis, [px, py])
+ # self.app.object_changed.emit(fcobj)
+ # fcobj.plot()
self.app.inform.emit('[success] Gerber %s %s...' % (str(fcobj.options['name']), _("was mirrored")))
def on_hole_size_toggle(self, val):
if val == "fixed":
- self.dia_entry.show()
- self.dia_label.show()
+ self.dia_entry.setDisabled(False)
+ self.dia_label.setDisabled(False)
- self.ring_label.hide()
- self.ring_entry.hide()
+ self.ring_label.setDisabled(True)
+ self.ring_entry.setDisabled(True)
else:
- self.dia_entry.hide()
- self.dia_label.hide()
+ self.dia_entry.setDisabled(True)
+ self.dia_label.setDisabled(True)
- self.ring_label.show()
- self.ring_entry.show()
+ self.ring_label.setDisabled(False)
+ self.ring_entry.setDisabled(False)
def reset_fields(self):
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
From c16ecfe0c3de7eb8855da06bf43cc923100604db Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 11 Jan 2020 00:52:06 +0200
Subject: [PATCH 005/209] - fixed issue in Film Tool where some parameters
names in calls of method export_positive() were not matching the actual
parameters name - finished the Extract Drills Tool - fixed a small issue in
the DoubleSided Tool
---
FlatCAMApp.py | 17 ++++--
README.md | 3 +
flatcamTools/ToolDblSided.py | 7 ++-
flatcamTools/ToolExtractDrills.py | 98 +++++++++++++++++++++----------
flatcamTools/ToolFilm.py | 31 ++++++----
5 files changed, 103 insertions(+), 53 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 3815287c..d80e3ec5 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -10389,7 +10389,8 @@ class App(QtCore.QObject):
self.report_usage("export_svg()")
if filename is None:
- filename = self.defaults["global_last_save_folder"]
+ filename = self.defaults["global_last_save_folder"] if self.defaults["global_last_save_folder"] \
+ is not None else self.defaults["global_last_folder"]
self.log.debug("export_svg()")
@@ -10457,7 +10458,8 @@ class App(QtCore.QObject):
self.report_usage("save source file()")
if filename is None:
- filename = self.defaults["global_last_save_folder"]
+ filename = self.defaults["global_last_save_folder"] if self.defaults["global_last_save_folder"] \
+ is not None else self.defaults["global_last_folder"]
self.log.debug("save source file()")
@@ -10500,7 +10502,10 @@ class App(QtCore.QObject):
self.report_usage("export_excellon()")
if filename is None:
- filename = self.defaults["global_last_save_folder"] + '/' + 'exported_excellon'
+ if self.defaults["global_last_save_folder"]:
+ filename = self.defaults["global_last_save_folder"] + '/' + 'exported_excellon'
+ else:
+ filename = self.defaults["global_last_folder"] + '/' + 'exported_excellon'
self.log.debug("export_excellon()")
@@ -10656,7 +10661,8 @@ class App(QtCore.QObject):
self.report_usage("export_gerber()")
if filename is None:
- filename = self.defaults["global_last_save_folder"]
+ filename = self.defaults["global_last_save_folder"] if self.defaults["global_last_save_folder"] \
+ is not None else self.defaults["global_last_folder"]
self.log.debug("export_gerber()")
@@ -10792,7 +10798,8 @@ class App(QtCore.QObject):
self.report_usage("export_dxf()")
if filename is None:
- filename = self.defaults["global_last_save_folder"]
+ filename = self.defaults["global_last_save_folder"] if self.defaults["global_last_save_folder"] \
+ is not None else self.defaults["global_last_folder"]
self.log.debug("export_dxf()")
diff --git a/README.md b/README.md
index 9093667b..3cc30ba8 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,9 @@ CAD program, and create G-Code for Isolation routing.
- working on a new tool: Extract Drills Tool who will create a Excellon object out of the apertures of a Gerber object
- finished the GUI in the Extract Drills Tool
+- fixed issue in Film Tool where some parameters names in calls of method export_positive() were not matching the actual parameters name
+- finished the Extract Drills Tool
+- fixed a small issue in the DoubleSided Tool
8.01.2019
diff --git a/flatcamTools/ToolDblSided.py b/flatcamTools/ToolDblSided.py
index 3308c159..0b00fc6e 100644
--- a/flatcamTools/ToolDblSided.py
+++ b/flatcamTools/ToolDblSided.py
@@ -533,16 +533,17 @@ class DblSidedTool(FlatCAMTool):
"Add them and retry."))
return
- drills = []
+ drills = list()
for hole in holes:
point = Point(hole)
point_mirror = affinity.scale(point, xscale, yscale, origin=(px, py))
drills.append({"point": point, "tool": "1"})
drills.append({"point": point_mirror, "tool": "1"})
- if 'solid_geometry' not in tools:
- tools["1"]['solid_geometry'] = []
+ if 'solid_geometry' not in tools["1"]:
+ tools["1"]['solid_geometry'] = list()
else:
+ tools["1"]['solid_geometry'].append(point)
tools["1"]['solid_geometry'].append(point_mirror)
def obj_init(obj_inst, app_inst):
diff --git a/flatcamTools/ToolExtractDrills.py b/flatcamTools/ToolExtractDrills.py
index 7f47ab3e..5d2a604e 100644
--- a/flatcamTools/ToolExtractDrills.py
+++ b/flatcamTools/ToolExtractDrills.py
@@ -150,11 +150,8 @@ class ToolExtractDrills(FlatCAMTool):
self.e_drills_button.clicked.connect(self.on_extract_drills_click)
self.reset_button.clicked.connect(self.set_tool_ui)
- self.tools = list()
- self.drills = dict()
-
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+E', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='ALT+I', **kwargs)
def run(self, toggle=True):
self.app.report_usage("Extract Drills()")
@@ -192,6 +189,12 @@ class ToolExtractDrills(FlatCAMTool):
self.ring_entry.set_value(float(self.app.defaults["tools_edrills_hole_ring"]))
def on_extract_drills_click(self):
+
+ drill_dia = self.dia_entry.get_value()
+ ring_val = self.ring_entry.get_value()
+ drills = list()
+ tools = dict()
+
selection_index = self.gerber_object_combo.currentIndex()
model_index = self.app.collection.index(selection_index, 0, self.gerber_object_combo.rootModelIndex())
@@ -201,34 +204,65 @@ class ToolExtractDrills(FlatCAMTool):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
return
- # axis = self.mirror_axis.get_value()
- # mode = self.axis_location.get_value()
- #
- # if mode == "point":
- # try:
- # px, py = self.point_entry.get_value()
- # except TypeError:
- # self.app.inform.emit('[WARNING_NOTCL] %s' % _("'Point' coordinates missing. "
- # "Using Origin (0, 0) as mirroring reference."))
- # px, py = (0, 0)
- #
- # else:
- # selection_index_box = self.box_combo.currentIndex()
- # model_index_box = self.app.collection.index(selection_index_box, 0, self.box_combo.rootModelIndex())
- # try:
- # bb_obj = model_index_box.internalPointer().obj
- # except Exception as e:
- # self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Box object loaded ..."))
- # return
- #
- # xmin, ymin, xmax, ymax = bb_obj.bounds()
- # px = 0.5 * (xmin + xmax)
- # py = 0.5 * (ymin + ymax)
- #
- # fcobj.mirror(axis, [px, py])
- # self.app.object_changed.emit(fcobj)
- # fcobj.plot()
- self.app.inform.emit('[success] Gerber %s %s...' % (str(fcobj.options['name']), _("was mirrored")))
+ outname = fcobj.options['name'].rpartition('.')[0]
+
+ mode = self.hole_size_radio.get_value()
+
+ if mode == 'fixed':
+ tools = {"1": {"C": drill_dia}}
+ for apid, apid_value in fcobj.apertures.items():
+ for geo_el in apid_value['geometry']:
+ if 'follow' in geo_el and isinstance(geo_el['follow'], Point):
+ drills.append({"point": geo_el['follow'], "tool": "1"})
+ if 'solid_geometry' not in tools["1"]:
+ tools["1"]['solid_geometry'] = list()
+ else:
+ tools["1"]['solid_geometry'].append(geo_el['follow'])
+ else:
+ for apid, apid_value in fcobj.apertures.items():
+ ap_type = apid_value['type']
+
+ dia = float(apid_value['size']) - (2 * ring_val)
+ if ap_type == 'R' or ap_type == 'O':
+ width = float(apid_value['width'])
+ height = float(apid_value['height'])
+ if width >= height:
+ dia = float(apid_value['height']) - (2 * ring_val)
+ else:
+ dia = float(apid_value['width']) - (2 * ring_val)
+
+ tool_in_drills = False
+ for tool, tool_val in tools.items():
+ if abs(float('%.*f' % (self.decimals, tool_val["C"])) - dia) < (10 ** -self.decimals):
+ tool_in_drills = tool
+
+ if tool_in_drills is False:
+ if tools:
+ new_tool = max([int(t) for t in tools]) + 1
+ tool_in_drills = str(new_tool)
+ else:
+ tool_in_drills = "1"
+
+ for geo_el in apid_value['geometry']:
+ if 'follow' in geo_el and isinstance(geo_el['follow'], Point):
+ if tool_in_drills not in tools:
+ tools[tool_in_drills] = {"C": dia}
+
+ drills.append({"point": geo_el['follow'], "tool": tool_in_drills})
+
+ if 'solid_geometry' not in tools[tool_in_drills]:
+ tools[tool_in_drills]['solid_geometry'] = list()
+ else:
+ tools[tool_in_drills]['solid_geometry'].append(geo_el['follow'])
+
+ def obj_init(obj_inst, app_inst):
+ obj_inst.tools = tools
+ obj_inst.drills = drills
+ obj_inst.create_geometry()
+ obj_inst.source_file = self.app.export_excellon(obj_name=outname, local_use=obj_inst, filename=None,
+ use_thread=False)
+
+ self.app.new_object("excellon", outname, obj_init)
def on_hole_size_toggle(self, val):
if val == "fixed":
diff --git a/flatcamTools/ToolFilm.py b/flatcamTools/ToolFilm.py
index ead110b1..a3542e29 100644
--- a/flatcamTools/ToolFilm.py
+++ b/flatcamTools/ToolFilm.py
@@ -752,7 +752,7 @@ class Film(FlatCAMTool):
skew_factor_x=skew_factor_x, skew_factor_y=skew_factor_y,
skew_reference=skew_reference,
mirror=mirror,
- pagesize=pagesize, orientation=orientation, color=color, opacity=1.0,
+ pagesize_val=pagesize, orientation_val=orientation, color_val=color, opacity_val=1.0,
ftype=ftype
)
@@ -1080,23 +1080,28 @@ class Film(FlatCAMTool):
skew_factor_x=None, skew_factor_y=None, skew_reference='center',
mirror=None, orientation_val='p', pagesize_val='A4', color_val='black', opacity_val=1.0,
use_thread=True, ftype='svg'):
+
"""
Exports a Geometry Object to an SVG file in positive black.
- :param obj_name: the name of the FlatCAM object to be saved as SVG
- :param box_name: the name of the FlatCAM object to be used as delimitation of the content to be saved
- :param filename: Path to the SVG file to save to.
+ :param obj_name: the name of the FlatCAM object to be saved
+ :param box_name: the name of the FlatCAM object to be used as delimitation of the content to be saved
+ :param filename: Path to the file to save to.
:param scale_stroke_factor: factor by which to change/scale the thickness of the features
- :param scale_factor_x: factor to scale the svg geometry on the X axis
- :param scale_factor_y: factor to scale the svg geometry on the Y axis
- :param skew_factor_x: factor to skew the svg geometry on the X axis
- :param skew_factor_y: factor to skew the svg geometry on the Y axis
- :param skew_reference: reference to use for skew. Can be 'bottomleft', 'bottomright', 'topleft', 'topright' and
- those are the 4 points of the bounding box of the geometry to be skewed.
- :param mirror: can be 'x' or 'y' or 'both'. Axis on which to mirror the svg geometry
+ :param scale_factor_x: factor to scale the geometry on the X axis
+ :param scale_factor_y: factor to scale the geometry on the Y axis
+ :param skew_factor_x: factor to skew the geometry on the X axis
+ :param skew_factor_y: factor to skew the geometry on the Y axis
+ :param skew_reference: reference to use for skew. Can be 'bottomleft', 'bottomright', 'topleft',
+ 'topright' and those are the 4 points of the bounding box of the geometry to be skewed.
+ :param mirror: can be 'x' or 'y' or 'both'. Axis on which to mirror the svg geometry
+ :param orientation_val:
+ :param pagesize_val:
+ :param color_val:
+ :param opacity_val:
+ :param use_thread: if to be run in a separate thread; boolean
+ :param ftype: the type of file for saving the film: 'svg', 'png' or 'pdf'
- :param use_thread: if to be run in a separate thread; boolean
- :param ftype: the type of file for saving the film: 'svg', 'png' or 'pdf'
:return:
"""
self.app.report_usage("export_positive()")
From c28f08a3927859887b0c1530c7831334441dd494 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 11 Jan 2020 17:30:48 +0200
Subject: [PATCH 006/209] - fixed an issue in the Distance Tool - expanded the
Extract Drills Tool to use a particular annular ring for each type of
aperture flash (pad)
---
FlatCAMApp.py | 11 +-
README.md | 11 +-
flatcamGUI/GUIElements.py | 4 +
flatcamTools/ToolDistance.py | 23 +--
flatcamTools/ToolExtractDrills.py | 279 +++++++++++++++++++++++++++---
5 files changed, 287 insertions(+), 41 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index d80e3ec5..05c2a850 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -957,7 +957,16 @@ class App(QtCore.QObject):
# Drills Extraction Tool
"tools_edrills_hole_type": 'fixed',
"tools_edrills_hole_fixed_dia": 0.5,
- "tools_edrills_hole_ring": 0.2,
+ "tools_edrills_circular_ring": 0.2,
+ "tools_edrills_oblong_ring": 0.2,
+ "tools_edrills_square_ring": 0.2,
+ "tools_edrills_rectangular_ring": 0.2,
+ "tools_edrills_others_ring": 0.2,
+ "tools_edrills_circular": True,
+ "tools_edrills_oblong": False,
+ "tools_edrills_square": False,
+ "tools_edrills_rectangular": False,
+ "tools_edrills_others": False,
# Utilities
# file associations
diff --git a/README.md b/README.md
index 3cc30ba8..19a3cfa8 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,12 @@ CAD program, and create G-Code for Isolation routing.
=================================================
-10.02.2019
+11.01.2020
+
+- fixed an issue in the Distance Tool
+- expanded the Extract Drills Tool to use a particular annular ring for each type of aperture flash (pad)
+
+10.02.2020
- working on a new tool: Extract Drills Tool who will create a Excellon object out of the apertures of a Gerber object
- finished the GUI in the Extract Drills Tool
@@ -17,14 +22,14 @@ CAD program, and create G-Code for Isolation routing.
- finished the Extract Drills Tool
- fixed a small issue in the DoubleSided Tool
-8.01.2019
+8.01.2020
- working in NCC Tool
- selected rows in the Tools Tables will stay colored in blue after loosing focus instead of the default gray
- in NCC Tool the Tool name in the Parameters section will be the Tool ID in the Tool Table
- added an exception catch in case the plotcanvas init failed for the OpenGL graphic engine and warn user about what happened
-7.01.2019
+7.01.2020
- solved issue #368 - when using the Enable/Disable prj context menu entries the plotted status is not updated in the object properties
- updates in NCC Tool
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index f52aced9..05314ffe 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -2009,6 +2009,10 @@ class FCTable(QtWidgets.QTableWidget):
palette = QtGui.QPalette()
palette.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.Highlight,
palette.color(QtGui.QPalette.Active, QtGui.QPalette.Highlight))
+
+ # make inactive rows text some color as active; may be useful in the future
+ # palette.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.HighlightedText,
+ # palette.color(QtGui.QPalette.Active, QtGui.QPalette.HighlightedText))
self.setPalette(palette)
if drag_drop:
diff --git a/flatcamTools/ToolDistance.py b/flatcamTools/ToolDistance.py
index c1f9ed8b..1a5bc568 100644
--- a/flatcamTools/ToolDistance.py
+++ b/flatcamTools/ToolDistance.py
@@ -361,11 +361,12 @@ class Distance(FlatCAMTool):
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
+ if dx != 0.0:
+ try:
+ angle = math.degrees(math.atan(dy / dx))
+ self.angle_entry.set_value('%.*f' % (self.decimals, angle))
+ except Exception as e:
+ pass
self.total_distance_entry.set_value('%.*f' % (self.decimals, abs(d)))
self.app.ui.rel_position_label.setText(
@@ -424,11 +425,13 @@ class Distance(FlatCAMTool):
if len(self.points) == 1:
self.utility_geometry(pos=pos)
# and display the temporary angle
- try:
- angle = math.degrees(math.atan(dy / dx))
- self.angle_entry.set_value('%.*f' % (self.decimals, angle))
- except Exception as e:
- pass
+ if dx != 0.0:
+ try:
+ angle = math.degrees(math.atan(dy / dx))
+ self.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
except Exception as e:
log.debug("Distance.on_mouse_move_meas() --> %s" % str(e))
diff --git a/flatcamTools/ToolExtractDrills.py b/flatcamTools/ToolExtractDrills.py
index 5d2a604e..fa50ecc8 100644
--- a/flatcamTools/ToolExtractDrills.py
+++ b/flatcamTools/ToolExtractDrills.py
@@ -2,13 +2,9 @@
from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, EvalEntry, FCEntry
-from FlatCAMObj import FlatCAMGerber, FlatCAMExcellon, FlatCAMGeometry
-
-from numpy import Inf
+from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox
from shapely.geometry import Point
-from shapely import affinity
import logging
import gettext
@@ -60,8 +56,62 @@ class ToolExtractDrills(FlatCAMTool):
self.grb_label.setToolTip('%s.' % _("Gerber from which to extract drill holes"))
# grid_lay.addRow("Bottom Layer:", self.object_combo)
- grid_lay.addWidget(self.grb_label, 0, 0)
- grid_lay.addWidget(self.gerber_object_combo, 1, 0)
+ grid_lay.addWidget(self.grb_label, 0, 0, 1, 2)
+ grid_lay.addWidget(self.gerber_object_combo, 1, 0, 1, 2)
+
+ self.padt_label = QtWidgets.QLabel("%s:" % _("Processed Pads Type"))
+ self.padt_label.setToolTip(
+ _("The type of pads shape to be processed.\n"
+ "If the PCB has many SMD pads with rectangular pads,\n"
+ "disable the Rectangular aperture.")
+ )
+
+ grid_lay.addWidget(self.padt_label, 2, 0, 1, 2)
+
+ # Circular Aperture Selection
+ self.circular_cb = FCCheckBox('%s' % _("Circular"))
+ self.circular_cb.setToolTip(
+ _("Create drills from circular pads.")
+ )
+
+ grid_lay.addWidget(self.circular_cb, 3, 0, 1, 2)
+
+ # Oblong Aperture Selection
+ self.oblong_cb = FCCheckBox('%s' % _("Oblong"))
+ self.oblong_cb.setToolTip(
+ _("Create drills from oblong pads.")
+ )
+
+ grid_lay.addWidget(self.oblong_cb, 4, 0, 1, 2)
+
+ # Square Aperture Selection
+ self.square_cb = FCCheckBox('%s' % _("Square"))
+ self.square_cb.setToolTip(
+ _("Create drills from square pads.")
+ )
+
+ grid_lay.addWidget(self.square_cb, 5, 0, 1, 2)
+
+ # Rectangular Aperture Selection
+ self.rectangular_cb = FCCheckBox('%s' % _("Rectangular"))
+ self.rectangular_cb.setToolTip(
+ _("Create drills from rectangular pads.")
+ )
+
+ grid_lay.addWidget(self.rectangular_cb, 6, 0, 1, 2)
+
+ # Others type of Apertures Selection
+ self.other_cb = FCCheckBox('%s' % _("Others"))
+ self.other_cb.setToolTip(
+ _("Create drills from other types of pad shape.")
+ )
+
+ grid_lay.addWidget(self.other_cb, 7, 0, 1, 2)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid_lay.addWidget(separator_line, 8, 0, 1, 2)
# ## Grid Layout
grid1 = QtWidgets.QGridLayout()
@@ -102,22 +152,95 @@ class ToolExtractDrills(FlatCAMTool):
grid1.addWidget(self.dia_label, 7, 0)
grid1.addWidget(self.dia_entry, 7, 1)
- # Annular Ring value
- self.ring_entry = FCDoubleSpinner()
- self.ring_entry.set_precision(self.decimals)
- self.ring_entry.set_range(0.0000, 9999.9999)
+ self.ring_frame = QtWidgets.QFrame()
+ self.ring_frame.setContentsMargins(0, 0, 0, 0)
+ self.layout.addWidget(self.ring_frame)
- self.ring_label = QtWidgets.QLabel('%s:' % _("Annular Ring"))
+ self.ring_box = QtWidgets.QVBoxLayout()
+ self.ring_box.setContentsMargins(0, 0, 0, 0)
+ self.ring_frame.setLayout(self.ring_box)
+
+ # ## Grid Layout
+ grid2 = QtWidgets.QGridLayout()
+ grid2.setColumnStretch(0, 0)
+ grid2.setColumnStretch(1, 1)
+ self.ring_box.addLayout(grid2)
+
+ # Annular Ring value
+ self.ring_label = QtWidgets.QLabel('%s' % _("Annular Ring"))
self.ring_label.setToolTip(
_("The size of annular ring.\n"
"The copper sliver between the drill hole exterior\n"
"and the margin of the copper pad.")
)
+ grid2.addWidget(self.ring_label, 0, 0, 1, 2)
- grid1.addWidget(self.ring_label, 8, 0)
- grid1.addWidget(self.ring_entry, 8, 1)
+ # Circular Annular Ring Value
+ self.circular_ring_label = QtWidgets.QLabel('%s:' % _("Circular"))
+ self.circular_ring_label.setToolTip(
+ _("The size of annular ring for circular pads.")
+ )
- # Calculate Bounding box
+ self.circular_ring_entry = FCDoubleSpinner()
+ self.circular_ring_entry.set_precision(self.decimals)
+ self.circular_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid2.addWidget(self.circular_ring_label, 1, 0)
+ grid2.addWidget(self.circular_ring_entry, 1, 1)
+
+ # Oblong Annular Ring Value
+ self.oblong_ring_label = QtWidgets.QLabel('%s:' % _("Oblong"))
+ self.oblong_ring_label.setToolTip(
+ _("The size of annular ring for oblong pads.")
+ )
+
+ self.oblong_ring_entry = FCDoubleSpinner()
+ self.oblong_ring_entry.set_precision(self.decimals)
+ self.oblong_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid2.addWidget(self.oblong_ring_label, 2, 0)
+ grid2.addWidget(self.oblong_ring_entry, 2, 1)
+
+ # Square Annular Ring Value
+ self.square_ring_label = QtWidgets.QLabel('%s:' % _("Square"))
+ self.square_ring_label.setToolTip(
+ _("The size of annular ring for square pads.")
+ )
+
+ self.square_ring_entry = FCDoubleSpinner()
+ self.square_ring_entry.set_precision(self.decimals)
+ self.square_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid2.addWidget(self.square_ring_label, 3, 0)
+ grid2.addWidget(self.square_ring_entry, 3, 1)
+
+ # Rectangular Annular Ring Value
+ self.rectangular_ring_label = QtWidgets.QLabel('%s:' % _("Rectangular"))
+ self.rectangular_ring_label.setToolTip(
+ _("The size of annular ring for rectangular pads.")
+ )
+
+ self.rectangular_ring_entry = FCDoubleSpinner()
+ self.rectangular_ring_entry.set_precision(self.decimals)
+ self.rectangular_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid2.addWidget(self.rectangular_ring_label, 4, 0)
+ grid2.addWidget(self.rectangular_ring_entry, 4, 1)
+
+ # Others Annular Ring Value
+ self.other_ring_label = QtWidgets.QLabel('%s:' % _("Others"))
+ self.other_ring_label.setToolTip(
+ _("The size of annular ring for other pads.")
+ )
+
+ self.other_ring_entry = FCDoubleSpinner()
+ self.other_ring_entry.set_precision(self.decimals)
+ self.other_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid2.addWidget(self.other_ring_label, 5, 0)
+ grid2.addWidget(self.other_ring_entry, 5, 1)
+
+ # Extract drills from Gerber apertures flashes (pads)
self.e_drills_button = QtWidgets.QPushButton(_("Extract Drills"))
self.e_drills_button.setToolTip(
_("Extract drills from a given Gerber file.")
@@ -145,11 +268,42 @@ class ToolExtractDrills(FlatCAMTool):
""")
self.layout.addWidget(self.reset_button)
+ self.circular_ring_entry.setEnabled(False)
+ self.oblong_ring_entry.setEnabled(False)
+ self.square_ring_entry.setEnabled(False)
+ self.rectangular_ring_entry.setEnabled(False)
+ self.other_ring_entry.setEnabled(False)
+
# ## Signals
self.hole_size_radio.activated_custom.connect(self.on_hole_size_toggle)
self.e_drills_button.clicked.connect(self.on_extract_drills_click)
self.reset_button.clicked.connect(self.set_tool_ui)
+ self.circular_cb.stateChanged.connect(
+ lambda state:
+ self.circular_ring_entry.setDisabled(False) if state else self.circular_ring_entry.setDisabled(True)
+ )
+
+ self.oblong_cb.stateChanged.connect(
+ lambda state:
+ self.oblong_ring_entry.setDisabled(False) if state else self.oblong_ring_entry.setDisabled(True)
+ )
+
+ self.square_cb.stateChanged.connect(
+ lambda state:
+ self.square_ring_entry.setDisabled(False) if state else self.square_ring_entry.setDisabled(True)
+ )
+
+ self.rectangular_cb.stateChanged.connect(
+ lambda state:
+ self.rectangular_ring_entry.setDisabled(False) if state else self.rectangular_ring_entry.setDisabled(True)
+ )
+
+ self.other_cb.stateChanged.connect(
+ lambda state:
+ self.other_ring_entry.setDisabled(False) if state else self.other_ring_entry.setDisabled(True)
+ )
+
def install(self, icon=None, separator=None, **kwargs):
FlatCAMTool.install(self, icon, separator, shortcut='ALT+I', **kwargs)
@@ -186,12 +340,28 @@ class ToolExtractDrills(FlatCAMTool):
self.hole_size_radio.set_value(self.app.defaults["tools_edrills_hole_type"])
self.dia_entry.set_value(float(self.app.defaults["tools_edrills_hole_fixed_dia"]))
- self.ring_entry.set_value(float(self.app.defaults["tools_edrills_hole_ring"]))
+
+ self.circular_ring_entry.set_value(float(self.app.defaults["tools_edrills_circular_ring"]))
+ self.oblong_ring_entry.set_value(float(self.app.defaults["tools_edrills_oblong_ring"]))
+ self.square_ring_entry.set_value(float(self.app.defaults["tools_edrills_square_ring"]))
+ self.rectangular_ring_entry.set_value(float(self.app.defaults["tools_edrills_rectangular_ring"]))
+ self.other_ring_entry.set_value(float(self.app.defaults["tools_edrills_others_ring"]))
+
+ self.circular_cb.set_value(self.app.defaults["tools_edrills_circular"])
+ self.oblong_cb.set_value(self.app.defaults["tools_edrills_oblong"])
+ self.square_cb.set_value(self.app.defaults["tools_edrills_square"])
+ self.rectangular_cb.set_value(self.app.defaults["tools_edrills_rectangular"])
+ self.other_cb.set_value(self.app.defaults["tools_edrills_others"])
def on_extract_drills_click(self):
drill_dia = self.dia_entry.get_value()
- ring_val = self.ring_entry.get_value()
+ circ_r_val = self.circular_ring_entry.get_value()
+ oblong_r_val = self.oblong_ring_entry.get_value()
+ square_r_val = self.square_ring_entry.get_value()
+ rect_r_val = self.rectangular_ring_entry.get_value()
+ other_r_val = self.other_ring_entry.get_value()
+
drills = list()
tools = dict()
@@ -211,6 +381,29 @@ class ToolExtractDrills(FlatCAMTool):
if mode == 'fixed':
tools = {"1": {"C": drill_dia}}
for apid, apid_value in fcobj.apertures.items():
+ ap_type = apid_value['type']
+
+ if ap_type == 'C':
+ if self.circular_cb.get_value() is False:
+ continue
+ elif ap_type == 'O':
+ if self.oblong_cb.get_value() is False:
+ continue
+ elif ap_type == 'R':
+ width = float(apid_value['width'])
+ height = float(apid_value['height'])
+
+ # if the height == width (float numbers so the reason for the following)
+ if round(width, self.decimals) == round(height, self.decimals):
+ if self.square_cb.get_value() is False:
+ continue
+ else:
+ if self.rectangular_cb.get_value() is False:
+ continue
+ else:
+ if self.other_cb.get_value() is False:
+ continue
+
for geo_el in apid_value['geometry']:
if 'follow' in geo_el and isinstance(geo_el['follow'], Point):
drills.append({"point": geo_el['follow'], "tool": "1"})
@@ -218,22 +411,46 @@ class ToolExtractDrills(FlatCAMTool):
tools["1"]['solid_geometry'] = list()
else:
tools["1"]['solid_geometry'].append(geo_el['follow'])
+
+ if 'solid_geometry' not in tools["1"] or not tools["1"]['solid_geometry']:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("No drills extracted. Try different parameters."))
+ return
else:
+ drills_found = set()
for apid, apid_value in fcobj.apertures.items():
ap_type = apid_value['type']
- dia = float(apid_value['size']) - (2 * ring_val)
- if ap_type == 'R' or ap_type == 'O':
+ dia = None
+ if ap_type == 'C':
+ if self.circular_cb.get_value():
+ dia = float(apid_value['size']) - (2 * circ_r_val)
+ elif ap_type == 'R' or ap_type == 'O':
width = float(apid_value['width'])
height = float(apid_value['height'])
- if width >= height:
- dia = float(apid_value['height']) - (2 * ring_val)
+
+ # if the height == width (float numbers so the reason for the following)
+ if abs(float('%.*f' % (self.decimals, width)) - float('%.*f' % (self.decimals, height))) < \
+ (10 ** -self.decimals):
+ if self.square_cb.get_value():
+ dia = float(apid_value['height']) - (2 * square_r_val)
else:
- dia = float(apid_value['width']) - (2 * ring_val)
+ if self.rectangular_cb.get_value():
+ if width > height:
+ dia = float(apid_value['height']) - (2 * rect_r_val)
+ else:
+ dia = float(apid_value['width']) - (2 * rect_r_val)
+ else:
+ if self.other_cb.get_value():
+ dia = float(apid_value['size']) - (2 * other_r_val)
+
+ # if dia is None then none of the above applied so we skip th e following
+ if dia is None:
+ continue
tool_in_drills = False
for tool, tool_val in tools.items():
- if abs(float('%.*f' % (self.decimals, tool_val["C"])) - dia) < (10 ** -self.decimals):
+ if abs(float('%.*f' % (self.decimals, tool_val["C"])) - float('%.*f' % (self.decimals, dia))) < \
+ (10 ** -self.decimals):
tool_in_drills = tool
if tool_in_drills is False:
@@ -255,6 +472,16 @@ class ToolExtractDrills(FlatCAMTool):
else:
tools[tool_in_drills]['solid_geometry'].append(geo_el['follow'])
+ if tool_in_drills in tools:
+ if 'solid_geometry' not in tools[tool_in_drills] or not tools[tool_in_drills]['solid_geometry']:
+ drills_found.add(False)
+ else:
+ drills_found.add(True)
+
+ if True not in drills_found:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("No drills extracted. Try different parameters."))
+ return
+
def obj_init(obj_inst, app_inst):
obj_inst.tools = tools
obj_inst.drills = drills
@@ -269,14 +496,12 @@ class ToolExtractDrills(FlatCAMTool):
self.dia_entry.setDisabled(False)
self.dia_label.setDisabled(False)
- self.ring_label.setDisabled(True)
- self.ring_entry.setDisabled(True)
+ self.ring_frame.setDisabled(True)
else:
self.dia_entry.setDisabled(True)
self.dia_label.setDisabled(True)
- self.ring_label.setDisabled(False)
- self.ring_entry.setDisabled(False)
+ self.ring_frame.setDisabled(False)
def reset_fields(self):
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
From f8c22ea32fb1c3dc8d3380afcb103d90ef63496c Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 12 Jan 2020 00:30:17 +0200
Subject: [PATCH 007/209] - Extract Drills Tool: fixed issue with oblong pads
and with pads made from aperture macros - Extract Drills Tool: added controls
in Edit -> Preferences
---
FlatCAMApp.py | 14 +++
README.md | 2 +
flatcamGUI/PreferencesUI.py | 190 +++++++++++++++++++++++++++++-
flatcamTools/ToolExtractDrills.py | 27 ++++-
4 files changed, 228 insertions(+), 5 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 05c2a850..63504639 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -1592,6 +1592,20 @@ class App(QtCore.QObject):
"tools_cal_toolchange_xy": self.ui.tools2_defaults_form.tools2_cal_group.toolchange_xy_entry,
"tools_cal_sec_point": self.ui.tools2_defaults_form.tools2_cal_group.second_point_radio,
+ # Extract Drills Tool
+ "tools_edrills_hole_type": self.ui.tools2_defaults_form.tools2_edrills_group.hole_size_radio,
+ "tools_edrills_hole_fixed_dia": self.ui.tools2_defaults_form.tools2_edrills_group.dia_entry,
+ "tools_edrills_circular_ring": self.ui.tools2_defaults_form.tools2_edrills_group.circular_ring_entry,
+ "tools_edrills_oblong_ring": self.ui.tools2_defaults_form.tools2_edrills_group.oblong_ring_entry,
+ "tools_edrills_square_ring": self.ui.tools2_defaults_form.tools2_edrills_group.square_ring_entry,
+ "tools_edrills_rectangular_ring": self.ui.tools2_defaults_form.tools2_edrills_group.rectangular_ring_entry,
+ "tools_edrills_others_ring": self.ui.tools2_defaults_form.tools2_edrills_group.other_ring_entry,
+ "tools_edrills_circular": self.ui.tools2_defaults_form.tools2_edrills_group.circular_cb,
+ "tools_edrills_oblong": self.ui.tools2_defaults_form.tools2_edrills_group.oblong_cb,
+ "tools_edrills_square": self.ui.tools2_defaults_form.tools2_edrills_group.square_cb,
+ "tools_edrills_rectangular": self.ui.tools2_defaults_form.tools2_edrills_group.rectangular_cb,
+ "tools_edrills_others": self.ui.tools2_defaults_form.tools2_edrills_group.other_cb,
+
# Utilities
# File associations
"fa_excellon": self.ui.util_defaults_form.fa_excellon_group.exc_list_text,
diff --git a/README.md b/README.md
index 19a3cfa8..afbc0e06 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,8 @@ CAD program, and create G-Code for Isolation routing.
- fixed an issue in the Distance Tool
- expanded the Extract Drills Tool to use a particular annular ring for each type of aperture flash (pad)
+- Extract Drills Tool: fixed issue with oblong pads and with pads made from aperture macros
+- Extract Drills Tool: added controls in Edit -> Preferences
10.02.2020
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index b84a514b..a073b534 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -242,19 +242,23 @@ class Tools2PreferencesUI(QtWidgets.QWidget):
self.tools2_cal_group = Tools2CalPrefGroupUI(decimals=self.decimals)
self.tools2_cal_group.setMinimumWidth(220)
+ self.tools2_edrills_group = Tools2EDrillsPrefGroupUI(decimals=self.decimals)
+ self.tools2_edrills_group.setMinimumWidth(220)
+
self.vlay = QtWidgets.QVBoxLayout()
self.vlay.addWidget(self.tools2_checkrules_group)
self.vlay.addWidget(self.tools2_optimal_group)
self.vlay1 = QtWidgets.QVBoxLayout()
self.vlay1.addWidget(self.tools2_qrcode_group)
+ self.vlay1.addWidget(self.tools2_fiducials_group)
self.vlay2 = QtWidgets.QVBoxLayout()
self.vlay2.addWidget(self.tools2_cfill_group)
self.vlay3 = QtWidgets.QVBoxLayout()
- self.vlay3.addWidget(self.tools2_fiducials_group)
self.vlay3.addWidget(self.tools2_cal_group)
+ self.vlay3.addWidget(self.tools2_edrills_group)
self.layout.addLayout(self.vlay)
self.layout.addLayout(self.vlay1)
@@ -7618,6 +7622,190 @@ class Tools2CalPrefGroupUI(OptionsGroupUI):
self.layout.addStretch()
+class Tools2EDrillsPrefGroupUI(OptionsGroupUI):
+ def __init__(self, decimals=4, parent=None):
+
+ super(Tools2EDrillsPrefGroupUI, self).__init__(self)
+
+ self.setTitle(str(_("Extract Drills Options")))
+ self.decimals = decimals
+
+ # ## Grid Layout
+ grid_lay = QtWidgets.QGridLayout()
+ self.layout.addLayout(grid_lay)
+ grid_lay.setColumnStretch(0, 0)
+ grid_lay.setColumnStretch(1, 1)
+
+ self.param_label = QtWidgets.QLabel('%s:' % _('Parameters'))
+ self.param_label.setToolTip(
+ _("Parameters used for this tool.")
+ )
+ grid_lay.addWidget(self.param_label, 0, 0, 1, 2)
+
+ self.padt_label = QtWidgets.QLabel("%s:" % _("Processed Pads Type"))
+ self.padt_label.setToolTip(
+ _("The type of pads shape to be processed.\n"
+ "If the PCB has many SMD pads with rectangular pads,\n"
+ "disable the Rectangular aperture.")
+ )
+
+ grid_lay.addWidget(self.padt_label, 2, 0, 1, 2)
+
+ # Circular Aperture Selection
+ self.circular_cb = FCCheckBox('%s' % _("Circular"))
+ self.circular_cb.setToolTip(
+ _("Create drills from circular pads.")
+ )
+
+ grid_lay.addWidget(self.circular_cb, 3, 0, 1, 2)
+
+ # Oblong Aperture Selection
+ self.oblong_cb = FCCheckBox('%s' % _("Oblong"))
+ self.oblong_cb.setToolTip(
+ _("Create drills from oblong pads.")
+ )
+
+ grid_lay.addWidget(self.oblong_cb, 4, 0, 1, 2)
+
+ # Square Aperture Selection
+ self.square_cb = FCCheckBox('%s' % _("Square"))
+ self.square_cb.setToolTip(
+ _("Create drills from square pads.")
+ )
+
+ grid_lay.addWidget(self.square_cb, 5, 0, 1, 2)
+
+ # Rectangular Aperture Selection
+ self.rectangular_cb = FCCheckBox('%s' % _("Rectangular"))
+ self.rectangular_cb.setToolTip(
+ _("Create drills from rectangular pads.")
+ )
+
+ grid_lay.addWidget(self.rectangular_cb, 6, 0, 1, 2)
+
+ # Others type of Apertures Selection
+ self.other_cb = FCCheckBox('%s' % _("Others"))
+ self.other_cb.setToolTip(
+ _("Create drills from other types of pad shape.")
+ )
+
+ grid_lay.addWidget(self.other_cb, 7, 0, 1, 2)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid_lay.addWidget(separator_line, 8, 0, 1, 2)
+
+ # ## Axis
+ self.hole_size_radio = RadioSet([{'label': _("Fixed"), 'value': 'fixed'},
+ {'label': _("Proportional"), 'value': 'prop'}])
+ self.hole_size_label = QtWidgets.QLabel('%s:' % _("Hole Size"))
+ self.hole_size_label.setToolTip(
+ _("The type of hole size. Can be:\n"
+ "- Fixed -> all holes will have a set size\n"
+ "- Proprotional -> each hole will havea a variable size\n"
+ "such as to preserve a set annular ring"))
+
+ grid_lay.addWidget(self.hole_size_label, 9, 0)
+ grid_lay.addWidget(self.hole_size_radio, 9, 1)
+
+ # grid_lay1.addWidget(QtWidgets.QLabel(''))
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid_lay.addWidget(separator_line, 10, 0, 1, 2)
+
+ # Diameter value
+ self.dia_entry = FCDoubleSpinner()
+ self.dia_entry.set_precision(self.decimals)
+ self.dia_entry.set_range(0.0000, 9999.9999)
+
+ self.dia_label = QtWidgets.QLabel('%s:' % _("Diameter"))
+ self.dia_label.setToolTip(
+ _("Fixed hole diameter.")
+ )
+
+ grid_lay.addWidget(self.dia_label, 11, 0)
+ grid_lay.addWidget(self.dia_entry, 11, 1)
+
+ # Annular Ring value
+ self.ring_label = QtWidgets.QLabel('%s' % _("Annular Ring"))
+ self.ring_label.setToolTip(
+ _("The size of annular ring.\n"
+ "The copper sliver between the drill hole exterior\n"
+ "and the margin of the copper pad.")
+ )
+ grid_lay.addWidget(self.ring_label, 12, 0, 1, 2)
+
+ # Circular Annular Ring Value
+ self.circular_ring_label = QtWidgets.QLabel('%s:' % _("Circular"))
+ self.circular_ring_label.setToolTip(
+ _("The size of annular ring for circular pads.")
+ )
+
+ self.circular_ring_entry = FCDoubleSpinner()
+ self.circular_ring_entry.set_precision(self.decimals)
+ self.circular_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid_lay.addWidget(self.circular_ring_label, 13, 0)
+ grid_lay.addWidget(self.circular_ring_entry, 13, 1)
+
+ # Oblong Annular Ring Value
+ self.oblong_ring_label = QtWidgets.QLabel('%s:' % _("Oblong"))
+ self.oblong_ring_label.setToolTip(
+ _("The size of annular ring for oblong pads.")
+ )
+
+ self.oblong_ring_entry = FCDoubleSpinner()
+ self.oblong_ring_entry.set_precision(self.decimals)
+ self.oblong_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid_lay.addWidget(self.oblong_ring_label, 14, 0)
+ grid_lay.addWidget(self.oblong_ring_entry, 14, 1)
+
+ # Square Annular Ring Value
+ self.square_ring_label = QtWidgets.QLabel('%s:' % _("Square"))
+ self.square_ring_label.setToolTip(
+ _("The size of annular ring for square pads.")
+ )
+
+ self.square_ring_entry = FCDoubleSpinner()
+ self.square_ring_entry.set_precision(self.decimals)
+ self.square_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid_lay.addWidget(self.square_ring_label, 15, 0)
+ grid_lay.addWidget(self.square_ring_entry, 15, 1)
+
+ # Rectangular Annular Ring Value
+ self.rectangular_ring_label = QtWidgets.QLabel('%s:' % _("Rectangular"))
+ self.rectangular_ring_label.setToolTip(
+ _("The size of annular ring for rectangular pads.")
+ )
+
+ self.rectangular_ring_entry = FCDoubleSpinner()
+ self.rectangular_ring_entry.set_precision(self.decimals)
+ self.rectangular_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid_lay.addWidget(self.rectangular_ring_label, 16, 0)
+ grid_lay.addWidget(self.rectangular_ring_entry, 16, 1)
+
+ # Others Annular Ring Value
+ self.other_ring_label = QtWidgets.QLabel('%s:' % _("Others"))
+ self.other_ring_label.setToolTip(
+ _("The size of annular ring for other pads.")
+ )
+
+ self.other_ring_entry = FCDoubleSpinner()
+ self.other_ring_entry.set_precision(self.decimals)
+ self.other_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid_lay.addWidget(self.other_ring_label, 17, 0)
+ grid_lay.addWidget(self.other_ring_entry, 17, 1)
+
+ self.layout.addStretch()
+
+
class FAExcPrefGroupUI(OptionsGroupUI):
def __init__(self, decimals=4, parent=None):
# OptionsGroupUI.__init__(self, "Excellon File associations Preferences", parent=None)
diff --git a/flatcamTools/ToolExtractDrills.py b/flatcamTools/ToolExtractDrills.py
index fa50ecc8..c0300549 100644
--- a/flatcamTools/ToolExtractDrills.py
+++ b/flatcamTools/ToolExtractDrills.py
@@ -59,7 +59,7 @@ class ToolExtractDrills(FlatCAMTool):
grid_lay.addWidget(self.grb_label, 0, 0, 1, 2)
grid_lay.addWidget(self.gerber_object_combo, 1, 0, 1, 2)
- self.padt_label = QtWidgets.QLabel("%s:" % _("Processed Pads Type"))
+ self.padt_label = QtWidgets.QLabel("%s" % _("Processed Pads Type"))
self.padt_label.setToolTip(
_("The type of pads shape to be processed.\n"
"If the PCB has many SMD pads with rectangular pads,\n"
@@ -424,7 +424,15 @@ class ToolExtractDrills(FlatCAMTool):
if ap_type == 'C':
if self.circular_cb.get_value():
dia = float(apid_value['size']) - (2 * circ_r_val)
- elif ap_type == 'R' or ap_type == 'O':
+ elif ap_type == 'O':
+ width = float(apid_value['width'])
+ height = float(apid_value['height'])
+ if self.oblong_cb.get_value():
+ if width > height:
+ dia = float(apid_value['height']) - (2 * rect_r_val)
+ else:
+ dia = float(apid_value['width']) - (2 * rect_r_val)
+ elif ap_type == 'R':
width = float(apid_value['width'])
height = float(apid_value['height'])
@@ -441,9 +449,20 @@ class ToolExtractDrills(FlatCAMTool):
dia = float(apid_value['width']) - (2 * rect_r_val)
else:
if self.other_cb.get_value():
- dia = float(apid_value['size']) - (2 * other_r_val)
+ try:
+ dia = float(apid_value['size']) - (2 * other_r_val)
+ except KeyError:
+ if ap_type == 'AM':
+ pol = apid_value['geometry'][0]['solid']
+ x0, y0, x1, y1 = pol.bounds
+ dx = x1 - x0
+ dy = y1 - y0
+ if dx <= dy:
+ dia = dx - (2 * other_r_val)
+ else:
+ dia = dy - (2 * other_r_val)
- # if dia is None then none of the above applied so we skip th e following
+ # if dia is None then none of the above applied so we skip the following
if dia is None:
continue
From a9b93cafa17f5cfebb65d9d1e0b5aff2f41d67c1 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 12 Jan 2020 03:28:05 +0200
Subject: [PATCH 008/209] - improved the circle approximation resolution
---
FlatCAMObj.py | 11 ++++-------
README.md | 6 +++++-
camlib.py | 31 +++++++++++++++----------------
3 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 712d766a..1ba88825 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -1307,7 +1307,6 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
else:
iso_name = outname
- # TODO: This is ugly. Create way to pass data into init function.
def iso_init(geo_obj, app_obj):
# Propagate options
geo_obj.options["cnctooldia"] = str(self.options["isotooldia"])
@@ -1318,8 +1317,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
iso_offset = dia * ((2 * i + 1) / 2.0) - (i * overlap * dia)
# if milling type is climb then the move is counter-clockwise around features
- mill_t = 1 if milling_type == 'cl' else 0
- geom = self.generate_envelope(iso_offset, mill_t, geometry=work_geo, env_iso_type=iso_t,
+ mill_dir = 1 if milling_type == 'cl' else 0
+ geom = self.generate_envelope(iso_offset, mill_dir, geometry=work_geo, env_iso_type=iso_t,
follow=follow, nr_passes=i)
if geom == 'fail':
@@ -1438,7 +1437,6 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
else:
iso_name = outname
- # TODO: This is ugly. Create way to pass data into init function.
def iso_init(geo_obj, app_obj):
# Propagate options
geo_obj.options["cnctooldia"] = str(self.options["isotooldia"])
@@ -1448,9 +1446,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
geo_obj.tool_type = 'C1'
# if milling type is climb then the move is counter-clockwise around features
- mill_t = 1 if milling_type == 'cl' else 0
- mill_t = 1 if milling_type == 'cl' else 0
- geom = self.generate_envelope(offset, mill_t, geometry=work_geo, env_iso_type=iso_t,
+ mill_dir = 1 if milling_type == 'cl' else 0
+ geom = self.generate_envelope(offset, mill_dir, geometry=work_geo, env_iso_type=iso_t,
follow=follow,
nr_passes=i)
diff --git a/README.md b/README.md
index afbc0e06..39de865e 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+12.01.2020
+
+- improved the circle approximation resolution
+
11.01.2020
- fixed an issue in the Distance Tool
@@ -36,7 +40,7 @@ CAD program, and create G-Code for Isolation routing.
- solved issue #368 - when using the Enable/Disable prj context menu entries the plotted status is not updated in the object properties
- updates in NCC Tool
-6.01.2019
+6.01.2020
- working on new NCC Tool
diff --git a/camlib.py b/camlib.py
index 1e58a423..6bbaf9ef 100644
--- a/camlib.py
+++ b/camlib.py
@@ -458,8 +458,8 @@ class Geometry(object):
"""
defaults = {
- "units": 'in',
- "geo_steps_per_circle": 64
+ "units": 'mm',
+ # "geo_steps_per_circle": 128
}
def __init__(self, geo_steps_per_circle=None):
@@ -529,12 +529,12 @@ class Geometry(object):
if type(self.solid_geometry) is list:
self.solid_geometry.append(Point(origin).buffer(
- radius, int(int(self.geo_steps_per_circle) / 4)))
+ radius, int(self.geo_steps_per_circle)))
return
try:
self.solid_geometry = self.solid_geometry.union(Point(origin).buffer(
- radius, int(int(self.geo_steps_per_circle) / 4)))
+ radius, int(self.geo_steps_per_circle)))
except Exception as e:
log.error("Failed to run union on polygons. %s" % str(e))
return
@@ -944,7 +944,7 @@ class Geometry(object):
geo_iso.append(pol)
else:
corner_type = 1 if corner is None else corner
- geo_iso.append(pol.buffer(offset, int(int(self.geo_steps_per_circle) / 4), join_style=corner_type))
+ geo_iso.append(pol.buffer(offset, int(self.geo_steps_per_circle), join_style=corner_type))
pol_nr += 1
disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
@@ -959,8 +959,7 @@ class Geometry(object):
geo_iso.append(working_geo)
else:
corner_type = 1 if corner is None else corner
- geo_iso.append(working_geo.buffer(offset, int(int(self.geo_steps_per_circle) / 4),
- join_style=corner_type))
+ geo_iso.append(working_geo.buffer(offset, int(self.geo_steps_per_circle), join_style=corner_type))
self.app.proc_container.update_view_text(' %s' % _("Buffering"))
geo_iso = unary_union(geo_iso)
@@ -1225,7 +1224,7 @@ class Geometry(object):
# Can only result in a Polygon or MultiPolygon
# NOTE: The resulting polygon can be "empty".
- current = polygon.buffer((-tooldia / 1.999999), int(int(steps_per_circle) / 4))
+ current = polygon.buffer((-tooldia / 1.999999), int(steps_per_circle))
if current.area == 0:
# Otherwise, trying to to insert current.exterior == None
# into the FlatCAMStorage will fail.
@@ -1254,7 +1253,7 @@ class Geometry(object):
QtWidgets.QApplication.processEvents()
# Can only result in a Polygon or MultiPolygon
- current = current.buffer(-tooldia * (1 - overlap), int(int(steps_per_circle) / 4))
+ current = current.buffer(-tooldia * (1 - overlap), int(steps_per_circle))
if current.area > 0:
# current can be a MultiPolygon
@@ -1372,11 +1371,12 @@ class Geometry(object):
# Clean inside edges (contours) of the original polygon
if contour:
- outer_edges = [x.exterior for x in autolist(
- polygon_to_clear.buffer(-tooldia / 2, int(steps_per_circle / 4)))]
+ outer_edges = [
+ x.exterior for x in autolist(polygon_to_clear.buffer(-tooldia / 2, int(steps_per_circle)))
+ ]
inner_edges = []
# Over resulting polygons
- for x in autolist(polygon_to_clear.buffer(-tooldia / 2, int(steps_per_circle / 4))):
+ for x in autolist(polygon_to_clear.buffer(-tooldia / 2, int(steps_per_circle))):
for y in x.interiors: # Over interiors of each polygon
inner_edges.append(y)
# geoms += outer_edges + inner_edges
@@ -1626,7 +1626,7 @@ class Geometry(object):
# Straight line from current_pt to pt.
# Is the toolpath inside the geometry?
walk_path = LineString([current_pt, pt])
- walk_cut = walk_path.buffer(tooldia / 2, int(steps_per_circle / 4))
+ walk_cut = walk_path.buffer(tooldia / 2, int(steps_per_circle))
if walk_cut.within(boundary) and walk_path.length < max_walk:
# log.debug("Walk to path #%d is inside. Joining." % path_count)
@@ -4213,7 +4213,7 @@ class CNCjob(Geometry):
radius = np.sqrt(gobj['I']**2 + gobj['J']**2)
start = np.arctan2(-gobj['J'], -gobj['I'])
stop = np.arctan2(-center[1] + y, -center[0] + x)
- path += arc(center, radius, start, stop, arcdir[current['G']], int(self.steps_per_circle / 4))
+ path += arc(center, radius, start, stop, arcdir[current['G']], int(self.steps_per_circle))
current['X'] = x
current['Y'] = y
@@ -4362,8 +4362,7 @@ class CNCjob(Geometry):
visible=visible, layer=1)
else:
# For Incremental coordinates type G91
- self.app.inform.emit('[ERROR_NOTCL] %s' %
- _('G91 coordinates not implemented ...'))
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _('G91 coordinates not implemented ...'))
for geo in gcode_parsed:
if geo['kind'][0] == 'T':
current_position = geo['geom'].coords[0]
From c9111dac9b861d0144e52f45c58d5dc9aef05991 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 12 Jan 2020 04:05:13 +0200
Subject: [PATCH 009/209] - fixed an issue in Gerber parser with detecting old
kind of units
---
README.md | 1 +
camlib.py | 8 ++++----
flatcamParsers/ParseGerber.py | 1 +
3 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 39de865e..57224d90 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
12.01.2020
- improved the circle approximation resolution
+- fixed an issue in Gerber parser with detecting old kind of units
11.01.2020
diff --git a/camlib.py b/camlib.py
index 6bbaf9ef..063478b1 100644
--- a/camlib.py
+++ b/camlib.py
@@ -528,13 +528,13 @@ class Geometry(object):
self.solid_geometry = []
if type(self.solid_geometry) is list:
- self.solid_geometry.append(Point(origin).buffer(
- radius, int(self.geo_steps_per_circle)))
+ self.solid_geometry.append(Point(origin).buffer(radius, int(self.geo_steps_per_circle)))
return
try:
- self.solid_geometry = self.solid_geometry.union(Point(origin).buffer(
- radius, int(self.geo_steps_per_circle)))
+ self.solid_geometry = self.solid_geometry.union(
+ Point(origin).buffer(radius, int(self.geo_steps_per_circle))
+ )
except Exception as e:
log.error("Failed to run union on polygons. %s" % str(e))
return
diff --git a/flatcamParsers/ParseGerber.py b/flatcamParsers/ParseGerber.py
index 6f79c31a..7fbfce1f 100644
--- a/flatcamParsers/ParseGerber.py
+++ b/flatcamParsers/ParseGerber.py
@@ -595,6 +595,7 @@ class Gerber(Geometry):
match = self.units_re.search(gline)
if match:
obs_gerber_units = {'0': 'IN', '1': 'MM'}[match.group(1)]
+ self.units = obs_gerber_units
log.warning("Gerber obsolete units found = %s" % obs_gerber_units)
# Changed for issue #80
# self.convert_units({'0': 'IN', '1': 'MM'}[match.group(1)])
From 5b3f318e567555f258bb7fab5e48b36dcd3fa854 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 12 Jan 2020 17:26:48 +0200
Subject: [PATCH 010/209] - if CTRL key is pressed during app startup the app
will start in the Legacy(2D) graphic engine compatibility mode
---
FlatCAMApp.py | 9 ++++++---
README.md | 1 +
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 63504639..2b25ad8f 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -12025,7 +12025,12 @@ class App(QtCore.QObject):
else:
plot_container = self.ui.right_layout
- if self.is_legacy is False:
+ modifier = QtWidgets.QApplication.queryKeyboardModifiers()
+ if self.is_legacy is True or modifier == QtCore.Qt.ControlModifier:
+ self.is_legacy = True
+ self.defaults["global_graphic_engine"] = "2D"
+ self.plotcanvas = PlotCanvasLegacy(plot_container, self)
+ else:
try:
self.plotcanvas = PlotCanvas(plot_container, self)
except Exception as er:
@@ -12038,8 +12043,6 @@ class App(QtCore.QObject):
msg += msg_txt
self.inform.emit(msg)
return 'fail'
- else:
- self.plotcanvas = PlotCanvasLegacy(plot_container, self)
# So it can receive key presses
self.plotcanvas.native.setFocus()
diff --git a/README.md b/README.md
index 57224d90..786cbb6b 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- improved the circle approximation resolution
- fixed an issue in Gerber parser with detecting old kind of units
+- if CTRL key is pressed during app startup the app will start in the Legacy(2D) graphic engine compatibility mode
11.01.2020
From 02cfd9671566718e4d799d9d025d0a7fd2afaa88 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 13 Jan 2020 16:06:29 +0200
Subject: [PATCH 011/209] - fixed a small GUI issue in Excellon UI when Basic
mode is active
---
FlatCAMApp.py | 4 ++--
FlatCAMObj.py | 5 ++++-
README.md | 4 ++++
3 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 2b25ad8f..43e94c63 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -524,8 +524,8 @@ class App(QtCore.QObject):
"global_cursor_type": "small",
"global_cursor_size": 20,
"global_cursor_width": 2,
- "global_cursor_color": '#000000',
- "global_cursor_color_enabled": False,
+ "global_cursor_color": '#FF0000',
+ "global_cursor_color_enabled": True,
# Gerber General
"gerber_plot": True,
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 1ba88825..6b98f6f2 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -2638,7 +2638,10 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
horizontal_header.setDefaultSectionSize(70)
horizontal_header.setSectionResizeMode(0, QtWidgets.QHeaderView.Fixed)
horizontal_header.resizeSection(0, 20)
- horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
+ if self.app.defaults["global_app_level"] == 'b':
+ horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
+ else:
+ horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
horizontal_header.setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeToContents)
horizontal_header.setSectionResizeMode(3, QtWidgets.QHeaderView.ResizeToContents)
horizontal_header.setSectionResizeMode(4, QtWidgets.QHeaderView.Stretch)
diff --git a/README.md b/README.md
index 786cbb6b..a30058fc 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+13.01.2020
+
+- fixed a small GUI issue in Excellon UI when Basic mode is active
+
12.01.2020
- improved the circle approximation resolution
From 41277d78ce99bf742862a3337c27ed61da139f6a Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 13 Jan 2020 21:43:25 +0200
Subject: [PATCH 012/209] - started the add of a new Tool: Align Objects Tool
which will align (sync) objects of Gerber or Excellon type
---
FlatCAMApp.py | 4 +
README.md | 1 +
flatcamTools/ToolAlignObjects.py | 423 ++++++++++++++++++++++++++++++
flatcamTools/ToolExtractDrills.py | 6 +
flatcamTools/__init__.py | 4 +-
share/align16.png | Bin 0 -> 457 bytes
share/align32.png | Bin 0 -> 539 bytes
7 files changed, 436 insertions(+), 2 deletions(-)
create mode 100644 flatcamTools/ToolAlignObjects.py
create mode 100644 share/align16.png
create mode 100644 share/align32.png
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 43e94c63..ca691c00 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -2493,6 +2493,7 @@ class App(QtCore.QObject):
self.copper_thieving_tool = None
self.fiducial_tool = None
self.edrills_tool = None
+ self.align_objects_tool = None
# always install tools only after the shell is initialized because the self.inform.emit() depends on shell
try:
@@ -3065,6 +3066,9 @@ class App(QtCore.QObject):
before=self.dblsidedtool.menuAction,
separator=False)
+ self.align_objects_tool = AlignObjects(self)
+ self.align_objects_tool.install(icon=QtGui.QIcon(self.resource_location + '/align16.png'), separator=False)
+
self.edrills_tool = ToolExtractDrills(self)
self.edrills_tool.install(icon=QtGui.QIcon(self.resource_location + '/drill16.png'), separator=True)
diff --git a/README.md b/README.md
index a30058fc..414cffad 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
13.01.2020
- fixed a small GUI issue in Excellon UI when Basic mode is active
+- started the add of a new Tool: Align Objects Tool which will align (sync) objects of Gerber or Excellon type
12.01.2020
diff --git a/flatcamTools/ToolAlignObjects.py b/flatcamTools/ToolAlignObjects.py
new file mode 100644
index 00000000..e787d0c6
--- /dev/null
+++ b/flatcamTools/ToolAlignObjects.py
@@ -0,0 +1,423 @@
+# ##########################################################
+# FlatCAM: 2D Post-processing for Manufacturing #
+# File Author: Marius Adrian Stanciu (c) #
+# Date: 1/13/2020 #
+# MIT Licence #
+# ##########################################################
+
+from PyQt5 import QtWidgets, QtGui, QtCore
+from FlatCAMTool import FlatCAMTool
+
+from flatcamGUI.GUIElements import FCComboBox
+
+from copy import deepcopy
+
+import numpy as np
+
+from shapely.geometry import Point
+
+import gettext
+import FlatCAMTranslation as fcTranslate
+import builtins
+import logging
+
+fcTranslate.apply_language('strings')
+if '_' not in builtins.__dict__:
+ _ = gettext.gettext
+
+log = logging.getLogger('base')
+
+
+class AlignObjects(FlatCAMTool):
+
+ toolName = _("Align Objects")
+
+ def __init__(self, app):
+ FlatCAMTool.__init__(self, app)
+
+ self.app = app
+ self.decimals = app.decimals
+
+ self.canvas = self.app.plotcanvas
+
+ # ## 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
+ grid0 = QtWidgets.QGridLayout()
+ grid0.setColumnStretch(0, 0)
+ grid0.setColumnStretch(1, 1)
+ self.layout.addLayout(grid0)
+
+ self.aligned_label = QtWidgets.QLabel('%s' % _("Selection of the aligned object"))
+ grid0.addWidget(self.aligned_label, 0, 0, 1, 2)
+
+ # Type of object to be aligned
+ self.type_obj_combo = QtWidgets.QComboBox()
+ 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"))
+
+ self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
+ self.type_obj_combo_label.setToolTip(
+ _("Specify the type of object to be aligned.\n"
+ "It can be of type: Gerber, Excellon or Geometry.\n"
+ "The selection here decide the type of objects that will be\n"
+ "in the Object combobox.")
+ )
+ grid0.addWidget(self.type_obj_combo_label, 2, 0)
+ grid0.addWidget(self.type_obj_combo, 2, 1)
+
+ # Object to be aligned
+ self.object_combo = QtWidgets.QComboBox()
+ self.object_combo.setModel(self.app.collection)
+ self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.object_combo.setCurrentIndex(1)
+
+ self.object_label = QtWidgets.QLabel('%s:' % _("Object"))
+ self.object_label.setToolTip(
+ _("Object to be aligned.")
+ )
+
+ grid0.addWidget(self.object_label, 3, 0)
+ grid0.addWidget(self.object_combo, 3, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 4, 0, 1, 2)
+
+ self.aligned_label = QtWidgets.QLabel('%s' % _("Selection of the aligner object"))
+ self.aligned_label.setToolTip(
+ _("Object to which the other objects will be aligned to (moved).")
+ )
+ grid0.addWidget(self.aligned_label, 6, 0, 1, 2)
+
+ # Type of object to be aligned to = aligner
+ self.type_aligner_obj_combo = QtWidgets.QComboBox()
+ self.type_aligner_obj_combo.addItem("Gerber")
+ self.type_aligner_obj_combo.addItem("Excellon")
+ self.type_aligner_obj_combo.addItem("Geometry")
+
+ self.type_aligner_obj_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
+ self.type_aligner_obj_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/drill16.png"))
+ self.type_aligner_obj_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
+
+ self.type_aligner_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
+ self.type_aligner_obj_combo_label.setToolTip(
+ _("Specify the type of object to be aligned to.\n"
+ "It can be of type: Gerber, Excellon or Geometry.\n"
+ "The selection here decide the type of objects that will be\n"
+ "in the Object combobox.")
+ )
+ grid0.addWidget(self.type_aligner_obj_combo_label, 7, 0)
+ grid0.addWidget(self.type_aligner_obj_combo, 7, 1)
+
+ # Object to be aligned to = aligner
+ self.aligner_object_combo = QtWidgets.QComboBox()
+ self.aligner_object_combo.setModel(self.app.collection)
+ self.aligner_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.aligner_object_combo.setCurrentIndex(1)
+
+ self.aligner_object_label = QtWidgets.QLabel('%s:' % _("Object"))
+ self.aligner_object_label.setToolTip(
+ _("Object to be aligned to. Aligner.")
+ )
+
+ grid0.addWidget(self.aligner_object_label, 8, 0)
+ grid0.addWidget(self.aligner_object_combo, 8, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 9, 0, 1, 2)
+
+ # Buttons
+ self.align_object_button = QtWidgets.QPushButton(_("Align Object"))
+ self.align_object_button.setToolTip(
+ _("Align the specified object to the aligner object.\n"
+ "If only one point is used then it assumes translation.\n"
+ "If tho points are used it assume translation and rotation.")
+ )
+ self.align_object_button.setStyleSheet("""
+ QPushButton
+ {
+ font-weight: bold;
+ }
+ """)
+ self.layout.addWidget(self.align_object_button)
+
+ self.layout.addStretch()
+
+ # ## Reset Tool
+ self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
+ self.reset_button.setToolTip(
+ _("Will reset the tool parameters.")
+ )
+ self.reset_button.setStyleSheet("""
+ QPushButton
+ {
+ font-weight: bold;
+ }
+ """)
+ self.layout.addWidget(self.reset_button)
+
+ # Signals
+ self.align_object_button.clicked.connect(self.on_align)
+ self.type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
+ self.type_aligner_obj_combo.currentIndexChanged.connect(self.on_type_aligner_index_changed)
+ self.reset_button.clicked.connect(self.set_tool_ui)
+
+ self.mr = None
+
+ # if the mouse events are connected to a local method set this True
+ self.local_connected = False
+
+ # store the status of the grid
+ self.grid_status_memory = None
+
+ self.aligned_obj = None
+ self.aligner_obj = None
+
+ # here store the alignment points for the aligned object
+ self.aligned_clicked_points = list()
+
+ # here store the alignment points for the aligner object
+ self.aligner_clicked_points = list()
+
+ # counter for the clicks
+ self.click_cnt = 0
+
+ def run(self, toggle=True):
+ self.app.report_usage("ToolAlignObjects()")
+
+ if toggle:
+ # if the splitter is hidden, display it, else hide it but only if the current widget is the same
+ if self.app.ui.splitter.sizes()[0] == 0:
+ self.app.ui.splitter.setSizes([1, 1])
+ else:
+ try:
+ if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
+ # if tab is populated with the tool but it does not have the focus, focus on it
+ if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
+ # focus on Tool Tab
+ self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
+ else:
+ self.app.ui.splitter.setSizes([0, 1])
+ except AttributeError:
+ pass
+ else:
+ if self.app.ui.splitter.sizes()[0] == 0:
+ self.app.ui.splitter.setSizes([1, 1])
+
+ FlatCAMTool.run(self)
+ self.set_tool_ui()
+
+ self.app.ui.notebook.setTabText(2, _("Align Tool"))
+
+ def install(self, icon=None, separator=None, **kwargs):
+ FlatCAMTool.install(self, icon, separator, shortcut='ALT+A', **kwargs)
+
+ def set_tool_ui(self):
+ self.reset_fields()
+
+ self.click_cnt = 0
+
+ if self.local_connected is True:
+ self.disconnect_cal_events()
+
+ def on_type_obj_index_changed(self):
+ obj_type = self.type_obj_combo.currentIndex()
+ self.object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
+ self.object_combo.setCurrentIndex(0)
+
+ def on_type_aligner_index_changed(self):
+ obj_type = self.type_aligner_obj_combo.currentIndex()
+ self.aligner_object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
+ self.aligner_object_combo.setCurrentIndex(0)
+
+ def on_align(self):
+
+ obj_sel_index = self.object_combo.currentIndex()
+ obj_model_index = self.app.collection.index(obj_sel_index, 0, self.object_combo.rootModelIndex())
+ try:
+ self.aligned_obj = obj_model_index.internalPointer().obj
+ except AttributeError:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no aligned FlatCAM object selected..."))
+ return
+
+ aligner_obj_sel_index = self.object_combo.currentIndex()
+ aligner_obj_model_index = self.app.collection.index(
+ aligner_obj_sel_index, 0, self.object_combo.rootModelIndex())
+
+ try:
+ self.aligner_obj = aligner_obj_model_index.internalPointer().obj
+ except AttributeError:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no aligner FlatCAM object selected..."))
+ return
+
+ # disengage the grid snapping since it will be hard to find the drills or pads on grid
+ if self.app.ui.grid_snap_btn.isChecked():
+ self.grid_status_memory = True
+ self.app.ui.grid_snap_btn.trigger()
+ else:
+ self.grid_status_memory = False
+
+ self.mr = self.canvas.graph_event_connect('mouse_release', self.on_mouse_click_release)
+
+ if self.app.is_legacy is False:
+ self.canvas.graph_event_disconnect('mouse_release', self.app.on_mouse_click_release_over_plot)
+ else:
+ self.canvas.graph_event_disconnect(self.app.mr)
+
+ self.local_connected = True
+
+ self.app.inform.emit(_("Get First alignment point on the aligned object."))
+
+ def on_mouse_click_release(self, event):
+ if self.app.is_legacy is False:
+ event_pos = event.pos
+ right_button = 2
+ self.app.event_is_dragging = self.app.event_is_dragging
+ else:
+ event_pos = (event.xdata, event.ydata)
+ right_button = 3
+ self.app.event_is_dragging = self.app.ui.popMenu.mouse_is_panning
+
+ pos_canvas = self.canvas.translate_coords(event_pos)
+
+ if event.button == 1:
+ click_pt = Point([pos_canvas[0], pos_canvas[1]])
+
+ if self.app.selection_type is not None:
+ # delete previous selection shape
+ self.app.delete_selection_shape()
+ self.app.selection_type = None
+ else:
+ if self.target_obj.kind.lower() == 'excellon':
+ for tool, tool_dict in self.target_obj.tools.items():
+ for geo in tool_dict['solid_geometry']:
+ if click_pt.within(geo):
+ center_pt = geo.centroid
+ self.click_points.append(
+ [
+ float('%.*f' % (self.decimals, center_pt.x)),
+ float('%.*f' % (self.decimals, center_pt.y))
+ ]
+ )
+ self.check_points()
+ elif self.target_obj.kind.lower() == 'gerber':
+ for apid, apid_val in self.target_obj.apertures.items():
+ for geo_el in apid_val['geometry']:
+ if 'solid' in geo_el:
+ if click_pt.within(geo_el['solid']):
+ if isinstance(geo_el['follow'], Point):
+ center_pt = geo_el['solid'].centroid
+ self.click_points.append(
+ [
+ float('%.*f' % (self.decimals, center_pt.x)),
+ float('%.*f' % (self.decimals, center_pt.y))
+ ]
+ )
+ self.check_points()
+
+ elif event.button == right_button and self.app.event_is_dragging is False:
+ if not len(self.click_points):
+ self.reset_calibration_points()
+ self.disconnect_cal_events()
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled by user request."))
+
+ def check_points(self):
+ if len(self.aligned_click_points) == 1:
+ self.app.inform.emit(_("Get Second alignment point on aligned object. "
+ "Or right click to get First alignment point on the aligner object."))
+
+ if len(self.aligned_click_points) == 2:
+ self.app.inform.emit(_("Get First alignment point on the aligner object."))
+
+ if len(self.aligner_click_points) == 1:
+ self.app.inform.emit(_("Get Second alignment point on the aligner object. Or right click to finish."))
+ self.align_translate()
+ self.align_rotate()
+ self.disconnect_cal_events()
+
+ def align_translate(self):
+ pass
+
+ def align_rotate(self):
+ pass
+
+ def execute(self):
+ aligned_name = self.object_combo.currentText()
+
+ # Get source object.
+ try:
+ aligned_obj = self.app.collection.get_by_name(str(aligned_name))
+ except Exception as e:
+ log.debug("AlignObjects.on_align() --> %s" % str(e))
+ self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), aligned_name))
+ return "Could not retrieve object: %s" % aligned_name
+
+ if aligned_obj is None:
+ self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Object not found"), aligned_obj))
+ return "Object not found: %s" % aligned_obj
+
+ aligner_name = self.box_combo.currentText()
+
+ try:
+ aligner_obj = self.app.collection.get_by_name(aligner_name)
+ except Exception as e:
+ log.debug("AlignObjects.on_align() --> %s" % str(e))
+ self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), aligner_name))
+ return "Could not retrieve object: %s" % aligner_name
+
+ if aligner_obj is None:
+ self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), aligner_name))
+
+ def align_job():
+ pass
+
+ proc = self.app.proc_container.new(_("Working..."))
+
+ def job_thread(app_obj):
+ try:
+ align_job()
+ app_obj.inform.emit('[success] %s' % _("Panel created successfully."))
+ except Exception as ee:
+ proc.done()
+ log.debug(str(ee))
+ return
+ proc.done()
+
+ self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+
+ def disconnect_cal_events(self):
+ # restore the Grid snapping if it was active before
+ if self.grid_status_memory is True:
+ self.app.ui.grid_snap_btn.trigger()
+
+ self.app.mr = self.canvas.graph_event_connect('mouse_release', self.app.on_mouse_click_release_over_plot)
+
+ if self.app.is_legacy is False:
+ self.canvas.graph_event_disconnect('mouse_release', self.on_mouse_click_release)
+ else:
+ self.canvas.graph_event_disconnect(self.mr)
+
+ self.local_connected = False
+ self.click_cnt = 0
+
+ def reset_fields(self):
+ self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.aligner_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
diff --git a/flatcamTools/ToolExtractDrills.py b/flatcamTools/ToolExtractDrills.py
index c0300549..e0c72c95 100644
--- a/flatcamTools/ToolExtractDrills.py
+++ b/flatcamTools/ToolExtractDrills.py
@@ -1,3 +1,9 @@
+# ##########################################################
+# FlatCAM: 2D Post-processing for Manufacturing #
+# File Author: Marius Adrian Stanciu (c) #
+# Date: 1/10/2020 #
+# MIT Licence #
+# ##########################################################
from PyQt5 import QtWidgets, QtCore
diff --git a/flatcamTools/__init__.py b/flatcamTools/__init__.py
index be389e70..a593e6c4 100644
--- a/flatcamTools/__init__.py
+++ b/flatcamTools/__init__.py
@@ -5,6 +5,8 @@ from flatcamTools.ToolCalibration import ToolCalibration
from flatcamTools.ToolCutOut import CutOut
from flatcamTools.ToolDblSided import DblSidedTool
+from flatcamTools.ToolExtractDrills import ToolExtractDrills
+from flatcamTools.ToolAlignObjects import AlignObjects
from flatcamTools.ToolFilm import Film
@@ -31,8 +33,6 @@ from flatcamTools.ToolRulesCheck import RulesCheck
from flatcamTools.ToolCopperThieving import ToolCopperThieving
from flatcamTools.ToolFiducials import ToolFiducials
-from flatcamTools.ToolExtractDrills import ToolExtractDrills
-
from flatcamTools.ToolShell import FCShell
from flatcamTools.ToolSolderPaste import SolderPaste
from flatcamTools.ToolSub import ToolSub
diff --git a/share/align16.png b/share/align16.png
new file mode 100644
index 0000000000000000000000000000000000000000..d21f1cec306b4d64a76075be2dd1bcb12a04237c
GIT binary patch
literal 457
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijSl0AZa
z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+uenMVO6iP5s=4O
z;1OBOz`%C|gc+x5^GO2**-JcqUD=;7@(N2TujDx{1r(a@>EaloaenDVTdqS10xb`Z
z&%Yw(nJ>%2pOn6|DS~TfllljlFtMbW#W!B)uF-8e;uN@Fh3nC69iGDmyS+V>I9tn(
zZrH-pns>C|lm5I}Zo2BpG(_9Olaw4{jAI$@$WAZ*tL6*r2<1_o9J2D}v-zz{&vkei>9nO2Eg
zLyhW$A3zO~ARB`7(@M${i&7cN%ggmL^RkPR6AM!H@{7`Ezq0{_6oaR$pUXO@geCw+
CkCP1m
literal 0
HcmV?d00001
diff --git a/share/align32.png b/share/align32.png
new file mode 100644
index 0000000000000000000000000000000000000000..b81511a28901c479d7b078e86de71a66c8d92602
GIT binary patch
literal 539
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50
z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzZ+Rj;xUkjGiz
z5n0T@z;^_M8K-LVNdpDhOFVsD*`F}-3QJ1nGsvv~3cd7naSZV|es!uXUz3AC>;47e
z3KeYL8a7S#8xO_3Kft=>i;7BE)UB230>YWL&7G~Sy^P#EjlA!?)Kq?LyFIhgIzO#U
zyd^{Oja{tXB<6Q_zVhX!lr26S>}4?d#ed$Mh|?T$HedLrnH)80JkI6*`u&DOzjOFJ
zEHD4mIH;zidcpg{jp-U)53Q?SrCn91lzCCin&7#Ld;O#dYdub$RXUZ+#%UVpD`2d~
zm~c?0p+!;MI96@pjrJt*oWA=W9g=&vS3Ek_;W59_dj-!Vt5bZ6d2^*q>&1QaFPX_N
z*?*KJ-t7aoytkI}46}R3#Cgv-*j-b21Pnd~)e_f;l9a@fRIB8oR3OD*WME{VYhb8r
zXdGf_X=P*zMA`-hRt5$KFKOID(U6;;l9^VCTf>I_328tLk{}y`^V3So6N^$A%FE03
gGV`*FlM@S4_413-XTP(N0xDwgboFyt=akR{080n5DgXcg
literal 0
HcmV?d00001
From 5c932dc5cc0bdc86bee72957fe20a92bc2dd18b8 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Tue, 14 Jan 2020 01:36:37 +0200
Subject: [PATCH 013/209] - fixed an issue in Gerber parser introduced recently
due of changes made to make Gerber files produced by Sprint Layout
---
README.md | 1 +
flatcamParsers/ParseGerber.py | 3 ++-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 414cffad..6e9d4270 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- fixed a small GUI issue in Excellon UI when Basic mode is active
- started the add of a new Tool: Align Objects Tool which will align (sync) objects of Gerber or Excellon type
+- fixed an issue in Gerber parser introduced recently due of changes made to make Gerber files produced by Sprint Layout
12.01.2020
diff --git a/flatcamParsers/ParseGerber.py b/flatcamParsers/ParseGerber.py
index 7fbfce1f..16ce8f37 100644
--- a/flatcamParsers/ParseGerber.py
+++ b/flatcamParsers/ParseGerber.py
@@ -835,7 +835,8 @@ class Gerber(Geometry):
# --- Buffered ---
geo_dict = dict()
if current_aperture in self.apertures:
- buff_value = float(self.apertures[current_aperture]['size']) / 2.0
+ # the following line breaks loading of Circuit Studio Gerber files
+ # buff_value = float(self.apertures[current_aperture]['size']) / 2.0
# region_geo = Polygon(path).buffer(buff_value, int(self.steps_per_circle))
region_geo = Polygon(path) # Sprint Layout Gerbers with ground fill are crashed with above
else:
From f9ec233b0f4d27417ec3279be1cd4eecc1ef3e85 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Tue, 14 Jan 2020 02:45:03 +0200
Subject: [PATCH 014/209] - working on the Align Objects Tool
---
FlatCAMApp.py | 3 +
README.md | 1 +
flatcamTools/ToolAlignObjects.py | 104 ++++++++++++++++++++++---------
3 files changed, 79 insertions(+), 29 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index ca691c00..b7aa387b 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -968,6 +968,9 @@ class App(QtCore.QObject):
"tools_edrills_rectangular": False,
"tools_edrills_others": False,
+ # Align Objects Tool
+ "tools_align_objects_align_type": 'sp',
+
# Utilities
# file associations
"fa_excellon": 'drd, drl, exc, ncd, tap, xln',
diff --git a/README.md b/README.md
index 6e9d4270..ac71ea1e 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ CAD program, and create G-Code for Isolation routing.
- fixed a small GUI issue in Excellon UI when Basic mode is active
- started the add of a new Tool: Align Objects Tool which will align (sync) objects of Gerber or Excellon type
- fixed an issue in Gerber parser introduced recently due of changes made to make Gerber files produced by Sprint Layout
+- working on the Align Objects Tool
12.01.2020
diff --git a/flatcamTools/ToolAlignObjects.py b/flatcamTools/ToolAlignObjects.py
index e787d0c6..a0e031ab 100644
--- a/flatcamTools/ToolAlignObjects.py
+++ b/flatcamTools/ToolAlignObjects.py
@@ -8,7 +8,7 @@
from PyQt5 import QtWidgets, QtGui, QtCore
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import FCComboBox
+from flatcamGUI.GUIElements import FCComboBox, RadioSet
from copy import deepcopy
@@ -61,7 +61,7 @@ class AlignObjects(FlatCAMTool):
grid0.addWidget(self.aligned_label, 0, 0, 1, 2)
# Type of object to be aligned
- self.type_obj_combo = QtWidgets.QComboBox()
+ self.type_obj_combo = FCComboBox()
self.type_obj_combo.addItem("Gerber")
self.type_obj_combo.addItem("Excellon")
self.type_obj_combo.addItem("Geometry")
@@ -81,7 +81,7 @@ class AlignObjects(FlatCAMTool):
grid0.addWidget(self.type_obj_combo, 2, 1)
# Object to be aligned
- self.object_combo = QtWidgets.QComboBox()
+ 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.setCurrentIndex(1)
@@ -106,7 +106,7 @@ class AlignObjects(FlatCAMTool):
grid0.addWidget(self.aligned_label, 6, 0, 1, 2)
# Type of object to be aligned to = aligner
- self.type_aligner_obj_combo = QtWidgets.QComboBox()
+ self.type_aligner_obj_combo = FCComboBox()
self.type_aligner_obj_combo.addItem("Gerber")
self.type_aligner_obj_combo.addItem("Excellon")
self.type_aligner_obj_combo.addItem("Geometry")
@@ -126,7 +126,7 @@ class AlignObjects(FlatCAMTool):
grid0.addWidget(self.type_aligner_obj_combo, 7, 1)
# Object to be aligned to = aligner
- self.aligner_object_combo = QtWidgets.QComboBox()
+ self.aligner_object_combo = FCComboBox()
self.aligner_object_combo.setModel(self.app.collection)
self.aligner_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.aligner_object_combo.setCurrentIndex(1)
@@ -144,6 +144,30 @@ class AlignObjects(FlatCAMTool):
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
grid0.addWidget(separator_line, 9, 0, 1, 2)
+ # Alignment Type
+ self.a_type_lbl = QtWidgets.QLabel('%s:' % _("Alignment Type"))
+ self.a_type_lbl.setToolTip(
+ _("The type of alignment can be:\n"
+ "- Single Point -> it require a single point of sync, the action will be a translation\n"
+ "- Dual Point -> it require two points of sync, the action will be translation followed by rotation")
+ )
+ self.a_type_radio = RadioSet(
+ [
+ {'label': _('Single Point'), 'value': 'sp'},
+ {'label': _('Dual Point'), 'value': 'dp'}
+ ],
+ orientation='horizontal',
+ stretch=False
+ )
+
+ grid0.addWidget(self.a_type_lbl, 10, 0, 1, 2)
+ grid0.addWidget(self.a_type_radio, 11, 0, 1, 2)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 12, 0, 1, 2)
+
# Buttons
self.align_object_button = QtWidgets.QPushButton(_("Align Object"))
self.align_object_button.setToolTip(
@@ -191,14 +215,13 @@ class AlignObjects(FlatCAMTool):
self.aligned_obj = None
self.aligner_obj = None
- # here store the alignment points for the aligned object
- self.aligned_clicked_points = list()
+ # this is one of the objects: self.aligned_obj or self.aligner_obj
+ self.target_obj = None
- # here store the alignment points for the aligner object
- self.aligner_clicked_points = list()
+ # here store the alignment points
+ self.clicked_points = list()
- # counter for the clicks
- self.click_cnt = 0
+ self.align_type = None
def run(self, toggle=True):
self.app.report_usage("ToolAlignObjects()")
@@ -233,7 +256,12 @@ class AlignObjects(FlatCAMTool):
def set_tool_ui(self):
self.reset_fields()
- self.click_cnt = 0
+ self.clicked_points = list()
+ self.target_obj = None
+ self.aligned_obj = None
+ self.aligner_obj = None
+
+ self.a_type_radio.set_value(self.app.defaults["tools_align_objects_align_type"])
if self.local_connected is True:
self.disconnect_cal_events()
@@ -268,6 +296,8 @@ class AlignObjects(FlatCAMTool):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no aligner FlatCAM object selected..."))
return
+ self.align_type = self.a_type_radio.get_value()
+
# disengage the grid snapping since it will be hard to find the drills or pads on grid
if self.app.ui.grid_snap_btn.isChecked():
self.grid_status_memory = True
@@ -285,6 +315,7 @@ class AlignObjects(FlatCAMTool):
self.local_connected = True
self.app.inform.emit(_("Get First alignment point on the aligned object."))
+ self.target_obj = self.aligned_obj
def on_mouse_click_release(self, event):
if self.app.is_legacy is False:
@@ -311,7 +342,7 @@ class AlignObjects(FlatCAMTool):
for geo in tool_dict['solid_geometry']:
if click_pt.within(geo):
center_pt = geo.centroid
- self.click_points.append(
+ self.clicked_points.append(
[
float('%.*f' % (self.decimals, center_pt.x)),
float('%.*f' % (self.decimals, center_pt.y))
@@ -325,7 +356,7 @@ class AlignObjects(FlatCAMTool):
if click_pt.within(geo_el['solid']):
if isinstance(geo_el['follow'], Point):
center_pt = geo_el['solid'].centroid
- self.click_points.append(
+ self.clicked_points.append(
[
float('%.*f' % (self.decimals, center_pt.x)),
float('%.*f' % (self.decimals, center_pt.y))
@@ -334,24 +365,37 @@ class AlignObjects(FlatCAMTool):
self.check_points()
elif event.button == right_button and self.app.event_is_dragging is False:
- if not len(self.click_points):
- self.reset_calibration_points()
- self.disconnect_cal_events()
- self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled by user request."))
+ self.clicked_points = list()
+ self.disconnect_cal_events()
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled by user request."))
def check_points(self):
- if len(self.aligned_click_points) == 1:
- self.app.inform.emit(_("Get Second alignment point on aligned object. "
- "Or right click to get First alignment point on the aligner object."))
+ if self.align_type == 'sp':
+ if len(self.clicked_points) == 1:
+ self.app.inform.emit(_("Get First alignment point on the aligner object."))
+ # TODO: not working
+ self.target_obj = self.aligner_obj
- if len(self.aligned_click_points) == 2:
- self.app.inform.emit(_("Get First alignment point on the aligner object."))
+ if len(self.clicked_points) == 2:
+ self.app.inform.emit('[success] %s' % _("Done."))
+ self.align_translate()
+ self.disconnect_cal_events()
+ else:
+ if len(self.clicked_points) == 1:
+ self.app.inform.emit(_("Get Second alignment point on aligned object. Or right click to cancel."))
- if len(self.aligner_click_points) == 1:
- self.app.inform.emit(_("Get Second alignment point on the aligner object. Or right click to finish."))
- self.align_translate()
- self.align_rotate()
- self.disconnect_cal_events()
+ if len(self.clicked_points) == 2:
+ self.app.inform.emit(_("Get First alignment point on the aligner object."))
+ self.target_obj = self.aligner_obj
+
+ if len(self.clicked_points) == 3:
+ self.app.inform.emit(_("Get Second alignment point on the aligner object. Or right click to cancel."))
+
+ if len(self.clicked_points) == 4:
+ self.app.inform.emit('[success] %s' % _("Done."))
+ self.align_translate()
+ self.align_rotate()
+ self.disconnect_cal_events()
def align_translate(self):
pass
@@ -416,7 +460,9 @@ class AlignObjects(FlatCAMTool):
self.canvas.graph_event_disconnect(self.mr)
self.local_connected = False
- self.click_cnt = 0
+ self.target_obj = None
+ self.aligned_obj = None
+ self.aligner_obj = None
def reset_fields(self):
self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
From 853f3f5d125df08bcf4690a532d04de70b39cc3b Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Tue, 14 Jan 2020 03:27:15 +0200
Subject: [PATCH 015/209] - working on the Align Objects Tool
---
flatcamTools/ToolAlignObjects.py | 35 ++++++++++++++++++++++++--------
1 file changed, 26 insertions(+), 9 deletions(-)
diff --git a/flatcamTools/ToolAlignObjects.py b/flatcamTools/ToolAlignObjects.py
index a0e031ab..505c5a30 100644
--- a/flatcamTools/ToolAlignObjects.py
+++ b/flatcamTools/ToolAlignObjects.py
@@ -10,11 +10,8 @@ from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import FCComboBox, RadioSet
-from copy import deepcopy
-
-import numpy as np
-
from shapely.geometry import Point
+from shapely.affinity import translate, rotate
import gettext
import FlatCAMTranslation as fcTranslate
@@ -221,6 +218,9 @@ class AlignObjects(FlatCAMTool):
# here store the alignment points
self.clicked_points = list()
+ self.new_start = None
+ self.new_stop = None
+
self.align_type = None
def run(self, toggle=True):
@@ -286,9 +286,9 @@ class AlignObjects(FlatCAMTool):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no aligned FlatCAM object selected..."))
return
- aligner_obj_sel_index = self.object_combo.currentIndex()
+ aligner_obj_sel_index = self.aligner_object_combo.currentIndex()
aligner_obj_model_index = self.app.collection.index(
- aligner_obj_sel_index, 0, self.object_combo.rootModelIndex())
+ aligner_obj_sel_index, 0, self.aligner_object_combo.rootModelIndex())
try:
self.aligner_obj = aligner_obj_model_index.internalPointer().obj
@@ -373,12 +373,13 @@ class AlignObjects(FlatCAMTool):
if self.align_type == 'sp':
if len(self.clicked_points) == 1:
self.app.inform.emit(_("Get First alignment point on the aligner object."))
- # TODO: not working
self.target_obj = self.aligner_obj
if len(self.clicked_points) == 2:
self.app.inform.emit('[success] %s' % _("Done."))
self.align_translate()
+ self.app.plot_all()
+
self.disconnect_cal_events()
else:
if len(self.clicked_points) == 1:
@@ -395,13 +396,29 @@ class AlignObjects(FlatCAMTool):
self.app.inform.emit('[success] %s' % _("Done."))
self.align_translate()
self.align_rotate()
+ self.app.plot_all()
+
self.disconnect_cal_events()
def align_translate(self):
- pass
+ dx = self.clicked_points[1][0] - self.clicked_points[0][0]
+ dy = self.clicked_points[1][1] - self.clicked_points[0][1]
+
+ if self.align_type == 'dp':
+ self.new_start = translate(Point(self.clicked_points[2]), xoff=dx, yoff=dy)
+ self.new_dest = translate(Point(self.clicked_points[3]), xoff=dx, yoff=dy)
+
+ self.aligned_obj.offset((dx, dy))
+
+ # Update the object bounding box options
+ a, b, c, d = self.aligned_obj.bounds()
+ self.aligned_obj.options['xmin'] = a
+ self.aligned_obj.options['ymin'] = b
+ self.aligned_obj.options['xmax'] = c
+ self.aligned_obj.options['ymax'] = d
def align_rotate(self):
- pass
+ print(self.new_start.x == self.new_dest.x)
def execute(self):
aligned_name = self.object_combo.currentText()
From 9a3f3b600b6aa733df09808ea40ad394ee863b3b Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Tue, 14 Jan 2020 16:23:23 +0200
Subject: [PATCH 016/209] - in Extract Drill Tool added a new method of drills
extraction. The methods are: fixed diameter, fixed annular ring and
proportional - in Align Objects Tool finished the Single Point method of
alignment
---
FlatCAMApp.py | 32 +++--
README.md | 5 +
flatcamGUI/PreferencesUI.py | 72 +++++++----
flatcamTools/ToolAlignObjects.py | 106 +++++++++++-----
flatcamTools/ToolExtractDrills.py | 194 +++++++++++++++++++++++++++---
5 files changed, 326 insertions(+), 83 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index b7aa387b..80df6cab 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -957,6 +957,7 @@ class App(QtCore.QObject):
# Drills Extraction Tool
"tools_edrills_hole_type": 'fixed',
"tools_edrills_hole_fixed_dia": 0.5,
+ "tools_edrills_hole_prop_factor": 80.0,
"tools_edrills_circular_ring": 0.2,
"tools_edrills_oblong_ring": 0.2,
"tools_edrills_square_ring": 0.2,
@@ -1598,6 +1599,7 @@ class App(QtCore.QObject):
# Extract Drills Tool
"tools_edrills_hole_type": self.ui.tools2_defaults_form.tools2_edrills_group.hole_size_radio,
"tools_edrills_hole_fixed_dia": self.ui.tools2_defaults_form.tools2_edrills_group.dia_entry,
+ "tools_edrills_hole_prop_factor": self.ui.tools2_defaults_form.tools2_edrills_group.factor_entry,
"tools_edrills_circular_ring": self.ui.tools2_defaults_form.tools2_edrills_group.circular_ring_entry,
"tools_edrills_oblong_ring": self.ui.tools2_defaults_form.tools2_edrills_group.oblong_ring_entry,
"tools_edrills_square_ring": self.ui.tools2_defaults_form.tools2_edrills_group.square_ring_entry,
@@ -4277,9 +4279,20 @@ class App(QtCore.QObject):
obj.options['xmax'] = xmax
obj.options['ymax'] = ymax
except Exception as e:
- log.warning("The object has no bounds properties. %s" % str(e))
+ log.warning("App.new_object() -> The object has no bounds properties. %s" % str(e))
return "fail"
+ try:
+ if kind == 'excellon':
+ obj.fill_color = self.app.defaults["excellon_plot_fill"]
+ obj.outline_color = self.app.defaults["excellon_plot_line"]
+
+ if kind == 'gerber':
+ obj.fill_color = self.app.defaults["gerber_plot_fill"]
+ obj.outline_color = self.app.defaults["gerber_plot_line"]
+ except Exception as e:
+ log.warning("App.new_object() -> setting colors error. %s" % str(e))
+
# update the KeyWords list with the name of the file
self.myKeywords.append(obj.options['name'])
@@ -12305,19 +12318,12 @@ class App(QtCore.QObject):
new_line_color = color_variant(new_color[:7], 0.7)
for sel_obj in sel_obj_list:
- if self.is_legacy is False:
- sel_obj.fill_color = new_color
- sel_obj.outline_color = new_line_color
+ sel_obj.fill_color = new_color
+ sel_obj.outline_color = new_line_color
- sel_obj.shapes.redraw(
- update_colors=(new_color, new_line_color)
- )
- else:
- sel_obj.fill_color = new_color
- sel_obj.outline_color = new_line_color
- sel_obj.shapes.redraw(
- update_colors=(new_color, new_line_color)
- )
+ sel_obj.shapes.redraw(
+ update_colors=(new_color, new_line_color)
+ )
def on_grid_snap_triggered(self, state):
if state:
diff --git a/README.md b/README.md
index ac71ea1e..ca9dc47d 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+14.01.2020
+
+- in Extract Drill Tool added a new method of drills extraction. The methods are: fixed diameter, fixed annular ring and proportional
+- in Align Objects Tool finished the Single Point method of alignment
+
13.01.2020
- fixed a small GUI issue in Excellon UI when Basic mode is active
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index a073b534..41ae3f32 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -7697,14 +7697,20 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI):
grid_lay.addWidget(separator_line, 8, 0, 1, 2)
# ## Axis
- self.hole_size_radio = RadioSet([{'label': _("Fixed"), 'value': 'fixed'},
- {'label': _("Proportional"), 'value': 'prop'}])
- self.hole_size_label = QtWidgets.QLabel('%s:' % _("Hole Size"))
+ self.hole_size_radio = RadioSet(
+ [
+ {'label': _("Fixed Diameter"), 'value': 'fixed'},
+ {'label': _("Fixed Annular Ring"), 'value': 'ring'},
+ {'label': _("Proportional"), 'value': 'prop'}
+ ],
+ orientation='vertical',
+ stretch=False)
+ self.hole_size_label = QtWidgets.QLabel('%s:' % _("Method"))
self.hole_size_label.setToolTip(
- _("The type of hole size. Can be:\n"
- "- Fixed -> all holes will have a set size\n"
- "- Proprotional -> each hole will havea a variable size\n"
- "such as to preserve a set annular ring"))
+ _("The selected method of extracting the drills. Can be:\n"
+ "- Fixed Diameter -> all holes will have a set size\n"
+ "- Fixed Annular Ring -> all holes will have a set annular ring\n"
+ "- Proportional -> each hole size will be a fraction of the pad size"))
grid_lay.addWidget(self.hole_size_label, 9, 0)
grid_lay.addWidget(self.hole_size_radio, 9, 1)
@@ -7716,27 +7722,31 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI):
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
grid_lay.addWidget(separator_line, 10, 0, 1, 2)
+ # Annular Ring
+ self.fixed_label = QtWidgets.QLabel('%s' % _("Fixed Diameter"))
+ grid_lay.addWidget(self.fixed_label, 11, 0, 1, 2)
+
# Diameter value
self.dia_entry = FCDoubleSpinner()
self.dia_entry.set_precision(self.decimals)
self.dia_entry.set_range(0.0000, 9999.9999)
- self.dia_label = QtWidgets.QLabel('%s:' % _("Diameter"))
+ self.dia_label = QtWidgets.QLabel('%s:' % _("value"))
self.dia_label.setToolTip(
_("Fixed hole diameter.")
)
- grid_lay.addWidget(self.dia_label, 11, 0)
- grid_lay.addWidget(self.dia_entry, 11, 1)
+ grid_lay.addWidget(self.dia_label, 12, 0)
+ grid_lay.addWidget(self.dia_entry, 12, 1)
# Annular Ring value
- self.ring_label = QtWidgets.QLabel('%s' % _("Annular Ring"))
+ self.ring_label = QtWidgets.QLabel('%s' % _("Fixed Annular Ring"))
self.ring_label.setToolTip(
_("The size of annular ring.\n"
"The copper sliver between the drill hole exterior\n"
"and the margin of the copper pad.")
)
- grid_lay.addWidget(self.ring_label, 12, 0, 1, 2)
+ grid_lay.addWidget(self.ring_label, 13, 0, 1, 2)
# Circular Annular Ring Value
self.circular_ring_label = QtWidgets.QLabel('%s:' % _("Circular"))
@@ -7748,8 +7758,8 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI):
self.circular_ring_entry.set_precision(self.decimals)
self.circular_ring_entry.set_range(0.0000, 9999.9999)
- grid_lay.addWidget(self.circular_ring_label, 13, 0)
- grid_lay.addWidget(self.circular_ring_entry, 13, 1)
+ grid_lay.addWidget(self.circular_ring_label, 14, 0)
+ grid_lay.addWidget(self.circular_ring_entry, 14, 1)
# Oblong Annular Ring Value
self.oblong_ring_label = QtWidgets.QLabel('%s:' % _("Oblong"))
@@ -7761,8 +7771,8 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI):
self.oblong_ring_entry.set_precision(self.decimals)
self.oblong_ring_entry.set_range(0.0000, 9999.9999)
- grid_lay.addWidget(self.oblong_ring_label, 14, 0)
- grid_lay.addWidget(self.oblong_ring_entry, 14, 1)
+ grid_lay.addWidget(self.oblong_ring_label, 15, 0)
+ grid_lay.addWidget(self.oblong_ring_entry, 15, 1)
# Square Annular Ring Value
self.square_ring_label = QtWidgets.QLabel('%s:' % _("Square"))
@@ -7774,8 +7784,8 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI):
self.square_ring_entry.set_precision(self.decimals)
self.square_ring_entry.set_range(0.0000, 9999.9999)
- grid_lay.addWidget(self.square_ring_label, 15, 0)
- grid_lay.addWidget(self.square_ring_entry, 15, 1)
+ grid_lay.addWidget(self.square_ring_label, 16, 0)
+ grid_lay.addWidget(self.square_ring_entry, 16, 1)
# Rectangular Annular Ring Value
self.rectangular_ring_label = QtWidgets.QLabel('%s:' % _("Rectangular"))
@@ -7787,8 +7797,8 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI):
self.rectangular_ring_entry.set_precision(self.decimals)
self.rectangular_ring_entry.set_range(0.0000, 9999.9999)
- grid_lay.addWidget(self.rectangular_ring_label, 16, 0)
- grid_lay.addWidget(self.rectangular_ring_entry, 16, 1)
+ grid_lay.addWidget(self.rectangular_ring_label, 17, 0)
+ grid_lay.addWidget(self.rectangular_ring_entry, 17, 1)
# Others Annular Ring Value
self.other_ring_label = QtWidgets.QLabel('%s:' % _("Others"))
@@ -7800,8 +7810,26 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI):
self.other_ring_entry.set_precision(self.decimals)
self.other_ring_entry.set_range(0.0000, 9999.9999)
- grid_lay.addWidget(self.other_ring_label, 17, 0)
- grid_lay.addWidget(self.other_ring_entry, 17, 1)
+ grid_lay.addWidget(self.other_ring_label, 18, 0)
+ grid_lay.addWidget(self.other_ring_entry, 18, 1)
+
+ self.prop_label = QtWidgets.QLabel('%s' % _("Proportional Diameter"))
+ grid_lay.addWidget(self.prop_label, 19, 0, 1, 2)
+
+ # Factor value
+ self.factor_entry = FCDoubleSpinner(suffix='%')
+ self.factor_entry.set_precision(self.decimals)
+ self.factor_entry.set_range(0.0000, 100.0000)
+ self.factor_entry.setSingleStep(0.1)
+
+ self.factor_label = QtWidgets.QLabel('%s:' % _("Factor"))
+ self.factor_label.setToolTip(
+ _("Proportional Diameter.\n"
+ "The drill diameter will be a fraction of the pad size.")
+ )
+
+ grid_lay.addWidget(self.factor_label, 20, 0)
+ grid_lay.addWidget(self.factor_entry, 20, 1)
self.layout.addStretch()
diff --git a/flatcamTools/ToolAlignObjects.py b/flatcamTools/ToolAlignObjects.py
index 505c5a30..91594c16 100644
--- a/flatcamTools/ToolAlignObjects.py
+++ b/flatcamTools/ToolAlignObjects.py
@@ -54,18 +54,16 @@ class AlignObjects(FlatCAMTool):
grid0.setColumnStretch(1, 1)
self.layout.addLayout(grid0)
- self.aligned_label = QtWidgets.QLabel('%s' % _("Selection of the aligned object"))
+ self.aligned_label = QtWidgets.QLabel('%s' % _("Selection of the WORKING object"))
grid0.addWidget(self.aligned_label, 0, 0, 1, 2)
# Type of object to be aligned
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"))
self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
self.type_obj_combo_label.setToolTip(
@@ -96,9 +94,9 @@ class AlignObjects(FlatCAMTool):
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
grid0.addWidget(separator_line, 4, 0, 1, 2)
- self.aligned_label = QtWidgets.QLabel('%s' % _("Selection of the aligner object"))
+ self.aligned_label = QtWidgets.QLabel('%s' % _("Selection of the TARGET object"))
self.aligned_label.setToolTip(
- _("Object to which the other objects will be aligned to (moved).")
+ _("Object to which the other objects will be aligned to (moved to).")
)
grid0.addWidget(self.aligned_label, 6, 0, 1, 2)
@@ -106,11 +104,9 @@ class AlignObjects(FlatCAMTool):
self.type_aligner_obj_combo = FCComboBox()
self.type_aligner_obj_combo.addItem("Gerber")
self.type_aligner_obj_combo.addItem("Excellon")
- self.type_aligner_obj_combo.addItem("Geometry")
self.type_aligner_obj_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
self.type_aligner_obj_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/drill16.png"))
- self.type_aligner_obj_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
self.type_aligner_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
self.type_aligner_obj_combo_label.setToolTip(
@@ -219,10 +215,17 @@ class AlignObjects(FlatCAMTool):
self.clicked_points = list()
self.new_start = None
- self.new_stop = None
+ self.new_dest = None
self.align_type = None
+ # old colors of objects involved in the alignment
+ self.aligner_old_fill_color = None
+ self.aligner_old_line_color = None
+ self.aligned_old_fill_color = None
+ self.aligned_old_line_color = None
+
+
def run(self, toggle=True):
self.app.report_usage("ToolAlignObjects()")
@@ -261,6 +264,11 @@ class AlignObjects(FlatCAMTool):
self.aligned_obj = None
self.aligner_obj = None
+ self.aligner_old_fill_color = None
+ self.aligner_old_line_color = None
+ self.aligned_old_fill_color = None
+ self.aligned_old_line_color = None
+
self.a_type_radio.set_value(self.app.defaults["tools_align_objects_align_type"])
if self.local_connected is True:
@@ -277,6 +285,7 @@ class AlignObjects(FlatCAMTool):
self.aligner_object_combo.setCurrentIndex(0)
def on_align(self):
+ self.app.delete_selection_shape()
obj_sel_index = self.object_combo.currentIndex()
obj_model_index = self.app.collection.index(obj_sel_index, 0, self.object_combo.rootModelIndex())
@@ -314,8 +323,14 @@ class AlignObjects(FlatCAMTool):
self.local_connected = True
- self.app.inform.emit(_("Get First alignment point on the aligned object."))
+ self.aligner_old_fill_color = self.aligner_obj.fill_color
+ self.aligner_old_line_color = self.aligner_obj.outline_color
+ self.aligned_old_fill_color = self.aligned_obj.fill_color
+ self.aligned_old_line_color = self.aligned_obj.outline_color
+
+ self.app.inform.emit('%s: %s' % (_("First Point"), _("Click on the START point.")))
self.target_obj = self.aligned_obj
+ self.set_color()
def on_mouse_click_release(self, event):
if self.app.is_legacy is False:
@@ -365,40 +380,47 @@ class AlignObjects(FlatCAMTool):
self.check_points()
elif event.button == right_button and self.app.event_is_dragging is False:
+ self.reset_color()
self.clicked_points = list()
self.disconnect_cal_events()
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled by user request."))
def check_points(self):
- if self.align_type == 'sp':
- if len(self.clicked_points) == 1:
- self.app.inform.emit(_("Get First alignment point on the aligner object."))
- self.target_obj = self.aligner_obj
+ if len(self.clicked_points) == 1:
+ self.app.inform.emit('%s: %s. %s' % (
+ _("First Point"), _("Click on the DESTINATION point."), _(" Or right click to cancel.")))
+ self.target_obj = self.aligner_obj
+ self.reset_color()
+ self.set_color()
- if len(self.clicked_points) == 2:
+ if len(self.clicked_points) == 2:
+ self.align_translate()
+ if self.align_type == 'sp':
self.app.inform.emit('[success] %s' % _("Done."))
- self.align_translate()
self.app.plot_all()
self.disconnect_cal_events()
- else:
- if len(self.clicked_points) == 1:
- self.app.inform.emit(_("Get Second alignment point on aligned object. Or right click to cancel."))
+ return
+ else:
+ self.app.inform.emit('%s: %s. %s' % (
+ _("Second Point"), _("Click on the START point."), _(" Or right click to cancel.")))
+ self.target_obj = self.aligned_obj
+ self.reset_color()
+ self.set_color()
- if len(self.clicked_points) == 2:
- self.app.inform.emit(_("Get First alignment point on the aligner object."))
- self.target_obj = self.aligner_obj
+ if len(self.clicked_points) == 3:
+ self.app.inform.emit('%s: %s. %s' % (
+ _("Second Point"), _("Click on the DESTINATION point."), _(" Or right click to cancel.")))
+ self.target_obj = self.aligner_obj
+ self.reset_color()
+ self.set_color()
- if len(self.clicked_points) == 3:
- self.app.inform.emit(_("Get Second alignment point on the aligner object. Or right click to cancel."))
+ if len(self.clicked_points) == 4:
+ self.align_rotate()
+ self.app.inform.emit('[success] %s' % _("Done."))
- if len(self.clicked_points) == 4:
- self.app.inform.emit('[success] %s' % _("Done."))
- self.align_translate()
- self.align_rotate()
- self.app.plot_all()
-
- self.disconnect_cal_events()
+ self.disconnect_cal_events()
+ self.app.plot_all()
def align_translate(self):
dx = self.clicked_points[1][0] - self.clicked_points[0][0]
@@ -477,9 +499,27 @@ class AlignObjects(FlatCAMTool):
self.canvas.graph_event_disconnect(self.mr)
self.local_connected = False
- self.target_obj = None
- self.aligned_obj = None
- self.aligner_obj = None
+
+ self.aligner_old_fill_color = None
+ self.aligner_old_line_color = None
+ self.aligned_old_fill_color = None
+ self.aligned_old_line_color = None
+
+ def set_color(self):
+ new_color = "#15678abf"
+ new_line_color = new_color
+ self.target_obj.shapes.redraw(
+ update_colors=(new_color, new_line_color)
+ )
+
+ def reset_color(self):
+ self.aligned_obj.shapes.redraw(
+ update_colors=(self.aligned_old_fill_color, self.aligned_old_line_color)
+ )
+
+ self.aligner_obj.shapes.redraw(
+ update_colors=(self.aligner_old_fill_color, self.aligner_old_line_color)
+ )
def reset_fields(self):
self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
diff --git a/flatcamTools/ToolExtractDrills.py b/flatcamTools/ToolExtractDrills.py
index e0c72c95..d75a61b5 100644
--- a/flatcamTools/ToolExtractDrills.py
+++ b/flatcamTools/ToolExtractDrills.py
@@ -125,15 +125,25 @@ class ToolExtractDrills(FlatCAMTool):
grid1.setColumnStretch(0, 0)
grid1.setColumnStretch(1, 1)
+ self.method_label = QtWidgets.QLabel('%s' % _("Method"))
+ grid1.addWidget(self.method_label, 2, 0, 1, 2)
+
# ## Axis
- self.hole_size_radio = RadioSet([{'label': _("Fixed"), 'value': 'fixed'},
- {'label': _("Proportional"), 'value': 'prop'}])
+ self.hole_size_radio = RadioSet(
+ [
+ {'label': _("Fixed Diameter"), 'value': 'fixed'},
+ {'label': _("Fixed Annular Ring"), 'value': 'ring'},
+ {'label': _("Proportional"), 'value': 'prop'}
+ ],
+ orientation='vertical',
+ stretch=False)
+
self.hole_size_label = QtWidgets.QLabel('%s:' % _("Hole Size"))
self.hole_size_label.setToolTip(
- _("The type of hole size. Can be:\n"
- "- Fixed -> all holes will have a set size\n"
- "- Proprotional -> each hole will havea a variable size\n"
- "such as to preserve a set annular ring"))
+ _("The selected method of extracting the drills. Can be:\n"
+ "- Fixed Diameter -> all holes will have a set size\n"
+ "- Fixed Annular Ring -> all holes will have a set annular ring\n"
+ "- Proportional -> each hole size will be a fraction of the pad size"))
grid1.addWidget(self.hole_size_label, 3, 0)
grid1.addWidget(self.hole_size_radio, 3, 1)
@@ -145,18 +155,27 @@ class ToolExtractDrills(FlatCAMTool):
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
grid1.addWidget(separator_line, 5, 0, 1, 2)
+ # Annular Ring
+ self.fixed_label = QtWidgets.QLabel('%s' % _("Fixed Diameter"))
+ grid1.addWidget(self.fixed_label, 6, 0, 1, 2)
+
# Diameter value
self.dia_entry = FCDoubleSpinner()
self.dia_entry.set_precision(self.decimals)
self.dia_entry.set_range(0.0000, 9999.9999)
- self.dia_label = QtWidgets.QLabel('%s:' % _("Diameter"))
+ self.dia_label = QtWidgets.QLabel('%s:' % _("Value"))
self.dia_label.setToolTip(
_("Fixed hole diameter.")
)
- grid1.addWidget(self.dia_label, 7, 0)
- grid1.addWidget(self.dia_entry, 7, 1)
+ grid1.addWidget(self.dia_label, 8, 0)
+ grid1.addWidget(self.dia_entry, 8, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid1.addWidget(separator_line, 9, 0, 1, 2)
self.ring_frame = QtWidgets.QFrame()
self.ring_frame.setContentsMargins(0, 0, 0, 0)
@@ -173,7 +192,7 @@ class ToolExtractDrills(FlatCAMTool):
self.ring_box.addLayout(grid2)
# Annular Ring value
- self.ring_label = QtWidgets.QLabel('%s' % _("Annular Ring"))
+ self.ring_label = QtWidgets.QLabel('%s' % _("Fixed Annular Ring"))
self.ring_label.setToolTip(
_("The size of annular ring.\n"
"The copper sliver between the drill hole exterior\n"
@@ -246,6 +265,35 @@ class ToolExtractDrills(FlatCAMTool):
grid2.addWidget(self.other_ring_label, 5, 0)
grid2.addWidget(self.other_ring_entry, 5, 1)
+ grid3 = QtWidgets.QGridLayout()
+ self.layout.addLayout(grid3)
+ grid3.setColumnStretch(0, 0)
+ grid3.setColumnStretch(1, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid3.addWidget(separator_line, 1, 0, 1, 2)
+
+ # Annular Ring value
+ self.prop_label = QtWidgets.QLabel('%s' % _("Proportional Diameter"))
+ grid3.addWidget(self.prop_label, 2, 0, 1, 2)
+
+ # Diameter value
+ self.factor_entry = FCDoubleSpinner(suffix='%')
+ self.factor_entry.set_precision(self.decimals)
+ self.factor_entry.set_range(0.0000, 100.0000)
+ self.factor_entry.setSingleStep(0.1)
+
+ self.factor_label = QtWidgets.QLabel('%s:' % _("Value"))
+ self.factor_label.setToolTip(
+ _("Proportional Diameter.\n"
+ "The drill diameter will be a fraction of the pad size.")
+ )
+
+ grid3.addWidget(self.factor_label, 3, 0)
+ grid3.addWidget(self.factor_entry, 3, 1)
+
# Extract drills from Gerber apertures flashes (pads)
self.e_drills_button = QtWidgets.QPushButton(_("Extract Drills"))
self.e_drills_button.setToolTip(
@@ -280,6 +328,13 @@ class ToolExtractDrills(FlatCAMTool):
self.rectangular_ring_entry.setEnabled(False)
self.other_ring_entry.setEnabled(False)
+ self.dia_entry.setDisabled(True)
+ self.dia_label.setDisabled(True)
+ self.factor_label.setDisabled(True)
+ self.factor_entry.setDisabled(True)
+
+ self.ring_frame.setDisabled(True)
+
# ## Signals
self.hole_size_radio.activated_custom.connect(self.on_hole_size_toggle)
self.e_drills_button.clicked.connect(self.on_extract_drills_click)
@@ -359,6 +414,8 @@ class ToolExtractDrills(FlatCAMTool):
self.rectangular_cb.set_value(self.app.defaults["tools_edrills_rectangular"])
self.other_cb.set_value(self.app.defaults["tools_edrills_others"])
+ self.factor_entry.set_value(float(self.app.defaults["tools_edrills_hole_prop_factor"]))
+
def on_extract_drills_click(self):
drill_dia = self.dia_entry.get_value()
@@ -368,6 +425,8 @@ class ToolExtractDrills(FlatCAMTool):
rect_r_val = self.rectangular_ring_entry.get_value()
other_r_val = self.other_ring_entry.get_value()
+ prop_factor = self.factor_entry.get_value() / 100.0
+
drills = list()
tools = dict()
@@ -376,7 +435,7 @@ class ToolExtractDrills(FlatCAMTool):
try:
fcobj = model_index.internalPointer().obj
- except Exception as e:
+ except Exception:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
return
@@ -421,7 +480,7 @@ class ToolExtractDrills(FlatCAMTool):
if 'solid_geometry' not in tools["1"] or not tools["1"]['solid_geometry']:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("No drills extracted. Try different parameters."))
return
- else:
+ elif mode == 'ring':
drills_found = set()
for apid, apid_value in fcobj.apertures.items():
ap_type = apid_value['type']
@@ -435,9 +494,9 @@ class ToolExtractDrills(FlatCAMTool):
height = float(apid_value['height'])
if self.oblong_cb.get_value():
if width > height:
- dia = float(apid_value['height']) - (2 * rect_r_val)
+ dia = float(apid_value['height']) - (2 * oblong_r_val)
else:
- dia = float(apid_value['width']) - (2 * rect_r_val)
+ dia = float(apid_value['width']) - (2 * oblong_r_val)
elif ap_type == 'R':
width = float(apid_value['width'])
height = float(apid_value['height'])
@@ -506,6 +565,91 @@ class ToolExtractDrills(FlatCAMTool):
if True not in drills_found:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("No drills extracted. Try different parameters."))
return
+ else:
+ drills_found = set()
+ for apid, apid_value in fcobj.apertures.items():
+ ap_type = apid_value['type']
+
+ dia = None
+ if ap_type == 'C':
+ if self.circular_cb.get_value():
+ dia = float(apid_value['size']) * prop_factor
+ elif ap_type == 'O':
+ width = float(apid_value['width'])
+ height = float(apid_value['height'])
+ if self.oblong_cb.get_value():
+ if width > height:
+ dia = float(apid_value['height']) * prop_factor
+ else:
+ dia = float(apid_value['width']) * prop_factor
+ elif ap_type == 'R':
+ width = float(apid_value['width'])
+ height = float(apid_value['height'])
+
+ # if the height == width (float numbers so the reason for the following)
+ if abs(float('%.*f' % (self.decimals, width)) - float('%.*f' % (self.decimals, height))) < \
+ (10 ** -self.decimals):
+ if self.square_cb.get_value():
+ dia = float(apid_value['height']) * prop_factor
+ else:
+ if self.rectangular_cb.get_value():
+ if width > height:
+ dia = float(apid_value['height']) * prop_factor
+ else:
+ dia = float(apid_value['width']) * prop_factor
+ else:
+ if self.other_cb.get_value():
+ try:
+ dia = float(apid_value['size']) * prop_factor
+ except KeyError:
+ if ap_type == 'AM':
+ pol = apid_value['geometry'][0]['solid']
+ x0, y0, x1, y1 = pol.bounds
+ dx = x1 - x0
+ dy = y1 - y0
+ if dx <= dy:
+ dia = dx * prop_factor
+ else:
+ dia = dy * prop_factor
+
+ # if dia is None then none of the above applied so we skip the following
+ if dia is None:
+ continue
+
+ tool_in_drills = False
+ for tool, tool_val in tools.items():
+ if abs(float('%.*f' % (self.decimals, tool_val["C"])) - float('%.*f' % (self.decimals, dia))) < \
+ (10 ** -self.decimals):
+ tool_in_drills = tool
+
+ if tool_in_drills is False:
+ if tools:
+ new_tool = max([int(t) for t in tools]) + 1
+ tool_in_drills = str(new_tool)
+ else:
+ tool_in_drills = "1"
+
+ for geo_el in apid_value['geometry']:
+ if 'follow' in geo_el and isinstance(geo_el['follow'], Point):
+ if tool_in_drills not in tools:
+ tools[tool_in_drills] = {"C": dia}
+
+ drills.append({"point": geo_el['follow'], "tool": tool_in_drills})
+
+ if 'solid_geometry' not in tools[tool_in_drills]:
+ tools[tool_in_drills]['solid_geometry'] = list()
+ else:
+ tools[tool_in_drills]['solid_geometry'].append(geo_el['follow'])
+
+ if tool_in_drills in tools:
+ if 'solid_geometry' not in tools[tool_in_drills] or not tools[tool_in_drills]['solid_geometry']:
+ drills_found.add(False)
+ else:
+ drills_found.add(True)
+
+ if True not in drills_found:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("No drills extracted. Try different parameters."))
+ return
def obj_init(obj_inst, app_inst):
obj_inst.tools = tools
@@ -518,16 +662,36 @@ class ToolExtractDrills(FlatCAMTool):
def on_hole_size_toggle(self, val):
if val == "fixed":
+ self.fixed_label.setDisabled(False)
self.dia_entry.setDisabled(False)
self.dia_label.setDisabled(False)
self.ring_frame.setDisabled(True)
- else:
+
+ self.prop_label.setDisabled(True)
+ self.factor_label.setDisabled(True)
+ self.factor_entry.setDisabled(True)
+ elif val == "ring":
+ self.fixed_label.setDisabled(True)
self.dia_entry.setDisabled(True)
self.dia_label.setDisabled(True)
self.ring_frame.setDisabled(False)
+ self.prop_label.setDisabled(True)
+ self.factor_label.setDisabled(True)
+ self.factor_entry.setDisabled(True)
+ elif val == "prop":
+ self.fixed_label.setDisabled(True)
+ self.dia_entry.setDisabled(True)
+ self.dia_label.setDisabled(True)
+
+ self.ring_frame.setDisabled(True)
+
+ self.prop_label.setDisabled(False)
+ self.factor_label.setDisabled(False)
+ self.factor_entry.setDisabled(False)
+
def reset_fields(self):
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.gerber_object_combo.setCurrentIndex(0)
From a8bea7805ed59e6044763fc8d2d8f83647794990 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Tue, 14 Jan 2020 17:18:24 +0200
Subject: [PATCH 017/209] - working on the Dual Point option in Align Objects
Tool - angle has to be recalculated
---
README.md | 1 +
flatcamTools/ToolAlignObjects.py | 34 ++++++++++++++++++++++--------
flatcamTools/ToolNonCopperClear.py | 2 +-
3 files changed, 27 insertions(+), 10 deletions(-)
diff --git a/README.md b/README.md
index ca9dc47d..79b484b3 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- in Extract Drill Tool added a new method of drills extraction. The methods are: fixed diameter, fixed annular ring and proportional
- in Align Objects Tool finished the Single Point method of alignment
+- working on the Dual Point option in Align Objects Tool - angle has to be recalculated
13.01.2020
diff --git a/flatcamTools/ToolAlignObjects.py b/flatcamTools/ToolAlignObjects.py
index 91594c16..9d79de17 100644
--- a/flatcamTools/ToolAlignObjects.py
+++ b/flatcamTools/ToolAlignObjects.py
@@ -10,8 +10,10 @@ from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import FCComboBox, RadioSet
+import math
+
from shapely.geometry import Point
-from shapely.affinity import translate, rotate
+from shapely.affinity import translate
import gettext
import FlatCAMTranslation as fcTranslate
@@ -68,7 +70,7 @@ class AlignObjects(FlatCAMTool):
self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
self.type_obj_combo_label.setToolTip(
_("Specify the type of object to be aligned.\n"
- "It can be of type: Gerber, Excellon or Geometry.\n"
+ "It can be of type: Gerber or Excellon.\n"
"The selection here decide the type of objects that will be\n"
"in the Object combobox.")
)
@@ -111,7 +113,7 @@ class AlignObjects(FlatCAMTool):
self.type_aligner_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
self.type_aligner_obj_combo_label.setToolTip(
_("Specify the type of object to be aligned to.\n"
- "It can be of type: Gerber, Excellon or Geometry.\n"
+ "It can be of type: Gerber or Excellon.\n"
"The selection here decide the type of objects that will be\n"
"in the Object combobox.")
)
@@ -394,8 +396,8 @@ class AlignObjects(FlatCAMTool):
self.set_color()
if len(self.clicked_points) == 2:
- self.align_translate()
if self.align_type == 'sp':
+ self.align_translate()
self.app.inform.emit('[success] %s' % _("Done."))
self.app.plot_all()
@@ -416,6 +418,7 @@ class AlignObjects(FlatCAMTool):
self.set_color()
if len(self.clicked_points) == 4:
+ self.align_translate()
self.align_rotate()
self.app.inform.emit('[success] %s' % _("Done."))
@@ -426,10 +429,6 @@ class AlignObjects(FlatCAMTool):
dx = self.clicked_points[1][0] - self.clicked_points[0][0]
dy = self.clicked_points[1][1] - self.clicked_points[0][1]
- if self.align_type == 'dp':
- self.new_start = translate(Point(self.clicked_points[2]), xoff=dx, yoff=dy)
- self.new_dest = translate(Point(self.clicked_points[3]), xoff=dx, yoff=dy)
-
self.aligned_obj.offset((dx, dy))
# Update the object bounding box options
@@ -440,7 +439,24 @@ class AlignObjects(FlatCAMTool):
self.aligned_obj.options['ymax'] = d
def align_rotate(self):
- print(self.new_start.x == self.new_dest.x)
+ dx = self.clicked_points[1][0] - self.clicked_points[0][0]
+ dy = self.clicked_points[1][1] - self.clicked_points[0][1]
+
+ new_start_pt = translate(Point(self.clicked_points[2]), xoff=dx, yoff=dy)
+ self.new_start = (new_start_pt.x, new_start_pt.y)
+ self.new_dest = self.clicked_points[3]
+
+ origin_pt = self.clicked_points[1]
+
+ sec_dx = self.new_dest[0] - self.new_start[0]
+ sec_dy = self.new_dest[1] - self.new_start[1]
+
+ rotation_not_needed = (abs(self.new_start[0] - self.new_dest[0]) <= (10 ** -self.decimals)) or \
+ (abs(self.new_start[1] - self.new_dest[1]) <= (10 ** -self.decimals))
+ if rotation_not_needed is False:
+ # calculate rotation angle
+ angle = math.degrees(math.atan(sec_dy / sec_dx))
+ self.aligned_obj.rotate(angle=angle, point=origin_pt)
def execute(self):
aligned_name = self.object_combo.currentText()
diff --git a/flatcamTools/ToolNonCopperClear.py b/flatcamTools/ToolNonCopperClear.py
index 9a6e047e..8b6ba546 100644
--- a/flatcamTools/ToolNonCopperClear.py
+++ b/flatcamTools/ToolNonCopperClear.py
@@ -641,7 +641,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
}
# #############################################################################
- # ############################ SGINALS ########################################
+ # ############################ SIGNALS ########################################
# #############################################################################
self.addtool_btn.clicked.connect(self.on_tool_add)
self.addtool_entry.returnPressed.connect(self.on_tool_add)
From acfb1ca9e7f1febbefb41668ef76b2122c4d2091 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 15 Jan 2020 00:55:12 +0200
Subject: [PATCH 018/209] - finished Dual Point option in Align Objects Tool
---
README.md | 1 +
flatcamTools/ToolAlignObjects.py | 24 +++++++++++++-----------
2 files changed, 14 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
index 79b484b3..5e49cd87 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ CAD program, and create G-Code for Isolation routing.
- in Extract Drill Tool added a new method of drills extraction. The methods are: fixed diameter, fixed annular ring and proportional
- in Align Objects Tool finished the Single Point method of alignment
- working on the Dual Point option in Align Objects Tool - angle has to be recalculated
+- finished Dual Point option in Align Objects Tool
13.01.2020
diff --git a/flatcamTools/ToolAlignObjects.py b/flatcamTools/ToolAlignObjects.py
index 9d79de17..7368b865 100644
--- a/flatcamTools/ToolAlignObjects.py
+++ b/flatcamTools/ToolAlignObjects.py
@@ -216,9 +216,6 @@ class AlignObjects(FlatCAMTool):
# here store the alignment points
self.clicked_points = list()
- self.new_start = None
- self.new_dest = None
-
self.align_type = None
# old colors of objects involved in the alignment
@@ -442,20 +439,25 @@ class AlignObjects(FlatCAMTool):
dx = self.clicked_points[1][0] - self.clicked_points[0][0]
dy = self.clicked_points[1][1] - self.clicked_points[0][1]
- new_start_pt = translate(Point(self.clicked_points[2]), xoff=dx, yoff=dy)
- self.new_start = (new_start_pt.x, new_start_pt.y)
- self.new_dest = self.clicked_points[3]
+ test_rotation_pt = translate(Point(self.clicked_points[2]), xoff=dx, yoff=dy)
+ new_start = (test_rotation_pt.x, test_rotation_pt.y)
+ new_dest = self.clicked_points[3]
origin_pt = self.clicked_points[1]
- sec_dx = self.new_dest[0] - self.new_start[0]
- sec_dy = self.new_dest[1] - self.new_start[1]
+ dxd = new_dest[0] - origin_pt[0]
+ dyd = new_dest[1] - origin_pt[1]
- rotation_not_needed = (abs(self.new_start[0] - self.new_dest[0]) <= (10 ** -self.decimals)) or \
- (abs(self.new_start[1] - self.new_dest[1]) <= (10 ** -self.decimals))
+ dxs = new_start[0] - origin_pt[0]
+ dys = new_start[1] - origin_pt[1]
+
+ rotation_not_needed = (abs(new_start[0] - new_dest[0]) <= (10 ** -self.decimals)) or \
+ (abs(new_start[1] - new_dest[1]) <= (10 ** -self.decimals))
if rotation_not_needed is False:
# calculate rotation angle
- angle = math.degrees(math.atan(sec_dy / sec_dx))
+ angle_dest = math.degrees(math.atan(dyd / dxd))
+ angle_start = math.degrees(math.atan(dys / dxs))
+ angle = angle_dest - angle_start
self.aligned_obj.rotate(angle=angle, point=origin_pt)
def execute(self):
From 821014f719e681dd26ddaa77687eae1c8c6019c9 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 15 Jan 2020 02:50:27 +0200
Subject: [PATCH 019/209] - added key shortcuts and toolbar icons for the new
tools: Align Object Tool (ALT+A) and Extract Drills (ALT+I) - added new
functionality (key shortcut SHIFT+J) to locate the corners of the bounding
box (and center) in a selected object
---
FlatCAMApp.py | 155 ++++++++++++++++++++++++++++++-
README.md | 5 +
flatcamGUI/FlatCAMGUI.py | 63 +++++++++++--
flatcamTools/ToolAlignObjects.py | 45 ---------
share/extract_drill16.png | Bin 0 -> 459 bytes
share/extract_drill32.png | Bin 0 -> 745 bytes
share/locate16.png | Bin 0 -> 565 bytes
share/locate32.png | Bin 0 -> 900 bytes
8 files changed, 214 insertions(+), 54 deletions(-)
create mode 100644 share/extract_drill16.png
create mode 100644 share/extract_drill32.png
create mode 100644 share/locate16.png
create mode 100644 share/locate32.png
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 80df6cab..5324290e 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -240,6 +240,9 @@ class App(QtCore.QObject):
# signal emitted when jumping
jump_signal = pyqtSignal(tuple)
+ # signal emitted when jumping
+ locate_signal = pyqtSignal(tuple, str)
+
# close app signal
close_app_signal = pyqtSignal()
@@ -429,6 +432,7 @@ class App(QtCore.QObject):
"global_stats": dict(),
"global_tabs_detachable": True,
"global_jump_ref": 'abs',
+ "global_locate_pt": 'bl',
"global_tpdf_tmargin": 15.0,
"global_tpdf_bmargin": 10.0,
"global_tpdf_lmargin": 20.0,
@@ -1956,6 +1960,7 @@ class App(QtCore.QObject):
self.ui.menueditorigin.triggered.connect(self.on_set_origin)
self.ui.menueditjump.triggered.connect(self.on_jump_to)
+ self.ui.menueditlocate.triggered.connect(lambda: self.on_locate(obj=self.collection.get_active()))
self.ui.menuedittoggleunits.triggered.connect(self.on_toggle_units_click)
self.ui.menueditselectall.triggered.connect(self.on_selectall)
@@ -3241,6 +3246,7 @@ class App(QtCore.QObject):
self.ui.distance_min_btn.triggered.connect(lambda: self.distance_min_tool.run(toggle=True))
self.ui.origin_btn.triggered.connect(self.on_set_origin)
self.ui.jmp_btn.triggered.connect(self.on_jump_to)
+ self.ui.locate_btn.triggered.connect(lambda: self.on_locate(obj=self.collection.get_active()))
self.ui.shell_btn.triggered.connect(self.on_toggle_shell)
self.ui.new_script_btn.triggered.connect(self.on_filenewscript)
@@ -3250,6 +3256,9 @@ class App(QtCore.QObject):
# Tools Toolbar Signals
self.ui.dblsided_btn.triggered.connect(lambda: self.dblsidedtool.run(toggle=True))
self.ui.cal_btn.triggered.connect(lambda: self.cal_exc_tool.run(toggle=True))
+ self.ui.align_btn.triggered.connect(lambda: self.align_objects_tool.run(toggle=True))
+ self.ui.extract_btn.triggered.connect(lambda: self.edrills_tool.run(toggle=True))
+
self.ui.cutout_btn.triggered.connect(lambda: self.cutout_tool.run(toggle=True))
self.ui.ncc_btn.triggered.connect(lambda: self.ncclear_tool.run(toggle=True))
self.ui.paint_btn.triggered.connect(lambda: self.paint_tool.run(toggle=True))
@@ -7288,7 +7297,151 @@ class App(QtCore.QObject):
self.jump_signal.emit(location)
- units = self.defaults['units'].upper()
+ if fit_center:
+ self.plotcanvas.fit_center(loc=location)
+
+ cursor = QtGui.QCursor()
+
+ if self.is_legacy is False:
+ # I don't know where those differences come from but they are constant for the current
+ # execution of the application and they are multiples of a value around 0.0263mm.
+ # In a random way sometimes they are more sometimes they are less
+ # if units == 'MM':
+ # cal_factor = 0.0263
+ # else:
+ # cal_factor = 0.0263 / 25.4
+
+ cal_location = (location[0], location[1])
+
+ canvas_origin = self.plotcanvas.native.mapToGlobal(QtCore.QPoint(0, 0))
+ jump_loc = self.plotcanvas.translate_coords_2((cal_location[0], cal_location[1]))
+
+ j_pos = (
+ int(canvas_origin.x() + round(jump_loc[0])),
+ int(canvas_origin.y() + round(jump_loc[1]))
+ )
+ cursor.setPos(j_pos[0], j_pos[1])
+ else:
+ # find the canvas origin which is in the top left corner
+ canvas_origin = self.plotcanvas.native.mapToGlobal(QtCore.QPoint(0, 0))
+ # determine the coordinates for the lowest left point of the canvas
+ x0, y0 = canvas_origin.x(), canvas_origin.y() + self.ui.right_layout.geometry().height()
+
+ # transform the given location from data coordinates to display coordinates. THe display coordinates are
+ # in pixels where the origin 0,0 is in the lowest left point of the display window (in our case is the
+ # canvas) and the point (width, height) is in the top-right location
+ loc = self.plotcanvas.axes.transData.transform_point(location)
+ j_pos = (
+ int(x0 + loc[0]),
+ int(y0 - loc[1])
+ )
+ cursor.setPos(j_pos[0], j_pos[1])
+ self.plotcanvas.mouse = [location[0], location[1]]
+ if self.defaults["global_cursor_color_enabled"] is True:
+ self.plotcanvas.draw_cursor(x_pos=location[0], y_pos=location[1], color=self.cursor_color_3D)
+ else:
+ self.plotcanvas.draw_cursor(x_pos=location[0], y_pos=location[1])
+
+ if self.grid_status():
+ # Update cursor
+ self.app_cursor.set_data(np.asarray([(location[0], location[1])]),
+ symbol='++', edge_color=self.cursor_color_3D,
+ edge_width=self.defaults["global_cursor_width"],
+ size=self.defaults["global_cursor_size"])
+
+ # Set the position label
+ self.ui.position_label.setText(" X: %.4f "
+ "Y: %.4f" % (location[0], location[1]))
+ # Set the relative position label
+ dx = location[0] - float(self.rel_point1[0])
+ dy = location[1] - float(self.rel_point1[1])
+ self.ui.rel_position_label.setText("Dx: %.4f Dy: "
+ "%.4f " % (dx, dy))
+
+ self.inform.emit('[success] %s' % _("Done."))
+ return location
+
+ def on_locate(self, obj, fit_center=True):
+ """
+ Jump to one of the corners (or center) of an object by setting the mouse cursor location
+ :return:
+
+ """
+ self.report_usage("on_locate()")
+
+ if obj is None:
+ self.inform.emit('[WARNING_NOTCL] %s' % _("There is no object selected..."))
+ return 'fail'
+
+ class DialogBoxChoice(QtWidgets.QDialog):
+ def __init__(self, title=None, icon=None, choice='bl'):
+ """
+
+ :param title: string with the window title
+ """
+ super(DialogBoxChoice, self).__init__()
+
+ self.ok = False
+
+ self.setWindowIcon(icon)
+ self.setWindowTitle(str(title))
+
+ self.form = QtWidgets.QFormLayout(self)
+
+ self.ref_radio = RadioSet([
+ {"label": _("Bottom-Left"), "value": "bl"},
+ {"label": _("Top-Left"), "value": "tl"},
+ {"label": _("Bottom-Right"), "value": "br"},
+ {"label": _("Top-Right"), "value": "tr"},
+ {"label": _("Center"), "value": "c"}
+ ], orientation='vertical', stretch=False)
+ self.ref_radio.set_value(choice)
+ self.form.addRow(self.ref_radio)
+
+ self.button_box = QtWidgets.QDialogButtonBox(
+ QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel,
+ Qt.Horizontal, parent=self)
+ self.form.addRow(self.button_box)
+
+ self.button_box.accepted.connect(self.accept)
+ self.button_box.rejected.connect(self.reject)
+
+ if self.exec_() == QtWidgets.QDialog.Accepted:
+ self.ok = True
+ self.location_point = self.ref_radio.get_value()
+ else:
+ self.ok = False
+ self.location_point = None
+
+ dia_box = DialogBoxChoice(title=_("Locate ..."),
+ icon=QtGui.QIcon(self.resource_location + '/locate16.png'),
+ choice=self.defaults['global_locate_pt'])
+
+ if dia_box.ok is True:
+ try:
+ location_point = dia_box.location_point
+ self.defaults['global_locate_pt'] = dia_box.location_point
+ except Exception:
+ return
+ else:
+ return
+
+ loc_b = obj.bounds()
+ if location_point == 'bl':
+ location = (loc_b[0], loc_b[1])
+ elif location_point == 'tl':
+ location = (loc_b[0], loc_b[3])
+ elif location_point == 'br':
+ location = (loc_b[2], loc_b[1])
+ elif location_point == 'tr':
+ location = (loc_b[2], loc_b[3])
+ else:
+ # center
+ cx = loc_b[0] + ((loc_b[2] - loc_b[0]) / 2)
+ cy = loc_b[1] + ((loc_b[3] - loc_b[1]) / 2)
+ location = (cx, cy)
+
+ self.locate_signal.emit(location, location_point)
if fit_center:
self.plotcanvas.fit_center(loc=location)
diff --git a/README.md b/README.md
index 5e49cd87..2c446e8a 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+15.01.2020
+
+- added key shortcuts and toolbar icons for the new tools: Align Object Tool (ALT+A) and Extract Drills (ALT+I)
+- added new functionality (key shortcut SHIFT+J) to locate the corners of the bounding box (and center) in a selected object
+
14.01.2020
- in Extract Drill Tool added a new method of drills extraction. The methods are: fixed diameter, fixed annular ring and proportional
diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py
index 111a9895..86974e3f 100644
--- a/flatcamGUI/FlatCAMGUI.py
+++ b/flatcamGUI/FlatCAMGUI.py
@@ -373,6 +373,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
QtGui.QIcon(self.app.resource_location + '/origin16.png'), _('Se&t Origin\tO'))
self.menueditjump = self.menuedit.addAction(
QtGui.QIcon(self.app.resource_location + '/jump_to16.png'), _('Jump to Location\tJ'))
+ self.menueditlocate = self.menuedit.addAction(
+ QtGui.QIcon(self.app.resource_location + '/locate16.png'), _('Locate in Object\tSHIFT+J'))
# Separator
self.menuedit.addSeparator()
@@ -825,6 +827,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
QtGui.QIcon(self.app.resource_location + '/origin32.png'), _('Set Origin'))
self.jmp_btn = self.toolbargeo.addAction(
QtGui.QIcon(self.app.resource_location + '/jump_to16.png'), _('Jump to Location'))
+ self.locate_btn = self.toolbargeo.addAction(
+ QtGui.QIcon(self.app.resource_location + '/locate32.png'), _('Locate in Object'))
# ########################################################################
# ########################## View Toolbar# ###############################
@@ -859,6 +863,11 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# ########################################################################
self.dblsided_btn = self.toolbartools.addAction(
QtGui.QIcon(self.app.resource_location + '/doubleside32.png'), _("2Sided Tool"))
+ self.align_btn = self.toolbartools.addAction(
+ QtGui.QIcon(self.app.resource_location + '/align32.png'), _("Align Objects Tool"))
+ self.extract_btn = self.toolbartools.addAction(
+ QtGui.QIcon(self.app.resource_location + '/extract_drill32.png'), _("Extract Drills Tool"))
+
self.cutout_btn = self.toolbartools.addAction(
QtGui.QIcon(self.app.resource_location + '/cut16_bis.png'), _("Cutout Tool"))
self.ncc_btn = self.toolbartools.addAction(
@@ -1474,6 +1483,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
| SHIFT+G |
%s |
+
+ | SHIFT+J |
+ %s |
+
| SHIFT+M |
%s |
@@ -1506,6 +1519,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
|
+
+ | ALT+A |
+ %s |
+
| ALT+C |
%s |
@@ -1518,6 +1535,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
ALT+E |
%s |
+
+ | ALT+I |
+ %s |
+
| ALT+J |
%s |
@@ -1637,11 +1658,13 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# SHIFT section
_("Copy Obj_Name"),
- _("Toggle Code Editor"), _("Toggle the axis"), _("Distance Minimum Tool"), _("Open Preferences Window"),
+ _("Toggle Code Editor"), _("Toggle the axis"), _("Locate in Object"), _("Distance Minimum Tool"),
+ _("Open Preferences Window"),
_("Rotate by 90 degree CCW"), _("Run a Script"), _("Toggle the workspace"), _("Skew on X axis"),
_("Skew on Y axis"),
# ALT section
- _("Calculators Tool"), _("2-Sided PCB Tool"), _("Transformations Tool"), _("Fiducials Tool"),
+ _("Align Objects Tool"), _("Calculators Tool"), _("2-Sided PCB Tool"), _("Transformations Tool"),
+ _("Extract Drills Tool"), _("Fiducials Tool"),
_("Solder Paste Dispensing Tool"),
_("Film PCB Tool"), _("Non-Copper Clearing Tool"), _("Optimal Tool"),
_("Paint Area Tool"), _("QRCode Tool"), _("Rules Check Tool"),
@@ -2457,8 +2480,12 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
QtGui.QIcon(self.app.resource_location + '/origin32.png'), _('Set Origin'))
self.jmp_btn = self.toolbargeo.addAction(
QtGui.QIcon(self.app.resource_location + '/jump_to16.png'), _('Jump to Location'))
+ self.locate_btn = self.toolbargeo.addAction(
+ QtGui.QIcon(self.app.resource_location + '/locate32.png'), _('Locate in Object'))
- # ## View Toolbar # ##
+ # ########################################################################
+ # ########################## View Toolbar# ###############################
+ # ########################################################################
self.replot_btn = self.toolbarview.addAction(
QtGui.QIcon(self.app.resource_location + '/replot32.png'), _("&Replot"))
self.clear_plot_btn = self.toolbarview.addAction(
@@ -2470,9 +2497,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.zoom_fit_btn = self.toolbarview.addAction(
QtGui.QIcon(self.app.resource_location + '/zoom_fit32.png'), _("Zoom Fit"))
- # self.toolbarview.setVisible(False)
-
- # ## Shell Toolbar # ##
+ # ########################################################################
+ # ########################## Shell Toolbar# ##############################
+ # ########################################################################
self.shell_btn = self.toolbarshell.addAction(
QtGui.QIcon(self.app.resource_location + '/shell32.png'), _("&Command Line"))
self.new_script_btn = self.toolbarshell.addAction(
@@ -2485,6 +2512,11 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# ## Tools Toolbar # ##
self.dblsided_btn = self.toolbartools.addAction(
QtGui.QIcon(self.app.resource_location + '/doubleside32.png'), _("2Sided Tool"))
+ self.align_btn = self.toolbartools.addAction(
+ QtGui.QIcon(self.app.resource_location + '/align32.png'), _("Align Objects Tool"))
+ self.extract_btn = self.toolbartools.addAction(
+ QtGui.QIcon(self.app.resource_location + '/extract_drill32.png'), _("Extract Drills Tool"))
+
self.cutout_btn = self.toolbartools.addAction(
QtGui.QIcon(self.app.resource_location + '/cut16_bis.png'), _("&Cutout Tool"))
self.ncc_btn = self.toolbartools.addAction(
@@ -2498,10 +2530,13 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.film_btn = self.toolbartools.addAction(
QtGui.QIcon(self.app.resource_location + '/film16.png'), _("Film Tool"))
self.solder_btn = self.toolbartools.addAction(
- QtGui.QIcon(self.app.resource_location + '/solderpastebis32.png'),
- _("SolderPaste Tool"))
+ QtGui.QIcon(self.app.resource_location + '/solderpastebis32.png'), _("SolderPaste Tool"))
self.sub_btn = self.toolbartools.addAction(
QtGui.QIcon(self.app.resource_location + '/sub32.png'), _("Subtract Tool"))
+ self.rules_btn = self.toolbartools.addAction(
+ QtGui.QIcon(self.app.resource_location + '/rules32.png'), _("Rules Tool"))
+ self.optimal_btn = self.toolbartools.addAction(
+ QtGui.QIcon(self.app.resource_location + '/open_excellon32.png'), _("Optimal Tool"))
self.toolbartools.addSeparator()
@@ -2834,6 +2869,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
if key == QtCore.Qt.Key_G:
self.app.on_toggle_axis()
+ # Locate in Object
+ if key == QtCore.Qt.Key_J:
+ self.app.on_locate(obj=self.app.collection.get_active())
+
# Run Distance Minimum Tool
if key == QtCore.Qt.Key_M:
self.app.distance_min_tool.run()
@@ -2882,6 +2921,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
if key == Qt.Key_3:
self.app.disable_other_plots()
+ # Align in Object Tool
+ if key == QtCore.Qt.Key_A:
+ self.app.align_objects_tool.run(toggle=True)
+
# Calculator Tool
if key == QtCore.Qt.Key_C:
self.app.calculator_tool.run(toggle=True)
@@ -2906,6 +2949,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.app.on_toggle_grid_lines()
return
+ # Align in Object Tool
+ if key == QtCore.Qt.Key_I:
+ self.app.edrills_tool.run(toggle=True)
+
# Fiducials Tool
if key == QtCore.Qt.Key_J:
self.app.fiducial_tool.run(toggle=True)
diff --git a/flatcamTools/ToolAlignObjects.py b/flatcamTools/ToolAlignObjects.py
index 7368b865..d1e77442 100644
--- a/flatcamTools/ToolAlignObjects.py
+++ b/flatcamTools/ToolAlignObjects.py
@@ -224,7 +224,6 @@ class AlignObjects(FlatCAMTool):
self.aligned_old_fill_color = None
self.aligned_old_line_color = None
-
def run(self, toggle=True):
self.app.report_usage("ToolAlignObjects()")
@@ -460,50 +459,6 @@ class AlignObjects(FlatCAMTool):
angle = angle_dest - angle_start
self.aligned_obj.rotate(angle=angle, point=origin_pt)
- def execute(self):
- aligned_name = self.object_combo.currentText()
-
- # Get source object.
- try:
- aligned_obj = self.app.collection.get_by_name(str(aligned_name))
- except Exception as e:
- log.debug("AlignObjects.on_align() --> %s" % str(e))
- self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), aligned_name))
- return "Could not retrieve object: %s" % aligned_name
-
- if aligned_obj is None:
- self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Object not found"), aligned_obj))
- return "Object not found: %s" % aligned_obj
-
- aligner_name = self.box_combo.currentText()
-
- try:
- aligner_obj = self.app.collection.get_by_name(aligner_name)
- except Exception as e:
- log.debug("AlignObjects.on_align() --> %s" % str(e))
- self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), aligner_name))
- return "Could not retrieve object: %s" % aligner_name
-
- if aligner_obj is None:
- self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), aligner_name))
-
- def align_job():
- pass
-
- proc = self.app.proc_container.new(_("Working..."))
-
- def job_thread(app_obj):
- try:
- align_job()
- app_obj.inform.emit('[success] %s' % _("Panel created successfully."))
- except Exception as ee:
- proc.done()
- log.debug(str(ee))
- return
- proc.done()
-
- self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
-
def disconnect_cal_events(self):
# restore the Grid snapping if it was active before
if self.grid_status_memory is True:
diff --git a/share/extract_drill16.png b/share/extract_drill16.png
new file mode 100644
index 0000000000000000000000000000000000000000..4b3a29abcbd40df29de8bdf4ab9798ff03c17576
GIT binary patch
literal 459
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6XVU3I`u#fXMsm#F#`je
z9|$vEn-I1eC^$dBC&U#<4`#4^vYiXieWoQre!&d-Fcpb6ALp-t2BX
literal 0
HcmV?d00001
diff --git a/share/extract_drill32.png b/share/extract_drill32.png
new file mode 100644
index 0000000000000000000000000000000000000000..41f740f249b02779fe8d74b1ecfa69ba7e1ea76e
GIT binary patch
literal 745
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jPK-BC>eK@{oCO|{#S9E=
zejv>?paQ`FpAc7|h-TdC#@_
zj!4m{1f7>3Y`Mc;YdY)~4{B#&V&gCFwmJul11?V&$B>FS$q5R421bGb2hKPxezqJt87lRy2f%1PJVA5)cp;pYE{LG0015rna)S
zdb5)L`UNYN^yn;D)O92<`1*w_j~)w)UA@-Wy|ATuo!sg^rTP0B7fv*cIdeqhDred=
zv1wsE6^&bYXEm&q)snwD+u=Y)|Ecl~stXvHEsTmDPAw05P=0Lfp`%knIVGg?)~$PY
zL$sozs`B&4pFcKjC@}u4|0cE$FL>C4e^W1y8Q*L2^CSQ40
z$*IX6OSIMppKQ2$BW00V#dg+jcYkh>&A;^P^ox0wk>P12Ql$x@)_2V|#6?$JToSW4
z;iQ7F*c#=9*VAfadKS%eIM}S5t@TUx-%j5syTqH_$Df_Qs4iXcFL{gL`*ZslCu}#p
z7QiOA6c|FPC9V-ADTyViR>?)FK#IZ0z{o(?z);uFG{nHb%D}?P#84Z=Fc8n)>WZQv
zH$NpatrE9}G&A0xKn;>08-nxGO3D+9QW?t2%k?tzvWt@w3sUv+i_&MmvylQSV(@hJ
Kb6Mw<&;$TR7|D+S
literal 0
HcmV?d00001
diff --git a/share/locate32.png b/share/locate32.png
new file mode 100644
index 0000000000000000000000000000000000000000..66d630b07edd92fcc124cfdfaaef755ab35847f1
GIT binary patch
literal 900
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50
z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzZ+Rj;xUkjGiz
z5n0T@z;^_M8K-LVNdpDhOFVsD*`F}-GjPZ!UiQ@oY6|jnaSZV|zVyod?!HQi;~%Gg
z+;Fz%U{sjonF*J=d=*bCbe>RAa`)>np7VhJLe6b9%L($C;YCVr773GtU4uR;tFy76
z>iKHWdh_e=@W;E^zyG~+{%=LzGfBJeC;#qU_x|g@xcjen{rWWb)pybR5ubY|e!e1V
z{+sLH%|ctJPj?O0>OZvKCCq;B`n$yn6{&7d8*G~%Y&w~+V?XOb-O#D6*DEwL!e?)i
z6=M0U&3s0XCEF`!@fVJ5)AP@HW$Ek)OR9dND5b?5;(U_z#d5QcU$`pR!lvAK_Dl2Q
zmsOfg54O(iOx3i>>>QvQK$i
zU`F!d-}4#k{6A@Ctp7ga!KA|q>-R-8A4@XYcx&!Po2~!O|Fg(xuTEP%slQ4n^+EvK
z0$2a6ukJM`x8J&BdViM_+eE)xa{|B4UHN>;md4FGA7-Ch^sp^evf!X|{-^2BXk24^fuoVMch$)B&Kn;yph-gIw;-K%;r=BF)*+)u&^>V)CMsOWY_J9LD7(#pOTqYiCaU?
zXO;&*4U!-mg7ec#$`gxH8OqDc^)mCai<1)zQuXqS(r3T3kpe1W@O1TaS?83{1OVCZ
Bf)W4#
literal 0
HcmV?d00001
From 9a9b6908bc8a73d632e183f0716b0b0069f02d94 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 15 Jan 2020 03:02:45 +0200
Subject: [PATCH 020/209] - minor changes
---
FlatCAMApp.py | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 5324290e..dce2111f 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -141,7 +141,7 @@ class App(QtCore.QObject):
# ################## Version and VERSION DATE ##############################
# ##########################################################################
version = 8.992
- version_date = "2020/01/02"
+ version_date = "2020/01/20"
beta = True
engine = '3D'
@@ -7202,15 +7202,13 @@ class App(QtCore.QObject):
obj.options['ymin'] = b
obj.options['xmax'] = c
obj.options['ymax'] = d
- self.inform.emit('[success] %s...' %
- _('Origin set'))
+ self.inform.emit('[success] %s...' % _('Origin set'))
if noplot_sig is False:
self.replot_signal.emit([])
if location is not None:
if len(location) != 2:
- self.inform.emit('[ERROR_NOTCL] %s...' %
- _("Origin coordinates specified but incomplete."))
+ self.inform.emit('[ERROR_NOTCL] %s...' % _("Origin coordinates specified but incomplete."))
return 'fail'
x, y = location
From f9a8d09b26441f22f04d92135937af125ba716ee Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 15 Jan 2020 17:47:28 +0200
Subject: [PATCH 021/209] - modified the NCC Tool GUI to prepare for accepting
a tool from a tool database - started to modify the Paint Tool to be similar
to NCC Tool and to accept a tool from a database
---
FlatCAMApp.py | 6 +
README.md | 2 +
flatcamTools/ToolNonCopperClear.py | 148 ++++---
flatcamTools/ToolPaint.py | 631 +++++++++++++++++++++++++----
4 files changed, 639 insertions(+), 148 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index dce2111f..e073978d 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -803,6 +803,12 @@ class App(QtCore.QObject):
"tools_pathconnect": True,
"tools_paintcontour": True,
"tools_paint_plotting": 'normal',
+ "tools_paintrest": False,
+ "tools_painttool_type": 'V',
+ "tools_paintcutz": -0.05,
+ "tools_painttipdia": 0.1,
+ "tools_painttipangle": 30,
+ "tools_paintnewdia": 1.0,
# 2-Sided Tool
"tools_2sided_mirror_axis": "X",
diff --git a/README.md b/README.md
index 2c446e8a..f91a123c 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,8 @@ CAD program, and create G-Code for Isolation routing.
- added key shortcuts and toolbar icons for the new tools: Align Object Tool (ALT+A) and Extract Drills (ALT+I)
- added new functionality (key shortcut SHIFT+J) to locate the corners of the bounding box (and center) in a selected object
+- modified the NCC Tool GUI to prepare for accepting a tool from a tool database
+- started to modify the Paint Tool to be similar to NCC Tool and to accept a tool from a database
14.01.2020
diff --git a/flatcamTools/ToolNonCopperClear.py b/flatcamTools/ToolNonCopperClear.py
index b8e365c5..5b2e8b1d 100644
--- a/flatcamTools/ToolNonCopperClear.py
+++ b/flatcamTools/ToolNonCopperClear.py
@@ -411,7 +411,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
_("Draw lines between resulting\n"
"segments to minimize tool lifts.")
)
- self.grid3.addWidget(self.ncc_connect_cb, 16, 0, 1, 2)
+ self.grid3.addWidget(self.ncc_connect_cb, 16, 0)
# Contour
self.ncc_contour_cb = FCCheckBox('%s' % _("Contour"))
@@ -421,7 +421,69 @@ class NonCopperClear(FlatCAMTool, Gerber):
_("Cut around the perimeter of the polygon\n"
"to trim rough edges.")
)
- self.grid3.addWidget(self.ncc_contour_cb, 17, 0, 1, 2)
+ self.grid3.addWidget(self.ncc_contour_cb, 16, 1)
+
+ # ## NCC Offset choice
+ self.ncc_choice_offset_cb = FCCheckBox('%s' % _("Offset"))
+ self.ncc_choice_offset_cb.setObjectName(_("Offset"))
+
+ self.ncc_choice_offset_cb.setToolTip(
+ _("If used, it will add an offset to the copper features.\n"
+ "The copper clearing will finish to a distance\n"
+ "from the copper features.\n"
+ "The value can be between 0 and 10 FlatCAM units.")
+ )
+ self.grid3.addWidget(self.ncc_choice_offset_cb, 19, 0)
+
+ # ## NCC Offset value
+ # self.ncc_offset_label = QtWidgets.QLabel('%s:' % _("Offset value"))
+ # self.ncc_offset_label.setToolTip(
+ # _("If used, it will add an offset to the copper features.\n"
+ # "The copper clearing will finish to a distance\n"
+ # "from the copper features.\n"
+ # "The value can be between 0 and 10 FlatCAM units.")
+ # )
+ self.ncc_offset_spinner = FCDoubleSpinner()
+ self.ncc_offset_spinner.set_range(0.00, 10.00)
+ self.ncc_offset_spinner.set_precision(4)
+ self.ncc_offset_spinner.setWrapping(True)
+ self.ncc_offset_spinner.setObjectName(_("Offset value"))
+
+ units = self.app.defaults['units'].upper()
+ if units == 'MM':
+ self.ncc_offset_spinner.setSingleStep(0.1)
+ else:
+ self.ncc_offset_spinner.setSingleStep(0.01)
+
+ # self.grid3.addWidget(self.ncc_offset_label, 20, 0)
+ self.grid3.addWidget(self.ncc_offset_spinner, 19, 1)
+
+ # self.ncc_offset_label.hide()
+ self.ncc_offset_spinner.setEnabled(False)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.grid3.addWidget(separator_line, 21, 0, 1, 2)
+
+ self.apply_param_to_all = FCButton(_("Apply parameters to all tools"))
+ self.apply_param_to_all.setToolTip(
+ _("The parameters in the current form will be applied\n"
+ "on all the tools from the Tool Table.")
+ )
+ self.grid3.addWidget(self.apply_param_to_all, 22, 0, 1, 2)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.grid3.addWidget(separator_line, 23, 0, 1, 2)
+
+ # General Parameters
+ self.gen_param_label = QtWidgets.QLabel('%s' % _("Common Parameters"))
+ self.gen_param_label.setToolTip(
+ _("Parameters that are common for all tools.")
+ )
+ self.grid3.addWidget(self.gen_param_label, 24, 0, 1, 2)
# Rest Machining
self.ncc_rest_cb = FCCheckBox('%s' % _("Rest Machining"))
@@ -437,51 +499,13 @@ class NonCopperClear(FlatCAMTool, Gerber):
"If not checked, use the standard algorithm.")
)
- self.grid3.addWidget(self.ncc_rest_cb, 18, 0, 1, 2)
-
- # ## NCC Offset choice
- self.ncc_choice_offset_cb = FCCheckBox('%s' % _("Offset"))
- self.ncc_choice_offset_cb.setObjectName(_("Offset"))
-
- self.ncc_choice_offset_cb.setToolTip(
- _("If used, it will add an offset to the copper features.\n"
- "The copper clearing will finish to a distance\n"
- "from the copper features.\n"
- "The value can be between 0 and 10 FlatCAM units.")
- )
- self.grid3.addWidget(self.ncc_choice_offset_cb, 19, 0, 1, 2)
-
- # ## NCC Offset value
- self.ncc_offset_label = QtWidgets.QLabel('%s:' % _("Offset value"))
- self.ncc_offset_label.setToolTip(
- _("If used, it will add an offset to the copper features.\n"
- "The copper clearing will finish to a distance\n"
- "from the copper features.\n"
- "The value can be between 0 and 10 FlatCAM units.")
- )
- self.ncc_offset_spinner = FCDoubleSpinner()
- self.ncc_offset_spinner.set_range(0.00, 10.00)
- self.ncc_offset_spinner.set_precision(4)
- self.ncc_offset_spinner.setWrapping(True)
- self.ncc_offset_spinner.setObjectName(_("Offset value"))
-
- units = self.app.defaults['units'].upper()
- if units == 'MM':
- self.ncc_offset_spinner.setSingleStep(0.1)
- else:
- self.ncc_offset_spinner.setSingleStep(0.01)
-
- self.grid3.addWidget(self.ncc_offset_label, 20, 0)
- self.grid3.addWidget(self.ncc_offset_spinner, 20, 1)
-
- self.ncc_offset_label.hide()
- self.ncc_offset_spinner.hide()
+ self.grid3.addWidget(self.ncc_rest_cb, 25, 0, 1, 2)
# ## Reference
self.reference_radio = RadioSet([
{'label': _('Itself'), 'value': 'itself'},
{"label": _("Area Selection"), "value": "area"},
- {'label': _("Reference Object"), 'value': 'box'}
+ {'label': _("Reference Object"), 'value': 'box'}
], orientation='vertical', stretch=False)
self.reference_radio.setObjectName(_("Reference"))
@@ -491,11 +515,11 @@ class NonCopperClear(FlatCAMTool, Gerber):
"- 'Area Selection' - left mouse click to start selection of the area to be painted.\n"
"- 'Reference Object' - will do non copper clearing within the area specified by another object.")
)
- self.grid3.addWidget(self.reference_label, 21, 0)
- self.grid3.addWidget(self.reference_radio, 21, 1)
+ self.grid3.addWidget(self.reference_label, 26, 0, 1, 2)
+ self.grid3.addWidget(self.reference_radio, 27, 0, 1, 2)
form1 = QtWidgets.QFormLayout()
- self.grid3.addLayout(form1, 22, 0, 1, 2)
+ self.grid3.addLayout(form1, 28, 0, 1, 2)
self.box_combo_type_label = QtWidgets.QLabel('%s:' % _("Ref. Type"))
self.box_combo_type_label.setToolTip(
@@ -523,17 +547,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.box_combo_type.hide()
self.box_combo_type_label.hide()
- separator_line2 = QtWidgets.QFrame()
- separator_line2.setFrameShape(QtWidgets.QFrame.HLine)
- separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.grid3.addWidget(separator_line2, 23, 0, 1, 2)
-
- self.apply_param_to_all = FCButton(_("Apply parameters to all tools"))
- self.apply_param_to_all.setToolTip(
- _("The parameters in the current form will be applied\n"
- "on all the tools from the Tool Table.")
- )
- self.grid3.addWidget(self.apply_param_to_all, 24, 0, 1, 2)
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.grid3.addWidget(separator_line, 29, 0, 1, 2)
self.generate_ncc_button = QtWidgets.QPushButton(_('Generate Geometry'))
self.generate_ncc_button.setToolTip(
@@ -630,10 +647,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
"nccmethod": self.ncc_method_radio,
"nccconnect": self.ncc_connect_cb,
"ncccontour": self.ncc_contour_cb,
- "nccrest": self.ncc_rest_cb,
"nccoffset": self.ncc_choice_offset_cb,
"nccoffset_value": self.ncc_offset_spinner,
- "nccref": self.reference_radio,
"milling_type": self.milling_type_radio
}
@@ -643,10 +658,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
_('Method'): "nccmethod",
_("Connect"): "nccconnect",
_("Contour"): "ncccontour",
- _("Rest Machining"): "nccrest",
_("Offset"): "nccoffset",
_("Offset value"): "nccoffset_value",
- _("Reference"): "nccref",
_('Milling Type'): "milling_type",
}
@@ -720,7 +733,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
form_value_storage = tooluid_value[key]
self.storage_to_form(form_value_storage)
except Exception as e:
- log.debug("FlatCAMObj ---> update_ui() " + str(e))
+ log.debug("NonCopperClear ---> update_ui() " + str(e))
self.blockSignals(False)
@@ -1164,12 +1177,13 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.box_combo_type_label.show()
def on_offset_choice(self, state):
- if state:
- self.ncc_offset_label.show()
- self.ncc_offset_spinner.show()
- else:
- self.ncc_offset_label.hide()
- self.ncc_offset_spinner.hide()
+ # if state:
+ # self.ncc_offset_label.show()
+ # self.ncc_offset_spinner.show()
+ # else:
+ # self.ncc_offset_label.hide()
+ # self.ncc_offset_spinner.hide()
+ self.ncc_offset_spinner.setEnabled(state)
def on_order_changed(self, order):
if order != 'no':
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 91dee46f..95fc26e7 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -14,13 +14,14 @@ from copy import deepcopy
from flatcamParsers.ParseGerber import Gerber
from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry
from camlib import Geometry
-from flatcamGUI.GUIElements import FCTable, FCDoubleSpinner, FCCheckBox, FCInputDialog, RadioSet
+from flatcamGUI.GUIElements import FCTable, FCDoubleSpinner, FCCheckBox, FCInputDialog, RadioSet, FCButton
import FlatCAMApp
from shapely.geometry import base, Polygon, MultiPolygon, LinearRing
from shapely.ops import cascaded_union
import numpy as np
+import math
from numpy import Inf
import traceback
import logging
@@ -66,8 +67,10 @@ class ToolPaint(FlatCAMTool, Gerber):
self.tools_frame.setLayout(self.tools_box)
# ## Form Layout
- form_layout = QtWidgets.QFormLayout()
- self.tools_box.addLayout(form_layout)
+ grid0 = QtWidgets.QGridLayout()
+ grid0.setColumnStretch(0, 0)
+ grid0.setColumnStretch(1, 1)
+ self.tools_box.addLayout(grid0)
# ################################################
# ##### Type of object to be painted #############
@@ -90,7 +93,8 @@ class ToolPaint(FlatCAMTool, Gerber):
"of objects that will populate the 'Object' combobox.")
)
self.type_obj_combo_label.setMinimumWidth(60)
- form_layout.addRow(self.type_obj_combo_label, self.type_obj_combo)
+ grid0.addWidget(self.type_obj_combo_label, 1, 0)
+ grid0.addWidget(self.type_obj_combo, 1, 1)
# ################################################
# ##### The object to be painted #################
@@ -103,10 +107,13 @@ class ToolPaint(FlatCAMTool, Gerber):
self.object_label = QtWidgets.QLabel('%s:' % _("Object"))
self.object_label.setToolTip(_("Object to be painted."))
- form_layout.addRow(self.object_label, self.obj_combo)
+ grid0.addWidget(self.object_label, 2, 0)
+ grid0.addWidget(self.obj_combo, 2, 1)
- e_lab_0 = QtWidgets.QLabel('')
- form_layout.addRow(e_lab_0)
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 5, 0, 1, 2)
# ### Tools ## ##
self.tools_table_label = QtWidgets.QLabel('%s' % _('Tools Table'))
@@ -114,10 +121,11 @@ class ToolPaint(FlatCAMTool, Gerber):
_("Tools pool from which the algorithm\n"
"will pick the ones used for painting.")
)
- self.tools_box.addWidget(self.tools_table_label)
self.tools_table = FCTable()
- self.tools_box.addWidget(self.tools_table)
+
+ grid0.addWidget(self.tools_table_label, 6, 0, 1, 2)
+ grid0.addWidget(self.tools_table, 7, 0, 1, 2)
self.tools_table.setColumnCount(4)
self.tools_table.setHorizontalHeaderLabels(['#', _('Diameter'), _('TT'), ''])
@@ -167,23 +175,107 @@ class ToolPaint(FlatCAMTool, Gerber):
"'Reverse' --> menas that the tools will ordered from big to small\n\n"
"WARNING: using rest machining will automatically set the order\n"
"in reverse and disable this control."))
- form = QtWidgets.QFormLayout()
- self.tools_box.addLayout(form)
- form.addRow(QtWidgets.QLabel(''), QtWidgets.QLabel(''))
- form.addRow(self.order_label, self.order_radio)
- # ### Add a new Tool ## ##
+ grid0.addWidget(self.order_label, 9, 0)
+ grid0.addWidget(self.order_radio, 9, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 10, 0, 1, 2)
+
+ self.grid3 = QtWidgets.QGridLayout()
+ self.tools_box.addLayout(self.grid3)
+ self.grid3.setColumnStretch(0, 0)
+ self.grid3.setColumnStretch(1, 1)
+
+ # ##############################################################################
+ # ###################### ADD A NEW TOOL ########################################
+ # ##############################################################################
+ self.tool_sel_label = QtWidgets.QLabel('%s' % _("New Tool"))
+ self.grid3.addWidget(self.tool_sel_label, 1, 0, 1, 2)
+
+ # Tool Type Radio Button
+ self.tool_type_label = QtWidgets.QLabel('%s:' % _('Tool Type'))
+ self.tool_type_label.setToolTip(
+ _("Default tool type:\n"
+ "- 'V-shape'\n"
+ "- Circular")
+ )
+
+ self.tool_type_radio = RadioSet([{'label': _('V-shape'), 'value': 'V'},
+ {'label': _('Circular'), 'value': 'C1'}])
+ self.tool_type_radio.setToolTip(
+ _("Default tool type:\n"
+ "- 'V-shape'\n"
+ "- Circular")
+ )
+ self.tool_type_radio.setObjectName(_("Tool Type"))
+
+ self.grid3.addWidget(self.tool_type_label, 2, 0)
+ self.grid3.addWidget(self.tool_type_radio, 2, 1)
+
+ # Tip Dia
+ self.tipdialabel = QtWidgets.QLabel('%s:' % _('V-Tip Dia'))
+ self.tipdialabel.setToolTip(
+ _("The tip diameter for V-Shape Tool"))
+ self.tipdia_entry = FCDoubleSpinner()
+ self.tipdia_entry.set_precision(self.decimals)
+ self.tipdia_entry.set_range(0.0000, 9999.9999)
+ self.tipdia_entry.setSingleStep(0.1)
+ self.tipdia_entry.setObjectName(_("V-Tip Dia"))
+
+ self.grid3.addWidget(self.tipdialabel, 3, 0)
+ self.grid3.addWidget(self.tipdia_entry, 3, 1)
+
+ # Tip Angle
+ self.tipanglelabel = QtWidgets.QLabel('%s:' % _('V-Tip Angle'))
+ self.tipanglelabel.setToolTip(
+ _("The tip angle for V-Shape Tool.\n"
+ "In degree."))
+ self.tipangle_entry = FCDoubleSpinner()
+ self.tipangle_entry.set_precision(self.decimals)
+ self.tipangle_entry.set_range(0.0000, 180.0000)
+ self.tipangle_entry.setSingleStep(5)
+ self.tipangle_entry.setObjectName(_("V-Tip Angle"))
+
+ self.grid3.addWidget(self.tipanglelabel, 4, 0)
+ self.grid3.addWidget(self.tipangle_entry, 4, 1)
+
+ # Cut Z entry
+ cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
+ cutzlabel.setToolTip(
+ _("Depth of cut into material. Negative value.\n"
+ "In FlatCAM units.")
+ )
+ self.cutz_entry = FCDoubleSpinner()
+ self.cutz_entry.set_precision(self.decimals)
+ self.cutz_entry.set_range(-99999.9999, 0.0000)
+ self.cutz_entry.setObjectName(_("Cut Z"))
+
+ self.cutz_entry.setToolTip(
+ _("Depth of cut into material. Negative value.\n"
+ "In FlatCAM units.")
+ )
+ self.grid3.addWidget(cutzlabel, 5, 0)
+ self.grid3.addWidget(self.cutz_entry, 5, 1)
+
+ # ### Tool Diameter ####
self.addtool_entry_lbl = QtWidgets.QLabel('%s:' % _('Tool Dia'))
self.addtool_entry_lbl.setToolTip(
- _("Diameter for the new tool.")
+ _("Diameter for the new tool to add in the Tool Table.\n"
+ "If the tool is V-shape type then this value is automatically\n"
+ "calculated from the other parameters.")
)
self.addtool_entry = FCDoubleSpinner()
self.addtool_entry.set_precision(self.decimals)
+ self.addtool_entry.set_range(0.000, 9999.9999)
+ self.addtool_entry.setObjectName(_("Tool Dia"))
- form.addRow(self.addtool_entry_lbl, self.addtool_entry)
+ self.grid3.addWidget(self.addtool_entry_lbl, 6, 0)
+ self.grid3.addWidget(self.addtool_entry, 6, 1)
- grid2 = QtWidgets.QGridLayout()
- self.tools_box.addLayout(grid2)
+ hlay = QtWidgets.QHBoxLayout()
self.addtool_btn = QtWidgets.QPushButton(_('Add'))
self.addtool_btn.setToolTip(
@@ -191,29 +283,50 @@ class ToolPaint(FlatCAMTool, Gerber):
"with the diameter specified above.")
)
- # self.copytool_btn = QtWidgets.QPushButton('Copy')
- # self.copytool_btn.setToolTip(
- # "Copy a selection of tools in the Tool Table\n"
- # "by first selecting a row in the Tool Table."
- # )
+ self.addtool_from_db_btn = QtWidgets.QPushButton(_('Add from DB'))
+ self.addtool_from_db_btn.setToolTip(
+ _("Add a new tool to the Tool Table\n"
+ "from the Tool DataBase.")
+ )
+
+ hlay.addWidget(self.addtool_btn)
+ hlay.addWidget(self.addtool_from_db_btn)
+
+ self.grid3.addLayout(hlay, 7, 0, 1, 2)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.grid3.addWidget(separator_line, 8, 0, 1, 2)
self.deltool_btn = QtWidgets.QPushButton(_('Delete'))
self.deltool_btn.setToolTip(
_("Delete a selection of tools in the Tool Table\n"
"by first selecting a row(s) in the Tool Table.")
)
+ self.grid3.addWidget(self.deltool_btn, 9, 0, 1, 2)
- grid2.addWidget(self.addtool_btn, 0, 0)
- # grid2.addWidget(self.copytool_btn, 0, 1)
- grid2.addWidget(self.deltool_btn, 0, 2)
+ self.grid3.addWidget(QtWidgets.QLabel(''), 10, 0, 1, 2)
- self.empty_label_0 = QtWidgets.QLabel('')
- self.tools_box.addWidget(self.empty_label_0)
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.grid3.addWidget(separator_line, 11, 0, 1, 2)
- grid3 = QtWidgets.QGridLayout()
- self.tools_box.addLayout(grid3)
- grid3.setColumnStretch(0, 0)
- grid3.setColumnStretch(1, 1)
+ self.tool_data_label = QtWidgets.QLabel(
+ "%s: %s %d" % (_('Parameters for'), _("Tool"), int(1)))
+ self.tool_data_label.setToolTip(
+ _(
+ "The data used for creating GCode.\n"
+ "Each tool store it's own set of such data."
+ )
+ )
+ self.grid3.addWidget(self.tool_data_label, 12, 0, 1, 2)
+
+ grid4 = QtWidgets.QGridLayout()
+ grid4.setColumnStretch(0, 0)
+ grid4.setColumnStretch(1, 1)
+ self.tools_box.addLayout(grid4)
# Overlap
ovlabel = QtWidgets.QLabel('%s:' % _('Overlap Rate'))
@@ -231,8 +344,10 @@ class ToolPaint(FlatCAMTool, Gerber):
self.paintoverlap_entry.setWrapping(True)
self.paintoverlap_entry.setRange(0.0000, 99.9999)
self.paintoverlap_entry.setSingleStep(0.1)
- grid3.addWidget(ovlabel, 1, 0)
- grid3.addWidget(self.paintoverlap_entry, 1, 1)
+ self.paintoverlap_entry.setObjectName(_("Overlap Rate"))
+
+ grid4.addWidget(ovlabel, 1, 0)
+ grid4.addWidget(self.paintoverlap_entry, 1, 1)
# Margin
marginlabel = QtWidgets.QLabel('%s:' % _('Margin'))
@@ -241,11 +356,12 @@ class ToolPaint(FlatCAMTool, Gerber):
"the edges of the polygon to\n"
"be painted.")
)
- grid3.addWidget(marginlabel, 2, 0)
self.paintmargin_entry = FCDoubleSpinner()
self.paintmargin_entry.set_precision(self.decimals)
+ self.paintmargin_entry.setObjectName(_("Margin"))
- grid3.addWidget(self.paintmargin_entry, 2, 1)
+ grid4.addWidget(marginlabel, 2, 0)
+ grid4.addWidget(self.paintmargin_entry, 2, 1)
# Method
methodlabel = QtWidgets.QLabel('%s:' % _('Method'))
@@ -255,30 +371,60 @@ class ToolPaint(FlatCAMTool, Gerber):
"- Seed-based: Outwards from seed.\n"
"- Line-based: Parallel lines.")
)
- grid3.addWidget(methodlabel, 3, 0)
self.paintmethod_combo = RadioSet([
{"label": _("Standard"), "value": "standard"},
{"label": _("Seed-based"), "value": "seed"},
{"label": _("Straight lines"), "value": "lines"}
], orientation='vertical', stretch=False)
- grid3.addWidget(self.paintmethod_combo, 3, 1)
+ self.paintmethod_combo.setObjectName(_("Method"))
+
+ grid4.addWidget(methodlabel, 3, 0)
+ grid4.addWidget(self.paintmethod_combo, 3, 1)
# Connect lines
self.pathconnect_cb = FCCheckBox('%s' % _("Connect"))
+ self.pathconnect_cb.setObjectName(_("Connect"))
self.pathconnect_cb.setToolTip(
_("Draw lines between resulting\n"
"segments to minimize tool lifts.")
)
- grid3.addWidget(self.pathconnect_cb, 4, 0, 1, 2)
self.paintcontour_cb = FCCheckBox('%s' % _("Contour"))
+ self.paintcontour_cb.setObjectName(_("Contour"))
self.paintcontour_cb.setToolTip(
_("Cut around the perimeter of the polygon\n"
"to trim rough edges.")
)
- grid3.addWidget(self.paintcontour_cb, 5, 0, 1, 2)
+
+ grid4.addWidget(self.pathconnect_cb, 4, 0)
+ grid4.addWidget(self.paintcontour_cb, 4, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid4.addWidget(separator_line, 5, 0, 1, 2)
+
+ self.apply_param_to_all = FCButton(_("Apply parameters to all tools"))
+ self.apply_param_to_all.setToolTip(
+ _("The parameters in the current form will be applied\n"
+ "on all the tools from the Tool Table.")
+ )
+ grid4.addWidget(self.apply_param_to_all, 7, 0, 1, 2)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid4.addWidget(separator_line, 8, 0, 1, 2)
+
+ # General Parameters
+ self.gen_param_label = QtWidgets.QLabel('%s' % _("Common Parameters"))
+ self.gen_param_label.setToolTip(
+ _("Parameters that are common for all tools.")
+ )
+ grid4.addWidget(self.gen_param_label, 10, 0, 1, 2)
self.rest_cb = FCCheckBox('%s' % _("Rest Machining"))
+ self.rest_cb.setObjectName(_("Rest Machining"))
self.rest_cb.setToolTip(
_("If checked, use 'rest machining'.\n"
"Basically it will clear copper outside PCB features,\n"
@@ -288,7 +434,7 @@ class ToolPaint(FlatCAMTool, Gerber):
"no more copper to clear or there are no more tools.\n\n"
"If not checked, use the standard algorithm.")
)
- grid3.addWidget(self.rest_cb, 6, 0, 1, 2)
+ grid4.addWidget(self.rest_cb, 11, 0, 1, 2)
# Polygon selection
selectlabel = QtWidgets.QLabel('%s:' % _('Selection'))
@@ -301,7 +447,7 @@ class ToolPaint(FlatCAMTool, Gerber):
"- 'Reference Object' - will do non copper clearing within the area\n"
"specified by another object.")
)
- grid3.addWidget(selectlabel, 7, 0)
+
# grid3 = QtWidgets.QGridLayout()
self.selectmethod_combo = RadioSet([
{"label": _("Polygon Selection"), "value": "single"},
@@ -309,6 +455,7 @@ class ToolPaint(FlatCAMTool, Gerber):
{"label": _("All Polygons"), "value": "all"},
{"label": _("Reference Object"), "value": "ref"}
], orientation='vertical', stretch=False)
+ self.selectmethod_combo.setObjectName(_("Selection"))
self.selectmethod_combo.setToolTip(
_("How to select Polygons to be painted.\n"
"- 'Polygon Selection' - left mouse click to add/remove polygons to be painted.\n"
@@ -318,10 +465,12 @@ class ToolPaint(FlatCAMTool, Gerber):
"- 'Reference Object' - will do non copper clearing within the area\n"
"specified by another object.")
)
- grid3.addWidget(self.selectmethod_combo, 7, 1)
+
+ grid4.addWidget(selectlabel, 13, 0, 1, 2)
+ grid4.addWidget(self.selectmethod_combo, 14, 0, 1, 2)
form1 = QtWidgets.QFormLayout()
- self.tools_box.addLayout(form1)
+ grid4.addLayout(form1, 15, 0, 1, 2)
self.box_combo_type_label = QtWidgets.QLabel('%s:' % _("Ref. Type"))
self.box_combo_type_label.setToolTip(
@@ -350,7 +499,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.box_combo_type_label.hide()
# GO Button
- self.generate_paint_button = QtWidgets.QPushButton(_('Create Paint Geometry'))
+ self.generate_paint_button = QtWidgets.QPushButton(_('Generate Geometry'))
self.generate_paint_button.setToolTip(
_("- 'Area Selection' - left mouse click to start selection of the area to be painted.\n"
"Keeping a modifier key pressed (CTRL or SHIFT) will allow to add multiple areas.\n"
@@ -381,8 +530,28 @@ class ToolPaint(FlatCAMTool, Gerber):
""")
self.tools_box.addWidget(self.reset_button)
- # #################################### FINSIHED GUI #####################################
- # #######################################################################################
+ # #################################### FINSIHED GUI ###########################
+ # #############################################################################
+
+ # #############################################################################
+ # ###################### Setup CONTEXT MENU ###################################
+ # #############################################################################
+ self.tools_table.setupContextMenu()
+ self.tools_table.addContextMenu(
+ _("Add"), self.on_add_tool_by_key, icon=QtGui.QIcon(self.app.resource_location + "/plus16.png")
+ )
+ self.tools_table.addContextMenu(
+ _("Add from DB"), self.on_add_tool_by_key, icon=QtGui.QIcon(self.app.resource_location + "/plus16.png")
+ )
+ self.tools_table.addContextMenu(
+ _("Delete"), lambda:
+ self.on_tool_delete(rows_to_delete=None, all_tools=None),
+ icon=QtGui.QIcon(self.app.resource_location + "/delete32.png")
+ )
+
+ # #############################################################################
+ # ########################## VARIABLES ########################################
+ # #############################################################################
self.obj_name = ""
self.paint_obj = None
@@ -422,8 +591,8 @@ class ToolPaint(FlatCAMTool, Gerber):
"name": '_paint',
"plot": self.app.defaults["geometry_plot"],
"cutz": self.app.defaults["geometry_cutz"],
- "vtipdia": 0.1,
- "vtipangle": 30,
+ "vtipdia": float(self.tipdia_entry.get_value()),
+ "vtipangle": float(self.tipangle_entry.get_value()),
"travelz": self.app.defaults["geometry_travelz"],
"feedrate": self.app.defaults["geometry_feedrate"],
"feedrate_z": self.app.defaults["geometry_feedrate_z"],
@@ -448,19 +617,43 @@ class ToolPaint(FlatCAMTool, Gerber):
"selectmethod": self.app.defaults["tools_selectmethod"],
"pathconnect": self.app.defaults["tools_pathconnect"],
"paintcontour": self.app.defaults["tools_paintcontour"],
- "paintoverlap": self.app.defaults["tools_paintoverlap"]
+ "paintoverlap": self.app.defaults["tools_paintoverlap"],
+ "paintrest": self.app.defaults["tools_paintrest"],
})
self.tool_type_item_options = ["C1", "C2", "C3", "C4", "B", "V"]
+ self.form_fields = {
+ "paintoverlap": self.paintoverlap_entry,
+ "paintmargin": self.paintmargin_entry,
+ "paintmethod": self.paintmethod_combo,
+ "pathconnect": self.pathconnect_cb,
+ "paintcontour": self.paintcontour_cb,
+ }
+
+ self.name2option = {
+ _('Overlap Rate'): "paintoverlap",
+ _('Margin'): "paintmargin",
+ _('Method'): "paintmethod",
+ _("Connect"): "pathconnect",
+ _("Contour"): "paintcontour",
+ }
+
# #############################################################################
# ################################# Signals ###################################
# #############################################################################
self.addtool_btn.clicked.connect(self.on_tool_add)
self.addtool_entry.returnPressed.connect(self.on_tool_add)
- # self.copytool_btn.clicked.connect(lambda: self.on_tool_copy())
- self.tools_table.itemChanged.connect(self.on_tool_edit)
self.deltool_btn.clicked.connect(self.on_tool_delete)
+
+ self.tipdia_entry.returnPressed.connect(self.on_calculate_tooldia)
+ self.tipangle_entry.returnPressed.connect(self.on_calculate_tooldia)
+ self.cutz_entry.returnPressed.connect(self.on_calculate_tooldia)
+
+ # self.copytool_btn.clicked.connect(lambda: self.on_tool_copy())
+ # self.tools_table.itemChanged.connect(self.on_tool_edit)
+ self.tools_table.currentItemChanged.connect(self.on_row_selection_change)
+
self.generate_paint_button.clicked.connect(self.on_paint_button_click)
self.selectmethod_combo.activated_custom.connect(self.on_radio_selection)
self.order_radio.activated_custom[str].connect(self.on_order_changed)
@@ -489,22 +682,6 @@ class ToolPaint(FlatCAMTool, Gerber):
def install(self, icon=None, separator=None, **kwargs):
FlatCAMTool.install(self, icon, separator, shortcut='ALT+P', **kwargs)
- def on_add_tool_by_key(self):
- tool_add_popup = FCInputDialog(title='%s...' % _("New Tool"),
- text='%s:' % _('Enter a Tool Diameter'),
- min=0.0000, max=99.9999, decimals=4)
- tool_add_popup.setWindowIcon(QtGui.QIcon(self.app.resource_location + '/letter_t_32.png'))
-
- val, ok = tool_add_popup.get_value()
- if ok:
- if float(val) == 0:
- self.app.inform.emit('[WARNING_NOTCL] %s' %
- _("Please enter a tool diameter with non-zero value, in Float format."))
- return
- self.on_tool_add(dia=float(val))
- else:
- self.app.inform.emit('[WARNING_NOTCL] %s...' % _("Adding Tool cancelled"))
-
def run(self, toggle=True):
self.app.report_usage("ToolPaint()")
@@ -532,16 +709,203 @@ class ToolPaint(FlatCAMTool, Gerber):
self.app.ui.notebook.setTabText(2, _("Paint Tool"))
- def reset_usage(self):
- self.obj_name = ""
- self.paint_obj = None
- self.bound_obj = None
+ def on_row_selection_change(self):
+ self.update_ui()
- self.first_click = False
- self.cursor_pos = None
- self.mouse_is_dragging = False
+ def update_ui(self, row=None):
+ self.blockSignals(True)
- self.sel_rect = []
+ if row is None:
+ try:
+ current_row = self.tools_table.currentRow()
+ except Exception:
+ current_row = 0
+ else:
+ current_row = row
+
+ if current_row < 0:
+ current_row = 0
+
+ # populate the form with the data from the tool associated with the row parameter
+ try:
+ item = self.tools_table.item(current_row, 3)
+ if item is not None:
+ tooluid = int(item.text())
+ else:
+ return
+ except Exception as e:
+ log.debug("Tool missing. Add a tool in the Tool Table. %s" % str(e))
+ return
+
+ # update the QLabel that shows for which Tool we have the parameters in the UI form
+ self.tool_data_label.setText(
+ "%s: %s %d" % (_('Parameters for'), _("Tool"), (current_row + 1))
+ )
+
+ try:
+ # set the form with data from the newly selected tool
+ for tooluid_key, tooluid_value in list(self.paint_tools.items()):
+ if int(tooluid_key) == tooluid:
+ for key, value in tooluid_value.items():
+ if key == 'data':
+ form_value_storage = tooluid_value[key]
+ self.storage_to_form(form_value_storage)
+ except Exception as e:
+ log.debug("ToolPaint ---> update_ui() " + str(e))
+
+ self.blockSignals(False)
+
+ def storage_to_form(self, dict_storage):
+ for form_key in self.form_fields:
+ for storage_key in dict_storage:
+ if form_key == storage_key:
+ try:
+ self.form_fields[form_key].set_value(dict_storage[form_key])
+ except Exception:
+ pass
+
+ def form_to_storage(self):
+ if self.tools_table.rowCount() == 0:
+ # there is no tool in tool table so we can't save the GUI elements values to storage
+ return
+
+ self.blockSignals(True)
+
+ widget_changed = self.sender()
+ wdg_objname = widget_changed.objectName()
+ option_changed = self.name2option[wdg_objname]
+
+ row = self.tools_table.currentRow()
+ if row < 0:
+ row = 0
+ tooluid_item = int(self.tools_table.item(row, 3).text())
+
+ for tooluid_key, tooluid_val in self.paint_tools.items():
+ if int(tooluid_key) == tooluid_item:
+ new_option_value = self.form_fields[option_changed].get_value()
+ if option_changed in tooluid_val:
+ tooluid_val[option_changed] = new_option_value
+ if option_changed in tooluid_val['data']:
+ tooluid_val['data'][option_changed] = new_option_value
+
+ self.blockSignals(False)
+
+ def on_apply_param_to_all_clicked(self):
+ if self.tools_table.rowCount() == 0:
+ # there is no tool in tool table so we can't save the GUI elements values to storage
+ log.debug("NonCopperClear.on_apply_param_to_all_clicked() --> no tool in Tools Table, aborting.")
+ return
+
+ self.blockSignals(True)
+
+ row = self.tools_table.currentRow()
+ if row < 0:
+ row = 0
+
+ # this new dict will hold the actual useful data, another dict that is the value of key 'data'
+ temp_tools = {}
+ temp_dia = {}
+ temp_data = {}
+
+ for tooluid_key, tooluid_value in self.paint_tools.items():
+ for key, value in tooluid_value.items():
+ if key == 'data':
+ # update the 'data' section
+ for data_key in tooluid_value[key].keys():
+ for form_key, form_value in self.form_fields.items():
+ if form_key == data_key:
+ temp_data[data_key] = form_value.get_value()
+ # make sure we make a copy of the keys not in the form (we may use 'data' keys that are
+ # updated from self.app.defaults
+ if data_key not in self.form_fields:
+ temp_data[data_key] = value[data_key]
+ temp_dia[key] = deepcopy(temp_data)
+ temp_data.clear()
+
+ elif key == 'solid_geometry':
+ temp_dia[key] = deepcopy(self.tools[tooluid_key]['solid_geometry'])
+ else:
+ temp_dia[key] = deepcopy(value)
+
+ temp_tools[tooluid_key] = deepcopy(temp_dia)
+
+ self.paint_tools.clear()
+ self.paint_tools = deepcopy(temp_tools)
+ temp_tools.clear()
+
+ self.blockSignals(False)
+
+ def on_add_tool_by_key(self):
+ tool_add_popup = FCInputDialog(title='%s...' % _("New Tool"),
+ text='%s:' % _('Enter a Tool Diameter'),
+ min=0.0000, max=99.9999, decimals=4)
+ tool_add_popup.setWindowIcon(QtGui.QIcon(self.app.resource_location + '/letter_t_32.png'))
+
+ val, ok = tool_add_popup.get_value()
+ if ok:
+ if float(val) == 0:
+ self.app.inform.emit('[WARNING_NOTCL] %s' %
+ _("Please enter a tool diameter with non-zero value, in Float format."))
+ return
+ self.on_tool_add(dia=float(val))
+ else:
+ self.app.inform.emit('[WARNING_NOTCL] %s...' % _("Adding Tool cancelled"))
+
+ def on_tooltable_cellwidget_change(self):
+ cw = self.sender()
+ cw_index = self.tools_table.indexAt(cw.pos())
+ cw_row = cw_index.row()
+ cw_col = cw_index.column()
+
+ current_uid = int(self.tools_table.item(cw_row, 3).text())
+
+ # if the sender is in the column with index 2 then we update the tool_type key
+ if cw_col == 2:
+ tt = cw.currentText()
+ typ = 'Iso' if tt == 'V' else "Rough"
+
+ self.paint_tools[current_uid].update({
+ 'type': typ,
+ 'tool_type': tt,
+ })
+
+ def on_tool_type(self, val):
+ if val == 'V':
+ self.addtool_entry_lbl.setDisabled(True)
+ self.addtool_entry.setDisabled(True)
+ self.tipdialabel.show()
+ self.tipdia_entry.show()
+ self.tipanglelabel.show()
+ self.tipangle_entry.show()
+ else:
+ self.addtool_entry_lbl.setDisabled(False)
+ self.addtool_entry.setDisabled(False)
+ self.tipdialabel.hide()
+ self.tipdia_entry.hide()
+ self.tipanglelabel.hide()
+ self.tipangle_entry.hide()
+
+ def on_calculate_tooldia(self):
+ if self.tool_type_radio.get_value() == 'V':
+ tip_dia = float(self.tipdia_entry.get_value())
+ tip_angle = float(self.tipangle_entry.get_value()) / 2.0
+ cut_z = float(self.cutz_entry.get_value())
+ cut_z = -cut_z if cut_z < 0 else cut_z
+
+ # calculated tool diameter so the cut_z parameter is obeyed
+ tool_dia = tip_dia + (2 * cut_z * math.tan(math.radians(tip_angle)))
+
+ # update the default_data so it is used in the ncc_tools dict
+ self.default_data.update({
+ "vtipdia": tip_dia,
+ "vtipangle": (tip_angle * 2),
+ })
+
+ self.addtool_entry.set_value(tool_dia)
+
+ return tool_dia
+ else:
+ return float(self.addtool_entry.get_value())
def on_radio_selection(self):
if self.selectmethod_combo.get_value() == "ref":
@@ -596,6 +960,14 @@ class ToolPaint(FlatCAMTool, Gerber):
self.paintcontour_cb.set_value(self.default_data["paintcontour"])
self.paintoverlap_entry.set_value(self.default_data["paintoverlap"])
+ self.cutz_entry.set_value(self.app.defaults["tools_paintcutz"])
+ self.tool_type_radio.set_value(self.app.defaults["tools_painttool_type"])
+ self.tipdia_entry.set_value(self.app.defaults["tools_painttipdia"])
+ self.tipangle_entry.set_value(self.app.defaults["tools_painttipangle"])
+ self.addtool_entry.set_value(self.app.defaults["tools_paintnewdia"])
+
+ self.on_tool_type(val=self.tool_type_radio.get_value())
+
# make the default object type, "Geometry"
self.type_obj_combo.setCurrentIndex(2)
# updated units
@@ -610,8 +982,8 @@ class ToolPaint(FlatCAMTool, Gerber):
"name": '_paint',
"plot": self.app.defaults["geometry_plot"],
"cutz": float(self.app.defaults["geometry_cutz"]),
- "vtipdia": 0.1,
- "vtipangle": 30,
+ "vtipdia": float(self.tipdia_entry.get_value()),
+ "vtipangle": float(self.tipangle_entry.get_value()),
"travelz": float(self.app.defaults["geometry_travelz"]),
"feedrate": float(self.app.defaults["geometry_feedrate"]),
"feedrate_z": float(self.app.defaults["geometry_feedrate_z"]),
@@ -1077,9 +1449,7 @@ class ToolPaint(FlatCAMTool, Gerber):
try:
self.bound_obj = self.app.collection.get_by_name(self.bound_obj_name)
except Exception as e:
- self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
- (_("Could not retrieve object"),
- self.obj_name))
+ self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), self.obj_name))
return "Could not retrieve object: %s" % self.obj_name
self.paint_poly_ref(obj=self.paint_obj,
@@ -2694,6 +3064,105 @@ class ToolPaint(FlatCAMTool, Gerber):
plot=plot,
run_threaded=run_threaded)
+ def ui_connect(self):
+ self.tools_table.itemChanged.connect(self.on_tool_edit)
+
+ for row in range(self.tools_table.rowCount()):
+ try:
+ self.tools_table.cellWidget(row, 2).currentIndexChanged.connect(self.on_tooltable_cellwidget_change)
+ except AttributeError:
+ pass
+
+ try:
+ self.tools_table.cellWidget(row, 4).currentIndexChanged.connect(self.on_tooltable_cellwidget_change)
+ except AttributeError:
+ pass
+
+ self.tool_type_radio.activated_custom.connect(self.on_tool_type)
+
+ # first disconnect
+ for opt in self.form_fields:
+ current_widget = self.form_fields[opt]
+ if isinstance(current_widget, FCCheckBox):
+ try:
+ current_widget.stateChanged.disconnect()
+ except (TypeError, ValueError):
+ pass
+ if isinstance(current_widget, RadioSet):
+ try:
+ current_widget.activated_custom.disconnect()
+ except (TypeError, ValueError):
+ pass
+ elif isinstance(current_widget, FCDoubleSpinner):
+ try:
+ current_widget.returnPressed.disconnect()
+ except (TypeError, ValueError):
+ pass
+
+ # then reconnect
+ for opt in self.form_fields:
+ current_widget = self.form_fields[opt]
+ if isinstance(current_widget, FCCheckBox):
+ current_widget.stateChanged.connect(self.form_to_storage)
+ if isinstance(current_widget, RadioSet):
+ current_widget.activated_custom.connect(self.form_to_storage)
+ elif isinstance(current_widget, FCDoubleSpinner):
+ current_widget.returnPressed.connect(self.form_to_storage)
+
+ self.ncc_choice_offset_cb.stateChanged.connect(self.on_offset_choice)
+ self.ncc_rest_cb.stateChanged.connect(self.on_rest_machining_check)
+ self.ncc_order_radio.activated_custom[str].connect(self.on_order_changed)
+
+ def ui_disconnect(self):
+ try:
+ # if connected, disconnect the signal from the slot on item_changed as it creates issues
+ self.tools_table.itemChanged.disconnect()
+ except (TypeError, AttributeError):
+ pass
+
+ try:
+ # if connected, disconnect the signal from the slot on item_changed as it creates issues
+ self.tool_type_radio.activated_custom.disconnect()
+ except (TypeError, AttributeError):
+ pass
+
+ for row in range(self.tools_table.rowCount()):
+ for col in [2, 4]:
+ try:
+ self.ui.geo_tools_table.cellWidget(row, col).currentIndexChanged.disconnect()
+ except (TypeError, AttributeError):
+ pass
+
+ for opt in self.form_fields:
+ current_widget = self.form_fields[opt]
+ if isinstance(current_widget, FCCheckBox):
+ try:
+ current_widget.stateChanged.disconnect()
+ except (TypeError, ValueError):
+ pass
+ if isinstance(current_widget, RadioSet):
+ try:
+ current_widget.activated_custom.disconnect()
+ except (TypeError, ValueError):
+ pass
+ elif isinstance(current_widget, FCDoubleSpinner):
+ try:
+ current_widget.returnPressed.disconnect()
+ except (TypeError, ValueError):
+ pass
+
+ def reset_usage(self):
+ self.obj_name = ""
+ self.paint_obj = None
+ self.bound_obj = None
+
+ self.first_click = False
+ self.cursor_pos = None
+ self.mouse_is_dragging = False
+
+ self.sel_rect = []
+
+
@staticmethod
def paint_bounds(geometry):
def bounds_rec(o):
From 82afd3bb6e569cd6d9268618c326d99e2473ab9e Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 15 Jan 2020 17:59:12 +0200
Subject: [PATCH 022/209] - work in Paint Tool GUI functionality
---
README.md | 1 +
flatcamTools/ToolPaint.py | 22 +++++++---------------
2 files changed, 8 insertions(+), 15 deletions(-)
diff --git a/README.md b/README.md
index f91a123c..4a872ab7 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ CAD program, and create G-Code for Isolation routing.
- added new functionality (key shortcut SHIFT+J) to locate the corners of the bounding box (and center) in a selected object
- modified the NCC Tool GUI to prepare for accepting a tool from a tool database
- started to modify the Paint Tool to be similar to NCC Tool and to accept a tool from a database
+- work in Paint Tool GUI functionality
14.01.2020
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 95fc26e7..462aaeef 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -1034,11 +1034,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.tools_table.setContextMenuPolicy(Qt.NoContextMenu)
def build_ui(self):
- try:
- # if connected, disconnect the signal from the slot on item_changed as it creates issues
- self.tools_table.itemChanged.disconnect()
- except (TypeError, AttributeError):
- pass
+ self.ui_disconnect()
# updated units
self.units = self.app.defaults['units'].upper()
@@ -1119,8 +1115,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.tools_table.setMinimumHeight(self.tools_table.getHeight())
self.tools_table.setMaximumHeight(self.tools_table.getHeight())
- # we reactivate the signals after the after the tool adding as we don't need to see the tool been populated
- self.tools_table.itemChanged.connect(self.on_tool_edit)
+ self.ui_connect()
def on_combo_box_type(self):
obj_type = self.box_combo_type.currentIndex()
@@ -1166,21 +1161,19 @@ class ToolPaint(FlatCAMTool, Gerber):
if float('%.*f' % (self.decimals, tool_dia)) in tool_dias:
if muted is None:
- self.app.inform.emit('[WARNING_NOTCL] %s' %
- _("Adding tool cancelled. Tool already in Tool Table."))
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Adding tool cancelled. Tool already in Tool Table."))
self.tools_table.itemChanged.connect(self.on_tool_edit)
return
else:
if muted is None:
- self.app.inform.emit('[success] %s' %
- _("New tool added to Tool Table."))
+ self.app.inform.emit('[success] %s' % _("New tool added to Tool Table."))
self.paint_tools.update({
int(self.tooluid): {
'tooldia': float('%.*f' % (self.decimals, tool_dia)),
'offset': 'Path',
'offset_value': 0.0,
'type': 'Iso',
- 'tool_type': 'V',
+ 'tool_type': self.tool_type_radio.get_value(),
'data': dict(self.default_data),
'solid_geometry': []
}
@@ -3109,9 +3102,8 @@ class ToolPaint(FlatCAMTool, Gerber):
elif isinstance(current_widget, FCDoubleSpinner):
current_widget.returnPressed.connect(self.form_to_storage)
- self.ncc_choice_offset_cb.stateChanged.connect(self.on_offset_choice)
- self.ncc_rest_cb.stateChanged.connect(self.on_rest_machining_check)
- self.ncc_order_radio.activated_custom[str].connect(self.on_order_changed)
+ self.rest_cb.stateChanged.connect(self.on_rest_machining_check)
+ self.order_radio.activated_custom[str].connect(self.on_order_changed)
def ui_disconnect(self):
try:
From 002617c2837113d3752fa08699ef3502150a46df Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 15 Jan 2020 18:14:07 +0200
Subject: [PATCH 023/209] - work in Paint Tool GUI functionality
---
flatcamTools/ToolPaint.py | 83 ++++++++++-----------------------------
1 file changed, 20 insertions(+), 63 deletions(-)
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 462aaeef..dd4e76a5 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -533,22 +533,6 @@ class ToolPaint(FlatCAMTool, Gerber):
# #################################### FINSIHED GUI ###########################
# #############################################################################
- # #############################################################################
- # ###################### Setup CONTEXT MENU ###################################
- # #############################################################################
- self.tools_table.setupContextMenu()
- self.tools_table.addContextMenu(
- _("Add"), self.on_add_tool_by_key, icon=QtGui.QIcon(self.app.resource_location + "/plus16.png")
- )
- self.tools_table.addContextMenu(
- _("Add from DB"), self.on_add_tool_by_key, icon=QtGui.QIcon(self.app.resource_location + "/plus16.png")
- )
- self.tools_table.addContextMenu(
- _("Delete"), lambda:
- self.on_tool_delete(rows_to_delete=None, all_tools=None),
- icon=QtGui.QIcon(self.app.resource_location + "/delete32.png")
- )
-
# #############################################################################
# ########################## VARIABLES ########################################
# #############################################################################
@@ -586,40 +570,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.poly_dict = dict()
# store here the default data for Geometry Data
- self.default_data = {}
- self.default_data.update({
- "name": '_paint',
- "plot": self.app.defaults["geometry_plot"],
- "cutz": self.app.defaults["geometry_cutz"],
- "vtipdia": float(self.tipdia_entry.get_value()),
- "vtipangle": float(self.tipangle_entry.get_value()),
- "travelz": self.app.defaults["geometry_travelz"],
- "feedrate": self.app.defaults["geometry_feedrate"],
- "feedrate_z": self.app.defaults["geometry_feedrate_z"],
- "feedrate_rapid": self.app.defaults["geometry_feedrate_rapid"],
- "dwell": self.app.defaults["geometry_dwell"],
- "dwelltime": self.app.defaults["geometry_dwelltime"],
- "multidepth": self.app.defaults["geometry_multidepth"],
- "ppname_g": self.app.defaults["geometry_ppname_g"],
- "depthperpass": self.app.defaults["geometry_depthperpass"],
- "extracut": self.app.defaults["geometry_extracut"],
- "extracut_length": self.app.defaults["geometry_extracut_length"],
- "toolchange": self.app.defaults["geometry_toolchange"],
- "toolchangez": self.app.defaults["geometry_toolchangez"],
- "endz": self.app.defaults["geometry_endz"],
- "spindlespeed": self.app.defaults["geometry_spindlespeed"],
- "toolchangexy": self.app.defaults["geometry_toolchangexy"],
- "startz": self.app.defaults["geometry_startz"],
-
- "tooldia": self.app.defaults["tools_painttooldia"],
- "paintmargin": self.app.defaults["tools_paintmargin"],
- "paintmethod": self.app.defaults["tools_paintmethod"],
- "selectmethod": self.app.defaults["tools_selectmethod"],
- "pathconnect": self.app.defaults["tools_pathconnect"],
- "paintcontour": self.app.defaults["tools_paintcontour"],
- "paintoverlap": self.app.defaults["tools_paintoverlap"],
- "paintrest": self.app.defaults["tools_paintrest"],
- })
+ self.default_data = dict()
self.tool_type_item_options = ["C1", "C2", "C3", "C4", "B", "V"]
@@ -668,11 +619,16 @@ class ToolPaint(FlatCAMTool, Gerber):
# #############################################################################
self.tools_table.setupContextMenu()
self.tools_table.addContextMenu(
- "Add", self.on_add_tool_by_key, icon=QtGui.QIcon(self.app.resource_location + "/plus16.png"))
+ _("Add"), self.on_add_tool_by_key, icon=QtGui.QIcon(self.app.resource_location + "/plus16.png")
+ )
self.tools_table.addContextMenu(
- "Delete", lambda:
- self.on_tool_delete(rows_to_delete=None, all=None),
- icon=QtGui.QIcon(self.app.resource_location + "/delete32.png"))
+ _("Add from DB"), self.on_add_tool_by_key, icon=QtGui.QIcon(self.app.resource_location + "/plus16.png")
+ )
+ self.tools_table.addContextMenu(
+ _("Delete"), lambda:
+ self.on_tool_delete(rows_to_delete=None, all_tools=None),
+ icon=QtGui.QIcon(self.app.resource_location + "/delete32.png")
+ )
def on_type_obj_index_changed(self, index):
obj_type = self.type_obj_combo.currentIndex()
@@ -953,12 +909,12 @@ class ToolPaint(FlatCAMTool, Gerber):
# ## Init the GUI interface
self.order_radio.set_value(self.app.defaults["tools_paintorder"])
- self.paintmargin_entry.set_value(self.default_data["paintmargin"])
- self.paintmethod_combo.set_value(self.default_data["paintmethod"])
- self.selectmethod_combo.set_value(self.default_data["selectmethod"])
- self.pathconnect_cb.set_value(self.default_data["pathconnect"])
- self.paintcontour_cb.set_value(self.default_data["paintcontour"])
- self.paintoverlap_entry.set_value(self.default_data["paintoverlap"])
+ self.paintmargin_entry.set_value(self.app.defaults["tools_paintmargin"])
+ self.paintmethod_combo.set_value(self.app.defaults["tools_paintmethod"])
+ self.selectmethod_combo.set_value(self.app.defaults["tools_selectmethod"])
+ self.pathconnect_cb.set_value(self.app.defaults["tools_pathconnect"])
+ self.paintcontour_cb.set_value(self.app.defaults["tools_paintcontour"])
+ self.paintoverlap_entry.set_value(self.app.defaults["tools_paintoverlap"])
self.cutz_entry.set_value(self.app.defaults["tools_paintcutz"])
self.tool_type_radio.set_value(self.app.defaults["tools_painttool_type"])
@@ -981,7 +937,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.default_data.update({
"name": '_paint',
"plot": self.app.defaults["geometry_plot"],
- "cutz": float(self.app.defaults["geometry_cutz"]),
+ "cutz": float(self.cutz_entry.get_value()),
"vtipdia": float(self.tipdia_entry.get_value()),
"vtipangle": float(self.tipangle_entry.get_value()),
"travelz": float(self.app.defaults["geometry_travelz"]),
@@ -1003,12 +959,13 @@ class ToolPaint(FlatCAMTool, Gerber):
"startz": self.app.defaults["geometry_startz"],
"tooldia": self.app.defaults["tools_painttooldia"],
- "paintmargin": float(self.app.defaults["tools_paintmargin"]),
+ "paintmargin": self.app.defaults["tools_paintmargin"],
"paintmethod": self.app.defaults["tools_paintmethod"],
"selectmethod": self.app.defaults["tools_selectmethod"],
"pathconnect": self.app.defaults["tools_pathconnect"],
"paintcontour": self.app.defaults["tools_paintcontour"],
- "paintoverlap": self.app.defaults["tools_paintoverlap"]
+ "paintoverlap": self.app.defaults["tools_paintoverlap"],
+ "paintrest": self.app.defaults["tools_paintrest"],
})
try:
From 3c569fdf6c72eb3c1161596cab6de03c974254d9 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 16 Jan 2020 02:07:00 +0200
Subject: [PATCH 024/209] - updated/optimized the GUI in Preferences for Paint
Tool and for NCC Tool - work in Paint Tool to bring it up to date with NCC
Tool
---
FlatCAMApp.py | 15 +-
README.md | 5 +
flatcamEditors/FlatCAMGeoEditor.py | 2 +-
flatcamGUI/PreferencesUI.py | 290 +++++++++++++++++++++--------
flatcamTools/ToolNonCopperClear.py | 17 +-
flatcamTools/ToolPaint.py | 51 ++---
6 files changed, 272 insertions(+), 108 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index e073978d..258c0852 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -776,11 +776,11 @@ class App(QtCore.QObject):
"tools_nccref": 'itself',
"tools_ncc_plotting": 'normal',
"tools_nccmilling_type": 'cl',
- "tools_ncctool_type": 'V',
+ "tools_ncctool_type": 'C1',
"tools_ncccutz": -0.05,
"tools_ncctipdia": 0.1,
"tools_ncctipangle": 30,
- "tools_nccnewdia": 1.0,
+ "tools_nccnewdia": 0.1,
# Cutout Tool
"tools_cutouttooldia": 2.4,
@@ -804,11 +804,11 @@ class App(QtCore.QObject):
"tools_paintcontour": True,
"tools_paint_plotting": 'normal',
"tools_paintrest": False,
- "tools_painttool_type": 'V',
+ "tools_painttool_type": 'C1',
"tools_paintcutz": -0.05,
"tools_painttipdia": 0.1,
"tools_painttipangle": 30,
- "tools_paintnewdia": 1.0,
+ "tools_paintnewdia": 0.1,
# 2-Sided Tool
"tools_2sided_mirror_axis": "X",
@@ -1453,6 +1453,13 @@ class App(QtCore.QObject):
"tools_paintcontour": self.ui.tools_defaults_form.tools_paint_group.contour_cb,
"tools_paint_plotting": self.ui.tools_defaults_form.tools_paint_group.paint_plotting_radio,
+ "tools_paintrest": self.ui.tools_defaults_form.tools_paint_group.rest_cb,
+ "tools_painttool_type": self.ui.tools_defaults_form.tools_paint_group.tool_type_radio,
+ "tools_paintcutz": self.ui.tools_defaults_form.tools_paint_group.cutz_entry,
+ "tools_painttipdia": self.ui.tools_defaults_form.tools_paint_group.tipdia_entry,
+ "tools_painttipangle": self.ui.tools_defaults_form.tools_paint_group.tipangle_entry,
+ "tools_paintnewdia": self.ui.tools_defaults_form.tools_paint_group.newdia_entry,
+
# 2-sided Tool
"tools_2sided_mirror_axis": self.ui.tools_defaults_form.tools_2sided_group.mirror_axis_radio,
"tools_2sided_axis_loc": self.ui.tools_defaults_form.tools_2sided_group.axis_location_radio,
diff --git a/README.md b/README.md
index 4a872ab7..a2f7d29a 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+16.01.2020
+
+- updated/optimized the GUI in Preferences for Paint Tool and for NCC Tool
+- work in Paint Tool to bring it up to date with NCC Tool
+
15.01.2020
- added key shortcuts and toolbar icons for the new tools: Align Object Tool (ALT+A) and Extract Drills (ALT+I)
diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py
index 20ccb225..5b0b95b9 100644
--- a/flatcamEditors/FlatCAMGeoEditor.py
+++ b/flatcamEditors/FlatCAMGeoEditor.py
@@ -451,7 +451,7 @@ class PaintOptionsTool(FlatCAMTool):
grid.addWidget(self.painttooldia_entry, 0, 1)
# Overlap
- ovlabel = QtWidgets.QLabel('%s:' % _('Overlap Rate'))
+ ovlabel = QtWidgets.QLabel('%s:' % _('Overlap'))
ovlabel.setToolTip(
_("How much (percentage) of the tool width to overlap each tool pass.\n"
"Adjust the value starting with lower values\n"
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index 41ae3f32..ca736455 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -163,6 +163,7 @@ class ToolsPreferencesUI(QtWidgets.QWidget):
self.tools_ncc_group = ToolsNCCPrefGroupUI(decimals=self.decimals)
self.tools_ncc_group.setMinimumWidth(220)
+
self.tools_paint_group = ToolsPaintPrefGroupUI(decimals=self.decimals)
self.tools_paint_group.setMinimumWidth(220)
@@ -192,26 +193,29 @@ class ToolsPreferencesUI(QtWidgets.QWidget):
self.vlay = QtWidgets.QVBoxLayout()
self.vlay.addWidget(self.tools_ncc_group)
- self.vlay.addWidget(self.tools_paint_group)
+ self.vlay.addWidget(self.tools_cutout_group)
self.vlay1 = QtWidgets.QVBoxLayout()
- self.vlay1.addWidget(self.tools_cutout_group)
- self.vlay1.addWidget(self.tools_transform_group)
- self.vlay1.addWidget(self.tools_2sided_group)
+ self.vlay1.addWidget(self.tools_paint_group)
+ self.vlay1.addWidget(self.tools_panelize_group)
self.vlay2 = QtWidgets.QVBoxLayout()
- self.vlay2.addWidget(self.tools_panelize_group)
+ self.vlay2.addWidget(self.tools_transform_group)
+ self.vlay2.addWidget(self.tools_2sided_group)
self.vlay2.addWidget(self.tools_sub_group)
- self.vlay2.addWidget(self.tools_film_group)
self.vlay3 = QtWidgets.QVBoxLayout()
- self.vlay3.addWidget(self.tools_solderpaste_group)
+ self.vlay3.addWidget(self.tools_film_group)
self.vlay3.addWidget(self.tools_calculators_group)
+ self.vlay4 = QtWidgets.QVBoxLayout()
+ self.vlay4.addWidget(self.tools_solderpaste_group)
+
self.layout.addLayout(self.vlay)
self.layout.addLayout(self.vlay1)
self.layout.addLayout(self.vlay2)
self.layout.addLayout(self.vlay3)
+ self.layout.addLayout(self.vlay4)
self.layout.addStretch()
@@ -3562,8 +3566,8 @@ class ExcellonEditorPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.sel_limit_label, 0, 0)
grid0.addWidget(self.sel_limit_entry, 0, 1)
- # New tool diameter
- self.addtool_entry_lbl = QtWidgets.QLabel('%s:' % _('New Tool Dia'))
+ # New Diameter
+ self.addtool_entry_lbl = QtWidgets.QLabel('%s:' % _('New Dia'))
self.addtool_entry_lbl.setToolTip(
_("Diameter for the new tool")
)
@@ -5012,7 +5016,7 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
grid0 = QtWidgets.QGridLayout()
self.layout.addLayout(grid0)
- ncctdlabel = QtWidgets.QLabel('%s:' % _('Tools dia'))
+ ncctdlabel = QtWidgets.QLabel('%s:' % _('Tools Dia'))
ncctdlabel.setToolTip(
_("Diameters of the cutting tools, separated by comma.\n"
"The value of the diameter has to use the dot decimals separator.\n"
@@ -5088,9 +5092,12 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.cutz_entry, 4, 1)
# New Diameter
- self.newdialabel = QtWidgets.QLabel('%s:' % _('New Tool Dia'))
+ self.newdialabel = QtWidgets.QLabel('%s:' % _('New Dia'))
self.newdialabel.setToolTip(
- _("The new tool diameter (cut width) to add in the tool table."))
+ _("Diameter for the new tool to add in the Tool Table.\n"
+ "If the tool is V-shape type then this value is automatically\n"
+ "calculated from the other parameters.")
+ )
self.newdia_entry = FCDoubleSpinner()
self.newdia_entry.set_precision(self.decimals)
self.newdia_entry.set_range(0.0001, 9999.9999)
@@ -5099,6 +5106,11 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.newdialabel, 5, 0)
grid0.addWidget(self.newdia_entry, 5, 1)
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 6, 0, 1, 2)
+
# Milling Type Radio Button
self.milling_type_label = QtWidgets.QLabel('%s:' % _('Milling Type'))
self.milling_type_label.setToolTip(
@@ -5115,8 +5127,8 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
"- conventional / useful when there is no backlash compensation")
)
- grid0.addWidget(self.milling_type_label, 6, 0)
- grid0.addWidget(self.milling_type_radio, 6, 1)
+ grid0.addWidget(self.milling_type_label, 7, 0)
+ grid0.addWidget(self.milling_type_radio, 7, 1)
# Tool order Radio Button
self.ncc_order_label = QtWidgets.QLabel('%s:' % _('Tool order'))
@@ -5136,11 +5148,16 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
"'Reverse' --> menas that the tools will ordered from big to small\n\n"
"WARNING: using rest machining will automatically set the order\n"
"in reverse and disable this control."))
- grid0.addWidget(self.ncc_order_label, 7, 0)
- grid0.addWidget(self.ncc_order_radio, 7, 1)
+ grid0.addWidget(self.ncc_order_label, 8, 0)
+ grid0.addWidget(self.ncc_order_radio, 8, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 9, 0, 1, 2)
# Overlap Entry
- nccoverlabel = QtWidgets.QLabel('%s:' % _('Overlap Rate'))
+ nccoverlabel = QtWidgets.QLabel('%s:' % _('Overlap'))
nccoverlabel.setToolTip(
_("How much (percentage) of the tool width to overlap each tool pass.\n"
"Adjust the value starting with lower values\n"
@@ -5155,8 +5172,9 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
self.ncc_overlap_entry.setWrapping(True)
self.ncc_overlap_entry.setRange(0.0000, 99.9999)
self.ncc_overlap_entry.setSingleStep(0.1)
- grid0.addWidget(nccoverlabel, 8, 0)
- grid0.addWidget(self.ncc_overlap_entry, 8, 1)
+
+ grid0.addWidget(nccoverlabel, 10, 0)
+ grid0.addWidget(self.ncc_overlap_entry, 10, 1)
# Margin entry
nccmarginlabel = QtWidgets.QLabel('%s:' % _('Margin'))
@@ -5168,8 +5186,8 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
self.ncc_margin_entry.set_range(-10000, 10000)
self.ncc_margin_entry.setSingleStep(0.1)
- grid0.addWidget(nccmarginlabel, 9, 0)
- grid0.addWidget(self.ncc_margin_entry, 9, 1)
+ grid0.addWidget(nccmarginlabel, 11, 0)
+ grid0.addWidget(self.ncc_margin_entry, 11, 1)
# Method
methodlabel = QtWidgets.QLabel('%s:' % _('Method'))
@@ -5186,8 +5204,8 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
{"label": _("Straight lines"), "value": "lines"}
], orientation='vertical', stretch=False)
- grid0.addWidget(methodlabel, 10, 0)
- grid0.addWidget(self.ncc_method_radio, 10, 1)
+ grid0.addWidget(methodlabel, 12, 0)
+ grid0.addWidget(self.ncc_method_radio, 12, 1)
# Connect lines
self.ncc_connect_cb = FCCheckBox('%s' % _("Connect"))
@@ -5196,7 +5214,7 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
"segments to minimize tool lifts.")
)
- grid0.addWidget(self.ncc_connect_cb, 11, 0, 1, 2)
+ grid0.addWidget(self.ncc_connect_cb, 13, 0)
# Contour Checkbox
self.ncc_contour_cb = FCCheckBox('%s' % _("Contour"))
@@ -5205,21 +5223,7 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
"to trim rough edges.")
)
- grid0.addWidget(self.ncc_contour_cb, 12, 0, 1, 2)
-
- # Rest machining CheckBox
- self.ncc_rest_cb = FCCheckBox('%s' % _("Rest Machining"))
- self.ncc_rest_cb.setToolTip(
- _("If checked, use 'rest machining'.\n"
- "Basically it will clear copper outside PCB features,\n"
- "using the biggest tool and continue with the next tools,\n"
- "from bigger to smaller, to clear areas of copper that\n"
- "could not be cleared by previous tool, until there is\n"
- "no more copper to clear or there are no more tools.\n"
- "If not checked, use the standard algorithm.")
- )
-
- grid0.addWidget(self.ncc_rest_cb, 13, 0, 1, 2)
+ grid0.addWidget(self.ncc_contour_cb, 13, 1)
# ## NCC Offset choice
self.ncc_choice_offset_cb = FCCheckBox('%s' % _("Offset"))
@@ -5249,10 +5253,31 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.ncc_offset_label, 15, 0)
grid0.addWidget(self.ncc_offset_spinner, 15, 1)
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 16, 0, 1, 2)
+
+ # Rest machining CheckBox
+ self.ncc_rest_cb = FCCheckBox('%s' % _("Rest Machining"))
+ self.ncc_rest_cb.setToolTip(
+ _("If checked, use 'rest machining'.\n"
+ "Basically it will clear copper outside PCB features,\n"
+ "using the biggest tool and continue with the next tools,\n"
+ "from bigger to smaller, to clear areas of copper that\n"
+ "could not be cleared by previous tool, until there is\n"
+ "no more copper to clear or there are no more tools.\n"
+ "If not checked, use the standard algorithm.")
+ )
+
+ grid0.addWidget(self.ncc_rest_cb, 17, 0, 1, 2)
+
# ## Reference
self.reference_radio = RadioSet([{'label': _('Itself'), 'value': 'itself'},
- {"label": _("Area"), "value": "area"},
- {'label': _('Ref'), 'value': 'box'}])
+ {"label": _("Area Selection"), "value": "area"},
+ {'label': _('Reference Object'), 'value': 'box'}],
+ orientation='vertical',
+ stretch=None)
reference_label = QtWidgets.QLabel('%s:' % _("Reference"))
reference_label.setToolTip(
_("- 'Itself' - the non copper clearing extent\n"
@@ -5263,8 +5288,13 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
"specified by another object.")
)
- grid0.addWidget(reference_label, 16, 0)
- grid0.addWidget(self.reference_radio, 16, 1)
+ grid0.addWidget(reference_label, 18, 0)
+ grid0.addWidget(self.reference_radio, 18, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 19, 0, 1, 2)
# ## Plotting type
self.ncc_plotting_radio = RadioSet([{'label': _('Normal'), 'value': 'normal'},
@@ -5274,8 +5304,8 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
_("- 'Normal' - normal plotting, done at the end of the NCC job\n"
"- 'Progressive' - after each shape is generated it will be plotted.")
)
- grid0.addWidget(plotting_label, 17, 0)
- grid0.addWidget(self.ncc_plotting_radio, 17, 1)
+ grid0.addWidget(plotting_label, 20, 0)
+ grid0.addWidget(self.ncc_plotting_radio, 20, 1)
self.layout.addStretch()
@@ -5520,10 +5550,12 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
self.layout.addWidget(self.paint_label)
grid0 = QtWidgets.QGridLayout()
+ grid0.setColumnStretch(0, 0)
+ grid0.setColumnStretch(1, 1)
self.layout.addLayout(grid0)
# Tool dia
- ptdlabel = QtWidgets.QLabel('%s:' % _('Tool dia'))
+ ptdlabel = QtWidgets.QLabel('%s:' % _('Tools Dia'))
ptdlabel.setToolTip(
_("Diameters of the cutting tools, separated by comma.\n"
"The value of the diameter has to use the dot decimals separator.\n"
@@ -5536,7 +5568,88 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.painttooldia_entry, 0, 1)
- self.paint_order_label = QtWidgets.QLabel('%s:' % _('Tool order'))
+ # Tool Type Radio Button
+ self.tool_type_label = QtWidgets.QLabel('%s:' % _('Tool Type'))
+ self.tool_type_label.setToolTip(
+ _("Default tool type:\n"
+ "- 'V-shape'\n"
+ "- Circular")
+ )
+
+ self.tool_type_radio = RadioSet([{'label': _('V-shape'), 'value': 'V'},
+ {'label': _('Circular'), 'value': 'C1'}])
+
+ self.tool_type_radio.setObjectName(_("Tool Type"))
+
+ grid0.addWidget(self.tool_type_label, 1, 0)
+ grid0.addWidget(self.tool_type_radio, 1, 1)
+
+ # Tip Dia
+ self.tipdialabel = QtWidgets.QLabel('%s:' % _('V-Tip Dia'))
+ self.tipdialabel.setToolTip(
+ _("The tip diameter for V-Shape Tool"))
+ self.tipdia_entry = FCDoubleSpinner()
+ self.tipdia_entry.set_precision(self.decimals)
+ self.tipdia_entry.set_range(0.0000, 9999.9999)
+ self.tipdia_entry.setSingleStep(0.1)
+ self.tipdia_entry.setObjectName(_("V-Tip Dia"))
+
+ grid0.addWidget(self.tipdialabel, 2, 0)
+ grid0.addWidget(self.tipdia_entry, 2, 1)
+
+ # Tip Angle
+ self.tipanglelabel = QtWidgets.QLabel('%s:' % _('V-Tip Angle'))
+ self.tipanglelabel.setToolTip(
+ _("The tip angle for V-Shape Tool.\n"
+ "In degree."))
+ self.tipangle_entry = FCDoubleSpinner()
+ self.tipangle_entry.set_precision(self.decimals)
+ self.tipangle_entry.set_range(0.0000, 180.0000)
+ self.tipangle_entry.setSingleStep(5)
+ self.tipangle_entry.setObjectName(_("V-Tip Angle"))
+
+ grid0.addWidget(self.tipanglelabel, 3, 0)
+ grid0.addWidget(self.tipangle_entry, 3, 1)
+
+ # Cut Z entry
+ cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
+ cutzlabel.setToolTip(
+ _("Depth of cut into material. Negative value.\n"
+ "In FlatCAM units.")
+ )
+ self.cutz_entry = FCDoubleSpinner()
+ self.cutz_entry.set_precision(self.decimals)
+ self.cutz_entry.set_range(-99999.9999, 0.0000)
+ self.cutz_entry.setObjectName(_("Cut Z"))
+
+ self.cutz_entry.setToolTip(
+ _("Depth of cut into material. Negative value.\n"
+ "In FlatCAM units.")
+ )
+ grid0.addWidget(cutzlabel, 4, 0)
+ grid0.addWidget(self.cutz_entry, 4, 1)
+
+ # ### Tool Diameter ####
+ self.newdialabel = QtWidgets.QLabel('%s:' % _('New Dia'))
+ self.newdialabel.setToolTip(
+ _("Diameter for the new tool to add in the Tool Table.\n"
+ "If the tool is V-shape type then this value is automatically\n"
+ "calculated from the other parameters.")
+ )
+ self.newdia_entry = FCDoubleSpinner()
+ self.newdia_entry.set_precision(self.decimals)
+ self.newdia_entry.set_range(0.000, 9999.9999)
+ self.newdia_entry.setObjectName(_("Tool Dia"))
+
+ grid0.addWidget(self.newdialabel, 5, 0)
+ grid0.addWidget(self.newdia_entry, 5, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 6, 0, 1, 2)
+
+ self.paint_order_label = QtWidgets.QLabel('%s:' % _('Tool order'))
self.paint_order_label.setToolTip(_("This set the way that the tools in the tools table are used.\n"
"'No' --> means that the used order is the one in the tool table\n"
"'Forward' --> means that the tools will be ordered from small to big\n"
@@ -5547,17 +5660,17 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
self.paint_order_radio = RadioSet([{'label': _('No'), 'value': 'no'},
{'label': _('Forward'), 'value': 'fwd'},
{'label': _('Reverse'), 'value': 'rev'}])
- self.paint_order_radio.setToolTip(_("This set the way that the tools in the tools table are used.\n"
- "'No' --> means that the used order is the one in the tool table\n"
- "'Forward' --> means that the tools will be ordered from small to big\n"
- "'Reverse' --> menas that the tools will ordered from big to small\n\n"
- "WARNING: using rest machining will automatically set the order\n"
- "in reverse and disable this control."))
- grid0.addWidget(self.paint_order_label, 1, 0)
- grid0.addWidget(self.paint_order_radio, 1, 1)
+
+ grid0.addWidget(self.paint_order_label, 7, 0)
+ grid0.addWidget(self.paint_order_radio, 7, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 8, 0, 1, 2)
# Overlap
- ovlabel = QtWidgets.QLabel('%s:' % _('Overlap Rate'))
+ ovlabel = QtWidgets.QLabel('%s:' % _('Overlap'))
ovlabel.setToolTip(
_("How much (percentage) of the tool width to overlap each tool pass.\n"
"Adjust the value starting with lower values\n"
@@ -5573,8 +5686,8 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
self.paintoverlap_entry.setRange(0.0000, 99.9999)
self.paintoverlap_entry.setSingleStep(0.1)
- grid0.addWidget(ovlabel, 2, 0)
- grid0.addWidget(self.paintoverlap_entry, 2, 1)
+ grid0.addWidget(ovlabel, 9, 0)
+ grid0.addWidget(self.paintoverlap_entry, 9, 1)
# Margin
marginlabel = QtWidgets.QLabel('%s:' % _('Margin'))
@@ -5583,13 +5696,13 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
"the edges of the polygon to\n"
"be painted.")
)
- grid0.addWidget(marginlabel, 3, 0)
self.paintmargin_entry = FCDoubleSpinner()
self.paintmargin_entry.set_range(-9999.9999, 9999.9999)
self.paintmargin_entry.set_precision(self.decimals)
self.paintmargin_entry.setSingleStep(0.1)
- grid0.addWidget(self.paintmargin_entry, 3, 1)
+ grid0.addWidget(marginlabel, 10, 0)
+ grid0.addWidget(self.paintmargin_entry, 10, 1)
# Method
methodlabel = QtWidgets.QLabel('%s:' % _('Method'))
@@ -5599,13 +5712,15 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
"Seed-based: Outwards from seed.
"
"Line-based: Parallel lines.")
)
- grid0.addWidget(methodlabel, 4, 0)
+
self.paintmethod_combo = RadioSet([
{"label": _("Standard"), "value": "standard"},
{"label": _("Seed-based"), "value": "seed"},
{"label": _("Straight lines"), "value": "lines"}
], orientation='vertical', stretch=False)
- grid0.addWidget(self.paintmethod_combo, 4, 1)
+
+ grid0.addWidget(methodlabel, 11, 0)
+ grid0.addWidget(self.paintmethod_combo, 11, 1)
# Connect lines
self.pathconnect_cb = FCCheckBox('%s' % _("Connect"))
@@ -5613,7 +5728,7 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
_("Draw lines between resulting\n"
"segments to minimize tool lifts.")
)
- grid0.addWidget(self.pathconnect_cb, 5, 0, 1, 2)
+ grid0.addWidget(self.pathconnect_cb, 12, 0)
# Paint contour
self.contour_cb = FCCheckBox('%s' % _("Contour"))
@@ -5621,7 +5736,25 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
_("Cut around the perimeter of the polygon\n"
"to trim rough edges.")
)
- grid0.addWidget(self.contour_cb, 6, 0, 1, 2)
+ grid0.addWidget(self.contour_cb, 12, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 13, 0, 1, 2)
+
+ self.rest_cb = FCCheckBox('%s' % _("Rest Machining"))
+ self.rest_cb.setObjectName(_("Rest Machining"))
+ self.rest_cb.setToolTip(
+ _("If checked, use 'rest machining'.\n"
+ "Basically it will clear copper outside PCB features,\n"
+ "using the biggest tool and continue with the next tools,\n"
+ "from bigger to smaller, to clear areas of copper that\n"
+ "could not be cleared by previous tool, until there is\n"
+ "no more copper to clear or there are no more tools.\n\n"
+ "If not checked, use the standard algorithm.")
+ )
+ grid0.addWidget(self.rest_cb, 14, 0, 1, 2)
# Polygon selection
selectlabel = QtWidgets.QLabel('%s:' % _('Selection'))
@@ -5634,14 +5767,23 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
"- 'Reference Object' - will do non copper clearing within the area\n"
"specified by another object.")
)
- self.selectmethod_combo = RadioSet([
- {"label": _("Sel"), "value": "single"},
- {"label": _("Area"), "value": "area"},
- {"label": _("All"), "value": "all"},
- {"label": _("Ref"), "value": "ref"}
- ])
- grid0.addWidget(selectlabel, 7, 0)
- grid0.addWidget(self.selectmethod_combo, 7, 1)
+ self.selectmethod_combo = RadioSet(
+ [
+ {"label": _("Polygon Selection"), "value": "single"},
+ {"label": _("Area Selection"), "value": "area"},
+ {"label": _("All Polygons"), "value": "all"},
+ {"label": _("Reference Object"), "value": "ref"}
+ ],
+ orientation='vertical',
+ stretch=None
+ )
+ grid0.addWidget(selectlabel, 15, 0)
+ grid0.addWidget(self.selectmethod_combo, 15, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 16, 0, 1, 2)
# ## Plotting type
self.paint_plotting_radio = RadioSet([{'label': _('Normal'), 'value': 'normal'},
@@ -5651,8 +5793,8 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
_("- 'Normal' - normal plotting, done at the end of the Paint job\n"
"- 'Progressive' - after each shape is generated it will be plotted.")
)
- grid0.addWidget(plotting_label, 8, 0)
- grid0.addWidget(self.paint_plotting_radio, 8, 1)
+ grid0.addWidget(plotting_label, 17, 0)
+ grid0.addWidget(self.paint_plotting_radio, 17, 1)
self.layout.addStretch()
diff --git a/flatcamTools/ToolNonCopperClear.py b/flatcamTools/ToolNonCopperClear.py
index 5b2e8b1d..1b0896dc 100644
--- a/flatcamTools/ToolNonCopperClear.py
+++ b/flatcamTools/ToolNonCopperClear.py
@@ -352,7 +352,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.grid3.addWidget(self.tool_data_label, 12, 0, 1, 2)
# Overlap Entry
- nccoverlabel = QtWidgets.QLabel('%s:' % _('Overlap Rate'))
+ nccoverlabel = QtWidgets.QLabel('%s:' % _('Overlap'))
nccoverlabel.setToolTip(
_("How much (percentage) of the tool width to overlap each tool pass.\n"
"Adjust the value starting with lower values\n"
@@ -367,7 +367,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.ncc_overlap_entry.setWrapping(True)
self.ncc_overlap_entry.setRange(0.000, 99.9999)
self.ncc_overlap_entry.setSingleStep(0.1)
- self.ncc_overlap_entry.setObjectName(_("Overlap Rate"))
+ self.ncc_overlap_entry.setObjectName(_("Overlap"))
self.grid3.addWidget(nccoverlabel, 13, 0)
self.grid3.addWidget(self.ncc_overlap_entry, 13, 1)
@@ -653,7 +653,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
}
self.name2option = {
- _('Overlap Rate'): "nccoverlap",
+ _('Overlap'): "nccoverlap",
_('Margin'): "nccmargin",
_('Method'): "nccmethod",
_("Connect"): "nccconnect",
@@ -663,6 +663,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
_('Milling Type'): "milling_type",
}
+ self.old_tool_dia = None
+
# #############################################################################
# ############################ SIGNALS ########################################
# #############################################################################
@@ -901,6 +903,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.tipangle_entry.set_value(self.app.defaults["tools_ncctipangle"])
self.addtool_entry.set_value(self.app.defaults["tools_nccnewdia"])
+ self.old_tool_dia = self.app.defaults["tools_nccnewdia"]
+
self.on_tool_type(val=self.tool_type_radio.get_value())
# init the working variables
@@ -1238,6 +1242,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.tipdia_entry.show()
self.tipanglelabel.show()
self.tipangle_entry.show()
+
+ self.on_calculate_tooldia()
else:
self.addtool_entry_lbl.setDisabled(False)
self.addtool_entry.setDisabled(False)
@@ -1246,6 +1252,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.tipanglelabel.hide()
self.tipangle_entry.hide()
+ self.addtool_entry.set_value(self.old_tool_dia)
+
def on_calculate_tooldia(self):
if self.tool_type_radio.get_value() == 'V':
tip_dia = float(self.tipdia_entry.get_value())
@@ -1332,7 +1340,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
})
self.blockSignals(False)
-
self.build_ui()
def on_tool_edit(self):
@@ -1393,7 +1400,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
deleted_tools_list = []
if all_tools:
- self.paint_tools.clear()
+ self.ncc_tools.clear()
self.blockSignals(False)
self.build_ui()
return
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index dd4e76a5..18f1f3a9 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -329,7 +329,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.tools_box.addLayout(grid4)
# Overlap
- ovlabel = QtWidgets.QLabel('%s:' % _('Overlap Rate'))
+ ovlabel = QtWidgets.QLabel('%s:' % _('Overlap'))
ovlabel.setToolTip(
_("How much (percentage) of the tool width to overlap each tool pass.\n"
"Adjust the value starting with lower values\n"
@@ -344,7 +344,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.paintoverlap_entry.setWrapping(True)
self.paintoverlap_entry.setRange(0.0000, 99.9999)
self.paintoverlap_entry.setSingleStep(0.1)
- self.paintoverlap_entry.setObjectName(_("Overlap Rate"))
+ self.paintoverlap_entry.setObjectName(_("Overlap"))
grid4.addWidget(ovlabel, 1, 0)
grid4.addWidget(self.paintoverlap_entry, 1, 1)
@@ -583,13 +583,15 @@ class ToolPaint(FlatCAMTool, Gerber):
}
self.name2option = {
- _('Overlap Rate'): "paintoverlap",
+ _('Overlap'): "paintoverlap",
_('Margin'): "paintmargin",
_('Method'): "paintmethod",
_("Connect"): "pathconnect",
_("Contour"): "paintcontour",
}
+ self.old_tool_dia = None
+
# #############################################################################
# ################################# Signals ###################################
# #############################################################################
@@ -833,6 +835,8 @@ class ToolPaint(FlatCAMTool, Gerber):
self.tipdia_entry.show()
self.tipanglelabel.show()
self.tipangle_entry.show()
+
+ self.on_calculate_tooldia()
else:
self.addtool_entry_lbl.setDisabled(False)
self.addtool_entry.setDisabled(False)
@@ -841,6 +845,8 @@ class ToolPaint(FlatCAMTool, Gerber):
self.tipanglelabel.hide()
self.tipangle_entry.hide()
+ self.addtool_entry.set_value(self.old_tool_dia)
+
def on_calculate_tooldia(self):
if self.tool_type_radio.get_value() == 'V':
tip_dia = float(self.tipdia_entry.get_value())
@@ -921,6 +927,9 @@ class ToolPaint(FlatCAMTool, Gerber):
self.tipdia_entry.set_value(self.app.defaults["tools_painttipdia"])
self.tipangle_entry.set_value(self.app.defaults["tools_painttipangle"])
self.addtool_entry.set_value(self.app.defaults["tools_paintnewdia"])
+ self.rest_cb.set_value(self.app.defaults["tools_paintrest"])
+
+ self.old_tool_dia = self.app.defaults["tools_paintnewdia"]
self.on_tool_type(val=self.tool_type_radio.get_value())
@@ -1080,21 +1089,16 @@ class ToolPaint(FlatCAMTool, Gerber):
self.box_combo.setCurrentIndex(0)
def on_tool_add(self, dia=None, muted=None):
-
- try:
- self.tools_table.itemChanged.disconnect()
- except TypeError:
- pass
+ self.blockSignals(True)
if dia:
tool_dia = dia
else:
- tool_dia = float(self.addtool_entry.get_value())
+ tool_dia = self.on_calculate_tooldia()
if tool_dia is None:
self.build_ui()
- self.app.inform.emit('[WARNING_NOTCL] %s' %
- _("Please enter a tool diameter to add, in Float format."))
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Please enter a tool diameter to add, in Float format."))
return
# construct a list of all 'tooluid' in the self.tools
@@ -1136,15 +1140,13 @@ class ToolPaint(FlatCAMTool, Gerber):
}
})
+ self.blockSignals(False)
self.build_ui()
def on_tool_edit(self):
- old_tool_dia = ''
+ self.blockSignals(True)
- try:
- self.tools_table.itemChanged.disconnect()
- except TypeError:
- pass
+ old_tool_dia = ''
tool_dias = []
for k, v in self.paint_tools.items():
@@ -1182,6 +1184,7 @@ class ToolPaint(FlatCAMTool, Gerber):
restore_dia_item.setText(str(old_tool_dia))
self.app.inform.emit('[WARNING_NOTCL] %s' %
_("Edit cancelled. New diameter value is already in the Tool Table."))
+ self.blockSignals(False)
self.build_ui()
# def on_tool_copy(self, all=None):
@@ -1240,15 +1243,13 @@ class ToolPaint(FlatCAMTool, Gerber):
# self.app.inform.emit("[success] Tool was copied in the Tool Table.")
def on_tool_delete(self, rows_to_delete=None, all=None):
- try:
- self.tools_table.itemChanged.disconnect()
- except TypeError:
- pass
+ self.blockSignals(True)
deleted_tools_list = []
if all:
self.paint_tools.clear()
+ self.blockSignals(False)
self.build_ui()
return
@@ -1262,6 +1263,8 @@ class ToolPaint(FlatCAMTool, Gerber):
for t in deleted_tools_list:
self.paint_tools.pop(t, None)
+
+ self.blockSignals(False)
self.build_ui()
return
@@ -1278,14 +1281,14 @@ class ToolPaint(FlatCAMTool, Gerber):
self.paint_tools.pop(t, None)
except AttributeError:
- self.app.inform.emit('[WARNING_NOTCL] %s' %
- _("Delete failed. Select a tool to delete."))
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Delete failed. Select a tool to delete."))
+ self.blockSignals(False)
return
except Exception as e:
log.debug(str(e))
- self.app.inform.emit('[success] %s' %
- _("Tool(s) deleted from Tool Table."))
+ self.app.inform.emit('[success] %s' % _("Tool(s) deleted from Tool Table."))
+ self.blockSignals(False)
self.build_ui()
def on_paint_button_click(self):
From 5ffa9b647085fc02dd08c335cab3f7ad146a2148 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 16 Jan 2020 02:21:20 +0200
Subject: [PATCH 025/209] - updated the GUI in preferences for Calculator Tool
---
README.md | 1 +
flatcamGUI/PreferencesUI.py | 23 +++++++++++------------
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/README.md b/README.md
index a2f7d29a..3ae584b3 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- updated/optimized the GUI in Preferences for Paint Tool and for NCC Tool
- work in Paint Tool to bring it up to date with NCC Tool
+- updated the GUI in preferences for Calculator Tool
15.01.2020
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index ca736455..728f86f6 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -6241,6 +6241,8 @@ class ToolsCalculatorsPrefGroupUI(OptionsGroupUI):
self.layout.addWidget(self.vshape_tool_label)
grid0 = QtWidgets.QGridLayout()
+ grid0.setColumnStretch(0, 0)
+ grid0.setColumnStretch(1, 1)
self.layout.addLayout(grid0)
# ## Tip Diameter
@@ -6291,10 +6293,7 @@ class ToolsCalculatorsPrefGroupUI(OptionsGroupUI):
_("This calculator is useful for those who plate the via/pad/drill holes,\n"
"using a method like grahite ink or calcium hypophosphite ink or palladium chloride.")
)
- self.layout.addWidget(self.plate_title_label)
-
- grid1 = QtWidgets.QGridLayout()
- self.layout.addLayout(grid1)
+ grid0.addWidget(self.plate_title_label, 3, 0, 1, 2)
# ## PCB Length
self.pcblength_entry = FCDoubleSpinner()
@@ -6305,8 +6304,8 @@ class ToolsCalculatorsPrefGroupUI(OptionsGroupUI):
self.pcblengthlabel = QtWidgets.QLabel('%s:' % _("Board Length"))
self.pcblengthlabel.setToolTip(_('This is the board length. In centimeters.'))
- grid1.addWidget(self.pcblengthlabel, 0, 0)
- grid1.addWidget(self.pcblength_entry, 0, 1)
+ grid0.addWidget(self.pcblengthlabel, 4, 0)
+ grid0.addWidget(self.pcblength_entry, 4, 1)
# ## PCB Width
self.pcbwidth_entry = FCDoubleSpinner()
@@ -6317,8 +6316,8 @@ class ToolsCalculatorsPrefGroupUI(OptionsGroupUI):
self.pcbwidthlabel = QtWidgets.QLabel('%s:' % _("Board Width"))
self.pcbwidthlabel.setToolTip(_('This is the board width.In centimeters.'))
- grid1.addWidget(self.pcbwidthlabel, 1, 0)
- grid1.addWidget(self.pcbwidth_entry, 1, 1)
+ grid0.addWidget(self.pcbwidthlabel, 5, 0)
+ grid0.addWidget(self.pcbwidth_entry, 5, 1)
# ## Current Density
self.cdensity_label = QtWidgets.QLabel('%s:' % _("Current Density"))
@@ -6329,8 +6328,8 @@ class ToolsCalculatorsPrefGroupUI(OptionsGroupUI):
self.cdensity_label.setToolTip(_("Current density to pass through the board. \n"
"In Amps per Square Feet ASF."))
- grid1.addWidget(self.cdensity_label, 2, 0)
- grid1.addWidget(self.cdensity_entry, 2, 1)
+ grid0.addWidget(self.cdensity_label, 6, 0)
+ grid0.addWidget(self.cdensity_entry, 6, 1)
# ## PCB Copper Growth
self.growth_label = QtWidgets.QLabel('%s:' % _("Copper Growth"))
@@ -6341,8 +6340,8 @@ class ToolsCalculatorsPrefGroupUI(OptionsGroupUI):
self.growth_label.setToolTip(_("How thick the copper growth is intended to be.\n"
"In microns."))
- grid1.addWidget(self.growth_label, 3, 0)
- grid1.addWidget(self.growth_entry, 3, 1)
+ grid0.addWidget(self.growth_label, 7, 0)
+ grid0.addWidget(self.growth_entry, 7, 1)
self.layout.addStretch()
From 24e01ad51824001a9c11cf977ebc8384d772a2db Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 16 Jan 2020 02:33:54 +0200
Subject: [PATCH 026/209] - a small change in the Excellon UI
---
README.md | 1 +
flatcamGUI/ObjectUI.py | 28 +++++++++++++++++++---------
2 files changed, 20 insertions(+), 9 deletions(-)
diff --git a/README.md b/README.md
index 3ae584b3..e49424ed 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ CAD program, and create G-Code for Isolation routing.
- updated/optimized the GUI in Preferences for Paint Tool and for NCC Tool
- work in Paint Tool to bring it up to date with NCC Tool
- updated the GUI in preferences for Calculator Tool
+- a small change in the Excellon UI
15.01.2020
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index 9cadf1ee..94729ce2 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -1050,6 +1050,16 @@ class ExcellonObjectUI(ObjectUI):
self.excellon_gcode_type_radio.setVisible(False)
gcode_type_label.hide()
+ warning_lbl = QtWidgets.QLabel(
+ _(
+ "Add / Select at least one tool in the tool-table.\n"
+ "Click the header to select all, or Ctrl + LMB\n"
+ "for custom selection of tools."
+ ))
+
+ grid2.addWidget(QtWidgets.QLabel(''), 2, 0, 1, 3)
+ grid2.addWidget(warning_lbl, 3, 0, 1, 3)
+
self.generate_cnc_button = QtWidgets.QPushButton(_('Create Drills GCode'))
self.generate_cnc_button.setToolTip(
_("Generate the CNC Job.")
@@ -1060,7 +1070,7 @@ class ExcellonObjectUI(ObjectUI):
font-weight: bold;
}
""")
- grid2.addWidget(self.generate_cnc_button, 2, 0, 1, 3)
+ grid2.addWidget(self.generate_cnc_button, 4, 0, 1, 3)
# ### Milling Holes Drills ####
self.mill_hole_label = QtWidgets.QLabel('%s' % _('Mill Holes'))
@@ -1069,7 +1079,7 @@ class ExcellonObjectUI(ObjectUI):
"Select from the Tools Table above the hole dias to be\n"
"milled. Use the # column to make the selection.")
)
- grid2.addWidget(self.mill_hole_label, 3, 0, 1, 3)
+ grid2.addWidget(self.mill_hole_label, 5, 0, 1, 3)
self.tdlabel = QtWidgets.QLabel('%s:' % _('Drill Tool dia'))
self.tdlabel.setToolTip(
@@ -1092,9 +1102,9 @@ class ExcellonObjectUI(ObjectUI):
}
""")
- grid2.addWidget(self.tdlabel, 4, 0)
- grid2.addWidget(self.tooldia_entry, 4, 1)
- grid2.addWidget(self.generate_milling_button, 4, 2)
+ grid2.addWidget(self.tdlabel, 6, 0)
+ grid2.addWidget(self.tooldia_entry, 6, 1)
+ grid2.addWidget(self.generate_milling_button, 6, 2)
self.stdlabel = QtWidgets.QLabel('%s:' % _('Slot Tool dia'))
self.stdlabel.setToolTip(
@@ -1119,9 +1129,9 @@ class ExcellonObjectUI(ObjectUI):
}
""")
- grid2.addWidget(self.stdlabel, 5, 0)
- grid2.addWidget(self.slot_tooldia_entry, 5, 1)
- grid2.addWidget(self.generate_milling_slots_button, 5, 2)
+ grid2.addWidget(self.stdlabel, 7, 0)
+ grid2.addWidget(self.slot_tooldia_entry, 7, 1)
+ grid2.addWidget(self.generate_milling_slots_button, 7, 2)
def hide_drills(self, state=True):
if state is True:
@@ -1697,7 +1707,7 @@ class GeometryObjectUI(ObjectUI):
warning_lbl = QtWidgets.QLabel(
_(
- "Add at least one tool in the tool-table.\n"
+ "Add / Select at least one tool in the tool-table.\n"
"Click the header to select all, or Ctrl + LMB\n"
"for custom selection of tools."
))
From 0221a9cfb6718a6ea175fea8c016498817e41c85 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 16 Jan 2020 15:49:51 +0200
Subject: [PATCH 027/209] - updated the Excellon and Geometry UI to be similar
- put bases for future changes to Excellon Object UI such that each tool will
hold it's own parameters
---
FlatCAMObj.py | 276 +++++++++++++++++++++++++++--------------
README.md | 2 +
flatcamGUI/ObjectUI.py | 79 ++++++------
3 files changed, 229 insertions(+), 128 deletions(-)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 6b98f6f2..8adf87c9 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -2775,22 +2775,92 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
def ui_connect(self):
+ # selective plotting
for row in range(self.ui.tools_table.rowCount() - 2):
self.ui.tools_table.cellWidget(row, 5).clicked.connect(self.on_plot_cb_click_table)
self.ui.plot_cb.stateChanged.connect(self.on_plot_cb_click)
+ # rows selected
+ self.ui.tools_table.clicked.connect(self.on_row_selection_change)
+ self.ui.tools_table.horizontalHeader().sectionClicked.connect(self.on_row_selection_change)
+
def ui_disconnect(self):
+ # selective plotting
for row in range(self.ui.tools_table.rowCount()):
try:
self.ui.tools_table.cellWidget(row, 5).clicked.disconnect()
except (TypeError, AttributeError):
pass
-
try:
self.ui.plot_cb.stateChanged.disconnect()
except (TypeError, AttributeError):
pass
+ # rows selected
+ try:
+ self.ui.tools_table.clicked.disconnect()
+ except (TypeError, AttributeError):
+ pass
+ try:
+ self.ui.tools_table.horizontalHeader().sectionClicked.disconnect()
+ except (TypeError, AttributeError):
+ pass
+
+ def on_row_selection_change(self):
+ self.update_ui()
+
+ def update_ui(self, row=None):
+ self.ui.blockSignals(True)
+
+ if row is None:
+ sel_rows = list()
+ sel_items = self.ui.tools_table.selectedItems()
+ for it in sel_items:
+ sel_rows.append(it.row())
+ else:
+ sel_rows = row if type(row) == list else [row]
+
+ if not sel_rows:
+ sel_rows = [0]
+
+ if len(sel_rows) == 1:
+ # update the QLabel that shows for which Tool we have the parameters in the UI form
+ tooluid = int(self.ui.tools_table.item(sel_rows[0], 0).text())
+ self.ui.tool_data_label.setText(
+ "%s: %s %d" % (_('Parameters for'), _("Tool"), tooluid)
+ )
+ else:
+ self.ui.tool_data_label.setText(
+ "%s: %s" % (_('Parameters for'), _("Multiple Tools"))
+ )
+
+ for c_row in sel_rows:
+ # populate the form with the data from the tool associated with the row parameter
+ try:
+ item = self.ui.tools_table.item(c_row, 0)
+ if type(item) is not None:
+ tooluid = int(item.text())
+ else:
+ self.ui.blockSignals(False)
+ return
+ except Exception as e:
+ log.debug("Tool missing. Add a tool in Geo Tool Table. %s" % str(e))
+ self.ui.blockSignals(False)
+ return
+
+ # try:
+ # # set the form with data from the newly selected tool
+ # for tooluid_key, tooluid_value in list(self.tools.items()):
+ # if int(tooluid_key) == tooluid:
+ # for key, value in tooluid_value.items():
+ # if key == 'data':
+ # form_value_storage = tooluid_value[key]
+ # self.update_form(form_value_storage)
+ # except Exception as e:
+ # log.debug("FlatCAMObj ---> update_ui() " + str(e))
+
+ self.ui.blockSignals(False)
+
def on_tool_offset_edit(self):
# if connected, disconnect the signal from the slot on item_changed as it creates issues
for row in range(self.ui.tools_table.rowCount()):
@@ -4056,7 +4126,10 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.copytool_btn.clicked.connect(lambda: self.on_tool_copy())
self.ui.deltool_btn.clicked.connect(lambda: self.on_tool_delete())
- self.ui.geo_tools_table.currentItemChanged.connect(self.on_row_selection_change)
+ # self.ui.geo_tools_table.currentItemChanged.connect(self.on_row_selection_change)
+ self.ui.geo_tools_table.clicked.connect(self.on_row_selection_change)
+ self.ui.geo_tools_table.horizontalHeader().sectionClicked.connect(self.on_row_selection_change)
+
self.ui.geo_tools_table.itemChanged.connect(self.on_tool_edit)
self.ui.tool_offset_entry.returnPressed.connect(self.on_offset_value_edited)
@@ -4115,7 +4188,11 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
pass
try:
- self.ui.geo_tools_table.currentItemChanged.disconnect()
+ self.ui.geo_tools_table.clicked.disconnect()
+ except (TypeError, AttributeError):
+ pass
+ try:
+ self.ui.geo_tools_table.horizontalHeader().sectionClicked.disconnect()
except (TypeError, AttributeError):
pass
@@ -4140,8 +4217,84 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
except (TypeError, AttributeError):
pass
+ def on_row_selection_change(self):
+ self.update_ui()
+
+ def update_ui(self, row=None):
+ self.ui.blockSignals(True)
+
+ if row is None:
+ sel_rows = list()
+ sel_items = self.ui.geo_tools_table.selectedItems()
+ for it in sel_items:
+ sel_rows.append(it.row())
+ else:
+ sel_rows = row if type(row) == list else [row]
+
+ if not sel_rows:
+ sel_rows = [0]
+
+ for current_row in sel_rows:
+ self.set_tool_offset_visibility(current_row)
+
+ # populate the form with the data from the tool associated with the row parameter
+ try:
+ item = self.ui.geo_tools_table.item(current_row, 5)
+ if type(item) is not None:
+ tooluid = int(item.text())
+ else:
+ self.ui.blockSignals(False)
+ return
+ except Exception as e:
+ log.debug("Tool missing. Add a tool in Geo Tool Table. %s" % str(e))
+ self.ui.blockSignals(False)
+ return
+
+ # update the QLabel that shows for which Tool we have the parameters in the UI form
+ if len(sel_rows) == 1:
+ self.ui.tool_data_label.setText(
+ "%s: %s %d" % (_('Parameters for'), _("Tool"), tooluid)
+ )
+ else:
+ self.ui.tool_data_label.setText(
+ "%s: %s" % (_('Parameters for'), _("Multiple Tools"))
+ )
+
+ # update the form with the V-Shape fields if V-Shape selected in the geo_tool_table
+ # also modify the Cut Z form entry to reflect the calculated Cut Z from values got from V-Shape Fields
+ try:
+ item = self.ui.geo_tools_table.cellWidget(current_row, 4)
+ if item is not None:
+ tool_type_txt = item.currentText()
+ self.ui_update_v_shape(tool_type_txt=tool_type_txt)
+ else:
+ self.ui.blockSignals(False)
+ return
+ except Exception as e:
+ log.debug("Tool missing in ui_update_v_shape(). Add a tool in Geo Tool Table. %s" % str(e))
+ return
+
+ try:
+ # set the form with data from the newly selected tool
+ for tooluid_key, tooluid_value in list(self.tools.items()):
+ if int(tooluid_key) == tooluid:
+ for key, value in tooluid_value.items():
+ if key == 'data':
+ form_value_storage = tooluid_value[key]
+ self.update_form(form_value_storage)
+ if key == 'offset_value':
+ # update the offset value in the entry even if the entry is hidden
+ self.ui.tool_offset_entry.set_value(tooluid_value[key])
+
+ if key == 'tool_type' and value == 'V':
+ self.update_cutz()
+ except Exception as e:
+ log.debug("FlatCAMObj ---> update_ui() " + str(e))
+
+ self.ui.blockSignals(False)
+
def on_tool_add(self, dia=None):
- self.ui_disconnect()
+ self.ui.blockSignals(True)
self.units = self.app.defaults['units'].upper()
@@ -4214,6 +4367,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ser_attrs.append('tools')
self.app.inform.emit('[success] %s' % _("Tool added in Tool Table."))
+ self.ui.blockSignals(False)
self.build_ui()
# if there is no tool left in the Tools Table, enable the parameters GUI
@@ -4244,7 +4398,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
:return: None
"""
- self.ui_disconnect()
+ self.ui.blockSignals(True)
self.units = self.app.defaults['units'].upper()
tooldia = float(tool['tooldia'])
@@ -4288,6 +4442,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
pass
self.ser_attrs.append('tools')
+ self.ui.blockSignals(False)
self.build_ui()
# if there is no tool left in the Tools Table, enable the parameters GUI
@@ -4295,7 +4450,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.geo_param_frame.setDisabled(False)
def on_tool_copy(self, all=None):
- self.ui_disconnect()
+ self.ui.blockSignals(True)
# find the tool_uid maximum value in the self.tools
uid_list = []
@@ -4319,8 +4474,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
max_uid += 1
self.tools[int(max_uid)] = deepcopy(self.tools[tooluid_copy])
except AttributeError:
- self.app.inform.emit('[WARNING_NOTCL] %s' %
- _("Failed. Select a tool to copy."))
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Failed. Select a tool to copy."))
+ self.ui.blockSignals(False)
self.build_ui()
return
except Exception as e:
@@ -4328,8 +4483,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# deselect the table
# self.ui.geo_tools_table.clearSelection()
else:
- self.app.inform.emit('[WARNING_NOTCL] %s' %
- _("Failed. Select a tool to copy."))
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Failed. Select a tool to copy."))
+ self.ui.blockSignals(False)
self.build_ui()
return
else:
@@ -4355,12 +4510,12 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
pass
self.ser_attrs.append('tools')
+ self.ui.blockSignals(False)
self.build_ui()
self.app.inform.emit('[success] %s' % _("Tool was copied in Tool Table."))
def on_tool_edit(self, current_item):
-
- self.ui_disconnect()
+ self.ui.blockSignals(True)
current_row = current_item.row()
try:
@@ -4385,10 +4540,11 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
pass
self.app.inform.emit('[success] %s' % _("Tool was edited in Tool Table."))
+ self.ui.blockSignals(False)
self.build_ui()
def on_tool_delete(self, all=None):
- self.ui_disconnect()
+ self.ui.blockSignals(True)
if all is None:
if self.ui.geo_tools_table.selectedItems():
@@ -4412,8 +4568,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.tools = deepcopy(temp_tools)
temp_tools.clear()
except AttributeError:
- self.app.inform.emit('[WARNING_NOTCL] %s' %
- _("Failed. Select a tool to delete."))
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Failed. Select a tool to delete."))
+ self.ui.blockSignals(False)
self.build_ui()
return
except Exception as e:
@@ -4421,8 +4577,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# deselect the table
# self.ui.geo_tools_table.clearSelection()
else:
- self.app.inform.emit('[WARNING_NOTCL] %s' %
- _("Failed. Select a tool to delete."))
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Failed. Select a tool to delete."))
+ self.ui.blockSignals(False)
self.build_ui()
return
else:
@@ -4443,9 +4599,9 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
pass
self.ser_attrs.append('tools')
+ self.ui.blockSignals(False)
self.build_ui()
- self.app.inform.emit('[success] %s' %
- _("Tool was deleted in Tool Table."))
+ self.app.inform.emit('[success] %s' % _("Tool was deleted in Tool Table."))
obj_active = self.app.collection.get_active()
# if the object was MultiGeo and now it has no tool at all (therefore no geometry)
@@ -4474,72 +4630,6 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
if self.ui.geo_tools_table.rowCount() == 0:
self.ui.geo_param_frame.setDisabled(True)
- def on_row_selection_change(self):
- self.update_ui()
-
- def update_ui(self, row=None):
- self.ui_disconnect()
-
- if row is None:
- try:
- current_row = self.ui.geo_tools_table.currentRow()
- except Exception:
- current_row = 0
- else:
- current_row = row
-
- if current_row < 0:
- current_row = 0
-
- self.set_tool_offset_visibility(current_row)
-
- # populate the form with the data from the tool associated with the row parameter
- try:
- item = self.ui.geo_tools_table.item(current_row, 5)
- if type(item) is not None:
- tooluid = int(item.text())
- else:
- return
- except Exception as e:
- log.debug("Tool missing. Add a tool in Geo Tool Table. %s" % str(e))
- return
-
- # update the QLabel that shows for which Tool we have the parameters in the UI form
- self.ui.tool_data_label.setText(
- "%s: %s %d" % (_('Parameters for'), _("Tool"), tooluid)
- )
-
- # update the form with the V-Shape fields if V-Shape selected in the geo_tool_table
- # also modify the Cut Z form entry to reflect the calculated Cut Z from values got from V-Shape Fields
- try:
- item = self.ui.geo_tools_table.cellWidget(current_row, 4)
- if item is not None:
- tool_type_txt = item.currentText()
- self.ui_update_v_shape(tool_type_txt=tool_type_txt)
- else:
- return
- except Exception as e:
- log.debug("Tool missing in ui_update_v_shape(). Add a tool in Geo Tool Table. %s" % str(e))
- return
-
- try:
- # set the form with data from the newly selected tool
- for tooluid_key, tooluid_value in list(self.tools.items()):
- if int(tooluid_key) == tooluid:
- for key, value in tooluid_value.items():
- if key == 'data':
- form_value_storage = tooluid_value[key]
- self.update_form(form_value_storage)
- if key == 'offset_value':
- # update the offset value in the entry even if the entry is hidden
- self.ui.tool_offset_entry.set_value(tooluid_value[key])
-
- if key == 'tool_type' and value == 'V':
- self.update_cutz()
- except Exception as e:
- log.debug("FlatCAMObj ---> update_ui() " + str(e))
- self.ui_connect()
-
def ui_update_v_shape(self, tool_type_txt):
if tool_type_txt == 'V':
self.ui.tipdialabel.show()
@@ -4643,7 +4733,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
log.debug("FlatCAMGeometry.gui_form_to_storage() --> no tool in Tools Table, aborting.")
return
- self.ui_disconnect()
+ self.ui.blockSignals(True)
row = self.ui.geo_tools_table.currentRow()
if row < 0:
@@ -4698,7 +4788,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.tools = deepcopy(temp_tools)
temp_tools.clear()
- self.ui_connect()
+ self.ui.blockSignals(False)
def gui_form_to_storage(self):
if self.ui.geo_tools_table.rowCount() == 0:
@@ -4706,7 +4796,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
log.debug("FlatCAMGeometry.gui_form_to_storage() --> no tool in Tools Table, aborting.")
return
- self.ui_disconnect()
+ self.ui.blockSignals(True)
widget_changed = self.sender()
try:
widget_idx = self.ui.grid3.indexOf(widget_changed)
@@ -4785,7 +4875,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.tools.clear()
self.tools = deepcopy(temp_tools)
temp_tools.clear()
- self.ui_connect()
+ self.ui.blockSignals(False)
def select_tools_table_row(self, row, clearsel=None):
if clearsel:
@@ -5813,7 +5903,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.read_form_item('plot')
self.plot()
- self.ui_disconnect()
+ self.ui.blockSignals(True)
cb_flag = self.ui.plot_cb.isChecked()
for row in range(self.ui.geo_tools_table.rowCount()):
table_cb = self.ui.geo_tools_table.cellWidget(row, 6)
@@ -5821,11 +5911,11 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
table_cb.setChecked(True)
else:
table_cb.setChecked(False)
- self.ui_connect()
+ self.ui.blockSignals(False)
def on_plot_cb_click_table(self):
# self.ui.cnc_tools_table.cellWidget(row, 2).widget().setCheckState(QtCore.Qt.Unchecked)
- self.ui_disconnect()
+ self.ui.blockSignals(True)
# cw = self.sender()
# cw_index = self.ui.geo_tools_table.indexAt(cw.pos())
# cw_row = cw_index.row()
@@ -5858,7 +5948,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.plot_cb.setChecked(False)
else:
self.ui.plot_cb.setChecked(True)
- self.ui_connect()
+ self.ui.blockSignals(False)
def merge(self, geo_list, geo_final, multigeo=None):
"""
diff --git a/README.md b/README.md
index e49424ed..807ddbed 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,8 @@ CAD program, and create G-Code for Isolation routing.
- work in Paint Tool to bring it up to date with NCC Tool
- updated the GUI in preferences for Calculator Tool
- a small change in the Excellon UI
+- updated the Excellon and Geometry UI to be similar
+- put bases for future changes to Excellon Object UI such that each tool will hold it's own parameters
15.01.2020
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index 94729ce2..5137b47d 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -800,16 +800,26 @@ class ExcellonObjectUI(ObjectUI):
_("Toggle display of the drills for the current tool.\n"
"This does not select the tools for G-code generation."))
- self.empty_label = QtWidgets.QLabel('')
- self.tools_box.addWidget(self.empty_label)
+ self.tools_box.addWidget(QtWidgets.QLabel(''))
- # ### Create CNC Job ####
- self.cncjob_label = QtWidgets.QLabel('%s' % _('Create CNC Job'))
- self.cncjob_label.setToolTip(
- _("Create a CNC Job object\n"
- "for this drill object.")
+ # ###########################################################
+ # ############# Create CNC Job ##############################
+ # ###########################################################
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.tools_box.addWidget(separator_line)
+
+ self.tool_data_label = QtWidgets.QLabel(
+ "%s: %s %d" % (_('Parameters for'), _("Tool"), int(1)))
+ self.tool_data_label.setToolTip(
+ _(
+ "The data used for creating GCode.\n"
+ "Each tool store it's own set of such data."
+ )
)
- self.tools_box.addWidget(self.cncjob_label)
+ self.tools_box.addWidget(self.tool_data_label)
grid1 = QtWidgets.QGridLayout()
self.tools_box.addLayout(grid1)
@@ -855,33 +865,29 @@ class ExcellonObjectUI(ObjectUI):
grid1.addWidget(self.travelz_entry, 1, 1)
# Tool change:
- self.toolchange_cb = FCCheckBox('%s' % _("Tool change"))
+ self.toolchange_cb = FCCheckBox('%s:' % _("Tool change Z"))
self.toolchange_cb.setToolTip(
_("Include tool-change sequence\n"
"in G-Code (Pause for tool change).")
)
- grid1.addWidget(self.toolchange_cb, 2, 0, 1, 2)
- # Tool change Z:
- toolchzlabel = QtWidgets.QLabel('%s:' % _("Tool change Z"))
- toolchzlabel.setToolTip(
+ self.toolchangez_entry = FCDoubleSpinner()
+ self.toolchangez_entry.set_precision(self.decimals)
+ self.toolchangez_entry.setToolTip(
_("Z-axis position (height) for\n"
"tool change.")
)
- grid1.addWidget(toolchzlabel, 3, 0)
- self.toolchangez_entry = FCDoubleSpinner()
- self.toolchangez_entry.set_precision(self.decimals)
-
if machinist_setting == 0:
self.toolchangez_entry.set_range(0.0, 9999.9999)
else:
self.toolchangez_entry.set_range(-9999.9999, 9999.9999)
self.toolchangez_entry.setSingleStep(0.1)
-
- grid1.addWidget(self.toolchangez_entry, 3, 1)
self.ois_tcz_e = OptionalInputSection(self.toolchange_cb, [self.toolchangez_entry])
+ grid1.addWidget(self.toolchange_cb, 2, 0)
+ grid1.addWidget(self.toolchangez_entry, 2, 1)
+
# Start move Z:
self.estartz_label = QtWidgets.QLabel('%s:' % _("Start Z"))
self.estartz_label.setToolTip(
@@ -1022,6 +1028,11 @@ class ExcellonObjectUI(ObjectUI):
self.feedrate_probe_label.hide()
self.feedrate_probe_entry.setVisible(False)
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid1.addWidget(separator_line, 13, 0, 1, 2)
+
grid2 = QtWidgets.QGridLayout()
self.tools_box.addLayout(grid2)
grid2.setColumnStretch(0, 0)
@@ -1349,9 +1360,9 @@ class GeometryObjectUI(ObjectUI):
self.empty_label = QtWidgets.QLabel('')
self.geo_tools_box.addWidget(self.empty_label)
- # ##################
- # Create CNC Job ###
- # ##################
+ # ###########################################################
+ # ############# Create CNC Job ##############################
+ # ###########################################################
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
@@ -1477,15 +1488,8 @@ class GeometryObjectUI(ObjectUI):
self.grid3.addWidget(travelzlabel, 5, 0)
self.grid3.addWidget(self.travelz_entry, 5, 1)
- # Tool change:
- self.toolchzlabel = QtWidgets.QLabel('%s:' % _("Tool change Z"))
- self.toolchzlabel.setToolTip(
- _(
- "Z-axis position (height) for\n"
- "tool change."
- )
- )
- self.toolchangeg_cb = FCCheckBox('%s' % _("Tool change"))
+ # Tool change
+ self.toolchangeg_cb = FCCheckBox('%s:' % _("Tool change Z"))
self.toolchangeg_cb.setToolTip(
_(
"Include tool-change sequence\n"
@@ -1494,6 +1498,12 @@ class GeometryObjectUI(ObjectUI):
)
self.toolchangez_entry = FCDoubleSpinner()
self.toolchangez_entry.set_precision(self.decimals)
+ self.toolchangez_entry.setToolTip(
+ _(
+ "Z-axis position (height) for\n"
+ "tool change."
+ )
+ )
if machinist_setting == 0:
self.toolchangez_entry.set_range(0, 9999.9999)
@@ -1501,12 +1511,11 @@ class GeometryObjectUI(ObjectUI):
self.toolchangez_entry.set_range(-9999.9999, 9999.9999)
self.toolchangez_entry.setSingleStep(0.1)
-
- self.grid3.addWidget(self.toolchangeg_cb, 6, 0, 1, 2)
- self.grid3.addWidget(self.toolchzlabel, 7, 0)
- self.grid3.addWidget(self.toolchangez_entry, 7, 1)
self.ois_tcz_geo = OptionalInputSection(self.toolchangeg_cb, [self.toolchangez_entry])
+ self.grid3.addWidget(self.toolchangeg_cb, 6, 0)
+ self.grid3.addWidget(self.toolchangez_entry, 6, 1)
+
# The Z value for the start move
# startzlabel = QtWidgets.QLabel('Start move Z:')
# startzlabel.setToolTip(
From b71d4e8c4570b862c2834d270a4c7f8bc47f5279 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 16 Jan 2020 16:43:39 +0200
Subject: [PATCH 028/209] - in ParseExcellon.Excellon the self.tools dict has
now a key 'data' which holds a dict with all the default values for Excellon
and Geometry - Excellon and Geometry objects, when started with multiple
tools selected, the parameters tool name reflect this situation
---
FlatCAMObj.py | 23 ++++++++++++++++++++++-
README.md | 2 ++
flatcamParsers/ParseExcellon.py | 26 ++++++++++++++++++++------
3 files changed, 44 insertions(+), 7 deletions(-)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 8adf87c9..cbb4a83b 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -2622,9 +2622,10 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
# sort the tool diameter column
# self.ui.tools_table.sortItems(1)
+
# all the tools are selected by default
self.ui.tools_table.selectColumn(0)
- #
+
self.ui.tools_table.resizeColumnsToContents()
self.ui.tools_table.resizeRowsToContents()
@@ -2686,6 +2687,16 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
except (TypeError, AttributeError):
pass
+ # set the text on tool_data_label after loading the object
+ sel_rows = list()
+ sel_items = self.ui.tools_table.selectedItems()
+ for it in sel_items:
+ sel_rows.append(it.row())
+ if len(sel_rows) > 1:
+ self.ui.tool_data_label.setText(
+ "%s: %s" % (_('Parameters for'), _("Multiple Tools"))
+ )
+
self.ui_connect()
def set_ui(self, ui):
@@ -3855,6 +3866,16 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.e_cut_entry.setDisabled(False) if self.ui.extracut_cb.get_value() else \
self.ui.e_cut_entry.setDisabled(True)
+ # set the text on tool_data_label after loading the object
+ sel_rows = list()
+ sel_items = self.ui.geo_tools_table.selectedItems()
+ for it in sel_items:
+ sel_rows.append(it.row())
+ if len(sel_rows) > 1:
+ self.ui.tool_data_label.setText(
+ "%s: %s" % (_('Parameters for'), _("Multiple Tools"))
+ )
+
def set_ui(self, ui):
FlatCAMObj.set_ui(self, ui)
diff --git a/README.md b/README.md
index 807ddbed..9e4ab4c3 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,8 @@ CAD program, and create G-Code for Isolation routing.
- a small change in the Excellon UI
- updated the Excellon and Geometry UI to be similar
- put bases for future changes to Excellon Object UI such that each tool will hold it's own parameters
+- in ParseExcellon.Excellon the self.tools dict has now a key 'data' which holds a dict with all the default values for Excellon and Geometry
+- Excellon and Geometry objects, when started with multiple tools selected, the parameters tool name reflect this situation
15.01.2020
diff --git a/flatcamParsers/ParseExcellon.py b/flatcamParsers/ParseExcellon.py
index adba5941..fb024bf4 100644
--- a/flatcamParsers/ParseExcellon.py
+++ b/flatcamParsers/ParseExcellon.py
@@ -121,6 +121,9 @@ class Excellon(Geometry):
self.zeros_found = deepcopy(self.zeros)
self.units_found = deepcopy(self.units)
+ # default set of data to be added to each tool in self.tools as self.tools[tool]['data'] = self.default_data
+ self.default_data = dict()
+
# this will serve as a default if the Excellon file has no info regarding of tool diameters (this info may be
# in another file like for PCB WIzard ECAD software
self.toolless_diam = 1.0
@@ -261,6 +264,14 @@ class Excellon(Geometry):
except Exception:
return "fail"
+ # fill in self.default_data values from self.options
+ for opt_key, opt_val in self.app.options.items():
+ if opt_key.find('excellon_') == 0:
+ self.default_data[opt_key] = deepcopy(opt_val)
+ for opt_key, opt_val in self.app.options.items():
+ if opt_key.find('geometry_') == 0:
+ self.default_data[opt_key] = deepcopy(opt_val)
+
def parse_lines(self, elines):
"""
Main Excellon parser.
@@ -961,10 +972,8 @@ class Excellon(Geometry):
try:
# clear the solid_geometry in self.tools
for tool in self.tools:
- try:
- self.tools[tool]['solid_geometry'][:] = []
- except KeyError:
- self.tools[tool]['solid_geometry'] = []
+ self.tools[tool]['solid_geometry'] = list()
+ self.tools[tool]['data'] = dict()
for drill in self.drills:
# poly = drill['point'].buffer(self.tools[drill['tool']]["C"]/2.0)
@@ -979,7 +988,10 @@ class Excellon(Geometry):
tooldia = self.tools[drill['tool']]['C']
poly = drill['point'].buffer(tooldia / 2.0, int(int(self.geo_steps_per_circle) / 4))
self.solid_geometry.append(poly)
- self.tools[drill['tool']]['solid_geometry'].append(poly)
+
+ tool_in_drills = drill['tool']
+ self.tools[tool_in_drills]['solid_geometry'].append(poly)
+ self.tools[tool_in_drills]['data'] = deepcopy(self.default_data)
for slot in self.slots:
slot_tooldia = self.tools[slot['tool']]['C']
@@ -989,8 +1001,10 @@ class Excellon(Geometry):
lines_string = LineString([start, stop])
poly = lines_string.buffer(slot_tooldia / 2.0, int(int(self.geo_steps_per_circle) / 4))
self.solid_geometry.append(poly)
- self.tools[slot['tool']]['solid_geometry'].append(poly)
+ tool_in_slots = slot['tool']
+ self.tools[tool_in_slots]['solid_geometry'].append(poly)
+ self.tools[tool_in_slots]['data'] = deepcopy(self.default_data)
except Exception as e:
log.debug("flatcamParsers.ParseExcellon.Excellon.create_geometry() -> "
"Excellon geometry creation failed due of ERROR: %s" % str(e))
From c41703089608ab7a01f0306d7e396544dc6c3821 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 16 Jan 2020 16:55:34 +0200
Subject: [PATCH 029/209] - moved default_data data update from Excellon parser
to the Excellon object constructor
---
FlatCAMObj.py | 11 +++++++++++
README.md | 1 +
flatcamParsers/ParseExcellon.py | 11 -----------
3 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index cbb4a83b..2e466d78 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -2269,6 +2269,17 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
# dict to hold the tool number as key and tool offset as value
self.tool_offset = dict()
+ # default set of data to be added to each tool in self.tools as self.tools[tool]['data'] = self.default_data
+ self.default_data = dict()
+
+ # fill in self.default_data values from self.options
+ for opt_key, opt_val in self.app.options.items():
+ if opt_key.find('excellon_') == 0:
+ self.default_data[opt_key] = deepcopy(opt_val)
+ for opt_key, opt_val in self.app.options.items():
+ if opt_key.find('geometry_') == 0:
+ self.default_data[opt_key] = deepcopy(opt_val)
+
# variable to store the total amount of drills per job
self.tot_drill_cnt = 0
self.tool_row = 0
diff --git a/README.md b/README.md
index 9e4ab4c3..d8c3dbb6 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,7 @@ CAD program, and create G-Code for Isolation routing.
- put bases for future changes to Excellon Object UI such that each tool will hold it's own parameters
- in ParseExcellon.Excellon the self.tools dict has now a key 'data' which holds a dict with all the default values for Excellon and Geometry
- Excellon and Geometry objects, when started with multiple tools selected, the parameters tool name reflect this situation
+- moved default_data data update from Excellon parser to the Excellon object constructor
15.01.2020
diff --git a/flatcamParsers/ParseExcellon.py b/flatcamParsers/ParseExcellon.py
index fb024bf4..a82cf401 100644
--- a/flatcamParsers/ParseExcellon.py
+++ b/flatcamParsers/ParseExcellon.py
@@ -121,9 +121,6 @@ class Excellon(Geometry):
self.zeros_found = deepcopy(self.zeros)
self.units_found = deepcopy(self.units)
- # default set of data to be added to each tool in self.tools as self.tools[tool]['data'] = self.default_data
- self.default_data = dict()
-
# this will serve as a default if the Excellon file has no info regarding of tool diameters (this info may be
# in another file like for PCB WIzard ECAD software
self.toolless_diam = 1.0
@@ -264,14 +261,6 @@ class Excellon(Geometry):
except Exception:
return "fail"
- # fill in self.default_data values from self.options
- for opt_key, opt_val in self.app.options.items():
- if opt_key.find('excellon_') == 0:
- self.default_data[opt_key] = deepcopy(opt_val)
- for opt_key, opt_val in self.app.options.items():
- if opt_key.find('geometry_') == 0:
- self.default_data[opt_key] = deepcopy(opt_val)
-
def parse_lines(self, elines):
"""
Main Excellon parser.
From 957903d30799c30af313219b5df778abd0d173bb Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 17 Jan 2020 03:15:13 +0200
Subject: [PATCH 030/209] - more changes to Excellon UI
---
FlatCAMObj.py | 97 +++++++----
README.md | 4 +
flatcamGUI/ObjectUI.py | 378 ++++++++++++++++++++++++++++++++---------
3 files changed, 363 insertions(+), 116 deletions(-)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 2e466d78..447090a5 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -2792,6 +2792,9 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.ui.generate_milling_button.clicked.connect(self.on_generate_milling_button_click)
self.ui.generate_milling_slots_button.clicked.connect(self.on_generate_milling_slots_button_click)
+ self.on_operation_type(val='drill')
+ self.ui.operation_radio.activated_custom.connect(self.on_operation_type)
+
self.ui.pp_excellon_name_cb.activated.connect(self.on_pp_changed)
self.units_found = self.app.defaults['units']
@@ -2832,7 +2835,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.update_ui()
def update_ui(self, row=None):
- self.ui.blockSignals(True)
+ self.ui_disconnect()
if row is None:
sel_rows = list()
@@ -2863,11 +2866,11 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
if type(item) is not None:
tooluid = int(item.text())
else:
- self.ui.blockSignals(False)
+ self.ui_connect()
return
except Exception as e:
log.debug("Tool missing. Add a tool in Geo Tool Table. %s" % str(e))
- self.ui.blockSignals(False)
+ self.ui_connect()
return
# try:
@@ -2881,7 +2884,31 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
# except Exception as e:
# log.debug("FlatCAMObj ---> update_ui() " + str(e))
- self.ui.blockSignals(False)
+ self.ui_connect()
+
+ def on_operation_type(self, val):
+ if val == 'mill':
+ self.ui.mill_type_label.show()
+ self.ui.mill_type_radio.show()
+ self.ui.mill_dia_label.show()
+ self.ui.mill_dia_entry.show()
+ self.ui.mpass_cb.show()
+ self.ui.maxdepth_entry.show()
+ self.ui.frxylabel.show()
+ self.ui.xyfeedrate_entry.show()
+ self.ui.extracut_cb.show()
+ self.ui.e_cut_entry.show()
+ else:
+ self.ui.mill_type_label.hide()
+ self.ui.mill_type_radio.hide()
+ self.ui.mill_dia_label.hide()
+ self.ui.mill_dia_entry.hide()
+ self.ui.mpass_cb.hide()
+ self.ui.maxdepth_entry.hide()
+ self.ui.frxylabel.hide()
+ self.ui.xyfeedrate_entry.hide()
+ self.ui.extracut_cb.hide()
+ self.ui.e_cut_entry.hide()
def on_tool_offset_edit(self):
# if connected, disconnect the signal from the slot on item_changed as it creates issues
@@ -4253,7 +4280,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.update_ui()
def update_ui(self, row=None):
- self.ui.blockSignals(True)
+ self.ui_disconnect()
if row is None:
sel_rows = list()
@@ -4275,11 +4302,11 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
if type(item) is not None:
tooluid = int(item.text())
else:
- self.ui.blockSignals(False)
+ self.ui_connect()
return
except Exception as e:
log.debug("Tool missing. Add a tool in Geo Tool Table. %s" % str(e))
- self.ui.blockSignals(False)
+ self.ui_connect()
return
# update the QLabel that shows for which Tool we have the parameters in the UI form
@@ -4300,7 +4327,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
tool_type_txt = item.currentText()
self.ui_update_v_shape(tool_type_txt=tool_type_txt)
else:
- self.ui.blockSignals(False)
+ self.ui_connect()
return
except Exception as e:
log.debug("Tool missing in ui_update_v_shape(). Add a tool in Geo Tool Table. %s" % str(e))
@@ -4308,25 +4335,25 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
try:
# set the form with data from the newly selected tool
- for tooluid_key, tooluid_value in list(self.tools.items()):
+ for tooluid_key, tooluid_value in self.tools.items():
if int(tooluid_key) == tooluid:
for key, value in tooluid_value.items():
if key == 'data':
- form_value_storage = tooluid_value[key]
+ form_value_storage = tooluid_value['data']
self.update_form(form_value_storage)
if key == 'offset_value':
# update the offset value in the entry even if the entry is hidden
- self.ui.tool_offset_entry.set_value(tooluid_value[key])
+ self.ui.tool_offset_entry.set_value(tooluid_value['offset_value'])
if key == 'tool_type' and value == 'V':
self.update_cutz()
except Exception as e:
- log.debug("FlatCAMObj ---> update_ui() " + str(e))
+ log.debug("FlatCAMGeometry.update_ui() -> %s " % str(e))
- self.ui.blockSignals(False)
+ self.ui_connect()
def on_tool_add(self, dia=None):
- self.ui.blockSignals(True)
+ self.ui_disconnect()
self.units = self.app.defaults['units'].upper()
@@ -4399,7 +4426,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ser_attrs.append('tools')
self.app.inform.emit('[success] %s' % _("Tool added in Tool Table."))
- self.ui.blockSignals(False)
+ self.ui_connect()
self.build_ui()
# if there is no tool left in the Tools Table, enable the parameters GUI
@@ -4430,7 +4457,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
:return: None
"""
- self.ui.blockSignals(True)
+ self.ui_disconnect()
self.units = self.app.defaults['units'].upper()
tooldia = float(tool['tooldia'])
@@ -4474,7 +4501,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
pass
self.ser_attrs.append('tools')
- self.ui.blockSignals(False)
+ self.ui_connect()
self.build_ui()
# if there is no tool left in the Tools Table, enable the parameters GUI
@@ -4482,7 +4509,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.geo_param_frame.setDisabled(False)
def on_tool_copy(self, all=None):
- self.ui.blockSignals(True)
+ self.ui_disconnect()
# find the tool_uid maximum value in the self.tools
uid_list = []
@@ -4507,7 +4534,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.tools[int(max_uid)] = deepcopy(self.tools[tooluid_copy])
except AttributeError:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Failed. Select a tool to copy."))
- self.ui.blockSignals(False)
+ self.ui_connect()
self.build_ui()
return
except Exception as e:
@@ -4516,7 +4543,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# self.ui.geo_tools_table.clearSelection()
else:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Failed. Select a tool to copy."))
- self.ui.blockSignals(False)
+ self.ui_connect()
self.build_ui()
return
else:
@@ -4542,12 +4569,12 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
pass
self.ser_attrs.append('tools')
- self.ui.blockSignals(False)
+ self.ui_connect()
self.build_ui()
self.app.inform.emit('[success] %s' % _("Tool was copied in Tool Table."))
def on_tool_edit(self, current_item):
- self.ui.blockSignals(True)
+ self.ui_disconnect()
current_row = current_item.row()
try:
@@ -4572,11 +4599,11 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
pass
self.app.inform.emit('[success] %s' % _("Tool was edited in Tool Table."))
- self.ui.blockSignals(False)
+ self.ui_connect()
self.build_ui()
def on_tool_delete(self, all=None):
- self.ui.blockSignals(True)
+ self.ui_disconnect()
if all is None:
if self.ui.geo_tools_table.selectedItems():
@@ -4601,7 +4628,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
temp_tools.clear()
except AttributeError:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Failed. Select a tool to delete."))
- self.ui.blockSignals(False)
+ self.ui_connect()
self.build_ui()
return
except Exception as e:
@@ -4610,7 +4637,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# self.ui.geo_tools_table.clearSelection()
else:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Failed. Select a tool to delete."))
- self.ui.blockSignals(False)
+ self.ui_connect()
self.build_ui()
return
else:
@@ -4631,7 +4658,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
pass
self.ser_attrs.append('tools')
- self.ui.blockSignals(False)
+ self.ui_connect()
self.build_ui()
self.app.inform.emit('[success] %s' % _("Tool was deleted in Tool Table."))
@@ -4765,7 +4792,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
log.debug("FlatCAMGeometry.gui_form_to_storage() --> no tool in Tools Table, aborting.")
return
- self.ui.blockSignals(True)
+ self.ui_disconnect()
row = self.ui.geo_tools_table.currentRow()
if row < 0:
@@ -4820,7 +4847,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.tools = deepcopy(temp_tools)
temp_tools.clear()
- self.ui.blockSignals(False)
+ self.ui_connect()
def gui_form_to_storage(self):
if self.ui.geo_tools_table.rowCount() == 0:
@@ -4828,7 +4855,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
log.debug("FlatCAMGeometry.gui_form_to_storage() --> no tool in Tools Table, aborting.")
return
- self.ui.blockSignals(True)
+ self.ui_disconnect()
widget_changed = self.sender()
try:
widget_idx = self.ui.grid3.indexOf(widget_changed)
@@ -4907,7 +4934,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.tools.clear()
self.tools = deepcopy(temp_tools)
temp_tools.clear()
- self.ui.blockSignals(False)
+ self.ui_connect()
def select_tools_table_row(self, row, clearsel=None):
if clearsel:
@@ -5935,7 +5962,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.read_form_item('plot')
self.plot()
- self.ui.blockSignals(True)
+ self.ui_disconnect()
cb_flag = self.ui.plot_cb.isChecked()
for row in range(self.ui.geo_tools_table.rowCount()):
table_cb = self.ui.geo_tools_table.cellWidget(row, 6)
@@ -5943,11 +5970,11 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
table_cb.setChecked(True)
else:
table_cb.setChecked(False)
- self.ui.blockSignals(False)
+ self.ui_connect()
def on_plot_cb_click_table(self):
# self.ui.cnc_tools_table.cellWidget(row, 2).widget().setCheckState(QtCore.Qt.Unchecked)
- self.ui.blockSignals(True)
+ self.ui_disconnect()
# cw = self.sender()
# cw_index = self.ui.geo_tools_table.indexAt(cw.pos())
# cw_row = cw_index.row()
@@ -5980,7 +6007,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.plot_cb.setChecked(False)
else:
self.ui.plot_cb.setChecked(True)
- self.ui.blockSignals(False)
+ self.ui_connect()
def merge(self, geo_list, geo_final, multigeo=None):
"""
diff --git a/README.md b/README.md
index d8c3dbb6..899a10e3 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+17.01.2020
+
+- more changes to Excellon UI
+
16.01.2020
- updated/optimized the GUI in Preferences for Paint Tool and for NCC Tool
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index 5137b47d..7143de33 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -821,10 +821,74 @@ class ExcellonObjectUI(ObjectUI):
)
self.tools_box.addWidget(self.tool_data_label)
- grid1 = QtWidgets.QGridLayout()
- self.tools_box.addLayout(grid1)
- grid1.setColumnStretch(0, 0)
- grid1.setColumnStretch(1, 1)
+ self.exc_param_frame = QtWidgets.QFrame()
+ self.exc_param_frame.setContentsMargins(0, 0, 0, 0)
+ self.tools_box.addWidget(self.exc_param_frame)
+
+ self.exc_tools_box = QtWidgets.QVBoxLayout()
+ self.exc_tools_box.setContentsMargins(0, 0, 0, 0)
+ self.exc_param_frame.setLayout(self.exc_tools_box)
+
+ # #################################################################
+ # ################# GRID LAYOUT 3 ###############################
+ # #################################################################
+
+ self.grid3 = QtWidgets.QGridLayout()
+ self.grid3.setColumnStretch(0, 0)
+ self.grid3.setColumnStretch(1, 1)
+ self.exc_tools_box.addLayout(self.grid3)
+
+ # Operation Type
+ self.operation_label = QtWidgets.QLabel('%s:' % _('Operation'))
+ self.operation_label.setToolTip(
+ _("Operation type:\n"
+ "- Drilling -> will drill the drills/slots associated with this tool\n"
+ "- Milling -> will mill the drills/slots")
+ )
+ self.operation_radio = RadioSet(
+ [
+ {'label': _('Drilling'), 'value': 'drill'},
+ {'label': _("Milling"), 'value': 'mill'}
+ ]
+ )
+
+ self.grid3.addWidget(self.operation_label, 0, 0)
+ self.grid3.addWidget(self.operation_radio, 0, 1)
+
+ # separator_line = QtWidgets.QFrame()
+ # separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ # separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ # self.grid3.addWidget(separator_line, 1, 0, 1, 2)
+
+ self.mill_type_label = QtWidgets.QLabel('%s:' % _('Milling Type'))
+ self.mill_type_label.setToolTip(
+ _("Milling type:\n"
+ "- Drills -> will mill the drills associated with this tool\n"
+ "- Slots -> will mill the slots associated with this tool\n"
+ "- Both -> will mill both drills and mills or whatever is available")
+ )
+ self.mill_type_radio = RadioSet(
+ [
+ {'label': _('Drills'), 'value': 'drills'},
+ {'label': _("Slots"), 'value': 'slots'},
+ {'label': _("Both"), 'value': 'both'},
+ ]
+ )
+
+ self.grid3.addWidget(self.mill_type_label, 2, 0)
+ self.grid3.addWidget(self.mill_type_radio, 2, 1)
+
+ self.mill_dia_label = QtWidgets.QLabel('%s:' % _('Milling Diameter'))
+ self.mill_dia_label.setToolTip(
+ _("The diameter of the tool who will do the milling")
+ )
+
+ self.mill_dia_entry = FCDoubleSpinner()
+ self.mill_dia_entry.set_precision(self.decimals)
+ self.mill_dia_entry.set_range(0.0000, 9999.9999)
+
+ self.grid3.addWidget(self.mill_dia_label, 3, 0)
+ self.grid3.addWidget(self.mill_dia_entry, 3, 1)
# Cut Z
cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
@@ -832,7 +896,7 @@ class ExcellonObjectUI(ObjectUI):
_("Drill depth (negative)\n"
"below the copper surface.")
)
- grid1.addWidget(cutzlabel, 0, 0)
+
self.cutz_entry = FCDoubleSpinner()
self.cutz_entry.set_precision(self.decimals)
@@ -843,7 +907,34 @@ class ExcellonObjectUI(ObjectUI):
self.cutz_entry.setSingleStep(0.1)
- grid1.addWidget(self.cutz_entry, 0, 1)
+ self.grid3.addWidget(cutzlabel, 4, 0)
+ self.grid3.addWidget(self.cutz_entry, 4, 1)
+
+ # Multi-Depth
+ self.mpass_cb = FCCheckBox('%s:' % _("Multi-Depth"))
+ self.mpass_cb.setToolTip(
+ _(
+ "Use multiple passes to limit\n"
+ "the cut depth in each pass. Will\n"
+ "cut multiple times until Cut Z is\n"
+ "reached."
+ )
+ )
+
+ self.maxdepth_entry = FCDoubleSpinner()
+ self.maxdepth_entry.set_precision(self.decimals)
+ self.maxdepth_entry.set_range(0, 9999.9999)
+ self.maxdepth_entry.setSingleStep(0.1)
+
+ self.maxdepth_entry.setToolTip(
+ _(
+ "Depth of each pass (positive)."
+ )
+ )
+ self.mis_mpass_geo = OptionalInputSection(self.mpass_cb, [self.maxdepth_entry])
+
+ self.grid3.addWidget(self.mpass_cb, 5, 0)
+ self.grid3.addWidget(self.maxdepth_entry, 5, 1)
# Travel Z (z_move)
travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z'))
@@ -851,7 +942,7 @@ class ExcellonObjectUI(ObjectUI):
_("Tool height when travelling\n"
"across the XY plane.")
)
- grid1.addWidget(travelzlabel, 1, 0)
+
self.travelz_entry = FCDoubleSpinner()
self.travelz_entry.set_precision(self.decimals)
@@ -862,7 +953,8 @@ class ExcellonObjectUI(ObjectUI):
self.travelz_entry.setSingleStep(0.1)
- grid1.addWidget(self.travelz_entry, 1, 1)
+ self.grid3.addWidget(travelzlabel, 6, 0)
+ self.grid3.addWidget(self.travelz_entry, 6, 1)
# Tool change:
self.toolchange_cb = FCCheckBox('%s:' % _("Tool change Z"))
@@ -885,8 +977,8 @@ class ExcellonObjectUI(ObjectUI):
self.toolchangez_entry.setSingleStep(0.1)
self.ois_tcz_e = OptionalInputSection(self.toolchange_cb, [self.toolchangez_entry])
- grid1.addWidget(self.toolchange_cb, 2, 0)
- grid1.addWidget(self.toolchangez_entry, 2, 1)
+ self.grid3.addWidget(self.toolchange_cb, 8, 0)
+ self.grid3.addWidget(self.toolchangez_entry, 8, 1)
# Start move Z:
self.estartz_label = QtWidgets.QLabel('%s:' % _("Start Z"))
@@ -894,9 +986,10 @@ class ExcellonObjectUI(ObjectUI):
_("Height of the tool just after start.\n"
"Delete the value if you don't need this feature.")
)
- grid1.addWidget(self.estartz_label, 4, 0)
self.estartz_entry = FloatEntry()
- grid1.addWidget(self.estartz_entry, 4, 1)
+
+ self.grid3.addWidget(self.estartz_label, 9, 0)
+ self.grid3.addWidget(self.estartz_entry, 9, 1)
# End move Z:
self.eendz_label = QtWidgets.QLabel('%s:' % _("End move Z"))
@@ -904,7 +997,6 @@ class ExcellonObjectUI(ObjectUI):
_("Height of the tool after\n"
"the last move at the end of the job.")
)
- grid1.addWidget(self.eendz_label, 5, 0)
self.eendz_entry = FCDoubleSpinner()
self.eendz_entry.set_precision(self.decimals)
@@ -915,7 +1007,22 @@ class ExcellonObjectUI(ObjectUI):
self.eendz_entry.setSingleStep(0.1)
- grid1.addWidget(self.eendz_entry, 5, 1)
+ self.grid3.addWidget(self.eendz_label, 11, 0)
+ self.grid3.addWidget(self.eendz_entry, 11, 1)
+
+ # Feedrate X-Y
+ self.frxylabel = QtWidgets.QLabel('%s:' % _('Feedrate X-Y'))
+ self.frxylabel.setToolTip(
+ _("Cutting speed in the XY\n"
+ "plane in units per minute")
+ )
+ self.xyfeedrate_entry = FCDoubleSpinner()
+ self.xyfeedrate_entry.set_precision(self.decimals)
+ self.xyfeedrate_entry.set_range(0, 9999.9999)
+ self.xyfeedrate_entry.setSingleStep(0.1)
+
+ self.grid3.addWidget(self.frxylabel, 12, 0)
+ self.grid3.addWidget(self.xyfeedrate_entry, 12, 1)
# Excellon Feedrate Z
frlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z'))
@@ -925,13 +1032,13 @@ class ExcellonObjectUI(ObjectUI):
"So called 'Plunge' feedrate.\n"
"This is for linear move G01.")
)
- grid1.addWidget(frlabel, 6, 0)
self.feedrate_entry = FCDoubleSpinner()
self.feedrate_entry.set_precision(self.decimals)
self.feedrate_entry.set_range(0.0, 9999.9999)
self.feedrate_entry.setSingleStep(0.1)
- grid1.addWidget(self.feedrate_entry, 6, 1)
+ self.grid3.addWidget(frlabel, 14, 0)
+ self.grid3.addWidget(self.feedrate_entry, 14, 1)
# Excellon Rapid Feedrate
self.feedrate_rapid_label = QtWidgets.QLabel('%s:' % _('Feedrate Rapids'))
@@ -942,28 +1049,57 @@ class ExcellonObjectUI(ObjectUI):
"It is useful only for Marlin,\n"
"ignore for any other cases.")
)
- grid1.addWidget(self.feedrate_rapid_label, 7, 0)
self.feedrate_rapid_entry = FCDoubleSpinner()
self.feedrate_rapid_entry.set_precision(self.decimals)
self.feedrate_rapid_entry.set_range(0.0, 9999.9999)
self.feedrate_rapid_entry.setSingleStep(0.1)
- grid1.addWidget(self.feedrate_rapid_entry, 7, 1)
+ self.grid3.addWidget(self.feedrate_rapid_label, 16, 0)
+ self.grid3.addWidget(self.feedrate_rapid_entry, 16, 1)
+
# default values is to hide
self.feedrate_rapid_label.hide()
self.feedrate_rapid_entry.hide()
+ # Cut over 1st point in path
+ self.extracut_cb = FCCheckBox('%s:' % _('Re-cut'))
+ self.extracut_cb.setToolTip(
+ _("In order to remove possible\n"
+ "copper leftovers where first cut\n"
+ "meet with last cut, we generate an\n"
+ "extended cut over the first cut section.")
+ )
+
+ self.e_cut_entry = FCDoubleSpinner()
+ self.e_cut_entry.set_range(0, 99999)
+ self.e_cut_entry.set_precision(self.decimals)
+ self.e_cut_entry.setSingleStep(0.1)
+ self.e_cut_entry.setWrapping(True)
+ self.e_cut_entry.setToolTip(
+ _("In order to remove possible\n"
+ "copper leftovers where first cut\n"
+ "meet with last cut, we generate an\n"
+ "extended cut over the first cut section.")
+ )
+
+ self.ois_recut = OptionalInputSection(self.extracut_cb, [self.e_cut_entry])
+
+ self.grid3.addWidget(self.extracut_cb, 17, 0)
+ self.grid3.addWidget(self.e_cut_entry, 17, 1)
+
# Spindlespeed
spdlabel = QtWidgets.QLabel('%s:' % _('Spindle speed'))
spdlabel.setToolTip(
_("Speed of the spindle\n"
"in RPM (optional)")
)
- grid1.addWidget(spdlabel, 8, 0)
+
self.spindlespeed_entry = FCSpinner()
self.spindlespeed_entry.set_range(0, 1000000)
self.spindlespeed_entry.setSingleStep(100)
- grid1.addWidget(self.spindlespeed_entry, 8, 1)
+
+ self.grid3.addWidget(spdlabel, 19, 0)
+ self.grid3.addWidget(self.spindlespeed_entry, 19, 1)
# Dwell
self.dwell_cb = FCCheckBox('%s:' % _('Dwell'))
@@ -979,35 +1115,27 @@ class ExcellonObjectUI(ObjectUI):
self.dwelltime_entry.setToolTip(
_("Number of time units for spindle to dwell.")
)
- grid1.addWidget(self.dwell_cb, 9, 0)
- grid1.addWidget(self.dwelltime_entry, 9, 1)
+
+ self.grid3.addWidget(self.dwell_cb, 20, 0)
+ self.grid3.addWidget(self.dwelltime_entry, 20, 1)
self.ois_dwell = OptionalInputSection(self.dwell_cb, [self.dwelltime_entry])
- # preprocessor selection
- pp_excellon_label = QtWidgets.QLabel('%s:' % _("Preprocessor"))
- pp_excellon_label.setToolTip(
- _("The preprocessor JSON file that dictates\n"
- "Gcode output.")
- )
- self.pp_excellon_name_cb = FCComboBox()
- self.pp_excellon_name_cb.setFocusPolicy(QtCore.Qt.StrongFocus)
- grid1.addWidget(pp_excellon_label, 10, 0)
- grid1.addWidget(self.pp_excellon_name_cb, 10, 1)
-
# Probe depth
self.pdepth_label = QtWidgets.QLabel('%s:' % _("Probe Z depth"))
self.pdepth_label.setToolTip(
_("The maximum depth that the probe is allowed\n"
"to probe. Negative value, in current units.")
)
- grid1.addWidget(self.pdepth_label, 11, 0)
+
self.pdepth_entry = FCDoubleSpinner()
self.pdepth_entry.set_precision(self.decimals)
self.pdepth_entry.set_range(-9999.9999, 9999.9999)
self.pdepth_entry.setSingleStep(0.1)
- grid1.addWidget(self.pdepth_entry, 11, 1)
+ self.grid3.addWidget(self.pdepth_label, 22, 0)
+ self.grid3.addWidget(self.pdepth_entry, 22, 1)
+
self.pdepth_label.hide()
self.pdepth_entry.setVisible(False)
@@ -1022,21 +1150,20 @@ class ExcellonObjectUI(ObjectUI):
self.feedrate_probe_entry.set_range(0.0, 9999.9999)
self.feedrate_probe_entry.setSingleStep(0.1)
- grid1.addWidget(self.feedrate_probe_label, 12, 0)
- grid1.addWidget(self.feedrate_probe_entry, 12, 1)
+ self.grid3.addWidget(self.feedrate_probe_label, 24, 0)
+ self.grid3.addWidget(self.feedrate_probe_entry, 24, 1)
self.feedrate_probe_label.hide()
self.feedrate_probe_entry.setVisible(False)
- separator_line = QtWidgets.QFrame()
- separator_line.setFrameShape(QtWidgets.QFrame.HLine)
- separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid1.addWidget(separator_line, 13, 0, 1, 2)
+ # #################################################################
+ # ################# GRID LAYOUT 4 ###############################
+ # #################################################################
- grid2 = QtWidgets.QGridLayout()
- self.tools_box.addLayout(grid2)
- grid2.setColumnStretch(0, 0)
- grid2.setColumnStretch(1, 1)
+ self.grid4 = QtWidgets.QGridLayout()
+ self.exc_tools_box.addLayout(self.grid4)
+ self.grid4.setColumnStretch(0, 0)
+ self.grid4.setColumnStretch(1, 1)
# choose_tools_label = QtWidgets.QLabel(
# _("Select from the Tools Table above the hole dias to be\n"
@@ -1055,12 +1182,69 @@ class ExcellonObjectUI(ObjectUI):
self.excellon_gcode_type_radio = RadioSet([{'label': 'Drills', 'value': 'drills'},
{'label': 'Slots', 'value': 'slots'},
{'label': 'Both', 'value': 'both'}])
- grid2.addWidget(gcode_type_label, 1, 0)
- grid2.addWidget(self.excellon_gcode_type_radio, 1, 1)
+ self.grid4.addWidget(gcode_type_label, 1, 0)
+ self.grid4.addWidget(self.excellon_gcode_type_radio, 1, 1)
# temporary action until I finish the feature
self.excellon_gcode_type_radio.setVisible(False)
gcode_type_label.hide()
+ # #################################################################
+ # ################# GRID LAYOUT 5 ###############################
+ # #################################################################
+
+ self.grid5 = QtWidgets.QGridLayout()
+ self.grid5.setColumnStretch(0, 0)
+ self.grid5.setColumnStretch(1, 1)
+ self.exc_tools_box.addLayout(self.grid5)
+
+ separator_line2 = QtWidgets.QFrame()
+ separator_line2.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.grid5.addWidget(separator_line2, 0, 0, 1, 2)
+
+ self.apply_param_to_all = FCButton(_("Apply parameters to all tools"))
+ self.apply_param_to_all.setToolTip(
+ _("The parameters in the current form will be applied\n"
+ "on all the tools from the Tool Table.")
+ )
+ self.grid5.addWidget(self.apply_param_to_all, 1, 0, 1, 2)
+
+ separator_line2 = QtWidgets.QFrame()
+ separator_line2.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.grid5.addWidget(separator_line2, 2, 0, 1, 2)
+
+ # General Parameters
+ self.gen_param_label = QtWidgets.QLabel('%s' % _("Common Parameters"))
+ self.gen_param_label.setToolTip(
+ _("Parameters that are common for all tools.")
+ )
+ self.grid5.addWidget(self.gen_param_label, 3, 0, 1, 2)
+
+ # preprocessor selection
+ pp_excellon_label = QtWidgets.QLabel('%s:' % _("Preprocessor"))
+ pp_excellon_label.setToolTip(
+ _("The preprocessor JSON file that dictates\n"
+ "Gcode output.")
+ )
+ self.pp_excellon_name_cb = FCComboBox()
+ self.pp_excellon_name_cb.setFocusPolicy(QtCore.Qt.StrongFocus)
+ self.grid5.addWidget(pp_excellon_label, 4, 0)
+ self.grid5.addWidget(self.pp_excellon_name_cb, 4, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.grid5.addWidget(separator_line, 5, 0, 1, 2)
+
+ # #################################################################
+ # ################# GRID LAYOUT 6 ###############################
+ # #################################################################
+ self.grid6 = QtWidgets.QGridLayout()
+ self.grid6.setColumnStretch(0, 0)
+ self.grid6.setColumnStretch(1, 1)
+ self.tools_box.addLayout(self.grid6)
+
warning_lbl = QtWidgets.QLabel(
_(
"Add / Select at least one tool in the tool-table.\n"
@@ -1068,12 +1252,13 @@ class ExcellonObjectUI(ObjectUI):
"for custom selection of tools."
))
- grid2.addWidget(QtWidgets.QLabel(''), 2, 0, 1, 3)
- grid2.addWidget(warning_lbl, 3, 0, 1, 3)
+ self.grid6.addWidget(QtWidgets.QLabel(''), 1, 0, 1, 3)
+ self.grid6.addWidget(warning_lbl, 2, 0, 1, 3)
- self.generate_cnc_button = QtWidgets.QPushButton(_('Create Drills GCode'))
+ self.generate_cnc_button = QtWidgets.QPushButton(_('Generate GCode'))
self.generate_cnc_button.setToolTip(
- _("Generate the CNC Job.")
+ _("Generate the CNC Job.\n"
+ "If milling then an additional Geometry object will be created")
)
self.generate_cnc_button.setStyleSheet("""
QPushButton
@@ -1081,7 +1266,12 @@ class ExcellonObjectUI(ObjectUI):
font-weight: bold;
}
""")
- grid2.addWidget(self.generate_cnc_button, 4, 0, 1, 3)
+ self.grid6.addWidget(self.generate_cnc_button, 3, 0, 1, 3)
+
+ separator_line2 = QtWidgets.QFrame()
+ separator_line2.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.grid6.addWidget(separator_line2, 4, 0, 1, 2)
# ### Milling Holes Drills ####
self.mill_hole_label = QtWidgets.QLabel('%s' % _('Mill Holes'))
@@ -1090,7 +1280,7 @@ class ExcellonObjectUI(ObjectUI):
"Select from the Tools Table above the hole dias to be\n"
"milled. Use the # column to make the selection.")
)
- grid2.addWidget(self.mill_hole_label, 5, 0, 1, 3)
+ self.grid6.addWidget(self.mill_hole_label, 5, 0, 1, 3)
self.tdlabel = QtWidgets.QLabel('%s:' % _('Drill Tool dia'))
self.tdlabel.setToolTip(
@@ -1113,9 +1303,9 @@ class ExcellonObjectUI(ObjectUI):
}
""")
- grid2.addWidget(self.tdlabel, 6, 0)
- grid2.addWidget(self.tooldia_entry, 6, 1)
- grid2.addWidget(self.generate_milling_button, 6, 2)
+ self.grid6.addWidget(self.tdlabel, 6, 0)
+ self.grid6.addWidget(self.tooldia_entry, 6, 1)
+ self.grid6.addWidget(self.generate_milling_button, 6, 2)
self.stdlabel = QtWidgets.QLabel('%s:' % _('Slot Tool dia'))
self.stdlabel.setToolTip(
@@ -1140,9 +1330,9 @@ class ExcellonObjectUI(ObjectUI):
}
""")
- grid2.addWidget(self.stdlabel, 7, 0)
- grid2.addWidget(self.slot_tooldia_entry, 7, 1)
- grid2.addWidget(self.generate_milling_slots_button, 7, 2)
+ self.grid6.addWidget(self.stdlabel, 7, 0)
+ self.grid6.addWidget(self.slot_tooldia_entry, 7, 1)
+ self.grid6.addWidget(self.generate_milling_slots_button, 7, 2)
def hide_drills(self, state=True):
if state is True:
@@ -1332,7 +1522,7 @@ class GeometryObjectUI(ObjectUI):
self.grid1.addWidget(self.addtool_entry, 1, 1)
self.grid1.addWidget(self.addtool_btn, 1, 2)
- self.addtool_from_db_btn = QtWidgets.QPushButton(_('Add Tool from DataBase'))
+ self.addtool_from_db_btn = QtWidgets.QPushButton(_('Add from DB'))
self.addtool_from_db_btn.setToolTip(
_("Add a new tool to the Tool Table\n"
"from the Tool DataBase.")
@@ -1388,7 +1578,13 @@ class GeometryObjectUI(ObjectUI):
self.geo_param_box.setContentsMargins(0, 0, 0, 0)
self.geo_param_frame.setLayout(self.geo_param_box)
+ # #################################################################
+ # ################# GRID LAYOUT 3 ###############################
+ # #################################################################
+
self.grid3 = QtWidgets.QGridLayout()
+ self.grid3.setColumnStretch(0, 0)
+ self.grid3.setColumnStretch(1, 1)
self.geo_param_box.addLayout(self.grid3)
# Tip Dia
@@ -1655,18 +1851,6 @@ class GeometryObjectUI(ObjectUI):
self.grid3.addWidget(self.dwell_cb, 15, 0)
self.grid3.addWidget(self.dwelltime_entry, 15, 1)
- # preprocessor selection
- pp_label = QtWidgets.QLabel('%s:' % _("Preprocessor"))
- pp_label.setToolTip(
- _("The Preprocessor file that dictates\n"
- "the Machine Code (like GCode, RML, HPGL) output.")
- )
- self.pp_geometry_name_cb = FCComboBox()
- self.pp_geometry_name_cb.setFocusPolicy(QtCore.Qt.StrongFocus)
-
- self.grid3.addWidget(pp_label, 16, 0)
- self.grid3.addWidget(self.pp_geometry_name_cb, 16, 1)
-
# Probe depth
self.pdepth_label = QtWidgets.QLabel('%s:' % _("Probe Z depth"))
self.pdepth_label.setToolTip(
@@ -1700,27 +1884,59 @@ class GeometryObjectUI(ObjectUI):
self.feedrate_probe_label.hide()
self.feedrate_probe_entry.setVisible(False)
+ # #################################################################
+ # ################# GRID LAYOUT 4 ###############################
+ # #################################################################
+
+ self.grid4 = QtWidgets.QGridLayout()
+ self.grid4.setColumnStretch(0, 0)
+ self.grid4.setColumnStretch(1, 1)
+ self.geo_param_box.addLayout(self.grid4)
+
separator_line2 = QtWidgets.QFrame()
separator_line2.setFrameShape(QtWidgets.QFrame.HLine)
separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.grid3.addWidget(separator_line2, 19, 0, 1, 2)
+ self.grid4.addWidget(separator_line2, 0, 0, 1, 2)
self.apply_param_to_all = FCButton(_("Apply parameters to all tools"))
self.apply_param_to_all.setToolTip(
_("The parameters in the current form will be applied\n"
"on all the tools from the Tool Table.")
)
- self.grid3.addWidget(self.apply_param_to_all, 20, 0, 1, 2)
+ self.grid4.addWidget(self.apply_param_to_all, 1, 0, 1, 2)
- self.grid3.addWidget(QtWidgets.QLabel(''), 21, 0, 1, 2)
+ separator_line2 = QtWidgets.QFrame()
+ separator_line2.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.grid4.addWidget(separator_line2, 2, 0, 1, 2)
+ # General Parameters
+ self.gen_param_label = QtWidgets.QLabel('%s' % _("Common Parameters"))
+ self.gen_param_label.setToolTip(
+ _("Parameters that are common for all tools.")
+ )
+ self.grid4.addWidget(self.gen_param_label, 3, 0, 1, 2)
+
+ # preprocessor selection
+ pp_label = QtWidgets.QLabel('%s:' % _("Preprocessor"))
+ pp_label.setToolTip(
+ _("The Preprocessor file that dictates\n"
+ "the Machine Code (like GCode, RML, HPGL) output.")
+ )
+ self.pp_geometry_name_cb = FCComboBox()
+ self.pp_geometry_name_cb.setFocusPolicy(QtCore.Qt.StrongFocus)
+
+ self.grid4.addWidget(pp_label, 4, 0)
+ self.grid4.addWidget(self.pp_geometry_name_cb, 4, 1)
+
+ self.grid4.addWidget(QtWidgets.QLabel(''), 5, 0, 1, 2)
warning_lbl = QtWidgets.QLabel(
_(
"Add / Select at least one tool in the tool-table.\n"
"Click the header to select all, or Ctrl + LMB\n"
"for custom selection of tools."
))
- self.grid3.addWidget(warning_lbl, 22, 0, 1, 2)
+ self.grid4.addWidget(warning_lbl, 6, 0, 1, 2)
# Button
self.generate_cnc_button = QtWidgets.QPushButton(_('Generate CNCJob object'))
@@ -1733,9 +1949,9 @@ class GeometryObjectUI(ObjectUI):
font-weight: bold;
}
""")
- self.grid3.addWidget(self.generate_cnc_button, 23, 0, 1, 2)
+ self.grid4.addWidget(self.generate_cnc_button, 7, 0, 1, 2)
- self.grid3.addWidget(QtWidgets.QLabel(''), 24, 0, 1, 2)
+ self.grid4.addWidget(QtWidgets.QLabel(''), 8, 0, 1, 2)
# ##############
# Paint area ##
@@ -1744,7 +1960,7 @@ class GeometryObjectUI(ObjectUI):
self.tools_label.setToolTip(
_("Launch Paint Tool in Tools Tab.")
)
- self.grid3.addWidget(self.tools_label, 25, 0, 1, 2)
+ self.grid4.addWidget(self.tools_label, 10, 0, 1, 2)
# Paint Button
self.paint_tool_button = QtWidgets.QPushButton(_('Paint Tool'))
@@ -1762,7 +1978,7 @@ class GeometryObjectUI(ObjectUI):
font-weight: bold;
}
""")
- self.grid3.addWidget(self.paint_tool_button, 26, 0, 1, 2)
+ self.grid4.addWidget(self.paint_tool_button, 12, 0, 1, 2)
# NCC Tool
self.generate_ncc_button = QtWidgets.QPushButton(_('NCC Tool'))
@@ -1776,7 +1992,7 @@ class GeometryObjectUI(ObjectUI):
font-weight: bold;
}
""")
- self.grid3.addWidget(self.generate_ncc_button, 27, 0, 1, 2)
+ self.grid4.addWidget(self.generate_ncc_button, 13, 0, 1, 2)
class CNCObjectUI(ObjectUI):
From eae5b3d8e3cea60a6fb6b896775e110a983a0bd3 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 17 Jan 2020 03:42:50 +0200
Subject: [PATCH 031/209] - changes to Geometry UI
---
README.md | 1 +
flatcamGUI/ObjectUI.py | 21 +++++++++++++++++----
2 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 899a10e3..204ff374 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
17.01.2020
- more changes to Excellon UI
+- changes to Geometry UI
16.01.2020
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index 7143de33..807b9cf3 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -1503,6 +1503,14 @@ class GeometryObjectUI(ObjectUI):
self.grid1.addWidget(self.tool_offset_lbl, 0, 0)
self.grid1.addWidget(self.tool_offset_entry, 0, 1, 1, 2)
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.grid1.addWidget(separator_line, 1, 0, 1, 3)
+
+ self.tool_sel_label = QtWidgets.QLabel('%s' % _("New Tool"))
+ self.grid1.addWidget(self.tool_sel_label, 2, 0, 1, 3)
+
self.addtool_entry_lbl = QtWidgets.QLabel('%s:' % _('Tool Dia'))
self.addtool_entry_lbl.setToolTip(
_("Diameter for the new tool")
@@ -1518,16 +1526,21 @@ class GeometryObjectUI(ObjectUI):
"with the specified diameter.")
)
- self.grid1.addWidget(self.addtool_entry_lbl, 1, 0)
- self.grid1.addWidget(self.addtool_entry, 1, 1)
- self.grid1.addWidget(self.addtool_btn, 1, 2)
+ self.grid1.addWidget(self.addtool_entry_lbl, 3, 0)
+ self.grid1.addWidget(self.addtool_entry, 3, 1)
+ self.grid1.addWidget(self.addtool_btn, 3, 2)
self.addtool_from_db_btn = QtWidgets.QPushButton(_('Add from DB'))
self.addtool_from_db_btn.setToolTip(
_("Add a new tool to the Tool Table\n"
"from the Tool DataBase.")
)
- self.grid1.addWidget(self.addtool_from_db_btn, 2, 0, 1, 3)
+ self.grid1.addWidget(self.addtool_from_db_btn, 4, 0, 1, 3)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.grid1.addWidget(separator_line, 5, 0, 1, 3)
grid2 = QtWidgets.QGridLayout()
self.geo_tools_box.addLayout(grid2)
From 316b04a56a5976d7f3f9b8b480f5e271456a514b Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 17 Jan 2020 03:44:34 +0200
Subject: [PATCH 032/209] - wip
---
flatcamGUI/ObjectUI.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index 807b9cf3..3d97ccb6 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -1255,7 +1255,7 @@ class ExcellonObjectUI(ObjectUI):
self.grid6.addWidget(QtWidgets.QLabel(''), 1, 0, 1, 3)
self.grid6.addWidget(warning_lbl, 2, 0, 1, 3)
- self.generate_cnc_button = QtWidgets.QPushButton(_('Generate GCode'))
+ self.generate_cnc_button = QtWidgets.QPushButton(_('Generate CNCJob object'))
self.generate_cnc_button.setToolTip(
_("Generate the CNC Job.\n"
"If milling then an additional Geometry object will be created")
From 6c43ffca1edf6233643ba34943f6afa3178bef56 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 17 Jan 2020 17:02:49 +0200
Subject: [PATCH 033/209] - more work in NCC Tool upgrade; each tool now work
with it's own set of parameters
---
FlatCAMApp.py | 8 +-
README.md | 1 +
flatcamTools/ToolNonCopperClear.py | 780 +++++++++++++----------------
3 files changed, 340 insertions(+), 449 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 258c0852..60457078 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -4306,12 +4306,12 @@ class App(QtCore.QObject):
try:
if kind == 'excellon':
- obj.fill_color = self.app.defaults["excellon_plot_fill"]
- obj.outline_color = self.app.defaults["excellon_plot_line"]
+ obj.fill_color = self.defaults["excellon_plot_fill"]
+ obj.outline_color = self.defaults["excellon_plot_line"]
if kind == 'gerber':
- obj.fill_color = self.app.defaults["gerber_plot_fill"]
- obj.outline_color = self.app.defaults["gerber_plot_line"]
+ obj.fill_color = self.defaults["gerber_plot_fill"]
+ obj.outline_color = self.defaults["gerber_plot_line"]
except Exception as e:
log.warning("App.new_object() -> setting colors error. %s" % str(e))
diff --git a/README.md b/README.md
index 204ff374..e7b553e6 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- more changes to Excellon UI
- changes to Geometry UI
+- more work in NCC Tool upgrade; each tool now work with it's own set of parameters
16.01.2020
diff --git a/flatcamTools/ToolNonCopperClear.py b/flatcamTools/ToolNonCopperClear.py
index 1b0896dc..2b145606 100644
--- a/flatcamTools/ToolNonCopperClear.py
+++ b/flatcamTools/ToolNonCopperClear.py
@@ -1455,12 +1455,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.app.report_usage("on_paint_button_click")
- self.overlap = float(self.ncc_overlap_entry.get_value()) / 100.0
self.grb_circle_steps = int(self.app.defaults["gerber_circle_steps"])
- self.connect = self.ncc_connect_cb.get_value()
- self.contour = self.ncc_contour_cb.get_value()
- self.has_offset = self.ncc_choice_offset_cb.isChecked()
- self.rest = self.ncc_rest_cb.get_value()
self.obj_name = self.object_combo.currentText()
# Get source object.
@@ -1514,12 +1509,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.clear_copper(ncc_obj=self.ncc_obj,
ncctooldia=self.ncc_dia_list,
isotooldia=self.iso_dia_list,
- has_offset=self.has_offset,
- outname=self.o_name,
- overlap=self.overlap,
- connect=self.connect,
- contour=self.contour,
- rest=self.rest)
+ outname=self.o_name)
elif self.select_method == 'area':
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click the start point of the area."))
@@ -1547,12 +1537,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
sel_obj=self.bound_obj,
ncctooldia=self.ncc_dia_list,
isotooldia=self.iso_dia_list,
- has_offset=self.has_offset,
- outname=self.o_name,
- overlap=self.overlap,
- connect=self.connect,
- contour=self.contour,
- rest=self.rest)
+ outname=self.o_name)
# To be called after clicking on the plot.
def on_mouse_release(self, event):
@@ -1629,12 +1614,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
sel_obj=self.bound_obj,
ncctooldia=self.ncc_dia_list,
isotooldia=self.iso_dia_list,
- has_offset=self.has_offset,
- outname=self.o_name,
- overlap=self.overlap,
- connect=self.connect,
- contour=self.contour,
- rest=self.rest)
+ outname=self.o_name)
# called on mouse move
def on_mouse_move(self, event):
@@ -1682,73 +1662,18 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.app.draw_moving_selection_shape(old_coords=(self.cursor_pos[0], self.cursor_pos[1]),
coords=(curr_pos[0], curr_pos[1]))
- def clear_copper(self, ncc_obj,
- sel_obj=None,
- ncctooldia=None,
- isotooldia=None,
- outname=None,
- order=None,
- tools_storage=None,
- plot=True,
- run_threaded=True):
+ def get_tool_bounding_box(self, ncc_obj, sel_obj, ncc_select, ncc_margin):
"""
- Clear the excess copper from the entire object.
+ Prepare non-copper polygons.
+ Create the bounding box area from which the copper features will be subtracted
- :param ncc_obj: ncc cleared object
- :param ncctooldia: a tuple or single element made out of diameters of the tools to be used to ncc clear
- :param isotooldia: a tuple or single element made out of diameters of the tools to be used for isolation
- :param outname: name of the resulting object
- :param tools_storage: whether to use the current tools_storage self.ncc_tools or a different one.
- Usage of the different one is related to when this function is called from a TcL command.
- :param plot: if True after the job is finished the result will be plotted, else it will not.
- :param run_threaded: If True the method will be run in a threaded way suitable for GUI usage; if False it will
- run non-threaded for TclShell usage
- :return:
+ :param ncc_obj: the Gerber object to be non-copper cleared
+ :param sel_obj: the FlatCAM object to be used as a area delimitator
+ :param ncc_select: the kind of area to be copper cleared
+ :param ncc_margin: the margin around the area to be copper cleared
+ :return: an geometric element (Polygon or MultiPolygon) that specify the area to be copper cleared
"""
- if run_threaded:
- proc = self.app.proc_container.new(_("Non-Copper clearing ..."))
- else:
- self.app.proc_container.view.set_busy(_("Non-Copper clearing ..."))
- QtWidgets.QApplication.processEvents()
- # #####################################################################
- # ####### Read the parameters #########################################
- # #####################################################################
-
- units = self.app.defaults['units']
- order = order if order else self.ncc_order_radio.get_value()
-
- # determine if to use the progressive plotting
- if self.app.defaults["tools_ncc_plotting"] == 'progressive':
- prog_plot = True
- else:
- prog_plot = False
-
- if tools_storage is not None:
- tools_storage = tools_storage
- else:
- tools_storage = self.ncc_tools
-
- # ######################################################################################################
- # # Read the tooldia parameter and create a sorted list out them - they may be more than one diameter ##
- # ######################################################################################################
- sorted_tools = []
- if ncctooldia is not None:
- try:
- sorted_tools = [float(eval(dia)) for dia in ncctooldia.split(",") if dia != '']
- except AttributeError:
- if not isinstance(ncctooldia, list):
- sorted_tools = [float(ncctooldia)]
- else:
- sorted_tools = ncctooldia
- else:
- for row in range(self.tools_table.rowCount()):
- if self.tools_table.cellWidget(row, 1).currentText() == 'clear_op':
- sorted_tools.append(float(self.tools_table.item(row, 1).text()))
-
- # ##############################################################################################################
- # Prepare non-copper polygons. Create the bounding box area from which the copper features will be subtracted ##
- # ##############################################################################################################
log.debug("NCC Tool. Preparing non-copper polygons.")
self.app.inform.emit(_("NCC Tool. Preparing non-copper polygons."))
@@ -1824,6 +1749,245 @@ class NonCopperClear(FlatCAMTool, Gerber):
return 'fail'
log.debug("NCC Tool. Finished non-copper polygons.")
+ return bounding_box
+
+ def get_tool_empty_area(self, name, ncc_obj, geo_obj, isotooldia, has_offset, ncc_offset, ncc_margin,
+ bounding_box, tools_storage):
+ """
+ Calculate the empty area by subtracting the solid_geometry from the object bounding box geometry.
+
+ :param name:
+ :param ncc_obj:
+ :param geo_obj:
+ :param isotooldia:
+ :param has_offset:
+ :param ncc_offset:
+ :param ncc_margin:
+ :param bounding_box:
+ :param tools_storage:
+ :return:
+ """
+
+ log.debug("NCC Tool. Calculate 'empty' area.")
+ self.app.inform.emit(_("NCC Tool. Calculate 'empty' area."))
+
+ # a flag to signal that the isolation is broken by the bounding box in 'area' and 'box' cases
+ # will store the number of tools for which the isolation is broken
+ warning_flag = 0
+
+ if ncc_obj.kind == 'gerber' and not isotooldia:
+ # unfortunately for this function to work time efficient,
+ # if the Gerber was loaded without buffering then it require the buffering now.
+ if self.app.defaults['gerber_buffering'] == 'no':
+ sol_geo = ncc_obj.solid_geometry.buffer(0)
+ else:
+ sol_geo = ncc_obj.solid_geometry
+
+ if has_offset is True:
+ self.app.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
+ if isinstance(sol_geo, list):
+ sol_geo = MultiPolygon(sol_geo)
+ sol_geo = sol_geo.buffer(distance=ncc_offset)
+ self.app.inform.emit('[success] %s ...' % _("Buffering finished"))
+
+ empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
+ if empty == 'fail':
+ return 'fail'
+
+ if empty.is_empty:
+ self.app.inform.emit('[ERROR_NOTCL] %s' %
+ _("Could not get the extent of the area to be non copper cleared."))
+ return 'fail'
+ elif ncc_obj.kind == 'gerber' and isotooldia:
+ isolated_geo = []
+
+ # unfortunately for this function to work time efficient,
+ # if the Gerber was loaded without buffering then it require the buffering now.
+ if self.app.defaults['gerber_buffering'] == 'no':
+ self.solid_geometry = ncc_obj.solid_geometry.buffer(0)
+ else:
+ self.solid_geometry = ncc_obj.solid_geometry
+
+ # if milling type is climb then the move is counter-clockwise around features
+ milling_type = self.milling_type_radio.get_value()
+
+ for tool_iso in isotooldia:
+ new_geometry = []
+
+ if milling_type == 'cl':
+ isolated_geo = self.generate_envelope(tool_iso / 2, 1)
+ else:
+ isolated_geo = self.generate_envelope(tool_iso / 2, 0)
+
+ if isolated_geo == 'fail':
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _("Isolation geometry could not be generated."))
+ else:
+ if ncc_margin < tool_iso:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Isolation geometry is broken. Margin is less "
+ "than isolation tool diameter."))
+ try:
+ for geo_elem in isolated_geo:
+ # provide the app with a way to process the GUI events when in a blocking loop
+ QtWidgets.QApplication.processEvents()
+
+ if self.app.abort_flag:
+ # graceful abort requested by the user
+ raise FlatCAMApp.GracefulException
+
+ if isinstance(geo_elem, Polygon):
+ for ring in self.poly2rings(geo_elem):
+ new_geo = ring.intersection(bounding_box)
+ if new_geo and not new_geo.is_empty:
+ new_geometry.append(new_geo)
+ elif isinstance(geo_elem, MultiPolygon):
+ for poly in geo_elem:
+ for ring in self.poly2rings(poly):
+ new_geo = ring.intersection(bounding_box)
+ if new_geo and not new_geo.is_empty:
+ new_geometry.append(new_geo)
+ elif isinstance(geo_elem, LineString):
+ new_geo = geo_elem.intersection(bounding_box)
+ if new_geo:
+ if not new_geo.is_empty:
+ new_geometry.append(new_geo)
+ elif isinstance(geo_elem, MultiLineString):
+ for line_elem in geo_elem:
+ new_geo = line_elem.intersection(bounding_box)
+ if new_geo and not new_geo.is_empty:
+ new_geometry.append(new_geo)
+ except TypeError:
+ if isinstance(isolated_geo, Polygon):
+ for ring in self.poly2rings(isolated_geo):
+ new_geo = ring.intersection(bounding_box)
+ if new_geo:
+ if not new_geo.is_empty:
+ new_geometry.append(new_geo)
+ elif isinstance(isolated_geo, LineString):
+ new_geo = isolated_geo.intersection(bounding_box)
+ if new_geo and not new_geo.is_empty:
+ new_geometry.append(new_geo)
+ elif isinstance(isolated_geo, MultiLineString):
+ for line_elem in isolated_geo:
+ new_geo = line_elem.intersection(bounding_box)
+ if new_geo and not new_geo.is_empty:
+ new_geometry.append(new_geo)
+
+ # a MultiLineString geometry element will show that the isolation is broken for this tool
+ for geo_e in new_geometry:
+ if type(geo_e) == MultiLineString:
+ warning_flag += 1
+ break
+
+ current_uid = 0
+ for k, v in tools_storage.items():
+ if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals,
+ tool_iso)):
+ current_uid = int(k)
+ # add the solid_geometry to the current too in self.paint_tools dictionary
+ # and then reset the temporary list that stored that solid_geometry
+ v['solid_geometry'] = deepcopy(new_geometry)
+ v['data']['name'] = name
+ break
+ geo_obj.tools[current_uid] = dict(tools_storage[current_uid])
+
+ sol_geo = cascaded_union(isolated_geo)
+ if has_offset is True:
+ self.app.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
+ sol_geo = sol_geo.buffer(distance=ncc_offset)
+ self.app.inform.emit('[success] %s ...' % _("Buffering finished"))
+ empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
+ if empty == 'fail':
+ return 'fail'
+
+ if empty.is_empty:
+ self.app.inform.emit('[ERROR_NOTCL] %s' %
+ _("Isolation geometry is broken. Margin is less than isolation tool diameter."))
+ return 'fail'
+ elif ncc_obj.kind == 'geometry':
+ sol_geo = cascaded_union(ncc_obj.solid_geometry)
+ if has_offset is True:
+ self.app.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
+ sol_geo = sol_geo.buffer(distance=ncc_offset)
+ self.app.inform.emit('[success] %s ...' % _("Buffering finished"))
+ empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
+ if empty == 'fail':
+ return 'fail'
+
+ if empty.is_empty:
+ self.app.inform.emit('[ERROR_NOTCL] %s' %
+ _("Could not get the extent of the area to be non copper cleared."))
+ return 'fail'
+ else:
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _('The selected object is not suitable for copper clearing.'))
+ return 'fail'
+
+ if type(empty) is Polygon:
+ empty = MultiPolygon([empty])
+
+ log.debug("NCC Tool. Finished calculation of 'empty' area.")
+ self.app.inform.emit(_("NCC Tool. Finished calculation of 'empty' area."))
+
+ return empty, warning_flag
+
+ def clear_copper(self, ncc_obj,
+ sel_obj=None,
+ ncctooldia=None,
+ isotooldia=None,
+ outname=None,
+ order=None,
+ tools_storage=None,
+ run_threaded=True):
+ """
+ Clear the excess copper from the entire object.
+
+ :param ncc_obj: ncc cleared object
+ :param ncctooldia: a tuple or single element made out of diameters of the tools to be used to ncc clear
+ :param isotooldia: a tuple or single element made out of diameters of the tools to be used for isolation
+ :param outname: name of the resulting object
+
+ :param tools_storage: whether to use the current tools_storage self.ncc_tools or a different one.
+ Usage of the different one is related to when this function is called from a TcL command.
+
+ :param run_threaded: If True the method will be run in a threaded way suitable for GUI usage; if False it will
+ run non-threaded for TclShell usage
+ :return:
+ """
+ if run_threaded:
+ proc = self.app.proc_container.new(_("Non-Copper clearing ..."))
+ else:
+ self.app.proc_container.view.set_busy(_("Non-Copper clearing ..."))
+ QtWidgets.QApplication.processEvents()
+
+ # #####################################################################
+ # ####### Read the parameters #########################################
+ # #####################################################################
+
+ units = self.app.defaults['units']
+ order = order if order else self.ncc_order_radio.get_value()
+ ncc_select = self.reference_radio.get_value()
+ rest_machining_choice = self.ncc_rest_cb.get_value()
+
+ # determine if to use the progressive plotting
+ prog_plot = True if self.app.defaults["tools_ncc_plotting"] == 'progressive' else False
+ tools_storage = tools_storage if tools_storage is not None else self.ncc_tools
+
+ # ######################################################################################################
+ # # Read the tooldia parameter and create a sorted list out them - they may be more than one diameter ##
+ # ######################################################################################################
+ sorted_tools = []
+ if ncctooldia is not None:
+ try:
+ sorted_tools = [float(eval(dia)) for dia in ncctooldia.split(",") if dia != '']
+ except AttributeError:
+ if not isinstance(ncctooldia, list):
+ sorted_tools = [float(ncctooldia)]
+ else:
+ sorted_tools = ncctooldia
+ else:
+ for row in range(self.tools_table.rowCount()):
+ if self.tools_table.cellWidget(row, 1).currentText() == 'clear_op':
+ sorted_tools.append(float(self.tools_table.item(row, 1).text()))
+
# ########################################################################################################
# set the name for the future Geometry object
# I do it here because it is also stored inside the gen_clear_area() and gen_clear_area_rest() methods
@@ -1870,163 +2034,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
except TypeError:
tool = eval(self.app.defaults["tools_ncctools"])
- # ###################################################################################################
- # Calculate the empty area by subtracting the solid_geometry from the object bounding box geometry ##
- # ###################################################################################################
- log.debug("NCC Tool. Calculate 'empty' area.")
- self.app.inform.emit(_("NCC Tool. Calculate 'empty' area."))
-
- if ncc_obj.kind == 'gerber' and not isotooldia:
- # unfortunately for this function to work time efficient,
- # if the Gerber was loaded without buffering then it require the buffering now.
- if self.app.defaults['gerber_buffering'] == 'no':
- sol_geo = ncc_obj.solid_geometry.buffer(0)
- else:
- sol_geo = ncc_obj.solid_geometry
-
- if has_offset is True:
- app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
- sol_geo = sol_geo.buffer(distance=ncc_offset)
- app_obj.inform.emit('[success] %s ...' % _("Buffering finished"))
-
- empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
- if empty == 'fail':
- return 'fail'
-
- if empty.is_empty:
- app_obj.inform.emit('[ERROR_NOTCL] %s' %
- _("Could not get the extent of the area to be non copper cleared."))
- return 'fail'
- elif ncc_obj.kind == 'gerber' and isotooldia:
- isolated_geo = []
-
- # unfortunately for this function to work time efficient,
- # if the Gerber was loaded without buffering then it require the buffering now.
- if self.app.defaults['gerber_buffering'] == 'no':
- self.solid_geometry = ncc_obj.solid_geometry.buffer(0)
- else:
- self.solid_geometry = ncc_obj.solid_geometry
-
- # if milling type is climb then the move is counter-clockwise around features
- milling_type = self.milling_type_radio.get_value()
-
- for tool_iso in isotooldia:
- new_geometry = []
-
- if milling_type == 'cl':
- isolated_geo = self.generate_envelope(tool_iso / 2, 1)
- else:
- isolated_geo = self.generate_envelope(tool_iso / 2, 0)
-
- if isolated_geo == 'fail':
- app_obj.inform.emit('[ERROR_NOTCL] %s' % _("Isolation geometry could not be generated."))
- else:
- if ncc_margin < tool_iso:
- app_obj.inform.emit('[WARNING_NOTCL] %s' % _("Isolation geometry is broken. Margin is less "
- "than isolation tool diameter."))
- try:
- for geo_elem in isolated_geo:
- # provide the app with a way to process the GUI events when in a blocking loop
- QtWidgets.QApplication.processEvents()
-
- if self.app.abort_flag:
- # graceful abort requested by the user
- raise FlatCAMApp.GracefulException
-
- if isinstance(geo_elem, Polygon):
- for ring in self.poly2rings(geo_elem):
- new_geo = ring.intersection(bounding_box)
- if new_geo and not new_geo.is_empty:
- new_geometry.append(new_geo)
- elif isinstance(geo_elem, MultiPolygon):
- for poly in geo_elem:
- for ring in self.poly2rings(poly):
- new_geo = ring.intersection(bounding_box)
- if new_geo and not new_geo.is_empty:
- new_geometry.append(new_geo)
- elif isinstance(geo_elem, LineString):
- new_geo = geo_elem.intersection(bounding_box)
- if new_geo:
- if not new_geo.is_empty:
- new_geometry.append(new_geo)
- elif isinstance(geo_elem, MultiLineString):
- for line_elem in geo_elem:
- new_geo = line_elem.intersection(bounding_box)
- if new_geo and not new_geo.is_empty:
- new_geometry.append(new_geo)
- except TypeError:
- if isinstance(isolated_geo, Polygon):
- for ring in self.poly2rings(isolated_geo):
- new_geo = ring.intersection(bounding_box)
- if new_geo:
- if not new_geo.is_empty:
- new_geometry.append(new_geo)
- elif isinstance(isolated_geo, LineString):
- new_geo = isolated_geo.intersection(bounding_box)
- if new_geo and not new_geo.is_empty:
- new_geometry.append(new_geo)
- elif isinstance(isolated_geo, MultiLineString):
- for line_elem in isolated_geo:
- new_geo = line_elem.intersection(bounding_box)
- if new_geo and not new_geo.is_empty:
- new_geometry.append(new_geo)
-
- # a MultiLineString geometry element will show that the isolation is broken for this tool
- for geo_e in new_geometry:
- if type(geo_e) == MultiLineString:
- warning_flag += 1
- break
-
- for k, v in tools_storage.items():
- if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals,
- tool_iso)):
- current_uid = int(k)
- # add the solid_geometry to the current too in self.paint_tools dictionary
- # and then reset the temporary list that stored that solid_geometry
- v['solid_geometry'] = deepcopy(new_geometry)
- v['data']['name'] = name
- break
- geo_obj.tools[current_uid] = dict(tools_storage[current_uid])
-
- sol_geo = cascaded_union(isolated_geo)
- if has_offset is True:
- app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
- sol_geo = sol_geo.buffer(distance=ncc_offset)
- app_obj.inform.emit('[success] %s ...' % _("Buffering finished"))
- empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
- if empty == 'fail':
- return 'fail'
-
- if empty.is_empty:
- app_obj.inform.emit('[ERROR_NOTCL] %s' %
- _("Isolation geometry is broken. Margin is less than isolation tool diameter."))
- return 'fail'
-
- elif ncc_obj.kind == 'geometry':
- sol_geo = cascaded_union(ncc_obj.solid_geometry)
- if has_offset is True:
- app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
- sol_geo = sol_geo.buffer(distance=ncc_offset)
- app_obj.inform.emit('[success] %s ...' % _("Buffering finished"))
- empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
- if empty == 'fail':
- return 'fail'
-
- if empty.is_empty:
- app_obj.inform.emit('[ERROR_NOTCL] %s' %
- _("Could not get the extent of the area to be non copper cleared."))
- return 'fail'
-
- else:
- app_obj.inform.emit('[ERROR_NOTCL] %s' % _('The selected object is not suitable for copper clearing.'))
- return 'fail'
-
- if type(empty) is Polygon:
- empty = MultiPolygon([empty])
-
- log.debug("NCC Tool. Finished calculation of 'empty' area.")
- self.app.inform.emit(_("NCC Tool. Finished calculation of 'empty' area."))
-
# COPPER CLEARING #
cp = None
for tool in sorted_tools:
@@ -2043,12 +2050,36 @@ class NonCopperClear(FlatCAMTool, Gerber):
)
app_obj.proc_container.update_view_text(' %d%%' % 0)
+ tooluid = 0
+ for k, v in self.ncc_tools.items():
+ if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals, tool)):
+ tooluid = int(k)
+ break
+
+ ncc_overlap = float(self.ncc_tools[tooluid]["data"]["nccoverlap"]) / 100.0
+ ncc_margin = float(self.ncc_tools[tooluid]["data"]["nccmargin"])
+ ncc_method = self.ncc_tools[tooluid]["data"]["nccmethod"]
+ ncc_connect = self.ncc_tools[tooluid]["data"]["nccconnect"]
+ ncc_contour = self.ncc_tools[tooluid]["data"]["ncccontour"]
+ has_offset = self.ncc_tools[tooluid]["data"]["nccoffset"]
+ ncc_offset = float(self.ncc_tools[tooluid]["data"]["nccoffset_value"])
+
cleared_geo[:] = []
# Get remaining tools offset
offset -= (tool - 1e-12)
+ # Bounding box for current tool
+ bbox = self.get_tool_bounding_box(ncc_obj=ncc_obj, sel_obj=sel_obj, ncc_select=ncc_select,
+ ncc_margin=ncc_margin)
+
# Area to clear
+ empty, warning_flag = self.get_tool_empty_area(name=name, ncc_obj=ncc_obj, geo_obj=geo_obj,
+ isotooldia=isotooldia,
+ has_offset=has_offset, ncc_offset=ncc_offset,
+ ncc_margin=ncc_margin, tools_storage=tools_storage,
+ bounding_box=bbox)
+
area = empty.buffer(-offset)
try:
area = area.difference(cleared)
@@ -2087,20 +2118,20 @@ class NonCopperClear(FlatCAMTool, Gerber):
if ncc_method == 'standard':
cp = self.clear_polygon(pol, tool,
self.grb_circle_steps,
- overlap=overlap, contour=contour,
- connect=connect,
+ overlap=ncc_overlap, contour=ncc_contour,
+ connect=ncc_connect,
prog_plot=prog_plot)
elif ncc_method == 'seed':
cp = self.clear_polygon2(pol, tool,
self.grb_circle_steps,
- overlap=overlap, contour=contour,
- connect=connect,
+ overlap=ncc_overlap, contour=ncc_contour,
+ connect=ncc_connect,
prog_plot=prog_plot)
else:
cp = self.clear_polygon3(pol, tool,
self.grb_circle_steps,
- overlap=overlap, contour=contour,
- connect=connect,
+ overlap=ncc_overlap, contour=ncc_contour,
+ connect=ncc_connect,
prog_plot=prog_plot)
if cp:
cleared_geo += list(cp.get_objects())
@@ -2115,15 +2146,18 @@ class NonCopperClear(FlatCAMTool, Gerber):
if isinstance(p, Polygon):
if ncc_method == 'standard':
cp = self.clear_polygon(p, tool, self.grb_circle_steps,
- overlap=overlap, contour=contour, connect=connect,
+ overlap=ncc_overlap, contour=ncc_contour,
+ connect=ncc_connect,
prog_plot=prog_plot)
elif ncc_method == 'seed':
cp = self.clear_polygon2(p, tool, self.grb_circle_steps,
- overlap=overlap, contour=contour, connect=connect,
+ overlap=ncc_overlap, contour=ncc_contour,
+ connect=ncc_connect,
prog_plot=prog_plot)
else:
cp = self.clear_polygon3(p, tool, self.grb_circle_steps,
- overlap=overlap, contour=contour, connect=connect,
+ overlap=ncc_overlap, contour=ncc_contour,
+ connect=ncc_connect,
prog_plot=prog_plot)
if cp:
cleared_geo += list(cp.get_objects())
@@ -2155,7 +2189,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
# check if there is a geometry at all in the cleared geometry
if cleared_geo:
# Overall cleared area
- cleared = empty.buffer(-offset * (1 + overlap)).buffer(-tool / 1.999999).buffer(
+ cleared = empty.buffer(-offset * (1 + ncc_overlap)).buffer(-tool / 1.999999).buffer(
tool / 1.999999)
# clean-up cleared geo
@@ -2181,18 +2215,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.defaults["tools_ncc_plotting"] == 'progressive':
self.temp_shapes.clear(update=True)
- # # delete tools with empty geometry
- # keys_to_delete = []
- # # look for keys in the tools_storage dict that have 'solid_geometry' values empty
- # for uid in tools_storage:
- # # if the solid_geometry (type=list) is empty
- # if not tools_storage[uid]['solid_geometry']:
- # keys_to_delete.append(uid)
- #
- # # actual delete of keys from the tools_storage dict
- # for k in keys_to_delete:
- # tools_storage.pop(k, None)
-
# delete tools with empty geometry
# look for keys in the tools_storage dict that have 'solid_geometry' values empty
for uid, uid_val in list(tools_storage.items()):
@@ -2248,26 +2270,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
app_obj.poly_not_cleared = False
return "fail"
- # create the solid_geometry
- # geo_obj.solid_geometry = list()
- # for tooluid in geo_obj.tools:
- # if geo_obj.tools[tooluid]['solid_geometry']:
- # try:
- # for geo in geo_obj.tools[tooluid]['solid_geometry']:
- # geo_obj.solid_geometry.append(geo)
- # except TypeError:
- # geo_obj.solid_geometry.append(geo_obj.tools[tooluid]['solid_geometry'])
- #
# # Experimental...
# # print("Indexing...", end=' ')
# # geo_obj.make_index()
- # if warning_flag == 0:
- # self.app.inform.emit('[success] %s' % _("NCC Tool clear all done."))
- # else:
- # self.app.inform.emit('[WARNING] %s: %s %s.' % (
- # _("NCC Tool clear all done but the copper features isolation is broken for"),
- # str(warning_flag),
- # _("tools")))
# ###########################################################################################
# Initializes the new geometry object for the case of the rest-machining ####################
@@ -2300,175 +2305,57 @@ class NonCopperClear(FlatCAMTool, Gerber):
# repurposed flag for final object, geo_obj. True if it has any solid_geometry, False if not.
app_obj.poly_not_cleared = True
+
log.debug("NCC Tool. Calculate 'empty' area.")
app_obj.inform.emit("NCC Tool. Calculate 'empty' area.")
- # ###################################################################################################
- # Calculate the empty area by subtracting the solid_geometry from the object bounding box geometry ##
- # ###################################################################################################
- if ncc_obj.kind == 'gerber' and not isotooldia:
- sol_geo = ncc_obj.solid_geometry
- if has_offset is True:
- app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
- sol_geo = sol_geo.buffer(distance=ncc_offset)
- app_obj.inform.emit('[success] %s ...' % _("Buffering finished"))
- empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
- if empty == 'fail':
- return 'fail'
-
- if empty.is_empty:
- app_obj.inform.emit('[ERROR_NOTCL] %s' %
- _("Could not get the extent of the area to be non copper cleared."))
- return 'fail'
- elif ncc_obj.kind == 'gerber' and isotooldia:
- isolated_geo = []
- self.solid_geometry = ncc_obj.solid_geometry
-
- # if milling type is climb then the move is counter-clockwise around features
- milling_type = self.milling_type_radio.get_value()
-
- for tool_iso in isotooldia:
- new_geometry = []
-
- if milling_type == 'cl':
- isolated_geo = self.generate_envelope(tool_iso, 1)
- else:
- isolated_geo = self.generate_envelope(tool_iso, 0)
-
- if isolated_geo == 'fail':
- app_obj.inform.emit('[ERROR_NOTCL] %s' % _("Isolation geometry could not be generated."))
- else:
- app_obj.inform.emit('[WARNING_NOTCL] %s' % _("Isolation geometry is broken. Margin is less "
- "than isolation tool diameter."))
-
- try:
- for geo_elem in isolated_geo:
- # provide the app with a way to process the GUI events when in a blocking loop
- QtWidgets.QApplication.processEvents()
-
- if self.app.abort_flag:
- # graceful abort requested by the user
- raise FlatCAMApp.GracefulException
-
- if isinstance(geo_elem, Polygon):
- for ring in self.poly2rings(geo_elem):
- new_geo = ring.intersection(bounding_box)
- if new_geo and not new_geo.is_empty:
- new_geometry.append(new_geo)
- elif isinstance(geo_elem, MultiPolygon):
- for poly in geo_elem:
- for ring in self.poly2rings(poly):
- new_geo = ring.intersection(bounding_box)
- if new_geo and not new_geo.is_empty:
- new_geometry.append(new_geo)
- elif isinstance(geo_elem, LineString):
- new_geo = geo_elem.intersection(bounding_box)
- if new_geo:
- if not new_geo.is_empty:
- new_geometry.append(new_geo)
- elif isinstance(geo_elem, MultiLineString):
- for line_elem in geo_elem:
- new_geo = line_elem.intersection(bounding_box)
- if new_geo and not new_geo.is_empty:
- new_geometry.append(new_geo)
- except TypeError:
- try:
- if isinstance(isolated_geo, Polygon):
- for ring in self.poly2rings(isolated_geo):
- new_geo = ring.intersection(bounding_box)
- if new_geo:
- if not new_geo.is_empty:
- new_geometry.append(new_geo)
- elif isinstance(isolated_geo, LineString):
- new_geo = isolated_geo.intersection(bounding_box)
- if new_geo and not new_geo.is_empty:
- new_geometry.append(new_geo)
- elif isinstance(isolated_geo, MultiLineString):
- for line_elem in isolated_geo:
- new_geo = line_elem.intersection(bounding_box)
- if new_geo and not new_geo.is_empty:
- new_geometry.append(new_geo)
- except Exception:
- pass
-
- # a MultiLineString geometry element will show that the isolation is broken for this tool
- for geo_e in new_geometry:
- if type(geo_e) == MultiLineString:
- warning_flag += 1
- break
-
- for k, v in tools_storage.items():
- if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals,
- tool_iso)):
- current_uid = int(k)
- # add the solid_geometry to the current too in self.paint_tools dictionary
- # and then reset the temporary list that stored that solid_geometry
- v['solid_geometry'] = deepcopy(new_geometry)
- v['data']['name'] = name
- break
- geo_obj.tools[current_uid] = dict(tools_storage[current_uid])
-
- sol_geo = cascaded_union(isolated_geo)
- if has_offset is True:
- app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
- sol_geo = sol_geo.buffer(distance=ncc_offset)
- app_obj.inform.emit('[success] %s ...' % _("Buffering finished"))
- empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
- if empty == 'fail':
- return 'fail'
-
- if empty.is_empty:
- app_obj.inform.emit('[ERROR_NOTCL] %s' %
- _("Isolation geometry is broken. Margin is less than isolation tool diameter."))
- return 'fail'
-
- elif ncc_obj.kind == 'geometry':
- sol_geo = cascaded_union(ncc_obj.solid_geometry)
- if has_offset is True:
- app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
- sol_geo = sol_geo.buffer(distance=ncc_offset)
- app_obj.inform.emit('[success] %s ...' % _("Buffering finished"))
- empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
- if empty == 'fail':
- return 'fail'
-
- if empty.is_empty:
- app_obj.inform.emit('[ERROR_NOTCL] %s' %
- _("Could not get the extent of the area to be non copper cleared."))
- return 'fail'
- else:
- app_obj.inform.emit('[ERROR_NOTCL] %s' % _('The selected object is not suitable for copper clearing.'))
- return
-
- if self.app.abort_flag:
- # graceful abort requested by the user
- raise FlatCAMApp.GracefulException
-
- if type(empty) is Polygon:
- empty = MultiPolygon([empty])
-
- area = empty.buffer(0)
-
- log.debug("NCC Tool. Finished calculation of 'empty' area.")
- app_obj.inform.emit("NCC Tool. Finished calculation of 'empty' area.")
-
# Generate area for each tool
while sorted_tools:
+ log.debug("Starting geometry processing for tool: %s" % str(tool))
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
- tool = sorted_tools.pop(0)
- log.debug("Starting geometry processing for tool: %s" % str(tool))
+ # provide the app with a way to process the GUI events when in a blocking loop
+ QtWidgets.QApplication.processEvents()
app_obj.inform.emit('[success] %s = %s%s %s' % (
_('NCC Tool clearing with tool diameter'), str(tool), units.lower(), _('started.'))
)
app_obj.proc_container.update_view_text(' %d%%' % 0)
+ tool = sorted_tools.pop(0)
+
+ tooluid = 0
+ for k, v in self.ncc_tools.items():
+ if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals, tool)):
+ tooluid = int(k)
+ break
+
+ ncc_overlap = float(self.ncc_tools[tooluid]["data"]["nccoverlap"]) / 100.0
+ ncc_margin = float(self.ncc_tools[tooluid]["data"]["nccmargin"])
+ ncc_method = self.ncc_tools[tooluid]["data"]["nccmethod"]
+ ncc_connect = self.ncc_tools[tooluid]["data"]["nccconnect"]
+ ncc_contour = self.ncc_tools[tooluid]["data"]["ncccontour"]
+ has_offset = self.ncc_tools[tooluid]["data"]["nccoffset"]
+ ncc_offset = float(self.ncc_tools[tooluid]["data"]["nccoffset_value"])
+
tool_used = tool - 1e-12
cleared_geo[:] = []
+ # Bounding box for current tool
+ bbox = self.get_tool_bounding_box(ncc_obj=ncc_obj, sel_obj=sel_obj, ncc_select=ncc_select,
+ ncc_margin=ncc_margin)
+
+ # Area to clear
+ empty, warning_flag = self.get_tool_empty_area(name=name, ncc_obj=ncc_obj, geo_obj=geo_obj,
+ isotooldia=isotooldia,
+ has_offset=has_offset, ncc_offset=ncc_offset,
+ ncc_margin=ncc_margin, tools_storage=tools_storage,
+ bounding_box=bbox)
+
+ area = empty.buffer(0)
+
# Area to clear
for poly in cleared_by_last_tool:
# provide the app with a way to process the GUI events when in a blocking loop
@@ -2479,7 +2366,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
raise FlatCAMApp.GracefulException
try:
area = area.difference(poly)
- except Exception as e:
+ except Exception:
pass
cleared_by_last_tool[:] = []
@@ -2520,17 +2407,20 @@ class NonCopperClear(FlatCAMTool, Gerber):
if ncc_method == 'standard':
cp = self.clear_polygon(p, tool_used,
self.grb_circle_steps,
- overlap=overlap, contour=contour, connect=connect,
+ overlap=ncc_overlap, contour=ncc_contour,
+ connect=ncc_connect,
prog_plot=prog_plot)
elif ncc_method == 'seed':
cp = self.clear_polygon2(p, tool_used,
self.grb_circle_steps,
- overlap=overlap, contour=contour, connect=connect,
+ overlap=ncc_overlap, contour=ncc_contour,
+ connect=ncc_connect,
prog_plot=prog_plot)
else:
cp = self.clear_polygon3(p, tool_used,
self.grb_circle_steps,
- overlap=overlap, contour=contour, connect=connect,
+ overlap=ncc_overlap, contour=ncc_contour,
+ connect=ncc_connect,
prog_plot=prog_plot)
cleared_geo.append(list(cp.get_objects()))
except Exception as e:
@@ -2549,20 +2439,20 @@ class NonCopperClear(FlatCAMTool, Gerber):
if ncc_method == 'standard':
cp = self.clear_polygon(poly, tool_used,
self.grb_circle_steps,
- overlap=overlap, contour=contour,
- connect=connect,
+ overlap=ncc_overlap, contour=ncc_contour,
+ connect=ncc_connect,
prog_plot=prog_plot)
elif ncc_method == 'seed':
cp = self.clear_polygon2(poly, tool_used,
self.grb_circle_steps,
- overlap=overlap, contour=contour,
- connect=connect,
+ overlap=ncc_overlap, contour=ncc_contour,
+ connect=ncc_connect,
prog_plot=prog_plot)
else:
cp = self.clear_polygon3(poly, tool_used,
self.grb_circle_steps,
- overlap=overlap, contour=contour,
- connect=connect,
+ overlap=ncc_overlap, contour=ncc_contour,
+ connect=ncc_connect,
prog_plot=prog_plot)
cleared_geo.append(list(cp.get_objects()))
except Exception as e:
@@ -2662,9 +2552,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
def job_thread(app_obj):
try:
if rest_machining_choice is True:
- app_obj.new_object("geometry", name, gen_clear_area_rest, plot=plot)
+ app_obj.new_object("geometry", name, gen_clear_area_rest)
else:
- app_obj.new_object("geometry", name, gen_clear_area, plot=plot)
+ app_obj.new_object("geometry", name, gen_clear_area)
except FlatCAMApp.GracefulException:
if run_threaded:
proc.done()
From 0ad0dbd9ea2112bd5c5634eb16370d3baf5757fe Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 17 Jan 2020 19:31:37 +0200
Subject: [PATCH 034/209] - NCC Tool - some PEP 8 corrections
---
flatcamTools/ToolNonCopperClear.py | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/flatcamTools/ToolNonCopperClear.py b/flatcamTools/ToolNonCopperClear.py
index 2b145606..fb88a710 100644
--- a/flatcamTools/ToolNonCopperClear.py
+++ b/flatcamTools/ToolNonCopperClear.py
@@ -1796,7 +1796,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if empty.is_empty:
self.app.inform.emit('[ERROR_NOTCL] %s' %
- _("Could not get the extent of the area to be non copper cleared."))
+ _("Could not get the extent of the area to be non copper cleared."))
return 'fail'
elif ncc_obj.kind == 'gerber' and isotooldia:
isolated_geo = []
@@ -1824,7 +1824,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
else:
if ncc_margin < tool_iso:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Isolation geometry is broken. Margin is less "
- "than isolation tool diameter."))
+ "than isolation tool diameter."))
try:
for geo_elem in isolated_geo:
# provide the app with a way to process the GUI events when in a blocking loop
@@ -1901,7 +1901,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if empty.is_empty:
self.app.inform.emit('[ERROR_NOTCL] %s' %
- _("Isolation geometry is broken. Margin is less than isolation tool diameter."))
+ _("Isolation geometry is broken. Margin is less than isolation tool diameter."))
return 'fail'
elif ncc_obj.kind == 'geometry':
sol_geo = cascaded_union(ncc_obj.solid_geometry)
@@ -1915,7 +1915,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if empty.is_empty:
self.app.inform.emit('[ERROR_NOTCL] %s' %
- _("Could not get the extent of the area to be non copper cleared."))
+ _("Could not get the extent of the area to be non copper cleared."))
return 'fail'
else:
self.app.inform.emit('[ERROR_NOTCL] %s' % _('The selected object is not suitable for copper clearing.'))
@@ -1941,10 +1941,11 @@ class NonCopperClear(FlatCAMTool, Gerber):
Clear the excess copper from the entire object.
:param ncc_obj: ncc cleared object
+ :param sel_obj:
:param ncctooldia: a tuple or single element made out of diameters of the tools to be used to ncc clear
:param isotooldia: a tuple or single element made out of diameters of the tools to be used for isolation
:param outname: name of the resulting object
-
+ :param order:
:param tools_storage: whether to use the current tools_storage self.ncc_tools or a different one.
Usage of the different one is related to when this function is called from a TcL command.
@@ -2035,7 +2036,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
tool = eval(self.app.defaults["tools_ncctools"])
# COPPER CLEARING #
- cp = None
for tool in sorted_tools:
log.debug("Starting geometry processing for tool: %s" % str(tool))
if self.app.abort_flag:
@@ -2604,6 +2604,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
Clear the excess copper from the entire object. To be used only in a TCL command.
:param ncc_obj: ncc cleared object
+ :param sel_obj:
:param ncctooldia: a tuple or single element made out of diameters of the tools to be used to ncc clear
:param isotooldia: a tuple or single element made out of diameters of the tools to be used for isolation
:param overlap: value by which the paths will overlap
@@ -2946,7 +2947,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
return 'fail'
else:
- app_obj.inform.emit('[ERROR_NOTCL] %s' % _('The selected object is not suitable for copper clearing.'))
+ app_obj.inform.emit('[ERROR_NOTCL] %s' % _('The selected object is not suitable for copper clearing.'))
return 'fail'
if type(empty) is Polygon:
@@ -2956,7 +2957,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.app.inform.emit(_("NCC Tool. Finished calculation of 'empty' area."))
# COPPER CLEARING #
- cp = None
for tool in sorted_tools:
log.debug("Starting geometry processing for tool: %s" % str(tool))
if self.app.abort_flag:
@@ -3279,7 +3279,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
new_geo = line_elem.intersection(bounding_box)
if new_geo and not new_geo.is_empty:
new_geometry.append(new_geo)
- except Exception as e:
+ except Exception:
pass
# a MultiLineString geometry element will show that the isolation is broken for this tool
@@ -3424,8 +3424,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
overlap=overlap, contour=contour, connect=connect,
prog_plot=False)
cleared_geo.append(list(cp.get_objects()))
- except Exception as e:
- log.warning("Polygon can't be cleared. %s" % str(e))
+ except Exception as ee:
+ log.warning("Polygon can't be cleared. %s" % str(ee))
# this polygon should be added to a list and then try clear it with
# a smaller tool
rest_geo.append(p)
@@ -3456,8 +3456,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
connect=connect,
prog_plot=False)
cleared_geo.append(list(cp.get_objects()))
- except Exception as e:
- log.warning("Polygon can't be cleared. %s" % str(e))
+ except Exception as eee:
+ log.warning("Polygon can't be cleared. %s" % str(eee))
# this polygon should be added to a list and then try clear it with
# a smaller tool
rest_geo.append(poly)
@@ -3598,7 +3598,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
boundary = boundary
try:
ret_val = boundary.difference(target)
- except Exception as e:
+ except Exception:
try:
for el in target:
# provide the app with a way to process the GUI events when in a blocking loop
@@ -3615,7 +3615,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.app.proc_container.update_view_text(' %d%%' % disp_number)
old_disp_number = disp_number
return boundary
- except Exception as e:
+ except Exception:
self.app.inform.emit('[ERROR_NOTCL] %s' %
_("Try to use the Buffering Type = Full in Preferences -> Gerber General. "
"Reload the Gerber file after this change."))
From 36280d9f543772dce3ba1099b7844c2e4cb15d8c Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 17 Jan 2020 23:06:28 +0200
Subject: [PATCH 035/209] - some updates in NCC Tool
---
README.md | 1 +
flatcamTools/ToolNonCopperClear.py | 44 +++++++++++++++++++++++++++---
2 files changed, 41 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index e7b553e6..86a2a19b 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ CAD program, and create G-Code for Isolation routing.
- more changes to Excellon UI
- changes to Geometry UI
- more work in NCC Tool upgrade; each tool now work with it's own set of parameters
+- some updates in NCC Tool
16.01.2020
diff --git a/flatcamTools/ToolNonCopperClear.py b/flatcamTools/ToolNonCopperClear.py
index fb88a710..840e383f 100644
--- a/flatcamTools/ToolNonCopperClear.py
+++ b/flatcamTools/ToolNonCopperClear.py
@@ -669,7 +669,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
# ############################ SIGNALS ########################################
# #############################################################################
self.addtool_btn.clicked.connect(self.on_tool_add)
- self.addtool_entry.returnPressed.connect(self.on_tool_add)
+ self.addtool_entry.returnPressed.connect(self.on_tooldia_updated)
self.deltool_btn.clicked.connect(self.on_tool_delete)
self.generate_ncc_button.clicked.connect(self.on_ncc_click)
@@ -686,8 +686,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
self.reset_button.clicked.connect(self.set_tool_ui)
- self.tools_table.currentItemChanged.connect(self.on_row_selection_change)
-
def on_type_obj_index_changed(self, index):
obj_type = self.type_obj_combo.currentIndex()
self.object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
@@ -760,6 +758,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
option_changed = self.name2option[wdg_objname]
row = self.tools_table.currentRow()
+
if row < 0:
row = 0
tooluid_item = int(self.tools_table.item(row, 3).text())
@@ -882,6 +881,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
def set_tool_ui(self):
self.units = self.app.defaults['units'].upper()
+ self.old_tool_dia = self.app.defaults["tools_nccnewdia"]
self.tools_frame.show()
@@ -1079,6 +1079,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
def ui_connect(self):
self.tools_table.itemChanged.connect(self.on_tool_edit)
+ # rows selected
+ self.tools_table.clicked.connect(self.on_row_selection_change)
+ self.tools_table.horizontalHeader().sectionClicked.connect(self.on_row_selection_change)
+
for row in range(self.tools_table.rowCount()):
try:
self.tools_table.cellWidget(row, 2).currentIndexChanged.connect(self.on_tooltable_cellwidget_change)
@@ -1111,6 +1115,15 @@ class NonCopperClear(FlatCAMTool, Gerber):
except (TypeError, ValueError):
pass
+ try:
+ self.ncc_rest_cb.stateChanged.disconnect()
+ except (TypeError, ValueError):
+ pass
+ try:
+ self.ncc_order_radio.activated_custom[str].disconnect()
+ except (TypeError, ValueError):
+ pass
+
# then reconnect
for opt in self.form_fields:
current_widget = self.form_fields[opt]
@@ -1121,11 +1134,11 @@ class NonCopperClear(FlatCAMTool, Gerber):
elif isinstance(current_widget, FCDoubleSpinner):
current_widget.returnPressed.connect(self.form_to_storage)
- self.ncc_choice_offset_cb.stateChanged.connect(self.on_offset_choice)
self.ncc_rest_cb.stateChanged.connect(self.on_rest_machining_check)
self.ncc_order_radio.activated_custom[str].connect(self.on_order_changed)
def ui_disconnect(self):
+
try:
# if connected, disconnect the signal from the slot on item_changed as it creates issues
self.tools_table.itemChanged.disconnect()
@@ -1163,6 +1176,29 @@ class NonCopperClear(FlatCAMTool, Gerber):
except (TypeError, ValueError):
pass
+ try:
+ self.ncc_rest_cb.stateChanged.disconnect()
+ except (TypeError, ValueError):
+ pass
+ try:
+ self.ncc_order_radio.activated_custom[str].disconnect()
+ except (TypeError, ValueError):
+ pass
+
+ # rows selected
+ try:
+ self.tools_table.clicked.disconnect()
+ except (TypeError, AttributeError):
+ pass
+ try:
+ self.tools_table.horizontalHeader().sectionClicked.disconnect()
+ except (TypeError, AttributeError):
+ pass
+
+ def on_tooldia_updated(self):
+ if self.tool_type_radio.get_value() == 'C1':
+ self.old_tool_dia = self.addtool_entry.get_value()
+
def on_combo_box_type(self):
obj_type = self.box_combo_type.currentIndex()
self.box_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
From abc20cf0a5d21e13ffddac41322d26d01aa5ad5e Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 18 Jan 2020 01:47:48 +0200
Subject: [PATCH 036/209] - optimized the object envelope generation in the
redesigned NCC Tool
---
README.md | 1 +
flatcamTools/ToolNonCopperClear.py | 146 ++++++++++++++++++-----------
2 files changed, 93 insertions(+), 54 deletions(-)
diff --git a/README.md b/README.md
index 86a2a19b..540febd5 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ CAD program, and create G-Code for Isolation routing.
- changes to Geometry UI
- more work in NCC Tool upgrade; each tool now work with it's own set of parameters
- some updates in NCC Tool
+- optimized the object envelope generation in the redesigned NCC Tool
16.01.2020
diff --git a/flatcamTools/ToolNonCopperClear.py b/flatcamTools/ToolNonCopperClear.py
index 840e383f..7eca4da2 100644
--- a/flatcamTools/ToolNonCopperClear.py
+++ b/flatcamTools/ToolNonCopperClear.py
@@ -1698,33 +1698,19 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.app.draw_moving_selection_shape(old_coords=(self.cursor_pos[0], self.cursor_pos[1]),
coords=(curr_pos[0], curr_pos[1]))
- def get_tool_bounding_box(self, ncc_obj, sel_obj, ncc_select, ncc_margin):
- """
- Prepare non-copper polygons.
- Create the bounding box area from which the copper features will be subtracted
-
- :param ncc_obj: the Gerber object to be non-copper cleared
- :param sel_obj: the FlatCAM object to be used as a area delimitator
- :param ncc_select: the kind of area to be copper cleared
- :param ncc_margin: the margin around the area to be copper cleared
- :return: an geometric element (Polygon or MultiPolygon) that specify the area to be copper cleared
+ def envelope_object(self, ncc_obj, ncc_select, box_obj=None):
"""
- log.debug("NCC Tool. Preparing non-copper polygons.")
- self.app.inform.emit(_("NCC Tool. Preparing non-copper polygons."))
+ :param ncc_obj:
+ :param box_obj:
+ :param ncc_select:
+ :return:
+ """
+ box_kind = box_obj.kind if box_obj is not None else None
- try:
- if sel_obj is None or sel_obj == 'itself':
- ncc_sel_obj = ncc_obj
- else:
- ncc_sel_obj = sel_obj
- except Exception as e:
- log.debug("NonCopperClear.clear_copper() --> %s" % str(e))
- return 'fail'
-
- bounding_box = None
+ env_obj = None
if ncc_select == 'itself':
- geo_n = ncc_sel_obj.solid_geometry
+ geo_n = ncc_obj.solid_geometry
try:
if isinstance(geo_n, MultiPolygon):
@@ -1735,51 +1721,85 @@ class NonCopperClear(FlatCAMTool, Gerber):
else:
env_obj = cascaded_union(geo_n)
env_obj = env_obj.convex_hull
-
- bounding_box = env_obj.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre)
except Exception as e:
- log.debug("NonCopperClear.clear_copper() 'itself' --> %s" % str(e))
+ log.debug("NonCopperClear.envelope_object() 'itself' --> %s" % str(e))
self.app.inform.emit('[ERROR_NOTCL] %s' % _("No object available."))
+ return None
+ elif ncc_select == 'area':
+ env_obj = cascaded_union(self.sel_rect)
+ try:
+ __ = iter(env_obj)
+ except Exception:
+ env_obj = [env_obj]
+ elif ncc_select == 'box':
+ if box_obj is None:
+ return None, None
+
+ box_geo = box_obj.solid_geometry
+ if box_kind == 'geometry':
+ try:
+ __ = iter(box_geo)
+ env_obj = box_geo
+ except Exception:
+ env_obj = [box_geo]
+
+ elif box_kind == 'gerber':
+ box_geo = cascaded_union(box_obj.solid_geometry).convex_hull
+ ncc_geo = cascaded_union(ncc_obj.solid_geometry).convex_hull
+ env_obj = ncc_geo.intersection(box_geo)
+ else:
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _("The reference object type is not supported."))
return 'fail'
- elif ncc_select == 'area':
- geo_n = cascaded_union(self.sel_rect)
- try:
- __ = iter(geo_n)
- except Exception as e:
- log.debug("NonCopperClear.clear_copper() 'area' --> %s" % str(e))
- geo_n = [geo_n]
+ return env_obj, box_kind
+ def envelope_object_to_tool_bounding_box(self, env_obj, box_kind, ncc_select, ncc_margin):
+ """
+ Prepare non-copper polygons.
+ Create the bounding box area from which the copper features will be subtracted
+
+ :param env_obj: the Geometry to be used as bounding box after applying the ncc_margin
+ :param box_kind: "geometry" or "gerber"
+ :param ncc_select: the kind of area to be copper cleared
+ :param ncc_margin: the margin around the area to be copper cleared
+ :return: an geometric element (Polygon or MultiPolygon) that specify the area to be copper cleared
+ """
+
+ log.debug("NCC Tool. Preparing non-copper polygons.")
+ self.app.inform.emit(_("NCC Tool. Preparing non-copper polygons."))
+
+ if env_obj is None:
+ log.debug("NonCopperClear.envelope_object_to_tool_bounding_box() --> The object is None")
+ return 'fail'
+
+ bounding_box = None
+ if ncc_select == 'itself':
+ try:
+ bounding_box = env_obj.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre)
+ except Exception as e:
+ log.debug("NonCopperClear.envelope_object_to_tool_bounding_box() 'itself' --> %s" % str(e))
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _("No object available."))
+ return 'fail'
+ elif ncc_select == 'area':
geo_buff_list = []
- for poly in geo_n:
+ for poly in env_obj:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
geo_buff_list.append(poly.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre))
-
bounding_box = cascaded_union(geo_buff_list)
-
elif ncc_select == 'box':
- geo_n = ncc_sel_obj.solid_geometry
- if ncc_sel_obj.kind == 'geometry':
- try:
- __ = iter(geo_n)
- except Exception as e:
- log.debug("NonCopperClear.clear_copper() 'box' --> %s" % str(e))
- geo_n = [geo_n]
-
- geo_buff_list = []
- for poly in geo_n:
+ if box_kind == 'geometry':
+ geo_buff_list = list()
+ for poly in env_obj:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
geo_buff_list.append(poly.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre))
bounding_box = cascaded_union(geo_buff_list)
- elif ncc_sel_obj.kind == 'gerber':
- geo_n = cascaded_union(geo_n).convex_hull
- bounding_box = cascaded_union(self.ncc_obj.solid_geometry).convex_hull.intersection(geo_n)
- bounding_box = bounding_box.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre)
+ elif box_kind == 'gerber':
+ bounding_box = env_obj.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre)
else:
self.app.inform.emit('[ERROR_NOTCL] %s' % _("The reference object type is not supported."))
return 'fail'
@@ -2071,6 +2091,15 @@ class NonCopperClear(FlatCAMTool, Gerber):
except TypeError:
tool = eval(self.app.defaults["tools_ncctools"])
+ if ncc_select == 'box':
+ env_obj, box_obj_kind = self.envelope_object(ncc_obj=ncc_obj, box_obj=sel_obj, ncc_select=ncc_select)
+ else:
+ env_obj, box_obj_kind = self.envelope_object(ncc_obj=ncc_obj, ncc_select=ncc_select)
+
+ if env_obj is None and box_obj_kind is None:
+ self.app.inform.emit("[ERROR_NOTCL] %s" % _("NCC Tool failed creating bounding box."))
+ return "fail"
+
# COPPER CLEARING #
for tool in sorted_tools:
log.debug("Starting geometry processing for tool: %s" % str(tool))
@@ -2106,8 +2135,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
offset -= (tool - 1e-12)
# Bounding box for current tool
- bbox = self.get_tool_bounding_box(ncc_obj=ncc_obj, sel_obj=sel_obj, ncc_select=ncc_select,
- ncc_margin=ncc_margin)
+ bbox = self.envelope_object_to_tool_bounding_box(env_obj=env_obj, box_kind=box_obj_kind,
+ ncc_select=ncc_select, ncc_margin=ncc_margin)
# Area to clear
empty, warning_flag = self.get_tool_empty_area(name=name, ncc_obj=ncc_obj, geo_obj=geo_obj,
@@ -2342,6 +2371,15 @@ class NonCopperClear(FlatCAMTool, Gerber):
# repurposed flag for final object, geo_obj. True if it has any solid_geometry, False if not.
app_obj.poly_not_cleared = True
+ if ncc_select == 'box':
+ env_obj, box_obj_kind = self.envelope_object(ncc_obj=ncc_obj, box_obj=sel_obj, ncc_select=ncc_select)
+ else:
+ env_obj, box_obj_kind = self.envelope_object(ncc_obj=ncc_obj, ncc_select=ncc_select)
+
+ if env_obj is None and box_obj_kind is None:
+ self.app.inform.emit("[ERROR_NOTCL] %s" % _("NCC Tool failed creating bounding box."))
+ return "fail"
+
log.debug("NCC Tool. Calculate 'empty' area.")
app_obj.inform.emit("NCC Tool. Calculate 'empty' area.")
@@ -2380,8 +2418,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
cleared_geo[:] = []
# Bounding box for current tool
- bbox = self.get_tool_bounding_box(ncc_obj=ncc_obj, sel_obj=sel_obj, ncc_select=ncc_select,
- ncc_margin=ncc_margin)
+ bbox = self.envelope_object_to_tool_bounding_box(env_obj=env_obj, box_kind=box_obj_kind,
+ ncc_select=ncc_select, ncc_margin=ncc_margin)
# Area to clear
empty, warning_flag = self.get_tool_empty_area(name=name, ncc_obj=ncc_obj, geo_obj=geo_obj,
From 24260b29b4c2652ca5a732e9c1462bc7ecc57a9c Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 19 Jan 2020 17:09:41 +0200
Subject: [PATCH 037/209] - fixed some bugs that are visible in Linux regarding
the ArgsThread class: on app close we need to quit the QThread running the
ArgsThread class and also close the opened Socket
---
FlatCAMApp.py | 8 ++++++++
README.md | 4 ++++
2 files changed, 12 insertions(+)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index dce2111f..1c843738 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -2681,6 +2681,9 @@ class App(QtCore.QObject):
from flatcamGUI.PlotCanvasLegacy import ShapeCollectionLegacy
self.tool_shapes = ShapeCollectionLegacy(obj=self, app=self, name="tool")
+ # used in the delayed shutdown self.start_delayed_quit() method
+ self.save_timer = None
+
# ###############################################################################
# ################# ADDING FlatCAM EDITORS section ##############################
# ###############################################################################
@@ -5200,6 +5203,7 @@ class App(QtCore.QObject):
del stgs
log.debug("App.final_save() --> App UI state saved.")
+ self.th.quit()
self.close_app_signal.emit()
def kill_app(self):
@@ -12654,6 +12658,10 @@ class ArgsThread(QtCore.QObject):
conn.send('close')
# close the current instance only if there are args
if len(sys.argv) > 1:
+ try:
+ listener.close()
+ except Exception:
+ pass
sys.exit()
def serve(self, conn):
diff --git a/README.md b/README.md
index 2c446e8a..e99020bc 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+19.01.2020
+
+- fixed some bugs that are visible in Linux regarding the ArgsThread class: on app close we need to quit the QThread running the ArgsThread class and also close the opened Socket
+
15.01.2020
- added key shortcuts and toolbar icons for the new tools: Align Object Tool (ALT+A) and Extract Drills (ALT+I)
From a9d69a57fe829130bf64b83e2a81fcada979afee Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 19 Jan 2020 17:39:32 +0200
Subject: [PATCH 038/209] - make sure that the fixes above apply when rebooting
app for theme change or for language change
---
FlatCAMApp.py | 23 +++++++++++++++++++----
FlatCAMTranslation.py | 6 ++++++
README.md | 1 +
3 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 1c843738..63924a09 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -5203,7 +5203,20 @@ class App(QtCore.QObject):
del stgs
log.debug("App.final_save() --> App UI state saved.")
- self.th.quit()
+
+ # try to quit the QThread that run ArgsThread class
+ try:
+ self.th.quit()
+ except Exception:
+ pass
+
+ # try to quit the Socket opened by ArgsThread class
+ try:
+ self.new_launch.listener.close()
+ except Exception:
+ pass
+
+ # quit app by signalling for self.kill_app() method
self.close_app_signal.emit()
def kill_app(self):
@@ -12644,13 +12657,15 @@ class ArgsThread(QtCore.QObject):
def __init__(self):
super(ArgsThread, self).__init__()
+ self.listener = None
+
self.start.connect(self.run)
def my_loop(self, address):
try:
- listener = Listener(*address)
+ self.listener = Listener(*address)
while True:
- conn = listener.accept()
+ conn = self.listener.accept()
self.serve(conn)
except socket.error:
conn = Client(*address)
@@ -12659,7 +12674,7 @@ class ArgsThread(QtCore.QObject):
# close the current instance only if there are args
if len(sys.argv) > 1:
try:
- listener.close()
+ self.listener.close()
except Exception:
pass
sys.exit()
diff --git a/FlatCAMTranslation.py b/FlatCAMTranslation.py
index 7db184d9..f7e75d96 100644
--- a/FlatCAMTranslation.py
+++ b/FlatCAMTranslation.py
@@ -183,6 +183,12 @@ def restart_program(app, ask=None):
else:
resource_loc = 'share'
+ # close the Socket in ArgsThread class
+ app.new_launch.listener.close()
+
+ # close the QThread that runs ArgsThread class
+ app.th.quit()
+
if app.should_we_save and app.collection.get_list() or ask is True:
msgbox = QtWidgets.QMessageBox()
msgbox.setText(_("There are files/objects modified in FlatCAM. "
diff --git a/README.md b/README.md
index e99020bc..b49bd5e4 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
19.01.2020
- fixed some bugs that are visible in Linux regarding the ArgsThread class: on app close we need to quit the QThread running the ArgsThread class and also close the opened Socket
+- make sure that the fixes above apply when rebooting app for theme change or for language change
15.01.2020
From 87faa7e8406c52944f5964352cc746defd2c133e Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 19 Jan 2020 17:47:35 +0200
Subject: [PATCH 039/209] - restored the Readme file
---
README.md | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/README.md b/README.md
index 540febd5..556d8f16 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+19.01.2020
+
+- fixed some bugs that are visible in Linux regarding the ArgsThread class: on app close we need to quit the QThread running the ArgsThread class and also close the opened Socket
+- make sure that the fixes above apply when rebooting app for theme change or for language change
+
17.01.2020
- more changes to Excellon UI
From 4047cc8499cc81d11775074cec451e401be4ec93 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 19 Jan 2020 17:55:34 +0200
Subject: [PATCH 040/209] - fixed and issue that made setting colors for the
Gerber file not possible if using a translation
---
FlatCAMApp.py | 17 ++++++++---------
README.md | 1 +
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 375601b0..3f3731ff 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -12459,33 +12459,32 @@ class App(QtCore.QObject):
def on_set_color_action_triggered(self):
new_color = self.defaults['gerber_plot_fill']
- act_name = self.sender().text().lower()
-
+ act_name = self.sender().text()
sel_obj_list = self.collection.get_selected()
if not sel_obj_list:
return
- if act_name == 'red':
+ if act_name == _('Red'):
new_color = '#FF0000' + \
str(hex(self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_slider.value())[2:])
- if act_name == 'blue':
+ if act_name == _('Blue'):
new_color = '#0000FF' + \
str(hex(self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_slider.value())[2:])
- if act_name == 'yellow':
+ if act_name == _('Yellow'):
new_color = '#FFDF00' + \
str(hex(self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_slider.value())[2:])
- if act_name == 'green':
+ if act_name == _('Green'):
new_color = '#00FF00' + \
str(hex(self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_slider.value())[2:])
- if act_name == 'purple':
+ if act_name == _('Purple'):
new_color = '#FF00FF' + \
str(hex(self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_slider.value())[2:])
- if act_name == 'brown':
+ if act_name == _('Brown'):
new_color = '#A52A2A' + \
str(hex(self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_slider.value())[2:])
- if act_name == 'custom':
+ if act_name == _('Custom'):
new_color = QtGui.QColor(self.defaults['gerber_plot_fill'][:7])
c_dialog = QtWidgets.QColorDialog()
plot_fill_color = c_dialog.getColor(initial=new_color)
diff --git a/README.md b/README.md
index 556d8f16..f8f3643c 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- fixed some bugs that are visible in Linux regarding the ArgsThread class: on app close we need to quit the QThread running the ArgsThread class and also close the opened Socket
- make sure that the fixes above apply when rebooting app for theme change or for language change
+- fixed and issue that made setting colors for the Gerber file not possible if using a translation
17.01.2020
From 5b63dee50d90c55b1a8de91b211e332dfdaedf7d Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 19 Jan 2020 19:47:42 +0200
Subject: [PATCH 041/209] - made possible to set the colors for Excellon
objects too - added to the possible colors the fundamentals: black and white
- in the project context menu for setting colors added the option to set the
transparency and also a default option which revert the color to the default
value set in the Preferences
---
FlatCAMApp.py | 84 +++++++++++++++++++++++++++++++++-------
FlatCAMObj.py | 13 ++++++-
ObjectCollection.py | 2 +-
README.md | 3 ++
flatcamGUI/FlatCAMGUI.py | 16 ++++++++
5 files changed, 101 insertions(+), 17 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 3f3731ff..9d73c0c8 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -12465,24 +12465,39 @@ class App(QtCore.QObject):
if not sel_obj_list:
return
+ # a default value, I just chose this one
+ alpha_level = 'BF'
+ for sel_obj in sel_obj_list:
+ if sel_obj.kind == 'excellon':
+ alpha_level = str(hex(
+ self.ui.excellon_defaults_form.excellon_gen_group.color_alpha_slider.value())[2:])
+ elif sel_obj.kind == 'gerber':
+ alpha_level = str(hex(self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_slider.value())[2:])
+ elif sel_obj.kind == 'geometry':
+ alpha_level = 'FF'
+ else:
+ log.debug(
+ "App.on_set_color_action_triggered() --> Default alpfa for this object type not supported yet")
+ continue
+ sel_obj.alpha_level = alpha_level
+
if act_name == _('Red'):
- new_color = '#FF0000' + \
- str(hex(self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_slider.value())[2:])
+ new_color = '#FF0000' + alpha_level
if act_name == _('Blue'):
- new_color = '#0000FF' + \
- str(hex(self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_slider.value())[2:])
+ new_color = '#0000FF' + alpha_level
+
if act_name == _('Yellow'):
- new_color = '#FFDF00' + \
- str(hex(self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_slider.value())[2:])
+ new_color = '#FFDF00' + alpha_level
if act_name == _('Green'):
- new_color = '#00FF00' + \
- str(hex(self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_slider.value())[2:])
+ new_color = '#00FF00' + alpha_level
if act_name == _('Purple'):
- new_color = '#FF00FF' + \
- str(hex(self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_slider.value())[2:])
+ new_color = '#FF00FF' + alpha_level
if act_name == _('Brown'):
- new_color = '#A52A2A' + \
- str(hex(self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_slider.value())[2:])
+ new_color = '#A52A2A' + alpha_level
+ if act_name == _('White'):
+ new_color = '#FFFFFF' + alpha_level
+ if act_name == _('Black'):
+ new_color = '#000000' + alpha_level
if act_name == _('Custom'):
new_color = QtGui.QColor(self.defaults['gerber_plot_fill'][:7])
@@ -12492,10 +12507,51 @@ class App(QtCore.QObject):
if plot_fill_color.isValid() is False:
return
- new_color = str(plot_fill_color.name()) + \
- str(hex(self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_slider.value())[2:])
+ new_color = str(plot_fill_color.name()) + alpha_level
+
+ if act_name == _("Default"):
+ for sel_obj in sel_obj_list:
+ if sel_obj.kind == 'excellon':
+ new_color = self.defaults['excellon_plot_fill']
+ new_line_color = self.defaults['excellon_plot_line']
+ elif sel_obj.kind == 'gerber':
+ new_color = self.defaults['gerber_plot_fill']
+ new_line_color = self.defaults['gerber_plot_line']
+ elif sel_obj.kind == 'geometry':
+ new_color = self.defaults['geometry_plot_line']
+ new_line_color = self.defaults['geometry_plot_line']
+ else:
+ log.debug(
+ "App.on_set_color_action_triggered() --> Default color for this object type not supported yet")
+ continue
+
+ sel_obj.fill_color = new_color
+ sel_obj.outline_color = new_line_color
+
+ sel_obj.shapes.redraw(
+ update_colors=(new_color, new_line_color)
+ )
+ return
+
+ if act_name == _("Transparency"):
+ alpha_level, ok_button = QtWidgets.QInputDialog.getInt(
+ self.ui, _("Set alpha level ..."), '%s:' % _("Value"), min=0, max=255, step=1, value=191)
+
+ if ok_button:
+
+ alpha_str = str(hex(alpha_level)[2:]) if alpha_level != 0 else '00'
+ for sel_obj in sel_obj_list:
+ sel_obj.fill_color = sel_obj.fill_color[:-2] + alpha_str
+
+ sel_obj.shapes.redraw(
+ update_colors=(sel_obj.fill_color, sel_obj.outline_color)
+ )
+
+ return
new_line_color = color_variant(new_color[:7], 0.7)
+ if act_name == _("White"):
+ new_line_color = color_variant("#dedede", 0.7)
for sel_obj in sel_obj_list:
sel_obj.fill_color = new_color
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 447090a5..37a2d4bc 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -661,6 +661,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
self.fill_color = self.app.defaults['gerber_plot_fill']
self.outline_color = self.app.defaults['gerber_plot_line']
+ self.alpha_level = 'bf'
# keep track if the UI is built so we don't have to build it every time
self.ui_build = False
@@ -671,7 +672,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
# Attributes to be included in serialization
# Always append to it because it carries contents
# from predecessors.
- self.ser_attrs += ['options', 'kind', 'fill_color', 'outline_color']
+ self.ser_attrs += ['options', 'kind', 'fill_color', 'outline_color', 'alpha_level']
def set_ui(self, ui):
"""
@@ -2297,10 +2298,14 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.multigeo = False
self.units_found = self.app.defaults['units']
+ self.fill_color = self.app.defaults['excellon_plot_fill']
+ self.outline_color = self.app.defaults['excellon_plot_line']
+ self.alpha_level = 'bf'
+
# Attributes to be included in serialization
# Always append to it because it carries contents
# from predecessors.
- self.ser_attrs += ['options', 'kind']
+ self.ser_attrs += ['options', 'kind',]
def merge(self, exc_list, exc_final):
"""
@@ -3753,6 +3758,10 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# save here the old value for the Cut Z before it is changed by selecting a V-shape type tool in the tool table
self.old_cutz = self.app.defaults["geometry_cutz"]
+ self.fill_color = self.app.defaults['geometry_plot_line']
+ self.outline_color = self.app.defaults['geometry_plot_line']
+ self.alpha_level = 'FF'
+
# Attributes to be included in serialization
# Always append to it because it carries contents
# from predecessors.
diff --git a/ObjectCollection.py b/ObjectCollection.py
index f134fc32..bf7c07dd 100644
--- a/ObjectCollection.py
+++ b/ObjectCollection.py
@@ -338,7 +338,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
self.app.ui.menuprojectcolor.setEnabled(False)
for obj in self.get_selected():
- if type(obj) == FlatCAMGerber:
+ if type(obj) == FlatCAMGerber or type(obj) == FlatCAMExcellon:
self.app.ui.menuprojectcolor.setEnabled(True)
if type(obj) != FlatCAMGeometry:
diff --git a/README.md b/README.md
index f8f3643c..da4e6eb1 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,9 @@ CAD program, and create G-Code for Isolation routing.
- fixed some bugs that are visible in Linux regarding the ArgsThread class: on app close we need to quit the QThread running the ArgsThread class and also close the opened Socket
- make sure that the fixes above apply when rebooting app for theme change or for language change
- fixed and issue that made setting colors for the Gerber file not possible if using a translation
+- made possible to set the colors for Excellon objects too
+- added to the possible colors the fundamentals: black and white
+- in the project context menu for setting colors added the option to set the transparency and also a default option which revert the color to the default value set in the Preferences
17.01.2020
diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py
index 86974e3f..9f7700d3 100644
--- a/flatcamGUI/FlatCAMGUI.py
+++ b/flatcamGUI/FlatCAMGUI.py
@@ -686,9 +686,25 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.menuproject_brown = self.menuprojectcolor.addAction(
QtGui.QIcon(self.app.resource_location + '/brown32.png'), _('Brown'))
+ self.menuproject_brown = self.menuprojectcolor.addAction(
+ QtGui.QIcon(self.app.resource_location + '/white32.png'), _('White'))
+
+ self.menuproject_brown = self.menuprojectcolor.addAction(
+ QtGui.QIcon(self.app.resource_location + '/black32.png'), _('Black'))
+
+ self.menuprojectcolor.addSeparator()
+
self.menuproject_custom = self.menuprojectcolor.addAction(
QtGui.QIcon(self.app.resource_location + '/set_color32.png'), _('Custom'))
+ self.menuprojectcolor.addSeparator()
+
+ self.menuproject_custom = self.menuprojectcolor.addAction(
+ QtGui.QIcon(self.app.resource_location + '/set_color32.png'), _('Transparency'))
+
+ self.menuproject_custom = self.menuprojectcolor.addAction(
+ QtGui.QIcon(self.app.resource_location + '/set_color32.png'), _('Default'))
+
self.menuproject.addSeparator()
self.menuprojectgeneratecnc = self.menuproject.addAction(
From 6a616168e10aa22e3d52020a3fc76c5350a77fc4 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 19 Jan 2020 19:49:34 +0200
Subject: [PATCH 042/209] - added the new icons - forgot about them in previous
commit
---
FlatCAMApp.py | 2 +-
share/black32.png | Bin 0 -> 183 bytes
share/white32.png | Bin 0 -> 189 bytes
3 files changed, 1 insertion(+), 1 deletion(-)
create mode 100644 share/black32.png
create mode 100644 share/white32.png
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 9d73c0c8..9ddc1770 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -141,7 +141,7 @@ class App(QtCore.QObject):
# ################## Version and VERSION DATE ##############################
# ##########################################################################
version = 8.992
- version_date = "2020/01/20"
+ version_date = "2020/01/22"
beta = True
engine = '3D'
diff --git a/share/black32.png b/share/black32.png
new file mode 100644
index 0000000000000000000000000000000000000000..ff19e7adb4a0102433789276f5a234b5953bf55c
GIT binary patch
literal 183
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJI!_nJkO=p;(@zUFDDbdOX7UmB
z`v3OFN+#}(#S+KQztEj{crnAhO>?Hbe13R(?ZrML{&ha7$(wqO8+P&8>)+qT?Xb8r
z?VU5Di*TykS%)vL`{fxJcn%;V2URwuNpIq8s~3e%N^?`cwQlE=SsC($uXg<|`^mI<
Xx{=~J-so-^vAN#G^%I%Em%$x@2O{)2G7*ryQe$?GQv+b?y
zg2m~FLPQf9+&67tyz=kwO8abq2A&hh$f1~d#e|f8BP*e|>Y39%R`vC8s0zO|_4Dql
cyBo*&*}p+?&N;qgK=&|sy85}Sb4q9e00=}!!T
Date: Wed, 22 Jan 2020 01:08:35 +0200
Subject: [PATCH 043/209] - fixed a bug in the bounding box generation
---
FlatCAMObj.py | 4 ++++
README.md | 4 ++++
2 files changed, 8 insertions(+)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 37a2d4bc..751063a7 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -1022,6 +1022,10 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
def geo_init(geo_obj, app_obj):
assert isinstance(geo_obj, FlatCAMGeometry)
+
+ if isinstance(self.solid_geometry, list):
+ self.solid_geometry = MultiPolygon(self.solid_geometry)
+
# Bounding box with rounded corners
bounding_box = self.solid_geometry.envelope.buffer(float(self.options["bboxmargin"]))
if not self.options["bboxrounded"]: # Remove rounded corners
diff --git a/README.md b/README.md
index da4e6eb1..8c96a14b 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+22.01.2020
+
+- fixed a bug in the bounding box generation
+
19.01.2020
- fixed some bugs that are visible in Linux regarding the ArgsThread class: on app close we need to quit the QThread running the ArgsThread class and also close the opened Socket
From ca87475694829d618bb48a3736c2d92d5e87333d Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 24 Jan 2020 22:12:15 +0200
Subject: [PATCH 044/209] - small changes to the Toolchange manual preprocessor
- fix for plotting Excellon objects if the color is changed and then the
object is moved - laying the GUI for a new Tool: Punch Gerber Tool which will
add holes in the Gerber apertures
---
FlatCAMApp.py | 5 +
FlatCAMObj.py | 23 +-
README.md | 6 +
flatcamGUI/FlatCAMGUI.py | 2 +
flatcamTools/ToolExtractDrills.py | 5 +-
flatcamTools/ToolPunchGerber.py | 373 +++++++++++++++++++++++++++++
flatcamTools/__init__.py | 1 +
preprocessors/Toolchange_manual.py | 2 +
share/punch16.png | Bin 0 -> 551 bytes
share/punch32.png | Bin 0 -> 839 bytes
10 files changed, 409 insertions(+), 8 deletions(-)
create mode 100644 flatcamTools/ToolPunchGerber.py
create mode 100644 share/punch16.png
create mode 100644 share/punch32.png
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 9ddc1770..05cc7136 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -2517,6 +2517,7 @@ class App(QtCore.QObject):
self.fiducial_tool = None
self.edrills_tool = None
self.align_objects_tool = None
+ self.punch_tool = None
# always install tools only after the shell is initialized because the self.inform.emit() depends on shell
try:
@@ -3150,6 +3151,9 @@ class App(QtCore.QObject):
self.qrcode_tool.install(icon=QtGui.QIcon(self.resource_location + '/qrcode32.png'),
pos=self.ui.menutool)
+ self.punch_tool = ToolPunchGerber(self)
+ self.punch_tool.install(icon=QtGui.QIcon(self.resource_location + '/punch32.png'), pos=self.ui.menutool)
+
self.transform_tool = ToolTransform(self)
self.transform_tool.install(icon=QtGui.QIcon(self.resource_location + '/transform.png'),
pos=self.ui.menuoptions, separator=True)
@@ -3291,6 +3295,7 @@ class App(QtCore.QObject):
self.ui.qrcode_btn.triggered.connect(lambda: self.qrcode_tool.run(toggle=True))
self.ui.copperfill_btn.triggered.connect(lambda: self.copper_thieving_tool.run(toggle=True))
self.ui.fiducials_btn.triggered.connect(lambda: self.fiducial_tool.run(toggle=True))
+ self.ui.punch_btn.triggered.connect(lambda: self.punch_tool.run(toggle=True))
def object2editor(self):
"""
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 751063a7..8cbc596a 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -1004,15 +1004,21 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
def geo_init(geo_obj, app_obj):
assert isinstance(geo_obj, FlatCAMGeometry)
if isinstance(self.solid_geometry, list):
- self.solid_geometry = cascaded_union(self.solid_geometry)
+ try:
+ self.solid_geometry = MultiPolygon(self.solid_geometry)
+ except Exception:
+ self.solid_geometry = cascaded_union(self.solid_geometry)
bounding_box = self.solid_geometry.envelope.buffer(float(self.options["noncoppermargin"]))
if not self.options["noncopperrounded"]:
bounding_box = bounding_box.envelope
non_copper = bounding_box.difference(self.solid_geometry)
+
+ if non_copper is None or non_copper.is_empty:
+ self.app.inform.emit("[ERROR_NOTCL] %s" % _("Operation could not be done."))
+ return "fail"
geo_obj.solid_geometry = non_copper
- # TODO: Check for None
self.app.new_object("geometry", name, geo_init)
def on_generatebb_button_click(self, *args):
@@ -1024,12 +1030,19 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
assert isinstance(geo_obj, FlatCAMGeometry)
if isinstance(self.solid_geometry, list):
- self.solid_geometry = MultiPolygon(self.solid_geometry)
+ try:
+ self.solid_geometry = MultiPolygon(self.solid_geometry)
+ except Exception:
+ self.solid_geometry = cascaded_union(self.solid_geometry)
# Bounding box with rounded corners
bounding_box = self.solid_geometry.envelope.buffer(float(self.options["bboxmargin"]))
if not self.options["bboxrounded"]: # Remove rounded corners
bounding_box = bounding_box.envelope
+
+ if bounding_box is None or bounding_box.is_empty:
+ self.app.inform.emit("[ERROR_NOTCL] %s" % _("Operation could not be done."))
+ return "fail"
geo_obj.solid_geometry = bounding_box
self.app.new_object("geometry", name, geo_init)
@@ -3641,8 +3654,8 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
if self.options["solid"]:
for geo in self.solid_geometry:
self.add_shape(shape=geo,
- color=self.app.defaults["excellon_plot_line"],
- face_color=self.app.defaults["excellon_plot_fill"],
+ color=self.outline_color,
+ face_color=self.fill_color,
visible=visible,
layer=2)
else:
diff --git a/README.md b/README.md
index 8c96a14b..33637b91 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,12 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+24.02.2020
+
+- small changes to the Toolchange manual preprocessor
+- fix for plotting Excellon objects if the color is changed and then the object is moved
+- laying the GUI for a new Tool: Punch Gerber Tool which will add holes in the Gerber apertures
+
22.01.2020
- fixed a bug in the bounding box generation
diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py
index 9f7700d3..2c921197 100644
--- a/flatcamGUI/FlatCAMGUI.py
+++ b/flatcamGUI/FlatCAMGUI.py
@@ -920,6 +920,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
QtGui.QIcon(self.app.resource_location + '/fiducials_32.png'), _("Fiducials Tool"))
self.cal_btn = self.toolbartools.addAction(
QtGui.QIcon(self.app.resource_location + '/calibrate_32.png'), _("Calibration Tool"))
+ self.punch_btn = self.toolbartools.addAction(
+ QtGui.QIcon(self.app.resource_location + '/punch32.png'), _("Punch Gerber Tool"))
# ########################################################################
# ########################## Excellon Editor Toolbar# ####################
diff --git a/flatcamTools/ToolExtractDrills.py b/flatcamTools/ToolExtractDrills.py
index d75a61b5..6973aecc 100644
--- a/flatcamTools/ToolExtractDrills.py
+++ b/flatcamTools/ToolExtractDrills.py
@@ -43,8 +43,7 @@ class ToolExtractDrills(FlatCAMTool):
""")
self.layout.addWidget(title_label)
- self.empty_lb = QtWidgets.QLabel("")
- self.layout.addWidget(self.empty_lb)
+ self.layout.addWidget(QtWidgets.QLabel(""))
# ## Grid Layout
grid_lay = QtWidgets.QGridLayout()
@@ -128,7 +127,7 @@ class ToolExtractDrills(FlatCAMTool):
self.method_label = QtWidgets.QLabel('%s' % _("Method"))
grid1.addWidget(self.method_label, 2, 0, 1, 2)
- # ## Axis
+ # ## Holes Size
self.hole_size_radio = RadioSet(
[
{'label': _("Fixed Diameter"), 'value': 'fixed'},
diff --git a/flatcamTools/ToolPunchGerber.py b/flatcamTools/ToolPunchGerber.py
new file mode 100644
index 00000000..17fa3a80
--- /dev/null
+++ b/flatcamTools/ToolPunchGerber.py
@@ -0,0 +1,373 @@
+# ##########################################################
+# FlatCAM: 2D Post-processing for Manufacturing #
+# File Author: Marius Adrian Stanciu (c) #
+# Date: 1/24/2020 #
+# MIT Licence #
+# ##########################################################
+
+from PyQt5 import QtGui, QtCore, QtWidgets
+
+from FlatCAMTool import FlatCAMTool
+from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, \
+ OptionalHideInputSection, OptionalInputSection, FCComboBox
+
+from copy import deepcopy
+import logging
+from shapely.geometry import Polygon, MultiPolygon, Point
+
+from reportlab.graphics import renderPDF
+from reportlab.pdfgen import canvas
+from reportlab.graphics import renderPM
+from reportlab.lib.units import inch, mm
+from reportlab.lib.pagesizes import landscape, portrait
+
+from svglib.svglib import svg2rlg
+from xml.dom.minidom import parseString as parse_xml_string
+from lxml import etree as ET
+from io import StringIO
+
+import gettext
+import FlatCAMTranslation as fcTranslate
+import builtins
+
+fcTranslate.apply_language('strings')
+if '_' not in builtins.__dict__:
+ _ = gettext.gettext
+
+log = logging.getLogger('base')
+
+
+class ToolPunchGerber(FlatCAMTool):
+
+ toolName = _("Punch Gerber")
+
+ def __init__(self, app):
+ FlatCAMTool.__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)
+
+ # Punch Drill holes
+ self.layout.addWidget(QtWidgets.QLabel(""))
+
+ # ## Grid Layout
+ grid_lay = QtWidgets.QGridLayout()
+ self.layout.addLayout(grid_lay)
+ grid_lay.setColumnStretch(0, 1)
+ grid_lay.setColumnStretch(1, 0)
+
+ # ## Gerber Object
+ self.gerber_object_combo = QtWidgets.QComboBox()
+ self.gerber_object_combo.setModel(self.app.collection)
+ self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.gerber_object_combo.setCurrentIndex(1)
+
+ self.grb_label = QtWidgets.QLabel("%s:" % _("GERBER"))
+ self.grb_label.setToolTip('%s.' % _("Gerber into which to punch holes"))
+
+ grid_lay.addWidget(self.grb_label, 0, 0, 1, 2)
+ grid_lay.addWidget(self.gerber_object_combo, 1, 0, 1, 2)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid_lay.addWidget(separator_line, 2, 0, 1, 2)
+
+ # Grid Layout
+ grid0 = QtWidgets.QGridLayout()
+ self.layout.addLayout(grid0)
+ grid0.setColumnStretch(0, 0)
+ grid0.setColumnStretch(1, 1)
+
+ self.method_label = QtWidgets.QLabel('%s:' % _("Method"))
+ self.method_label.setToolTip(
+ _("The punch hole source can be:\n"
+ "- Excellon -> an Excellon holes center will serve as reference.\n"
+ "- Fixed Diameter -> will try to use the pads center as reference.\n"
+ "- Fixed Annular Ring -> will try to use the pads center as reference.\n"
+ "- Proportional -> will try to use the pads center as reference.\n")
+ )
+ self.method_punch = RadioSet(
+ [
+ {'label': _('Excellon'), 'value': 'exc'},
+ {'label': _("Fixed Diameter"), 'value': 'fixed'},
+ {'label': _("Fixed Annular Ring"), 'value': 'ring'},
+ {'label': _("Proportional"), 'value': 'prop'}
+ ],
+ orientation='vertical',
+ stretch=False)
+ grid0.addWidget(self.method_label, 0, 0)
+ grid0.addWidget(self.method_punch, 0, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 1, 0, 1, 2)
+
+ self.exc_label = QtWidgets.QLabel('%s' % _("Excellon"))
+ self.exc_label.setToolTip(
+ _("Remove the geometry of Excellon from the Gerber to create the holes in pads.")
+ )
+
+ self.exc_combo = QtWidgets.QComboBox()
+ self.exc_combo.setModel(self.app.collection)
+ self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
+ self.exc_combo.setCurrentIndex(1)
+
+ grid0.addWidget(self.exc_label, 2, 0, 1, 2)
+ grid0.addWidget(self.exc_combo, 3, 0, 1, 2)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 5, 0, 1, 2)
+
+ # Fixed Dia
+ self.fixed_label = QtWidgets.QLabel('%s' % _("Fixed Diameter"))
+ grid0.addWidget(self.fixed_label, 6, 0, 1, 2)
+
+ # Diameter value
+ self.dia_entry = FCDoubleSpinner()
+ self.dia_entry.set_precision(self.decimals)
+ self.dia_entry.set_range(0.0000, 9999.9999)
+
+ self.dia_label = QtWidgets.QLabel('%s:' % _("Value"))
+ self.dia_label.setToolTip(
+ _("Fixed hole diameter.")
+ )
+
+ grid0.addWidget(self.dia_label, 8, 0)
+ grid0.addWidget(self.dia_entry, 8, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 9, 0, 1, 2)
+
+ self.ring_frame = QtWidgets.QFrame()
+ self.ring_frame.setContentsMargins(0, 0, 0, 0)
+ grid0.addWidget(self.ring_frame, 10, 0, 1, 2)
+
+ self.ring_box = QtWidgets.QVBoxLayout()
+ self.ring_box.setContentsMargins(0, 0, 0, 0)
+ self.ring_frame.setLayout(self.ring_box)
+
+ # ## Grid Layout
+ grid1 = QtWidgets.QGridLayout()
+ grid1.setColumnStretch(0, 0)
+ grid1.setColumnStretch(1, 1)
+ self.ring_box.addLayout(grid1)
+
+ # Annular Ring value
+ self.ring_label = QtWidgets.QLabel('%s' % _("Fixed Annular Ring"))
+ self.ring_label.setToolTip(
+ _("The size of annular ring.\n"
+ "The copper sliver between the drill hole exterior\n"
+ "and the margin of the copper pad.")
+ )
+ grid1.addWidget(self.ring_label, 0, 0, 1, 2)
+
+ # Circular Annular Ring Value
+ self.circular_ring_label = QtWidgets.QLabel('%s:' % _("Circular"))
+ self.circular_ring_label.setToolTip(
+ _("The size of annular ring for circular pads.")
+ )
+
+ self.circular_ring_entry = FCDoubleSpinner()
+ self.circular_ring_entry.set_precision(self.decimals)
+ self.circular_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid1.addWidget(self.circular_ring_label, 1, 0)
+ grid1.addWidget(self.circular_ring_entry, 1, 1)
+
+ # Oblong Annular Ring Value
+ self.oblong_ring_label = QtWidgets.QLabel('%s:' % _("Oblong"))
+ self.oblong_ring_label.setToolTip(
+ _("The size of annular ring for oblong pads.")
+ )
+
+ self.oblong_ring_entry = FCDoubleSpinner()
+ self.oblong_ring_entry.set_precision(self.decimals)
+ self.oblong_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid1.addWidget(self.oblong_ring_label, 2, 0)
+ grid1.addWidget(self.oblong_ring_entry, 2, 1)
+
+ # Square Annular Ring Value
+ self.square_ring_label = QtWidgets.QLabel('%s:' % _("Square"))
+ self.square_ring_label.setToolTip(
+ _("The size of annular ring for square pads.")
+ )
+
+ self.square_ring_entry = FCDoubleSpinner()
+ self.square_ring_entry.set_precision(self.decimals)
+ self.square_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid1.addWidget(self.square_ring_label, 3, 0)
+ grid1.addWidget(self.square_ring_entry, 3, 1)
+
+ # Rectangular Annular Ring Value
+ self.rectangular_ring_label = QtWidgets.QLabel('%s:' % _("Rectangular"))
+ self.rectangular_ring_label.setToolTip(
+ _("The size of annular ring for rectangular pads.")
+ )
+
+ self.rectangular_ring_entry = FCDoubleSpinner()
+ self.rectangular_ring_entry.set_precision(self.decimals)
+ self.rectangular_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid1.addWidget(self.rectangular_ring_label, 4, 0)
+ grid1.addWidget(self.rectangular_ring_entry, 4, 1)
+
+ # Others Annular Ring Value
+ self.other_ring_label = QtWidgets.QLabel('%s:' % _("Others"))
+ self.other_ring_label.setToolTip(
+ _("The size of annular ring for other pads.")
+ )
+
+ self.other_ring_entry = FCDoubleSpinner()
+ self.other_ring_entry.set_precision(self.decimals)
+ self.other_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid1.addWidget(self.other_ring_label, 5, 0)
+ grid1.addWidget(self.other_ring_entry, 5, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 11, 0, 1, 2)
+
+ # Proportional value
+ self.prop_label = QtWidgets.QLabel('%s' % _("Proportional Diameter"))
+ grid0.addWidget(self.prop_label, 12, 0, 1, 2)
+
+ # Diameter value
+ self.factor_entry = FCDoubleSpinner(suffix='%')
+ self.factor_entry.set_precision(self.decimals)
+ self.factor_entry.set_range(0.0000, 100.0000)
+ self.factor_entry.setSingleStep(0.1)
+
+ self.factor_label = QtWidgets.QLabel('%s:' % _("Value"))
+ self.factor_label.setToolTip(
+ _("Proportional Diameter.\n"
+ "The drill diameter will be a fraction of the pad size.")
+ )
+
+ grid0.addWidget(self.factor_label, 13, 0)
+ grid0.addWidget(self.factor_entry, 13, 1)
+
+ separator_line3 = QtWidgets.QFrame()
+ separator_line3.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line3.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line3, 14, 0, 1, 2)
+
+ # Buttons
+ self.punch_object_button = QtWidgets.QPushButton(_("Punch Gerber"))
+ self.punch_object_button.setToolTip(
+ _("Create a Gerber object from the selected object, within\n"
+ "the specified box.")
+ )
+ self.punch_object_button.setStyleSheet("""
+ QPushButton
+ {
+ font-weight: bold;
+ }
+ """)
+ self.layout.addWidget(self.punch_object_button)
+
+ self.layout.addStretch()
+
+ # ## Reset Tool
+ self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
+ self.reset_button.setToolTip(
+ _("Will reset the tool parameters.")
+ )
+ self.reset_button.setStyleSheet("""
+ QPushButton
+ {
+ font-weight: bold;
+ }
+ """)
+ self.layout.addWidget(self.reset_button)
+
+ self.units = self.app.defaults['units']
+
+ # ## Signals
+
+ self.method_punch.activated_custom.connect(self.on_method)
+ self.reset_button.clicked.connect(self.set_tool_ui)
+
+ def run(self, toggle=True):
+ self.app.report_usage("ToolPunchGerber()")
+
+ if toggle:
+ # if the splitter is hidden, display it, else hide it but only if the current widget is the same
+ if self.app.ui.splitter.sizes()[0] == 0:
+ self.app.ui.splitter.setSizes([1, 1])
+ else:
+ try:
+ if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
+ # if tab is populated with the tool but it does not have the focus, focus on it
+ if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
+ # focus on Tool Tab
+ self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
+ else:
+ self.app.ui.splitter.setSizes([0, 1])
+ except AttributeError:
+ pass
+ else:
+ if self.app.ui.splitter.sizes()[0] == 0:
+ self.app.ui.splitter.setSizes([1, 1])
+
+ FlatCAMTool.run(self)
+
+ self.set_tool_ui()
+
+ self.app.ui.notebook.setTabText(2, _("Punch Tool"))
+
+ def install(self, icon=None, separator=None, **kwargs):
+ FlatCAMTool.install(self, icon, separator, shortcut='ALT+H', **kwargs)
+
+ def set_tool_ui(self):
+ self.reset_fields()
+
+ self.method_punch.set_value('exc')
+
+ def on_method(self, val):
+ self.exc_label.setEnabled(False)
+ self.exc_combo.setEnabled(False)
+ self.fixed_label.setEnabled(False)
+ self.dia_label.setEnabled(False)
+ self.dia_entry.setEnabled(False)
+ self.ring_frame.setEnabled(False)
+ self.prop_label.setEnabled(False)
+ self.factor_label.setEnabled(False)
+ self.factor_entry.setEnabled(False)
+
+ if val == 'exc':
+ self.exc_label.setEnabled(True)
+ self.exc_combo.setEnabled(True)
+ elif val == 'fixed':
+ self.fixed_label.setEnabled(True)
+ self.dia_label.setEnabled(True)
+ self.dia_entry.setEnabled(True)
+ elif val == 'ring':
+ self.ring_frame.setEnabled(True)
+ elif val == 'prop':
+ self.prop_label.setEnabled(True)
+ self.factor_label.setEnabled(True)
+ self.factor_entry.setEnabled(True)
+
+ def reset_fields(self):
+ self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
diff --git a/flatcamTools/__init__.py b/flatcamTools/__init__.py
index a593e6c4..b503ca38 100644
--- a/flatcamTools/__init__.py
+++ b/flatcamTools/__init__.py
@@ -38,3 +38,4 @@ from flatcamTools.ToolSolderPaste import SolderPaste
from flatcamTools.ToolSub import ToolSub
from flatcamTools.ToolTransform import ToolTransform
+from flatcamTools.ToolPunchGerber import ToolPunchGerber
diff --git a/preprocessors/Toolchange_manual.py b/preprocessors/Toolchange_manual.py
index dc7a304d..ef583a7c 100644
--- a/preprocessors/Toolchange_manual.py
+++ b/preprocessors/Toolchange_manual.py
@@ -119,6 +119,7 @@ M0
G00 Z{z_toolchange}
(MSG, Now the tool can be tightened more securely.)
M0
+(MSG, Drilling with Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills})
""".format(x_toolchange=self.coordinate_format % (p.coords_decimals, x_toolchange),
y_toolchange=self.coordinate_format % (p.coords_decimals, y_toolchange),
z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
@@ -139,6 +140,7 @@ M0
G00 Z{z_toolchange}
(MSG, Now the tool can be tightened more securely.)
M0
+(MSG, Milling with Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills})
""".format(
z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
tool=int(p.tool),
diff --git a/share/punch16.png b/share/punch16.png
new file mode 100644
index 0000000000000000000000000000000000000000..65c2581087206249e9a21e88c4d510da661ad720
GIT binary patch
literal 551
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijSl0AZa
z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+uenMVO6iP5s=4O
z;1OBOz`%C|gc+x5^GO2**-JcqUD=;7O7NPh)T;>`01AEeba4#PIA40tG@QyEbfVu4jt_*nxNsgL}qHzshJ{A-TnB^^{u<3Z#D5xHOh36
zd%v%Sz16@Et*namy>P@9den$^;><;7O&{tELB9d$78~xPD
zFLHi+M^D`0OTJzQ_oQ!EZ11vbmJd$8ly_wE!7%CSC*u7~ddfkYQ`Q0lK()j*q9i4;
zB-JXpC>2OC7#SED=o%R68kvL`8e5qfTN#^a8yHv_81!^bI)$PkH$NpatrE9}zgM)%
yfEpx0HU#IVm6RtIr81P4m+NKbWfvzW7NqLs7p2dBXCnnv#Ng@b=d#Wzp$Py-JjYuA
literal 0
HcmV?d00001
diff --git a/share/punch32.png b/share/punch32.png
new file mode 100644
index 0000000000000000000000000000000000000000..b3c130ba19b5f210fe256bfd6f5e78bd3cdf4a56
GIT binary patch
literal 839
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50
z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzZ+Rj;xUkjGiz
z5n0T@z;^_M8K-LVNdpDhOFVsD*`F{<@S5^1nR``OlaA7emy0kz^$EhkvU>Rp7
zOJ>3PCdX?EQXMIG*y8$bJ&xbO<~unr?uXxBG1X(1Rxw7}KA$4(ZV2pX
ze%F?JH_}{frz+c7PT{!4=l5tDhnp_r^5S<}x~kV_rNyF{g^xE)V!R}D|7hHai>t21
zY3p7{yuhrVBV@khT*fDxqSDL_fgzLMzuWm}t^BMn)@r`p?M0KBxxQF68_mC>{_NV1
zv~;D@X>Ze(J8jv$GU&{v1=efxSXAS_g~S!POndE?Gs~zr-ur=Gg{J-0nL2-0o1dS<
zeaCXW=n|(tD{JQZv8)T6zGy>-(q1X1@+;Lx69rX&HU0M7+kfhi(zNbdVmoSot)219
z*=3=Vq^H1Y-c?+8@&Z?@i*4rZ?)G2xC4QAbM(l&KjwtJmJB~cR^8K8c;nT*|g29#>
zf20Wg{eSE6<0Zx`j1ofAR;1lCyskXEmUaD}jYctS1wrnQTGtsEd`$9{KTzra^p#lzv6Z2Twt<0_fkC8k%RCefx%nxXX_dG&Xyn-_0X0a1YzWRzD=AMb
mN@XZ7FW1Y=%Pvk%EJ)SMFG`>N&PEETh{4m<&t;ucLK6VOOi9ZC
literal 0
HcmV?d00001
From 3ac8e960711569b2ed90672dc91bf73822c19f26 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 25 Jan 2020 01:44:44 +0200
Subject: [PATCH 045/209] - fixed bugs in Minimum Distance Tool
---
FlatCAMApp.py | 17 ++++++++++-------
README.md | 1 +
flatcamEditors/FlatCAMExcEditor.py | 2 +-
flatcamEditors/FlatCAMGeoEditor.py | 2 +-
flatcamEditors/FlatCAMGrbEditor.py | 2 +-
flatcamGUI/FlatCAMGUI.py | 2 +-
flatcamTools/ToolCalibration.py | 4 ++--
flatcamTools/ToolDistanceMin.py | 16 ++++++++++++++--
8 files changed, 31 insertions(+), 15 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 05cc7136..e6dc95ea 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -1967,7 +1967,7 @@ class App(QtCore.QObject):
self.ui.menueditdelete.triggered.connect(self.on_delete)
- self.ui.menueditcopyobject.triggered.connect(self.on_copy_object)
+ self.ui.menueditcopyobject.triggered.connect(self.on_copy_command)
self.ui.menueditconvert_any2geo.triggered.connect(self.convert_any2geo)
self.ui.menueditconvert_any2gerber.triggered.connect(self.convert_any2gerber)
@@ -2030,7 +2030,7 @@ class App(QtCore.QObject):
self.ui.menuprojectgeneratecnc.triggered.connect(lambda: self.generate_cnc_job(self.collection.get_selected()))
self.ui.menuprojectviewsource.triggered.connect(self.on_view_source)
- self.ui.menuprojectcopy.triggered.connect(self.on_copy_object)
+ self.ui.menuprojectcopy.triggered.connect(self.on_copy_command)
self.ui.menuprojectedit.triggered.connect(self.object2editor)
self.ui.menuprojectdelete.triggered.connect(self.on_delete)
@@ -2061,7 +2061,7 @@ class App(QtCore.QObject):
self.ui.clearplot.triggered.connect(self.clear_plots)
self.ui.replot.triggered.connect(self.plot_all)
- self.ui.popmenu_copy.triggered.connect(self.on_copy_object)
+ self.ui.popmenu_copy.triggered.connect(self.on_copy_command)
self.ui.popmenu_delete.triggered.connect(self.on_delete)
self.ui.popmenu_edit.triggered.connect(self.object2editor)
self.ui.popmenu_save.triggered.connect(lambda: self.editor2object())
@@ -3259,7 +3259,7 @@ class App(QtCore.QObject):
self.ui.newexc_btn.triggered.connect(self.new_excellon_object)
self.ui.editgeo_btn.triggered.connect(self.object2editor)
self.ui.update_obj_btn.triggered.connect(lambda: self.editor2object())
- self.ui.copy_btn.triggered.connect(self.on_copy_object)
+ self.ui.copy_btn.triggered.connect(self.on_copy_command)
self.ui.delete_btn.triggered.connect(self.on_delete)
self.ui.distance_btn.triggered.connect(lambda: self.distance_tool.run(toggle=True))
@@ -7540,8 +7540,8 @@ class App(QtCore.QObject):
self.inform.emit('[success] %s' % _("Done."))
return location
- def on_copy_object(self):
- self.report_usage("on_copy_object()")
+ def on_copy_command(self):
+ self.report_usage("on_copy_command()")
def initialize(obj_init, app):
obj_init.solid_geometry = deepcopy(obj.solid_geometry)
@@ -7559,7 +7559,7 @@ class App(QtCore.QObject):
if obj.tools:
obj_init.tools = deepcopy(obj.tools)
except Exception as e:
- log.debug("App.on_copy_object() --> %s" % str(e))
+ log.debug("App.on_copy_command() --> %s" % str(e))
try:
obj_init.source_file = deepcopy(obj.source_file)
@@ -7600,6 +7600,9 @@ class App(QtCore.QObject):
except Exception as e:
return "Operation failed: %s" % str(e)
+ def on_paste_command(self):
+ pass
+
def on_copy_object2(self, custom_name):
def initialize_geometry(obj_init, app):
diff --git a/README.md b/README.md
index 33637b91..a196be6e 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ CAD program, and create G-Code for Isolation routing.
- small changes to the Toolchange manual preprocessor
- fix for plotting Excellon objects if the color is changed and then the object is moved
- laying the GUI for a new Tool: Punch Gerber Tool which will add holes in the Gerber apertures
+- fixed bugs in Minimum Distance Tool
22.01.2020
diff --git a/flatcamEditors/FlatCAMExcEditor.py b/flatcamEditors/FlatCAMExcEditor.py
index b77019cd..1e621a9c 100644
--- a/flatcamEditors/FlatCAMExcEditor.py
+++ b/flatcamEditors/FlatCAMExcEditor.py
@@ -2974,7 +2974,7 @@ class FlatCAMExcEditor(QtCore.QObject):
except (TypeError, AttributeError):
pass
- self.app.ui.popmenu_copy.triggered.connect(self.app.on_copy_object)
+ self.app.ui.popmenu_copy.triggered.connect(self.app.on_copy_command)
self.app.ui.popmenu_delete.triggered.connect(self.app.on_delete)
self.app.ui.popmenu_move.triggered.connect(self.app.obj_move)
diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py
index 5b0b95b9..8e12c935 100644
--- a/flatcamEditors/FlatCAMGeoEditor.py
+++ b/flatcamEditors/FlatCAMGeoEditor.py
@@ -3553,7 +3553,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
except (TypeError, AttributeError):
pass
- self.app.ui.popmenu_copy.triggered.connect(self.app.on_copy_object)
+ self.app.ui.popmenu_copy.triggered.connect(self.app.on_copy_command)
self.app.ui.popmenu_delete.triggered.connect(self.app.on_delete)
self.app.ui.popmenu_move.triggered.connect(self.app.obj_move)
diff --git a/flatcamEditors/FlatCAMGrbEditor.py b/flatcamEditors/FlatCAMGrbEditor.py
index 5d1b4ae5..0aba714b 100644
--- a/flatcamEditors/FlatCAMGrbEditor.py
+++ b/flatcamEditors/FlatCAMGrbEditor.py
@@ -3742,7 +3742,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
except (TypeError, AttributeError):
pass
- self.app.ui.popmenu_copy.triggered.connect(self.app.on_copy_object)
+ self.app.ui.popmenu_copy.triggered.connect(self.app.on_copy_command)
self.app.ui.popmenu_delete.triggered.connect(self.app.on_delete)
self.app.ui.popmenu_move.triggered.connect(self.app.obj_move)
diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py
index 2c921197..e7a4bc68 100644
--- a/flatcamGUI/FlatCAMGUI.py
+++ b/flatcamGUI/FlatCAMGUI.py
@@ -2815,7 +2815,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.app.tools_db_tab.on_tool_copy()
return
- self.app.on_copy_object()
+ self.app.on_copy_command()
# Copy an FlatCAM object
if key == QtCore.Qt.Key_D:
diff --git a/flatcamTools/ToolCalibration.py b/flatcamTools/ToolCalibration.py
index 7e50a3c3..fa533f9e 100644
--- a/flatcamTools/ToolCalibration.py
+++ b/flatcamTools/ToolCalibration.py
@@ -1275,7 +1275,7 @@ class ToolCalibration(FlatCAMTool):
if obj.tools:
obj_init.tools = deepcopy(obj.tools)
except Exception as ee:
- log.debug("App.on_copy_object() --> %s" % str(ee))
+ log.debug("ToolCalibration.new_calibrated_object.initialize_geometry() --> %s" % str(ee))
obj_init.scale(xfactor=scalex, yfactor=scaley, point=(origin_x, origin_y))
obj_init.skew(angle_x=skewx, angle_y=skewy, point=(origin_x, origin_y))
@@ -1301,7 +1301,7 @@ class ToolCalibration(FlatCAMTool):
if obj.tools:
obj_init.tools = deepcopy(obj.tools)
except Exception as err:
- log.debug("App.on_copy_object() --> %s" % str(err))
+ log.debug("ToolCalibration.new_calibrated_object.initialize_gerber() --> %s" % str(err))
obj_init.scale(xfactor=scalex, yfactor=scaley, point=(origin_x, origin_y))
obj_init.skew(angle_x=skewx, angle_y=skewy, point=(origin_x, origin_y))
diff --git a/flatcamTools/ToolDistanceMin.py b/flatcamTools/ToolDistanceMin.py
index 9197ac58..08bfc62f 100644
--- a/flatcamTools/ToolDistanceMin.py
+++ b/flatcamTools/ToolDistanceMin.py
@@ -11,7 +11,8 @@ from flatcamGUI.VisPyVisuals import *
from flatcamGUI.GUIElements import FCEntry
from shapely.ops import nearest_points
-from shapely.geometry import Point
+from shapely.geometry import Point, MultiPolygon
+from shapely.ops import cascaded_union
import math
import logging
@@ -205,6 +206,17 @@ class DistanceMin(FlatCAMTool):
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':
@@ -278,7 +290,7 @@ class DistanceMin(FlatCAMTool):
)
if d != 0:
- self.app.inform.emit("{tx1}: {tx2} D(x) = {d_x} | D(y) = {d_y} | (tx3} = {d_z}".format(
+ self.app.inform.emit("{tx1}: {tx2} D(x) = {d_x} | D(y) = {d_y} | {tx3} = {d_z}".format(
tx1=_("MEASURING"),
tx2=_("Result"),
tx3=_("Distance"),
From 0be89a4dfbe588fc372510c8755048266aff6c1f Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 25 Jan 2020 03:19:42 +0200
Subject: [PATCH 046/209] - update in the GUI for the Punch Gerber Tool
---
README.md | 1 +
flatcamTools/ToolPunchGerber.py | 136 ++++++++++++++++++++++++--------
2 files changed, 105 insertions(+), 32 deletions(-)
diff --git a/README.md b/README.md
index a196be6e..fa51f802 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ CAD program, and create G-Code for Isolation routing.
- fix for plotting Excellon objects if the color is changed and then the object is moved
- laying the GUI for a new Tool: Punch Gerber Tool which will add holes in the Gerber apertures
- fixed bugs in Minimum Distance Tool
+- update in the GUI for the Punch Gerber Tool
22.01.2020
diff --git a/flatcamTools/ToolPunchGerber.py b/flatcamTools/ToolPunchGerber.py
index 17fa3a80..9938b14a 100644
--- a/flatcamTools/ToolPunchGerber.py
+++ b/flatcamTools/ToolPunchGerber.py
@@ -92,10 +92,10 @@ class ToolPunchGerber(FlatCAMTool):
self.method_label = QtWidgets.QLabel('%s:' % _("Method"))
self.method_label.setToolTip(
_("The punch hole source can be:\n"
- "- Excellon -> an Excellon holes center will serve as reference.\n"
- "- Fixed Diameter -> will try to use the pads center as reference.\n"
- "- Fixed Annular Ring -> will try to use the pads center as reference.\n"
- "- Proportional -> will try to use the pads center as reference.\n")
+ "- Excellon Object-> the Excellon object drills center will serve as reference.\n"
+ "- Fixed Diameter -> will try to use the pads center as reference adding fixed diameter holes.\n"
+ "- Fixed Annular Ring -> will try to keep a set annular ring.\n"
+ "- Proportional -> will make a Gerber punch hole having the diameter a percentage of the pad diameter.\n")
)
self.method_punch = RadioSet(
[
@@ -162,12 +162,6 @@ class ToolPunchGerber(FlatCAMTool):
self.ring_box.setContentsMargins(0, 0, 0, 0)
self.ring_frame.setLayout(self.ring_box)
- # ## Grid Layout
- grid1 = QtWidgets.QGridLayout()
- grid1.setColumnStretch(0, 0)
- grid1.setColumnStretch(1, 1)
- self.ring_box.addLayout(grid1)
-
# Annular Ring value
self.ring_label = QtWidgets.QLabel('%s' % _("Fixed Annular Ring"))
self.ring_label.setToolTip(
@@ -175,11 +169,21 @@ class ToolPunchGerber(FlatCAMTool):
"The copper sliver between the drill hole exterior\n"
"and the margin of the copper pad.")
)
- grid1.addWidget(self.ring_label, 0, 0, 1, 2)
+ self.ring_box.addWidget(self.ring_label)
+
+ # Select all
+ self.select_all_cb = FCCheckBox('%s' % _("ALL"))
+ self.ring_box.addWidget(self.select_all_cb)
+
+ # ## Grid Layout
+ self.grid1 = QtWidgets.QGridLayout()
+ self.grid1.setColumnStretch(0, 0)
+ self.grid1.setColumnStretch(1, 1)
+ self.ring_box.addLayout(self.grid1)
# Circular Annular Ring Value
- self.circular_ring_label = QtWidgets.QLabel('%s:' % _("Circular"))
- self.circular_ring_label.setToolTip(
+ self.circular_ring_cb = FCCheckBox('%s:' % _("Circular"))
+ self.circular_ring_cb.setToolTip(
_("The size of annular ring for circular pads.")
)
@@ -187,12 +191,14 @@ class ToolPunchGerber(FlatCAMTool):
self.circular_ring_entry.set_precision(self.decimals)
self.circular_ring_entry.set_range(0.0000, 9999.9999)
- grid1.addWidget(self.circular_ring_label, 1, 0)
- grid1.addWidget(self.circular_ring_entry, 1, 1)
+ self.c_ois = OptionalInputSection(self.circular_ring_cb, [self.circular_ring_entry])
+
+ self.grid1.addWidget(self.circular_ring_cb, 3, 0)
+ self.grid1.addWidget(self.circular_ring_entry, 3, 1)
# Oblong Annular Ring Value
- self.oblong_ring_label = QtWidgets.QLabel('%s:' % _("Oblong"))
- self.oblong_ring_label.setToolTip(
+ self.oblong_ring_cb= FCCheckBox('%s:' % _("Oblong"))
+ self.oblong_ring_cb.setToolTip(
_("The size of annular ring for oblong pads.")
)
@@ -200,12 +206,14 @@ class ToolPunchGerber(FlatCAMTool):
self.oblong_ring_entry.set_precision(self.decimals)
self.oblong_ring_entry.set_range(0.0000, 9999.9999)
- grid1.addWidget(self.oblong_ring_label, 2, 0)
- grid1.addWidget(self.oblong_ring_entry, 2, 1)
+ self.o_ois = OptionalInputSection(self.oblong_ring_cb, [self.oblong_ring_entry])
+
+ self.grid1.addWidget(self.oblong_ring_cb, 4, 0)
+ self.grid1.addWidget(self.oblong_ring_entry, 4, 1)
# Square Annular Ring Value
- self.square_ring_label = QtWidgets.QLabel('%s:' % _("Square"))
- self.square_ring_label.setToolTip(
+ self.square_ring_cb = FCCheckBox('%s:' % _("Square"))
+ self.square_ring_cb.setToolTip(
_("The size of annular ring for square pads.")
)
@@ -213,12 +221,14 @@ class ToolPunchGerber(FlatCAMTool):
self.square_ring_entry.set_precision(self.decimals)
self.square_ring_entry.set_range(0.0000, 9999.9999)
- grid1.addWidget(self.square_ring_label, 3, 0)
- grid1.addWidget(self.square_ring_entry, 3, 1)
+ self.s_ois = OptionalInputSection(self.square_ring_cb, [self.square_ring_entry])
+
+ self.grid1.addWidget(self.square_ring_cb, 5, 0)
+ self.grid1.addWidget(self.square_ring_entry, 5, 1)
# Rectangular Annular Ring Value
- self.rectangular_ring_label = QtWidgets.QLabel('%s:' % _("Rectangular"))
- self.rectangular_ring_label.setToolTip(
+ self.rectangular_ring_cb = FCCheckBox('%s:' % _("Rectangular"))
+ self.rectangular_ring_cb.setToolTip(
_("The size of annular ring for rectangular pads.")
)
@@ -226,12 +236,14 @@ class ToolPunchGerber(FlatCAMTool):
self.rectangular_ring_entry.set_precision(self.decimals)
self.rectangular_ring_entry.set_range(0.0000, 9999.9999)
- grid1.addWidget(self.rectangular_ring_label, 4, 0)
- grid1.addWidget(self.rectangular_ring_entry, 4, 1)
+ self.r_ois = OptionalInputSection(self.rectangular_ring_cb, [self.rectangular_ring_entry])
+
+ self.grid1.addWidget(self.rectangular_ring_cb, 6, 0)
+ self.grid1.addWidget(self.rectangular_ring_entry, 6, 1)
# Others Annular Ring Value
- self.other_ring_label = QtWidgets.QLabel('%s:' % _("Others"))
- self.other_ring_label.setToolTip(
+ self.other_ring_cb = FCCheckBox('%s:' % _("Others"))
+ self.other_ring_cb.setToolTip(
_("The size of annular ring for other pads.")
)
@@ -239,8 +251,10 @@ class ToolPunchGerber(FlatCAMTool):
self.other_ring_entry.set_precision(self.decimals)
self.other_ring_entry.set_range(0.0000, 9999.9999)
- grid1.addWidget(self.other_ring_label, 5, 0)
- grid1.addWidget(self.other_ring_entry, 5, 1)
+ self.ot_ois = OptionalInputSection(self.other_ring_cb, [self.other_ring_entry])
+
+ self.grid1.addWidget(self.other_ring_cb, 7, 0)
+ self.grid1.addWidget(self.other_ring_entry, 7, 1)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
@@ -302,8 +316,12 @@ class ToolPunchGerber(FlatCAMTool):
self.units = self.app.defaults['units']
- # ## Signals
+ self.cb_items = [
+ self.grid1.itemAt(w).widget() for w in range(self.grid1.count())
+ if isinstance(self.grid1.itemAt(w).widget(), FCCheckBox)
+ ]
+ # ## Signals
self.method_punch.activated_custom.connect(self.on_method)
self.reset_button.clicked.connect(self.set_tool_ui)
@@ -341,7 +359,25 @@ class ToolPunchGerber(FlatCAMTool):
def set_tool_ui(self):
self.reset_fields()
+ self.ui_connect()
self.method_punch.set_value('exc')
+ self.select_all_cb.set_value(True)
+
+ def on_select_all(self, state):
+ self.ui_disconnect()
+ if state:
+ self.circular_ring_cb.setChecked(True)
+ self.oblong_ring_cb.setChecked(True)
+ self.square_ring_cb.setChecked(True)
+ self.rectangular_ring_cb.setChecked(True)
+ self.other_ring_cb.setChecked(True)
+ else:
+ self.circular_ring_cb.setChecked(False)
+ self.oblong_ring_cb.setChecked(False)
+ self.square_ring_cb.setChecked(False)
+ self.rectangular_ring_cb.setChecked(False)
+ self.other_ring_cb.setChecked(False)
+ self.ui_connect()
def on_method(self, val):
self.exc_label.setEnabled(False)
@@ -368,6 +404,42 @@ class ToolPunchGerber(FlatCAMTool):
self.factor_label.setEnabled(True)
self.factor_entry.setEnabled(True)
+ def on_ring_cb_toggled(self):
+ sum_cb = 0
+ for it in self.cb_items:
+ if it.get_value():
+ sum_cb += 1
+
+ self.ui_disconnect()
+ if sum_cb == 5:
+ self.select_all_cb.set_value(True)
+ else:
+ self.select_all_cb.set_value(False)
+ self.ui_connect()
+
+ def ui_connect(self):
+ self.select_all_cb.stateChanged.connect(self.on_select_all)
+
+ for it in self.cb_items:
+ try:
+ it.stateChanged.connect(self.on_ring_cb_toggled)
+ except (AttributeError, TypeError):
+ pass
+
+ def ui_disconnect(self):
+ try:
+ self.select_all_cb.stateChanged.disconnect()
+ except (AttributeError, TypeError):
+ pass
+
+ for it in self.cb_items:
+ try:
+ it.stateChanged.disconnect()
+ except (AttributeError, TypeError):
+ pass
+
def reset_fields(self):
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
+ self.ui_disconnect()
+
From 03e1dc54e7194178e60214f4d601fb85407ed488 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 25 Jan 2020 03:49:55 +0200
Subject: [PATCH 047/209] - update in the GUI for the Punch Gerber Tool
---
flatcamTools/ToolExtractDrills.py | 15 +--
flatcamTools/ToolPunchGerber.py | 203 +++++++++++++++++++-----------
2 files changed, 135 insertions(+), 83 deletions(-)
diff --git a/flatcamTools/ToolExtractDrills.py b/flatcamTools/ToolExtractDrills.py
index 6973aecc..7fa1dc98 100644
--- a/flatcamTools/ToolExtractDrills.py
+++ b/flatcamTools/ToolExtractDrills.py
@@ -125,6 +125,11 @@ class ToolExtractDrills(FlatCAMTool):
grid1.setColumnStretch(1, 1)
self.method_label = QtWidgets.QLabel('%s' % _("Method"))
+ self.method_label.setToolTip(
+ _("The selected method of extracting the drills. Can be:\n"
+ "- Fixed Diameter -> all holes will have a set size\n"
+ "- Fixed Annular Ring -> all holes will have a set annular ring\n"
+ "- Proportional -> each hole size will be a fraction of the pad size"))
grid1.addWidget(self.method_label, 2, 0, 1, 2)
# ## Holes Size
@@ -137,15 +142,7 @@ class ToolExtractDrills(FlatCAMTool):
orientation='vertical',
stretch=False)
- self.hole_size_label = QtWidgets.QLabel('%s:' % _("Hole Size"))
- self.hole_size_label.setToolTip(
- _("The selected method of extracting the drills. Can be:\n"
- "- Fixed Diameter -> all holes will have a set size\n"
- "- Fixed Annular Ring -> all holes will have a set annular ring\n"
- "- Proportional -> each hole size will be a fraction of the pad size"))
-
- grid1.addWidget(self.hole_size_label, 3, 0)
- grid1.addWidget(self.hole_size_radio, 3, 1)
+ grid1.addWidget(self.hole_size_radio, 3, 0, 1, 2)
# grid_lay1.addWidget(QtWidgets.QLabel(''))
diff --git a/flatcamTools/ToolPunchGerber.py b/flatcamTools/ToolPunchGerber.py
index 9938b14a..3a1dcf79 100644
--- a/flatcamTools/ToolPunchGerber.py
+++ b/flatcamTools/ToolPunchGerber.py
@@ -83,13 +83,71 @@ class ToolPunchGerber(FlatCAMTool):
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
grid_lay.addWidget(separator_line, 2, 0, 1, 2)
+ self.padt_label = QtWidgets.QLabel("%s" % _("Processed Pads Type"))
+ self.padt_label.setToolTip(
+ _("The type of pads shape to be processed.\n"
+ "If the PCB has many SMD pads with rectangular pads,\n"
+ "disable the Rectangular aperture.")
+ )
+
+ grid_lay.addWidget(self.padt_label, 3, 0, 1, 2)
+
+ # Select all
+ self.select_all_cb = FCCheckBox('%s' % _("ALL"))
+ grid_lay.addWidget(self.select_all_cb)
+
+ # Circular Aperture Selection
+ self.circular_cb = FCCheckBox('%s' % _("Circular"))
+ self.circular_cb.setToolTip(
+ _("Create drills from circular pads.")
+ )
+
+ grid_lay.addWidget(self.circular_cb, 5, 0, 1, 2)
+
+ # Oblong Aperture Selection
+ self.oblong_cb = FCCheckBox('%s' % _("Oblong"))
+ self.oblong_cb.setToolTip(
+ _("Create drills from oblong pads.")
+ )
+
+ grid_lay.addWidget(self.oblong_cb, 6, 0, 1, 2)
+
+ # Square Aperture Selection
+ self.square_cb = FCCheckBox('%s' % _("Square"))
+ self.square_cb.setToolTip(
+ _("Create drills from square pads.")
+ )
+
+ grid_lay.addWidget(self.square_cb, 7, 0, 1, 2)
+
+ # Rectangular Aperture Selection
+ self.rectangular_cb = FCCheckBox('%s' % _("Rectangular"))
+ self.rectangular_cb.setToolTip(
+ _("Create drills from rectangular pads.")
+ )
+
+ grid_lay.addWidget(self.rectangular_cb, 8, 0, 1, 2)
+
+ # Others type of Apertures Selection
+ self.other_cb = FCCheckBox('%s' % _("Others"))
+ self.other_cb.setToolTip(
+ _("Create drills from other types of pad shape.")
+ )
+
+ grid_lay.addWidget(self.other_cb, 9, 0, 1, 2)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid_lay.addWidget(separator_line, 10, 0, 1, 2)
+
# Grid Layout
grid0 = QtWidgets.QGridLayout()
self.layout.addLayout(grid0)
grid0.setColumnStretch(0, 0)
grid0.setColumnStretch(1, 1)
- self.method_label = QtWidgets.QLabel('%s:' % _("Method"))
+ self.method_label = QtWidgets.QLabel('%s:' % _("Method"))
self.method_label.setToolTip(
_("The punch hole source can be:\n"
"- Excellon Object-> the Excellon object drills center will serve as reference.\n"
@@ -106,13 +164,13 @@ class ToolPunchGerber(FlatCAMTool):
],
orientation='vertical',
stretch=False)
- grid0.addWidget(self.method_label, 0, 0)
- grid0.addWidget(self.method_punch, 0, 1)
+ grid0.addWidget(self.method_label, 0, 0, 1, 2)
+ grid0.addWidget(self.method_punch, 1, 0, 1, 2)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid0.addWidget(separator_line, 1, 0, 1, 2)
+ grid0.addWidget(separator_line, 2, 0, 1, 2)
self.exc_label = QtWidgets.QLabel('%s' % _("Excellon"))
self.exc_label.setToolTip(
@@ -124,8 +182,8 @@ class ToolPunchGerber(FlatCAMTool):
self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
self.exc_combo.setCurrentIndex(1)
- grid0.addWidget(self.exc_label, 2, 0, 1, 2)
- grid0.addWidget(self.exc_combo, 3, 0, 1, 2)
+ grid0.addWidget(self.exc_label, 3, 0, 1, 2)
+ grid0.addWidget(self.exc_combo, 4, 0, 1, 2)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
@@ -171,10 +229,6 @@ class ToolPunchGerber(FlatCAMTool):
)
self.ring_box.addWidget(self.ring_label)
- # Select all
- self.select_all_cb = FCCheckBox('%s' % _("ALL"))
- self.ring_box.addWidget(self.select_all_cb)
-
# ## Grid Layout
self.grid1 = QtWidgets.QGridLayout()
self.grid1.setColumnStretch(0, 0)
@@ -182,8 +236,8 @@ class ToolPunchGerber(FlatCAMTool):
self.ring_box.addLayout(self.grid1)
# Circular Annular Ring Value
- self.circular_ring_cb = FCCheckBox('%s:' % _("Circular"))
- self.circular_ring_cb.setToolTip(
+ self.circular_ring_label = QtWidgets.QLabel('%s:' % _("Circular"))
+ self.circular_ring_label.setToolTip(
_("The size of annular ring for circular pads.")
)
@@ -191,14 +245,12 @@ class ToolPunchGerber(FlatCAMTool):
self.circular_ring_entry.set_precision(self.decimals)
self.circular_ring_entry.set_range(0.0000, 9999.9999)
- self.c_ois = OptionalInputSection(self.circular_ring_cb, [self.circular_ring_entry])
-
- self.grid1.addWidget(self.circular_ring_cb, 3, 0)
+ self.grid1.addWidget(self.circular_ring_label, 3, 0)
self.grid1.addWidget(self.circular_ring_entry, 3, 1)
# Oblong Annular Ring Value
- self.oblong_ring_cb= FCCheckBox('%s:' % _("Oblong"))
- self.oblong_ring_cb.setToolTip(
+ self.oblong_ring_label= QtWidgets.QLabel('%s:' % _("Oblong"))
+ self.oblong_ring_label.setToolTip(
_("The size of annular ring for oblong pads.")
)
@@ -206,14 +258,12 @@ class ToolPunchGerber(FlatCAMTool):
self.oblong_ring_entry.set_precision(self.decimals)
self.oblong_ring_entry.set_range(0.0000, 9999.9999)
- self.o_ois = OptionalInputSection(self.oblong_ring_cb, [self.oblong_ring_entry])
-
- self.grid1.addWidget(self.oblong_ring_cb, 4, 0)
+ self.grid1.addWidget(self.oblong_ring_label, 4, 0)
self.grid1.addWidget(self.oblong_ring_entry, 4, 1)
# Square Annular Ring Value
- self.square_ring_cb = FCCheckBox('%s:' % _("Square"))
- self.square_ring_cb.setToolTip(
+ self.square_ring_label = QtWidgets.QLabel('%s:' % _("Square"))
+ self.square_ring_label.setToolTip(
_("The size of annular ring for square pads.")
)
@@ -221,14 +271,12 @@ class ToolPunchGerber(FlatCAMTool):
self.square_ring_entry.set_precision(self.decimals)
self.square_ring_entry.set_range(0.0000, 9999.9999)
- self.s_ois = OptionalInputSection(self.square_ring_cb, [self.square_ring_entry])
-
- self.grid1.addWidget(self.square_ring_cb, 5, 0)
+ self.grid1.addWidget(self.square_ring_label, 5, 0)
self.grid1.addWidget(self.square_ring_entry, 5, 1)
# Rectangular Annular Ring Value
- self.rectangular_ring_cb = FCCheckBox('%s:' % _("Rectangular"))
- self.rectangular_ring_cb.setToolTip(
+ self.rectangular_ring_label = QtWidgets.QLabel('%s:' % _("Rectangular"))
+ self.rectangular_ring_label.setToolTip(
_("The size of annular ring for rectangular pads.")
)
@@ -236,14 +284,12 @@ class ToolPunchGerber(FlatCAMTool):
self.rectangular_ring_entry.set_precision(self.decimals)
self.rectangular_ring_entry.set_range(0.0000, 9999.9999)
- self.r_ois = OptionalInputSection(self.rectangular_ring_cb, [self.rectangular_ring_entry])
-
- self.grid1.addWidget(self.rectangular_ring_cb, 6, 0)
+ self.grid1.addWidget(self.rectangular_ring_label, 6, 0)
self.grid1.addWidget(self.rectangular_ring_entry, 6, 1)
# Others Annular Ring Value
- self.other_ring_cb = FCCheckBox('%s:' % _("Others"))
- self.other_ring_cb.setToolTip(
+ self.other_ring_label = QtWidgets.QLabel('%s:' % _("Others"))
+ self.other_ring_label.setToolTip(
_("The size of annular ring for other pads.")
)
@@ -251,9 +297,7 @@ class ToolPunchGerber(FlatCAMTool):
self.other_ring_entry.set_precision(self.decimals)
self.other_ring_entry.set_range(0.0000, 9999.9999)
- self.ot_ois = OptionalInputSection(self.other_ring_cb, [self.other_ring_entry])
-
- self.grid1.addWidget(self.other_ring_cb, 7, 0)
+ self.grid1.addWidget(self.other_ring_label, 7, 0)
self.grid1.addWidget(self.other_ring_entry, 7, 1)
separator_line = QtWidgets.QFrame()
@@ -316,15 +360,51 @@ class ToolPunchGerber(FlatCAMTool):
self.units = self.app.defaults['units']
- self.cb_items = [
- self.grid1.itemAt(w).widget() for w in range(self.grid1.count())
- if isinstance(self.grid1.itemAt(w).widget(), FCCheckBox)
- ]
+ # self.cb_items = [
+ # self.grid1.itemAt(w).widget() for w in range(self.grid1.count())
+ # if isinstance(self.grid1.itemAt(w).widget(), FCCheckBox)
+ # ]
+
+ self.circular_ring_entry.setEnabled(False)
+ self.oblong_ring_entry.setEnabled(False)
+ self.square_ring_entry.setEnabled(False)
+ self.rectangular_ring_entry.setEnabled(False)
+ self.other_ring_entry.setEnabled(False)
+
+ self.dia_entry.setDisabled(True)
+ self.dia_label.setDisabled(True)
+ self.factor_label.setDisabled(True)
+ self.factor_entry.setDisabled(True)
# ## Signals
self.method_punch.activated_custom.connect(self.on_method)
self.reset_button.clicked.connect(self.set_tool_ui)
+ self.circular_cb.stateChanged.connect(
+ lambda state:
+ self.circular_ring_entry.setDisabled(False) if state else self.circular_ring_entry.setDisabled(True)
+ )
+
+ self.oblong_cb.stateChanged.connect(
+ lambda state:
+ self.oblong_ring_entry.setDisabled(False) if state else self.oblong_ring_entry.setDisabled(True)
+ )
+
+ self.square_cb.stateChanged.connect(
+ lambda state:
+ self.square_ring_entry.setDisabled(False) if state else self.square_ring_entry.setDisabled(True)
+ )
+
+ self.rectangular_cb.stateChanged.connect(
+ lambda state:
+ self.rectangular_ring_entry.setDisabled(False) if state else self.rectangular_ring_entry.setDisabled(True)
+ )
+
+ self.other_cb.stateChanged.connect(
+ lambda state:
+ self.other_ring_entry.setDisabled(False) if state else self.other_ring_entry.setDisabled(True)
+ )
+
def run(self, toggle=True):
self.app.report_usage("ToolPunchGerber()")
@@ -366,17 +446,17 @@ class ToolPunchGerber(FlatCAMTool):
def on_select_all(self, state):
self.ui_disconnect()
if state:
- self.circular_ring_cb.setChecked(True)
- self.oblong_ring_cb.setChecked(True)
- self.square_ring_cb.setChecked(True)
- self.rectangular_ring_cb.setChecked(True)
- self.other_ring_cb.setChecked(True)
+ self.circular_cb.setChecked(True)
+ self.oblong_cb.setChecked(True)
+ self.square_cb.setChecked(True)
+ self.rectangular_cb.setChecked(True)
+ self.other_cb.setChecked(True)
else:
- self.circular_ring_cb.setChecked(False)
- self.oblong_ring_cb.setChecked(False)
- self.square_ring_cb.setChecked(False)
- self.rectangular_ring_cb.setChecked(False)
- self.other_ring_cb.setChecked(False)
+ self.circular_cb.setChecked(False)
+ self.oblong_cb.setChecked(False)
+ self.square_cb.setChecked(False)
+ self.rectangular_cb.setChecked(False)
+ self.other_cb.setChecked(False)
self.ui_connect()
def on_method(self, val):
@@ -404,40 +484,15 @@ class ToolPunchGerber(FlatCAMTool):
self.factor_label.setEnabled(True)
self.factor_entry.setEnabled(True)
- def on_ring_cb_toggled(self):
- sum_cb = 0
- for it in self.cb_items:
- if it.get_value():
- sum_cb += 1
-
- self.ui_disconnect()
- if sum_cb == 5:
- self.select_all_cb.set_value(True)
- else:
- self.select_all_cb.set_value(False)
- self.ui_connect()
-
def ui_connect(self):
self.select_all_cb.stateChanged.connect(self.on_select_all)
- for it in self.cb_items:
- try:
- it.stateChanged.connect(self.on_ring_cb_toggled)
- except (AttributeError, TypeError):
- pass
-
def ui_disconnect(self):
try:
self.select_all_cb.stateChanged.disconnect()
except (AttributeError, TypeError):
pass
- for it in self.cb_items:
- try:
- it.stateChanged.disconnect()
- except (AttributeError, TypeError):
- pass
-
def reset_fields(self):
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
From 408d46fd820dc02fbd99c18f7b4cd12b5c3fbf09 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 25 Jan 2020 03:57:37 +0200
Subject: [PATCH 048/209] - changed icons for Punch Gerber Tool
---
FlatCAMApp.py | 2 +-
share/punch16.png | Bin 551 -> 514 bytes
share/punch32.png | Bin 839 -> 726 bytes
3 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index e6dc95ea..a97d67f6 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -141,7 +141,7 @@ class App(QtCore.QObject):
# ################## Version and VERSION DATE ##############################
# ##########################################################################
version = 8.992
- version_date = "2020/01/22"
+ version_date = "2020/01/30"
beta = True
engine = '3D'
diff --git a/share/punch16.png b/share/punch16.png
index 65c2581087206249e9a21e88c4d510da661ad720..679b1b75111f660db5a8fe50dbe37998483e00e1 100644
GIT binary patch
delta 339
zcmZ3^(!?^MyIzvfTt7R-^fUtl!v#+l#}JM4trr)19WE3(`mx_a%*7y6>afDJ#2MU8
zz6D&yH|}u1;S|ZSJFw`WLI?kXiyJIv+*~8(cv?qFBv4=v+y6h`+wZ5S&prK9ZpZY~
zEWS_kjyG+}RjoZ<7xcx4rH2
delta 328
zcmZo-S1Xo;c~y
z(axd?8h%S;rY4=5De~0akMCUHx;r}Vsau6Kv+A2>UpjTN|8UypySF}n`ne~5e){`+
z@BKaI&S1@yU$^J#;efZ>lwJpISC!1(XJU}eruq9;6aQ4BOc%NL_4{hrTMevaIjL6@z38gBREK<_H%1n2@wy{ii#-_e0!WZ{z
ztkYg_CepRvc%#>Z?RPJv-c*|8cl0pF?l3+MeKnOSBDrS1(NCTHBImbv^u!&$4|711kfA
Vp3X_9CNIDu@%M^W+2o6ih5&OAk?sHh
diff --git a/share/punch32.png b/share/punch32.png
index b3c130ba19b5f210fe256bfd6f5e78bd3cdf4a56..5c1efec102e5939138c2dfbb0ad9d93f1e079eaa 100644
GIT binary patch
delta 553
zcmX@kc8zsHcfBN|xy+Rb7;fJa{@4wxeXZfMJ
z>hV@(-)-L4;N|~2;
zy5q|O2CV3LSNA}
z!HbG%J2M^4BKvQ|I5VSULjfkxUI59
zZo(xyQS0;Wyr56(`!RJ`tPq!?#Y~b6V%$Rd)4x^3&E|
zu8(e*roh0!pjzS@QIe8al4_M)lnSI6j0}tnbPWu3jZ8xf46RH}t&A+R4GgRd4E!u(
Z9-(N+%}>cptCYj7!#?Fn++;CkLjWO?4
z*pwmS;%chlvZ#flv#UwUlQnSSVzo{I7Z%f^OAC~AoT`EZmT_jXWEQM%a=fM>)sb?C
zEw1m@etH8`eLo-+udF?nVIX0RkP9jE9%d#{YXn!I-T}5ZMoBy
z-7AC6Y+7KwHjhO$?psJ)k;}B#ZaK4zisQW>=v8RiU!AG*ceVNXIox+F*NZN3`m?fT
zt{=;~!0C%NbSUkWVk*B92oq@r}BwzUhmHtm}>85c%^pd#lDtQ0P
zjiv1-NBKO;BW5oYm{5|OC#iNhtW@sxH}Cqy6*k+tciF}r@?M@E;E}Z3XYsey^B5O|
zNH6gWm$HdT6cHDFZvOR3wbHM3KNA=j7*tDKBT7;dOH!?pi&B9UgOP!efv$m}u8~QI
sp|O>zv6Z2Twt<0_fkC8k%RCefx%nxXX_crN1dw%T
Date: Mon, 27 Jan 2020 04:12:46 +0200
Subject: [PATCH 049/209] - in Geometry Editor made sure that on final save,
for MultiLineString geometry all the connected lines are merged into one
LineString to minimize the number of vertical movements in GCode - more work
in Punch Gerber Tool
---
README.md | 5 ++
flatcamEditors/FlatCAMGeoEditor.py | 23 +++--
flatcamTools/ToolPunchGerber.py | 137 +++++++++++++++++++++++++++++
3 files changed, 160 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index fa51f802..5d35f12f 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+27.01.2020
+
+- in Geometry Editor made sure that on final save, for MultiLineString geometry all the connected lines are merged into one LineString to minimize the number of vertical movements in GCode
+- more work in Punch Gerber Tool
+
24.02.2020
- small changes to the Toolchange manual preprocessor
diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py
index 8e12c935..4dbf6389 100644
--- a/flatcamEditors/FlatCAMGeoEditor.py
+++ b/flatcamEditors/FlatCAMGeoEditor.py
@@ -23,7 +23,7 @@ from flatcamParsers.ParseFont import *
import FlatCAMApp
from shapely.geometry import LineString, LinearRing, MultiLineString, Polygon, MultiPolygon
-from shapely.ops import cascaded_union, unary_union
+from shapely.ops import cascaded_union, unary_union, linemerge
import shapely.affinity as affinity
from shapely.geometry.polygon import orient
@@ -2498,6 +2498,9 @@ class FCSelect(DrawTool):
raise
return ""
+ def clean_up(self):
+ pass
+
class FCExplode(FCShapeTool):
def __init__(self, draw_app):
@@ -3739,8 +3742,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
)
)
else:
- geo_to_edit = self.flatten(geometry=fcgeometry.solid_geometry,
- orient_val=milling_type)
+ geo_to_edit = self.flatten(geometry=fcgeometry.solid_geometry, orient_val=milling_type)
for shape in geo_to_edit:
if shape is not None: # TODO: Make flatten never create a None
@@ -4396,13 +4398,24 @@ class FlatCAMGeoEditor(QtCore.QObject):
fcgeometry.tools[self.multigeo_tool]['solid_geometry'] = []
# for shape in self.shape_buffer:
for shape in self.storage.get_objects():
- fcgeometry.tools[self.multigeo_tool]['solid_geometry'].append(shape.geo)
+ new_geo = shape.geo
+
+ # simplify the MultiLineString
+ if isinstance(new_geo, MultiLineString):
+ new_geo = linemerge(new_geo)
+
+ fcgeometry.tools[self.multigeo_tool]['solid_geometry'].append(new_geo)
self.multigeo_tool = None
fcgeometry.solid_geometry = []
# for shape in self.shape_buffer:
for shape in self.storage.get_objects():
- fcgeometry.solid_geometry.append(shape.geo)
+ new_geo = shape.geo
+
+ # simplify the MultiLineString
+ if isinstance(new_geo, MultiLineString):
+ new_geo = linemerge(new_geo)
+ fcgeometry.solid_geometry.append(new_geo)
def update_options(self, obj):
if self.paint_tooldia:
diff --git a/flatcamTools/ToolPunchGerber.py b/flatcamTools/ToolPunchGerber.py
index 3a1dcf79..b52058ef 100644
--- a/flatcamTools/ToolPunchGerber.py
+++ b/flatcamTools/ToolPunchGerber.py
@@ -379,6 +379,7 @@ class ToolPunchGerber(FlatCAMTool):
# ## Signals
self.method_punch.activated_custom.connect(self.on_method)
self.reset_button.clicked.connect(self.set_tool_ui)
+ self.punch_object_button.clicked.connect(self.on_generate_object)
self.circular_cb.stateChanged.connect(
lambda state:
@@ -493,6 +494,142 @@ class ToolPunchGerber(FlatCAMTool):
except (AttributeError, TypeError):
pass
+ def on_generate_object(self):
+
+ # get the Gerber file who is the source of the punched Gerber
+ selection_index = self.gerber_object_combo.currentIndex()
+ model_index = self.app.collection.index(selection_index, 0, self.gerber_object_combo.rootModelIndex())
+
+ try:
+ grb_obj = model_index.internalPointer().obj
+ except Exception:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
+ return
+
+ name = grb_obj.options['name'].rpartition('.')[0]
+ outname = name + "_punched"
+
+ punch_method = self.method_punch.get_value()
+
+ if punch_method == 'exc':
+
+ # get the Excellon file whose geometry will create the punch holes
+ selection_index = self.exc_combo.currentIndex()
+ model_index = self.app.collection.index(selection_index, 0, self.exc_combo.rootModelIndex())
+
+ try:
+ exc_obj = model_index.internalPointer().obj
+ except Exception:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Excellon object loaded ..."))
+ return
+
+ # this is the punching geometry
+ exc_solid_geometry = MultiPolygon(exc_obj.solid_geometry)
+ if isinstance(grb_obj.solid_geometry, list):
+ grb_solid_geometry = MultiPolygon(grb_obj.solid_geometry)
+ else:
+ grb_solid_geometry = grb_obj.solid_geometry
+
+ # create the punched Gerber solid_geometry
+ punched_solid_geometry = grb_solid_geometry.difference(exc_solid_geometry)
+
+ new_apertures = dict()
+ new_apertures = deepcopy(grb_obj.apertures)
+
+ holes_apertures = dict()
+
+ for apid, val in new_apertures.items():
+ for elem in val['geometry']:
+ # make it work only for Gerber Flashes who are Points in 'follow'
+ if 'solid' in elem and isinstance(elem['follow'], Point):
+ for drill in exc_obj.drills:
+ clear_apid = exc_obj.tools[drill['tool']]['C']
+ exc_poly = drill['point'].buffer(clear_apid / 2.0)
+ if exc_poly.within(elem['solid']):
+
+ if clear_apid not in holes_apertures or holes_apertures[clear_apid]['type'] != 'C':
+ holes_apertures[clear_apid] = dict()
+ holes_apertures[clear_apid]['type'] = 'C'
+ holes_apertures[clear_apid]['size'] = clear_apid
+ holes_apertures[clear_apid]['geometry'] = list()
+ geo_elem = dict()
+ geo_elem['clear'] = exc_poly
+ geo_elem['follow'] = exc_poly.centroid
+ holes_apertures[clear_apid]['geometry'].append(deepcopy(geo_elem))
+
+ elem['clear'] = exc_poly.centroid
+
+ for apid, val in new_apertures.items():
+ for clear_apid, clear_val in holes_apertures.items():
+ if round(clear_apid, self.decimals) == round(val['size'], self.decimals):
+ geo_elem = dict()
+
+ val['geometry'].append(geo_elem)
+
+ def init_func(new_obj, app_obj):
+ new_obj.options.update(grb_obj.options)
+ new_obj.options['name'] = outname
+ new_obj.fill_color = deepcopy(grb_obj.fill_color)
+ new_obj.outline_color = deepcopy(grb_obj.outline_color)
+
+ new_obj.apertures = deepcopy(new_apertures)
+
+ new_obj.solid_geometry = deepcopy(punched_solid_geometry)
+ new_obj.source_file = self.app.export_gerber(obj_name=outname, filename=None,
+ local_use=new_obj, use_thread=False)
+
+ self.app.new_object('gerber', outname, init_func)
+ elif punch_method == 'fixed':
+ punch_size = float(self.dia_entry.get_value())
+
+ punching_geo = list()
+ for apid in grb_obj.apertures:
+ if grb_obj.apertures[apid]['type'] == 'C':
+ if punch_size >= float(grb_obj.apertures[apid]['size']):
+ self.app.inform.emit('[ERROR_NOTCL] %s' %
+ _(" Could not generate punched hole Gerber because the punch hole size"
+ "is bigger than some of the apertures in the Gerber object."))
+ return 'fail'
+ else:
+ for elem in grb_obj.apertures[apid]['geometry']:
+ if 'follow' in elem:
+ if isinstance(elem['follow'], Point):
+ punching_geo.append(elem['follow'].buffer(punch_size / 2))
+ else:
+ if punch_size >= float(grb_obj.apertures[apid]['width']) or \
+ punch_size >= float(grb_obj.apertures[apid]['height']):
+ self.app.inform.emit('[ERROR_NOTCL] %s' %
+ _("Could not generate punched hole Gerber because the punch hole size"
+ "is bigger than some of the apertures in the Gerber object."))
+ return 'fail'
+ else:
+ for elem in grb_obj.apertures[apid]['geometry']:
+ if 'follow' in elem:
+ if isinstance(elem['follow'], Point):
+ punching_geo.append(elem['follow'].buffer(punch_size / 2))
+
+ punching_geo = MultiPolygon(punching_geo)
+ if isinstance(grb_obj.solid_geometry, list):
+ temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry)
+ else:
+ temp_solid_geometry = grb_obj.solid_geometry
+ punched_solid_geometry = temp_solid_geometry.difference(punching_geo)
+
+ if punched_solid_geometry == temp_solid_geometry:
+ self.app.inform.emit('[WARNING_NOTCL] %s' %
+ _("Could not generate punched hole Gerber because the newly created object "
+ "geometry is the same as the one in the source object geometry..."))
+ return 'fail'
+
+ def init_func(new_obj, app_obj):
+ new_obj.solid_geometry = deepcopy(punched_solid_geometry)
+
+ self.app.new_object('gerber', outname, init_func)
+ elif punch_method == 'ring':
+ pass
+ elif punch_method == 'prop':
+ pass
+
def reset_fields(self):
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
From aa7bc125f4827f6e22efeecb2560fe330bda8fcd Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 27 Jan 2020 15:27:34 +0200
Subject: [PATCH 050/209] - the Jump To popup window will now autoselect the
LineEdit therefore no more need for an extra click after launching the
function
---
README.md | 1 +
flatcamGUI/GUIElements.py | 6 ++++--
flatcamTools/ToolPunchGerber.py | 3 +--
3 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 5d35f12f..555aad09 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- in Geometry Editor made sure that on final save, for MultiLineString geometry all the connected lines are merged into one LineString to minimize the number of vertical movements in GCode
- more work in Punch Gerber Tool
+- the Jump To popup window will now autoselect the LineEdit therefore no more need for an extra click after launching the function
24.02.2020
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index 05314ffe..8127739a 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -2278,7 +2278,7 @@ class Dialog_box(QtWidgets.QWidget):
class DialogBoxRadio(QtWidgets.QDialog):
- def __init__(self, title=None, label=None, icon=None, initial_text=None, reference='abs'):
+ def __init__(self, title=None, label=None, icon=None, initial_text=None, reference='abs', parent=None):
"""
:param title: string with the window title
@@ -2322,8 +2322,10 @@ class DialogBoxRadio(QtWidgets.QDialog):
"If the reference is Relative then the Jump will be at the (x,y) distance\n"
"from the current mouse location point.")
)
- self.lineEdit = EvalEntry()
+ self.lineEdit = EvalEntry(self)
self.lineEdit.setText(str(self.location).replace('(', '').replace(')', ''))
+ self.lineEdit.selectAll()
+ self.lineEdit.setFocus()
self.form.addRow(self.loc_label, self.lineEdit)
self.button_box = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel,
diff --git a/flatcamTools/ToolPunchGerber.py b/flatcamTools/ToolPunchGerber.py
index b52058ef..16aeabb8 100644
--- a/flatcamTools/ToolPunchGerber.py
+++ b/flatcamTools/ToolPunchGerber.py
@@ -249,7 +249,7 @@ class ToolPunchGerber(FlatCAMTool):
self.grid1.addWidget(self.circular_ring_entry, 3, 1)
# Oblong Annular Ring Value
- self.oblong_ring_label= QtWidgets.QLabel('%s:' % _("Oblong"))
+ self.oblong_ring_label = QtWidgets.QLabel('%s:' % _("Oblong"))
self.oblong_ring_label.setToolTip(
_("The size of annular ring for oblong pads.")
)
@@ -634,4 +634,3 @@ class ToolPunchGerber(FlatCAMTool):
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
self.ui_disconnect()
-
From fbf0b8606ed41d25197ba952a0f01e7e4fd173bd Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 27 Jan 2020 17:20:06 +0200
Subject: [PATCH 051/209] - made some structural changes in Properties Tool
---
README.md | 1 +
flatcamGUI/GUIElements.py | 34 ++++++
flatcamTools/ToolProperties.py | 206 ++++++++++++++++-----------------
3 files changed, 137 insertions(+), 104 deletions(-)
diff --git a/README.md b/README.md
index 555aad09..caf14993 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ CAD program, and create G-Code for Isolation routing.
- in Geometry Editor made sure that on final save, for MultiLineString geometry all the connected lines are merged into one LineString to minimize the number of vertical movements in GCode
- more work in Punch Gerber Tool
- the Jump To popup window will now autoselect the LineEdit therefore no more need for an extra click after launching the function
+- made some structural changes in Properties Tool
24.02.2020
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index 8127739a..a136e16c 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -152,6 +152,40 @@ class RadioSet(QtWidgets.QWidget):
# wgt.show()
+class FCTree(QtWidgets.QTreeWidget):
+
+ def __init__(self, parent=None, columns=2, header_hidden=True):
+ super(FCTree, self).__init__(parent)
+
+ self.setColumnCount(columns)
+ self.setHeaderHidden(header_hidden)
+ self.header().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
+ self.setSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Expanding)
+
+ def addParent(self, parent, title, expanded=False, color=None, font=None):
+ item = QtWidgets.QTreeWidgetItem(parent, [title])
+ item.setChildIndicatorPolicy(QtWidgets.QTreeWidgetItem.ShowIndicator)
+ item.setExpanded(expanded)
+ if color is not None:
+ # item.setTextColor(0, color) # PyQt4
+ item.setForeground(0, QtGui.QBrush(color))
+ if font is not None:
+ item.setFont(0, font)
+ return item
+
+ def addChild(self, parent, title, column1=None, font=None, font_items=None):
+ item = QtWidgets.QTreeWidgetItem(parent)
+ item.setText(0, str(title[0]))
+ if column1 is not None:
+ item.setText(1, str(title[1]))
+ if font and font_items:
+ try:
+ for fi in font_items:
+ item.setFont(fi, font)
+ except TypeError:
+ item.setFont(font_items, font)
+
+
class LengthEntry(QtWidgets.QLineEdit):
def __init__(self, output_units='IN', decimals=None, parent=None):
super(LengthEntry, self).__init__(parent)
diff --git a/flatcamTools/ToolProperties.py b/flatcamTools/ToolProperties.py
index 03dfb755..6429982e 100644
--- a/flatcamTools/ToolProperties.py
+++ b/flatcamTools/ToolProperties.py
@@ -7,6 +7,7 @@
from PyQt5 import QtGui, QtCore, QtWidgets
from FlatCAMTool import FlatCAMTool
+from flatcamGUI.GUIElements import FCTree
from shapely.geometry import MultiPolygon, Polygon
from shapely.ops import cascaded_union
@@ -64,11 +65,7 @@ class Properties(FlatCAMTool):
self.properties_box.addLayout(self.vlay)
- self.treeWidget = QtWidgets.QTreeWidget()
- self.treeWidget.setColumnCount(2)
- self.treeWidget.setHeaderHidden(True)
- self.treeWidget.header().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
- self.treeWidget.setSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Expanding)
+ self.treeWidget = FCTree(columns=2)
self.vlay.addWidget(self.treeWidget)
self.vlay.setStretch(0, 0)
@@ -146,36 +143,50 @@ class Properties(FlatCAMTool):
font.setBold(True)
# main Items categories
- obj_type = self.addParent(parent, _('TYPE'), expanded=True, color=QtGui.QColor("#000000"), font=font)
- obj_name = self.addParent(parent, _('NAME'), expanded=True, color=QtGui.QColor("#000000"), font=font)
- dims = self.addParent(parent, _('Dimensions'), expanded=True, color=QtGui.QColor("#000000"), font=font)
- units = self.addParent(parent, _('Units'), expanded=True, color=QtGui.QColor("#000000"), font=font)
- options = self.addParent(parent, _('Options'), color=QtGui.QColor("#000000"), font=font)
+ obj_type = self.treeWidget.addParent(parent, _('TYPE'), expanded=True, color=QtGui.QColor("#000000"), font=font)
+ obj_name = self.treeWidget.addParent(parent, _('NAME'), expanded=True, color=QtGui.QColor("#000000"), font=font)
+ dims = self.treeWidget.addParent(
+ parent, _('Dimensions'), expanded=True, color=QtGui.QColor("#000000"), font=font)
+ units = self.treeWidget.addParent(parent, _('Units'), expanded=True, color=QtGui.QColor("#000000"), font=font)
+ options = self.treeWidget.addParent(parent, _('Options'), color=QtGui.QColor("#000000"), font=font)
if obj.kind.lower() == 'gerber':
- apertures = self.addParent(parent, _('Apertures'), expanded=True, color=QtGui.QColor("#000000"), font=font)
+ apertures = self.treeWidget.addParent(
+ parent, _('Apertures'), expanded=True, color=QtGui.QColor("#000000"), font=font)
else:
- tools = self.addParent(parent, _('Tools'), expanded=True, color=QtGui.QColor("#000000"), font=font)
+ tools = self.treeWidget.addParent(
+ parent, _('Tools'), expanded=True, color=QtGui.QColor("#000000"), font=font)
if obj.kind.lower() == 'excellon':
- drills = self.addParent(parent, _('Drills'), expanded=True, color=QtGui.QColor("#000000"), font=font)
- slots = self.addParent(parent, _('Slots'), expanded=True, color=QtGui.QColor("#000000"), font=font)
+ drills = self.treeWidget.addParent(
+ parent, _('Drills'), expanded=True, color=QtGui.QColor("#000000"), font=font)
+ slots = self.treeWidget.addParent(
+ parent, _('Slots'), expanded=True, color=QtGui.QColor("#000000"), font=font)
if obj.kind.lower() == 'cncjob':
- others = self.addParent(parent, _('Others'), expanded=True, color=QtGui.QColor("#000000"), font=font)
+ others = self.treeWidget.addParent(
+ parent, _('Others'), expanded=True, color=QtGui.QColor("#000000"), font=font)
- separator = self.addParent(parent, '')
+ separator = self.treeWidget.addParent(parent, '')
- self.addChild(obj_type, ['%s:' % _('Object Type'), ('%s' % (obj.kind.upper()))], True, font=font, font_items=1)
+ self.treeWidget.addChild(
+ obj_type, ['%s:' % _('Object Type'), ('%s' % (obj.kind.upper()))], True, font=font, font_items=1)
try:
- self.addChild(obj_type,
- ['%s:' % _('Geo Type'),
- ('%s' % ({False: _("Single-Geo"), True: _("Multi-Geo")}[obj.multigeo]))],
- True)
+ self.treeWidget.addChild(obj_type,
+ [
+ '%s:' % _('Geo Type'),
+ ('%s' % (
+ {
+ False: _("Single-Geo"),
+ True: _("Multi-Geo")
+ }[obj.multigeo])
+ )
+ ],
+ True)
except Exception as e:
log.debug("Properties.addItems() --> %s" % str(e))
- self.addChild(obj_name, [obj.options['name']])
+ self.treeWidget.addChild(obj_name, [obj.options['name']])
def job_thread(obj_prop):
proc = self.app.proc_container.new(_("Calculating dimensions ... Please wait."))
@@ -193,8 +204,8 @@ class Properties(FlatCAMTool):
length = abs(xmax - xmin)
width = abs(ymax - ymin)
- except Exception as e:
- log.debug("PropertiesTool.addItems() -> calculate dimensions --> %s" % str(e))
+ except Exception as ee:
+ log.debug("PropertiesTool.addItems() -> calculate dimensions --> %s" % str(ee))
# calculate box area
if self.app.defaults['units'].lower() == 'mm':
@@ -278,24 +289,27 @@ class Properties(FlatCAMTool):
except TypeError:
copper_area += geo_tools.area
copper_area /= 100
- except Exception as e:
- log.debug("Properties.addItems() --> %s" % str(e))
+ except Exception as err:
+ log.debug("Properties.addItems() --> %s" % str(err))
area_chull = 0.0
if obj_prop.kind.lower() != 'cncjob':
# calculate and add convex hull area
if geo:
- if isinstance(geo, MultiPolygon):
- env_obj = geo.convex_hull
- elif (isinstance(geo, MultiPolygon) and len(geo) == 1) or \
- (isinstance(geo, list) and len(geo) == 1) and isinstance(geo[0], Polygon):
- env_obj = cascaded_union(obj_prop.solid_geometry)
- env_obj = env_obj.convex_hull
- else:
- env_obj = cascaded_union(obj_prop.solid_geometry)
- env_obj = env_obj.convex_hull
+ if isinstance(geo, list) and geo[0] is not None:
+ if isinstance(geo, MultiPolygon):
+ env_obj = geo.convex_hull
+ elif (isinstance(geo, MultiPolygon) and len(geo) == 1) or \
+ (isinstance(geo, list) and len(geo) == 1) and isinstance(geo[0], Polygon):
+ env_obj = cascaded_union(geo)
+ env_obj = env_obj.convex_hull
+ else:
+ env_obj = cascaded_union(geo)
+ env_obj = env_obj.convex_hull
- area_chull = env_obj.area
+ area_chull = env_obj.area
+ else:
+ area_chull = 0
else:
try:
area_chull = []
@@ -303,9 +317,9 @@ class Properties(FlatCAMTool):
area_el = cascaded_union(obj_prop.tools[tool_k]['solid_geometry']).convex_hull
area_chull.append(area_el.area)
area_chull = max(area_chull)
- except Exception as e:
+ except Exception as er:
area_chull = None
- log.debug("Properties.addItems() --> %s" % str(e))
+ log.debug("Properties.addItems() --> %s" % str(er))
if self.app.defaults['units'].lower() == 'mm' and area_chull:
area_chull = area_chull / 100
@@ -319,7 +333,7 @@ class Properties(FlatCAMTool):
# Units items
f_unit = {'in': _('Inch'), 'mm': _('Metric')}[str(self.app.defaults['units'].lower())]
- self.addChild(units, ['FlatCAM units:', f_unit], True)
+ self.treeWidget.addChild(units, ['FlatCAM units:', f_unit], True)
o_unit = {
'in': _('Inch'),
@@ -327,13 +341,13 @@ class Properties(FlatCAMTool):
'inch': _('Inch'),
'metric': _('Metric')
}[str(obj.units_found.lower())]
- self.addChild(units, ['Object units:', o_unit], True)
+ self.treeWidget.addChild(units, ['Object units:', o_unit], True)
# Options items
for option in obj.options:
if option is 'name':
continue
- self.addChild(options, [str(option), str(obj.options[option])], True)
+ self.treeWidget.addChild(options, [str(option), str(obj.options[option])], True)
# Items that depend on the object type
if obj.kind.lower() == 'gerber':
@@ -363,15 +377,17 @@ class Properties(FlatCAMTool):
temp_ap['Follow_Geo'] = '%s LineStrings' % str(follow_nr)
temp_ap['Clear_Geo'] = '%s Polygons' % str(clear_nr)
- apid = self.addParent(apertures, str(ap), expanded=False, color=QtGui.QColor("#000000"), font=font)
+ apid = self.treeWidget.addParent(
+ apertures, str(ap), expanded=False, color=QtGui.QColor("#000000"), font=font)
for key in temp_ap:
- self.addChild(apid, [str(key), str(temp_ap[key])], True)
+ self.treeWidget.addChild(apid, [str(key), str(temp_ap[key])], True)
elif obj.kind.lower() == 'excellon':
tot_drill_cnt = 0
tot_slot_cnt = 0
for tool, value in obj.tools.items():
- toolid = self.addParent(tools, str(tool), expanded=False, color=QtGui.QColor("#000000"), font=font)
+ toolid = self.treeWidget.addParent(
+ tools, str(tool), expanded=False, color=QtGui.QColor("#000000"), font=font)
drill_cnt = 0 # variable to store the nr of drills per tool
slot_cnt = 0 # variable to store the nr of slots per tool
@@ -390,7 +406,7 @@ class Properties(FlatCAMTool):
tot_slot_cnt += slot_cnt
- self.addChild(
+ self.treeWidget.addChild(
toolid,
[
_('Diameter'),
@@ -398,52 +414,55 @@ class Properties(FlatCAMTool):
],
True
)
- self.addChild(toolid, [_('Drills number'), str(drill_cnt)], True)
- self.addChild(toolid, [_('Slots number'), str(slot_cnt)], True)
+ self.treeWidget.addChild(toolid, [_('Drills number'), str(drill_cnt)], True)
+ self.treeWidget.addChild(toolid, [_('Slots number'), str(slot_cnt)], True)
- self.addChild(drills, [_('Drills total number:'), str(tot_drill_cnt)], True)
- self.addChild(slots, [_('Slots total number:'), str(tot_slot_cnt)], True)
+ self.treeWidget.addChild(drills, [_('Drills total number:'), str(tot_drill_cnt)], True)
+ self.treeWidget.addChild(slots, [_('Slots total number:'), str(tot_slot_cnt)], True)
elif obj.kind.lower() == 'geometry':
for tool, value in obj.tools.items():
- geo_tool = self.addParent(tools, str(tool), expanded=True, color=QtGui.QColor("#000000"), font=font)
+ geo_tool = self.treeWidget.addParent(
+ tools, str(tool), expanded=True, color=QtGui.QColor("#000000"), font=font)
for k, v in value.items():
if k == 'solid_geometry':
printed_value = _('Present') if v else _('None')
- self.addChild(geo_tool, [str(k), printed_value], True)
+ self.treeWidget.addChild(geo_tool, [str(k), printed_value], True)
elif k == 'data':
- tool_data = self.addParent(geo_tool, str(k).capitalize(),
- color=QtGui.QColor("#000000"), font=font)
+ tool_data = self.treeWidget.addParent(
+ geo_tool, str(k).capitalize(), color=QtGui.QColor("#000000"), font=font)
for data_k, data_v in v.items():
- self.addChild(tool_data, [str(data_k), str(data_v)], True)
+ self.treeWidget.addChild(tool_data, [str(data_k), str(data_v)], True)
else:
- self.addChild(geo_tool, [str(k), str(v)], True)
+ self.treeWidget.addChild(geo_tool, [str(k), str(v)], True)
elif obj.kind.lower() == 'cncjob':
# for cncjob objects made from gerber or geometry
for tool, value in obj.cnc_tools.items():
- geo_tool = self.addParent(tools, str(tool), expanded=True, color=QtGui.QColor("#000000"), font=font)
+ geo_tool = self.treeWidget.addParent(
+ tools, str(tool), expanded=True, color=QtGui.QColor("#000000"), font=font)
for k, v in value.items():
if k == 'solid_geometry':
printed_value = _('Present') if v else _('None')
- self.addChild(geo_tool, [_("Solid Geometry"), printed_value], True)
+ self.treeWidget.addChild(geo_tool, [_("Solid Geometry"), printed_value], True)
elif k == 'gcode':
printed_value = _('Present') if v != '' else _('None')
- self.addChild(geo_tool, [_("GCode Text"), printed_value], True)
+ self.treeWidget.addChild(geo_tool, [_("GCode Text"), printed_value], True)
elif k == 'gcode_parsed':
printed_value = _('Present') if v else _('None')
- self.addChild(geo_tool, [_("GCode Geometry"), printed_value], True)
+ self.treeWidget.addChild(geo_tool, [_("GCode Geometry"), printed_value], True)
elif k == 'data':
- tool_data = self.addParent(geo_tool, _("Data"), color=QtGui.QColor("#000000"), font=font)
+ tool_data = self.treeWidget.addParent(
+ geo_tool, _("Data"), color=QtGui.QColor("#000000"), font=font)
for data_k, data_v in v.items():
- self.addChild(tool_data, [str(data_k).capitalize(), str(data_v)], True)
+ self.treeWidget.addChild(tool_data, [str(data_k).capitalize(), str(data_v)], True)
else:
- self.addChild(geo_tool, [str(k), str(v)], True)
+ self.treeWidget.addChild(geo_tool, [str(k), str(v)], True)
# for cncjob objects made from excellon
for tool_dia, value in obj.exc_cnc_tools.items():
- exc_tool = self.addParent(
+ exc_tool = self.treeWidget.addParent(
tools, str(value['tool']), expanded=False, color=QtGui.QColor("#000000"), font=font
)
- self.addChild(
+ self.treeWidget.addChild(
exc_tool,
[
_('Diameter'),
@@ -454,15 +473,15 @@ class Properties(FlatCAMTool):
for k, v in value.items():
if k == 'solid_geometry':
printed_value = _('Present') if v else _('None')
- self.addChild(exc_tool, [_("Solid Geometry"), printed_value], True)
+ self.treeWidget.addChild(exc_tool, [_("Solid Geometry"), printed_value], True)
elif k == 'nr_drills':
- self.addChild(exc_tool, [_("Drills number"), str(v)], True)
+ self.treeWidget.addChild(exc_tool, [_("Drills number"), str(v)], True)
elif k == 'nr_slots':
- self.addChild(exc_tool, [_("Slots number"), str(v)], True)
+ self.treeWidget.addChild(exc_tool, [_("Slots number"), str(v)], True)
else:
pass
- self.addChild(
+ self.treeWidget.addChild(
exc_tool,
[
_("Depth of Cut"),
@@ -474,7 +493,7 @@ class Properties(FlatCAMTool):
],
True
)
- self.addChild(
+ self.treeWidget.addChild(
exc_tool,
[
_("Clearance Height"),
@@ -486,7 +505,7 @@ class Properties(FlatCAMTool):
],
True
)
- self.addChild(
+ self.treeWidget.addChild(
exc_tool,
[
_("Feedrate"),
@@ -506,14 +525,14 @@ class Properties(FlatCAMTool):
r_time *= 60
units_lbl = 'sec'
r_time = math.ceil(float(r_time))
- self.addChild(
+ self.treeWidget.addChild(
others,
[
'%s:' % _('Routing time'),
'%.*f %s' % (self.decimals, r_time, units_lbl)],
True
)
- self.addChild(
+ self.treeWidget.addChild(
others,
[
'%s:' % _('Travelled distance'),
@@ -522,40 +541,17 @@ class Properties(FlatCAMTool):
True
)
- self.addChild(separator, [''])
-
- def addParent(self, parent, title, expanded=False, color=None, font=None):
- item = QtWidgets.QTreeWidgetItem(parent, [title])
- item.setChildIndicatorPolicy(QtWidgets.QTreeWidgetItem.ShowIndicator)
- item.setExpanded(expanded)
- if color is not None:
- # item.setTextColor(0, color) # PyQt4
- item.setForeground(0, QtGui.QBrush(color))
- if font is not None:
- item.setFont(0, font)
- return item
-
- def addChild(self, parent, title, column1=None, font=None, font_items=None):
- item = QtWidgets.QTreeWidgetItem(parent)
- item.setText(0, str(title[0]))
- if column1 is not None:
- item.setText(1, str(title[1]))
- if font and font_items:
- try:
- for fi in font_items:
- item.setFont(fi, font)
- except TypeError:
- item.setFont(font_items, font)
+ self.treeWidget.addChild(separator, [''])
def show_area_chull(self, area, length, width, chull_area, copper_area, location):
# add dimensions
- self.addChild(
+ self.treeWidget.addChild(
location,
['%s:' % _('Length'), '%.*f %s' % (self.decimals, length, self.app.defaults['units'].lower())],
True
)
- self.addChild(
+ self.treeWidget.addChild(
location,
['%s:' % _('Width'), '%.*f %s' % (self.decimals, width, self.app.defaults['units'].lower())],
True
@@ -563,16 +559,16 @@ class Properties(FlatCAMTool):
# add box area
if self.app.defaults['units'].lower() == 'mm':
- self.addChild(location, ['%s:' % _('Box Area'), '%.*f %s' % (self.decimals, area, 'cm2')], True)
- self.addChild(
+ self.treeWidget.addChild(location, ['%s:' % _('Box Area'), '%.*f %s' % (self.decimals, area, 'cm2')], True)
+ self.treeWidget.addChild(
location,
['%s:' % _('Convex_Hull Area'), '%.*f %s' % (self.decimals, chull_area, 'cm2')],
True
)
else:
- self.addChild(location, ['%s:' % _('Box Area'), '%.*f %s' % (self.decimals, area, 'in2')], True)
- self.addChild(
+ self.treeWidget.addChild(location, ['%s:' % _('Box Area'), '%.*f %s' % (self.decimals, area, 'in2')], True)
+ self.treeWidget.addChild(
location,
['%s:' % _('Convex_Hull Area'), '%.*f %s' % (self.decimals, chull_area, 'in2')],
True
@@ -580,8 +576,10 @@ class Properties(FlatCAMTool):
# add copper area
if self.app.defaults['units'].lower() == 'mm':
- self.addChild(location, ['%s:' % _('Copper Area'), '%.*f %s' % (self.decimals, copper_area, 'cm2')], True)
+ self.treeWidget.addChild(
+ location, ['%s:' % _('Copper Area'), '%.*f %s' % (self.decimals, copper_area, 'cm2')], True)
else:
- self.addChild(location, ['%s:' % _('Copper Area'), '%.*f %s' % (self.decimals, copper_area, 'in2')], True)
+ self.treeWidget.addChild(
+ location, ['%s:' % _('Copper Area'), '%.*f %s' % (self.decimals, copper_area, 'in2')], True)
# end of file
From 64ff4fb9fd13c13318124a7a9e87a128ce7a889c Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 27 Jan 2020 17:43:00 +0200
Subject: [PATCH 052/209] - started t omake some changs in Geometry Editor
---
FlatCAMApp.py | 5 ++---
README.md | 1 +
flatcamEditors/FlatCAMGeoEditor.py | 36 +++++++++++++++++++++---------
3 files changed, 29 insertions(+), 13 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index a97d67f6..db4c9ad1 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -3314,8 +3314,7 @@ class App(QtCore.QObject):
isinstance(edited_object, FlatCAMExcellon):
pass
else:
- self.inform.emit('[WARNING_NOTCL] %s' %
- _("Select a Geometry, Gerber or Excellon Object to edit."))
+ self.inform.emit('[WARNING_NOTCL] %s' % _("Select a Geometry, Gerber or Excellon Object to edit."))
return
if isinstance(edited_object, FlatCAMGeometry):
@@ -3323,7 +3322,7 @@ class App(QtCore.QObject):
self.geo_editor.toolbar_old_state = True if self.ui.geo_edit_toolbar.isVisible() else False
# we set the notebook to hidden
- self.ui.splitter.setSizes([0, 1])
+ # self.ui.splitter.setSizes([0, 1])
if edited_object.multigeo is True:
sel_rows = [item.row() for item in edited_object.ui.geo_tools_table.selectedItems()]
diff --git a/README.md b/README.md
index caf14993..ed74004a 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ CAD program, and create G-Code for Isolation routing.
- more work in Punch Gerber Tool
- the Jump To popup window will now autoselect the LineEdit therefore no more need for an extra click after launching the function
- made some structural changes in Properties Tool
+- started t omake some changs in Geometry Editor
24.02.2020
diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py
index 4dbf6389..340c61bc 100644
--- a/flatcamEditors/FlatCAMGeoEditor.py
+++ b/flatcamEditors/FlatCAMGeoEditor.py
@@ -3341,10 +3341,25 @@ class FlatCAMGeoEditor(QtCore.QObject):
self.delete_selected()
self.replot()
+ def set_ui(self):
+ # updated units
+ self.units = self.app.defaults['units'].upper()
+ self.decimals = self.app.decimals
+
+ def build_ui(self, first_run=None):
+
+ # try:
+ # # if connected, disconnect the signal from the slot on item_changed as it creates issues
+ # self.apertures_table.itemChanged.disconnect()
+ # except (TypeError, AttributeError):
+ # pass
+ pass
+
def activate(self):
# adjust the status of the menu entries related to the editor
self.app.ui.menueditedit.setDisabled(True)
self.app.ui.menueditok.setDisabled(False)
+
# adjust the visibility of some of the canvas context menu
self.app.ui.popmenu_edit.setVisible(False)
self.app.ui.popmenu_save.setVisible(True)
@@ -3382,9 +3397,9 @@ class FlatCAMGeoEditor(QtCore.QObject):
self.app.ui.g_editor_cmenu.menuAction().setVisible(True)
# prevent the user to change anything in the Selected Tab while the Geo Editor is active
- sel_tab_widget_list = self.app.ui.selected_tab.findChildren(QtWidgets.QWidget)
- for w in sel_tab_widget_list:
- w.setEnabled(False)
+ # sel_tab_widget_list = self.app.ui.selected_tab.findChildren(QtWidgets.QWidget)
+ # for w in sel_tab_widget_list:
+ # w.setEnabled(False)
# Tell the App that the editor is active
self.editor_active = True
@@ -3399,6 +3414,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
# adjust the status of the menu entries related to the editor
self.app.ui.menueditedit.setDisabled(False)
self.app.ui.menueditok.setDisabled(True)
+
# adjust the visibility of some of the canvas context menu
self.app.ui.popmenu_edit.setVisible(True)
self.app.ui.popmenu_save.setVisible(False)
@@ -3456,13 +3472,13 @@ class FlatCAMGeoEditor(QtCore.QObject):
self.app.ui.e_editor_cmenu.menuAction().setVisible(False)
self.app.ui.g_editor_cmenu.menuAction().setVisible(False)
- try:
- # re-enable all the widgets in the Selected Tab that were disabled after entering in Edit Geometry Mode
- sel_tab_widget_list = self.app.ui.selected_tab.findChildren(QtWidgets.QWidget)
- for w in sel_tab_widget_list:
- w.setEnabled(True)
- except Exception as e:
- log.debug("FlatCAMGeoEditor.deactivate() --> %s" % str(e))
+ # try:
+ # # re-enable all the widgets in the Selected Tab that were disabled after entering in Edit Geometry Mode
+ # sel_tab_widget_list = self.app.ui.selected_tab.findChildren(QtWidgets.QWidget)
+ # for w in sel_tab_widget_list:
+ # w.setEnabled(True)
+ # except Exception as e:
+ # log.debug("FlatCAMGeoEditor.deactivate() --> %s" % str(e))
# Show original geometry
if self.fcgeometry:
From fd0438842d9a234806a6df66a7da1da8bacc1d63 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Tue, 28 Jan 2020 03:59:15 +0200
Subject: [PATCH 053/209] - finished adding in Geometry Editor a TreeWidget
with the geometry shapes found in the edited object
---
FlatCAMApp.py | 11 +-
README.md | 3 +-
camlib.py | 2 +-
flatcamEditors/FlatCAMGeoEditor.py | 202 ++++++++++++++++++++++++++---
flatcamGUI/GUIElements.py | 5 +-
5 files changed, 202 insertions(+), 21 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index db4c9ad1..1a228bf9 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -3444,6 +3444,13 @@ class App(QtCore.QObject):
self.inform.emit('[WARNING] %s' %
_("Object empty after edit."))
log.debug("App.editor2object() --> Geometry --> %s" % str(e))
+
+ # restore GUI to the Selected TAB
+ # Remove anything else in the GUI
+ self.ui.tool_scroll_area.takeWidget()
+ # Switch notebook to Selected page
+ self.ui.notebook.setCurrentWidget(self.ui.selected_tab)
+
elif isinstance(edited_obj, FlatCAMGerber):
obj_type = "Gerber"
if cleanup is None:
@@ -3494,8 +3501,7 @@ class App(QtCore.QObject):
_("Select a Gerber, Geometry or Excellon Object to update."))
return
- self.inform.emit('[selected] %s %s' %
- (obj_type, _("is updated, returning to App...")))
+ self.inform.emit('[selected] %s %s' % (obj_type, _("is updated, returning to App...")))
elif response == bt_no:
# clean the Tools Tab
self.ui.tool_scroll_area.takeWidget()
@@ -3514,6 +3520,7 @@ class App(QtCore.QObject):
_("Select a Gerber, Geometry or Excellon Object to update."))
return
edited_obj.set_ui(edited_obj.ui_type(decimals=self.decimals))
+ edited_obj.build_ui()
self.ui.notebook.setCurrentWidget(self.ui.selected_tab)
elif response == bt_cancel:
return
diff --git a/README.md b/README.md
index ed74004a..e3dfaf54 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,8 @@ CAD program, and create G-Code for Isolation routing.
- more work in Punch Gerber Tool
- the Jump To popup window will now autoselect the LineEdit therefore no more need for an extra click after launching the function
- made some structural changes in Properties Tool
-- started t omake some changs in Geometry Editor
+- started to make some changes in Geometry Editor
+- finished adding in Geometry Editor a TreeWidget with the geometry shapes found in the edited object
24.02.2020
diff --git a/camlib.py b/camlib.py
index 063478b1..d234dc90 100644
--- a/camlib.py
+++ b/camlib.py
@@ -5972,7 +5972,7 @@ class FlatCAMRTreeStorage(FlatCAMRTree):
self.objects.append(obj)
idx = len(self.objects) - 1
- # Note: Shapely objects are not hashable any more, althought
+ # Note: Shapely objects are not hashable any more, although
# there seem to be plans to re-introduce the feature in
# version 2.0. For now, we will index using the object's id,
# but it's important to remember that shapely geometry is
diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py
index 340c61bc..7a5a63c6 100644
--- a/flatcamEditors/FlatCAMGeoEditor.py
+++ b/flatcamEditors/FlatCAMGeoEditor.py
@@ -18,7 +18,7 @@ from camlib import distance, arc, three_point_circle, Geometry, FlatCAMRTreeStor
from FlatCAMTool import FlatCAMTool
from flatcamGUI.ObjectUI import RadioSet
from flatcamGUI.GUIElements import OptionalInputSection, FCCheckBox, FCEntry, FCComboBox, FCTextAreaRich, \
- FCTable, FCDoubleSpinner, FCButton, EvalEntry2, FCInputDialog
+ FCTable, FCDoubleSpinner, FCButton, EvalEntry2, FCInputDialog, FCTree
from flatcamParsers.ParseFont import *
import FlatCAMApp
@@ -2494,8 +2494,29 @@ class FCSelect(DrawTool):
self.draw_app.selected = []
self.draw_app.selected.append(obj_to_add)
except Exception as e:
- log.error("[ERROR] Something went bad. %s" % str(e))
- raise
+ log.error("[ERROR] FlatCAMGeoEditor.FCSelect.click_release() -> Something went bad. %s" % str(e))
+
+ # if selection is done on canvas update the Tree in Selected Tab with the selection
+ try:
+ self.draw_app.tw.itemSelectionChanged.disconnect(self.draw_app.on_tree_selection_change)
+ except (AttributeError, TypeError):
+ pass
+
+ self.draw_app.tw.selectionModel().clearSelection()
+ for sel_shape in self.draw_app.selected:
+ iterator = QtWidgets.QTreeWidgetItemIterator(self.draw_app.tw)
+ while iterator.value():
+ item = iterator.value()
+ try:
+ if int(item.text(1)) == id(sel_shape):
+ item.setSelected(True)
+ except ValueError:
+ pass
+
+ iterator += 1
+
+ self.draw_app.tw.itemSelectionChanged.connect(self.draw_app.on_tree_selection_change)
+
return ""
def clean_up(self):
@@ -3126,6 +3147,9 @@ class FCTransform(FCShapeTool):
# ###############################################
class FlatCAMGeoEditor(QtCore.QObject):
+ # will emit the name of the object that was just selected
+ item_selected = QtCore.pyqtSignal(str)
+
transform_complete = QtCore.pyqtSignal()
draw_shape_idx = -1
@@ -3140,6 +3164,47 @@ class FlatCAMGeoEditor(QtCore.QObject):
self.canvas = app.plotcanvas
self.decimals = app.decimals
+ self.geo_edit_widget = QtWidgets.QWidget()
+ # ## Box for custom widgets
+ # This gets populated in offspring implementations.
+ layout = QtWidgets.QVBoxLayout()
+ self.geo_edit_widget.setLayout(layout)
+
+ # 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.geo_frame = QtWidgets.QFrame()
+ self.geo_frame.setContentsMargins(0, 0, 0, 0)
+ layout.addWidget(self.geo_frame)
+ self.tools_box = QtWidgets.QVBoxLayout()
+ self.tools_box.setContentsMargins(0, 0, 0, 0)
+ self.geo_frame.setLayout(self.tools_box)
+
+ # ## Page Title box (spacing between children)
+ self.title_box = QtWidgets.QHBoxLayout()
+ self.tools_box.addLayout(self.title_box)
+
+ # ## Page Title icon
+ pixmap = QtGui.QPixmap(self.app.resource_location + '/flatcam_icon32.png')
+ self.icon = QtWidgets.QLabel()
+ self.icon.setPixmap(pixmap)
+ self.title_box.addWidget(self.icon, stretch=0)
+
+ # ## Title label
+ self.title_label = QtWidgets.QLabel("%s" % _('Geometry Editor'))
+ self.title_label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
+ self.title_box.addWidget(self.title_label, stretch=1)
+ self.title_box.addWidget(QtWidgets.QLabel(''))
+
+ self.tw = FCTree(extended_sel=True)
+ self.tools_box.addWidget(self.tw)
+
+ self.geo_font = QtGui.QFont()
+ self.geo_font.setBold(True)
+
+ parent = self.tw.invisibleRootItem()
+ self.geo_parent = self.tw.addParent(
+ parent, _('Geometry Elements'), expanded=True, color=QtGui.QColor("#000000"), font=self.geo_font)
+
# ## Toolbar events and properties
self.tools = {
"select": {"button": self.app.ui.geo_select_btn,
@@ -3346,6 +3411,13 @@ class FlatCAMGeoEditor(QtCore.QObject):
self.units = self.app.defaults['units'].upper()
self.decimals = self.app.decimals
+ # Remove anything else in the GUI Selected Tab
+ self.app.ui.selected_scroll_area.takeWidget()
+ # Put ourselves in the GUI Selected Tab
+ self.app.ui.selected_scroll_area.setWidget(self.geo_edit_widget)
+ # Switch notebook to Selected page
+ self.app.ui.notebook.setCurrentWidget(self.app.ui.selected_tab)
+
def build_ui(self, first_run=None):
# try:
@@ -3353,8 +3425,56 @@ class FlatCAMGeoEditor(QtCore.QObject):
# self.apertures_table.itemChanged.disconnect()
# except (TypeError, AttributeError):
# pass
+
+ iterator = QtWidgets.QTreeWidgetItemIterator(self.geo_parent)
+ to_delete = list()
+ while iterator.value():
+ item = iterator.value()
+ to_delete.append(item)
+ iterator += 1
+ for it in to_delete:
+ self.geo_parent.removeChild(it)
+
+ for elem in self.storage.get_objects():
+ geo_type = type(elem.geo)
+ title = None
+ if geo_type is LinearRing:
+ title = _('ID Ring')
+ elif geo_type is LineString:
+ title = _('ID Line')
+ elif geo_type is Polygon:
+ title = _('ID Polygon')
+ elif geo_type is MultiLineString:
+ title = _('ID Multi-Line')
+ elif geo_type is MultiPolygon:
+ title = _('ID Multi-Polygon')
+
+ self.tw.addChild(
+ self.geo_parent,
+ [
+ '%s:' % title,
+ str(id(elem))
+ ],
+ True,
+ font=self.geo_font,
+ font_items=1
+ )
+
+ def on_geo_elem_selected(self):
pass
+ def on_tree_selection_change(self):
+ self.selected = list()
+ selected_tree_items = self.tw.selectedItems()
+ for sel in selected_tree_items:
+ for obj_shape in self.storage.get_objects():
+ try:
+ if id(obj_shape) == int(sel.text(1)):
+ self.selected.append(obj_shape)
+ except ValueError:
+ pass
+ self.replot()
+
def activate(self):
# adjust the status of the menu entries related to the editor
self.app.ui.menueditedit.setDisabled(True)
@@ -3403,12 +3523,22 @@ class FlatCAMGeoEditor(QtCore.QObject):
# Tell the App that the editor is active
self.editor_active = True
+
+ self.item_selected.connect(self.on_geo_elem_selected)
+
+ # ## GUI Events
+ self.tw.itemSelectionChanged.connect(self.on_tree_selection_change)
+ # self.tw.keyPressed.connect(self.app.ui.keyPressEvent)
+ # self.tw.customContextMenuRequested.connect(self.on_menu_request)
+
+ self.geo_frame.show()
+
log.debug("Finished activating the Geometry Editor...")
def deactivate(self):
try:
QtGui.QGuiApplication.restoreOverrideCursor()
- except Exception as e:
+ except Exception:
pass
# adjust the status of the menu entries related to the editor
@@ -3472,6 +3602,19 @@ class FlatCAMGeoEditor(QtCore.QObject):
self.app.ui.e_editor_cmenu.menuAction().setVisible(False)
self.app.ui.g_editor_cmenu.menuAction().setVisible(False)
+ try:
+ self.item_selected.disconnect()
+ except (AttributeError, TypeError):
+ pass
+
+ try:
+ # ## GUI Events
+ self.tw.itemSelectionChanged.disconnect(self.on_tree_selection_change)
+ # self.tw.keyPressed.connect(self.app.ui.keyPressEvent)
+ # self.tw.customContextMenuRequested.connect(self.on_menu_request)
+ except (AttributeError, TypeError):
+ pass
+
# try:
# # re-enable all the widgets in the Selected Tab that were disabled after entering in Edit Geometry Mode
# sel_tab_widget_list = self.app.ui.selected_tab.findChildren(QtWidgets.QWidget)
@@ -3483,6 +3626,10 @@ class FlatCAMGeoEditor(QtCore.QObject):
# Show original geometry
if self.fcgeometry:
self.fcgeometry.visible = True
+
+ # hide the UI
+ self.geo_frame.hide()
+
log.debug("Finished deactivating the Geometry Editor...")
def connect_canvas_event_handlers(self):
@@ -3684,6 +3831,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
self.utility.append(shape)
else:
self.storage.insert(shape) # TODO: Check performance
+ self.build_ui()
def delete_utility_geometry(self):
# for_deletion = [shape for shape in self.shape_buffer if shape.utility]
@@ -3724,6 +3872,8 @@ class FlatCAMGeoEditor(QtCore.QObject):
self.deactivate()
self.activate()
+ self.set_ui()
+
# Hide original geometry
self.fcgeometry = fcgeometry
fcgeometry.visible = False
@@ -3845,7 +3995,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
self.pos = self.canvas.translate_coords(event_pos)
- if self.app.grid_status() == True:
+ if self.app.grid_status():
self.pos = self.app.geo_editor.snap(self.pos[0], self.pos[1])
else:
self.pos = (self.pos[0], self.pos[1])
@@ -3925,7 +4075,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
return
# ### Snap coordinates ###
- if self.app.grid_status() == True:
+ if self.app.grid_status():
x, y = self.snap(x, y)
# Update cursor
@@ -3939,7 +4089,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
# update the position label in the infobar since the APP mouse event handlers are disconnected
self.app.ui.position_label.setText(" X: %.4f "
- "Y: %.4f" % (x, y))
+ "Y: %.4f" % (x, y))
if self.pos is None:
self.pos = (0, 0)
@@ -3948,7 +4098,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
# update the reference position label in the infobar since the APP mouse event handlers are disconnected
self.app.ui.rel_position_label.setText("Dx: %.4f Dy: "
- "%.4f " % (dx, dy))
+ "%.4f " % (dx, dy))
if event.button == 1 and event_is_dragging and isinstance(self.active_tool, FCEraser):
pass
@@ -3961,8 +4111,8 @@ class FlatCAMGeoEditor(QtCore.QObject):
self.app.delete_selection_shape()
if dx < 0:
self.app.draw_moving_selection_shape((self.pos[0], self.pos[1]), (x, y),
- color=self.app.defaults["global_alt_sel_line"],
- face_color=self.app.defaults['global_alt_sel_fill'])
+ color=self.app.defaults["global_alt_sel_line"],
+ face_color=self.app.defaults['global_alt_sel_fill'])
self.app.selection_type = False
else:
self.app.draw_moving_selection_shape((self.pos[0], self.pos[1]), (x, y))
@@ -4011,19 +4161,18 @@ class FlatCAMGeoEditor(QtCore.QObject):
# self.app.inform.emit(msg)
self.replot()
elif event.button == right_button: # right click
- if self.app.ui.popMenu.mouse_is_panning == False:
+ if self.app.ui.popMenu.mouse_is_panning is False:
if self.in_action is False:
try:
QtGui.QGuiApplication.restoreOverrideCursor()
- except Exception as e:
+ except Exception:
pass
if self.active_tool.complete is False and not isinstance(self.active_tool, FCSelect):
self.active_tool.complete = True
self.in_action = False
self.delete_utility_geometry()
- self.app.inform.emit('[success] %s' %
- _("Done."))
+ self.app.inform.emit('[success] %s' % _("Done."))
self.select_tool('select')
else:
self.app.cursor = QtGui.QCursor()
@@ -4037,8 +4186,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
self.active_tool.make()
if self.active_tool.complete:
self.on_shape_complete()
- self.app.inform.emit('[success] %s' %
- _("Done."))
+ self.app.inform.emit('[success] %s' % _("Done."))
self.select_tool(self.active_tool.name)
except Exception as e:
log.warning("FLatCAMGeoEditor.on_geo_click_release() --> Error: %s" % str(e))
@@ -4082,6 +4230,27 @@ class FlatCAMGeoEditor(QtCore.QObject):
self.selected = []
self.selected = sel_objects_list
+ # if selection is done on canvas update the Tree in Selected Tab with the selection
+ try:
+ self.tw.itemSelectionChanged.disconnect(self.on_tree_selection_change)
+ except (AttributeError, TypeError):
+ pass
+
+ self.tw.selectionModel().clearSelection()
+ for sel_shape in self.selected:
+ iterator = QtWidgets.QTreeWidgetItemIterator(self.tw)
+ while iterator.value():
+ item = iterator.value()
+ try:
+ if int(item.text(1)) == id(sel_shape):
+ item.setSelected(True)
+ except ValueError:
+ pass
+
+ iterator += 1
+
+ self.tw.itemSelectionChanged.connect(self.on_tree_selection_change)
+
self.replot()
def draw_utility_geometry(self, geo):
@@ -4131,6 +4300,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
for shape in tempref:
self.delete_shape(shape)
self.selected = []
+ self.build_ui()
def delete_shape(self, shape):
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index a136e16c..b9f17d9e 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -154,7 +154,7 @@ class RadioSet(QtWidgets.QWidget):
class FCTree(QtWidgets.QTreeWidget):
- def __init__(self, parent=None, columns=2, header_hidden=True):
+ def __init__(self, parent=None, columns=2, header_hidden=True, extended_sel=False):
super(FCTree, self).__init__(parent)
self.setColumnCount(columns)
@@ -162,6 +162,9 @@ class FCTree(QtWidgets.QTreeWidget):
self.header().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
self.setSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Expanding)
+ if extended_sel:
+ self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
+
def addParent(self, parent, title, expanded=False, color=None, font=None):
item = QtWidgets.QTreeWidgetItem(parent, [title])
item.setChildIndicatorPolicy(QtWidgets.QTreeWidgetItem.ShowIndicator)
From 85afb7cdb2a1173653431c87e5f941dd652e5a55 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Tue, 28 Jan 2020 17:34:21 +0200
Subject: [PATCH 054/209] - some changes in Excellon Editor
---
FlatCAMApp.py | 16 ++++++----------
README.md | 4 ++++
flatcamTools/ToolPunchGerber.py | 11 -----------
3 files changed, 10 insertions(+), 21 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 1a228bf9..a0c2bd30 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -3448,8 +3448,6 @@ class App(QtCore.QObject):
# restore GUI to the Selected TAB
# Remove anything else in the GUI
self.ui.tool_scroll_area.takeWidget()
- # Switch notebook to Selected page
- self.ui.notebook.setCurrentWidget(self.ui.selected_tab)
elif isinstance(edited_obj, FlatCAMGerber):
obj_type = "Gerber"
@@ -3473,14 +3471,12 @@ class App(QtCore.QObject):
# restore GUI to the Selected TAB
# Remove anything else in the GUI
self.ui.selected_scroll_area.takeWidget()
- # Switch notebook to Selected page
- self.ui.notebook.setCurrentWidget(self.ui.selected_tab)
elif isinstance(edited_obj, FlatCAMExcellon):
obj_type = "Excellon"
if cleanup is None:
self.exc_editor.update_fcexcellon(edited_obj)
- self.exc_editor.update_options(edited_obj)
+ # self.exc_editor.update_options(edited_obj)
self.exc_editor.deactivate()
@@ -3493,8 +3489,6 @@ class App(QtCore.QObject):
# restore GUI to the Selected TAB
# Remove anything else in the GUI
self.ui.tool_scroll_area.takeWidget()
- # Switch notebook to Selected page
- self.ui.notebook.setCurrentWidget(self.ui.selected_tab)
else:
self.inform.emit('[WARNING_NOTCL] %s' %
@@ -3519,11 +3513,13 @@ class App(QtCore.QObject):
self.inform.emit('[WARNING_NOTCL] %s' %
_("Select a Gerber, Geometry or Excellon Object to update."))
return
- edited_obj.set_ui(edited_obj.ui_type(decimals=self.decimals))
- edited_obj.build_ui()
- self.ui.notebook.setCurrentWidget(self.ui.selected_tab)
elif response == bt_cancel:
return
+
+ edited_obj.set_ui(edited_obj.ui_type(decimals=self.decimals))
+ edited_obj.build_ui()
+ # Switch notebook to Selected page
+ self.ui.notebook.setCurrentWidget(self.ui.selected_tab)
else:
if isinstance(edited_obj, FlatCAMGeometry):
self.geo_editor.deactivate()
diff --git a/README.md b/README.md
index e3dfaf54..fc0ebf77 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+28.01.2020
+
+- some changes in Excellon Editor
+
27.01.2020
- in Geometry Editor made sure that on final save, for MultiLineString geometry all the connected lines are merged into one LineString to minimize the number of vertical movements in GCode
diff --git a/flatcamTools/ToolPunchGerber.py b/flatcamTools/ToolPunchGerber.py
index 16aeabb8..807bbe0c 100644
--- a/flatcamTools/ToolPunchGerber.py
+++ b/flatcamTools/ToolPunchGerber.py
@@ -15,17 +15,6 @@ from copy import deepcopy
import logging
from shapely.geometry import Polygon, MultiPolygon, Point
-from reportlab.graphics import renderPDF
-from reportlab.pdfgen import canvas
-from reportlab.graphics import renderPM
-from reportlab.lib.units import inch, mm
-from reportlab.lib.pagesizes import landscape, portrait
-
-from svglib.svglib import svg2rlg
-from xml.dom.minidom import parseString as parse_xml_string
-from lxml import etree as ET
-from io import StringIO
-
import gettext
import FlatCAMTranslation as fcTranslate
import builtins
From d7f7d79d6a522cf5ccac196dea07c4bdcf82bc84 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 29 Jan 2020 03:14:46 +0200
Subject: [PATCH 055/209] - changes in how the Editor exit is handled - small
fix in some pywin32 imports
---
FlatCAMApp.py | 62 +++++++++++++++++-------------
ObjectCollection.py | 53 +++++++++++++++++++++++++
README.md | 5 +++
flatcamEditors/FlatCAMExcEditor.py | 2 +
4 files changed, 96 insertions(+), 26 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index a0c2bd30..c84bfc4b 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -279,7 +279,7 @@ class App(QtCore.QObject):
# Folder for user settings.
if sys.platform == 'win32':
- from win32com.shell import shell, shellcon
+ from win32comext.shell import shell, shellcon
if platform.architecture()[0] == '32bit':
App.log.debug("Win32!")
else:
@@ -3430,9 +3430,14 @@ class App(QtCore.QObject):
obj_type = "Geometry"
if cleanup is None:
self.geo_editor.update_fcgeometry(edited_obj)
- self.geo_editor.update_options(edited_obj)
+ # self.geo_editor.update_options(edited_obj)
+
self.geo_editor.deactivate()
+ # restore GUI to the Selected TAB
+ # Remove anything else in the GUI
+ self.ui.tool_scroll_area.takeWidget()
+
# update the geo object options so it is including the bounding box values
try:
xmin, ymin, xmax, ymax = edited_obj.bounds()
@@ -3441,13 +3446,11 @@ class App(QtCore.QObject):
edited_obj.options['xmax'] = xmax
edited_obj.options['ymax'] = ymax
except AttributeError as e:
- self.inform.emit('[WARNING] %s' %
- _("Object empty after edit."))
+ self.inform.emit('[WARNING] %s' % _("Object empty after edit."))
log.debug("App.editor2object() --> Geometry --> %s" % str(e))
- # restore GUI to the Selected TAB
- # Remove anything else in the GUI
- self.ui.tool_scroll_area.takeWidget()
+ edited_obj.build_ui()
+ self.inform.emit('[success] %s' % _("Editor exited. Editor content saved."))
elif isinstance(edited_obj, FlatCAMGerber):
obj_type = "Gerber"
@@ -3468,6 +3471,8 @@ class App(QtCore.QObject):
# a single Polygon, therefore we pass this
pass
+ self.inform.emit('[success] %s' % _("Editor exited. Editor content saved."))
+
# restore GUI to the Selected TAB
# Remove anything else in the GUI
self.ui.selected_scroll_area.takeWidget()
@@ -3480,16 +3485,16 @@ class App(QtCore.QObject):
self.exc_editor.deactivate()
- # delete the old object (the source object) if it was an empty one
- if len(edited_obj.drills) == 0 and len(edited_obj.slots) == 0:
- old_name = edited_obj.options['name']
- self.collection.set_active(old_name)
- self.collection.delete_active()
-
# restore GUI to the Selected TAB
# Remove anything else in the GUI
self.ui.tool_scroll_area.takeWidget()
+ # delete the old object (the source object) if it was an empty one
+ if len(edited_obj.drills) == 0 and len(edited_obj.slots) == 0:
+ old_name = edited_obj.options['name']
+ self.collection.delete_by_name(name=old_name)
+ self.inform.emit('[success] %s' % _("Editor exited. Editor content saved."))
+
else:
self.inform.emit('[WARNING_NOTCL] %s' %
_("Select a Gerber, Geometry or Excellon Object to update."))
@@ -3502,13 +3507,17 @@ class App(QtCore.QObject):
self.ui.tool_scroll_area.setWidget(QtWidgets.QWidget())
self.ui.notebook.setTabText(2, "Tool")
+ self.inform.emit('[WARNING_NOTCL] %s' % _("Editor exited. Editor content was not saved."))
+
if isinstance(edited_obj, FlatCAMGeometry):
self.geo_editor.deactivate()
+ edited_obj.build_ui()
elif isinstance(edited_obj, FlatCAMGerber):
self.grb_editor.deactivate_grb_editor()
+ edited_obj.build_ui()
elif isinstance(edited_obj, FlatCAMExcellon):
self.exc_editor.deactivate()
- # set focus on the project tab
+ edited_obj.build_ui()
else:
self.inform.emit('[WARNING_NOTCL] %s' %
_("Select a Gerber, Geometry or Excellon Object to update."))
@@ -3516,8 +3525,8 @@ class App(QtCore.QObject):
elif response == bt_cancel:
return
- edited_obj.set_ui(edited_obj.ui_type(decimals=self.decimals))
- edited_obj.build_ui()
+ # edited_obj.set_ui(edited_obj.ui_type(decimals=self.decimals))
+ # edited_obj.build_ui()
# Switch notebook to Selected page
self.ui.notebook.setCurrentWidget(self.ui.selected_tab)
else:
@@ -3926,7 +3935,8 @@ class App(QtCore.QObject):
json.dump(self.defaults, f_f_def_s, default=to_dict, indent=2, sort_keys=True)
f_f_def_s.close()
- # and then make the factory_defaults.FlatConfig file read_only so it can't be modified after creation.
+ # and then make the factory_defaults.FlatConfig file read_only
+ # so it can't be modified after creation.
os.chmod(fact_def_file_path, S_IREAD | S_IRGRP | S_IROTH)
except Exception as e:
log.debug("App.load_defaults() -> deleting old factory defaults file -> %s" % str(e))
@@ -10362,7 +10372,7 @@ class App(QtCore.QObject):
filename, _f = QtWidgets.QFileDialog.getSaveFileName(
caption=_("Save Project As ..."),
directory=('{l_save}/{proj}_{date}').format(l_save=str(self.get_last_save_folder()), date=self.date,
- proj=_("Project")),
+ proj=_("Project")),
filter=filter_
)
except TypeError:
@@ -10416,8 +10426,8 @@ class App(QtCore.QObject):
filename, _f = QtWidgets.QFileDialog.getSaveFileName(
caption=_("Save Object as PDF ..."),
directory=('{l_save}/{obj_name}_{date}').format(l_save=str(self.get_last_save_folder()),
- obj_name=obj_name,
- date=self.date),
+ obj_name=obj_name,
+ date=self.date),
filter=filter_
)
except TypeError:
@@ -11204,7 +11214,7 @@ class App(QtCore.QObject):
# # ## Object creation # ##
ret = self.new_object("gerber", name, obj_init, autoselected=False)
if ret == 'fail':
- self.inform.emit('[ERROR_NOTCL]%s' % _(' Open Gerber failed. Probable not a Gerber file.'))
+ self.inform.emit('[ERROR_NOTCL]%s' % _(' Open Gerber failed. Probable not a Gerber file.'))
return 'fail'
# Register recent file
@@ -11218,11 +11228,11 @@ class App(QtCore.QObject):
Opens an Excellon file, parses it and creates a new object for
it in the program. Thread-safe.
- :param outname: Name of the resulting object. None causes the
- name to be that of the file.
- :param filename: Excellon file filename
- :type filename: str
- :return: None
+ :param outname: Name of the resulting object. None causes the name to be that of the file.
+ :param filename: Excellon file filename
+ :type filename: str
+ :param plot: boolean, to plot or not the resulting object
+ :return: None
"""
App.log.debug("open_excellon()")
diff --git a/ObjectCollection.py b/ObjectCollection.py
index bf7c07dd..799d163c 100644
--- a/ObjectCollection.py
+++ b/ObjectCollection.py
@@ -645,6 +645,59 @@ class ObjectCollection(QtCore.QAbstractItemModel):
if not self.get_list():
self.app.ui.splitter.setSizes([0, 1])
+ def delete_by_name(self, name, select_project=True):
+ obj = self.get_by_name(name=name)
+ item = obj.item
+ group = self.group_items[obj.kind]
+
+ group_index = self.index(group.row(), 0, QtCore.QModelIndex())
+ item_index = self.index(item.row(), 0, group_index)
+
+ deleted = item_index.internalPointer()
+ group = deleted.parent_item
+
+ # some objects add a Tab on creation, close it here
+ for idx in range(self.app.ui.plot_tab_area.count()):
+ if self.app.ui.plot_tab_area.widget(idx).objectName() == deleted.obj.options['name']:
+ self.app.ui.plot_tab_area.removeTab(idx)
+ break
+
+ # update the SHELL auto-completer model data
+ name = deleted.obj.options['name']
+ try:
+ self.app.myKeywords.remove(name)
+ self.app.shell._edit.set_model_data(self.app.myKeywords)
+ # this is not needed any more because now the code editor is created on demand
+ # self.app.ui.code_editor.set_model_data(self.app.myKeywords)
+ except Exception as e:
+ log.debug(
+ "delete_active() --> Could not remove the old object name from auto-completer model list. %s" % str(e))
+
+ self.app.object_status_changed.emit(deleted.obj, 'delete', name)
+
+ # ############ OBJECT DELETION FROM MODEL STARTS HERE ####################
+ self.beginRemoveRows(self.index(group.row(), 0, QtCore.QModelIndex()), deleted.row(), deleted.row())
+ group.remove_child(deleted)
+ # after deletion of object store the current list of objects into the self.app.all_objects_list
+ self.app.all_objects_list = self.get_list()
+ self.endRemoveRows()
+ # ############ OBJECT DELETION FROM MODEL STOPS HERE ####################
+
+ if self.app.is_legacy is False:
+ self.app.plotcanvas.redraw()
+
+ if select_project:
+ # always go to the Project Tab after object deletion as it may be done with a shortcut key
+ self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
+
+ self.app.should_we_save = True
+
+ # decide if to show or hide the Notebook side of the screen
+ if self.app.defaults["global_project_autohide"] is True:
+ # hide the notebook if there are no objects in the collection
+ if not self.get_list():
+ self.app.ui.splitter.setSizes([0, 1])
+
def delete_all(self):
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.delete_all()")
diff --git a/README.md b/README.md
index fc0ebf77..dcd8d762 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+29.01.2020
+
+- changes in how the Editor exit is handled
+- small fix in some pywin32 imports
+
28.01.2020
- some changes in Excellon Editor
diff --git a/flatcamEditors/FlatCAMExcEditor.py b/flatcamEditors/FlatCAMExcEditor.py
index 1e621a9c..e2dc8bdb 100644
--- a/flatcamEditors/FlatCAMExcEditor.py
+++ b/flatcamEditors/FlatCAMExcEditor.py
@@ -3270,6 +3270,8 @@ class FlatCAMExcEditor(QtCore.QObject):
self.new_slots,
self.new_tools]})
+ return self.edited_obj_name
+
def update_options(self, obj):
try:
if not obj.options:
From a6b2b0af54287e68bee28991283340aab6e4f538 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 29 Jan 2020 15:52:44 +0200
Subject: [PATCH 056/209] - remade the GUI + small fixes in 2Sided Tool
---
FlatCAMApp.py | 5 +-
README.md | 1 +
flatcamTools/ToolDblSided.py | 260 ++++++++++++++++++++++-------------
3 files changed, 168 insertions(+), 98 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index c84bfc4b..fcd66c45 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -7152,12 +7152,11 @@ class App(QtCore.QObject):
pass
self.delete_first_selected()
- self.inform.emit('%s...' %
- _("Object(s) deleted"))
+ self.inform.emit('%s...' % _("Object(s) deleted"))
# make sure that the selection shape is deleted, too
self.delete_selection_shape()
else:
- self.inform.emit(_("Failed. No object(s) selected..."))
+ self.inform.emit('[ERROR_NOTCL] %s' % _("Failed. No object(s) selected..."))
else:
self.inform.emit(_("Save the work in Editor and try again ..."))
diff --git a/README.md b/README.md
index dcd8d762..5510fb44 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- changes in how the Editor exit is handled
- small fix in some pywin32 imports
+- remade the GUI + small fixes in 2Sided Tool
28.01.2020
diff --git a/flatcamTools/ToolDblSided.py b/flatcamTools/ToolDblSided.py
index 0b00fc6e..bbc6c266 100644
--- a/flatcamTools/ToolDblSided.py
+++ b/flatcamTools/ToolDblSided.py
@@ -2,7 +2,7 @@
from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, EvalEntry, FCEntry
+from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, EvalEntry, FCEntry, FCButton
from FlatCAMObj import FlatCAMGerber, FlatCAMExcellon, FlatCAMGeometry
from numpy import Inf
@@ -41,14 +41,19 @@ class DblSidedTool(FlatCAMTool):
""")
self.layout.addWidget(title_label)
- self.empty_lb = QtWidgets.QLabel("")
- self.layout.addWidget(self.empty_lb)
+ self.layout.addWidget(QtWidgets.QLabel(""))
# ## Grid Layout
grid_lay = QtWidgets.QGridLayout()
- self.layout.addLayout(grid_lay)
grid_lay.setColumnStretch(0, 1)
grid_lay.setColumnStretch(1, 0)
+ self.layout.addLayout(grid_lay)
+
+ # Objects to be mirrored
+ self.m_objects_label = QtWidgets.QLabel("%s:" % _("Mirror Operation"))
+ self.m_objects_label.setToolTip('%s.' % _("Objects to be mirrored"))
+
+ grid_lay.addWidget(self.m_objects_label, 0, 0, 1, 2)
# ## Gerber Object to mirror
self.gerber_object_combo = QtWidgets.QComboBox()
@@ -56,7 +61,7 @@ class DblSidedTool(FlatCAMTool):
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.gerber_object_combo.setCurrentIndex(1)
- self.botlay_label = QtWidgets.QLabel("%s:" % _("GERBER"))
+ self.botlay_label = QtWidgets.QLabel("%s:" % _("GERBER"))
self.botlay_label.setToolTip('%s.' % _("Gerber to be mirrored"))
self.mirror_gerber_button = QtWidgets.QPushButton(_("Mirror"))
@@ -73,10 +78,9 @@ class DblSidedTool(FlatCAMTool):
""")
self.mirror_gerber_button.setMinimumWidth(60)
- # grid_lay.addRow("Bottom Layer:", self.object_combo)
- grid_lay.addWidget(self.botlay_label, 0, 0)
- grid_lay.addWidget(self.gerber_object_combo, 1, 0)
- grid_lay.addWidget(self.mirror_gerber_button, 1, 1)
+ grid_lay.addWidget(self.botlay_label, 1, 0)
+ grid_lay.addWidget(self.gerber_object_combo, 2, 0)
+ grid_lay.addWidget(self.mirror_gerber_button, 2, 1)
# ## Excellon Object to mirror
self.exc_object_combo = QtWidgets.QComboBox()
@@ -84,7 +88,7 @@ class DblSidedTool(FlatCAMTool):
self.exc_object_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
self.exc_object_combo.setCurrentIndex(1)
- self.excobj_label = QtWidgets.QLabel("%s:" % _("EXCELLON"))
+ self.excobj_label = QtWidgets.QLabel("%s:" % _("EXCELLON"))
self.excobj_label.setToolTip(_("Excellon Object to be mirrored."))
self.mirror_exc_button = QtWidgets.QPushButton(_("Mirror"))
@@ -101,10 +105,9 @@ class DblSidedTool(FlatCAMTool):
""")
self.mirror_exc_button.setMinimumWidth(60)
- # grid_lay.addRow("Bottom Layer:", self.object_combo)
- grid_lay.addWidget(self.excobj_label, 2, 0)
- grid_lay.addWidget(self.exc_object_combo, 3, 0)
- grid_lay.addWidget(self.mirror_exc_button, 3, 1)
+ grid_lay.addWidget(self.excobj_label, 3, 0)
+ grid_lay.addWidget(self.exc_object_combo, 4, 0)
+ grid_lay.addWidget(self.mirror_exc_button, 4, 1)
# ## Geometry Object to mirror
self.geo_object_combo = QtWidgets.QComboBox()
@@ -112,7 +115,7 @@ class DblSidedTool(FlatCAMTool):
self.geo_object_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
self.geo_object_combo.setCurrentIndex(1)
- self.geoobj_label = QtWidgets.QLabel("%s:" % _("GEOMETRY"))
+ self.geoobj_label = QtWidgets.QLabel("%s:" % _("GEOMETRY"))
self.geoobj_label.setToolTip(
_("Geometry Obj to be mirrored.")
)
@@ -132,58 +135,57 @@ class DblSidedTool(FlatCAMTool):
self.mirror_geo_button.setMinimumWidth(60)
# grid_lay.addRow("Bottom Layer:", self.object_combo)
- grid_lay.addWidget(self.geoobj_label, 4, 0)
- grid_lay.addWidget(self.geo_object_combo, 5, 0)
- grid_lay.addWidget(self.mirror_geo_button, 5, 1)
+ grid_lay.addWidget(self.geoobj_label, 5, 0)
+ grid_lay.addWidget(self.geo_object_combo, 6, 0)
+ grid_lay.addWidget(self.mirror_geo_button, 6, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid_lay.addWidget(separator_line, 7, 0, 1, 2)
+
+ self.layout.addWidget(QtWidgets.QLabel(""))
# ## Grid Layout
grid_lay1 = QtWidgets.QGridLayout()
+ grid_lay1.setColumnStretch(0, 0)
+ grid_lay1.setColumnStretch(1, 1)
self.layout.addLayout(grid_lay1)
+ # Objects to be mirrored
+ self.param_label = QtWidgets.QLabel("%s:" % _("Mirror Parameters"))
+ self.param_label.setToolTip('%s.' % _("Parameters for the mirror operation"))
+
+ grid_lay1.addWidget(self.param_label, 0, 0, 1, 3)
+
# ## Axis
+ self.mirax_label = QtWidgets.QLabel(_("Axis:"))
+ self.mirax_label.setToolTip(_("Mirror vertically (X) or horizontally (Y)."))
self.mirror_axis = RadioSet([{'label': 'X', 'value': 'X'},
{'label': 'Y', 'value': 'Y'}])
- self.mirax_label = QtWidgets.QLabel(_("Mirror Axis:"))
- self.mirax_label.setToolTip(_("Mirror vertically (X) or horizontally (Y)."))
- # grid_lay.addRow("Mirror Axis:", self.mirror_axis)
- self.empty_lb1 = QtWidgets.QLabel("")
- grid_lay1.addWidget(self.empty_lb1, 6, 0)
- grid_lay1.addWidget(self.mirax_label, 7, 0)
- grid_lay1.addWidget(self.mirror_axis, 7, 1)
+ grid_lay1.addWidget(self.mirax_label, 2, 0)
+ grid_lay1.addWidget(self.mirror_axis, 2, 1, 1, 2)
# ## Axis Location
+ self.axloc_label = QtWidgets.QLabel('%s:' % _("Reference"))
+ self.axloc_label.setToolTip(
+ _("The coordinates used as reference for the mirror operation.\n"
+ "Can be:\n"
+ "- Point -> a set of coordinates (x,y) around which the object is mirrored\n"
+ "- Box -> a set of coordinates (x, y) obtained from the center of the\n"
+ "bounding box of another object selected below")
+ )
self.axis_location = RadioSet([{'label': _('Point'), 'value': 'point'},
{'label': _('Box'), 'value': 'box'}])
- self.axloc_label = QtWidgets.QLabel('%s:' % _("Axis Ref"))
- self.axloc_label.setToolTip(
- _("The axis should pass through a point or cut\n "
- "a specified box (in a FlatCAM object) through \n"
- "the center.")
- )
- # grid_lay.addRow("Axis Location:", self.axis_location)
- grid_lay1.addWidget(self.axloc_label, 8, 0)
- grid_lay1.addWidget(self.axis_location, 8, 1)
- self.empty_lb2 = QtWidgets.QLabel("")
- grid_lay1.addWidget(self.empty_lb2, 9, 0)
-
- # ## Grid Layout
- grid_lay2 = QtWidgets.QGridLayout()
- self.layout.addLayout(grid_lay2)
- grid_lay2.setColumnStretch(0, 1)
- grid_lay2.setColumnStretch(1, 0)
+ grid_lay1.addWidget(self.axloc_label, 4, 0)
+ grid_lay1.addWidget(self.axis_location, 4, 1, 1, 2)
# ## Point/Box
- self.point_box_container = QtWidgets.QVBoxLayout()
- self.pb_label = QtWidgets.QLabel("%s:" % _('Point/Box Reference'))
- self.pb_label.setToolTip(
- _("If 'Point' is selected above it store the coordinates (x, y) through which\n"
- "the mirroring axis passes.\n"
- "If 'Box' is selected above, select here a FlatCAM object (Gerber, Exc or Geo).\n"
- "Through the center of this object pass the mirroring axis selected above.")
- )
+ self.point_entry = EvalEntry()
+ # Add a reference
self.add_point_button = QtWidgets.QPushButton(_("Add"))
self.add_point_button.setToolTip(
_("Add the coordinates in format (x, y) through which the mirroring axis \n "
@@ -192,42 +194,75 @@ class DblSidedTool(FlatCAMTool):
"and left mouse button click on canvas or you can enter the coords manually.")
)
self.add_point_button.setStyleSheet("""
- QPushButton
- {
- font-weight: bold;
- }
- """)
+ QPushButton
+ {
+ font-weight: bold;
+ }
+ """)
self.add_point_button.setMinimumWidth(60)
- grid_lay2.addWidget(self.pb_label, 10, 0)
- grid_lay2.addLayout(self.point_box_container, 11, 0)
- grid_lay2.addWidget(self.add_point_button, 11, 1)
+ grid_lay1.addWidget(self.point_entry, 7, 0, 1, 2)
+ grid_lay1.addWidget(self.add_point_button, 7, 2)
- self.point_entry = EvalEntry()
- self.point_box_container.addWidget(self.point_entry)
+ # ## Grid Layout
+ grid_lay2 = QtWidgets.QGridLayout()
+ grid_lay2.setColumnStretch(0, 0)
+ grid_lay2.setColumnStretch(1, 1)
+ self.layout.addLayout(grid_lay2)
+ self.box_type_label = QtWidgets.QLabel('%s:' % _("Object Type"))
+ self.box_type_label.setToolTip(
+ _("It can be of type: Gerber or Excellon or Geometry.\n"
+ "The selection here decide the type of objects that will be\n"
+ "in the Object combobox.")
+ )
+
+ # Type of object used as BOX reference
+ self.box_type_radio = RadioSet([{'label': _('Gerber'), 'value': 'grb'},
+ {'label': _('Excellon'), 'value': 'exc'},
+ {'label': _('Geometry'), 'value': 'geo'}])
+
+ self.box_type_label.hide()
+ self.box_type_radio.hide()
+
+ grid_lay2.addWidget(self.box_type_label, 0, 0, 1, 2)
+ grid_lay2.addWidget(self.box_type_radio, 1, 0, 1, 2)
+
+ self.box_object_label = QtWidgets.QLabel('%s:' % _("Object"))
+ self.box_object_label.setToolTip(
+ _("Object to be used as mirror reference.")
+ )
+
+ # Object used as BOX reference
self.box_combo = QtWidgets.QComboBox()
self.box_combo.setModel(self.app.collection)
self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.box_combo.setCurrentIndex(1)
- self.box_combo_type = QtWidgets.QComboBox()
- self.box_combo_type.addItem(_("Reference Gerber"))
- self.box_combo_type.addItem(_("Reference Excellon"))
- self.box_combo_type.addItem(_("Reference Geometry"))
-
- self.point_box_container.addWidget(self.box_combo_type)
- self.point_box_container.addWidget(self.box_combo)
+ self.box_object_label.hide()
self.box_combo.hide()
- self.box_combo_type.hide()
+
+ grid_lay2.addWidget(self.box_object_label, 2, 0, 1, 2)
+ grid_lay2.addWidget(self.box_combo, 3, 0, 1, 2)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid_lay2.addWidget(separator_line, 12, 0, 1, 2)
+ self.layout.addWidget(separator_line)
+
+ self.layout.addWidget(QtWidgets.QLabel(""))
# ## Alignment holes
- self.ah_label = QtWidgets.QLabel("%s:" % _('Alignment Drill Coordinates'))
+ self.alignment_label = QtWidgets.QLabel("%s:" % _('Alignment Excellon object'))
+ self.alignment_label.setToolTip(
+ _("Creates an Excellon Object containing the\n"
+ "specified alignment holes and their mirror\n"
+ "images.")
+ )
+ self.layout.addWidget(self.alignment_label)
+
+ # ## Alignment holes
+ self.ah_label = QtWidgets.QLabel("%s:" % _('Alignment Drill Coordinates'))
self.ah_label.setToolTip(
_("Alignment holes (x1, y1), (x2, y2), ... "
"on one side of the mirror axis. For each set of (x, y) coordinates\n"
@@ -241,8 +276,9 @@ class DblSidedTool(FlatCAMTool):
self.layout.addLayout(grid_lay3)
self.alignment_holes = EvalEntry()
+ grid_lay3.addWidget(self.alignment_holes, 0, 0, 1, 2)
- self.add_drill_point_button = QtWidgets.QPushButton(_("Add"))
+ self.add_drill_point_button = FCButton(_("Add"))
self.add_drill_point_button.setToolTip(
_("Add alignment drill holes coords in the format: (x1, y1), (x2, y2), ... \n"
"on one side of the mirror axis.\n\n"
@@ -258,10 +294,17 @@ class DblSidedTool(FlatCAMTool):
font-weight: bold;
}
""")
- self.add_drill_point_button.setMinimumWidth(60)
- grid_lay3.addWidget(self.alignment_holes, 0, 0)
- grid_lay3.addWidget(self.add_drill_point_button, 0, 1)
+ self.delete_drill_point_button = FCButton(_("Delete Last"))
+ self.delete_drill_point_button.setToolTip(
+ _("Delete the last coordinates tupple in the list.")
+ )
+ drill_hlay = QtWidgets.QHBoxLayout()
+
+ drill_hlay.addWidget(self.add_drill_point_button)
+ drill_hlay.addWidget(self.delete_drill_point_button)
+
+ grid_lay3.addLayout(drill_hlay, 1, 0, 1, 2)
grid0 = QtWidgets.QGridLayout()
self.layout.addLayout(grid0)
@@ -269,7 +312,7 @@ class DblSidedTool(FlatCAMTool):
grid0.setColumnStretch(1, 1)
# ## Drill diameter for alignment holes
- self.dt_label = QtWidgets.QLabel("%s:" % _('Alignment Drill Diameter'))
+ self.dt_label = QtWidgets.QLabel("%s:" % _('Alignment Drill Diameter'))
self.dt_label.setToolTip(
_("Diameter of the drill for the "
"alignment holes.")
@@ -315,6 +358,14 @@ class DblSidedTool(FlatCAMTool):
grid1.setColumnStretch(0, 0)
grid1.setColumnStretch(1, 1)
+ # ## Title Bounds Values
+ self.bv_label = QtWidgets.QLabel("%s:" % _('Bounds Values'))
+ self.bv_label.setToolTip(
+ _("Select on canvas the object(s)\n"
+ "for which to calculate bounds values.")
+ )
+ grid1.addWidget(self.bv_label, 0, 0, 1, 2)
+
# Xmin value
self.xmin_entry = FCDoubleSpinner()
self.xmin_entry.set_precision(self.decimals)
@@ -420,7 +471,8 @@ class DblSidedTool(FlatCAMTool):
self.mirror_geo_button.clicked.connect(self.on_mirror_geo)
self.add_point_button.clicked.connect(self.on_point_add)
self.add_drill_point_button.clicked.connect(self.on_drill_add)
- self.box_combo_type.currentIndexChanged.connect(self.on_combo_box_type)
+ self.delete_drill_point_button.clicked.connect(self.on_drill_delete_last)
+ self.box_type_radio.activated_custom.connect(self.on_combo_box_type)
self.axis_location.group_toggle_fn = self.on_toggle_pointbox
@@ -477,8 +529,12 @@ class DblSidedTool(FlatCAMTool):
self.ymax_entry.set_value(0.0)
self.center_entry.set_value('')
- def on_combo_box_type(self):
- obj_type = self.box_combo_type.currentIndex()
+ def on_combo_box_type(self, val):
+ obj_type = {
+ 'grb': 0,
+ 'exc': 1,
+ 'geo': 2
+ }[val]
self.box_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.box_combo.setCurrentIndex(0)
@@ -524,7 +580,10 @@ class DblSidedTool(FlatCAMTool):
_("No value or wrong format in Drill Dia entry. Add it and retry."))
return
- tools = {"1": {"C": dia}}
+ tools = dict()
+ tools["1"] = dict()
+ tools["1"]["C"] = dia
+ tools["1"]['solid_geometry'] = list()
# holes = self.alignment_holes.get_value()
holes = eval('[{}]'.format(self.alignment_holes.text()))
@@ -538,18 +597,19 @@ class DblSidedTool(FlatCAMTool):
for hole in holes:
point = Point(hole)
point_mirror = affinity.scale(point, xscale, yscale, origin=(px, py))
+
drills.append({"point": point, "tool": "1"})
drills.append({"point": point_mirror, "tool": "1"})
- if 'solid_geometry' not in tools["1"]:
- tools["1"]['solid_geometry'] = list()
- else:
- tools["1"]['solid_geometry'].append(point)
- tools["1"]['solid_geometry'].append(point_mirror)
+
+ tools["1"]['solid_geometry'].append(point)
+ tools["1"]['solid_geometry'].append(point_mirror)
def obj_init(obj_inst, app_inst):
obj_inst.tools = tools
obj_inst.drills = drills
obj_inst.create_geometry()
+ obj_inst.source_file = self.app.export_excellon(obj_name=obj_inst.options['name'], local_use=obj_inst,
+ filename=None, use_thread=False)
self.app.new_object("excellon", "Alignment Drills", obj_init)
self.drill_values = ''
@@ -561,7 +621,7 @@ class DblSidedTool(FlatCAMTool):
model_index = self.app.collection.index(selection_index, 0, self.gerber_object_combo.rootModelIndex())
try:
fcobj = model_index.internalPointer().obj
- except Exception as e:
+ except Exception:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
return
@@ -585,7 +645,7 @@ class DblSidedTool(FlatCAMTool):
model_index_box = self.app.collection.index(selection_index_box, 0, self.box_combo.rootModelIndex())
try:
bb_obj = model_index_box.internalPointer().obj
- except Exception as e:
+ except Exception:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Box object loaded ..."))
return
@@ -604,7 +664,7 @@ class DblSidedTool(FlatCAMTool):
model_index = self.app.collection.index(selection_index, 0, self.exc_object_combo.rootModelIndex())
try:
fcobj = model_index.internalPointer().obj
- except Exception as e:
+ except Exception:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Excellon object loaded ..."))
return
@@ -648,7 +708,7 @@ class DblSidedTool(FlatCAMTool):
model_index = self.app.collection.index(selection_index, 0, self.geo_object_combo.rootModelIndex())
try:
fcobj = model_index.internalPointer().obj
- except Exception as e:
+ except Exception:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Geometry object loaded ..."))
return
@@ -666,7 +726,7 @@ class DblSidedTool(FlatCAMTool):
model_index_box = self.app.collection.index(selection_index_box, 0, self.box_combo.rootModelIndex())
try:
bb_obj = model_index_box.internalPointer().obj
- except Exception as e:
+ except Exception:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Box object loaded ..."))
return
@@ -679,7 +739,6 @@ class DblSidedTool(FlatCAMTool):
fcobj.plot()
self.app.inform.emit('[success] Geometry %s %s...' % (str(fcobj.options['name']), _("was mirrored")))
-
def on_point_add(self):
val = self.app.defaults["global_point_clipboard_format"] % (self.app.pos[0], self.app.pos[1])
self.point_entry.set_value(val)
@@ -689,17 +748,27 @@ class DblSidedTool(FlatCAMTool):
(self.app.pos[0], self.app.pos[1])) + ','
self.alignment_holes.set_value(self.drill_values)
+ def on_drill_delete_last(self):
+ drill_values_without_last_tupple = self.drill_values.rpartition('(')[0]
+ self.drill_values = drill_values_without_last_tupple
+ self.alignment_holes.set_value(self.drill_values)
+
def on_toggle_pointbox(self):
if self.axis_location.get_value() == "point":
self.point_entry.show()
+ self.add_point_button.show()
+ self.box_type_label.hide()
+ self.box_type_radio.hide()
+ self.box_object_label.hide()
self.box_combo.hide()
- self.box_combo_type.hide()
- self.add_point_button.setDisabled(False)
else:
self.point_entry.hide()
+ self.add_point_button.hide()
+
+ self.box_type_label.show()
+ self.box_type_radio.show()
+ self.box_object_label.show()
self.box_combo.show()
- self.box_combo_type.show()
- self.add_point_button.setDisabled(True)
def on_bbox_coordinates(self):
@@ -735,6 +804,7 @@ class DblSidedTool(FlatCAMTool):
self.center_entry.set_value(val_txt)
self.axis_location.set_value('point')
self.point_entry.set_value(val_txt)
+ self.app.delete_selection_shape()
def reset_fields(self):
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
@@ -746,6 +816,6 @@ class DblSidedTool(FlatCAMTool):
self.exc_object_combo.setCurrentIndex(0)
self.geo_object_combo.setCurrentIndex(0)
self.box_combo.setCurrentIndex(0)
- self.box_combo_type.setCurrentIndex(0)
+ self.box_type_radio.set_value('grb')
self.drill_values = ""
From cd45276819488f651b17c782fed422ea875e72ad Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 29 Jan 2020 21:49:22 +0200
Subject: [PATCH 057/209] - updated 2Sided Tool
---
FlatCAMApp.py | 9 +-
README.md | 1 +
flatcamEditors/FlatCAMGeoEditor.py | 4 +-
flatcamEditors/FlatCAMGrbEditor.py | 3 +-
flatcamGUI/PreferencesUI.py | 25 +-
flatcamTools/ToolDblSided.py | 406 +++++++++++++++++------------
6 files changed, 270 insertions(+), 178 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index fcd66c45..697978a7 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -516,7 +516,7 @@ class App(QtCore.QObject):
"zoom_in_key": '=',
"grid_toggle_key": 'G',
"global_zoom_ratio": 1.5,
- "global_point_clipboard_format": "(%.4f, %.4f)",
+ "global_point_clipboard_format": "(%.*f, %.*f)",
"global_zdownrate": None,
# General GUI Settings
@@ -814,6 +814,7 @@ class App(QtCore.QObject):
"tools_2sided_mirror_axis": "X",
"tools_2sided_axis_loc": "point",
"tools_2sided_drilldia": 3.125,
+ "tools_2sided_allign_axis": "X",
# Film Tool
"tools_film_type": 'neg',
@@ -1464,6 +1465,7 @@ class App(QtCore.QObject):
"tools_2sided_mirror_axis": self.ui.tools_defaults_form.tools_2sided_group.mirror_axis_radio,
"tools_2sided_axis_loc": self.ui.tools_defaults_form.tools_2sided_group.axis_location_radio,
"tools_2sided_drilldia": self.ui.tools_defaults_form.tools_2sided_group.drill_dia_entry,
+ "tools_2sided_allign_axis": self.ui.tools_defaults_form.tools_2sided_group.align_axis_radio,
# Film Tool
"tools_film_type": self.ui.tools_defaults_form.tools_film_group.film_type_radio,
@@ -8799,7 +8801,10 @@ class App(QtCore.QObject):
# do not auto open the Project Tab
self.click_noproject = True
- self.clipboard.setText(self.defaults["global_point_clipboard_format"] % (self.pos[0], self.pos[1]))
+ self.clipboard.setText(
+ self.defaults["global_point_clipboard_format"] %
+ (self.decimals, self.pos[0], self.decimals, self.pos[1])
+ )
self.inform.emit('[success] %s' % _("Coordinates copied to clipboard."))
return
diff --git a/README.md b/README.md
index 5510fb44..9e86ffa6 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ CAD program, and create G-Code for Isolation routing.
- changes in how the Editor exit is handled
- small fix in some pywin32 imports
- remade the GUI + small fixes in 2Sided Tool
+- updated 2Sided Tool
28.01.2020
diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py
index 7a5a63c6..0bd67d36 100644
--- a/flatcamEditors/FlatCAMGeoEditor.py
+++ b/flatcamEditors/FlatCAMGeoEditor.py
@@ -4008,7 +4008,9 @@ class FlatCAMGeoEditor(QtCore.QObject):
# If the SHIFT key is pressed when LMB is clicked then the coordinates are copied to clipboard
if modifiers == QtCore.Qt.ShiftModifier:
self.app.clipboard.setText(
- self.app.defaults["global_point_clipboard_format"] % (self.pos[0], self.pos[1]))
+ self.app.defaults["global_point_clipboard_format"] %
+ (self.decimals, self.pos[0], self.decimals, self.pos[1])
+ )
return
# Selection with left mouse button
diff --git a/flatcamEditors/FlatCAMGrbEditor.py b/flatcamEditors/FlatCAMGrbEditor.py
index 0aba714b..2bd6a8bb 100644
--- a/flatcamEditors/FlatCAMGrbEditor.py
+++ b/flatcamEditors/FlatCAMGrbEditor.py
@@ -4371,7 +4371,8 @@ class FlatCAMGrbEditor(QtCore.QObject):
# If the SHIFT key is pressed when LMB is clicked then the coordinates are copied to clipboard
if modifiers == QtCore.Qt.ShiftModifier:
self.app.clipboard.setText(
- self.app.defaults["global_point_clipboard_format"] % (self.pos[0], self.pos[1])
+ self.app.defaults["global_point_clipboard_format"] %
+ (self.decimals, self.pos[0], self.decimals, self.pos[1])
)
self.app.inform.emit('[success] %s' %
_("Coordinates copied to clipboard."))
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index 728f86f6..57b6b68d 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -5500,6 +5500,17 @@ class Tools2sidedPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.dd_label, 0, 0)
grid0.addWidget(self.drill_dia_entry, 0, 1)
+ # ## Alignment Axis
+ self.align_ax_label = QtWidgets.QLabel('%s:' % _("Align Axis"))
+ self.align_ax_label.setToolTip(
+ _("Mirror vertically (X) or horizontally (Y).")
+ )
+ self.align_axis_radio = RadioSet([{'label': 'X', 'value': 'X'},
+ {'label': 'Y', 'value': 'Y'}])
+
+ grid0.addWidget(self.align_ax_label, 1, 0)
+ grid0.addWidget(self.align_axis_radio, 1, 1)
+
# ## Axis
self.mirror_axis_radio = RadioSet([{'label': 'X', 'value': 'X'},
{'label': 'Y', 'value': 'Y'}])
@@ -5507,11 +5518,11 @@ class Tools2sidedPrefGroupUI(OptionsGroupUI):
self.mirax_label.setToolTip(
_("Mirror vertically (X) or horizontally (Y).")
)
- # grid_lay.addRow("Mirror Axis:", self.mirror_axis)
+
self.empty_lb1 = QtWidgets.QLabel("")
- grid0.addWidget(self.empty_lb1, 1, 0)
- grid0.addWidget(self.mirax_label, 2, 0)
- grid0.addWidget(self.mirror_axis_radio, 2, 1)
+ grid0.addWidget(self.empty_lb1, 2, 0)
+ grid0.addWidget(self.mirax_label, 3, 0)
+ grid0.addWidget(self.mirror_axis_radio, 3, 1)
# ## Axis Location
self.axis_location_radio = RadioSet([{'label': _('Point'), 'value': 'point'},
@@ -5522,9 +5533,9 @@ class Tools2sidedPrefGroupUI(OptionsGroupUI):
"a specified box (in a FlatCAM object) through \n"
"the center.")
)
- # grid_lay.addRow("Axis Location:", self.axis_location)
- grid0.addWidget(self.axloc_label, 3, 0)
- grid0.addWidget(self.axis_location_radio, 3, 1)
+
+ grid0.addWidget(self.axloc_label, 4, 0)
+ grid0.addWidget(self.axis_location_radio, 4, 1)
self.layout.addStretch()
diff --git a/flatcamTools/ToolDblSided.py b/flatcamTools/ToolDblSided.py
index bbc6c266..11888004 100644
--- a/flatcamTools/ToolDblSided.py
+++ b/flatcamTools/ToolDblSided.py
@@ -159,7 +159,7 @@ class DblSidedTool(FlatCAMTool):
grid_lay1.addWidget(self.param_label, 0, 0, 1, 3)
# ## Axis
- self.mirax_label = QtWidgets.QLabel(_("Axis:"))
+ self.mirax_label = QtWidgets.QLabel('%s:' % _("Axis"))
self.mirax_label.setToolTip(_("Mirror vertically (X) or horizontally (Y)."))
self.mirror_axis = RadioSet([{'label': 'X', 'value': 'X'},
{'label': 'Y', 'value': 'Y'}])
@@ -191,7 +191,7 @@ class DblSidedTool(FlatCAMTool):
_("Add the coordinates in format (x, y) through which the mirroring axis \n "
"selected in 'MIRROR AXIS' pass.\n"
"The (x, y) coordinates are captured by pressing SHIFT key\n"
- "and left mouse button click on canvas or you can enter the coords manually.")
+ "and left mouse button click on canvas or you can enter the coordinates manually.")
)
self.add_point_button.setStyleSheet("""
QPushButton
@@ -210,11 +210,11 @@ class DblSidedTool(FlatCAMTool):
grid_lay2.setColumnStretch(1, 1)
self.layout.addLayout(grid_lay2)
- self.box_type_label = QtWidgets.QLabel('%s:' % _("Object Type"))
+ self.box_type_label = QtWidgets.QLabel('%s:' % _("Reference Object"))
self.box_type_label.setToolTip(
_("It can be of type: Gerber or Excellon or Geometry.\n"
- "The selection here decide the type of objects that will be\n"
- "in the Object combobox.")
+ "The coordinates of the center of the bounding box are used\n"
+ "as reference for mirror operation.")
)
# Type of object used as BOX reference
@@ -228,38 +228,179 @@ class DblSidedTool(FlatCAMTool):
grid_lay2.addWidget(self.box_type_label, 0, 0, 1, 2)
grid_lay2.addWidget(self.box_type_radio, 1, 0, 1, 2)
- self.box_object_label = QtWidgets.QLabel('%s:' % _("Object"))
- self.box_object_label.setToolTip(
- _("Object to be used as mirror reference.")
- )
-
# Object used as BOX reference
self.box_combo = QtWidgets.QComboBox()
self.box_combo.setModel(self.app.collection)
self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.box_combo.setCurrentIndex(1)
- self.box_object_label.hide()
self.box_combo.hide()
- grid_lay2.addWidget(self.box_object_label, 2, 0, 1, 2)
grid_lay2.addWidget(self.box_combo, 3, 0, 1, 2)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.layout.addWidget(separator_line)
+ grid_lay2.addWidget(separator_line, 4, 0, 1, 2)
- self.layout.addWidget(QtWidgets.QLabel(""))
+ grid_lay2.addWidget(QtWidgets.QLabel(""), 5, 0, 1, 2)
+
+ # ## Title Bounds Values
+ self.bv_label = QtWidgets.QLabel("%s:" % _('Bounds Values'))
+ self.bv_label.setToolTip(
+ _("Select on canvas the object(s)\n"
+ "for which to calculate bounds values.")
+ )
+ grid_lay2.addWidget(self.bv_label, 6, 0, 1, 2)
+
+ # Xmin value
+ self.xmin_entry = FCDoubleSpinner()
+ self.xmin_entry.set_precision(self.decimals)
+ self.xmin_entry.set_range(-9999.9999, 9999.9999)
+
+ self.xmin_btn = FCButton('%s:' % _("X min"))
+ self.xmin_btn.setToolTip(
+ _("Minimum location.")
+ )
+ self.xmin_entry.setReadOnly(True)
+
+ grid_lay2.addWidget(self.xmin_btn, 7, 0)
+ grid_lay2.addWidget(self.xmin_entry, 7, 1)
+
+ # Ymin value
+ self.ymin_entry = FCDoubleSpinner()
+ self.ymin_entry.set_precision(self.decimals)
+ self.ymin_entry.set_range(-9999.9999, 9999.9999)
+
+ self.ymin_btn = FCButton('%s:' % _("Y min"))
+ self.ymin_btn.setToolTip(
+ _("Minimum location.")
+ )
+ self.ymin_entry.setReadOnly(True)
+
+ grid_lay2.addWidget(self.ymin_btn, 8, 0)
+ grid_lay2.addWidget(self.ymin_entry, 8, 1)
+
+ # Xmax value
+ self.xmax_entry = FCDoubleSpinner()
+ self.xmax_entry.set_precision(self.decimals)
+ self.xmax_entry.set_range(-9999.9999, 9999.9999)
+
+ self.xmax_btn = FCButton('%s:' % _("X max"))
+ self.xmax_btn.setToolTip(
+ _("Maximum location.")
+ )
+ self.xmax_entry.setReadOnly(True)
+
+ grid_lay2.addWidget(self.xmax_btn, 9, 0)
+ grid_lay2.addWidget(self.xmax_entry, 9, 1)
+
+ # Ymax value
+ self.ymax_entry = FCDoubleSpinner()
+ self.ymax_entry.set_precision(self.decimals)
+ self.ymax_entry.set_range(-9999.9999, 9999.9999)
+
+ self.ymax_btn = FCButton('%s:' % _("Y max"))
+ self.ymax_btn.setToolTip(
+ _("Maximum location.")
+ )
+ self.ymax_entry.setReadOnly(True)
+
+ grid_lay2.addWidget(self.ymax_btn, 10, 0)
+ grid_lay2.addWidget(self.ymax_entry, 10, 1)
+
+ # Center point value
+ self.center_entry = FCEntry()
+
+ self.center_btn = FCButton('%s:' % _("Centroid"))
+ self.center_btn.setToolTip(
+ _("The center point location for the rectangular\n"
+ "bounding shape. Centroid. Format is (x, y).")
+ )
+ self.center_entry.setReadOnly(True)
+
+ grid_lay2.addWidget(self.center_btn, 12, 0)
+ grid_lay2.addWidget(self.center_entry, 12, 1)
+
+ # Calculate Bounding box
+ self.calculate_bb_button = QtWidgets.QPushButton(_("Calculate Bounds Values"))
+ self.calculate_bb_button.setToolTip(
+ _("Calculate the enveloping rectangular shape coordinates,\n"
+ "for the selection of objects.\n"
+ "The envelope shape is parallel with the X, Y axis.")
+ )
+ self.calculate_bb_button.setStyleSheet("""
+ QPushButton
+ {
+ font-weight: bold;
+ }
+ """)
+ grid_lay2.addWidget(self.calculate_bb_button, 13, 0, 1, 2)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid_lay2.addWidget(separator_line, 14, 0, 1, 2)
+
+ grid_lay2.addWidget(QtWidgets.QLabel(""), 15, 0, 1, 2)
# ## Alignment holes
- self.alignment_label = QtWidgets.QLabel("%s:" % _('Alignment Excellon object'))
+ self.alignment_label = QtWidgets.QLabel("%s:" % _('PCB Alignment'))
self.alignment_label.setToolTip(
_("Creates an Excellon Object containing the\n"
"specified alignment holes and their mirror\n"
"images.")
)
- self.layout.addWidget(self.alignment_label)
+ grid_lay2.addWidget(self.alignment_label, 25, 0, 1, 2)
+
+ # ## Drill diameter for alignment holes
+ self.dt_label = QtWidgets.QLabel("%s:" % _('Drill Diameter'))
+ self.dt_label.setToolTip(
+ _("Diameter of the drill for the alignment holes.")
+ )
+
+ self.drill_dia = FCDoubleSpinner()
+ self.drill_dia.setToolTip(
+ _("Diameter of the drill for the alignment holes.")
+ )
+ self.drill_dia.set_precision(self.decimals)
+ self.drill_dia.set_range(0.0000, 9999.9999)
+
+ grid_lay2.addWidget(self.dt_label, 26, 0)
+ grid_lay2.addWidget(self.drill_dia, 26, 1)
+
+ # ## Alignment Axis
+ self.align_ax_label = QtWidgets.QLabel('%s:' % _("Align Axis"))
+ self.align_ax_label.setToolTip(
+ _("Mirror vertically (X) or horizontally (Y).")
+ )
+ self.align_axis_radio = RadioSet([{'label': 'X', 'value': 'X'},
+ {'label': 'Y', 'value': 'Y'}])
+
+ grid_lay2.addWidget(self.align_ax_label, 27, 0)
+ grid_lay2.addWidget(self.align_axis_radio, 27, 1)
+
+ # ## Alignment Reference Point
+ self.align_ref_label = QtWidgets.QLabel('%s:' % _("Reference"))
+ self.align_ref_label.setToolTip(
+ _("The reference point used to create the second alignment drill\n"
+ "from the first alignment drill, by doing mirror.\n"
+ "It can be modified in the Mirror Parameters -> Reference section")
+ )
+
+ self.align_ref_label_val = EvalEntry()
+ self.align_ref_label_val.setToolTip(
+ _("The reference point used to create the second alignment drill\n"
+ "from the first alignment drill, by doing mirror.\n"
+ "It can be modified in the Mirror Parameters -> Reference section")
+ )
+ self.align_ref_label_val.setDisabled(True)
+
+ grid_lay2.addWidget(self.align_ref_label, 28, 0)
+ grid_lay2.addWidget(self.align_ref_label_val, 28, 1)
+
+ grid_lay4 = QtWidgets.QGridLayout()
+ self.layout.addLayout(grid_lay4)
# ## Alignment holes
self.ah_label = QtWidgets.QLabel("%s:" % _('Alignment Drill Coordinates'))
@@ -268,68 +409,41 @@ class DblSidedTool(FlatCAMTool):
"on one side of the mirror axis. For each set of (x, y) coordinates\n"
"entered here, a pair of drills will be created:\n\n"
"- one drill at the coordinates from the field\n"
- "- one drill in mirror position over the axis selected above in the 'Mirror Axis'.")
+ "- one drill in mirror position over the axis selected above in the 'Align Axis'.")
)
- self.layout.addWidget(self.ah_label)
-
- grid_lay3 = QtWidgets.QGridLayout()
- self.layout.addLayout(grid_lay3)
self.alignment_holes = EvalEntry()
- grid_lay3.addWidget(self.alignment_holes, 0, 0, 1, 2)
+
+ grid_lay4.addWidget(self.ah_label, 0, 0, 1, 2)
+ grid_lay4.addWidget(self.alignment_holes, 1, 0, 1, 2)
self.add_drill_point_button = FCButton(_("Add"))
self.add_drill_point_button.setToolTip(
- _("Add alignment drill holes coords in the format: (x1, y1), (x2, y2), ... \n"
- "on one side of the mirror axis.\n\n"
+ _("Add alignment drill holes coordinates in the format: (x1, y1), (x2, y2), ... \n"
+ "on one side of the alignment axis.\n\n"
"The coordinates set can be obtained:\n"
"- press SHIFT key and left mouse clicking on canvas. Then click Add.\n"
"- press SHIFT key and left mouse clicking on canvas. Then CTRL+V in the field.\n"
"- press SHIFT key and left mouse clicking on canvas. Then RMB click in the field and click Paste.\n"
"- by entering the coords manually in the format: (x1, y1), (x2, y2), ...")
)
- self.add_drill_point_button.setStyleSheet("""
- QPushButton
- {
- font-weight: bold;
- }
- """)
+ # self.add_drill_point_button.setStyleSheet("""
+ # QPushButton
+ # {
+ # font-weight: bold;
+ # }
+ # """)
self.delete_drill_point_button = FCButton(_("Delete Last"))
self.delete_drill_point_button.setToolTip(
- _("Delete the last coordinates tupple in the list.")
+ _("Delete the last coordinates tuple in the list.")
)
drill_hlay = QtWidgets.QHBoxLayout()
drill_hlay.addWidget(self.add_drill_point_button)
drill_hlay.addWidget(self.delete_drill_point_button)
- grid_lay3.addLayout(drill_hlay, 1, 0, 1, 2)
-
- grid0 = QtWidgets.QGridLayout()
- self.layout.addLayout(grid0)
- grid0.setColumnStretch(0, 0)
- grid0.setColumnStretch(1, 1)
-
- # ## Drill diameter for alignment holes
- self.dt_label = QtWidgets.QLabel("%s:" % _('Alignment Drill Diameter'))
- self.dt_label.setToolTip(
- _("Diameter of the drill for the "
- "alignment holes.")
- )
- grid0.addWidget(self.dt_label, 0, 0, 1, 2)
-
- # Drill diameter value
- self.drill_dia = FCDoubleSpinner()
- self.drill_dia.set_precision(self.decimals)
- self.drill_dia.set_range(0.0000, 9999.9999)
-
- self.drill_dia.setToolTip(
- _("Diameter of the drill for the "
- "alignment holes.")
- )
-
- grid0.addWidget(self.drill_dia, 1, 0, 1, 2)
+ grid_lay4.addLayout(drill_hlay, 2, 0, 1, 2)
# ## Buttons
self.create_alignment_hole_button = QtWidgets.QPushButton(_("Create Excellon Object"))
@@ -346,110 +460,6 @@ class DblSidedTool(FlatCAMTool):
""")
self.layout.addWidget(self.create_alignment_hole_button)
- separator_line = QtWidgets.QFrame()
- separator_line.setFrameShape(QtWidgets.QFrame.HLine)
- separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.layout.addWidget(separator_line)
-
- self.layout.addWidget(QtWidgets.QLabel(''))
-
- grid1 = QtWidgets.QGridLayout()
- self.layout.addLayout(grid1)
- grid1.setColumnStretch(0, 0)
- grid1.setColumnStretch(1, 1)
-
- # ## Title Bounds Values
- self.bv_label = QtWidgets.QLabel("%s:" % _('Bounds Values'))
- self.bv_label.setToolTip(
- _("Select on canvas the object(s)\n"
- "for which to calculate bounds values.")
- )
- grid1.addWidget(self.bv_label, 0, 0, 1, 2)
-
- # Xmin value
- self.xmin_entry = FCDoubleSpinner()
- self.xmin_entry.set_precision(self.decimals)
- self.xmin_entry.set_range(-9999.9999, 9999.9999)
-
- self.xmin_label = QtWidgets.QLabel('%s:' % _("X min"))
- self.xmin_label.setToolTip(
- _("Minimum location.")
- )
- self.xmin_entry.setReadOnly(True)
-
- grid1.addWidget(self.xmin_label, 1, 0)
- grid1.addWidget(self.xmin_entry, 1, 1)
-
- # Ymin value
- self.ymin_entry = FCDoubleSpinner()
- self.ymin_entry.set_precision(self.decimals)
- self.ymin_entry.set_range(-9999.9999, 9999.9999)
-
- self.ymin_label = QtWidgets.QLabel('%s:' % _("Y min"))
- self.ymin_label.setToolTip(
- _("Minimum location.")
- )
- self.ymin_entry.setReadOnly(True)
-
- grid1.addWidget(self.ymin_label, 2, 0)
- grid1.addWidget(self.ymin_entry, 2, 1)
-
- # Xmax value
- self.xmax_entry = FCDoubleSpinner()
- self.xmax_entry.set_precision(self.decimals)
- self.xmax_entry.set_range(-9999.9999, 9999.9999)
-
- self.xmax_label = QtWidgets.QLabel('%s:' % _("X max"))
- self.xmax_label.setToolTip(
- _("Maximum location.")
- )
- self.xmax_entry.setReadOnly(True)
-
- grid1.addWidget(self.xmax_label, 3, 0)
- grid1.addWidget(self.xmax_entry, 3, 1)
-
- # Ymax value
- self.ymax_entry = FCDoubleSpinner()
- self.ymax_entry.set_precision(self.decimals)
- self.ymax_entry.set_range(-9999.9999, 9999.9999)
-
- self.ymax_label = QtWidgets.QLabel('%s:' % _("Y max"))
- self.ymax_label.setToolTip(
- _("Maximum location.")
- )
- self.ymax_entry.setReadOnly(True)
-
- grid1.addWidget(self.ymax_label, 4, 0)
- grid1.addWidget(self.ymax_entry, 4, 1)
-
- # Center point value
- self.center_entry = FCEntry()
-
- self.center_label = QtWidgets.QLabel('%s:' % _("Centroid"))
- self.center_label.setToolTip(
- _("The center point location for the rectangular\n"
- "bounding shape. Centroid. Format is (x, y).")
- )
- self.center_entry.setReadOnly(True)
-
- grid1.addWidget(self.center_label, 5, 0)
- grid1.addWidget(self.center_entry, 5, 1)
-
- # Calculate Bounding box
- self.calculate_bb_button = QtWidgets.QPushButton(_("Calculate Bounds Values"))
- self.calculate_bb_button.setToolTip(
- _("Calculate the enveloping rectangular shape coordinates,\n"
- "for the selection of objects.\n"
- "The envelope shape is parallel with the X, Y axis.")
- )
- self.calculate_bb_button.setStyleSheet("""
- QPushButton
- {
- font-weight: bold;
- }
- """)
- self.layout.addWidget(self.calculate_bb_button)
-
self.layout.addStretch()
# ## Reset Tool
@@ -469,6 +479,7 @@ class DblSidedTool(FlatCAMTool):
self.mirror_gerber_button.clicked.connect(self.on_mirror_gerber)
self.mirror_exc_button.clicked.connect(self.on_mirror_exc)
self.mirror_geo_button.clicked.connect(self.on_mirror_geo)
+
self.add_point_button.clicked.connect(self.on_point_add)
self.add_drill_point_button.clicked.connect(self.on_drill_add)
self.delete_drill_point_button.clicked.connect(self.on_drill_delete_last)
@@ -476,6 +487,18 @@ class DblSidedTool(FlatCAMTool):
self.axis_location.group_toggle_fn = self.on_toggle_pointbox
+ self.point_entry.textChanged.connect(lambda val: self.align_ref_label_val.set_value(val))
+
+ self.xmin_btn.clicked.connect(self.on_xmin_clicked)
+ self.ymin_btn.clicked.connect(self.on_ymin_clicked)
+ self.xmax_btn.clicked.connect(self.on_xmax_clicked)
+ self.ymax_btn.clicked.connect(self.on_ymax_clicked)
+
+ self.center_btn.clicked.connect(
+ lambda: self.point_entry.set_value(self.center_entry.get_value())
+ )
+
+
self.create_alignment_hole_button.clicked.connect(self.on_create_alignment_holes)
self.calculate_bb_button.clicked.connect(self.on_bbox_coordinates)
@@ -522,6 +545,7 @@ class DblSidedTool(FlatCAMTool):
self.mirror_axis.set_value(self.app.defaults["tools_2sided_mirror_axis"])
self.axis_location.set_value(self.app.defaults["tools_2sided_axis_loc"])
self.drill_dia.set_value(self.app.defaults["tools_2sided_drilldia"])
+ self.align_axis_radio.set_value(self.app.defaults["tools_2sided_allign_axis"])
self.xmin_entry.set_value(0.0)
self.ymin_entry.set_value(0.0)
@@ -529,6 +553,8 @@ class DblSidedTool(FlatCAMTool):
self.ymax_entry.set_value(0.0)
self.center_entry.set_value('')
+ self.align_ref_label_val.set_value('%.*f' % (self.decimals, 0.0))
+
def on_combo_box_type(self, val):
obj_type = {
'grb': 0,
@@ -539,7 +565,7 @@ class DblSidedTool(FlatCAMTool):
self.box_combo.setCurrentIndex(0)
def on_create_alignment_holes(self):
- axis = self.mirror_axis.get_value()
+ axis = self.align_axis_radio.get_value()
mode = self.axis_location.get_value()
if mode == "point":
@@ -608,7 +634,7 @@ class DblSidedTool(FlatCAMTool):
obj_inst.tools = tools
obj_inst.drills = drills
obj_inst.create_geometry()
- obj_inst.source_file = self.app.export_excellon(obj_name=obj_inst.options['name'], local_use=obj_inst,
+ obj_inst.source_file = app_inst.export_excellon(obj_name=obj_inst.options['name'], local_use=obj_inst,
filename=None, use_thread=False)
self.app.new_object("excellon", "Alignment Drills", obj_init)
@@ -740,12 +766,13 @@ class DblSidedTool(FlatCAMTool):
self.app.inform.emit('[success] Geometry %s %s...' % (str(fcobj.options['name']), _("was mirrored")))
def on_point_add(self):
- val = self.app.defaults["global_point_clipboard_format"] % (self.app.pos[0], self.app.pos[1])
+ val = self.app.defaults["global_point_clipboard_format"] % \
+ (self.decimals, self.app.pos[0], self.decimals, self.app.pos[1])
self.point_entry.set_value(val)
def on_drill_add(self):
self.drill_values += (self.app.defaults["global_point_clipboard_format"] %
- (self.app.pos[0], self.app.pos[1])) + ','
+ (self.decimals, self.app.pos[0], self.decimals, self.app.pos[1])) + ','
self.alignment_holes.set_value(self.drill_values)
def on_drill_delete_last(self):
@@ -759,7 +786,6 @@ class DblSidedTool(FlatCAMTool):
self.add_point_button.show()
self.box_type_label.hide()
self.box_type_radio.hide()
- self.box_object_label.hide()
self.box_combo.hide()
else:
self.point_entry.hide()
@@ -767,9 +793,10 @@ class DblSidedTool(FlatCAMTool):
self.box_type_label.show()
self.box_type_radio.show()
- self.box_object_label.show()
self.box_combo.show()
+ self.align_ref_label_val.set_value("Box centroid")
+
def on_bbox_coordinates(self):
xmin = Inf
@@ -806,6 +833,50 @@ class DblSidedTool(FlatCAMTool):
self.point_entry.set_value(val_txt)
self.app.delete_selection_shape()
+ def on_xmin_clicked(self):
+ xmin = self.xmin_entry.get_value()
+ self.axis_location.set_value('point')
+
+ try:
+ px, py = self.point_entry.get_value()
+ val = self.app.defaults["global_point_clipboard_format"] % (self.decimals, xmin, self.decimals, py)
+ except TypeError:
+ val = self.app.defaults["global_point_clipboard_format"] % (self.decimals, xmin, self.decimals, 0.0)
+ self.point_entry.set_value(val)
+
+ def on_ymin_clicked(self):
+ ymin = self.ymin_entry.get_value()
+ self.axis_location.set_value('point')
+
+ try:
+ px, py = self.point_entry.get_value()
+ val = self.app.defaults["global_point_clipboard_format"] % (self.decimals, px, self.decimals, ymin)
+ except TypeError:
+ val = self.app.defaults["global_point_clipboard_format"] % (self.decimals, 0.0, self.decimals, ymin)
+ self.point_entry.set_value(val)
+
+ def on_xmax_clicked(self):
+ xmax = self.xmax_entry.get_value()
+ self.axis_location.set_value('point')
+
+ try:
+ px, py = self.point_entry.get_value()
+ val = self.app.defaults["global_point_clipboard_format"] % (self.decimals, xmax, self.decimals, py)
+ except TypeError:
+ val = self.app.defaults["global_point_clipboard_format"] % (self.decimals, xmax, self.decimals, 0.0)
+ self.point_entry.set_value(val)
+
+ def on_ymax_clicked(self):
+ ymax = self.ymax_entry.get_value()
+ self.axis_location.set_value('point')
+
+ try:
+ px, py = self.point_entry.get_value()
+ val = self.app.defaults["global_point_clipboard_format"] % (self.decimals, px, self.decimals, ymax)
+ except TypeError:
+ val = self.app.defaults["global_point_clipboard_format"] % (self.decimals, 0.0, self.decimals, ymax)
+ self.point_entry.set_value(val)
+
def reset_fields(self):
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.exc_object_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
@@ -819,3 +890,4 @@ class DblSidedTool(FlatCAMTool):
self.box_type_radio.set_value('grb')
self.drill_values = ""
+ self.align_ref_label_val.set_value('')
From e7c25e9b8aabf562f161f19f0482ef00160ab60d Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 29 Jan 2020 22:04:23 +0200
Subject: [PATCH 058/209] - updated 2Sided Tool- wip
---
flatcamTools/ToolDblSided.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/flatcamTools/ToolDblSided.py b/flatcamTools/ToolDblSided.py
index 11888004..dc1bbd9f 100644
--- a/flatcamTools/ToolDblSided.py
+++ b/flatcamTools/ToolDblSided.py
@@ -159,7 +159,7 @@ class DblSidedTool(FlatCAMTool):
grid_lay1.addWidget(self.param_label, 0, 0, 1, 3)
# ## Axis
- self.mirax_label = QtWidgets.QLabel('%s:' % _("Axis"))
+ self.mirax_label = QtWidgets.QLabel('%s:' % _("Mirror Axis"))
self.mirax_label.setToolTip(_("Mirror vertically (X) or horizontally (Y)."))
self.mirror_axis = RadioSet([{'label': 'X', 'value': 'X'},
{'label': 'Y', 'value': 'Y'}])
@@ -787,6 +787,8 @@ class DblSidedTool(FlatCAMTool):
self.box_type_label.hide()
self.box_type_radio.hide()
self.box_combo.hide()
+
+ self.align_ref_label_val.set_value(self.point_entry.get_value())
else:
self.point_entry.hide()
self.add_point_button.hide()
From 123ae16b203ce66b176cbaa702238c5058c2c5ea Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 30 Jan 2020 05:14:05 +0200
Subject: [PATCH 059/209] - remade GUI in Tool Cutout, Tool Align Objects, Tool
Panelize
---
README.md | 4 ++
flatcamTools/ToolAlignObjects.py | 94 +++++++++++++-------------
flatcamTools/ToolCutOut.py | 110 +++++++++++++++++--------------
flatcamTools/ToolPanelize.py | 35 +++++-----
4 files changed, 127 insertions(+), 116 deletions(-)
diff --git a/README.md b/README.md
index 9e86ffa6..9a1c3463 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+30.01.2020
+
+- remade GUI in Tool Cutout, Tool Align Objects, Tool Panelize
+
29.01.2020
- changes in how the Editor exit is handled
diff --git a/flatcamTools/ToolAlignObjects.py b/flatcamTools/ToolAlignObjects.py
index d1e77442..9cc4c196 100644
--- a/flatcamTools/ToolAlignObjects.py
+++ b/flatcamTools/ToolAlignObjects.py
@@ -50,32 +50,31 @@ class AlignObjects(FlatCAMTool):
""")
self.layout.addWidget(title_label)
+ self.layout.addWidget(QtWidgets.QLabel(''))
+
# Form Layout
grid0 = QtWidgets.QGridLayout()
grid0.setColumnStretch(0, 0)
grid0.setColumnStretch(1, 1)
self.layout.addLayout(grid0)
- self.aligned_label = QtWidgets.QLabel('%s' % _("Selection of the WORKING object"))
+ self.aligned_label = QtWidgets.QLabel('%s:' % _("MOVING object"))
grid0.addWidget(self.aligned_label, 0, 0, 1, 2)
- # Type of object to be aligned
- self.type_obj_combo = FCComboBox()
- self.type_obj_combo.addItem("Gerber")
- self.type_obj_combo.addItem("Excellon")
-
- 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_label = QtWidgets.QLabel('%s:' % _("Object Type"))
- self.type_obj_combo_label.setToolTip(
+ self.aligned_label.setToolTip(
_("Specify the type of object to be aligned.\n"
"It can be of type: Gerber or Excellon.\n"
"The selection here decide the type of objects that will be\n"
"in the Object combobox.")
)
- grid0.addWidget(self.type_obj_combo_label, 2, 0)
- grid0.addWidget(self.type_obj_combo, 2, 1)
+
+ # Type of object to be aligned
+ self.type_obj_radio = RadioSet([
+ {"label": _("Gerber"), "value": "grb"},
+ {"label": _("Excellon"), "value": "exc"},
+ ], orientation='vertical', stretch=False)
+
+ grid0.addWidget(self.type_obj_radio, 3, 0, 1, 2)
# Object to be aligned
self.object_combo = FCComboBox()
@@ -83,42 +82,35 @@ class AlignObjects(FlatCAMTool):
self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.object_combo.setCurrentIndex(1)
- self.object_label = QtWidgets.QLabel('%s:' % _("Object"))
- self.object_label.setToolTip(
+ self.object_combo.setToolTip(
_("Object to be aligned.")
)
- grid0.addWidget(self.object_label, 3, 0)
- grid0.addWidget(self.object_combo, 3, 1)
+ grid0.addWidget(self.object_combo, 4, 0, 1, 2)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid0.addWidget(separator_line, 4, 0, 1, 2)
+ grid0.addWidget(separator_line, 5, 0, 1, 2)
- self.aligned_label = QtWidgets.QLabel('%s' % _("Selection of the TARGET object"))
+ grid0.addWidget(QtWidgets.QLabel(''), 6, 0, 1, 2)
+
+ self.aligned_label = QtWidgets.QLabel('%s:' % _("TARGET object"))
self.aligned_label.setToolTip(
- _("Object to which the other objects will be aligned to (moved to).")
- )
- grid0.addWidget(self.aligned_label, 6, 0, 1, 2)
-
- # Type of object to be aligned to = aligner
- self.type_aligner_obj_combo = FCComboBox()
- self.type_aligner_obj_combo.addItem("Gerber")
- self.type_aligner_obj_combo.addItem("Excellon")
-
- self.type_aligner_obj_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
- self.type_aligner_obj_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/drill16.png"))
-
- self.type_aligner_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
- self.type_aligner_obj_combo_label.setToolTip(
_("Specify the type of object to be aligned to.\n"
"It can be of type: Gerber or Excellon.\n"
"The selection here decide the type of objects that will be\n"
"in the Object combobox.")
)
- grid0.addWidget(self.type_aligner_obj_combo_label, 7, 0)
- grid0.addWidget(self.type_aligner_obj_combo, 7, 1)
+ grid0.addWidget(self.aligned_label, 7, 0, 1, 2)
+
+ # Type of object to be aligned to = aligner
+ self.type_aligner_obj_radio = RadioSet([
+ {"label": _("Gerber"), "value": "grb"},
+ {"label": _("Excellon"), "value": "exc"},
+ ], orientation='vertical', stretch=False)
+
+ grid0.addWidget(self.type_aligner_obj_radio, 8, 0, 1, 2)
# Object to be aligned to = aligner
self.aligner_object_combo = FCComboBox()
@@ -126,18 +118,18 @@ class AlignObjects(FlatCAMTool):
self.aligner_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.aligner_object_combo.setCurrentIndex(1)
- self.aligner_object_label = QtWidgets.QLabel('%s:' % _("Object"))
- self.aligner_object_label.setToolTip(
+ self.aligner_object_combo.setToolTip(
_("Object to be aligned to. Aligner.")
)
- grid0.addWidget(self.aligner_object_label, 8, 0)
- grid0.addWidget(self.aligner_object_combo, 8, 1)
+ grid0.addWidget(self.aligner_object_combo, 9, 0, 1, 2)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid0.addWidget(separator_line, 9, 0, 1, 2)
+ grid0.addWidget(separator_line, 10, 0, 1, 2)
+
+ grid0.addWidget(QtWidgets.QLabel(''), 11, 0, 1, 2)
# Alignment Type
self.a_type_lbl = QtWidgets.QLabel('%s:' % _("Alignment Type"))
@@ -151,17 +143,17 @@ class AlignObjects(FlatCAMTool):
{'label': _('Single Point'), 'value': 'sp'},
{'label': _('Dual Point'), 'value': 'dp'}
],
- orientation='horizontal',
+ orientation='vertical',
stretch=False
)
- grid0.addWidget(self.a_type_lbl, 10, 0, 1, 2)
- grid0.addWidget(self.a_type_radio, 11, 0, 1, 2)
+ grid0.addWidget(self.a_type_lbl, 12, 0, 1, 2)
+ grid0.addWidget(self.a_type_radio, 13, 0, 1, 2)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid0.addWidget(separator_line, 12, 0, 1, 2)
+ grid0.addWidget(separator_line, 14, 0, 1, 2)
# Buttons
self.align_object_button = QtWidgets.QPushButton(_("Align Object"))
@@ -195,8 +187,8 @@ class AlignObjects(FlatCAMTool):
# Signals
self.align_object_button.clicked.connect(self.on_align)
- self.type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
- self.type_aligner_obj_combo.currentIndexChanged.connect(self.on_type_aligner_index_changed)
+ self.type_obj_radio.activated_custom.connect(self.on_type_obj_changed)
+ self.type_aligner_obj_radio.activated_custom.connect(self.on_type_aligner_changed)
self.reset_button.clicked.connect(self.set_tool_ui)
self.mr = None
@@ -268,17 +260,19 @@ class AlignObjects(FlatCAMTool):
self.aligned_old_line_color = None
self.a_type_radio.set_value(self.app.defaults["tools_align_objects_align_type"])
+ self.type_obj_radio.set_value('grb')
+ self.type_aligner_obj_radio.set_value('grb')
if self.local_connected is True:
self.disconnect_cal_events()
- def on_type_obj_index_changed(self):
- obj_type = self.type_obj_combo.currentIndex()
+ def on_type_obj_changed(self, val):
+ obj_type = {'grb': 0, 'exc': 1}[val]
self.object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.object_combo.setCurrentIndex(0)
- def on_type_aligner_index_changed(self):
- obj_type = self.type_aligner_obj_combo.currentIndex()
+ def on_type_aligner_changed(self, val):
+ obj_type = {'grb': 0, 'exc': 1}[val]
self.aligner_object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.aligner_object_combo.setCurrentIndex(0)
diff --git a/flatcamTools/ToolCutOut.py b/flatcamTools/ToolCutOut.py
index 4209b70b..2e0d7924 100644
--- a/flatcamTools/ToolCutOut.py
+++ b/flatcamTools/ToolCutOut.py
@@ -7,7 +7,7 @@
from PyQt5 import QtWidgets, QtGui, QtCore
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, RadioSet, FCComboBox, OptionalInputSection
+from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, RadioSet, FCComboBox, OptionalInputSection, FCButton
from FlatCAMObj import FlatCAMGerber
from shapely.geometry import box, MultiPolygon, Polygon, LineString, LinearRing
@@ -59,46 +59,18 @@ class CutOut(FlatCAMTool):
""")
self.layout.addWidget(title_label)
+ self.layout.addWidget(QtWidgets.QLabel(''))
+
# Form Layout
grid0 = QtWidgets.QGridLayout()
grid0.setColumnStretch(0, 0)
grid0.setColumnStretch(1, 1)
self.layout.addLayout(grid0)
- # Type of object to be cutout
- self.type_obj_combo = QtWidgets.QComboBox()
- self.type_obj_combo.addItem("Gerber")
- self.type_obj_combo.addItem("Excellon")
- self.type_obj_combo.addItem("Geometry")
-
- # we get rid of item1 ("Excellon") as it is not suitable for creating film
- self.type_obj_combo.view().setRowHidden(1, True)
- 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"))
-
- self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
- self.type_obj_combo_label.setToolTip(
- _("Specify the type of object to be cutout.\n"
- "It can be of type: Gerber or Geometry.\n"
- "What is selected here will dictate the kind\n"
- "of objects that will populate the 'Object' combobox.")
- )
- self.type_obj_combo_label.setMinimumWidth(60)
- grid0.addWidget(self.type_obj_combo_label, 0, 0)
- grid0.addWidget(self.type_obj_combo, 0, 1)
-
- self.object_label = QtWidgets.QLabel('%s:' % _("Object to be cutout"))
+ self.object_label = QtWidgets.QLabel('%s:' % _("Source Object"))
self.object_label.setToolTip('%s.' % _("Object to be cutout"))
- # Object to be cutout
- self.obj_combo = QtWidgets.QComboBox()
- self.obj_combo.setModel(self.app.collection)
- self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.obj_combo.setCurrentIndex(1)
-
- grid0.addWidget(self.object_label, 1, 0, 1, 2)
- grid0.addWidget(self.obj_combo, 2, 0, 1, 2)
+ grid0.addWidget(self.object_label, 0, 0, 1, 2)
# Object kind
self.kindlabel = QtWidgets.QLabel('%s:' % _('Object kind'))
@@ -112,8 +84,43 @@ class CutOut(FlatCAMTool):
{"label": _("Single"), "value": "single"},
{"label": _("Panel"), "value": "panel"},
])
- grid0.addWidget(self.kindlabel, 3, 0)
- grid0.addWidget(self.obj_kind_combo, 3, 1)
+ grid0.addWidget(self.kindlabel, 1, 0)
+ grid0.addWidget(self.obj_kind_combo, 1, 1)
+
+ # Type of object to be cutout
+ self.type_obj_radio = RadioSet([
+ {"label": _("Gerber"), "value": "grb"},
+ {"label": _("Geometry"), "value": "geo"},
+ ])
+
+ self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
+ self.type_obj_combo_label.setToolTip(
+ _("Specify the type of object to be cutout.\n"
+ "It can be of type: Gerber or Geometry.\n"
+ "What is selected here will dictate the kind\n"
+ "of objects that will populate the 'Object' combobox.")
+ )
+
+ grid0.addWidget(self.type_obj_combo_label, 2, 0)
+ grid0.addWidget(self.type_obj_radio, 2, 1)
+
+ # Object to be cutout
+ self.obj_combo = QtWidgets.QComboBox()
+ self.obj_combo.setModel(self.app.collection)
+ self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.obj_combo.setCurrentIndex(1)
+
+ grid0.addWidget(self.obj_combo, 3, 0, 1, 2)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 4, 0, 1, 2)
+
+ grid0.addWidget(QtWidgets.QLabel(''), 5, 0, 1, 2)
+
+ self.param_label = QtWidgets.QLabel('%s:' % _("Tool Parameters"))
+ grid0.addWidget(self.param_label, 6, 0, 1, 2)
# Tool Diameter
self.dia = FCDoubleSpinner()
@@ -125,8 +132,8 @@ class CutOut(FlatCAMTool):
_("Diameter of the tool used to cutout\n"
"the PCB shape out of the surrounding material.")
)
- grid0.addWidget(self.dia_label, 4, 0)
- grid0.addWidget(self.dia, 4, 1)
+ grid0.addWidget(self.dia_label, 8, 0)
+ grid0.addWidget(self.dia, 8, 1)
# Cut Z
cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
@@ -146,8 +153,8 @@ class CutOut(FlatCAMTool):
self.cutz_entry.setSingleStep(0.1)
- grid0.addWidget(cutzlabel, 5, 0)
- grid0.addWidget(self.cutz_entry, 5, 1)
+ grid0.addWidget(cutzlabel, 9, 0)
+ grid0.addWidget(self.cutz_entry, 9, 1)
# Multi-pass
self.mpass_cb = FCCheckBox('%s:' % _("Multi-Depth"))
@@ -172,8 +179,8 @@ class CutOut(FlatCAMTool):
)
self.ois_mpass_geo = OptionalInputSection(self.mpass_cb, [self.maxdepth_entry])
- grid0.addWidget(self.mpass_cb, 6, 0)
- grid0.addWidget(self.maxdepth_entry, 6, 1)
+ grid0.addWidget(self.mpass_cb, 10, 0)
+ grid0.addWidget(self.maxdepth_entry, 10, 1)
# Margin
self.margin = FCDoubleSpinner()
@@ -187,8 +194,8 @@ class CutOut(FlatCAMTool):
"will make the cutout of the PCB further from\n"
"the actual PCB border")
)
- grid0.addWidget(self.margin_label, 7, 0)
- grid0.addWidget(self.margin, 7, 1)
+ grid0.addWidget(self.margin_label, 11, 0)
+ grid0.addWidget(self.margin, 11, 1)
# Gapsize
self.gapsize = FCDoubleSpinner()
@@ -201,8 +208,8 @@ class CutOut(FlatCAMTool):
"the surrounding material (the one \n"
"from which the PCB is cutout).")
)
- grid0.addWidget(self.gapsize_label, 8, 0)
- grid0.addWidget(self.gapsize, 8, 1)
+ grid0.addWidget(self.gapsize_label, 13, 0)
+ grid0.addWidget(self.gapsize, 13, 1)
# How gaps wil be rendered:
# lr - left + right
@@ -219,12 +226,14 @@ class CutOut(FlatCAMTool):
_("Create a convex shape surrounding the entire PCB.\n"
"Used only if the source object type is Gerber.")
)
- grid0.addWidget(self.convex_box, 9, 0, 1, 2)
+ grid0.addWidget(self.convex_box, 15, 0, 1, 2)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid0.addWidget(separator_line, 10, 0, 1, 2)
+ grid0.addWidget(separator_line, 16, 0, 1, 2)
+
+ grid0.addWidget(QtWidgets.QLabel(''), 17, 0, 1, 2)
# Title2
title_param_label = QtWidgets.QLabel("%s" % _('A. Automatic Bridge Gaps'))
@@ -398,13 +407,13 @@ class CutOut(FlatCAMTool):
self.ff_cutout_object_btn.clicked.connect(self.on_freeform_cutout)
self.rect_cutout_object_btn.clicked.connect(self.on_rectangular_cutout)
- self.type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
+ self.type_obj_radio.activated_custom.connect(self.on_type_obj_changed)
self.man_geo_creation_btn.clicked.connect(self.on_manual_geo)
self.man_gaps_creation_btn.clicked.connect(self.on_manual_gap_click)
self.reset_button.clicked.connect(self.set_tool_ui)
- def on_type_obj_index_changed(self, index):
- obj_type = self.type_obj_combo.currentIndex()
+ def on_type_obj_changed(self, val):
+ obj_type = {'grb': 0, 'geo': 2}[val]
self.obj_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.obj_combo.setCurrentIndex(0)
@@ -451,6 +460,7 @@ class CutOut(FlatCAMTool):
self.gapsize.set_value(float(self.app.defaults["tools_cutoutgapsize"]))
self.gaps.set_value(self.app.defaults["tools_gaps_ff"])
self.convex_box.set_value(self.app.defaults['tools_cutout_convexshape'])
+ self.type_obj_radio.set_value('grb')
def on_freeform_cutout(self):
diff --git a/flatcamTools/ToolPanelize.py b/flatcamTools/ToolPanelize.py
index 7159e81f..a836d320 100644
--- a/flatcamTools/ToolPanelize.py
+++ b/flatcamTools/ToolPanelize.py
@@ -49,6 +49,18 @@ class Panelize(FlatCAMTool):
""")
self.layout.addWidget(title_label)
+ self.layout.addWidget(QtWidgets.QLabel(''))
+
+ self.object_label = QtWidgets.QLabel('%s:' % _("Source Object"))
+ self.object_label.setToolTip(
+ _("Specify the type of object to be panelized\n"
+ "It can be of type: Gerber, Excellon or Geometry.\n"
+ "The selection here decide the type of objects that will be\n"
+ "in the Object combobox.")
+ )
+
+ self.layout.addWidget(self.object_label)
+
# Form Layout
form_layout_0 = QtWidgets.QFormLayout()
self.layout.addLayout(form_layout_0)
@@ -63,14 +75,9 @@ class Panelize(FlatCAMTool):
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"))
- self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
- self.type_obj_combo_label.setToolTip(
- _("Specify the type of object to be panelized\n"
- "It can be of type: Gerber, Excellon or Geometry.\n"
- "The selection here decide the type of objects that will be\n"
- "in the Object combobox.")
- )
- form_layout_0.addRow(self.type_obj_combo_label, self.type_obj_combo)
+ self.type_object_label = QtWidgets.QLabel('%s:' % _("Object Type"))
+
+ form_layout_0.addRow(self.type_object_label, self.type_obj_combo)
# Object to be panelized
self.object_combo = QtWidgets.QComboBox()
@@ -78,12 +85,11 @@ class Panelize(FlatCAMTool):
self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.object_combo.setCurrentIndex(1)
- self.object_label = QtWidgets.QLabel('%s:' % _("Object"))
- self.object_label.setToolTip(
+ self.object_combo.setToolTip(
_("Object to be panelized. This means that it will\n"
"be duplicated in an array of rows and columns.")
)
- form_layout_0.addRow(self.object_label, self.object_combo)
+ form_layout_0.addRow(self.object_combo)
form_layout_0.addRow(QtWidgets.QLabel(""))
# Form Layout
@@ -133,12 +139,11 @@ class Panelize(FlatCAMTool):
self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.box_combo.setCurrentIndex(1)
- self.box_combo_label = QtWidgets.QLabel('%s:' % _("Box Object"))
- self.box_combo_label.setToolTip(
+ self.box_combo.setToolTip(
_("The actual object that is used a container for the\n "
"selected object that is to be panelized.")
)
- form_layout.addRow(self.box_combo_label, self.box_combo)
+ form_layout.addRow(self.box_combo)
form_layout.addRow(QtWidgets.QLabel(""))
panel_data_label = QtWidgets.QLabel("%s:" % _("Panel Data"))
@@ -382,12 +387,10 @@ class Panelize(FlatCAMTool):
self.type_box_combo.setDisabled(False)
self.type_box_combo_label.setDisabled(False)
self.box_combo.setDisabled(False)
- self.box_combo_label.setDisabled(False)
else:
self.type_box_combo.setDisabled(True)
self.type_box_combo_label.setDisabled(True)
self.box_combo.setDisabled(True)
- self.box_combo_label.setDisabled(True)
def on_panelize(self):
name = self.object_combo.currentText()
From a44d7b97b561d8751efcc1e698bb39c1ea5bcdfd Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 30 Jan 2020 05:55:46 +0200
Subject: [PATCH 060/209] - some changed in the Excellon UI
---
FlatCAMObj.py | 13 ++++++++++++-
README.md | 1 +
flatcamGUI/ObjectUI.py | 4 ++--
3 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 8cbc596a..3ed53b66 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -2868,7 +2868,18 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
sel_rows = row if type(row) == list else [row]
if not sel_rows:
- sel_rows = [0]
+ self.ui.tool_data_label.setText(
+ "%s: %s" % (_('Parameters for'), _("No Tool Selected"))
+ )
+ self.ui.generate_cnc_button.setDisabled(True)
+ self.ui.generate_milling_button.setDisabled(True)
+ self.ui.generate_milling_slots_button.setDisabled(True)
+ self.ui_connect()
+ return
+ else:
+ self.ui.generate_cnc_button.setDisabled(False)
+ self.ui.generate_milling_button.setDisabled(False)
+ self.ui.generate_milling_slots_button.setDisabled(False)
if len(sel_rows) == 1:
# update the QLabel that shows for which Tool we have the parameters in the UI form
diff --git a/README.md b/README.md
index 9a1c3463..e16d8193 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
30.01.2020
- remade GUI in Tool Cutout, Tool Align Objects, Tool Panelize
+- some changed in the Excellon UI
29.01.2020
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index 3d97ccb6..6a0b2df5 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -1248,7 +1248,7 @@ class ExcellonObjectUI(ObjectUI):
warning_lbl = QtWidgets.QLabel(
_(
"Add / Select at least one tool in the tool-table.\n"
- "Click the header to select all, or Ctrl + LMB\n"
+ "Click the # header to select all, or Ctrl + LMB\n"
"for custom selection of tools."
))
@@ -1946,7 +1946,7 @@ class GeometryObjectUI(ObjectUI):
warning_lbl = QtWidgets.QLabel(
_(
"Add / Select at least one tool in the tool-table.\n"
- "Click the header to select all, or Ctrl + LMB\n"
+ "Click the # header to select all, or Ctrl + LMB\n"
"for custom selection of tools."
))
self.grid4.addWidget(warning_lbl, 6, 0, 1, 2)
From ece94b7f6050efc8a77f52cc42c75daea82eae84 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 30 Jan 2020 06:26:14 +0200
Subject: [PATCH 061/209] - some UI changes in the common object UI
---
FlatCAMObj.py | 4 --
README.md | 1 +
flatcamGUI/ObjectUI.py | 97 ++++++++++++++++++++++--------------------
3 files changed, 51 insertions(+), 51 deletions(-)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 3ed53b66..33c6aeed 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -2695,20 +2695,16 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.ui.tools_table.setMaximumHeight(self.ui.tools_table.getHeight())
if not self.drills:
- self.ui.tdlabel.hide()
self.ui.tooldia_entry.hide()
self.ui.generate_milling_button.hide()
else:
- self.ui.tdlabel.show()
self.ui.tooldia_entry.show()
self.ui.generate_milling_button.show()
if not self.slots:
- self.ui.stdlabel.hide()
self.ui.slot_tooldia_entry.hide()
self.ui.generate_milling_slots_button.hide()
else:
- self.ui.stdlabel.show()
self.ui.slot_tooldia_entry.show()
self.ui.generate_milling_slots_button.show()
diff --git a/README.md b/README.md
index e16d8193..92b79cb6 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- remade GUI in Tool Cutout, Tool Align Objects, Tool Panelize
- some changed in the Excellon UI
+- some UI changes in the common object UI
29.01.2020
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index 6a0b2df5..6270e332 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -95,28 +95,31 @@ class ObjectUI(QtWidgets.QWidget):
# ###########################
if common is True:
self.common_grid = QtWidgets.QGridLayout()
+ self.common_grid.setColumnStretch(0, 1)
+ self.common_grid.setColumnStretch(1, 0)
layout.addLayout(self.common_grid)
- self.common_grid.setColumnStretch(0, 0)
- self.common_grid.setColumnStretch(1, 1)
- # ### Scale ####
- self.scale_label = QtWidgets.QLabel('%s' % _('Scale'))
- self.scale_label.setToolTip(
- _("Change the size of the object.")
+ # self.common_grid.addWidget(QtWidgets.QLabel(''), 1, 0, 1, 2)
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.common_grid.addWidget(separator_line, 1, 0, 1, 2)
+
+ self.transform_label = QtWidgets.QLabel('%s' % _('Transformations'))
+ self.transform_label.setToolTip(
+ _("Geometrical transformations of the current object.")
)
- self.common_grid.addWidget(self.scale_label, 0, 0, 1, 3)
+ self.common_grid.addWidget(self.transform_label, 2, 0, 1, 2)
- # Factor
- faclabel = QtWidgets.QLabel('%s:' % _('Factor'))
- faclabel.setToolTip(
+ # ### Scale ####
+ self.scale_entry = FCEntry()
+ self.scale_entry.set_value(1.0)
+ self.scale_entry.setToolTip(
_("Factor by which to multiply\n"
"geometric features of this object.\n"
"Expressions are allowed. E.g: 1/25.4")
)
- self.scale_entry = FCEntry()
- self.scale_entry.set_value(1.0)
-
# GO Button
self.scale_button = QtWidgets.QPushButton(_('Scale'))
self.scale_button.setToolTip(
@@ -124,26 +127,17 @@ class ObjectUI(QtWidgets.QWidget):
)
self.scale_button.setMinimumWidth(70)
- self.common_grid.addWidget(faclabel, 1, 0)
- self.common_grid.addWidget(self.scale_entry, 1, 1)
- self.common_grid.addWidget(self.scale_button, 1, 2)
+ self.common_grid.addWidget(self.scale_entry, 3, 0)
+ self.common_grid.addWidget(self.scale_button, 3, 1)
# ### Offset ####
- self.offset_label = QtWidgets.QLabel('%s' % _('Offset'))
- self.offset_label.setToolTip(
- _("Change the position of this object.")
- )
-
- self.common_grid.addWidget(self.offset_label, 2, 0, 1, 3)
-
- self.offset_vectorlabel = QtWidgets.QLabel('%s:' % _('Vector'))
- self.offset_vectorlabel.setToolTip(
+ self.offsetvector_entry = EvalEntry2()
+ self.offsetvector_entry.setText("(0.0, 0.0)")
+ self.offsetvector_entry.setToolTip(
_("Amount by which to move the object\n"
"in the x and y axes in (x, y) format.\n"
"Expressions are allowed. E.g: (1/3.2, 0.5*3)")
)
- self.offsetvector_entry = EvalEntry2()
- self.offsetvector_entry.setText("(0.0, 0.0)")
self.offset_button = QtWidgets.QPushButton(_('Offset'))
self.offset_button.setToolTip(
@@ -151,9 +145,8 @@ class ObjectUI(QtWidgets.QWidget):
)
self.offset_button.setMinimumWidth(70)
- self.common_grid.addWidget(self.offset_vectorlabel, 3, 0)
- self.common_grid.addWidget(self.offsetvector_entry, 3, 1)
- self.common_grid.addWidget(self.offset_button, 3, 2)
+ self.common_grid.addWidget(self.offsetvector_entry, 4, 0)
+ self.common_grid.addWidget(self.offset_button, 4, 1)
layout.addStretch()
@@ -1156,6 +1149,21 @@ class ExcellonObjectUI(ObjectUI):
self.feedrate_probe_label.hide()
self.feedrate_probe_entry.setVisible(False)
+ # Tool Offset
+ self.tool_offset_label = QtWidgets.QLabel('%s:' % _('Offset Z'))
+ self.tool_offset_label.setToolTip(
+ _("Some drill bits (the larger ones) need to drill deeper\n"
+ "to create the desired exit hole diameter due of the tip shape.\n"
+ "The value here can compensate the Cut Z parameter.")
+ )
+
+ self.offset_entry = FCDoubleSpinner()
+ self.offset_entry.set_precision(self.decimals)
+ self.offset_entry.set_range(-9999.9999, 9999.9999)
+
+ self.grid3.addWidget(self.tool_offset_label, 25, 0)
+ self.grid3.addWidget(self.offset_entry, 25, 1)
+
# #################################################################
# ################# GRID LAYOUT 4 ###############################
# #################################################################
@@ -1271,10 +1279,10 @@ class ExcellonObjectUI(ObjectUI):
separator_line2 = QtWidgets.QFrame()
separator_line2.setFrameShape(QtWidgets.QFrame.HLine)
separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.grid6.addWidget(separator_line2, 4, 0, 1, 2)
+ self.grid6.addWidget(separator_line2, 4, 0, 1, 3)
# ### Milling Holes Drills ####
- self.mill_hole_label = QtWidgets.QLabel('%s' % _('Mill Holes'))
+ self.mill_hole_label = QtWidgets.QLabel('%s' % _('Milling Geometry'))
self.mill_hole_label.setToolTip(
_("Create Geometry for milling holes.\n"
"Select from the Tools Table above the hole dias to be\n"
@@ -1282,16 +1290,19 @@ class ExcellonObjectUI(ObjectUI):
)
self.grid6.addWidget(self.mill_hole_label, 5, 0, 1, 3)
- self.tdlabel = QtWidgets.QLabel('%s:' % _('Drill Tool dia'))
+ self.tdlabel = QtWidgets.QLabel('%s:' % _('Tool Dia'))
self.tdlabel.setToolTip(
_("Diameter of the cutting tool.")
)
+
+ self.grid6.addWidget(self.tdlabel, 6, 0, 1, 3)
+
self.tooldia_entry = FCDoubleSpinner()
self.tooldia_entry.set_precision(self.decimals)
self.tooldia_entry.set_range(0.0, 9999.9999)
self.tooldia_entry.setSingleStep(0.1)
- self.generate_milling_button = QtWidgets.QPushButton(_('Mill Drills Geo'))
+ self.generate_milling_button = QtWidgets.QPushButton(_('Mill Drills'))
self.generate_milling_button.setToolTip(
_("Create the Geometry Object\n"
"for milling DRILLS toolpaths.")
@@ -1303,22 +1314,15 @@ class ExcellonObjectUI(ObjectUI):
}
""")
- self.grid6.addWidget(self.tdlabel, 6, 0)
- self.grid6.addWidget(self.tooldia_entry, 6, 1)
- self.grid6.addWidget(self.generate_milling_button, 6, 2)
-
- self.stdlabel = QtWidgets.QLabel('%s:' % _('Slot Tool dia'))
- self.stdlabel.setToolTip(
- _("Diameter of the cutting tool\n"
- "when milling slots.")
- )
+ self.grid6.addWidget(self.tooldia_entry, 7, 0, 1, 2)
+ self.grid6.addWidget(self.generate_milling_button, 7, 2)
self.slot_tooldia_entry = FCDoubleSpinner()
self.slot_tooldia_entry.set_precision(self.decimals)
self.slot_tooldia_entry.set_range(0.0, 9999.9999)
self.slot_tooldia_entry.setSingleStep(0.1)
- self.generate_milling_slots_button = QtWidgets.QPushButton(_('Mill Slots Geo'))
+ self.generate_milling_slots_button = QtWidgets.QPushButton(_('Mill Slots'))
self.generate_milling_slots_button.setToolTip(
_("Create the Geometry Object\n"
"for milling SLOTS toolpaths.")
@@ -1330,9 +1334,8 @@ class ExcellonObjectUI(ObjectUI):
}
""")
- self.grid6.addWidget(self.stdlabel, 7, 0)
- self.grid6.addWidget(self.slot_tooldia_entry, 7, 1)
- self.grid6.addWidget(self.generate_milling_slots_button, 7, 2)
+ self.grid6.addWidget(self.slot_tooldia_entry, 8, 0, 1, 2)
+ self.grid6.addWidget(self.generate_milling_slots_button, 8, 2)
def hide_drills(self, state=True):
if state is True:
From 0b162bbd550480ab1f821b8ed3e2039bb754ee6d Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 31 Jan 2020 22:34:20 +0200
Subject: [PATCH 062/209] - added a new functionality, a variation of Set
Origin named Move to Origin. It will move a selection of objects to origin
such as the bottom left corner of the bounding box that fit them all is in
origin.
---
FlatCAMApp.py | 53 ++++++++++++++++++++++++++++++++++++++-
README.md | 4 +++
flatcamGUI/FlatCAMGUI.py | 6 +++++
share/origin16.png | Bin 563 -> 523 bytes
share/origin2_16.png | Bin 0 -> 516 bytes
share/origin2_32.png | Bin 0 -> 763 bytes
share/origin32.png | Bin 750 -> 808 bytes
7 files changed, 62 insertions(+), 1 deletion(-)
create mode 100644 share/origin2_16.png
create mode 100644 share/origin2_32.png
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 697978a7..14a05111 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -1974,6 +1974,8 @@ class App(QtCore.QObject):
self.ui.menueditconvert_any2gerber.triggered.connect(self.convert_any2gerber)
self.ui.menueditorigin.triggered.connect(self.on_set_origin)
+ self.ui.menuedit_move2origin.triggered.connect(self.on_move2origin)
+
self.ui.menueditjump.triggered.connect(self.on_jump_to)
self.ui.menueditlocate.triggered.connect(lambda: self.on_locate(obj=self.collection.get_active()))
@@ -3267,6 +3269,8 @@ class App(QtCore.QObject):
self.ui.distance_btn.triggered.connect(lambda: self.distance_tool.run(toggle=True))
self.ui.distance_min_btn.triggered.connect(lambda: self.distance_min_tool.run(toggle=True))
self.ui.origin_btn.triggered.connect(self.on_set_origin)
+ self.ui.move2origin_btn.triggered.connect(self.on_move2origin)
+
self.ui.jmp_btn.triggered.connect(self.on_jump_to)
self.ui.locate_btn.triggered.connect(lambda: self.on_locate(obj=self.collection.get_active()))
@@ -7275,7 +7279,7 @@ class App(QtCore.QObject):
event_pos = (event.xdata, event.ydata)
pos_canvas = self.plotcanvas.translate_coords(event_pos)
- if self.grid_status() == True:
+ if self.grid_status():
pos = self.geo_editor.snap(pos_canvas[0], pos_canvas[1])
else:
pos = pos_canvas
@@ -7289,6 +7293,53 @@ class App(QtCore.QObject):
worker_task()
self.should_we_save = True
+ def on_move2origin(self, use_thread=True):
+ """
+
+ :param event:
+ :param location:
+ :param noplot:
+ :param use_thread:
+ :return:
+ """
+
+ def worker_task():
+ with self.proc_container.new(_("Moving to Origin...")):
+ obj_list = self.collection.get_selected()
+ xminlist = list()
+ yminlist = list()
+
+ # first get a bounding box to fit all
+ for obj in obj_list:
+ xmin, ymin, xmax, ymax = obj.bounds()
+ xminlist.append(xmin)
+ yminlist.append(ymin)
+
+ # get the minimum x,y for all objects selected
+ x = min(xminlist)
+ y = min(yminlist)
+
+ for obj in obj_list:
+ obj.offset((-x, -y))
+ self.object_changed.emit(obj)
+
+ # Update the object bounding box options
+ a, b, c, d = obj.bounds()
+ obj.options['xmin'] = a
+ obj.options['ymin'] = b
+ obj.options['xmax'] = c
+ obj.options['ymax'] = d
+
+ for obj in obj_list:
+ obj.plot()
+ self.inform.emit('[success] %s...' % _('Origin set'))
+
+ if use_thread is True:
+ self.worker_task.emit({'fcn': worker_task, 'params': []})
+ else:
+ worker_task()
+ self.should_we_save = True
+
def on_jump_to(self, custom_location=None, fit_center=True):
"""
Jump to a location by setting the mouse cursor location
diff --git a/README.md b/README.md
index 92b79cb6..c537aaf9 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+31.01.2020
+
+- added a new functionality, a variation of Set Origin named Move to Origin. It will move a selection of objects to origin such as the bottom left corner of the bounding box that fit them all is in origin.
+
30.01.2020
- remade GUI in Tool Cutout, Tool Align Objects, Tool Panelize
diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py
index e7a4bc68..b67b4c0e 100644
--- a/flatcamGUI/FlatCAMGUI.py
+++ b/flatcamGUI/FlatCAMGUI.py
@@ -371,6 +371,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.menuedit.addSeparator()
self.menueditorigin = self.menuedit.addAction(
QtGui.QIcon(self.app.resource_location + '/origin16.png'), _('Se&t Origin\tO'))
+ self.menuedit_move2origin = self.menuedit.addAction(
+ QtGui.QIcon(self.app.resource_location + '/origin2_16.png'), _('Move to Origin\tSHIFT+O'))
+
self.menueditjump = self.menuedit.addAction(
QtGui.QIcon(self.app.resource_location + '/jump_to16.png'), _('Jump to Location\tJ'))
self.menueditlocate = self.menuedit.addAction(
@@ -841,6 +844,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
QtGui.QIcon(self.app.resource_location + '/distance_min32.png'), _("Distance Min Tool"))
self.origin_btn = self.toolbargeo.addAction(
QtGui.QIcon(self.app.resource_location + '/origin32.png'), _('Set Origin'))
+ self.move2origin_btn = self.toolbargeo.addAction(
+ QtGui.QIcon(self.app.resource_location + '/origin2_32.png'), _('Move to Origin'))
+
self.jmp_btn = self.toolbargeo.addAction(
QtGui.QIcon(self.app.resource_location + '/jump_to16.png'), _('Jump to Location'))
self.locate_btn = self.toolbargeo.addAction(
diff --git a/share/origin16.png b/share/origin16.png
index e9fa79406da44f822d269ff5fb394d930e69e6f5..2c0374d81eff13a16666d3c0b0ea8613f1256f30 100644
GIT binary patch
delta 330
zcmdnY(#Uk%e0^&Pnj1(?MmAHP`LMrGbVrA|NToPRY~-0xYeIYhb8rY#3r_VP$A&WoWK#U|?lnaO~g|ugMn~
Q#c;`QpQH0_G82;_0Ivau(f|Me
delta 394
zcmeBX*~~Jbv;Hv`Kc~7??D^Ts3=E8no-U3d8s|eV9Mo=%f!bFzq{^VBq-`HFfwC;(L9@oidAKq=ZVBfX
zyk5~Pp>1~OG)IlrjuPSNSL*vSXYcrMV{%YutGV;MyWhO)*UmTLpX(<3l!1XkwZt`|
zBqgyV)hf9t6-Y4{85mmX8XD*tnuZuyS{YkfnObNYm{=JYM71u+M$wR)pOTqYiCcsA
P4T^mT`@Tw0nS*ukeH=5SChz^rkFqry!mryOl1A=xW6NsSswZ*H7h`|Rvo^Y8A)
zZf?Fx8GDk_{f^EKS??qq&b0f-m&eBzy)03hoRHS$@~*V#R>l2rs
z3`zXD-gd(FV?0m3y$;p4IjtogG*eyw?6+gjoUDHY?bw!cpGj$Y#hUE$#l`RJADF2I
zu90RdP`(kYX@0Ff!0JFw`|R3^BB@GB&j`FxECOure@Mzj$R0
ziiX_$l+3hB+#2rv6FdOaAPKS|I6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD<-
MPgg&ebxsLQ0J@~H`Tzg`
literal 0
HcmV?d00001
diff --git a/share/origin2_32.png b/share/origin2_32.png
new file mode 100644
index 0000000000000000000000000000000000000000..b4c6c721ec72937a194949c4e7fe30cb7a7b35ec
GIT binary patch
literal 763
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50
z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzZ+Rj;xUkjGiz
z5n0T@z;^_M8K-LVNdpDhOFVsD*`F}V3n}S#UirYrz`%IY)5S5wrB1dO
zla*`NUR%QFRk^MII(ujOuYI52*?zzG`QGg}rE
zWqXe4&)B?l;i@G|RwV{IYQ+^@suew*=lMD)WXgoH+g)8vDa*gq<>#C>ncv-Y_VW^1
z?_Z03-fUm;Xi{sy$4cc@YlR#ejptS7AG)sm`*+eIcJ70YO-$eCOb+dr`M7)yWBK8^
z>siw54{Ug7rng$=o9i>3@}eD`p+C!tPM^KOWNa3_a!OlCPNO3)^Z%gmn)em@d=mp~
zcPQW8@oK*6AF)vSi6MQJ1ja>+G8*m@8o~JZ~Fh(
zzrRk~2ZS;f>^zP+QeKTvVc)%0_7s_nQE
zkG$)>A$^7;d6UA#2H|6^lDtz_pZAD$beo>YEynYDievwklBIfXt*bK(Ra^G#QB}Oy
zBKOeq=ZizdTTXa>wbGb)wShiPH{uU?NxQ*{6TwruD>{NSm_V*Lgw{XR{Y<*ht=j%&)aXmp6#}}YA62f
z`$O-C{~BC3m)&@|x^hqP!ip)$tWjR6Wt*Mk=W(@n8(E~B6nMw&e*OG|$*gN74lh;u
zlN#N#@alQdjEQpGk+*%l=f+=lY~SN@%rmim!58l>oXHld=@)rRg*p%Coj#p;%=@9w
z&JMShye%_CJ_S`O`eYp|OHDkQh#UmS+O7Af3Y6kxpgv2!t)zVNDJB&FVZ|$F
delta 614
zcmZ3%_KsDtGr-TCmrII^fq{Y7)59eQNK1e)2Mdt&s{2|zQ8AfA?*~$zI
zjC(v?978NlPrY*1drF`P+lTuvG#q`|`aFH!{%R7N>c+tpse4O;({alS=9Rup3W7UJ
z1m8umvij}FP!_#vA0VVFCBu_`LQSJX?B%62!CsFEy3fw7Hr}gev-o6pNHzLz$+HmjM;&KJ3wG=EQZ*_E#o
zj1sTi`|+CF@2J_`e8*)UtGXlq&h~rR6SMaAvloXpt!%LF*|F}nUVP|*a`w08+v5}$
zrlcRJ?aGrdf46MWy$QLWJ(FTDBwH=mvdHJllAcB14%n0y-QDrHNU`?nlBFvy)K6Ly
z&G@_|w0F1m!#S?W4>pw_yU;B1&Ehq`h0@})Q9+T1y6&G!xT>ET65w_!D?ux4%34)h
zw?k$(ACz|IM9kEAS0Ohe@H6AW)7=?Ttn7=H@oTzWu6`O(y5Q=M7h9ehG-#gR;{D_0
zB*mi-&PuzRTiHHwYzcOI`n1=}b!Yp!tLxqBCvRsni|yr3`}e=dN@PyID36v$cjp$#
z{x|D{OJ;qsDynwAy!Eo^_P-zQCDvS2f4naCbBNR3;lXO`7z!Lg@QD
z-T$Wl7?=Oa-go=pr%Yh{s+PD$l%ynogODkhbD^m+?
j0}~4?1B0m61=%P%a`RI%(<*W30BX>_A#r{3cP2vs7^@DS
From 6eb96264f1e9eb1f9a2a80e6446cb60b3aa5ea92 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 1 Feb 2020 04:01:48 +0200
Subject: [PATCH 063/209] - fixed some bugs
---
FlatCAMObj.py | 32 ++++++++++++++++-------------
README.md | 1 +
camlib.py | 11 +++++-----
flatcamEditors/FlatCAMTextEditor.py | 2 +-
4 files changed, 26 insertions(+), 20 deletions(-)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 33c6aeed..870003b9 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -4229,6 +4229,9 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.geo_tools_table.cellWidget(row, 6).clicked.connect(self.on_plot_cb_click_table)
self.ui.plot_cb.stateChanged.connect(self.on_plot_cb_click)
+ # common parameters update
+ self.ui.pp_geometry_name_cb.currentIndexChanged.connect(self.update_common_param_in_storage)
+
def ui_disconnect(self):
# on any change to the widgets that matter it will be called self.gui_form_to_storage which will save the
@@ -4969,6 +4972,10 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
temp_tools.clear()
self.ui_connect()
+ def update_common_param_in_storage(self):
+ for tooluid_value in self.tools.values():
+ tooluid_value['data']['ppname_g'] = self.ui.pp_geometry_name_cb.get_value()
+
def select_tools_table_row(self, row, clearsel=None):
if clearsel:
self.ui.geo_tools_table.clearSelection()
@@ -5117,16 +5124,14 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# this reads the values in the UI form to the self.options dictionary
self.read_form()
- self.sel_tools = {}
+ self.sel_tools = dict()
try:
if self.special_group:
- self.app.inform.emit('[WARNING_NOTCL] %s %s %s.' %
- (_("This Geometry can't be processed because it is"),
- str(self.special_group),
- _("geometry")
- )
- )
+ self.app.inform.emit(
+ '[WARNING_NOTCL] %s %s %s.' %
+ (_("This Geometry can't be processed because it is"), str(self.special_group), _("geometry"))
+ )
return
except AttributeError:
pass
@@ -5166,8 +5171,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.geo_tools_table.clearSelection()
else:
- self.app.inform.emit('[ERROR_NOTCL] %s' %
- _("Failed. No tool selected in the tool table ..."))
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed. No tool selected in the tool table ..."))
def mtool_gen_cncjob(self, outname=None, tools_dict=None, tools_in_use=None, segx=None, segy=None,
plot=True, use_thread=True):
@@ -5261,15 +5265,15 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
try:
offset_value = float(self.ui.tool_offset_entry.get_value().replace(',', '.'))
except ValueError:
- self.app.inform.emit('[ERROR_NOTCL] %s' %
- _("Wrong value format entered, use a number."))
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _("Wrong value format entered, use a number."))
return
if offset_value:
tool_offset = float(offset_value)
else:
- self.app.inform.emit('[WARNING] %s' % _("Tool Offset is selected in Tool Table but "
- "no value is provided.\n"
- "Add a Tool Offset or change the Offset Type."))
+ self.app.inform.emit(
+ '[WARNING] %s' % _("Tool Offset is selected in Tool Table but no value is provided.\n"
+ "Add a Tool Offset or change the Offset Type.")
+ )
return
else:
tool_offset = 0.0
diff --git a/README.md b/README.md
index c537aaf9..513825ac 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
31.01.2020
- added a new functionality, a variation of Set Origin named Move to Origin. It will move a selection of objects to origin such as the bottom left corner of the bounding box that fit them all is in origin.
+- fixed some bugs
30.01.2020
diff --git a/camlib.py b/camlib.py
index d234dc90..b51be9a8 100644
--- a/camlib.py
+++ b/camlib.py
@@ -2876,7 +2876,7 @@ class CNCjob(Geometry):
# Tool change sequence (optional)
if toolchange:
- gcode += self.doformat(p.toolchange_code,toolchangexy=(self.oldx, self.oldy))
+ gcode += self.doformat(p.toolchange_code, toolchangexy=(self.oldx, self.oldy))
gcode += self.doformat(p.spindle_code) # Spindle start)
if self.dwell is True:
gcode += self.doformat(p.dwell_code) # Dwell time
@@ -3419,7 +3419,7 @@ class CNCjob(Geometry):
self.app.inform.emit('[ERROR] %s: %s' %
(_("Expected a Geometry, got"), type(geometry)))
return 'fail'
- log.debug("Generate_from_geometry_2()")
+ log.debug("Executing camlib.CNCJob.generate_from_geometry_2()")
# if solid_geometry is empty raise an exception
if not geometry.solid_geometry:
@@ -3470,7 +3470,7 @@ class CNCjob(Geometry):
return 'fail'
# hack: make offset smaller by 0.0000000001 which is insignificant difference but allow the job
# to continue
- elif -offset == ((c - a) / 2) or -offset == ((d - b) / 2):
+ elif -offset == ((c - a) / 2) or -offset == ((d - b) / 2):
offset_for_use = offset - 0.0000000001
for it in geometry.solid_geometry:
@@ -3487,11 +3487,12 @@ class CNCjob(Geometry):
flat_geometry = self.flatten(temp_solid_geometry, pathonly=True)
log.debug("%d paths" % len(flat_geometry))
- if type(self.app.defaults["geometry_cnctooldia"]) == float:
+ default_dia = 0.01
+ if isinstance(self.app.defaults["geometry_cnctooldia"], float):
default_dia = self.app.defaults["geometry_cnctooldia"]
else:
try:
- tools_string = self.defaults["geometry_cnctooldia"].split(",")
+ tools_string = self.app.defaults["geometry_cnctooldia"].split(",")
tools_diameters = [eval(a) for a in tools_string if a != '']
default_dia = tools_diameters[0] if tools_diameters else 0.0
except Exception as e:
diff --git a/flatcamEditors/FlatCAMTextEditor.py b/flatcamEditors/FlatCAMTextEditor.py
index a8d9eff7..4e1dbe60 100644
--- a/flatcamEditors/FlatCAMTextEditor.py
+++ b/flatcamEditors/FlatCAMTextEditor.py
@@ -313,7 +313,7 @@ class TextEditor(QtWidgets.QWidget):
if qc.hasSelection():
qc.insertText(new)
else:
- self.ui.code_editor.moveCursor(QtGui.QTextCursor.Start)
+ self.code_editor.moveCursor(QtGui.QTextCursor.Start)
break
# Mark end of undo block
cursor.endEditBlock()
From 7aea33914c995f23842b0d21dba087a801dfc7c8 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 1 Feb 2020 06:59:15 +0200
Subject: [PATCH 064/209] - fixed a division by zero error: fixed #377
---
FlatCAMApp.py | 8 ++++++--
FlatCAMObj.py | 6 +++++-
README.md | 1 +
flatcamEditors/FlatCAMTextEditor.py | 4 +++-
4 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 14a05111..23340b0c 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -7193,8 +7193,7 @@ class App(QtCore.QObject):
# Clear form
self.setup_component_editor()
- self.inform.emit('%s: %s' %
- (_("Object deleted"), name))
+ self.inform.emit('%s: %s' % (_("Object deleted"), name))
def on_set_origin(self):
"""
@@ -7306,6 +7305,11 @@ class App(QtCore.QObject):
def worker_task():
with self.proc_container.new(_("Moving to Origin...")):
obj_list = self.collection.get_selected()
+
+ if not obj_list:
+ self.inform.emit('[ERROR_NOTCL] %s' % _("Failed. No object(s) selected..."))
+ return
+
xminlist = list()
yminlist = list()
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 870003b9..288ae791 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -4756,7 +4756,11 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
return
tooldia = float(tool_dia_item.text())
- new_cutz = (tooldia - vdia) / (2 * math.tan(math.radians(half_vangle)))
+ try:
+ new_cutz = (tooldia - vdia) / (2 * math.tan(math.radians(half_vangle)))
+ except ZeroDivisionError:
+ new_cutz = self.old_cutz
+
new_cutz = float('%.*f' % (self.decimals, new_cutz)) * -1.0 # this value has to be negative
self.ui.cutz_entry.set_value(new_cutz)
diff --git a/README.md b/README.md
index 513825ac..a324e0e9 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- added a new functionality, a variation of Set Origin named Move to Origin. It will move a selection of objects to origin such as the bottom left corner of the bounding box that fit them all is in origin.
- fixed some bugs
+- fixed a division by zero error: fixed #377
30.01.2020
diff --git a/flatcamEditors/FlatCAMTextEditor.py b/flatcamEditors/FlatCAMTextEditor.py
index 4e1dbe60..fe0b847e 100644
--- a/flatcamEditors/FlatCAMTextEditor.py
+++ b/flatcamEditors/FlatCAMTextEditor.py
@@ -29,6 +29,8 @@ class TextEditor(QtWidgets.QWidget):
super().__init__()
self.app = app
+ self.plain_text = plain_text
+
self.setSizePolicy(
QtWidgets.QSizePolicy.MinimumExpanding,
QtWidgets.QSizePolicy.MinimumExpanding
@@ -45,7 +47,7 @@ class TextEditor(QtWidgets.QWidget):
self.work_editor_layout.setContentsMargins(2, 2, 2, 2)
self.t_frame.setLayout(self.work_editor_layout)
- if plain_text:
+ if self.plain_text:
self.editor_class = FCTextAreaLineNumber()
self.code_editor = self.editor_class.edit
From bfd71a81b8a7a0ff30e37fffe667789364322228 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 2 Feb 2020 05:34:26 +0200
Subject: [PATCH 065/209] - fixed issue #376 where the V-Shape parameters from
Gerber UI are not transfered to the resulting Geometry object if the
'combine' checkbox is not checked in the Gerber UI
---
FlatCAMApp.py | 2 +-
FlatCAMObj.py | 174 +++++++++++++++++++++++++++++++++-----------------
README.md | 4 ++
3 files changed, 120 insertions(+), 60 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 23340b0c..b6a695ae 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -141,7 +141,7 @@ class App(QtCore.QObject):
# ################## Version and VERSION DATE ##############################
# ##########################################################################
version = 8.992
- version_date = "2020/01/30"
+ version_date = "2020/02/12"
beta = True
engine = '3D'
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 288ae791..9e5dd15d 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -1156,8 +1156,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
visible=True)
self.poly_dict[shape_id] = clicked_poly
self.app.inform.emit(
- '%s: %d. %s' % (_("Added polygon"),
- int(len(self.poly_dict)),
+ '%s: %d. %s' % (_("Added polygon"), int(len(self.poly_dict)),
_("Click to add next polygon or right click to start isolation."))
)
else:
@@ -1330,7 +1329,61 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
geo_obj.options["cnctooldia"] = str(self.options["isotooldia"])
geo_obj.tool_type = self.ui.tool_type_radio.get_value().upper()
- geo_obj.solid_geometry = []
+ geo_obj.solid_geometry = list()
+
+ # transfer the Cut Z and Vtip and VAngle values in case that we use the V-Shape tool in Gerber UI
+ if self.ui.tool_type_radio.get_value() == 'v':
+ new_cutz = self.ui.cutz_spinner.get_value()
+ new_vtipdia = self.ui.tipdia_spinner.get_value()
+ new_vtipangle = self.ui.tipangle_spinner.get_value()
+ tool_type = 'V'
+ else:
+ new_cutz = self.app.defaults['geometry_cutz']
+ new_vtipdia = self.app.defaults['geometry_vtipdia']
+ new_vtipangle = self.app.defaults['geometry_vtipangle']
+ tool_type = 'C1'
+
+ # store here the default data for Geometry Data
+ default_data = {}
+ default_data.update({
+ "name": iso_name,
+ "plot": self.app.defaults['geometry_plot'],
+ "cutz": new_cutz,
+ "vtipdia": new_vtipdia,
+ "vtipangle": new_vtipangle,
+ "travelz": self.app.defaults['geometry_travelz'],
+ "feedrate": self.app.defaults['geometry_feedrate'],
+ "feedrate_z": self.app.defaults['geometry_feedrate_z'],
+ "feedrate_rapid": self.app.defaults['geometry_feedrate_rapid'],
+ "dwell": self.app.defaults['geometry_dwell'],
+ "dwelltime": self.app.defaults['geometry_dwelltime'],
+ "multidepth": self.app.defaults['geometry_multidepth'],
+ "ppname_g": self.app.defaults['geometry_ppname_g'],
+ "depthperpass": self.app.defaults['geometry_depthperpass'],
+ "extracut": self.app.defaults['geometry_extracut'],
+ "extracut_length": self.app.defaults['geometry_extracut_length'],
+ "toolchange": self.app.defaults['geometry_toolchange'],
+ "toolchangez": self.app.defaults['geometry_toolchangez'],
+ "endz": self.app.defaults['geometry_endz'],
+ "spindlespeed": self.app.defaults['geometry_spindlespeed'],
+ "toolchangexy": self.app.defaults['geometry_toolchangexy'],
+ "startz": self.app.defaults['geometry_startz']
+ })
+
+ geo_obj.tools = dict()
+ geo_obj.tools['1'] = dict()
+ geo_obj.tools.update({
+ '1': {
+ 'tooldia': float(self.options["isotooldia"]),
+ 'offset': 'Path',
+ 'offset_value': 0.0,
+ 'type': _('Rough'),
+ 'tool_type': tool_type,
+ 'data': default_data,
+ 'solid_geometry': geo_obj.solid_geometry
+ }
+ })
+
for i in range(passes):
iso_offset = dia * ((2 * i + 1) / 2.0) - (i * overlap * dia)
@@ -1344,58 +1397,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
return 'fail'
geo_obj.solid_geometry.append(geom)
- # transfer the Cut Z and Vtip and VAngle values in case that we use the V-Shape tool in Gerber UI
- if self.ui.tool_type_radio.get_value() == 'v':
- new_cutz = self.ui.cutz_spinner.get_value()
- new_vtipdia = self.ui.tipdia_spinner.get_value()
- new_vtipangle = self.ui.tipangle_spinner.get_value()
- tool_type = 'V'
- else:
- new_cutz = self.app.defaults['geometry_cutz']
- new_vtipdia = self.app.defaults['geometry_vtipdia']
- new_vtipangle = self.app.defaults['geometry_vtipangle']
- tool_type = 'C1'
-
- # store here the default data for Geometry Data
- default_data = {}
- default_data.update({
- "name": iso_name,
- "plot": self.app.defaults['geometry_plot'],
- "cutz": new_cutz,
- "vtipdia": new_vtipdia,
- "vtipangle": new_vtipangle,
- "travelz": self.app.defaults['geometry_travelz'],
- "feedrate": self.app.defaults['geometry_feedrate'],
- "feedrate_z": self.app.defaults['geometry_feedrate_z'],
- "feedrate_rapid": self.app.defaults['geometry_feedrate_rapid'],
- "dwell": self.app.defaults['geometry_dwell'],
- "dwelltime": self.app.defaults['geometry_dwelltime'],
- "multidepth": self.app.defaults['geometry_multidepth'],
- "ppname_g": self.app.defaults['geometry_ppname_g'],
- "depthperpass": self.app.defaults['geometry_depthperpass'],
- "extracut": self.app.defaults['geometry_extracut'],
- "extracut_length": self.app.defaults['geometry_extracut_length'],
- "toolchange": self.app.defaults['geometry_toolchange'],
- "toolchangez": self.app.defaults['geometry_toolchangez'],
- "endz": self.app.defaults['geometry_endz'],
- "spindlespeed": self.app.defaults['geometry_spindlespeed'],
- "toolchangexy": self.app.defaults['geometry_toolchangexy'],
- "startz": self.app.defaults['geometry_startz']
- })
-
- geo_obj.tools = dict()
- geo_obj.tools['1'] = dict()
- geo_obj.tools.update({
- '1': {
- 'tooldia': float(self.options["isotooldia"]),
- 'offset': 'Path',
- 'offset_value': 0.0,
- 'type': _('Rough'),
- 'tool_type': tool_type,
- 'data': default_data,
- 'solid_geometry': geo_obj.solid_geometry
- }
- })
+ # update the geometry in the tools
+ geo_obj.tools['1']['solid_geometry'] = geo_obj.solid_geometry
# detect if solid_geometry is empty and this require list flattening which is "heavy"
# or just looking in the lists (they are one level depth) and if any is not empty
@@ -1415,8 +1418,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
if empty_cnt == len(geo_obj.solid_geometry):
raise ValidationError("Empty Geometry", None)
else:
- app_obj.inform.emit('[success] %s" %s' %
- (_("Isolation geometry created"), geo_obj.options["name"]))
+ app_obj.inform.emit('[success] %s" %s' % (_("Isolation geometry created"), geo_obj.options["name"]))
# even if combine is checked, one pass is still single-geo
geo_obj.multigeo = True if passes > 1 else False
@@ -1470,12 +1472,66 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
nr_passes=i)
if geom == 'fail':
- app_obj.inform.emit('[ERROR_NOTCL] %s' %
- _("Isolation geometry could not be generated."))
+ app_obj.inform.emit('[ERROR_NOTCL] %s' % _("Isolation geometry could not be generated."))
return 'fail'
geo_obj.solid_geometry = geom
+ # transfer the Cut Z and Vtip and VAngle values in case that we use the V-Shape tool in Gerber UI
+ # even if the resulting geometry is not multigeo we add the tools dict which will hold the data
+ # required to be transfered to the Geometry object
+ if self.ui.tool_type_radio.get_value() == 'v':
+ new_cutz = self.ui.cutz_spinner.get_value()
+ new_vtipdia = self.ui.tipdia_spinner.get_value()
+ new_vtipangle = self.ui.tipangle_spinner.get_value()
+ tool_type = 'V'
+ else:
+ new_cutz = self.app.defaults['geometry_cutz']
+ new_vtipdia = self.app.defaults['geometry_vtipdia']
+ new_vtipangle = self.app.defaults['geometry_vtipangle']
+ tool_type = 'C1'
+
+ # store here the default data for Geometry Data
+ default_data = {}
+ default_data.update({
+ "name": iso_name,
+ "plot": self.app.defaults['geometry_plot'],
+ "cutz": new_cutz,
+ "vtipdia": new_vtipdia,
+ "vtipangle": new_vtipangle,
+ "travelz": self.app.defaults['geometry_travelz'],
+ "feedrate": self.app.defaults['geometry_feedrate'],
+ "feedrate_z": self.app.defaults['geometry_feedrate_z'],
+ "feedrate_rapid": self.app.defaults['geometry_feedrate_rapid'],
+ "dwell": self.app.defaults['geometry_dwell'],
+ "dwelltime": self.app.defaults['geometry_dwelltime'],
+ "multidepth": self.app.defaults['geometry_multidepth'],
+ "ppname_g": self.app.defaults['geometry_ppname_g'],
+ "depthperpass": self.app.defaults['geometry_depthperpass'],
+ "extracut": self.app.defaults['geometry_extracut'],
+ "extracut_length": self.app.defaults['geometry_extracut_length'],
+ "toolchange": self.app.defaults['geometry_toolchange'],
+ "toolchangez": self.app.defaults['geometry_toolchangez'],
+ "endz": self.app.defaults['geometry_endz'],
+ "spindlespeed": self.app.defaults['geometry_spindlespeed'],
+ "toolchangexy": self.app.defaults['geometry_toolchangexy'],
+ "startz": self.app.defaults['geometry_startz']
+ })
+
+ geo_obj.tools = dict()
+ geo_obj.tools['1'] = dict()
+ geo_obj.tools.update({
+ '1': {
+ 'tooldia': float(self.options["isotooldia"]),
+ 'offset': 'Path',
+ 'offset_value': 0.0,
+ 'type': _('Rough'),
+ 'tool_type': tool_type,
+ 'data': default_data,
+ 'solid_geometry': geo_obj.solid_geometry
+ }
+ })
+
# detect if solid_geometry is empty and this require list flattening which is "heavy"
# or just looking in the lists (they are one level depth) and if any is not empty
# proceed with object creation, if there are empty and the number of them is the length
diff --git a/README.md b/README.md
index a324e0e9..dcec7b58 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+2.02.2020
+
+- fixed issue #376 where the V-Shape parameters from Gerber UI are not transfered to the resulting Geometry object if the 'combine' checkbox is not checked in the Gerber UI
+
31.01.2020
- added a new functionality, a variation of Set Origin named Move to Origin. It will move a selection of objects to origin such as the bottom left corner of the bounding box that fit them all is in origin.
From 1be1851ac7cb50b9e4bc016a8d617f3415daa18d Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 2 Feb 2020 05:53:03 +0200
Subject: [PATCH 066/209] - in Excellon UI, if Basic application mode is
selected in Preferences, the Plot column 'P' is hidden now because some
inexperienced users mistake this column checkboxes for tool selection
---
FlatCAMObj.py | 1 +
README.md | 1 +
2 files changed, 2 insertions(+)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 9e5dd15d..e9982564 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -2847,6 +2847,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.ui.level.setText('%s' % _('Basic'))
self.ui.tools_table.setColumnHidden(4, True)
+ self.ui.tools_table.setColumnHidden(5, True)
self.ui.estartz_label.hide()
self.ui.estartz_entry.hide()
self.ui.feedrate_rapid_label.hide()
diff --git a/README.md b/README.md
index dcec7b58..90b2adbe 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
2.02.2020
- fixed issue #376 where the V-Shape parameters from Gerber UI are not transfered to the resulting Geometry object if the 'combine' checkbox is not checked in the Gerber UI
+- in Excellon UI, if Basic application mode is selected in Preferences, the Plot column 'P' is hidden now because some inexperienced users mistake this column checkboxes for tool selection
31.01.2020
From c7074d71bafea4d83324ca6cf5316d269e129eb1 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 2 Feb 2020 15:54:09 +0200
Subject: [PATCH 067/209] - fixed an error in Gerber Parser; the initial values
for currnet_x, current_y were None but should have been 0.0 - limited the
lower limit of angle of V-tip to a value of 1 because 0 makes no sense
---
README.md | 2 ++
flatcamGUI/ObjectUI.py | 4 ++--
flatcamGUI/PreferencesUI.py | 6 +++---
flatcamParsers/ParseGerber.py | 8 ++++----
4 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/README.md b/README.md
index 90b2adbe..daf74c75 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,8 @@ CAD program, and create G-Code for Isolation routing.
- fixed issue #376 where the V-Shape parameters from Gerber UI are not transfered to the resulting Geometry object if the 'combine' checkbox is not checked in the Gerber UI
- in Excellon UI, if Basic application mode is selected in Preferences, the Plot column 'P' is hidden now because some inexperienced users mistake this column checkboxes for tool selection
+- fixed an error in Gerber Parser; the initial values for currnet_x, current_y were None but should have been 0.0
+- limited the lower limit of angle of V-tip to a value of 1 because 0 makes no sense
31.01.2020
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index 6270e332..0b5b251a 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -327,7 +327,7 @@ class GerberObjectUI(ObjectUI):
"In degree.")
)
self.tipangle_spinner = FCDoubleSpinner()
- self.tipangle_spinner.set_range(0, 180)
+ self.tipangle_spinner.set_range(1, 180)
self.tipangle_spinner.set_precision(self.decimals)
self.tipangle_spinner.setSingleStep(5)
self.tipangle_spinner.setWrapping(True)
@@ -1628,7 +1628,7 @@ class GeometryObjectUI(ObjectUI):
)
self.tipangle_entry = FCDoubleSpinner()
self.tipangle_entry.set_precision(self.decimals)
- self.tipangle_entry.set_range(0.0, 180.0)
+ self.tipangle_entry.set_range(1.0, 180.0)
self.tipangle_entry.setSingleStep(1)
self.grid3.addWidget(self.tipanglelabel, 2, 0)
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index 57b6b68d..be3e1e20 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -2235,7 +2235,7 @@ class GerberAdvOptPrefGroupUI(OptionsGroupUI):
"In degree.")
)
self.tipangle_spinner = FCSpinner()
- self.tipangle_spinner.set_range(0, 180)
+ self.tipangle_spinner.set_range(1, 180)
self.tipangle_spinner.setSingleStep(5)
self.tipangle_spinner.setWrapping(True)
grid0.addWidget(self.tipanglelabel, 5, 0)
@@ -5065,7 +5065,7 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
"In degree."))
self.tipangle_entry = FCDoubleSpinner()
self.tipangle_entry.set_precision(self.decimals)
- self.tipangle_entry.set_range(-360, 360)
+ self.tipangle_entry.set_range(1, 180)
self.tipangle_entry.setSingleStep(5)
self.tipangle_entry.setWrapping(True)
@@ -5615,7 +5615,7 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
"In degree."))
self.tipangle_entry = FCDoubleSpinner()
self.tipangle_entry.set_precision(self.decimals)
- self.tipangle_entry.set_range(0.0000, 180.0000)
+ self.tipangle_entry.set_range(1.0000, 180.0000)
self.tipangle_entry.setSingleStep(5)
self.tipangle_entry.setObjectName(_("V-Tip Angle"))
diff --git a/flatcamParsers/ParseGerber.py b/flatcamParsers/ParseGerber.py
index 16ce8f37..8acb3482 100644
--- a/flatcamParsers/ParseGerber.py
+++ b/flatcamParsers/ParseGerber.py
@@ -394,10 +394,10 @@ class Gerber(Geometry):
current_operation_code = None
# Current coordinates
- current_x = None
- current_y = None
- previous_x = None
- previous_y = None
+ current_x = 0
+ current_y = 0
+ previous_x = 0
+ previous_y = 0
current_d = None
From 31c0cd09522eaf13a9ec1c0d0f285793150084c0 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 3 Feb 2020 00:43:38 +0200
Subject: [PATCH 068/209] - small changes in Gerber UI - in Geometry Editor
make sure that after an edit is finished (correctly or forced) the QTree in
the Editor UI is cleared of items
---
README.md | 6 +++--
flatcamEditors/FlatCAMGeoEditor.py | 6 +++++
flatcamGUI/ObjectUI.py | 38 +++++++++++++-----------------
3 files changed, 26 insertions(+), 24 deletions(-)
diff --git a/README.md b/README.md
index daf74c75..e05d72fc 100644
--- a/README.md
+++ b/README.md
@@ -11,10 +11,12 @@ CAD program, and create G-Code for Isolation routing.
2.02.2020
-- fixed issue #376 where the V-Shape parameters from Gerber UI are not transfered to the resulting Geometry object if the 'combine' checkbox is not checked in the Gerber UI
+- fixed issue #376 where the V-Shape parameters from Gerber UI are not transferred to the resulting Geometry object if the 'combine' checkbox is not checked in the Gerber UI
- in Excellon UI, if Basic application mode is selected in Preferences, the Plot column 'P' is hidden now because some inexperienced users mistake this column checkboxes for tool selection
-- fixed an error in Gerber Parser; the initial values for currnet_x, current_y were None but should have been 0.0
+- fixed an error in Gerber Parser; the initial values for current_x, current_y were None but should have been 0.0
- limited the lower limit of angle of V-tip to a value of 1 because 0 makes no sense
+- small changes in Gerber UI
+- in Geometry Editor make sure that after an edit is finished (correctly or forced) the QTree in the Editor UI is cleared of items
31.01.2020
diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py
index 0bd67d36..604227b1 100644
--- a/flatcamEditors/FlatCAMGeoEditor.py
+++ b/flatcamEditors/FlatCAMGeoEditor.py
@@ -3627,6 +3627,12 @@ class FlatCAMGeoEditor(QtCore.QObject):
if self.fcgeometry:
self.fcgeometry.visible = True
+ # clear the Tree
+ self.tw.clear()
+ parent = self.tw.invisibleRootItem()
+ self.geo_parent = self.tw.addParent(
+ parent, _('Geometry Elements'), expanded=True, color=QtGui.QColor("#000000"), font=self.geo_font)
+
# hide the UI
self.geo_frame.hide()
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index 0b5b251a..67559194 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -160,8 +160,6 @@ class GerberObjectUI(ObjectUI):
ObjectUI.__init__(self, title=_('Gerber Object'), parent=parent, decimals=decimals)
self.decimals = decimals
- self.custom_box.addWidget(QtWidgets.QLabel(''))
-
# Plot options
grid0 = QtWidgets.QGridLayout()
grid0.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
@@ -169,20 +167,10 @@ class GerberObjectUI(ObjectUI):
grid0.setColumnStretch(0, 0)
grid0.setColumnStretch(1, 1)
- # Plot CB
- self.plot_cb = FCCheckBox()
- self.plot_cb.setToolTip(
- _("Plot (show) this object.")
- )
- plot_label = QtWidgets.QLabel('%s:' % _("Plot"))
-
- grid0.addWidget(plot_label, 0, 0)
- grid0.addWidget(self.plot_cb, 0, 1)
-
self.plot_options_label = QtWidgets.QLabel("%s:" % _("Plot Options"))
self.plot_options_label.setMinimumWidth(90)
- grid0.addWidget(self.plot_options_label, 1, 0)
+ grid0.addWidget(self.plot_options_label, 0, 0)
# Solid CB
self.solid_cb = FCCheckBox(label=_('Solid'))
@@ -190,7 +178,7 @@ class GerberObjectUI(ObjectUI):
_("Solid color polygons.")
)
self.solid_cb.setMinimumWidth(50)
- grid0.addWidget(self.solid_cb, 1, 1)
+ grid0.addWidget(self.solid_cb, 0, 1)
# Multicolored CB
self.multicolored_cb = FCCheckBox(label=_('Multi-Color'))
@@ -198,7 +186,14 @@ class GerberObjectUI(ObjectUI):
_("Draw polygons in different colors.")
)
self.multicolored_cb.setMinimumWidth(55)
- grid0.addWidget(self.multicolored_cb, 1, 2)
+ grid0.addWidget(self.multicolored_cb, 0, 2)
+
+ # Plot CB
+ self.plot_cb = FCCheckBox('%s' % _("Plot"))
+ # self.plot_cb.setLayoutDirection(QtCore.Qt.RightToLeft)
+ self.plot_cb.setToolTip(_("Plot (show) this object."))
+
+ grid0.addWidget(self.plot_cb, 1, 0, 1, 2)
# ## Object name
self.name_hlay = QtWidgets.QHBoxLayout()
@@ -526,7 +521,7 @@ class GerberObjectUI(ObjectUI):
"Clicking this will create the buffered geometry\n"
"required for isolation.")
)
- grid1.addWidget(self.create_buffer_button, 13, 0, 1, 2)
+ grid1.addWidget(self.create_buffer_button, 13, 0, 1, 3)
self.ohis_iso = OptionalHideInputSection(
self.except_cb,
@@ -534,7 +529,11 @@ class GerberObjectUI(ObjectUI):
logic=True
)
- grid1.addWidget(QtWidgets.QLabel(''), 14, 0)
+ separator_line2 = QtWidgets.QFrame()
+ separator_line2.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid1.addWidget(separator_line2, 14, 0, 1, 3)
+ # grid1.addWidget(QtWidgets.QLabel(''), 15, 0)
# ###########################################
# ########## NEW GRID #######################
@@ -681,11 +680,6 @@ class GerberObjectUI(ObjectUI):
grid2.addWidget(self.bbrounded_cb, 10, 0)
grid2.addWidget(self.generate_bb_button, 10, 1)
- separator_line2 = QtWidgets.QFrame()
- separator_line2.setFrameShape(QtWidgets.QFrame.HLine)
- separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid2.addWidget(separator_line2, 11, 0, 1, 2)
-
class ExcellonObjectUI(ObjectUI):
"""
From 10d4ed512b37a7d43cdcbcf387c754f478839faf Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 3 Feb 2020 02:18:28 +0200
Subject: [PATCH 069/209] - modified Spinbox and DoubleSpinbox Custom UI
elements such that they issue a warning status message when the typed value
is out of range
---
ObjectCollection.py | 2 +-
README.md | 4 +
flatcamGUI/GUIElements.py | 42 +++++++++-
flatcamGUI/ObjectUI.py | 162 ++++++++++++++++++++++----------------
4 files changed, 136 insertions(+), 74 deletions(-)
diff --git a/ObjectCollection.py b/ObjectCollection.py
index 799d163c..e0f0bd4c 100644
--- a/ObjectCollection.py
+++ b/ObjectCollection.py
@@ -504,7 +504,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
name += "_1"
obj.options["name"] = name
- obj.set_ui(obj.ui_type(decimals=self.app.decimals))
+ obj.set_ui(obj.ui_type(app=self.app))
# Required before appending (Qt MVC)
group = self.group_items[obj.kind]
diff --git a/README.md b/README.md
index e05d72fc..2ee1e479 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+3.02.2020
+
+- modified Spinbox and DoubleSpinbox Custom UI elements such that they issue a warning status message when the typed value is out of range
+
2.02.2020
- fixed issue #376 where the V-Shape parameters from Gerber UI are not transferred to the resulting Geometry object if the 'combine' checkbox is not checked in the Gerber UI
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index b9f17d9e..de4fd34f 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -575,12 +575,16 @@ class EvalEntry2(QtWidgets.QLineEdit):
class FCSpinner(QtWidgets.QSpinBox):
returnPressed = QtCore.pyqtSignal()
+ confirmation_signal = QtCore.pyqtSignal(bool, float, float)
- def __init__(self, suffix=None, alignment=None, parent=None):
+ def __init__(self, suffix=None, alignment=None, parent=None, callback=None):
super(FCSpinner, self).__init__(parent)
self.readyToEdit = True
self.editingFinished.connect(self.on_edit_finished)
+ if callback:
+ self.confirmation_signal.connect(callback)
+
self.lineEdit().installEventFilter(self)
if suffix:
@@ -650,6 +654,21 @@ class FCSpinner(QtWidgets.QSpinBox):
return
self.setValue(k)
+ def validate(self, p_str, p_int):
+ text = p_str
+
+ min_val = self.minimum()
+ max_val = self.maximum()
+ try:
+ if int(text) < min_val or int(text) > max_val:
+ self.confirmation_signal.emit(False, min_val, max_val)
+ return QtGui.QValidator.Intermediate, text, p_int
+ except ValueError:
+ pass
+
+ self.confirmation_signal.emit(True, min_val, max_val)
+ return QtGui.QValidator.Acceptable, p_str, p_int
+
def set_range(self, min_val, max_val):
self.setRange(min_val, max_val)
@@ -661,12 +680,23 @@ class FCSpinner(QtWidgets.QSpinBox):
class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
returnPressed = QtCore.pyqtSignal()
+ confirmation_signal = QtCore.pyqtSignal(bool, float, float)
- def __init__(self, suffix=None, alignment=None, parent=None):
+ def __init__(self, suffix=None, alignment=None, parent=None, callback=None):
+ """
+
+ :param suffix: a char added to the end of the value in the LineEdit; like a '%' or '$' etc
+ :param alignment: the value is aligned to left or right
+ :param parent:
+ :param callback: called when the entered value is outside limits; the min and max value will be passed to it
+ """
super(FCDoubleSpinner, self).__init__(parent)
self.readyToEdit = True
self.editingFinished.connect(self.on_edit_finished)
+ if callback:
+ self.confirmation_signal.connect(callback)
+
self.lineEdit().installEventFilter(self)
# by default don't allow the minus sign to be entered as the default for QDoubleSpinBox is the positive range
@@ -736,11 +766,17 @@ class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
def validate(self, p_str, p_int):
text = p_str.replace(',', '.')
+
+ min_val = self.minimum()
+ max_val = self.maximum()
try:
- if float(text) < self.minimum() or float(text) > self.maximum():
+ if float(text) < min_val or float(text) > max_val:
+ self.confirmation_signal.emit(False, min_val, max_val)
return QtGui.QValidator.Intermediate, text, p_int
except ValueError:
pass
+
+ self.confirmation_signal.emit(True, min_val, max_val)
return QtGui.QValidator.Acceptable, p_str, p_int
def get_value(self):
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index 67559194..63c747a4 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -35,11 +35,11 @@ class ObjectUI(QtWidgets.QWidget):
put UI elements in ObjectUI.custom_box (QtWidgets.QLayout).
"""
- def __init__(self, icon_file='share/flatcam_icon32.png', title=_('FlatCAM Object'), parent=None, common=True,
- decimals=4):
+ def __init__(self, app, icon_file='share/flatcam_icon32.png', title=_('FlatCAM Object'), parent=None, common=True):
QtWidgets.QWidget.__init__(self, parent=parent)
-
- self.decimals = decimals
+
+ self.app = app
+ self.decimals = app.decimals
theme_settings = QtCore.QSettings("Open Source", "FlatCAM")
if theme_settings.contains("theme"):
@@ -149,6 +149,20 @@ class ObjectUI(QtWidgets.QWidget):
self.common_grid.addWidget(self.offset_button, 4, 1)
layout.addStretch()
+
+ def confirmation_message(self, accepted, minval, maxval):
+ if accepted is False:
+ self.app.inform.emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' %
+ (_("Edited value is out of range"), self.decimals, minval, self.decimals, maxval))
+ else:
+ self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
+
+ def confirmation_message_int(self, accepted, minval, maxval):
+ if accepted is False:
+ self.app.inform.emit('[WARNING_NOTCL] %s: [%d, %d]' %
+ (_("Edited value is out of range"), minval, maxval))
+ else:
+ self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
class GerberObjectUI(ObjectUI):
@@ -156,9 +170,11 @@ class GerberObjectUI(ObjectUI):
User interface for Gerber objects.
"""
- def __init__(self, decimals, parent=None):
- ObjectUI.__init__(self, title=_('Gerber Object'), parent=parent, decimals=decimals)
- self.decimals = decimals
+ def __init__(self, app, parent=None):
+ self.decimals = app.decimals
+ self.app = app
+
+ ObjectUI.__init__(self, title=_('Gerber Object'), parent=parent, app=self.app)
# Plot options
grid0 = QtWidgets.QGridLayout()
@@ -307,7 +323,7 @@ class GerberObjectUI(ObjectUI):
self.tipdialabel.setToolTip(
_("The tip diameter for V-Shape Tool")
)
- self.tipdia_spinner = FCDoubleSpinner()
+ self.tipdia_spinner = FCDoubleSpinner(callback=self.confirmation_message)
self.tipdia_spinner.set_range(-99.9999, 99.9999)
self.tipdia_spinner.set_precision(self.decimals)
self.tipdia_spinner.setSingleStep(0.1)
@@ -321,7 +337,7 @@ class GerberObjectUI(ObjectUI):
_("The tip angle for V-Shape Tool.\n"
"In degree.")
)
- self.tipangle_spinner = FCDoubleSpinner()
+ self.tipangle_spinner = FCDoubleSpinner(callback=self.confirmation_message)
self.tipangle_spinner.set_range(1, 180)
self.tipangle_spinner.set_precision(self.decimals)
self.tipangle_spinner.setSingleStep(5)
@@ -335,7 +351,7 @@ class GerberObjectUI(ObjectUI):
_("Cutting depth (negative)\n"
"below the copper surface.")
)
- self.cutz_spinner = FCDoubleSpinner()
+ self.cutz_spinner = FCDoubleSpinner(callback=self.confirmation_message)
self.cutz_spinner.set_range(-9999.9999, 0.0000)
self.cutz_spinner.set_precision(self.decimals)
self.cutz_spinner.setSingleStep(0.1)
@@ -353,7 +369,7 @@ class GerberObjectUI(ObjectUI):
"this parameter.")
)
tdlabel.setMinimumWidth(90)
- self.iso_tool_dia_entry = FCDoubleSpinner()
+ self.iso_tool_dia_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.iso_tool_dia_entry.set_range(-9999.9999, 9999.9999)
self.iso_tool_dia_entry.set_precision(self.decimals)
self.iso_tool_dia_entry.setSingleStep(0.1)
@@ -368,7 +384,7 @@ class GerberObjectUI(ObjectUI):
"number (integer) of tool widths.")
)
passlabel.setMinimumWidth(90)
- self.iso_width_entry = FCSpinner()
+ self.iso_width_entry = FCSpinner(callback=self.confirmation_message_int)
self.iso_width_entry.set_range(1, 999)
grid1.addWidget(passlabel, 5, 0)
grid1.addWidget(self.iso_width_entry, 5, 1, 1, 2)
@@ -379,7 +395,7 @@ class GerberObjectUI(ObjectUI):
_("How much (percentage) of the tool width to overlap each tool pass.")
)
overlabel.setMinimumWidth(90)
- self.iso_overlap_entry = FCDoubleSpinner(suffix='%')
+ self.iso_overlap_entry = FCDoubleSpinner(suffix='%', callback=self.confirmation_message)
self.iso_overlap_entry.set_precision(self.decimals)
self.iso_overlap_entry.setWrapping(True)
self.iso_overlap_entry.set_range(0.0000, 99.9999)
@@ -617,7 +633,7 @@ class GerberObjectUI(ObjectUI):
"distance.")
)
bmlabel.setMinimumWidth(90)
- self.noncopper_margin_entry = FCDoubleSpinner()
+ self.noncopper_margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.noncopper_margin_entry.set_range(-9999.9999, 9999.9999)
self.noncopper_margin_entry.set_precision(self.decimals)
self.noncopper_margin_entry.setSingleStep(0.1)
@@ -656,7 +672,7 @@ class GerberObjectUI(ObjectUI):
"to the nearest polygon.")
)
bbmargin.setMinimumWidth(90)
- self.bbmargin_entry = FCDoubleSpinner()
+ self.bbmargin_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.bbmargin_entry.set_range(-9999.9999, 9999.9999)
self.bbmargin_entry.set_precision(self.decimals)
self.bbmargin_entry.setSingleStep(0.1)
@@ -686,7 +702,10 @@ class ExcellonObjectUI(ObjectUI):
User interface for Excellon objects.
"""
- def __init__(self, decimals, parent=None):
+ def __init__(self, app, parent=None):
+
+ self.decimals = app.decimals
+ self.app = app
theme_settings = QtCore.QSettings("Open Source", "FlatCAM")
if theme_settings.contains("theme"):
@@ -702,9 +721,7 @@ class ExcellonObjectUI(ObjectUI):
ObjectUI.__init__(self, title=_('Excellon Object'),
icon_file=self.resource_loc + '/drill32.png',
parent=parent,
- decimals=decimals)
-
- self.decimals = decimals
+ app=self.app)
# ### Plot options ####
hlay_plot = QtWidgets.QHBoxLayout()
@@ -870,7 +887,7 @@ class ExcellonObjectUI(ObjectUI):
_("The diameter of the tool who will do the milling")
)
- self.mill_dia_entry = FCDoubleSpinner()
+ self.mill_dia_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.mill_dia_entry.set_precision(self.decimals)
self.mill_dia_entry.set_range(0.0000, 9999.9999)
@@ -884,7 +901,7 @@ class ExcellonObjectUI(ObjectUI):
"below the copper surface.")
)
- self.cutz_entry = FCDoubleSpinner()
+ self.cutz_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.cutz_entry.set_precision(self.decimals)
if machinist_setting == 0:
@@ -908,7 +925,7 @@ class ExcellonObjectUI(ObjectUI):
)
)
- self.maxdepth_entry = FCDoubleSpinner()
+ self.maxdepth_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.maxdepth_entry.set_precision(self.decimals)
self.maxdepth_entry.set_range(0, 9999.9999)
self.maxdepth_entry.setSingleStep(0.1)
@@ -930,7 +947,7 @@ class ExcellonObjectUI(ObjectUI):
"across the XY plane.")
)
- self.travelz_entry = FCDoubleSpinner()
+ self.travelz_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.travelz_entry.set_precision(self.decimals)
if machinist_setting == 0:
@@ -950,7 +967,7 @@ class ExcellonObjectUI(ObjectUI):
"in G-Code (Pause for tool change).")
)
- self.toolchangez_entry = FCDoubleSpinner()
+ self.toolchangez_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.toolchangez_entry.set_precision(self.decimals)
self.toolchangez_entry.setToolTip(
_("Z-axis position (height) for\n"
@@ -984,7 +1001,7 @@ class ExcellonObjectUI(ObjectUI):
_("Height of the tool after\n"
"the last move at the end of the job.")
)
- self.eendz_entry = FCDoubleSpinner()
+ self.eendz_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.eendz_entry.set_precision(self.decimals)
if machinist_setting == 0:
@@ -1003,7 +1020,7 @@ class ExcellonObjectUI(ObjectUI):
_("Cutting speed in the XY\n"
"plane in units per minute")
)
- self.xyfeedrate_entry = FCDoubleSpinner()
+ self.xyfeedrate_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.xyfeedrate_entry.set_precision(self.decimals)
self.xyfeedrate_entry.set_range(0, 9999.9999)
self.xyfeedrate_entry.setSingleStep(0.1)
@@ -1019,7 +1036,7 @@ class ExcellonObjectUI(ObjectUI):
"So called 'Plunge' feedrate.\n"
"This is for linear move G01.")
)
- self.feedrate_entry = FCDoubleSpinner()
+ self.feedrate_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.feedrate_entry.set_precision(self.decimals)
self.feedrate_entry.set_range(0.0, 9999.9999)
self.feedrate_entry.setSingleStep(0.1)
@@ -1036,7 +1053,7 @@ class ExcellonObjectUI(ObjectUI):
"It is useful only for Marlin,\n"
"ignore for any other cases.")
)
- self.feedrate_rapid_entry = FCDoubleSpinner()
+ self.feedrate_rapid_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.feedrate_rapid_entry.set_precision(self.decimals)
self.feedrate_rapid_entry.set_range(0.0, 9999.9999)
self.feedrate_rapid_entry.setSingleStep(0.1)
@@ -1057,7 +1074,7 @@ class ExcellonObjectUI(ObjectUI):
"extended cut over the first cut section.")
)
- self.e_cut_entry = FCDoubleSpinner()
+ self.e_cut_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.e_cut_entry.set_range(0, 99999)
self.e_cut_entry.set_precision(self.decimals)
self.e_cut_entry.setSingleStep(0.1)
@@ -1081,7 +1098,7 @@ class ExcellonObjectUI(ObjectUI):
"in RPM (optional)")
)
- self.spindlespeed_entry = FCSpinner()
+ self.spindlespeed_entry = FCSpinner(callback=self.confirmation_message_int)
self.spindlespeed_entry.set_range(0, 1000000)
self.spindlespeed_entry.setSingleStep(100)
@@ -1094,7 +1111,7 @@ class ExcellonObjectUI(ObjectUI):
_("Pause to allow the spindle to reach its\n"
"speed before cutting.")
)
- self.dwelltime_entry = FCDoubleSpinner()
+ self.dwelltime_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.dwelltime_entry.set_precision(self.decimals)
self.dwelltime_entry.set_range(0.0, 9999.9999)
self.dwelltime_entry.setSingleStep(0.1)
@@ -1115,7 +1132,7 @@ class ExcellonObjectUI(ObjectUI):
"to probe. Negative value, in current units.")
)
- self.pdepth_entry = FCDoubleSpinner()
+ self.pdepth_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.pdepth_entry.set_precision(self.decimals)
self.pdepth_entry.set_range(-9999.9999, 9999.9999)
self.pdepth_entry.setSingleStep(0.1)
@@ -1132,7 +1149,7 @@ class ExcellonObjectUI(ObjectUI):
_("The feedrate used while the probe is probing.")
)
- self.feedrate_probe_entry = FCDoubleSpinner()
+ self.feedrate_probe_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.feedrate_probe_entry.set_precision(self.decimals)
self.feedrate_probe_entry.set_range(0.0, 9999.9999)
self.feedrate_probe_entry.setSingleStep(0.1)
@@ -1151,7 +1168,7 @@ class ExcellonObjectUI(ObjectUI):
"The value here can compensate the Cut Z parameter.")
)
- self.offset_entry = FCDoubleSpinner()
+ self.offset_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.offset_entry.set_precision(self.decimals)
self.offset_entry.set_range(-9999.9999, 9999.9999)
@@ -1291,7 +1308,7 @@ class ExcellonObjectUI(ObjectUI):
self.grid6.addWidget(self.tdlabel, 6, 0, 1, 3)
- self.tooldia_entry = FCDoubleSpinner()
+ self.tooldia_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.tooldia_entry.set_precision(self.decimals)
self.tooldia_entry.set_range(0.0, 9999.9999)
self.tooldia_entry.setSingleStep(0.1)
@@ -1311,7 +1328,7 @@ class ExcellonObjectUI(ObjectUI):
self.grid6.addWidget(self.tooldia_entry, 7, 0, 1, 2)
self.grid6.addWidget(self.generate_milling_button, 7, 2)
- self.slot_tooldia_entry = FCDoubleSpinner()
+ self.slot_tooldia_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.slot_tooldia_entry.set_precision(self.decimals)
self.slot_tooldia_entry.set_range(0.0, 9999.9999)
self.slot_tooldia_entry.setSingleStep(0.1)
@@ -1343,7 +1360,10 @@ class GeometryObjectUI(ObjectUI):
User interface for Geometry objects.
"""
- def __init__(self, decimals, parent=None):
+ def __init__(self, app, parent=None):
+
+ self.decimals = app.decimals
+ self.app = app
theme_settings = QtCore.QSettings("Open Source", "FlatCAM")
if theme_settings.contains("theme"):
@@ -1358,11 +1378,9 @@ class GeometryObjectUI(ObjectUI):
super(GeometryObjectUI, self).__init__(
title=_('Geometry Object'),
- icon_file=self.resource_loc + '/geometry32.png', parent=parent, decimals=decimals
+ icon_file=self.resource_loc + '/geometry32.png', parent=parent, app=self.app
)
- self.decimals = decimals
-
# Plot options
self.plot_options_label = QtWidgets.QLabel("%s:" % _("Plot Options"))
self.custom_box.addWidget(self.plot_options_label)
@@ -1492,7 +1510,7 @@ class GeometryObjectUI(ObjectUI):
"cut and negative for 'inside' cut."
)
)
- self.tool_offset_entry = FCDoubleSpinner()
+ self.tool_offset_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.tool_offset_entry.set_precision(self.decimals)
self.tool_offset_entry.set_range(-9999.9999, 9999.9999)
self.tool_offset_entry.setSingleStep(0.1)
@@ -1512,7 +1530,7 @@ class GeometryObjectUI(ObjectUI):
self.addtool_entry_lbl.setToolTip(
_("Diameter for the new tool")
)
- self.addtool_entry = FCDoubleSpinner()
+ self.addtool_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.addtool_entry.set_precision(self.decimals)
self.addtool_entry.set_range(0.00001, 9999.9999)
self.addtool_entry.setSingleStep(0.1)
@@ -1604,7 +1622,7 @@ class GeometryObjectUI(ObjectUI):
"The tip diameter for V-Shape Tool"
)
)
- self.tipdia_entry = FCDoubleSpinner()
+ self.tipdia_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.tipdia_entry.set_precision(self.decimals)
self.tipdia_entry.set_range(0.00001, 9999.9999)
self.tipdia_entry.setSingleStep(0.1)
@@ -1620,7 +1638,7 @@ class GeometryObjectUI(ObjectUI):
"In degree."
)
)
- self.tipangle_entry = FCDoubleSpinner()
+ self.tipangle_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.tipangle_entry.set_precision(self.decimals)
self.tipangle_entry.set_range(1.0, 180.0)
self.tipangle_entry.setSingleStep(1)
@@ -1636,7 +1654,7 @@ class GeometryObjectUI(ObjectUI):
"below the copper surface."
)
)
- self.cutz_entry = FCDoubleSpinner()
+ self.cutz_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.cutz_entry.set_precision(self.decimals)
if machinist_setting == 0:
@@ -1660,7 +1678,7 @@ class GeometryObjectUI(ObjectUI):
)
)
- self.maxdepth_entry = FCDoubleSpinner()
+ self.maxdepth_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.maxdepth_entry.set_precision(self.decimals)
self.maxdepth_entry.set_range(0, 9999.9999)
self.maxdepth_entry.setSingleStep(0.1)
@@ -1681,7 +1699,7 @@ class GeometryObjectUI(ObjectUI):
_("Height of the tool when\n"
"moving without cutting.")
)
- self.travelz_entry = FCDoubleSpinner()
+ self.travelz_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.travelz_entry.set_precision(self.decimals)
if machinist_setting == 0:
@@ -1702,7 +1720,7 @@ class GeometryObjectUI(ObjectUI):
"in the Machine Code (Pause for tool change)."
)
)
- self.toolchangez_entry = FCDoubleSpinner()
+ self.toolchangez_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.toolchangez_entry.set_precision(self.decimals)
self.toolchangez_entry.setToolTip(
_(
@@ -1739,7 +1757,7 @@ class GeometryObjectUI(ObjectUI):
_("Height of the tool after\n"
"the last move at the end of the job.")
)
- self.gendz_entry = FCDoubleSpinner()
+ self.gendz_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.gendz_entry.set_precision(self.decimals)
if machinist_setting == 0:
@@ -1758,7 +1776,7 @@ class GeometryObjectUI(ObjectUI):
_("Cutting speed in the XY\n"
"plane in units per minute")
)
- self.cncfeedrate_entry = FCDoubleSpinner()
+ self.cncfeedrate_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.cncfeedrate_entry.set_precision(self.decimals)
self.cncfeedrate_entry.set_range(0, 9999.9999)
self.cncfeedrate_entry.setSingleStep(0.1)
@@ -1773,7 +1791,7 @@ class GeometryObjectUI(ObjectUI):
"plane in units per minute.\n"
"It is called also Plunge.")
)
- self.cncplunge_entry = FCDoubleSpinner()
+ self.cncplunge_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.cncplunge_entry.set_precision(self.decimals)
self.cncplunge_entry.set_range(0, 9999.9999)
self.cncplunge_entry.setSingleStep(0.1)
@@ -1790,7 +1808,7 @@ class GeometryObjectUI(ObjectUI):
"It is useful only for Marlin,\n"
"ignore for any other cases.")
)
- self.cncfeedrate_rapid_entry = FCDoubleSpinner()
+ self.cncfeedrate_rapid_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.cncfeedrate_rapid_entry.set_precision(self.decimals)
self.cncfeedrate_rapid_entry.set_range(0, 9999.9999)
self.cncfeedrate_rapid_entry.setSingleStep(0.1)
@@ -1810,7 +1828,7 @@ class GeometryObjectUI(ObjectUI):
"extended cut over the first cut section.")
)
- self.e_cut_entry = FCDoubleSpinner()
+ self.e_cut_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.e_cut_entry.set_range(0, 99999)
self.e_cut_entry.set_precision(self.decimals)
self.e_cut_entry.setSingleStep(0.1)
@@ -1833,7 +1851,7 @@ class GeometryObjectUI(ObjectUI):
"this value is the power of laser."
)
)
- self.cncspindlespeed_entry = FCSpinner()
+ self.cncspindlespeed_entry = FCSpinner(callback=self.confirmation_message_int)
self.cncspindlespeed_entry.set_range(0, 1000000)
self.cncspindlespeed_entry.setSingleStep(100)
@@ -1848,7 +1866,7 @@ class GeometryObjectUI(ObjectUI):
"speed before cutting."
)
)
- self.dwelltime_entry = FCDoubleSpinner()
+ self.dwelltime_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.dwelltime_entry.set_precision(self.decimals)
self.dwelltime_entry.set_range(0, 9999.9999)
self.dwelltime_entry.setSingleStep(0.1)
@@ -1867,7 +1885,7 @@ class GeometryObjectUI(ObjectUI):
_("The maximum depth that the probe is allowed\n"
"to probe. Negative value, in current units.")
)
- self.pdepth_entry = FCDoubleSpinner()
+ self.pdepth_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.pdepth_entry.set_precision(self.decimals)
self.pdepth_entry.set_range(-9999.9999, 9999.9999)
self.pdepth_entry.setSingleStep(0.1)
@@ -1883,7 +1901,7 @@ class GeometryObjectUI(ObjectUI):
self.feedrate_probe_label.setToolTip(
_("The feedrate used while the probe is probing.")
)
- self.feedrate_probe_entry = FCDoubleSpinner()
+ self.feedrate_probe_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.feedrate_probe_entry.set_precision(self.decimals)
self.feedrate_probe_entry.set_range(0.0, 9999.9999)
self.feedrate_probe_entry.setSingleStep(0.1)
@@ -2010,12 +2028,15 @@ class CNCObjectUI(ObjectUI):
User interface for CNCJob objects.
"""
- def __init__(self, decimals, parent=None):
+ def __init__(self, app, parent=None):
"""
Creates the user interface for CNCJob objects. GUI elements should
be placed in ``self.custom_box`` to preserve the layout.
"""
+ self.decimals = app.decimals
+ self.app = app
+
theme_settings = QtCore.QSettings("Open Source", "FlatCAM")
if theme_settings.contains("theme"):
theme = theme_settings.value('theme', type=str)
@@ -2030,8 +2051,7 @@ class CNCObjectUI(ObjectUI):
ObjectUI.__init__(
self, title=_('CNC Job Object'),
icon_file=self.resource_loc + '/cnc32.png', parent=parent,
- decimals=decimals)
- self.decimals = decimals
+ app=self.app)
for i in range(0, self.common_grid.count()):
self.common_grid.itemAt(i).widget().hide()
@@ -2172,7 +2192,7 @@ class CNCObjectUI(ObjectUI):
_('P')])
self.exc_cnc_tools_table.setColumnHidden(4, True)
- self.tooldia_entry = FCDoubleSpinner()
+ self.tooldia_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.tooldia_entry.set_range(0, 9999.9999)
self.tooldia_entry.set_precision(self.decimals)
self.tooldia_entry.setSingleStep(0.1)
@@ -2341,12 +2361,15 @@ class ScriptObjectUI(ObjectUI):
User interface for Script objects.
"""
- def __init__(self, decimals, parent=None):
+ def __init__(self, app, parent=None):
"""
Creates the user interface for Script objects. GUI elements should
be placed in ``self.custom_box`` to preserve the layout.
"""
+ self.decimals = app.decimals
+ self.app = app
+
theme_settings = QtCore.QSettings("Open Source", "FlatCAM")
if theme_settings.contains("theme"):
theme = theme_settings.value('theme', type=str)
@@ -2362,9 +2385,7 @@ class ScriptObjectUI(ObjectUI):
icon_file=self.resource_loc + '/script_new24.png',
parent=parent,
common=False,
- decimals=decimals)
-
- self.decimals = decimals
+ app=self.app)
# ## Object name
self.name_hlay = QtWidgets.QHBoxLayout()
@@ -2407,12 +2428,15 @@ class DocumentObjectUI(ObjectUI):
User interface for Notes objects.
"""
- def __init__(self, decimals, parent=None):
+ def __init__(self, app, parent=None):
"""
Creates the user interface for Notes objects. GUI elements should
be placed in ``self.custom_box`` to preserve the layout.
"""
+ self.decimals = app.decimals
+ self.app = app
+
theme_settings = QtCore.QSettings("Open Source", "FlatCAM")
if theme_settings.contains("theme"):
theme = theme_settings.value('theme', type=str)
@@ -2428,9 +2452,7 @@ class DocumentObjectUI(ObjectUI):
icon_file=self.resource_loc + '/notes16_1.png',
parent=parent,
common=False,
- decimals=decimals)
-
- self.decimals = decimals
+ app=self.app)
# ## Object name
self.name_hlay = QtWidgets.QHBoxLayout()
@@ -2589,7 +2611,7 @@ class DocumentObjectUI(ObjectUI):
self.tab_size_label.setToolTip(
_("Set the tab size. In pixels. Default value is 80 pixels.")
)
- self.tab_size_spinner = FCSpinner()
+ self.tab_size_spinner = FCSpinner(callback=self.confirmation_message_int)
self.tab_size_spinner.set_range(0, 1000)
self.form_box.addRow(self.tab_size_label, self.tab_size_spinner)
From 23a1495c328122018445827abc216920dccff256 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 3 Feb 2020 14:46:39 +0200
Subject: [PATCH 070/209] - fixed the preprocessors with 'laser' in the name to
use the spindle direction set in the Preferences - increased the upper limit
for feedrates by an order of magnitude
---
README.md | 2 ++
camlib.py | 10 ++++++----
flatcamGUI/ObjectUI.py | 10 +++++-----
flatcamGUI/PreferencesUI.py | 22 +++++++++++-----------
flatcamTools/ToolSolderPaste.py | 18 +++++++++---------
preprocessors/default.py | 10 +++++-----
preprocessors/grbl_laser.py | 5 +++--
7 files changed, 41 insertions(+), 36 deletions(-)
diff --git a/README.md b/README.md
index 2ee1e479..e50d47be 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,8 @@ CAD program, and create G-Code for Isolation routing.
3.02.2020
- modified Spinbox and DoubleSpinbox Custom UI elements such that they issue a warning status message when the typed value is out of range
+- fixed the preprocessors with 'laser' in the name to use the spindle direction set in the Preferences
+- increased the upper limit for feedrates by an order of magnitude
2.02.2020
diff --git a/camlib.py b/camlib.py
index b51be9a8..9eaa8ab8 100644
--- a/camlib.py
+++ b/camlib.py
@@ -3105,7 +3105,9 @@ class CNCjob(Geometry):
:param feedrate_z:
:param feedrate_rapid:
:param spindlespeed:
- :param spindledir:
+ :param spindledir: Direction of rotation for the spindle. If using GRBL laser mode will
+ adjust the laser mode
+
:param dwell:
:param dwelltime:
:param multidepth: If True, use multiple passes to reach the desired depth.
@@ -4055,14 +4057,14 @@ class CNCjob(Geometry):
else:
command['Z'] = 0
- elif 'grbl_laser' in self.pp_excellon_name or 'grbl_laser' in self.pp_geometry_name or \
- (self.pp_solderpaste_name is not None and 'Paste' in self.pp_solderpaste_name):
+ elif 'laser' in self.pp_excellon_name.lower() or 'laser' in self.pp_geometry_name.lower() or \
+ (self.pp_solderpaste_name is not None and 'paste' in self.pp_solderpaste_name.lower()):
match_lsr = re.search(r"X([\+-]?\d+.[\+-]?\d+)\s*Y([\+-]?\d+.[\+-]?\d+)", gline)
if match_lsr:
command['X'] = float(match_lsr.group(1).replace(" ", ""))
command['Y'] = float(match_lsr.group(2).replace(" ", ""))
- match_lsr_pos = re.search(r"^(M0[3|5])", gline)
+ match_lsr_pos = re.search(r"^(M0[3-5])", gline)
if match_lsr_pos:
if 'M05' in match_lsr_pos.group(1):
# the value does not matter, only that it is positive so the gcode_parse() know it is > 0,
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index 63c747a4..ed9863ae 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -1038,7 +1038,7 @@ class ExcellonObjectUI(ObjectUI):
)
self.feedrate_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.feedrate_entry.set_precision(self.decimals)
- self.feedrate_entry.set_range(0.0, 9999.9999)
+ self.feedrate_entry.set_range(0.0, 99999.9999)
self.feedrate_entry.setSingleStep(0.1)
self.grid3.addWidget(frlabel, 14, 0)
@@ -1055,7 +1055,7 @@ class ExcellonObjectUI(ObjectUI):
)
self.feedrate_rapid_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.feedrate_rapid_entry.set_precision(self.decimals)
- self.feedrate_rapid_entry.set_range(0.0, 9999.9999)
+ self.feedrate_rapid_entry.set_range(0.0, 99999.9999)
self.feedrate_rapid_entry.setSingleStep(0.1)
self.grid3.addWidget(self.feedrate_rapid_label, 16, 0)
@@ -1778,7 +1778,7 @@ class GeometryObjectUI(ObjectUI):
)
self.cncfeedrate_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.cncfeedrate_entry.set_precision(self.decimals)
- self.cncfeedrate_entry.set_range(0, 9999.9999)
+ self.cncfeedrate_entry.set_range(0, 99999.9999)
self.cncfeedrate_entry.setSingleStep(0.1)
self.grid3.addWidget(frlabel, 10, 0)
@@ -1793,7 +1793,7 @@ class GeometryObjectUI(ObjectUI):
)
self.cncplunge_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.cncplunge_entry.set_precision(self.decimals)
- self.cncplunge_entry.set_range(0, 9999.9999)
+ self.cncplunge_entry.set_range(0, 99999.9999)
self.cncplunge_entry.setSingleStep(0.1)
self.grid3.addWidget(frzlabel, 11, 0)
@@ -1810,7 +1810,7 @@ class GeometryObjectUI(ObjectUI):
)
self.cncfeedrate_rapid_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.cncfeedrate_rapid_entry.set_precision(self.decimals)
- self.cncfeedrate_rapid_entry.set_range(0, 9999.9999)
+ self.cncfeedrate_rapid_entry.set_range(0, 99999.9999)
self.cncfeedrate_rapid_entry.setSingleStep(0.1)
self.grid3.addWidget(self.fr_rapidlabel, 12, 0)
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index be3e1e20..cde679cf 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -3154,7 +3154,7 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
)
self.feedrate_entry = FCDoubleSpinner()
self.feedrate_entry.set_precision(self.decimals)
- self.feedrate_entry.set_range(0, 999)
+ self.feedrate_entry.set_range(0, 99999.9999)
grid2.addWidget(frlabel, 5, 0)
grid2.addWidget(self.feedrate_entry, 5, 1)
@@ -3316,7 +3316,7 @@ class ExcellonAdvOptPrefGroupUI(OptionsGroupUI):
)
self.feedrate_rapid_entry = FCDoubleSpinner()
self.feedrate_rapid_entry.set_precision(self.decimals)
- self.feedrate_rapid_entry.set_range(0, 9999999.9999)
+ self.feedrate_rapid_entry.set_range(0, 99999.9999)
grid1.addWidget(fr_rapid_label, 3, 0)
grid1.addWidget(self.feedrate_rapid_entry, 3, 1)
@@ -3341,7 +3341,7 @@ class ExcellonAdvOptPrefGroupUI(OptionsGroupUI):
)
self.feedrate_probe_entry = FCDoubleSpinner()
self.feedrate_probe_entry.set_precision(self.decimals)
- self.feedrate_probe_entry.set_range(0, 9999999.9999)
+ self.feedrate_probe_entry.set_range(0, 99999.9999)
grid1.addWidget(self.feedrate_probe_label, 5, 0)
grid1.addWidget(self.feedrate_probe_entry, 5, 1)
@@ -4081,7 +4081,7 @@ class GeometryOptPrefGroupUI(OptionsGroupUI):
"plane in units per minute")
)
self.cncfeedrate_entry = FCDoubleSpinner()
- self.cncfeedrate_entry.set_range(0, 99999)
+ self.cncfeedrate_entry.set_range(0, 99999.9999)
self.cncfeedrate_entry.set_precision(self.decimals)
self.cncfeedrate_entry.setSingleStep(0.1)
self.cncfeedrate_entry.setWrapping(True)
@@ -4097,7 +4097,7 @@ class GeometryOptPrefGroupUI(OptionsGroupUI):
"It is called also Plunge.")
)
self.cncplunge_entry = FCDoubleSpinner()
- self.cncplunge_entry.set_range(0, 99999)
+ self.cncplunge_entry.set_range(0, 99999.9999)
self.cncplunge_entry.set_precision(self.decimals)
self.cncplunge_entry.setSingleStep(0.1)
self.cncplunge_entry.setWrapping(True)
@@ -4208,7 +4208,7 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
"ignore for any other cases.")
)
self.cncfeedrate_rapid_entry = FCDoubleSpinner()
- self.cncfeedrate_rapid_entry.set_range(0, 99999)
+ self.cncfeedrate_rapid_entry.set_range(0, 99999.9999)
self.cncfeedrate_rapid_entry.set_precision(self.decimals)
self.cncfeedrate_rapid_entry.setSingleStep(0.1)
self.cncfeedrate_rapid_entry.setWrapping(True)
@@ -4260,7 +4260,7 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
_("The feedrate used while the probe is probing.")
)
self.feedrate_probe_entry = FCDoubleSpinner()
- self.feedrate_probe_entry.set_range(0, 99999)
+ self.feedrate_probe_entry.set_range(0, 99999.9999)
self.feedrate_probe_entry.set_precision(self.decimals)
self.feedrate_probe_entry.setSingleStep(0.1)
self.feedrate_probe_entry.setWrapping(True)
@@ -6709,7 +6709,7 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
# Feedrate X-Y
self.frxy_entry = FCDoubleSpinner()
self.frxy_entry.set_precision(self.decimals)
- self.frxy_entry.set_range(0.0000001, 9999.9999)
+ self.frxy_entry.set_range(0.0000001, 99999.9999)
self.frxy_entry.setSingleStep(0.1)
self.frxy_label = QtWidgets.QLabel('%s:' % _("Feedrate X-Y"))
@@ -6722,7 +6722,7 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
# Feedrate Z
self.frz_entry = FCDoubleSpinner()
self.frz_entry.set_precision(self.decimals)
- self.frz_entry.set_range(0.0000001, 9999.9999)
+ self.frz_entry.set_range(0.0000001, 99999.9999)
self.frz_entry.setSingleStep(0.1)
self.frz_label = QtWidgets.QLabel('%s:' % _("Feedrate Z"))
@@ -6736,7 +6736,7 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
# Feedrate Z Dispense
self.frz_dispense_entry = FCDoubleSpinner()
self.frz_dispense_entry.set_precision(self.decimals)
- self.frz_dispense_entry.set_range(0.0000001, 9999.9999)
+ self.frz_dispense_entry.set_range(0.0000001, 99999.9999)
self.frz_dispense_entry.setSingleStep(0.1)
self.frz_dispense_label = QtWidgets.QLabel('%s:' % _("Feedrate Z Dispense"))
@@ -6749,7 +6749,7 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
# Spindle Speed Forward
self.speedfwd_entry = FCSpinner()
- self.speedfwd_entry.set_range(0, 999999)
+ self.speedfwd_entry.set_range(0, 99999)
self.speedfwd_entry.setSingleStep(1000)
self.speedfwd_label = QtWidgets.QLabel('%s:' % _("Spindle Speed FWD"))
diff --git a/flatcamTools/ToolSolderPaste.py b/flatcamTools/ToolSolderPaste.py
index c2393bd2..af227bd3 100644
--- a/flatcamTools/ToolSolderPaste.py
+++ b/flatcamTools/ToolSolderPaste.py
@@ -245,7 +245,7 @@ class SolderPaste(FlatCAMTool):
# Feedrate X-Y
self.frxy_entry = FCDoubleSpinner()
- self.frxy_entry.set_range(0.0000001, 9999.9999)
+ self.frxy_entry.set_range(0.0000, 99999.9999)
self.frxy_entry.set_precision(self.decimals)
self.frxy_entry.setSingleStep(0.1)
@@ -257,7 +257,7 @@ class SolderPaste(FlatCAMTool):
# Feedrate Z
self.frz_entry = FCDoubleSpinner()
- self.frz_entry.set_range(0.0000001, 9999.9999)
+ self.frz_entry.set_range(0.0000, 99999.9999)
self.frz_entry.set_precision(self.decimals)
self.frz_entry.setSingleStep(0.1)
@@ -270,7 +270,7 @@ class SolderPaste(FlatCAMTool):
# Feedrate Z Dispense
self.frz_dispense_entry = FCDoubleSpinner()
- self.frz_dispense_entry.set_range(0.0000001, 9999.9999)
+ self.frz_dispense_entry.set_range(0.0000, 99999.9999)
self.frz_dispense_entry.set_precision(self.decimals)
self.frz_dispense_entry.setSingleStep(0.1)
@@ -491,6 +491,8 @@ class SolderPaste(FlatCAMTool):
self.units = ''
self.name = ""
+ self.obj = None
+
self.text_editor_tab = None
# this will be used in the combobox context menu, for delete entry
@@ -652,10 +654,10 @@ class SolderPaste(FlatCAMTool):
for tooluid_key, tooluid_value in self.tooltable_tools.items():
if float('%.*f' % (self.decimals, tooluid_value['tooldia'])) == tool_sorted:
tool_id += 1
- id = QtWidgets.QTableWidgetItem('%d' % int(tool_id))
- id.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
+ id_item = QtWidgets.QTableWidgetItem('%d' % int(tool_id))
+ id_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
row_no = tool_id - 1
- self.tools_table.setItem(row_no, 0, id) # Tool name/id
+ self.tools_table.setItem(row_no, 0, id_item) # Tool name/id
# Make sure that the drill diameter when in MM is with no more than 2 decimals
# There are no drill bits in MM with more than 2 decimals diameter
@@ -1295,7 +1297,7 @@ class SolderPaste(FlatCAMTool):
if obj.tools[tooluid_key]['solid_geometry'] is None:
a += 1
if a == len(obj.tools):
- self.app.inform.emit('[ERROR_NOTCL] %s...' % _('Cancelled. Empty file, it has no geometry'))
+ self.app.inform.emit('[ERROR_NOTCL] %s...' % _('Cancelled. Empty file, it has no geometry'))
return 'fail'
# use the name of the first tool selected in self.geo_tools_table which has the diameter passed as tool_dia
@@ -1334,8 +1336,6 @@ class SolderPaste(FlatCAMTool):
assert isinstance(job_obj, FlatCAMCNCjob), \
"Initializer expected a FlatCAMCNCjob, got %s" % type(job_obj)
- tool_cnc_dict = {}
-
# this turn on the FlatCAMCNCJob plot for multiple tools
job_obj.multitool = True
job_obj.multigeo = True
diff --git a/preprocessors/default.py b/preprocessors/default.py
index d1ddf6ad..e57ed812 100644
--- a/preprocessors/default.py
+++ b/preprocessors/default.py
@@ -117,11 +117,11 @@ M6
M0
G00 Z{z_toolchange}
""".format(x_toolchange=self.coordinate_format % (p.coords_decimals, x_toolchange),
- y_toolchange=self.coordinate_format % (p.coords_decimals, y_toolchange),
- z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
- tool=int(p.tool),
- t_drills=no_drills,
- toolC=toolC_formatted)
+ y_toolchange=self.coordinate_format % (p.coords_decimals, y_toolchange),
+ z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
+ tool=int(p.tool),
+ t_drills=no_drills,
+ toolC=toolC_formatted)
else:
gcode = """
M5
diff --git a/preprocessors/grbl_laser.py b/preprocessors/grbl_laser.py
index a95708ca..e975a703 100644
--- a/preprocessors/grbl_laser.py
+++ b/preprocessors/grbl_laser.py
@@ -54,10 +54,11 @@ class grbl_laser(FlatCAMPostProc):
return 'M05 S0'
def down_code(self, p):
+ sdir = {'CW': 'M03', 'CCW': 'M04'}[p.spindledir]
if p.spindlespeed:
- return 'M03 S%d' % p.spindlespeed
+ return '%s S%s' % (sdir, str(p.spindlespeed))
else:
- return 'M03'
+ return sdir
def toolchange_code(self, p):
return ''
From 7424bb917ca2f42f0b2d6c0b7b50bd34ccbbb332 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 6 Feb 2020 01:39:19 +0200
Subject: [PATCH 071/209] - Modified the Distance Tool such that the Measure
button can't be clicked while measuring is in progress - optimized selection
of drills in the Excellon Editor - fixed bugs in multiple selection in
Excellon Editor - fixed selection problems in Gerber Editor - in Distance
Tool, when run in the Excellon or Gerber Editor, added a new option to snap
to center of the geometry (drill for Excellon, pad for Gerber)
---
FlatCAMApp.py | 3 +
README.md | 8 +
flatcamEditors/FlatCAMExcEditor.py | 62 +++---
flatcamEditors/FlatCAMGrbEditor.py | 53 ++---
flatcamTools/ToolDistance.py | 300 +++++++++++++++++++++--------
5 files changed, 298 insertions(+), 128 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index b6a695ae..3f0d9086 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -890,6 +890,9 @@ class App(QtCore.QObject):
# Subtract Tool
"tools_sub_close_paths": True,
+ # Distance Tool
+ "tools_dist_snap_center": False,
+
# ###################################################################################
# ################################ TOOLS 2 ##########################################
# ###################################################################################
diff --git a/README.md b/README.md
index e50d47be..2728cc8b 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,14 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+5.02.2020
+
+- Modified the Distance Tool such that the Measure button can't be clicked while measuring is in progress
+- optimized selection of drills in the Excellon Editor
+- fixed bugs in multiple selection in Excellon Editor
+- fixed selection problems in Gerber Editor
+- in Distance Tool, when run in the Excellon or Gerber Editor, added a new option to snap to center of the geometry (drill for Excellon, pad for Gerber)
+
3.02.2020
- modified Spinbox and DoubleSpinbox Custom UI elements such that they issue a warning status message when the typed value is out of range
diff --git a/flatcamEditors/FlatCAMExcEditor.py b/flatcamEditors/FlatCAMExcEditor.py
index e2dc8bdb..a4136d3c 100644
--- a/flatcamEditors/FlatCAMExcEditor.py
+++ b/flatcamEditors/FlatCAMExcEditor.py
@@ -1334,8 +1334,8 @@ class FCDrillCopy(FCDrillMove):
class FCDrillSelect(DrawTool):
- def __init__(self, exc_editor_app):
- DrawTool.__init__(self, exc_editor_app)
+ def __init__(self, draw_app):
+ DrawTool.__init__(self, draw_app)
self.name = 'drill_select'
try:
@@ -1343,7 +1343,7 @@ class FCDrillSelect(DrawTool):
except Exception as e:
pass
- self.exc_editor_app = exc_editor_app
+ self.exc_editor_app = draw_app
self.storage = self.exc_editor_app.storage_dict
# self.selected = self.exc_editor_app.selected
@@ -1368,10 +1368,10 @@ class FCDrillSelect(DrawTool):
else:
mod_key = None
- if mod_key == self.draw_app.app.defaults["global_mselect_key"]:
+ if mod_key == self.exc_editor_app.app.defaults["global_mselect_key"]:
pass
else:
- self.exc_editor_app.selected = []
+ self.exc_editor_app.selected = list()
def click_release(self, pos):
self.exc_editor_app.tools_table_exc.clearSelection()
@@ -1379,8 +1379,10 @@ class FCDrillSelect(DrawTool):
try:
for storage in self.exc_editor_app.storage_dict:
- for sh in self.exc_editor_app.storage_dict[storage].get_objects():
- self.sel_storage.insert(sh)
+ # for sh in self.exc_editor_app.storage_dict[storage].get_objects():
+ # self.sel_storage.insert(sh)
+ _, st_closest_shape = self.exc_editor_app.storage_dict[storage].nearest(pos)
+ self.sel_storage.insert(st_closest_shape)
_, closest_shape = self.sel_storage.nearest(pos)
@@ -1417,37 +1419,41 @@ class FCDrillSelect(DrawTool):
else:
mod_key = None
- if mod_key == self.draw_app.app.defaults["global_mselect_key"]:
+ if mod_key == self.exc_editor_app.app.defaults["global_mselect_key"]:
if closest_shape in self.exc_editor_app.selected:
self.exc_editor_app.selected.remove(closest_shape)
else:
self.exc_editor_app.selected.append(closest_shape)
else:
- self.draw_app.selected = []
- self.draw_app.selected.append(closest_shape)
+ self.exc_editor_app.selected = list()
+ self.exc_editor_app.selected.append(closest_shape)
# select the diameter of the selected shape in the tool table
try:
- self.draw_app.tools_table_exc.cellPressed.disconnect()
+ self.exc_editor_app.tools_table_exc.cellPressed.disconnect()
except (TypeError, AttributeError):
pass
- self.exc_editor_app.tools_table_exc.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
+ # if mod_key == self.exc_editor_app.app.defaults["global_mselect_key"]:
+ # self.exc_editor_app.tools_table_exc.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
+ self.sel_tools.clear()
+
for shape_s in self.exc_editor_app.selected:
for storage in self.exc_editor_app.storage_dict:
if shape_s in self.exc_editor_app.storage_dict[storage].get_objects():
self.sel_tools.add(storage)
+ self.exc_editor_app.tools_table_exc.clearSelection()
for storage in self.sel_tools:
- for k, v in self.draw_app.tool2tooldia.items():
+ for k, v in self.exc_editor_app.tool2tooldia.items():
if v == storage:
self.exc_editor_app.tools_table_exc.selectRow(int(k) - 1)
- self.draw_app.last_tool_selected = int(k)
+ self.exc_editor_app.last_tool_selected = int(k)
break
- self.exc_editor_app.tools_table_exc.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
+ # self.exc_editor_app.tools_table_exc.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
- self.draw_app.tools_table_exc.cellPressed.connect(self.draw_app.on_row_selected)
+ self.exc_editor_app.tools_table_exc.cellPressed.connect(self.exc_editor_app.on_row_selected)
# delete whatever is in selection storage, there is no longer need for those shapes
self.sel_storage = FlatCAMExcEditor.make_storage()
@@ -2054,32 +2060,32 @@ class FlatCAMExcEditor(QtCore.QObject):
self.in_action = False
- self.storage_dict = {}
+ self.storage_dict = dict()
- self.current_storage = []
+ self.current_storage = list()
# build the data from the Excellon point into a dictionary
# {tool_dia: [geometry_in_points]}
- self.points_edit = {}
- self.slot_points_edit = {}
+ self.points_edit = dict()
+ self.slot_points_edit = dict()
- self.sorted_diameters = []
+ self.sorted_diameters = list()
- self.new_drills = []
- self.new_tools = {}
- self.new_slots = []
- self.new_tool_offset = {}
+ self.new_drills = list()
+ self.new_tools = dict()
+ self.new_slots = list()
+ self.new_tool_offset = dict()
# dictionary to store the tool_row and diameters in Tool_table
# it will be updated everytime self.build_ui() is called
- self.olddia_newdia = {}
+ self.olddia_newdia = dict()
- self.tool2tooldia = {}
+ self.tool2tooldia = dict()
# this will store the value for the last selected tool, for use after clicking on canvas when the selection
# is cleared but as a side effect also the selected tool is cleared
self.last_tool_selected = None
- self.utility = []
+ self.utility = list()
# this will flag if the Editor "tools" are launched from key shortcuts (True) or from menu toolbar (False)
self.launched_from_shortcuts = False
diff --git a/flatcamEditors/FlatCAMGrbEditor.py b/flatcamEditors/FlatCAMGrbEditor.py
index 2bd6a8bb..e1006725 100644
--- a/flatcamEditors/FlatCAMGrbEditor.py
+++ b/flatcamEditors/FlatCAMGrbEditor.py
@@ -2300,10 +2300,10 @@ class FCApertureSelect(DrawTool):
# since FCApertureSelect tool is activated whenever a tool is exited I place here the reinitialization of the
# bending modes using in FCRegion and FCTrack
- self.draw_app.bend_mode = 1
+ self.grb_editor_app.bend_mode = 1
# here store the selected apertures
- self.sel_aperture = set()
+ self.sel_aperture = list()
try:
self.grb_editor_app.apertures_table.clearSelection()
@@ -2332,7 +2332,7 @@ class FCApertureSelect(DrawTool):
else:
mod_key = None
- if mod_key == self.draw_app.app.defaults["global_mselect_key"]:
+ if mod_key == self.grb_editor_app.app.defaults["global_mselect_key"]:
pass
else:
self.grb_editor_app.selected = []
@@ -2348,46 +2348,53 @@ class FCApertureSelect(DrawTool):
else:
mod_key = None
+ if mod_key != self.grb_editor_app.app.defaults["global_mselect_key"]:
+ self.grb_editor_app.selected.clear()
+ self.sel_aperture.clear()
+
for storage in self.grb_editor_app.storage_dict:
try:
- for geo_el in self.grb_editor_app.storage_dict[storage]['geometry']:
- if 'solid' in geo_el.geo:
- geometric_data = geo_el.geo['solid']
+ for shape_stored in self.grb_editor_app.storage_dict[storage]['geometry']:
+ if 'solid' in shape_stored.geo:
+ geometric_data = shape_stored.geo['solid']
if Point(point).within(geometric_data):
- if mod_key == self.grb_editor_app.app.defaults["global_mselect_key"]:
- if geo_el in self.draw_app.selected:
- self.draw_app.selected.remove(geo_el)
- self.sel_aperture.remove(storage)
- else:
- # add the object to the selected shapes
- self.draw_app.selected.append(geo_el)
- self.sel_aperture.add(storage)
+ if shape_stored in self.grb_editor_app.selected:
+ self.grb_editor_app.selected.remove(shape_stored)
else:
- self.draw_app.selected.append(geo_el)
- self.sel_aperture.add(storage)
+ # add the object to the selected shapes
+ self.grb_editor_app.selected.append(shape_stored)
except KeyError:
pass
# select the aperture in the Apertures Table that is associated with the selected shape
+ self.sel_aperture.clear()
+
+ self.grb_editor_app.apertures_table.clearSelection()
try:
- self.draw_app.apertures_table.cellPressed.disconnect()
+ self.grb_editor_app.apertures_table.cellPressed.disconnect()
except Exception as e:
log.debug("FlatCAMGrbEditor.FCApertureSelect.click_release() --> %s" % str(e))
- self.grb_editor_app.apertures_table.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
+ for shape_s in self.grb_editor_app.selected:
+ for storage in self.grb_editor_app.storage_dict:
+ if shape_s in self.grb_editor_app.storage_dict[storage]['geometry']:
+ self.sel_aperture.append(storage)
+
+ # self.grb_editor_app.apertures_table.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
for aper in self.sel_aperture:
for row in range(self.grb_editor_app.apertures_table.rowCount()):
if str(aper) == self.grb_editor_app.apertures_table.item(row, 1).text():
- self.grb_editor_app.apertures_table.selectRow(row)
- self.draw_app.last_aperture_selected = aper
- self.grb_editor_app.apertures_table.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
+ if not self.grb_editor_app.apertures_table.item(row, 0).isSelected():
+ self.grb_editor_app.apertures_table.selectRow(row)
+ self.grb_editor_app.last_aperture_selected = aper
+ # self.grb_editor_app.apertures_table.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
- self.draw_app.apertures_table.cellPressed.connect(self.draw_app.on_row_selected)
+ self.grb_editor_app.apertures_table.cellPressed.connect(self.grb_editor_app.on_row_selected)
return ""
def clean_up(self):
- self.draw_app.plot_all()
+ self.grb_editor_app.plot_all()
class FCTransform(FCShapeTool):
diff --git a/flatcamTools/ToolDistance.py b/flatcamTools/ToolDistance.py
index 1a5bc568..84a6c547 100644
--- a/flatcamTools/ToolDistance.py
+++ b/flatcamTools/ToolDistance.py
@@ -9,13 +9,18 @@ from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool
from flatcamGUI.VisPyVisuals import *
-from flatcamGUI.GUIElements import FCEntry
+from flatcamGUI.GUIElements import FCEntry, FCButton, FCCheckBox
+
+from shapely.geometry import Point, MultiLineString, Polygon
+
+import FlatCAMTranslation as fcTranslate
+from camlib import FlatCAMRTreeStorage
+from flatcamEditors.FlatCAMGeoEditor import DrawToolShape
from copy import copy
import math
import logging
import gettext
-import FlatCAMTranslation as fcTranslate
import builtins
fcTranslate.apply_language('strings')
@@ -43,82 +48,101 @@ class Distance(FlatCAMTool):
self.layout.addWidget(title_label)
# ## Form Layout
- form_layout = QtWidgets.QFormLayout()
- self.layout.addLayout(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.stop_label = QtWidgets.QLabel("%s:" % _('Stop Coords'))
- self.stop_label.setToolTip(_("This is the measuring Stop point coordinates."))
-
- self.distance_x_label = QtWidgets.QLabel('%s:' % _("Dx"))
- self.distance_x_label.setToolTip(_("This is the distance measured over the X axis."))
-
- self.distance_y_label = QtWidgets.QLabel('%s:' % _("Dy"))
- self.distance_y_label.setToolTip(_("This is the distance measured over the Y axis."))
-
- self.angle_label = QtWidgets.QLabel('%s:' % _("Angle"))
- self.angle_label.setToolTip(_("This is orientation angle of the measuring line."))
-
- self.total_distance_label = QtWidgets.QLabel("%s:" % _('DISTANCE'))
- self.total_distance_label.setToolTip(_("This is the point to point Euclidian distance."))
-
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."))
- self.measure_btn = QtWidgets.QPushButton(_("Measure"))
+ 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)
- form_layout.addRow(self.units_label, self.units_value)
- form_layout.addRow(self.start_label, self.start_entry)
- form_layout.addRow(self.stop_label, self.stop_entry)
- form_layout.addRow(self.distance_x_label, self.distance_x_entry)
- form_layout.addRow(self.distance_y_label, self.distance_y_entry)
- form_layout.addRow(self.angle_label, self.angle_entry)
- form_layout.addRow(self.total_distance_label, self.total_distance_entry)
-
- # 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.layout.addStretch()
# store here the first click and second click of the measurement process
@@ -137,6 +161,15 @@ class Distance(FlatCAMTool):
self.mm = None
self.mr = None
+ # monitor if the tool was used
+ self.tool_done = False
+
+ # store the grid status here
+ self.grid_status_memory = False
+
+ # store here if the snap button was clicked
+ self.snap_toggled = None
+
# VisPy visuals
if self.app.is_legacy is False:
self.sel_shapes = ShapeCollection(parent=self.app.plotcanvas.view.scene, layers=1)
@@ -145,6 +178,7 @@ class Distance(FlatCAMTool):
self.sel_shapes = ShapeCollectionLegacy(obj=self, app=self.app, name='measurement')
self.measure_btn.clicked.connect(self.activate_measure_tool)
+ self.snap_center_cb.toggled.connect(self.on_snap_toggled)
def run(self, toggle=False):
self.app.report_usage("ToolDistance()")
@@ -154,6 +188,8 @@ class Distance(FlatCAMTool):
self.rel_point1 = None
self.rel_point2 = None
+ self.tool_done = False
+
if self.app.tool_tab_locked is True:
return
@@ -177,7 +213,7 @@ class Distance(FlatCAMTool):
# Remove anything else in the GUI
self.app.ui.tool_scroll_area.takeWidget()
- # Put ourself in the GUI
+ # Put ourselves in the GUI
self.app.ui.tool_scroll_area.setWidget(self)
# Switch notebook to tool page
@@ -195,20 +231,45 @@ class Distance(FlatCAMTool):
self.angle_entry.set_value('0.0')
self.total_distance_entry.set_value('0.0')
+ self.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()
+ else:
+ self.snap_center_cb.hide()
+
# this is a hack; seems that triggering the grid will make the visuals better
# trigger it twice to return to the original state
self.app.ui.grid_snap_btn.trigger()
self.app.ui.grid_snap_btn.trigger()
+ if self.app.ui.grid_snap_btn.isChecked():
+ self.grid_status_memory = True
+
log.debug("Distance Tool --> tool initialized")
+ def on_snap_toggled(self, state):
+ self.app.defaults['tools_dist_snap_center'] = state
+ if state:
+ # disengage the grid snapping since it will be hard to find the drills or pads on grid
+ if self.app.ui.grid_snap_btn.isChecked():
+ self.app.ui.grid_snap_btn.trigger()
+
def activate_measure_tool(self):
# ENABLE the Measuring TOOL
self.active = True
+ # disable the measuring button
+ self.measure_btn.setDisabled(True)
+ self.measure_btn.setText('%s...' % _("Working"))
+
self.clicked_meas = 0
self.original_call_source = copy(self.app.call_source)
+ snap_center = self.app.defaults['tools_dist_snap_center']
+ self.on_snap_toggled(snap_center)
+
self.app.inform.emit(_("MEASURING: Click on the Start point ..."))
self.units = self.app.defaults['units'].lower()
@@ -267,6 +328,10 @@ class Distance(FlatCAMTool):
self.active = False
self.points = []
+ # disable the measuring button
+ self.measure_btn.setDisabled(False)
+ self.measure_btn.setText(_("Measure"))
+
self.app.call_source = copy(self.original_call_source)
if self.original_call_source == 'app':
self.app.mm = self.canvas.graph_event_connect('mouse_move', self.app.on_mouse_move_over_plot)
@@ -307,8 +372,16 @@ class Distance(FlatCAMTool):
# delete the measuring line
self.delete_shape()
+ # restore the grid status
+ if (self.app.ui.grid_snap_btn.isChecked() and self.grid_status_memory is False) or \
+ (not self.app.ui.grid_snap_btn.isChecked() and self.grid_status_memory is True):
+ self.app.ui.grid_snap_btn.trigger()
+
log.debug("Distance Tool --> exit tool")
+ if self.tool_done is False:
+ self.app.inform.emit('%s' % _("Distance Tool finished."))
+
def on_mouse_click_release(self, event):
# mouse click releases will be accepted only if the left button is clicked
# this is necessary because right mouse click or middle mouse click
@@ -323,11 +396,71 @@ class Distance(FlatCAMTool):
pos_canvas = self.canvas.translate_coords(event_pos)
- # if GRID is active we need to get the snapped positions
- if self.app.grid_status() == True:
- pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1])
+ if self.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])
+ else:
+ pos = pos_canvas[0], pos_canvas[1]
else:
- pos = pos_canvas[0], pos_canvas[1]
+ pos = (pos_canvas[0], pos_canvas[1])
+ current_pt = Point(pos)
+ shapes_storage = self.make_storage()
+
+ if self.original_call_source == 'exc_editor':
+ for storage in self.app.exc_editor.storage_dict:
+ __, st_closest_shape = self.app.exc_editor.storage_dict[storage].nearest(pos)
+ shapes_storage.insert(st_closest_shape)
+
+ __, closest_shape = shapes_storage.nearest(pos)
+
+ # if it's a drill
+ if isinstance(closest_shape.geo, MultiLineString):
+ radius = closest_shape.geo[0].length / 2.0
+ center_pt = closest_shape.geo.centroid
+
+ geo_buffered = center_pt.buffer(radius)
+
+ if current_pt.within(geo_buffered):
+ pos = (center_pt.x, center_pt.y)
+
+ # if it's a slot
+ elif isinstance(closest_shape.geo, Polygon):
+ geo_buffered = closest_shape.geo.buffer(0)
+ center_pt = geo_buffered.centroid
+
+ if current_pt.within(geo_buffered):
+ pos = (center_pt.x, center_pt.y)
+
+ elif self.original_call_source == 'grb_editor':
+ clicked_pads = list()
+ for storage in self.app.grb_editor.storage_dict:
+ try:
+ for shape_stored in self.app.grb_editor.storage_dict[storage]['geometry']:
+ if 'solid' in shape_stored.geo:
+ geometric_data = shape_stored.geo['solid']
+ if Point(current_pt).within(geometric_data):
+ if isinstance(shape_stored.geo['follow'], Point):
+ clicked_pads.append(shape_stored.geo['follow'])
+ except KeyError:
+ pass
+
+ if len(clicked_pads) > 1:
+ self.tool_done = True
+ self.deactivate_measure_tool()
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Pads overlapped. Aborting."))
+ return
+
+ pos = (clicked_pads[0].x, clicked_pads[0].y)
+
+ self.app.on_jump_to(custom_location=pos, fit_center=False)
+ # Update cursor
+ self.app.app_cursor.enabled = True
+ self.app.app_cursor.set_data(np.asarray([(pos[0], pos[1])]),
+ symbol='++', edge_color='#000000',
+ edge_width=self.app.defaults["global_cursor_width"],
+ size=self.app.defaults["global_cursor_size"])
+
self.points.append(pos)
# Reset here the relative coordinates so there is a new reference on the click position
@@ -340,41 +473,46 @@ class Distance(FlatCAMTool):
self.rel_point2 = copy(self.rel_point1)
self.rel_point1 = pos
- if len(self.points) == 1:
- self.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:
- 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.calculate_distance(pos=pos)
- 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)))
+ 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.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.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)))
+ )
+
+ self.distance_x_entry.set_value('%.*f' % (self.decimals, abs(dx)))
+ self.distance_y_entry.set_value('%.*f' % (self.decimals, abs(dy)))
+
+ if dx != 0.0:
+ try:
+ angle = math.degrees(math.atan(dy / dx))
+ self.angle_entry.set_value('%.*f' % (self.decimals, angle))
+ except Exception:
+ pass
+
+ self.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])
)
-
- self.distance_x_entry.set_value('%.*f' % (self.decimals, abs(dx)))
- self.distance_y_entry.set_value('%.*f' % (self.decimals, abs(dy)))
-
- if dx != 0.0:
- try:
- angle = math.degrees(math.atan(dy / dx))
- self.angle_entry.set_value('%.*f' % (self.decimals, angle))
- except Exception as e:
- pass
-
- self.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])
- )
- )
- self.deactivate_measure_tool()
+ )
+ self.tool_done = True
+ self.deactivate_measure_tool()
def on_mouse_move_meas(self, event):
try: # May fail in case mouse not within axes
@@ -391,7 +529,7 @@ class Distance(FlatCAMTool):
pos_canvas = self.app.plotcanvas.translate_coords((x, y))
- if self.app.grid_status() == True:
+ if self.app.grid_status():
pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1])
# Update cursor
@@ -465,7 +603,15 @@ class Distance(FlatCAMTool):
self.sel_shapes.clear()
self.sel_shapes.redraw()
- def set_meas_units(self, units):
- self.meas.units_label.setText("[" + self.app.options["units"].lower() + "]")
+ @staticmethod
+ def make_storage():
+ # ## Shape storage.
+ storage = FlatCAMRTreeStorage()
+ storage.get_points = DrawToolShape.get_pts
+
+ return storage
+
+ # def set_meas_units(self, units):
+ # self.meas.units_label.setText("[" + self.app.options["units"].lower() + "]")
# end of file
From 9911402c959ef16e41ff834112766bb04ac213a9 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 8 Feb 2020 18:01:32 +0200
Subject: [PATCH 072/209] - added a new preprocessor for using laser on a
Marlin 3D printer named 'Marlin_laser' - modified the Geometry UI when using
laser preprocessors
---
FlatCAMApp.py | 4 +-
FlatCAMObj.py | 123 +++++++++++++++++++++++--
README.md | 7 +-
camlib.py | 75 +++++++--------
flatcamGUI/ObjectUI.py | 80 ++++++++--------
flatcamGUI/PreferencesUI.py | 20 ++--
preprocessors/{marlin.py => Marlin.py} | 4 +-
preprocessors/Marlin_laser.py | 122 ++++++++++++++++++++++++
preprocessors/grbl_laser.py | 8 +-
9 files changed, 336 insertions(+), 107 deletions(-)
rename preprocessors/{marlin.py => Marlin.py} (98%)
create mode 100644 preprocessors/Marlin_laser.py
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 3f0d9086..9189e8f8 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -1291,7 +1291,7 @@ class App(QtCore.QObject):
"excellon_drillz": self.ui.excellon_defaults_form.excellon_opt_group.cutz_entry,
"excellon_travelz": self.ui.excellon_defaults_form.excellon_opt_group.travelz_entry,
"excellon_endz": self.ui.excellon_defaults_form.excellon_opt_group.eendz_entry,
- "excellon_feedrate": self.ui.excellon_defaults_form.excellon_opt_group.feedrate_entry,
+ "excellon_feedrate": self.ui.excellon_defaults_form.excellon_opt_group.feedrate_z_entry,
"excellon_spindlespeed": self.ui.excellon_defaults_form.excellon_opt_group.spindlespeed_entry,
"excellon_dwell": self.ui.excellon_defaults_form.excellon_opt_group.dwell_cb,
"excellon_dwelltime": self.ui.excellon_defaults_form.excellon_opt_group.dwelltime_entry,
@@ -1361,7 +1361,7 @@ class App(QtCore.QObject):
"geometry_cutz": self.ui.geometry_defaults_form.geometry_opt_group.cutz_entry,
"geometry_travelz": self.ui.geometry_defaults_form.geometry_opt_group.travelz_entry,
"geometry_feedrate": self.ui.geometry_defaults_form.geometry_opt_group.cncfeedrate_entry,
- "geometry_feedrate_z": self.ui.geometry_defaults_form.geometry_opt_group.cncplunge_entry,
+ "geometry_feedrate_z": self.ui.geometry_defaults_form.geometry_opt_group.feedrate_z_entry,
"geometry_spindlespeed": self.ui.geometry_defaults_form.geometry_opt_group.cncspindlespeed_entry,
"geometry_dwell": self.ui.geometry_defaults_form.geometry_opt_group.dwell_cb,
"geometry_dwelltime": self.ui.geometry_defaults_form.geometry_opt_group.dwelltime_entry,
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index e9982564..fdc45475 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -2804,7 +2804,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
"solid": self.ui.solid_cb,
"drillz": self.ui.cutz_entry,
"travelz": self.ui.travelz_entry,
- "feedrate": self.ui.feedrate_entry,
+ "feedrate": self.ui.feedrate_z_entry,
"feedrate_rapid": self.ui.feedrate_rapid_entry,
"tooldia": self.ui.tooldia_entry,
"slot_tooldia": self.ui.slot_tooldia_entry,
@@ -2978,12 +2978,14 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.ui.mill_type_radio.show()
self.ui.mill_dia_label.show()
self.ui.mill_dia_entry.show()
- self.ui.mpass_cb.show()
- self.ui.maxdepth_entry.show()
self.ui.frxylabel.show()
self.ui.xyfeedrate_entry.show()
self.ui.extracut_cb.show()
self.ui.e_cut_entry.show()
+
+ if 'laser' not in self.ui.pp_excellon_name_cb.get_value().lower():
+ self.ui.mpass_cb.show()
+ self.ui.maxdepth_entry.show()
else:
self.ui.mill_type_label.hide()
self.ui.mill_type_radio.hide()
@@ -3464,6 +3466,59 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.ui.feedrate_rapid_label.hide()
self.ui.feedrate_rapid_entry.hide()
+ if 'laser' in current_pp.lower():
+ self.ui.cutzlabel.hide()
+ self.ui.cutz_entry.hide()
+ try:
+ self.ui.mpass_cb.hide()
+ self.ui.maxdepth_entry.hide()
+ except AttributeError:
+ pass
+
+ self.ui.travelzlabel.setText('%s:' % _("Focus Z"))
+
+ try:
+ self.ui.frzlabel.hide()
+ self.ui.feedrate_z_entry.hide()
+ except AttributeError:
+ pass
+ self.ui.dwell_cb.hide()
+ self.ui.dwelltime_entry.hide()
+
+ self.ui.spindle_label.setText('%s:' % _("Laser Power"))
+
+ try:
+ self.ui.tool_offset_label.hide()
+ self.ui.offset_entry.hide()
+ except AttributeError:
+ pass
+ else:
+ self.ui.cutzlabel.show()
+ self.ui.cutz_entry.show()
+ try:
+ self.ui.mpass_cb.show()
+ self.ui.maxdepth_entry.show()
+ except AttributeError:
+ pass
+
+ self.ui.travelzlabel.setText('%s:' % _('Travel Z'))
+
+ try:
+ self.ui.frzlabel.show()
+ self.ui.feedrate_z_entry.show()
+ except AttributeError:
+ pass
+ self.ui.dwell_cb.show()
+ self.ui.dwelltime_entry.show()
+
+ self.ui.spindle_label.setText('%s:' % _('Spindle speed'))
+
+ try:
+ self.ui.tool_offset_lbl.show()
+ self.ui.offset_entry.show()
+ except AttributeError:
+ pass
+
def on_create_cncjob_button_click(self, *args):
self.app.report_usage("excellon_on_create_cncjob_button")
self.read_form()
@@ -4026,7 +4081,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
"vtipangle": self.ui.tipangle_entry,
"travelz": self.ui.travelz_entry,
"feedrate": self.ui.cncfeedrate_entry,
- "feedrate_z": self.ui.cncplunge_entry,
+ "feedrate_z": self.ui.feedrate_z_entry,
"feedrate_rapid": self.ui.cncfeedrate_rapid_entry,
"spindlespeed": self.ui.cncspindlespeed_entry,
"dwell": self.ui.dwell_cb,
@@ -5178,6 +5233,59 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.fr_rapidlabel.hide()
self.ui.cncfeedrate_rapid_entry.hide()
+ if 'laser' in current_pp.lower():
+ self.ui.cutzlabel.hide()
+ self.ui.cutz_entry.hide()
+ try:
+ self.ui.mpass_cb.hide()
+ self.ui.maxdepth_entry.hide()
+ except AttributeError:
+ pass
+
+ self.ui.travelzlabel.setText('%s:' % _("Focus Z"))
+
+ try:
+ self.ui.frzlabel.hide()
+ self.ui.feedrate_z_entry.hide()
+ except AttributeError:
+ pass
+ self.ui.dwell_cb.hide()
+ self.ui.dwelltime_entry.hide()
+
+ self.ui.spindle_label.setText('%s:' % _("Laser Power"))
+
+ try:
+ self.ui.tool_offset_label.hide()
+ self.ui.offset_entry.hide()
+ except AttributeError:
+ pass
+ else:
+ self.ui.cutzlabel.show()
+ self.ui.cutz_entry.show()
+ try:
+ self.ui.mpass_cb.show()
+ self.ui.maxdepth_entry.show()
+ except AttributeError:
+ pass
+
+ self.ui.travelzlabel.setText('%s:' % _('Travel Z'))
+
+ try:
+ self.ui.frzlabel.show()
+ self.ui.feedrate_z_entry.show()
+ except AttributeError:
+ pass
+ self.ui.dwell_cb.show()
+ self.ui.dwelltime_entry.show()
+
+ self.ui.spindle_label.setText('%s:' % _('Spindle speed'))
+
+ try:
+ self.ui.tool_offset_lbl.show()
+ self.ui.offset_entry.show()
+ except AttributeError:
+ pass
+
def on_generatecnc_button_click(self, *args):
log.debug("Generating CNCJob from Geometry ...")
self.app.report_usage("geometry_on_generatecnc_button")
@@ -6783,7 +6891,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
try:
for key in self.cnc_tools:
ppg = self.cnc_tools[key]['data']['ppname_g']
- if ppg == 'marlin' or ppg == 'Repetier':
+ if 'marlin' in ppg.lower() or 'repetier' in ppg.lower() :
marlin = True
break
if ppg == 'hpgl':
@@ -6797,7 +6905,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
pass
try:
- if self.options['ppname_e'] == 'marlin' or self.options['ppname_e'] == 'Repetier':
+ if 'marlin' in self.options['ppname_e'].lower() or 'repetier' in self.options['ppname_e'].lower():
marlin = True
except KeyError:
# log.debug("FlatCAMCNCJob.gcode_header(): --> There is no such self.option: %s" % str(e))
@@ -7150,8 +7258,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
_("The used preprocessor file has to have in it's name: "
"'toolchange_custom'"))
except KeyError:
- self.app.inform.emit('[ERROR] %s' %
- _("There is no preprocessor file."))
+ self.app.inform.emit('[ERROR] %s' % _("There is no preprocessor file."))
def get_gcode(self, preamble='', postamble=''):
# we need this to be able get_gcode separatelly for shell command export_gcode
diff --git a/README.md b/README.md
index 2728cc8b..38b752bc 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+8.02.2020
+
+- added a new preprocessor for using laser on a Marlin 3D printer named 'Marlin_laser'
+- modified the Geometry UI when using laser preprocessors
+
5.02.2020
- Modified the Distance Tool such that the Measure button can't be clicked while measuring is in progress
@@ -583,7 +588,7 @@ CAD program, and create G-Code for Isolation routing.
16.11.2019
-- fixed issue #341 that affected both postprocessors that have inlined feedrate: marlin and repetier. THe used feedrate was the Feedrate X-Y and instead had to be Feedrate Z.
+- fixed issue #341 that affected both postprocessors that have inlined feedrate: marlin and repetier. The used feedrate was the Feedrate X-Y and instead had to be Feedrate Z.
15.11.2019
diff --git a/camlib.py b/camlib.py
index 9eaa8ab8..217e3ef5 100644
--- a/camlib.py
+++ b/camlib.py
@@ -3299,7 +3299,7 @@ class CNCjob(Geometry):
# ## Iterate over geometry paths getting the nearest each time.
log.debug("Starting G-Code...")
- self.app.inform.emit(_("Starting G-Code..."))
+ self.app.inform.emit('%s...' % _("Starting G-Code"))
path_count = 0
current_pt = (0, 0)
@@ -3381,12 +3381,9 @@ class CNCjob(Geometry):
self.gcode += self.doformat(p.spindle_stop_code)
self.gcode += self.doformat(p.lift_code, x=current_pt[0], y=current_pt[1])
self.gcode += self.doformat(p.end_code, x=0, y=0)
- self.app.inform.emit('%s... %s %s.' %
- (_("Finished G-Code generation"),
- str(path_count),
- _("paths traced")
- )
- )
+ self.app.inform.emit(
+ '%s... %s %s.' % (_("Finished G-Code generation"), str(path_count), _("paths traced"))
+ )
return self.gcode
def generate_from_geometry_2(
@@ -3418,8 +3415,7 @@ class CNCjob(Geometry):
"""
if not isinstance(geometry, Geometry):
- self.app.inform.emit('[ERROR] %s: %s' %
- (_("Expected a Geometry, got"), type(geometry)))
+ self.app.inform.emit('[ERROR] %s: %s' % (_("Expected a Geometry, got"), type(geometry)))
return 'fail'
log.debug("Executing camlib.CNCJob.generate_from_geometry_2()")
@@ -3465,10 +3461,11 @@ class CNCjob(Geometry):
# if the offset is less than half of the total length or less than half of the total width of the
# solid geometry it's obvious we can't do the offset
if -offset > ((c - a) / 2) or -offset > ((d - b) / 2):
- self.app.inform.emit('[ERROR_NOTCL] %s' % _(
- "The Tool Offset value is too negative to use "
- "for the current_geometry.\n"
- "Raise the value (in module) and try again."))
+ self.app.inform.emit(
+ '[ERROR_NOTCL] %s' %
+ _("The Tool Offset value is too negative to use for the current_geometry.\n"
+ "Raise the value (in module) and try again.")
+ )
return 'fail'
# hack: make offset smaller by 0.0000000001 which is insignificant difference but allow the job
# to continue
@@ -3532,9 +3529,11 @@ class CNCjob(Geometry):
else:
self.xy_toolchange = [float(eval(a)) for a in toolchangexy.split(",")]
if len(self.xy_toolchange) < 2:
- self.app.inform.emit('[ERROR] %s' %
- _("The Toolchange X,Y field in Edit -> Preferences has to be "
- "in the format (x, y) \nbut now there is only one value, not two. "))
+ self.app.inform.emit(
+ '[ERROR] %s' %
+ _("The Toolchange X,Y field in Edit -> Preferences has to be in the format (x, y) \n"
+ "but now there is only one value, not two. ")
+ )
return 'fail'
except Exception as e:
log.debug("camlib.CNCJob.generate_from_geometry_2() --> %s" % str(e))
@@ -3545,9 +3544,10 @@ class CNCjob(Geometry):
if self.machinist_setting == 0:
if self.z_cut is None:
- self.app.inform.emit('[ERROR_NOTCL] %s' %
- _("Cut_Z parameter is None or zero. Most likely a bad combinations of "
- "other parameters."))
+ self.app.inform.emit(
+ '[ERROR_NOTCL] %s' % _("Cut_Z parameter is None or zero. Most likely a bad combinations of "
+ "other parameters.")
+ )
return 'fail'
if self.z_cut > 0:
@@ -3559,14 +3559,14 @@ class CNCjob(Geometry):
"Check the resulting CNC code (Gcode etc)."))
self.z_cut = -self.z_cut
elif self.z_cut == 0:
- self.app.inform.emit('[WARNING] %s: %s' %
- (_("The Cut Z parameter is zero. There will be no cut, skipping file"),
- geometry.options['name']))
+ self.app.inform.emit(
+ '[WARNING] %s: %s' % (_("The Cut Z parameter is zero. There will be no cut, skipping file"),
+ geometry.options['name'])
+ )
return 'fail'
if self.z_move is None:
- self.app.inform.emit('[ERROR_NOTCL] %s' %
- _("Travel Z parameter is None or zero."))
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _("Travel Z parameter is None or zero."))
return 'fail'
if self.z_move < 0:
@@ -3578,9 +3578,10 @@ class CNCjob(Geometry):
"Check the resulting CNC code (Gcode etc)."))
self.z_move = -self.z_move
elif self.z_move == 0:
- self.app.inform.emit('[WARNING] %s: %s' %
- (_("The Z Travel parameter is zero. "
- "This is dangerous, skipping file"), self.options['name']))
+ self.app.inform.emit(
+ '[WARNING] %s: %s' % (_("The Z Travel parameter is zero. This is dangerous, skipping file"),
+ self.options['name'])
+ )
return 'fail'
# made sure that depth_per_cut is no more then the z_cut
@@ -3663,7 +3664,7 @@ class CNCjob(Geometry):
# Iterate over geometry paths getting the nearest each time.
log.debug("Starting G-Code...")
- self.app.inform.emit(_("Starting G-Code..."))
+ self.app.inform.emit('%s...' % _("Starting G-Code"))
# variables to display the percentage of work done
geo_len = len(flat_geometry)
@@ -3674,9 +3675,7 @@ class CNCjob(Geometry):
current_tooldia = float('%.*f' % (self.decimals, float(self.tooldia)))
self.app.inform.emit(
- '%s: %s%s.' % (_("Starting G-Code for tool with diameter"),
- str(current_tooldia),
- str(self.units))
+ '%s: %s%s.' % (_("Starting G-Code for tool with diameter"), str(current_tooldia), str(self.units))
)
path_count = 0
@@ -3859,13 +3858,9 @@ class CNCjob(Geometry):
pass
log.debug("Finishing SolderPste G-Code... %s paths traced." % path_count)
- self.app.inform.emit('%s... %s %s' %
- (_("Finished SolderPste G-Code generation"),
- str(path_count),
- _("paths traced.")
- )
- )
-
+ self.app.inform.emit(
+ '%s... %s %s' % (_("Finished SolderPste G-Code generation"), str(path_count), _("paths traced."))
+ )
# Finish
self.gcode += self.doformat(p.lift_code)
@@ -4064,9 +4059,9 @@ class CNCjob(Geometry):
command['X'] = float(match_lsr.group(1).replace(" ", ""))
command['Y'] = float(match_lsr.group(2).replace(" ", ""))
- match_lsr_pos = re.search(r"^(M0[3-5])", gline)
+ match_lsr_pos = re.search(r"^(M0?[3-5])", gline)
if match_lsr_pos:
- if 'M05' in match_lsr_pos.group(1):
+ if 'M05' in match_lsr_pos.group(1) or 'M5' in match_lsr_pos.group(1):
# the value does not matter, only that it is positive so the gcode_parse() know it is > 0,
# therefore the move is of kind T (travel)
command['Z'] = 1
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index ed9863ae..0a08d60b 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -895,8 +895,8 @@ class ExcellonObjectUI(ObjectUI):
self.grid3.addWidget(self.mill_dia_entry, 3, 1)
# Cut Z
- cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
- cutzlabel.setToolTip(
+ self.cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
+ self.cutzlabel.setToolTip(
_("Drill depth (negative)\n"
"below the copper surface.")
)
@@ -911,7 +911,7 @@ class ExcellonObjectUI(ObjectUI):
self.cutz_entry.setSingleStep(0.1)
- self.grid3.addWidget(cutzlabel, 4, 0)
+ self.grid3.addWidget(self.cutzlabel, 4, 0)
self.grid3.addWidget(self.cutz_entry, 4, 1)
# Multi-Depth
@@ -930,19 +930,15 @@ class ExcellonObjectUI(ObjectUI):
self.maxdepth_entry.set_range(0, 9999.9999)
self.maxdepth_entry.setSingleStep(0.1)
- self.maxdepth_entry.setToolTip(
- _(
- "Depth of each pass (positive)."
- )
- )
+ self.maxdepth_entry.setToolTip(_("Depth of each pass (positive)."))
self.mis_mpass_geo = OptionalInputSection(self.mpass_cb, [self.maxdepth_entry])
self.grid3.addWidget(self.mpass_cb, 5, 0)
self.grid3.addWidget(self.maxdepth_entry, 5, 1)
# Travel Z (z_move)
- travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z'))
- travelzlabel.setToolTip(
+ self.travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z'))
+ self.travelzlabel.setToolTip(
_("Tool height when travelling\n"
"across the XY plane.")
)
@@ -957,7 +953,7 @@ class ExcellonObjectUI(ObjectUI):
self.travelz_entry.setSingleStep(0.1)
- self.grid3.addWidget(travelzlabel, 6, 0)
+ self.grid3.addWidget(self.travelzlabel, 6, 0)
self.grid3.addWidget(self.travelz_entry, 6, 1)
# Tool change:
@@ -1029,20 +1025,20 @@ class ExcellonObjectUI(ObjectUI):
self.grid3.addWidget(self.xyfeedrate_entry, 12, 1)
# Excellon Feedrate Z
- frlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z'))
- frlabel.setToolTip(
+ self.frzlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z'))
+ self.frzlabel.setToolTip(
_("Tool speed while drilling\n"
"(in units per minute).\n"
"So called 'Plunge' feedrate.\n"
"This is for linear move G01.")
)
- self.feedrate_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.feedrate_entry.set_precision(self.decimals)
- self.feedrate_entry.set_range(0.0, 99999.9999)
- self.feedrate_entry.setSingleStep(0.1)
+ self.feedrate_z_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.feedrate_z_entry.set_precision(self.decimals)
+ self.feedrate_z_entry.set_range(0.0, 99999.9999)
+ self.feedrate_z_entry.setSingleStep(0.1)
- self.grid3.addWidget(frlabel, 14, 0)
- self.grid3.addWidget(self.feedrate_entry, 14, 1)
+ self.grid3.addWidget(self.frzlabel, 14, 0)
+ self.grid3.addWidget(self.feedrate_z_entry, 14, 1)
# Excellon Rapid Feedrate
self.feedrate_rapid_label = QtWidgets.QLabel('%s:' % _('Feedrate Rapids'))
@@ -1092,8 +1088,8 @@ class ExcellonObjectUI(ObjectUI):
self.grid3.addWidget(self.e_cut_entry, 17, 1)
# Spindlespeed
- spdlabel = QtWidgets.QLabel('%s:' % _('Spindle speed'))
- spdlabel.setToolTip(
+ self.spindle_label = QtWidgets.QLabel('%s:' % _('Spindle speed'))
+ self.spindle_label.setToolTip(
_("Speed of the spindle\n"
"in RPM (optional)")
)
@@ -1102,7 +1098,7 @@ class ExcellonObjectUI(ObjectUI):
self.spindlespeed_entry.set_range(0, 1000000)
self.spindlespeed_entry.setSingleStep(100)
- self.grid3.addWidget(spdlabel, 19, 0)
+ self.grid3.addWidget(self.spindle_label, 19, 0)
self.grid3.addWidget(self.spindlespeed_entry, 19, 1)
# Dwell
@@ -1647,8 +1643,8 @@ class GeometryObjectUI(ObjectUI):
self.grid3.addWidget(self.tipangle_entry, 2, 1)
# Cut Z
- cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
- cutzlabel.setToolTip(
+ self.cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
+ self.cutzlabel.setToolTip(
_(
"Cutting depth (negative)\n"
"below the copper surface."
@@ -1664,7 +1660,7 @@ class GeometryObjectUI(ObjectUI):
self.cutz_entry.setSingleStep(0.1)
- self.grid3.addWidget(cutzlabel, 3, 0)
+ self.grid3.addWidget(self.cutzlabel, 3, 0)
self.grid3.addWidget(self.cutz_entry, 3, 1)
# Multi-pass
@@ -1694,8 +1690,8 @@ class GeometryObjectUI(ObjectUI):
self.grid3.addWidget(self.maxdepth_entry, 4, 1)
# Travel Z
- travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z'))
- travelzlabel.setToolTip(
+ self.travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z'))
+ self.travelzlabel.setToolTip(
_("Height of the tool when\n"
"moving without cutting.")
)
@@ -1709,7 +1705,7 @@ class GeometryObjectUI(ObjectUI):
self.travelz_entry.setSingleStep(0.1)
- self.grid3.addWidget(travelzlabel, 5, 0)
+ self.grid3.addWidget(self.travelzlabel, 5, 0)
self.grid3.addWidget(self.travelz_entry, 5, 1)
# Tool change
@@ -1771,8 +1767,8 @@ class GeometryObjectUI(ObjectUI):
self.grid3.addWidget(self.gendz_entry, 9, 1)
# Feedrate X-Y
- frlabel = QtWidgets.QLabel('%s:' % _('Feedrate X-Y'))
- frlabel.setToolTip(
+ self.frlabel = QtWidgets.QLabel('%s:' % _('Feedrate X-Y'))
+ self.frlabel.setToolTip(
_("Cutting speed in the XY\n"
"plane in units per minute")
)
@@ -1781,23 +1777,23 @@ class GeometryObjectUI(ObjectUI):
self.cncfeedrate_entry.set_range(0, 99999.9999)
self.cncfeedrate_entry.setSingleStep(0.1)
- self.grid3.addWidget(frlabel, 10, 0)
+ self.grid3.addWidget(self.frlabel, 10, 0)
self.grid3.addWidget(self.cncfeedrate_entry, 10, 1)
# Feedrate Z (Plunge)
- frzlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z'))
- frzlabel.setToolTip(
+ self.frzlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z'))
+ self.frzlabel.setToolTip(
_("Cutting speed in the XY\n"
"plane in units per minute.\n"
"It is called also Plunge.")
)
- self.cncplunge_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.cncplunge_entry.set_precision(self.decimals)
- self.cncplunge_entry.set_range(0, 99999.9999)
- self.cncplunge_entry.setSingleStep(0.1)
+ self.feedrate_z_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.feedrate_z_entry.set_precision(self.decimals)
+ self.feedrate_z_entry.set_range(0, 99999.9999)
+ self.feedrate_z_entry.setSingleStep(0.1)
- self.grid3.addWidget(frzlabel, 11, 0)
- self.grid3.addWidget(self.cncplunge_entry, 11, 1)
+ self.grid3.addWidget(self.frzlabel, 11, 0)
+ self.grid3.addWidget(self.feedrate_z_entry, 11, 1)
# Feedrate rapids
self.fr_rapidlabel = QtWidgets.QLabel('%s:' % _('Feedrate Rapids'))
@@ -1843,8 +1839,8 @@ class GeometryObjectUI(ObjectUI):
self.grid3.addWidget(self.e_cut_entry, 13, 1)
# Spindlespeed
- spdlabel = QtWidgets.QLabel('%s:' % _('Spindle speed'))
- spdlabel.setToolTip(
+ self.spindle_label = QtWidgets.QLabel('%s:' % _('Spindle speed'))
+ self.spindle_label.setToolTip(
_(
"Speed of the spindle in RPM (optional).\n"
"If LASER preprocessor is used,\n"
@@ -1855,7 +1851,7 @@ class GeometryObjectUI(ObjectUI):
self.cncspindlespeed_entry.set_range(0, 1000000)
self.cncspindlespeed_entry.setSingleStep(100)
- self.grid3.addWidget(spdlabel, 14, 0)
+ self.grid3.addWidget(self.spindle_label, 14, 0)
self.grid3.addWidget(self.cncspindlespeed_entry, 14, 1)
# Dwell
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index cde679cf..92e06f69 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -3152,12 +3152,12 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
"So called 'Plunge' feedrate.\n"
"This is for linear move G01.")
)
- self.feedrate_entry = FCDoubleSpinner()
- self.feedrate_entry.set_precision(self.decimals)
- self.feedrate_entry.set_range(0, 99999.9999)
+ self.feedrate_z_entry = FCDoubleSpinner()
+ self.feedrate_z_entry.set_precision(self.decimals)
+ self.feedrate_z_entry.set_range(0, 99999.9999)
grid2.addWidget(frlabel, 5, 0)
- grid2.addWidget(self.feedrate_entry, 5, 1)
+ grid2.addWidget(self.feedrate_z_entry, 5, 1)
# Spindle speed
spdlabel = QtWidgets.QLabel('%s:' % _('Spindle Speed'))
@@ -4096,14 +4096,14 @@ class GeometryOptPrefGroupUI(OptionsGroupUI):
"plane in units per minute.\n"
"It is called also Plunge.")
)
- self.cncplunge_entry = FCDoubleSpinner()
- self.cncplunge_entry.set_range(0, 99999.9999)
- self.cncplunge_entry.set_precision(self.decimals)
- self.cncplunge_entry.setSingleStep(0.1)
- self.cncplunge_entry.setWrapping(True)
+ self.feedrate_z_entry = FCDoubleSpinner()
+ self.feedrate_z_entry.set_range(0, 99999.9999)
+ self.feedrate_z_entry.set_precision(self.decimals)
+ self.feedrate_z_entry.setSingleStep(0.1)
+ self.feedrate_z_entry.setWrapping(True)
grid1.addWidget(frz_label, 8, 0)
- grid1.addWidget(self.cncplunge_entry, 8, 1)
+ grid1.addWidget(self.feedrate_z_entry, 8, 1)
# Spindle Speed
spdlabel = QtWidgets.QLabel('%s:' % _('Spindle speed'))
diff --git a/preprocessors/marlin.py b/preprocessors/Marlin.py
similarity index 98%
rename from preprocessors/marlin.py
rename to preprocessors/Marlin.py
index 5eafd92d..65428e8f 100644
--- a/preprocessors/marlin.py
+++ b/preprocessors/Marlin.py
@@ -9,7 +9,7 @@
from FlatCAMPostProc import *
-class marlin(FlatCAMPostProc):
+class Marlin(FlatCAMPostProc):
include_header = True
coordinate_format = "%.*f"
@@ -34,7 +34,7 @@ class marlin(FlatCAMPostProc):
if str(p['options']['type']) == 'Geometry':
gcode += ';Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + '\n'
- gcode += ';Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + '\n' + '\n'
+ gcode += ';Feedrate rapids: ' + str(p['feedrate_rapid']) + units + '/min' + '\n' + '\n'
gcode += ';Z_Cut: ' + str(p['z_cut']) + units + '\n'
if str(p['options']['type']) == 'Geometry':
diff --git a/preprocessors/Marlin_laser.py b/preprocessors/Marlin_laser.py
new file mode 100644
index 00000000..e67e9bb5
--- /dev/null
+++ b/preprocessors/Marlin_laser.py
@@ -0,0 +1,122 @@
+# ##########################################################
+# FlatCAM: 2D Post-processing for Manufacturing #
+# Website: http://flatcam.org #
+# File Author: Marius Adrian Stanciu (c) #
+# Date: 8-Feb-2020 #
+# License: MIT Licence #
+# ##########################################################
+
+from FlatCAMPostProc import *
+
+
+class Marlin_laser(FlatCAMPostProc):
+
+ include_header = True
+ coordinate_format = "%.*f"
+ feedrate_format = '%.*f'
+ feedrate_rapid_format = feedrate_format
+
+ def start_code(self, p):
+ units = ' ' + str(p['units']).lower()
+ coords_xy = p['xy_toolchange']
+ gcode = ''
+
+ xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
+ xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
+ ymin = '%.*f' % (p.coords_decimals, p['options']['ymin'])
+ ymax = '%.*f' % (p.coords_decimals, p['options']['ymax'])
+
+ gcode += ';Feedrate: ' + str(p['feedrate']) + units + '/min' + '\n'
+ gcode += ';Feedrate rapids: ' + str(p['feedrate_rapid']) + units + '/min' + '\n' + '\n'
+
+ gcode += ';Z Focus: ' + str(p['z_move']) + units + '\n'
+
+ gcode += ';Steps per circle: ' + str(p['steps_per_circle']) + '\n'
+
+ if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
+ gcode += ';Preprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n'
+ else:
+ gcode += ';Preprocessor Geometry: ' + str(p['pp_geometry_name']) + '\n' + '\n'
+
+ gcode += ';X range: ' + '{: >9s}'.format(xmin) + ' ... ' + '{: >9s}'.format(xmax) + ' ' + units + '\n'
+ gcode += ';Y range: ' + '{: >9s}'.format(ymin) + ' ... ' + '{: >9s}'.format(ymax) + ' ' + units + '\n\n'
+
+ gcode += ';Laser Power (Spindle Speed): ' + str(p['spindlespeed']) + '\n' + '\n'
+
+ gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n"
+ gcode += 'G90\n'
+ gcode += 'G94'
+
+ return gcode
+
+ def startz_code(self, p):
+ if p.startz is not None:
+ return 'G0 Z' + self.coordinate_format % (p.coords_decimals, p.z_move)
+ else:
+ return ''
+
+ def lift_code(self, p):
+ gcode = 'M400\n'
+ gcode += 'M5 S0'
+ return gcode
+
+ def down_code(self, p):
+ sdir = {'CW': 'M3', 'CCW': 'M4'}[p.spindledir]
+ if p.spindlespeed:
+ return '%s S%s' % (sdir, str(p.spindlespeed))
+ else:
+ return sdir
+
+ def toolchange_code(self, p):
+ return ''
+
+ def up_to_zero_code(self, p):
+ gcode = 'M400\n'
+ gcode += 'M5'
+ return gcode
+
+ def position_code(self, p):
+ return ('X' + self.coordinate_format + ' Y' + self.coordinate_format) % \
+ (p.coords_decimals, p.x, p.coords_decimals, p.y)
+
+ def rapid_code(self, p):
+ return ('G0 ' + self.position_code(p)).format(**p) + " " + self.feedrate_rapid_code(p)
+
+ def linear_code(self, p):
+ return ('G1 ' + self.position_code(p)).format(**p) + " " + self.inline_feedrate_code(p)
+
+ def end_code(self, p):
+ coords_xy = p['xy_toolchange']
+ gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + " " + self.feedrate_rapid_code(p) + "\n")
+
+ if coords_xy is not None:
+ gcode += 'G0 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + " " + self.feedrate_rapid_code(p) + "\n"
+
+ return gcode
+
+ def feedrate_code(self, p):
+ return 'G1 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
+
+ def z_feedrate_code(self, p):
+ return 'G1 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate))
+
+ def inline_feedrate_code(self, p):
+ return 'F' + self.feedrate_format % (p.fr_decimals, p.feedrate)
+
+ def feedrate_rapid_code(self, p):
+ return 'F' + self.feedrate_rapid_format % (p.fr_decimals, p.feedrate_rapid)
+
+ def spindle_code(self, p):
+ sdir = {'CW': 'M3', 'CCW': 'M4'}[p.spindledir]
+ if p.spindlespeed:
+ return '%s S%s' % (sdir, str(p.spindlespeed))
+ else:
+ return sdir
+
+ def dwell_code(self, p):
+ return ''
+
+ def spindle_stop_code(self, p):
+ gcode = 'M400\n'
+ gcode += 'M5'
+ return gcode
diff --git a/preprocessors/grbl_laser.py b/preprocessors/grbl_laser.py
index e975a703..a3f4da7d 100644
--- a/preprocessors/grbl_laser.py
+++ b/preprocessors/grbl_laser.py
@@ -28,7 +28,9 @@ class grbl_laser(FlatCAMPostProc):
ymax = '%.*f' % (p.coords_decimals, p['options']['ymax'])
gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n'
- gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
+ gcode += '(Feedrate rapids: ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
+
+ gcode += '(Z Focus: ' + str(p['z_move']) + units + ')\n'
gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n'
@@ -40,10 +42,12 @@ class grbl_laser(FlatCAMPostProc):
gcode += '(X range: ' + '{: >9s}'.format(xmin) + ' ... ' + '{: >9s}'.format(xmax) + ' ' + units + ')\n'
gcode += '(Y range: ' + '{: >9s}'.format(ymin) + ' ... ' + '{: >9s}'.format(ymax) + ' ' + units + ')\n\n'
+ gcode += '(Laser Power (Spindle Speed): ' + str(p['spindlespeed']) + ')\n\n'
+
gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n"
gcode += 'G90\n'
gcode += 'G17\n'
- gcode += 'G94\n'
+ gcode += 'G94'
return gcode
From 48029da52b726c8c37dbf6fb1548ccb2afe6195a Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 8 Feb 2020 20:38:51 +0200
Subject: [PATCH 073/209] - added a new preprocessor file for using laser on a
Marlin motion controller but with the laser connected to one of the FAN pins,
named 'Marlin_laser_use_FAN_pin'
---
FlatCAMApp.py | 10 +-
FlatCAMObj.py | 52 ++++++--
README.md | 11 +-
camlib.py | 7 +
flatcamGUI/ObjectUI.py | 48 +++----
flatcamGUI/PreferencesUI.py | 48 +++----
preprocessors/Berta_CNC.py | 4 +-
.../{grbl_laser.py => GRBL_laser.py} | 11 +-
preprocessors/ISEL_CNC.py | 2 +-
preprocessors/ISEL_ICP_CNC.py | 2 +-
preprocessors/Marlin.py | 10 +-
preprocessors/Marlin_laser_use_FAN_pin.py | 120 ++++++++++++++++++
...ser.py => Marlin_laser_use_Spindle_pin.py} | 10 +-
preprocessors/Repetier.py | 2 +-
preprocessors/Toolchange_Probe_MACH3.py | 2 +-
preprocessors/default.py | 5 +-
preprocessors/grbl_11.py | 3 +-
17 files changed, 256 insertions(+), 91 deletions(-)
rename preprocessors/{grbl_laser.py => GRBL_laser.py} (92%)
create mode 100644 preprocessors/Marlin_laser_use_FAN_pin.py
rename preprocessors/{Marlin_laser.py => Marlin_laser_use_Spindle_pin.py} (93%)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 9189e8f8..36c06ba9 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -1001,7 +1001,7 @@ class App(QtCore.QObject):
'box, center_x, center_y, columns, combine, connect, contour, default, '
'depthperpass, dia, diatol, dist, drilled_dias, drillz, dwelltime, '
'extracut_length, '
- 'feedrate_z, grbl_11, grbl_laser, gridoffsety, gridx, gridy, has_offset, '
+ 'feedrate_z, grbl_11, GRBL_laser, gridoffsety, gridx, gridy, has_offset, '
'holes, hpgl, iso_type, line_xyz, margin, marlin, method, milled_dias, '
'minoffset, name, offset, opt_type, order, outname, overlap, '
'passes, postamble, pp, ppname_e, ppname_g, preamble, radius, ref, rest, '
@@ -1290,7 +1290,7 @@ class App(QtCore.QObject):
# Excellon Options
"excellon_drillz": self.ui.excellon_defaults_form.excellon_opt_group.cutz_entry,
"excellon_travelz": self.ui.excellon_defaults_form.excellon_opt_group.travelz_entry,
- "excellon_endz": self.ui.excellon_defaults_form.excellon_opt_group.eendz_entry,
+ "excellon_endz": self.ui.excellon_defaults_form.excellon_opt_group.endz_entry,
"excellon_feedrate": self.ui.excellon_defaults_form.excellon_opt_group.feedrate_z_entry,
"excellon_spindlespeed": self.ui.excellon_defaults_form.excellon_opt_group.spindlespeed_entry,
"excellon_dwell": self.ui.excellon_defaults_form.excellon_opt_group.dwell_cb,
@@ -1368,14 +1368,14 @@ class App(QtCore.QObject):
"geometry_ppname_g": self.ui.geometry_defaults_form.geometry_opt_group.pp_geometry_name_cb,
"geometry_toolchange": self.ui.geometry_defaults_form.geometry_opt_group.toolchange_cb,
"geometry_toolchangez": self.ui.geometry_defaults_form.geometry_opt_group.toolchangez_entry,
- "geometry_endz": self.ui.geometry_defaults_form.geometry_opt_group.gendz_entry,
+ "geometry_endz": self.ui.geometry_defaults_form.geometry_opt_group.endz_entry,
"geometry_depthperpass": self.ui.geometry_defaults_form.geometry_opt_group.depthperpass_entry,
"geometry_multidepth": self.ui.geometry_defaults_form.geometry_opt_group.multidepth_cb,
# Geometry Advanced Options
"geometry_toolchangexy": self.ui.geometry_defaults_form.geometry_adv_opt_group.toolchangexy_entry,
"geometry_startz": self.ui.geometry_defaults_form.geometry_adv_opt_group.gstartz_entry,
- "geometry_feedrate_rapid": self.ui.geometry_defaults_form.geometry_adv_opt_group.cncfeedrate_rapid_entry,
+ "geometry_feedrate_rapid": self.ui.geometry_defaults_form.geometry_adv_opt_group.feedrate_rapid_entry,
"geometry_extracut": self.ui.geometry_defaults_form.geometry_adv_opt_group.extracut_cb,
"geometry_extracut_length": self.ui.geometry_defaults_form.geometry_adv_opt_group.e_cut_entry,
"geometry_z_pdepth": self.ui.geometry_defaults_form.geometry_adv_opt_group.pdepth_entry,
@@ -2263,7 +2263,7 @@ class App(QtCore.QObject):
'box', 'center_x', 'center_y', 'columns', 'combine', 'connect', 'contour', 'default',
'depthperpass', 'dia', 'diatol', 'dist', 'drilled_dias', 'drillz',
'dwelltime', 'extracut_length',
- 'feedrate_z', 'grbl_11', 'grbl_laser', 'gridoffsety', 'gridx', 'gridy',
+ 'feedrate_z', 'grbl_11', 'GRBL_laser', 'gridoffsety', 'gridx', 'gridy',
'has_offset', 'holes', 'hpgl', 'iso_type', 'line_xyz', 'margin', 'marlin', 'method',
'milled_dias', 'minoffset', 'name', 'offset', 'opt_type', 'order',
'outname', 'overlap', 'passes', 'postamble', 'pp', 'ppname_e', 'ppname_g',
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index fdc45475..f7faf045 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -2814,7 +2814,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
"dwell": self.ui.dwell_cb,
"dwelltime": self.ui.dwelltime_entry,
"startz": self.ui.estartz_entry,
- "endz": self.ui.eendz_entry,
+ "endz": self.ui.endz_entry,
"ppname_e": self.ui.pp_excellon_name_cb,
"z_pdepth": self.ui.pdepth_entry,
"feedrate_probe": self.ui.feedrate_probe_entry,
@@ -3475,13 +3475,23 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
except AttributeError:
pass
- self.ui.travelzlabel.setText('%s:' % _("Focus Z"))
+ if 'marlin' in current_pp.lower():
+ self.ui.travelzlabel.setText('%s:' % _("Focus Z"))
+ self.ui.endz_label.show()
+ self.ui.endz_entry.show()
+ else:
+ self.ui.travelzlabel.hide()
+ self.ui.travelz_entry.hide()
+
+ self.ui.endz_label.hide()
+ self.ui.endz_entry.hide()
try:
self.ui.frzlabel.hide()
self.ui.feedrate_z_entry.hide()
except AttributeError:
pass
+
self.ui.dwell_cb.hide()
self.ui.dwelltime_entry.hide()
@@ -3503,6 +3513,12 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.ui.travelzlabel.setText('%s:' % _('Travel Z'))
+ self.ui.travelzlabel.show()
+ self.ui.travelz_entry.show()
+
+ self.ui.endz_label.show()
+ self.ui.endz_entry.show()
+
try:
self.ui.frzlabel.show()
self.ui.feedrate_z_entry.show()
@@ -4082,7 +4098,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
"travelz": self.ui.travelz_entry,
"feedrate": self.ui.cncfeedrate_entry,
"feedrate_z": self.ui.feedrate_z_entry,
- "feedrate_rapid": self.ui.cncfeedrate_rapid_entry,
+ "feedrate_rapid": self.ui.feedrate_rapid_entry,
"spindlespeed": self.ui.cncspindlespeed_entry,
"dwell": self.ui.dwell_cb,
"dwelltime": self.ui.dwelltime_entry,
@@ -4095,7 +4111,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
"extracut_length": self.ui.e_cut_entry,
"toolchange": self.ui.toolchangeg_cb,
"toolchangez": self.ui.toolchangez_entry,
- "endz": self.ui.gendz_entry,
+ "endz": self.ui.endz_entry,
"cnctooldia": self.ui.addtool_entry
})
@@ -4225,10 +4241,10 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.addtool_btn.hide()
self.ui.copytool_btn.hide()
self.ui.deltool_btn.hide()
- # self.ui.endzlabel.hide()
- # self.ui.gendz_entry.hide()
+ # self.ui.endz_label.hide()
+ # self.ui.endz_entry.hide()
self.ui.fr_rapidlabel.hide()
- self.ui.cncfeedrate_rapid_entry.hide()
+ self.ui.feedrate_rapid_entry.hide()
self.ui.extracut_cb.hide()
self.ui.e_cut_entry.hide()
self.ui.pdepth_label.hide()
@@ -5228,10 +5244,10 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
if 'marlin' in current_pp.lower() or 'custom' in current_pp.lower():
self.ui.fr_rapidlabel.show()
- self.ui.cncfeedrate_rapid_entry.show()
+ self.ui.feedrate_rapid_entry.show()
else:
self.ui.fr_rapidlabel.hide()
- self.ui.cncfeedrate_rapid_entry.hide()
+ self.ui.feedrate_rapid_entry.hide()
if 'laser' in current_pp.lower():
self.ui.cutzlabel.hide()
@@ -5242,13 +5258,23 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
except AttributeError:
pass
- self.ui.travelzlabel.setText('%s:' % _("Focus Z"))
+ if 'marlin' in current_pp.lower():
+ self.ui.travelzlabel.setText('%s:' % _("Focus Z"))
+ self.ui.endz_label.show()
+ self.ui.endz_entry.show()
+ else:
+ self.ui.travelzlabel.hide()
+ self.ui.travelz_entry.hide()
+
+ self.ui.endz_label.hide()
+ self.ui.endz_entry.hide()
try:
self.ui.frzlabel.hide()
self.ui.feedrate_z_entry.hide()
except AttributeError:
pass
+
self.ui.dwell_cb.hide()
self.ui.dwelltime_entry.hide()
@@ -5270,6 +5296,12 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.travelzlabel.setText('%s:' % _('Travel Z'))
+ self.ui.travelzlabel.show()
+ self.ui.travelz_entry.show()
+
+ self.ui.endz_label.show()
+ self.ui.endz_entry.show()
+
try:
self.ui.frzlabel.show()
self.ui.feedrate_z_entry.show()
diff --git a/README.md b/README.md
index 38b752bc..f727c607 100644
--- a/README.md
+++ b/README.md
@@ -11,8 +11,9 @@ CAD program, and create G-Code for Isolation routing.
8.02.2020
-- added a new preprocessor for using laser on a Marlin 3D printer named 'Marlin_laser'
+- added a new preprocessor for using laser on a Marlin 3D printer named 'Marlin_laser_use_Spindle_pin'
- modified the Geometry UI when using laser preprocessors
+- added a new preprocessor file for using laser on a Marlin motion controller but with the laser connected to one of the FAN pins, named 'Marlin_laser_use_FAN_pin'
5.02.2020
@@ -2772,7 +2773,7 @@ CAD program, and create G-Code for Isolation routing.
- added options for trace segmentation that can be useful for auto-levelling (code snippet from Lei Zheng from a rejected pull request on FlatCAM https://bitbucket.org/realthunder/ )
- added shortcut key 'L' for creating 'New Excellon'
- added shortcut key combo 'SHIFT+S' for Running a Script.
-- modified grbl_laser postprocessor file so it includes a Sxxxx command on the line with M03 (laser active) whenever a value is enter in the Spindlespeed entry field
+- modified GRBL_laser postprocessor file so it includes a Sxxxx command on the line with M03 (laser active) whenever a value is enter in the Spindlespeed entry field
- remade the EDIT -> PREFERENCES window, the Excellon and Gerber sections. Created a new section named TOOLS
26.01.2019
@@ -2780,7 +2781,7 @@ CAD program, and create G-Code for Isolation routing.
- fixed grbl_11 postprocessor in linear_code() function
- added icons to the Project Tab context menu
- added new entries to the Canvas context menu (Copy, Delete, Edit/Save, Move, New Excellon, New Geometry, New Project)
-- fixed grbl_laser postprocessor file
+- fixed GRBL_laser postprocessor file
- updated function for copy of an Excellon object for the case when the object has slots
- updated FlatCAMExcellon.merge() function to work in case some (or all) of the merged objects have slots
@@ -2800,8 +2801,8 @@ CAD program, and create G-Code for Isolation routing.
- added the Copy entry to the Project context menu
- made the functions behind Disable and Enable project context menu entries, non-threaded to fix a possible issue
- added multiple object selection on Open ... and Import ... (idea and code snippet came from Travers Carter, BitBucket user https://bitbucket.org/travc/)
-- fixed 'grbl_laser' postprocessor bugs (missing functions)
-- fixed display geometry for 'grbl_laser' postprocessor
+- fixed 'GRBL_laser' postprocessor bugs (missing functions)
+- fixed display geometry for 'GRBL_laser' postprocessor
- Excellon Editor - added possibility to create an linear drill array rotated at an custom angle
- added the Edit and Properties entries to the Project context menu
diff --git a/camlib.py b/camlib.py
index 217e3ef5..e3002d8a 100644
--- a/camlib.py
+++ b/camlib.py
@@ -4067,6 +4067,13 @@ class CNCjob(Geometry):
command['Z'] = 1
else:
command['Z'] = 0
+
+ match_lsr_pos_2 = re.search(r"^(M10[6|7])", gline)
+ if match_lsr_pos_2:
+ if 'M107' in match_lsr_pos_2.group(1):
+ command['Z'] = 1
+ else:
+ command['Z'] = 0
elif self.pp_solderpaste_name is not None:
if 'Paste' in self.pp_solderpaste_name:
match_paste = re.search(r"X([\+-]?\d+.[\+-]?\d+)\s*Y([\+-]?\d+.[\+-]?\d+)", gline)
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index 0a08d60b..1bac450d 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -992,23 +992,23 @@ class ExcellonObjectUI(ObjectUI):
self.grid3.addWidget(self.estartz_entry, 9, 1)
# End move Z:
- self.eendz_label = QtWidgets.QLabel('%s:' % _("End move Z"))
- self.eendz_label.setToolTip(
+ self.endz_label = QtWidgets.QLabel('%s:' % _("End move Z"))
+ self.endz_label.setToolTip(
_("Height of the tool after\n"
"the last move at the end of the job.")
)
- self.eendz_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.eendz_entry.set_precision(self.decimals)
+ self.endz_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.endz_entry.set_precision(self.decimals)
if machinist_setting == 0:
- self.eendz_entry.set_range(0.0, 9999.9999)
+ self.endz_entry.set_range(0.0, 9999.9999)
else:
- self.eendz_entry.set_range(-9999.9999, 9999.9999)
+ self.endz_entry.set_range(-9999.9999, 9999.9999)
- self.eendz_entry.setSingleStep(0.1)
+ self.endz_entry.setSingleStep(0.1)
- self.grid3.addWidget(self.eendz_label, 11, 0)
- self.grid3.addWidget(self.eendz_entry, 11, 1)
+ self.grid3.addWidget(self.endz_label, 11, 0)
+ self.grid3.addWidget(self.endz_entry, 11, 1)
# Feedrate X-Y
self.frxylabel = QtWidgets.QLabel('%s:' % _('Feedrate X-Y'))
@@ -1748,23 +1748,23 @@ class GeometryObjectUI(ObjectUI):
# self.grid3.addWidget(self.gstartz_entry, 8, 1)
# The Z value for the end move
- self.endzlabel = QtWidgets.QLabel('%s:' % _('End move Z'))
- self.endzlabel.setToolTip(
+ self.endz_label = QtWidgets.QLabel('%s:' % _('End move Z'))
+ self.endz_label.setToolTip(
_("Height of the tool after\n"
"the last move at the end of the job.")
)
- self.gendz_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.gendz_entry.set_precision(self.decimals)
+ self.endz_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.endz_entry.set_precision(self.decimals)
if machinist_setting == 0:
- self.gendz_entry.set_range(0, 9999.9999)
+ self.endz_entry.set_range(0, 9999.9999)
else:
- self.gendz_entry.set_range(-9999.9999, 9999.9999)
+ self.endz_entry.set_range(-9999.9999, 9999.9999)
- self.gendz_entry.setSingleStep(0.1)
+ self.endz_entry.setSingleStep(0.1)
- self.grid3.addWidget(self.endzlabel, 9, 0)
- self.grid3.addWidget(self.gendz_entry, 9, 1)
+ self.grid3.addWidget(self.endz_label, 9, 0)
+ self.grid3.addWidget(self.endz_entry, 9, 1)
# Feedrate X-Y
self.frlabel = QtWidgets.QLabel('%s:' % _('Feedrate X-Y'))
@@ -1804,16 +1804,16 @@ class GeometryObjectUI(ObjectUI):
"It is useful only for Marlin,\n"
"ignore for any other cases.")
)
- self.cncfeedrate_rapid_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.cncfeedrate_rapid_entry.set_precision(self.decimals)
- self.cncfeedrate_rapid_entry.set_range(0, 99999.9999)
- self.cncfeedrate_rapid_entry.setSingleStep(0.1)
+ self.feedrate_rapid_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.feedrate_rapid_entry.set_precision(self.decimals)
+ self.feedrate_rapid_entry.set_range(0, 99999.9999)
+ self.feedrate_rapid_entry.setSingleStep(0.1)
self.grid3.addWidget(self.fr_rapidlabel, 12, 0)
- self.grid3.addWidget(self.cncfeedrate_rapid_entry, 12, 1)
+ self.grid3.addWidget(self.feedrate_rapid_entry, 12, 1)
# default values is to hide
self.fr_rapidlabel.hide()
- self.cncfeedrate_rapid_entry.hide()
+ self.feedrate_rapid_entry.hide()
# Cut over 1st point in path
self.extracut_cb = FCCheckBox('%s:' % _('Re-cut'))
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index 92e06f69..33c23ab3 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -3128,21 +3128,21 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
grid2.addWidget(self.toolchangez_entry, 3, 1)
# End Move Z
- endzlabel = QtWidgets.QLabel('%s:' % _('End move Z'))
- endzlabel.setToolTip(
+ endz_label = QtWidgets.QLabel('%s:' % _('End move Z'))
+ endz_label.setToolTip(
_("Height of the tool after\n"
"the last move at the end of the job.")
)
- self.eendz_entry = FCDoubleSpinner()
- self.eendz_entry.set_precision(self.decimals)
+ self.endz_entry = FCDoubleSpinner()
+ self.endz_entry.set_precision(self.decimals)
if machinist_setting == 0:
- self.eendz_entry.set_range(0.0000, 9999.9999)
+ self.endz_entry.set_range(0.0000, 9999.9999)
else:
- self.eendz_entry.set_range(-9999.9999, 9999.9999)
+ self.endz_entry.set_range(-9999.9999, 9999.9999)
- grid2.addWidget(endzlabel, 4, 0)
- grid2.addWidget(self.eendz_entry, 4, 1)
+ grid2.addWidget(endz_label, 4, 0)
+ grid2.addWidget(self.endz_entry, 4, 1)
# Feedrate Z
frlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z'))
@@ -4055,24 +4055,24 @@ class GeometryOptPrefGroupUI(OptionsGroupUI):
grid1.addWidget(self.toolchangez_entry, 5, 1)
# End move Z
- endzlabel = QtWidgets.QLabel('%s:' % _('End move Z'))
- endzlabel.setToolTip(
+ endz_label = QtWidgets.QLabel('%s:' % _('End move Z'))
+ endz_label.setToolTip(
_("Height of the tool after\n"
"the last move at the end of the job.")
)
- self.gendz_entry = FCDoubleSpinner()
+ self.endz_entry = FCDoubleSpinner()
if machinist_setting == 0:
- self.gendz_entry.set_range(0.000, 9999.9999)
+ self.endz_entry.set_range(0.000, 9999.9999)
else:
- self.gendz_entry.set_range(-9999.9999, 9999.9999)
+ self.endz_entry.set_range(-9999.9999, 9999.9999)
- self.gendz_entry.set_precision(self.decimals)
- self.gendz_entry.setSingleStep(0.1)
- self.gendz_entry.setWrapping(True)
+ self.endz_entry.set_precision(self.decimals)
+ self.endz_entry.setSingleStep(0.1)
+ self.endz_entry.setWrapping(True)
- grid1.addWidget(endzlabel, 6, 0)
- grid1.addWidget(self.gendz_entry, 6, 1)
+ grid1.addWidget(endz_label, 6, 0)
+ grid1.addWidget(self.endz_entry, 6, 1)
# Feedrate X-Y
frlabel = QtWidgets.QLabel('%s:' % _('Feedrate X-Y'))
@@ -4207,14 +4207,14 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
"It is useful only for Marlin,\n"
"ignore for any other cases.")
)
- self.cncfeedrate_rapid_entry = FCDoubleSpinner()
- self.cncfeedrate_rapid_entry.set_range(0, 99999.9999)
- self.cncfeedrate_rapid_entry.set_precision(self.decimals)
- self.cncfeedrate_rapid_entry.setSingleStep(0.1)
- self.cncfeedrate_rapid_entry.setWrapping(True)
+ self.feedrate_rapid_entry = FCDoubleSpinner()
+ self.feedrate_rapid_entry.set_range(0, 99999.9999)
+ self.feedrate_rapid_entry.set_precision(self.decimals)
+ self.feedrate_rapid_entry.setSingleStep(0.1)
+ self.feedrate_rapid_entry.setWrapping(True)
grid1.addWidget(fr_rapid_label, 4, 0)
- grid1.addWidget(self.cncfeedrate_rapid_entry, 4, 1)
+ grid1.addWidget(self.feedrate_rapid_entry, 4, 1)
# End move extra cut
self.extracut_cb = FCCheckBox('%s' % _('Re-cut'))
diff --git a/preprocessors/Berta_CNC.py b/preprocessors/Berta_CNC.py
index 784f0cd0..6da9d5d6 100644
--- a/preprocessors/Berta_CNC.py
+++ b/preprocessors/Berta_CNC.py
@@ -22,7 +22,7 @@ class Berta_CNC(FlatCAMPostProc):
def start_code(self, p):
units = ' ' + str(p['units']).lower()
coords_xy = p['xy_toolchange']
- gcode = ''
+ gcode = '(This preprocessor is used with a BERTA CNC router.)\n\n'
xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
@@ -80,7 +80,7 @@ class Berta_CNC(FlatCAMPostProc):
gcode += 'G54\n'
gcode += 'G0\n'
gcode += '(Berta)\n'
- gcode += 'G94\n'
+ gcode += 'G94'
return gcode
diff --git a/preprocessors/grbl_laser.py b/preprocessors/GRBL_laser.py
similarity index 92%
rename from preprocessors/grbl_laser.py
rename to preprocessors/GRBL_laser.py
index a3f4da7d..6c7a7c34 100644
--- a/preprocessors/grbl_laser.py
+++ b/preprocessors/GRBL_laser.py
@@ -12,7 +12,7 @@ from FlatCAMPostProc import *
# is compatible with almost any version of Grbl.
-class grbl_laser(FlatCAMPostProc):
+class GRBL_laser(FlatCAMPostProc):
include_header = True
coordinate_format = "%.*f"
@@ -20,7 +20,8 @@ class grbl_laser(FlatCAMPostProc):
def start_code(self, p):
units = ' ' + str(p['units']).lower()
- gcode = ''
+ gcode = '(This preprocessor is used with a motion controller loaded with GRBL firmware. )\n'
+ gcode += '(It is for the case when it is used together with a LASER connected on the SPINDLE connector.)\n\n'
xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
@@ -55,7 +56,7 @@ class grbl_laser(FlatCAMPostProc):
return ''
def lift_code(self, p):
- return 'M05 S0'
+ return 'M5'
def down_code(self, p):
sdir = {'CW': 'M03', 'CCW': 'M04'}[p.spindledir]
@@ -68,7 +69,7 @@ class grbl_laser(FlatCAMPostProc):
return ''
def up_to_zero_code(self, p):
- return 'M05'
+ return 'M5'
def position_code(self, p):
return ('X' + self.coordinate_format + ' Y' + self.coordinate_format) % \
@@ -106,4 +107,4 @@ class grbl_laser(FlatCAMPostProc):
return ''
def spindle_stop_code(self, p):
- return 'M05'
+ return 'M5'
diff --git a/preprocessors/ISEL_CNC.py b/preprocessors/ISEL_CNC.py
index 7753669c..c32b4272 100644
--- a/preprocessors/ISEL_CNC.py
+++ b/preprocessors/ISEL_CNC.py
@@ -17,7 +17,7 @@ class ISEL_CNC(FlatCAMPostProc):
def start_code(self, p):
units = ' ' + str(p['units']).lower()
coords_xy = p['xy_toolchange']
- gcode = ''
+ gcode = '(This preprocessor is used with a ISEL CNC router.)\n\n'
xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
diff --git a/preprocessors/ISEL_ICP_CNC.py b/preprocessors/ISEL_ICP_CNC.py
index 5898437e..ca820d8f 100644
--- a/preprocessors/ISEL_ICP_CNC.py
+++ b/preprocessors/ISEL_ICP_CNC.py
@@ -15,7 +15,7 @@ class ISEL_ICP_CNC(FlatCAMPostProc):
def start_code(self, p):
units = ' ' + str(p['units']).lower()
coords_xy = p['xy_toolchange']
- gcode = ''
+ gcode = '; This preprocessor is used with a ISEL ICP CNC router.\n\n'
xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
diff --git a/preprocessors/Marlin.py b/preprocessors/Marlin.py
index 65428e8f..128d1937 100644
--- a/preprocessors/Marlin.py
+++ b/preprocessors/Marlin.py
@@ -66,8 +66,7 @@ class Marlin(FlatCAMPostProc):
gcode += ';Spindle Speed: ' + str(p['spindlespeed']) + ' RPM' + '\n' + '\n'
gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n"
- gcode += 'G90\n'
- gcode += 'G94\n'
+ gcode += 'G90'
return gcode
@@ -219,8 +218,11 @@ G0 Z{z_toolchange}
return sdir
def dwell_code(self, p):
+ gcode = 'G4 P' + str(p.dwelltime)
if p.dwelltime:
- return 'G4 P' + str(p.dwelltime)
+ return gcode
def spindle_stop_code(self, p):
- return 'M5'
+ gcode = 'M400\n'
+ gcode += 'M5'
+ return gcode
diff --git a/preprocessors/Marlin_laser_use_FAN_pin.py b/preprocessors/Marlin_laser_use_FAN_pin.py
new file mode 100644
index 00000000..36d958a4
--- /dev/null
+++ b/preprocessors/Marlin_laser_use_FAN_pin.py
@@ -0,0 +1,120 @@
+# ##########################################################
+# FlatCAM: 2D Post-processing for Manufacturing #
+# Website: http://flatcam.org #
+# File Author: Marius Adrian Stanciu (c) #
+# Date: 8-Feb-2020 #
+# License: MIT Licence #
+# ##########################################################
+
+from FlatCAMPostProc import *
+
+
+class Marlin_laser_use_FAN_pin(FlatCAMPostProc):
+
+ include_header = True
+ coordinate_format = "%.*f"
+ feedrate_format = '%.*f'
+ feedrate_rapid_format = feedrate_format
+
+ def start_code(self, p):
+ units = ' ' + str(p['units']).lower()
+ coords_xy = p['xy_toolchange']
+ gcode = ';This preprocessor is used with a motion controller loaded with MARLIN firmware.\n'
+ gcode += ';It is for the case when it is used together with a LASER connected on one of the FAN pins.\n\n'
+
+ xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
+ xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
+ ymin = '%.*f' % (p.coords_decimals, p['options']['ymin'])
+ ymax = '%.*f' % (p.coords_decimals, p['options']['ymax'])
+
+ gcode += ';Feedrate: ' + str(p['feedrate']) + units + '/min' + '\n'
+ gcode += ';Feedrate rapids: ' + str(p['feedrate_rapid']) + units + '/min' + '\n\n'
+
+ gcode += ';Z Focus: ' + str(p['z_move']) + units + '\n'
+
+ gcode += ';Steps per circle: ' + str(p['steps_per_circle']) + '\n'
+
+ if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
+ gcode += ';Preprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n'
+ else:
+ gcode += ';Preprocessor Geometry: ' + str(p['pp_geometry_name']) + '\n' + '\n'
+
+ gcode += ';X range: ' + '{: >9s}'.format(xmin) + ' ... ' + '{: >9s}'.format(xmax) + ' ' + units + '\n'
+ gcode += ';Y range: ' + '{: >9s}'.format(ymin) + ' ... ' + '{: >9s}'.format(ymax) + ' ' + units + '\n\n'
+
+ gcode += ';Laser Power (Spindle Speed): ' + str(p['spindlespeed']) + '\n' + '\n'
+
+ gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n"
+ gcode += 'G90'
+
+ return gcode
+
+ def startz_code(self, p):
+ if p.startz is not None:
+ return 'G0 Z' + self.coordinate_format % (p.coords_decimals, p.z_move)
+ else:
+ return ''
+
+ def lift_code(self, p):
+ gcode = 'M400\n'
+ gcode += 'M107'
+ return gcode
+
+ def down_code(self, p):
+ if p.spindlespeed:
+ return '%s S%s' % ('M106', str(p.spindlespeed))
+ else:
+ return 'M106'
+
+ def toolchange_code(self, p):
+ return ''
+
+ def up_to_zero_code(self, p):
+ gcode = 'M400\n'
+ gcode += 'M107'
+ return gcode
+
+ def position_code(self, p):
+ return ('X' + self.coordinate_format + ' Y' + self.coordinate_format) % \
+ (p.coords_decimals, p.x, p.coords_decimals, p.y)
+
+ def rapid_code(self, p):
+ return ('G0 ' + self.position_code(p)).format(**p) + " " + self.feedrate_rapid_code(p)
+
+ def linear_code(self, p):
+ return ('G1 ' + self.position_code(p)).format(**p) + " " + self.inline_feedrate_code(p)
+
+ def end_code(self, p):
+ coords_xy = p['xy_toolchange']
+ gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + " " + self.feedrate_rapid_code(p) + "\n")
+
+ if coords_xy is not None:
+ gcode += 'G0 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + " " + self.feedrate_rapid_code(p) + "\n"
+
+ return gcode
+
+ def feedrate_code(self, p):
+ return 'G1 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
+
+ def z_feedrate_code(self, p):
+ return 'G1 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate))
+
+ def inline_feedrate_code(self, p):
+ return 'F' + self.feedrate_format % (p.fr_decimals, p.feedrate)
+
+ def feedrate_rapid_code(self, p):
+ return 'F' + self.feedrate_rapid_format % (p.fr_decimals, p.feedrate_rapid)
+
+ def spindle_code(self, p):
+ if p.spindlespeed:
+ return '%s S%s' % ('M106 ', str(p.spindlespeed))
+ else:
+ return 'M106'
+
+ def dwell_code(self, p):
+ return ''
+
+ def spindle_stop_code(self, p):
+ gcode = 'M400\n'
+ gcode += 'M107'
+ return gcode
diff --git a/preprocessors/Marlin_laser.py b/preprocessors/Marlin_laser_use_Spindle_pin.py
similarity index 93%
rename from preprocessors/Marlin_laser.py
rename to preprocessors/Marlin_laser_use_Spindle_pin.py
index e67e9bb5..a1f7fb1e 100644
--- a/preprocessors/Marlin_laser.py
+++ b/preprocessors/Marlin_laser_use_Spindle_pin.py
@@ -9,7 +9,7 @@
from FlatCAMPostProc import *
-class Marlin_laser(FlatCAMPostProc):
+class Marlin_laser_use_Spindle_pin(FlatCAMPostProc):
include_header = True
coordinate_format = "%.*f"
@@ -19,7 +19,8 @@ class Marlin_laser(FlatCAMPostProc):
def start_code(self, p):
units = ' ' + str(p['units']).lower()
coords_xy = p['xy_toolchange']
- gcode = ''
+ gcode = ';This preprocessor is used with a motion controller loaded with MARLIN firmware.\n'
+ gcode += ';It is for the case when it is used together with a LASER connected on the SPINDLE connector.\n\n'
xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
@@ -44,8 +45,7 @@ class Marlin_laser(FlatCAMPostProc):
gcode += ';Laser Power (Spindle Speed): ' + str(p['spindlespeed']) + '\n' + '\n'
gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n"
- gcode += 'G90\n'
- gcode += 'G94'
+ gcode += 'G90'
return gcode
@@ -57,7 +57,7 @@ class Marlin_laser(FlatCAMPostProc):
def lift_code(self, p):
gcode = 'M400\n'
- gcode += 'M5 S0'
+ gcode += 'M5'
return gcode
def down_code(self, p):
diff --git a/preprocessors/Repetier.py b/preprocessors/Repetier.py
index c149513c..fa760dfd 100644
--- a/preprocessors/Repetier.py
+++ b/preprocessors/Repetier.py
@@ -19,7 +19,7 @@ class Repetier(FlatCAMPostProc):
def start_code(self, p):
units = ' ' + str(p['units']).lower()
coords_xy = p['xy_toolchange']
- gcode = ''
+ gcode = ';This preprocessor is used with a motion controller loaded with REPETIER firmware.\n\n'
xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
diff --git a/preprocessors/Toolchange_Probe_MACH3.py b/preprocessors/Toolchange_Probe_MACH3.py
index 38371154..424848f8 100644
--- a/preprocessors/Toolchange_Probe_MACH3.py
+++ b/preprocessors/Toolchange_Probe_MACH3.py
@@ -18,7 +18,7 @@ class Toolchange_Probe_MACH3(FlatCAMPostProc):
def start_code(self, p):
units = ' ' + str(p['units']).lower()
coords_xy = p['xy_toolchange']
- gcode = ''
+ gcode = '(This preprocessor is used with MACH3 with probing height.)\n\n'
xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
diff --git a/preprocessors/default.py b/preprocessors/default.py
index e57ed812..ce4bd85b 100644
--- a/preprocessors/default.py
+++ b/preprocessors/default.py
@@ -18,7 +18,8 @@ class default(FlatCAMPostProc):
def start_code(self, p):
units = ' ' + str(p['units']).lower()
coords_xy = p['xy_toolchange']
- gcode = ''
+ gcode = '(This preprocessor is the default preprocessor used by FlatCAM.)\n'
+ gcode += '(It is made to work with MACH3 compatible motion controllers.)\n\n'
xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
@@ -66,7 +67,7 @@ class default(FlatCAMPostProc):
gcode += ('G20\n' if p.units.upper() == 'IN' else 'G21\n')
gcode += 'G90\n'
- gcode += 'G94\n'
+ gcode += 'G94'
return gcode
diff --git a/preprocessors/grbl_11.py b/preprocessors/grbl_11.py
index 9a53c0ab..a8a03b88 100644
--- a/preprocessors/grbl_11.py
+++ b/preprocessors/grbl_11.py
@@ -18,7 +18,8 @@ class grbl_11(FlatCAMPostProc):
def start_code(self, p):
units = ' ' + str(p['units']).lower()
coords_xy = p['xy_toolchange']
- gcode = ''
+ gcode = '(This preprocessor is used with a motion controller loaded with GRBL firmware.)\n'
+ gcode += '(It is configured to be compatible with almost any version of GRBL firmware.)\n\n'
xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
From d33505096c518f2e926b62ae1120dfea67b375d9 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 8 Feb 2020 22:38:08 +0200
Subject: [PATCH 074/209] - modified the Excellon GCode generation so now it
can use multi depth drilling; modified the preprocessors to show the number
of passes
---
FlatCAMApp.py | 4 +
FlatCAMObj.py | 18 ++-
README.md | 1 +
camlib.py | 141 ++++++++++++++++++------
flatcamGUI/PreferencesUI.py | 80 ++++++++++----
preprocessors/ISEL_CNC.py | 7 +-
preprocessors/ISEL_ICP_CNC.py | 8 +-
preprocessors/Marlin.py | 7 +-
preprocessors/Repetier.py | 7 +-
preprocessors/Toolchange_Custom.py | 7 +-
preprocessors/Toolchange_Probe_MACH3.py | 7 +-
preprocessors/Toolchange_manual.py | 7 +-
preprocessors/default.py | 7 +-
preprocessors/grbl_11.py | 7 +-
preprocessors/line_xyz.py | 7 +-
15 files changed, 215 insertions(+), 100 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 36c06ba9..8fe6897a 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -633,6 +633,8 @@ class App(QtCore.QObject):
# Excellon Options
"excellon_drillz": -1.7,
+ "excellon_multidepth": False,
+ "excellon_depthperpass": 0.7,
"excellon_travelz": 2,
"excellon_endz": 0.5,
"excellon_feedrate": 300,
@@ -1289,6 +1291,8 @@ class App(QtCore.QObject):
# Excellon Options
"excellon_drillz": self.ui.excellon_defaults_form.excellon_opt_group.cutz_entry,
+ "excellon_multidepth": self.ui.excellon_defaults_form.excellon_opt_group.mpass_cb,
+ "excellon_depthperpass":self.ui.excellon_defaults_form.excellon_opt_group.maxdepth_entry,
"excellon_travelz": self.ui.excellon_defaults_form.excellon_opt_group.travelz_entry,
"excellon_endz": self.ui.excellon_defaults_form.excellon_opt_group.endz_entry,
"excellon_feedrate": self.ui.excellon_defaults_form.excellon_opt_group.feedrate_z_entry,
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index f7faf045..6567993f 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -2317,6 +2317,8 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
"plot": True,
"solid": False,
"drillz": -0.1,
+ "multidepth": False,
+ "depthperpass": 0.7,
"travelz": 0.1,
"feedrate": 5.0,
"feedrate_rapid": 5.0,
@@ -2803,6 +2805,8 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
"plot": self.ui.plot_cb,
"solid": self.ui.solid_cb,
"drillz": self.ui.cutz_entry,
+ "multidepth": self.ui.mpass_cb,
+ "depthperpass": self.ui.maxdepth_entry,
"travelz": self.ui.travelz_entry,
"feedrate": self.ui.feedrate_z_entry,
"feedrate_rapid": self.ui.feedrate_rapid_entry,
@@ -2983,16 +2987,16 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.ui.extracut_cb.show()
self.ui.e_cut_entry.show()
- if 'laser' not in self.ui.pp_excellon_name_cb.get_value().lower():
- self.ui.mpass_cb.show()
- self.ui.maxdepth_entry.show()
+ # if 'laser' not in self.ui.pp_excellon_name_cb.get_value().lower():
+ # self.ui.mpass_cb.show()
+ # self.ui.maxdepth_entry.show()
else:
self.ui.mill_type_label.hide()
self.ui.mill_type_radio.hide()
self.ui.mill_dia_label.hide()
self.ui.mill_dia_entry.hide()
- self.ui.mpass_cb.hide()
- self.ui.maxdepth_entry.hide()
+ # self.ui.mpass_cb.hide()
+ # self.ui.maxdepth_entry.hide()
self.ui.frxylabel.hide()
self.ui.xyfeedrate_entry.hide()
self.ui.extracut_cb.hide()
@@ -3580,6 +3584,10 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
job_obj.options['ppname_e'] = pp_excellon_name
job_obj.z_cut = float(self.options["drillz"])
+
+ job_obj.multidepth = self.options["multidepth"]
+ job_obj.z_depthpercut = self.options["depthperpass"]
+
job_obj.tool_offset = self.tool_offset
job_obj.z_move = float(self.options["travelz"])
job_obj.feedrate = float(self.options["feedrate"])
diff --git a/README.md b/README.md
index f727c607..434c81bb 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ CAD program, and create G-Code for Isolation routing.
- added a new preprocessor for using laser on a Marlin 3D printer named 'Marlin_laser_use_Spindle_pin'
- modified the Geometry UI when using laser preprocessors
- added a new preprocessor file for using laser on a Marlin motion controller but with the laser connected to one of the FAN pins, named 'Marlin_laser_use_FAN_pin'
+- modified the Excellon GCode generation so now it can use multi depth drilling; modified the preprocessors to show the number of passes
5.02.2020
diff --git a/camlib.py b/camlib.py
index e3002d8a..2c62d018 100644
--- a/camlib.py
+++ b/camlib.py
@@ -2230,7 +2230,7 @@ class CNCjob(Geometry):
z_cut=-0.002, z_move=0.1,
feedrate=3.0, feedrate_z=3.0, feedrate_rapid=3.0, feedrate_probe=3.0,
pp_geometry_name='default', pp_excellon_name='default',
- depthpercut=0.1,z_pdepth=-0.02,
+ depthpercut=0.1, z_pdepth=-0.02,
spindlespeed=None, spindledir='CW', dwell=True, dwelltime=1000,
toolchangez=0.787402, toolchange_xy=[0.0, 0.0],
endz=2.0,
@@ -2265,7 +2265,10 @@ class CNCjob(Geometry):
self.toolC = tooldia
+ self.startz = None
self.z_end = endz
+
+ self.multidepth = False
self.z_depthpercut = depthpercut
self.unitcode = {"IN": "G20", "MM": "G21"}
@@ -2566,8 +2569,6 @@ class CNCjob(Geometry):
[it[0], it[1], drill_no, slot_no]
)
- print(self.options['Tools_in_use'])
-
self.app.inform.emit(_("Creating a list of points to drill..."))
# Points (Group by tool)
points = dict()
@@ -2777,18 +2778,43 @@ class CNCjob(Geometry):
locy = locations[k][1]
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
- gcode += self.doformat(p.down_code, x=locx, y=locy)
- measured_down_distance += abs(self.z_cut) + abs(self.z_move)
+ if self.multidepth and abs(self.z_cut) > abs(self.z_depthpercut):
+ doc = deepcopy(self.z_cut)
+ self.z_cut = 0.0
+
+ while abs(self.z_cut) < abs(doc):
+
+ self.z_cut -= self.z_depthpercut
+ if abs(doc) < abs(self.z_cut) < (abs(doc) + self.z_depthpercut):
+ self.z_cut = doc
+ gcode += self.doformat(p.down_code, x=locx, y=locy)
+
+ measured_down_distance += abs(self.z_cut) + abs(self.z_move)
+
+ if self.f_retract is False:
+ gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy)
+ measured_up_to_zero_distance += abs(self.z_cut)
+ measured_lift_distance += abs(self.z_move)
+ else:
+ measured_lift_distance += abs(self.z_cut) + abs(self.z_move)
+
+ gcode += self.doformat(p.lift_code, x=locx, y=locy)
- if self.f_retract is False:
- gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy)
- measured_up_to_zero_distance += abs(self.z_cut)
- measured_lift_distance += abs(self.z_move)
else:
- measured_lift_distance += abs(self.z_cut) + abs(self.z_move)
+ gcode += self.doformat(p.down_code, x=locx, y=locy)
+
+ measured_down_distance += abs(self.z_cut) + abs(self.z_move)
+
+ if self.f_retract is False:
+ gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy)
+ measured_up_to_zero_distance += abs(self.z_cut)
+ measured_lift_distance += abs(self.z_move)
+ else:
+ measured_lift_distance += abs(self.z_cut) + abs(self.z_move)
+
+ gcode += self.doformat(p.lift_code, x=locx, y=locy)
- gcode += self.doformat(p.lift_code, x=locx, y=locy)
measured_distance += abs(distance_euclidian(locx, locy, self.oldx, self.oldy))
self.oldx = locx
self.oldy = locy
@@ -2920,18 +2946,43 @@ class CNCjob(Geometry):
locy = locations[k][1]
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
- gcode += self.doformat(p.down_code, x=locx, y=locy)
- measured_down_distance += abs(self.z_cut) + abs(self.z_move)
+ if self.multidepth and abs(self.z_cut) > abs(self.z_depthpercut):
+ doc = deepcopy(self.z_cut)
+ self.z_cut = 0.0
+
+ while abs(self.z_cut) < abs(doc):
+
+ self.z_cut -= self.z_depthpercut
+ if abs(doc) < abs(self.z_cut) < (abs(doc) + self.z_depthpercut):
+ self.z_cut = doc
+ gcode += self.doformat(p.down_code, x=locx, y=locy)
+
+ measured_down_distance += abs(self.z_cut) + abs(self.z_move)
+
+ if self.f_retract is False:
+ gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy)
+ measured_up_to_zero_distance += abs(self.z_cut)
+ measured_lift_distance += abs(self.z_move)
+ else:
+ measured_lift_distance += abs(self.z_cut) + abs(self.z_move)
+
+ gcode += self.doformat(p.lift_code, x=locx, y=locy)
- if self.f_retract is False:
- gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy)
- measured_up_to_zero_distance += abs(self.z_cut)
- measured_lift_distance += abs(self.z_move)
else:
- measured_lift_distance += abs(self.z_cut) + abs(self.z_move)
+ gcode += self.doformat(p.down_code, x=locx, y=locy)
+
+ measured_down_distance += abs(self.z_cut) + abs(self.z_move)
+
+ if self.f_retract is False:
+ gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy)
+ measured_up_to_zero_distance += abs(self.z_cut)
+ measured_lift_distance += abs(self.z_move)
+ else:
+ measured_lift_distance += abs(self.z_cut) + abs(self.z_move)
+
+ gcode += self.doformat(p.lift_code, x=locx, y=locy)
- gcode += self.doformat(p.lift_code, x=locx, y=locy)
measured_distance += abs(distance_euclidian(locx, locy, self.oldx, self.oldy))
self.oldx = locx
self.oldy = locy
@@ -3023,22 +3074,50 @@ class CNCjob(Geometry):
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
- gcode += self.doformat(p.rapid_code, x=point[0], y=point[1])
- gcode += self.doformat(p.down_code, x=point[0], y=point[1])
+ locx = point[0]
+ locy = point[1]
- measured_down_distance += abs(self.z_cut) + abs(self.z_move)
+ gcode += self.doformat(p.rapid_code, x=locx, y=locy)
+
+ if self.multidepth and abs(self.z_cut) > abs(self.z_depthpercut):
+ doc = deepcopy(self.z_cut)
+ self.z_cut = 0.0
+
+ while abs(self.z_cut) < abs(doc):
+
+ self.z_cut -= self.z_depthpercut
+ if abs(doc) < abs(self.z_cut) < (abs(doc) + self.z_depthpercut):
+ self.z_cut = doc
+ gcode += self.doformat(p.down_code, x=locx, y=locy)
+
+ measured_down_distance += abs(self.z_cut) + abs(self.z_move)
+
+ if self.f_retract is False:
+ gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy)
+ measured_up_to_zero_distance += abs(self.z_cut)
+ measured_lift_distance += abs(self.z_move)
+ else:
+ measured_lift_distance += abs(self.z_cut) + abs(self.z_move)
+
+ gcode += self.doformat(p.lift_code, x=locx, y=locy)
- if self.f_retract is False:
- gcode += self.doformat(p.up_to_zero_code, x=point[0], y=point[1])
- measured_up_to_zero_distance += abs(self.z_cut)
- measured_lift_distance += abs(self.z_move)
else:
- measured_lift_distance += abs(self.z_cut) + abs(self.z_move)
+ gcode += self.doformat(p.down_code, x=locx, y=locy)
- gcode += self.doformat(p.lift_code, x=point[0], y=point[1])
- measured_distance += abs(distance_euclidian(point[0], point[1], self.oldx, self.oldy))
- self.oldx = point[0]
- self.oldy = point[1]
+ measured_down_distance += abs(self.z_cut) + abs(self.z_move)
+
+ if self.f_retract is False:
+ gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy)
+ measured_up_to_zero_distance += abs(self.z_cut)
+ measured_lift_distance += abs(self.z_move)
+ else:
+ measured_lift_distance += abs(self.z_cut) + abs(self.z_move)
+
+ gcode += self.doformat(p.lift_code, x=locx, y=locy)
+
+ measured_distance += abs(distance_euclidian(locx, locy, self.oldx, self.oldy))
+ self.oldx = locx
+ self.oldy = locy
loc_nr += 1
disp_number = int(np.interp(loc_nr, [0, geo_len], [0, 100]))
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index 33c23ab3..b003b71c 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -3074,7 +3074,7 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
_("Drill depth (negative)\n"
"below the copper surface.")
)
- grid2.addWidget(cutzlabel, 0, 0)
+
self.cutz_entry = FCDoubleSpinner()
if machinist_setting == 0:
@@ -3084,15 +3084,38 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
self.cutz_entry.setSingleStep(0.1)
self.cutz_entry.set_precision(self.decimals)
+
+ grid2.addWidget(cutzlabel, 0, 0)
grid2.addWidget(self.cutz_entry, 0, 1)
+ # Multi-Depth
+ self.mpass_cb = FCCheckBox('%s:' % _("Multi-Depth"))
+ self.mpass_cb.setToolTip(
+ _(
+ "Use multiple passes to limit\n"
+ "the cut depth in each pass. Will\n"
+ "cut multiple times until Cut Z is\n"
+ "reached."
+ )
+ )
+
+ self.maxdepth_entry = FCDoubleSpinner()
+ self.maxdepth_entry.set_precision(self.decimals)
+ self.maxdepth_entry.set_range(0, 9999.9999)
+ self.maxdepth_entry.setSingleStep(0.1)
+
+ self.maxdepth_entry.setToolTip(_("Depth of each pass (positive)."))
+
+ grid2.addWidget(self.mpass_cb, 1, 0)
+ grid2.addWidget(self.maxdepth_entry, 1, 1)
+
# Travel Z
travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z'))
travelzlabel.setToolTip(
_("Tool height when travelling\n"
"across the XY plane.")
)
- grid2.addWidget(travelzlabel, 1, 0)
+
self.travelz_entry = FCDoubleSpinner()
self.travelz_entry.set_precision(self.decimals)
@@ -3101,7 +3124,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
else:
self.travelz_entry.set_range(-9999.9999, 9999.9999)
- grid2.addWidget(self.travelz_entry, 1, 1)
+ grid2.addWidget(travelzlabel, 2, 0)
+ grid2.addWidget(self.travelz_entry, 2, 1)
# Tool change:
self.toolchange_cb = FCCheckBox('%s' % _("Tool change"))
@@ -3109,14 +3133,15 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
_("Include tool-change sequence\n"
"in G-Code (Pause for tool change).")
)
- grid2.addWidget(self.toolchange_cb, 2, 0, 1, 2)
+ grid2.addWidget(self.toolchange_cb, 3, 0, 1, 2)
+ # Tool Change Z
toolchangezlabel = QtWidgets.QLabel('%s:' % _('Toolchange Z'))
toolchangezlabel.setToolTip(
_("Z-axis position (height) for\n"
"tool change.")
)
- grid2.addWidget(toolchangezlabel, 3, 0)
+
self.toolchangez_entry = FCDoubleSpinner()
self.toolchangez_entry.set_precision(self.decimals)
@@ -3125,7 +3150,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
else:
self.toolchangez_entry.set_range(-9999.9999, 9999.9999)
- grid2.addWidget(self.toolchangez_entry, 3, 1)
+ grid2.addWidget(toolchangezlabel, 4, 0)
+ grid2.addWidget(self.toolchangez_entry, 4, 1)
# End Move Z
endz_label = QtWidgets.QLabel('%s:' % _('End move Z'))
@@ -3141,8 +3167,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
else:
self.endz_entry.set_range(-9999.9999, 9999.9999)
- grid2.addWidget(endz_label, 4, 0)
- grid2.addWidget(self.endz_entry, 4, 1)
+ grid2.addWidget(endz_label, 5, 0)
+ grid2.addWidget(self.endz_entry, 5, 1)
# Feedrate Z
frlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z'))
@@ -3156,8 +3182,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
self.feedrate_z_entry.set_precision(self.decimals)
self.feedrate_z_entry.set_range(0, 99999.9999)
- grid2.addWidget(frlabel, 5, 0)
- grid2.addWidget(self.feedrate_z_entry, 5, 1)
+ grid2.addWidget(frlabel, 6, 0)
+ grid2.addWidget(self.feedrate_z_entry, 6, 1)
# Spindle speed
spdlabel = QtWidgets.QLabel('%s:' % _('Spindle Speed'))
@@ -3165,11 +3191,13 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
_("Speed of the spindle\n"
"in RPM (optional)")
)
- grid2.addWidget(spdlabel, 6, 0)
+
self.spindlespeed_entry = FCSpinner()
self.spindlespeed_entry.set_range(0, 1000000)
self.spindlespeed_entry.setSingleStep(100)
- grid2.addWidget(self.spindlespeed_entry, 6, 1)
+
+ grid2.addWidget(spdlabel, 10, 0)
+ grid2.addWidget(self.spindlespeed_entry, 10, 1)
# Dwell
self.dwell_cb = FCCheckBox('%s' % _('Enable Dwell'))
@@ -3177,16 +3205,18 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
_("Pause to allow the spindle to reach its\n"
"speed before cutting.")
)
- grid2.addWidget(self.dwell_cb, 7, 0, 1, 2)
+ grid2.addWidget(self.dwell_cb, 11, 0, 1, 2)
+
+ # Dwell Time
dwelltime = QtWidgets.QLabel('%s:' % _('Duration'))
dwelltime.setToolTip(_("Number of time units for spindle to dwell."))
self.dwelltime_entry = FCDoubleSpinner()
self.dwelltime_entry.set_precision(self.decimals)
self.dwelltime_entry.set_range(0, 99999.9999)
- grid2.addWidget(dwelltime, 8, 0)
- grid2.addWidget(self.dwelltime_entry, 8, 1)
+ grid2.addWidget(dwelltime, 12, 0)
+ grid2.addWidget(self.dwelltime_entry, 12, 1)
self.ois_dwell_exc = OptionalInputSection(self.dwell_cb, [self.dwelltime_entry])
@@ -3196,10 +3226,12 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
_("The preprocessor JSON file that dictates\n"
"Gcode output.")
)
- grid2.addWidget(pp_excellon_label, 9, 0)
+
self.pp_excellon_name_cb = FCComboBox()
self.pp_excellon_name_cb.setFocusPolicy(Qt.StrongFocus)
- grid2.addWidget(self.pp_excellon_name_cb, 9, 1)
+
+ grid2.addWidget(pp_excellon_label, 14, 0)
+ grid2.addWidget(self.pp_excellon_name_cb, 14, 1)
# ### Choose what to use for Gcode creation: Drills, Slots or Both
excellon_gcode_type_label = QtWidgets.QLabel('%s' % _('Gcode'))
@@ -3212,8 +3244,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
self.excellon_gcode_type_radio = RadioSet([{'label': 'Drills', 'value': 'drills'},
{'label': 'Slots', 'value': 'slots'},
{'label': 'Both', 'value': 'both'}])
- grid2.addWidget(excellon_gcode_type_label, 10, 0)
- grid2.addWidget(self.excellon_gcode_type_radio, 10, 1)
+ grid2.addWidget(excellon_gcode_type_label, 15, 0)
+ grid2.addWidget(self.excellon_gcode_type_radio, 15, 1)
# until I decide to implement this feature those remain disabled
excellon_gcode_type_label.hide()
@@ -3224,7 +3256,7 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
self.mill_hole_label.setToolTip(
_("Create Geometry for milling holes.")
)
- grid2.addWidget(self.mill_hole_label, 11, 0, 1, 2)
+ grid2.addWidget(self.mill_hole_label, 16, 0, 1, 2)
tdlabel = QtWidgets.QLabel('%s:' % _('Drill Tool dia'))
tdlabel.setToolTip(
@@ -3234,8 +3266,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
self.tooldia_entry.set_precision(self.decimals)
self.tooldia_entry.set_range(0, 999.9999)
- grid2.addWidget(tdlabel, 12, 0)
- grid2.addWidget(self.tooldia_entry, 12, 1)
+ grid2.addWidget(tdlabel, 18, 0)
+ grid2.addWidget(self.tooldia_entry, 18, 1)
stdlabel = QtWidgets.QLabel('%s:' % _('Slot Tool dia'))
stdlabel.setToolTip(
@@ -3246,8 +3278,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
self.slot_tooldia_entry.set_precision(self.decimals)
self.slot_tooldia_entry.set_range(0, 999.9999)
- grid2.addWidget(stdlabel, 13, 0)
- grid2.addWidget(self.slot_tooldia_entry, 13, 1)
+ grid2.addWidget(stdlabel, 21, 0)
+ grid2.addWidget(self.slot_tooldia_entry, 21, 1)
self.layout.addStretch()
diff --git a/preprocessors/ISEL_CNC.py b/preprocessors/ISEL_CNC.py
index c32b4272..2e20c06e 100644
--- a/preprocessors/ISEL_CNC.py
+++ b/preprocessors/ISEL_CNC.py
@@ -35,10 +35,9 @@ class ISEL_CNC(FlatCAMPostProc):
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
- if str(p['options']['type']) == 'Geometry':
- if p['multidepth'] is True:
- gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ if p['multidepth'] is True:
+ gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
diff --git a/preprocessors/ISEL_ICP_CNC.py b/preprocessors/ISEL_ICP_CNC.py
index ca820d8f..92a08691 100644
--- a/preprocessors/ISEL_ICP_CNC.py
+++ b/preprocessors/ISEL_ICP_CNC.py
@@ -33,10 +33,10 @@ class ISEL_ICP_CNC(FlatCAMPostProc):
gcode += '\n'
gcode += '; Z_Cut: ' + str(p['z_cut']) + units + '\n'
- if str(p['options']['type']) == 'Geometry':
- if p['multidepth'] is True:
- gcode += '; DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + '\n'
+ if p['multidepth'] is True:
+ gcode += '; DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + '\n'
+
gcode += '; Z_Move: ' + str(p['z_move']) + units + '\n'
gcode += '; Z Toolchange: ' + str(p['z_toolchange']) + units + '\n'
if coords_xy is not None:
diff --git a/preprocessors/Marlin.py b/preprocessors/Marlin.py
index 128d1937..d5144d59 100644
--- a/preprocessors/Marlin.py
+++ b/preprocessors/Marlin.py
@@ -37,10 +37,9 @@ class Marlin(FlatCAMPostProc):
gcode += ';Feedrate rapids: ' + str(p['feedrate_rapid']) + units + '/min' + '\n' + '\n'
gcode += ';Z_Cut: ' + str(p['z_cut']) + units + '\n'
- if str(p['options']['type']) == 'Geometry':
- if p['multidepth'] is True:
- gcode += ';DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + '\n'
+ if p['multidepth'] is True:
+ gcode += ';DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + '\n'
gcode += ';Z_Move: ' + str(p['z_move']) + units + '\n'
gcode += ';Z Toolchange: ' + str(p['z_toolchange']) + units + '\n'
diff --git a/preprocessors/Repetier.py b/preprocessors/Repetier.py
index fa760dfd..3d31a176 100644
--- a/preprocessors/Repetier.py
+++ b/preprocessors/Repetier.py
@@ -37,10 +37,9 @@ class Repetier(FlatCAMPostProc):
gcode += ';Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + '\n' + '\n'
gcode += ';Z_Cut: ' + str(p['z_cut']) + units + '\n'
- if str(p['options']['type']) == 'Geometry':
- if p['multidepth'] is True:
- gcode += ';DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + '\n'
+ if p['multidepth'] is True:
+ gcode += ';DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + '\n'
gcode += ';Z_Move: ' + str(p['z_move']) + units + '\n'
gcode += ';Z Toolchange: ' + str(p['z_toolchange']) + units + '\n'
diff --git a/preprocessors/Toolchange_Custom.py b/preprocessors/Toolchange_Custom.py
index ce6814b9..162defbb 100644
--- a/preprocessors/Toolchange_Custom.py
+++ b/preprocessors/Toolchange_Custom.py
@@ -36,10 +36,9 @@ class Toolchange_Custom(FlatCAMPostProc):
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
- if str(p['options']['type']) == 'Geometry':
- if p['multidepth'] is True:
- gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ if p['multidepth'] is True:
+ gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
diff --git a/preprocessors/Toolchange_Probe_MACH3.py b/preprocessors/Toolchange_Probe_MACH3.py
index 424848f8..3f0bb7c8 100644
--- a/preprocessors/Toolchange_Probe_MACH3.py
+++ b/preprocessors/Toolchange_Probe_MACH3.py
@@ -37,10 +37,9 @@ class Toolchange_Probe_MACH3(FlatCAMPostProc):
gcode += '(Feedrate Probe ' + str(p['feedrate_probe']) + units + '/min' + ')\n' + '\n'
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
- if str(p['options']['type']) == 'Geometry':
- if p['multidepth'] is True:
- gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ if p['multidepth'] is True:
+ gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
diff --git a/preprocessors/Toolchange_manual.py b/preprocessors/Toolchange_manual.py
index ef583a7c..f096ab25 100644
--- a/preprocessors/Toolchange_manual.py
+++ b/preprocessors/Toolchange_manual.py
@@ -36,10 +36,9 @@ class Toolchange_manual(FlatCAMPostProc):
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
- if str(p['options']['type']) == 'Geometry':
- if p['multidepth'] is True:
- gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ if p['multidepth'] is True:
+ gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
diff --git a/preprocessors/default.py b/preprocessors/default.py
index ce4bd85b..216ba98e 100644
--- a/preprocessors/default.py
+++ b/preprocessors/default.py
@@ -37,10 +37,9 @@ class default(FlatCAMPostProc):
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
- if str(p['options']['type']) == 'Geometry':
- if p['multidepth'] is True:
- gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ if p['multidepth'] is True:
+ gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
diff --git a/preprocessors/grbl_11.py b/preprocessors/grbl_11.py
index a8a03b88..9fc8676b 100644
--- a/preprocessors/grbl_11.py
+++ b/preprocessors/grbl_11.py
@@ -37,10 +37,9 @@ class grbl_11(FlatCAMPostProc):
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
- if str(p['options']['type']) == 'Geometry':
- if p['multidepth'] is True:
- gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ if p['multidepth'] is True:
+ gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
diff --git a/preprocessors/line_xyz.py b/preprocessors/line_xyz.py
index b3beacdd..b6130729 100644
--- a/preprocessors/line_xyz.py
+++ b/preprocessors/line_xyz.py
@@ -36,10 +36,9 @@ class line_xyz(FlatCAMPostProc):
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
- if str(p['options']['type']) == 'Geometry':
- if p['multidepth'] is True:
- gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ if p['multidepth'] is True:
+ gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
From c004c9082f9442ff7e123362f78324bd999a62c5 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 10 Feb 2020 04:00:34 +0200
Subject: [PATCH 075/209] - optimized the Paint and NCC Tools. When the Lines
type of painting/clearing is used, the lines will try to arrange themselves
on the direction that the lines length clearing the polygon are bigger
---
README.md | 4 +++
camlib.py | 84 ++++++++++++++++++++++++++++++++++++++-----------------
2 files changed, 63 insertions(+), 25 deletions(-)
diff --git a/README.md b/README.md
index 434c81bb..49619892 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+10.02.2020
+
+- optimized the Paint and NCC Tools. When the Lines type of painting/clearing is used, the lines will try to arrange themselves on the direction that the lines length clearing the polygon are bigger
+
8.02.2020
- added a new preprocessor for using laser on a Marlin 3D printer named 'Marlin_laser_use_Spindle_pin'
diff --git a/camlib.py b/camlib.py
index 2c62d018..165635b8 100644
--- a/camlib.py
+++ b/camlib.py
@@ -1445,37 +1445,71 @@ class Geometry(object):
log.debug("camlib.Geometry.clear_polygon3() --> Could not buffer the Polygon")
return None
- # First line
- try:
- y = top - tooldia / 1.99999999
- while y > bot + tooldia / 1.999999999:
- if self.app.abort_flag:
- # graceful abort requested by the user
- raise FlatCAMApp.GracefulException
+ # decide the direction of the lines
+ if abs(left - right) >= abs(top -bot):
+ # First line
+ try:
+ y = top - tooldia / 1.99999999
+ while y > bot + tooldia / 1.999999999:
+ if self.app.abort_flag:
+ # graceful abort requested by the user
+ raise FlatCAMApp.GracefulException
- # provide the app with a way to process the GUI events when in a blocking loop
- QtWidgets.QApplication.processEvents()
+ # provide the app with a way to process the GUI events when in a blocking loop
+ QtWidgets.QApplication.processEvents()
+ line = LineString([(left, y), (right, y)])
+ line = line.intersection(margin_poly)
+ lines_trimmed.append(line)
+ y -= tooldia * (1 - overlap)
+ if prog_plot:
+ self.plot_temp_shapes(line)
+ self.temp_shapes.redraw()
+
+ # Last line
+ y = bot + tooldia / 2
line = LineString([(left, y), (right, y)])
line = line.intersection(margin_poly)
- lines_trimmed.append(line)
- y -= tooldia * (1 - overlap)
- if prog_plot:
- self.plot_temp_shapes(line)
- self.temp_shapes.redraw()
- # Last line
- y = bot + tooldia / 2
- line = LineString([(left, y), (right, y)])
- line = line.intersection(margin_poly)
+ for ll in line:
+ lines_trimmed.append(ll)
+ if prog_plot:
+ self.plot_temp_shapes(line)
+ except Exception as e:
+ log.debug('camlib.Geometry.clear_polygon3() Processing poly --> %s' % str(e))
+ return None
+ else:
+ # First line
+ try:
+ x = left + tooldia / 1.99999999
+ while x < right - tooldia / 1.999999999:
+ if self.app.abort_flag:
+ # graceful abort requested by the user
+ raise FlatCAMApp.GracefulException
- for ll in line:
- lines_trimmed.append(ll)
- if prog_plot:
- self.plot_temp_shapes(line)
- except Exception as e:
- log.debug('camlib.Geometry.clear_polygon3() Processing poly --> %s' % str(e))
- return None
+ # provide the app with a way to process the GUI events when in a blocking loop
+ QtWidgets.QApplication.processEvents()
+
+ line = LineString([(x, top), (x, bot)])
+ line = line.intersection(margin_poly)
+ lines_trimmed.append(line)
+ x += tooldia * (1 - overlap)
+ if prog_plot:
+ self.plot_temp_shapes(line)
+ self.temp_shapes.redraw()
+
+ # Last line
+ x = right + tooldia / 2
+ line = LineString([(x, top), (x, bot)])
+ line = line.intersection(margin_poly)
+
+ for ll in line:
+ lines_trimmed.append(ll)
+ if prog_plot:
+ self.plot_temp_shapes(line)
+ except Exception as e:
+ log.debug('camlib.Geometry.clear_polygon3() Processing poly --> %s' % str(e))
+ return None
if prog_plot:
self.temp_shapes.redraw()
From 0807e9aaf12cbda4c59dd892f0fae59c5fdc3414 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 10 Feb 2020 04:28:46 +0200
Subject: [PATCH 076/209] - solved bug that made drilling with Marlin
preprocessor very slow
---
FlatCAMObj.py | 1 +
README.md | 1 +
2 files changed, 2 insertions(+)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 6567993f..da4a2a07 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -3591,6 +3591,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
job_obj.tool_offset = self.tool_offset
job_obj.z_move = float(self.options["travelz"])
job_obj.feedrate = float(self.options["feedrate"])
+ job_obj.z_feedrate = float(self.options["feedrate"])
job_obj.feedrate_rapid = float(self.options["feedrate_rapid"])
job_obj.spindlespeed = float(self.options["spindlespeed"]) if self.options["spindlespeed"] != 0 else None
diff --git a/README.md b/README.md
index 49619892..8baee38b 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
10.02.2020
- optimized the Paint and NCC Tools. When the Lines type of painting/clearing is used, the lines will try to arrange themselves on the direction that the lines length clearing the polygon are bigger
+- solved bug that made drilling with Marlin preprocessor very slow
8.02.2020
From e3be6ff22f1660537d95adcbb7183d500fd9d0f8 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 10 Feb 2020 04:30:32 +0200
Subject: [PATCH 077/209] - applied the fix for above bug to the TclCommand
Drillcncjob too
---
README.md | 1 +
tclCommands/TclCommandDrillcncjob.py | 3 +++
2 files changed, 4 insertions(+)
diff --git a/README.md b/README.md
index 8baee38b..1466cc4b 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- optimized the Paint and NCC Tools. When the Lines type of painting/clearing is used, the lines will try to arrange themselves on the direction that the lines length clearing the polygon are bigger
- solved bug that made drilling with Marlin preprocessor very slow
+- applied the fix for above bug to the TclCommand Drillcncjob too
8.02.2020
diff --git a/tclCommands/TclCommandDrillcncjob.py b/tclCommands/TclCommandDrillcncjob.py
index a815569c..a420f2ae 100644
--- a/tclCommands/TclCommandDrillcncjob.py
+++ b/tclCommands/TclCommandDrillcncjob.py
@@ -185,7 +185,10 @@ class TclCommandDrillcncjob(TclCommandSignaled):
opt_type = args["opt_type"] if "opt_type" in args and args["opt_type"] else 'B'
job_obj.z_move = args["travelz"] if "travelz" in args and args["travelz"] else obj.options["travelz"]
+
job_obj.feedrate = args["feedrate"] if "feedrate" in args and args["feedrate"] else obj.options["feedrate"]
+ job_obj.z_feedrate = args["feedrate"] if "feedrate" in args and args["feedrate"] else \
+ obj.options["feedrate"]
job_obj.feedrate_rapid = args["feedrate_rapid"] \
if "feedrate_rapid" in args and args["feedrate_rapid"] else obj.options["feedrate_rapid"]
From 82ab0d83d65f149dea2ab2f863487ea5241e8595 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 10 Feb 2020 12:27:49 +0200
Subject: [PATCH 078/209] - started a new way to clear the Gerber polygons
based on the 'follow' lines
---
README.md | 1 +
camlib.py | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 141 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 1466cc4b..bc8f6675 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ CAD program, and create G-Code for Isolation routing.
- optimized the Paint and NCC Tools. When the Lines type of painting/clearing is used, the lines will try to arrange themselves on the direction that the lines length clearing the polygon are bigger
- solved bug that made drilling with Marlin preprocessor very slow
- applied the fix for above bug to the TclCommand Drillcncjob too
+- started a new way to clear the Gerber polygons based on the 'follow' lines
8.02.2020
diff --git a/camlib.py b/camlib.py
index 165635b8..2fb8180e 100644
--- a/camlib.py
+++ b/camlib.py
@@ -1446,7 +1446,7 @@ class Geometry(object):
return None
# decide the direction of the lines
- if abs(left - right) >= abs(top -bot):
+ if abs(left - right) >= abs(top - bot):
# First line
try:
y = top - tooldia / 1.99999999
@@ -1562,6 +1562,145 @@ class Geometry(object):
return geoms
+ def fill_with_lines(self, line, aperture_size, tooldia, steps_per_circle, overlap=0.15, connect=True, contour=True,
+ prog_plot=False):
+ """
+ Creates geometry of lines inside a polygon for a tool to cover
+ the whole area.
+
+ This algorithm draws parallel lines inside the polygon.
+
+ :param line: The target line that create painted polygon.
+ :type line: shapely.geometry.LineString or shapely.geometry.MultiLineString
+ :param tooldia: Tool diameter.
+ :param steps_per_circle: how many linear segments to use to approximate a circle
+ :param overlap: Tool path overlap percentage.
+ :param connect: Connect lines to avoid tool lifts.
+ :param contour: Paint around the edges.
+ :param prog_plot: boolean; if to use the progressive plotting
+ :return:
+ """
+
+ # log.debug("camlib.fill_with_lines()")
+ if not isinstance(line, LineString) or not isinstance(line, MultiLineString):
+ log.debug("camlib.Geometry.fill_with_lines() --> Not a LineString/MultiLineString but %s" % str(type(line)))
+ return None
+
+ # ## The toolpaths
+ # Index first and last points in paths
+ def get_pts(o):
+ return [o.coords[0], o.coords[-1]]
+
+ geoms = FlatCAMRTreeStorage()
+ geoms.get_points = get_pts
+
+ lines_trimmed = []
+
+ polygon = line.buffer(aperture_size / 1.99999999999999999, int(steps_per_circle))
+
+ try:
+ margin_poly = polygon.buffer(-tooldia / 1.99999999, int(steps_per_circle))
+ except Exception:
+ log.debug("camlib.Geometry.fill_with_lines() --> Could not buffer the Polygon, tool diameter too high")
+ return None
+
+ # First line
+ try:
+ delta = 0
+ while delta < aperture_size / 2:
+ if self.app.abort_flag:
+ # graceful abort requested by the user
+ raise FlatCAMApp.GracefulException
+
+ # provide the app with a way to process the GUI events when in a blocking loop
+ QtWidgets.QApplication.processEvents()
+
+ line = line.parallel_offset(distance=delta, side='left', resolution=int(steps_per_circle))
+ line = line.intersection(margin_poly)
+ lines_trimmed.append(line)
+
+ line = line.parallel_offset(distance=delta, side='right', resolution=int(steps_per_circle))
+ line = line.intersection(margin_poly)
+ lines_trimmed.append(line)
+
+ delta += tooldia * (1 - overlap)
+ if prog_plot:
+ self.plot_temp_shapes(line)
+ self.temp_shapes.redraw()
+
+ # Last line
+ delta = aperture_size / 2
+
+ line = line.parallel_offset(distance=delta, side='left', resolution=int(steps_per_circle))
+ line = line.intersection(margin_poly)
+
+ for ll in line:
+ lines_trimmed.append(ll)
+ if prog_plot:
+ self.plot_temp_shapes(line)
+
+ line = line.parallel_offset(distance=delta, side='left', resolution=int(steps_per_circle))
+ line = line.intersection(margin_poly)
+
+ for ll in line:
+ lines_trimmed.append(ll)
+ if prog_plot:
+ self.plot_temp_shapes(line)
+ except Exception as e:
+ log.debug('camlib.Geometry.fill_with_lines() Processing poly --> %s' % str(e))
+ return None
+
+ if prog_plot:
+ self.temp_shapes.redraw()
+
+ lines_trimmed = unary_union(lines_trimmed)
+
+ # Add lines to storage
+ try:
+ for line in lines_trimmed:
+ if isinstance(line, LineString) or isinstance(line, LinearRing):
+ geoms.insert(line)
+ else:
+ log.debug("camlib.Geometry.fill_with_lines(). Not a line: %s" % str(type(line)))
+ except TypeError:
+ # in case lines_trimmed are not iterable (Linestring, LinearRing)
+ geoms.insert(lines_trimmed)
+
+ # Add margin (contour) to storage
+ if contour:
+ try:
+ for poly in margin_poly:
+ if isinstance(poly, Polygon) and not poly.is_empty:
+ geoms.insert(poly.exterior)
+ if prog_plot:
+ self.plot_temp_shapes(poly.exterior)
+ for ints in poly.interiors:
+ geoms.insert(ints)
+ if prog_plot:
+ self.plot_temp_shapes(ints)
+ except TypeError:
+ if isinstance(margin_poly, Polygon) and not margin_poly.is_empty:
+ marg_ext = margin_poly.exterior
+ geoms.insert(marg_ext)
+ if prog_plot:
+ self.plot_temp_shapes(margin_poly.exterior)
+ for ints in margin_poly.interiors:
+ geoms.insert(ints)
+ if prog_plot:
+ self.plot_temp_shapes(ints)
+
+ if prog_plot:
+ self.temp_shapes.redraw()
+
+ # Optimization: Reduce lifts
+ if connect:
+ # log.debug("Reducing tool lifts...")
+ geoms_conn = Geometry.paint_connect(geoms, polygon, tooldia, steps_per_circle)
+ if geoms_conn:
+ return geoms_conn
+
+ return geoms
+
def scale(self, xfactor, yfactor, point=None):
"""
Scales all of the object's geometry by a given factor. Override
From cf9f15152a01fcfb82fcf86db02105c964cda8fa Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 10 Feb 2020 13:46:03 +0200
Subject: [PATCH 079/209] - some cleanup and bug fixes for the Paint Tool
---
README.md | 2 ++
flatcamTools/ToolPaint.py | 50 +++++++++++++++++++--------------------
2 files changed, 27 insertions(+), 25 deletions(-)
diff --git a/README.md b/README.md
index bc8f6675..250aef2a 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,8 @@ CAD program, and create G-Code for Isolation routing.
- solved bug that made drilling with Marlin preprocessor very slow
- applied the fix for above bug to the TclCommand Drillcncjob too
- started a new way to clear the Gerber polygons based on the 'follow' lines
+- some cleanup and bug fixes for the Paint Tool
+
8.02.2020
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 18f1f3a9..60ff4f07 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -542,7 +542,9 @@ class ToolPaint(FlatCAMTool, Gerber):
self.bound_obj_name = ""
self.bound_obj = None
- self.tooldia_list = []
+ self.tooldia_list = list()
+ self.tooldia = None
+
self.sel_rect = None
self.o_name = None
self.overlap = None
@@ -1122,7 +1124,7 @@ class ToolPaint(FlatCAMTool, Gerber):
if float('%.*f' % (self.decimals, tool_dia)) in tool_dias:
if muted is None:
- self.app.inform.emit('[WARNING_NOTCL] %s' % _("Adding tool cancelled. Tool already in Tool Table."))
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Adding tool cancelled. Tool already in Tool Table."))
self.tools_table.itemChanged.connect(self.on_tool_edit)
return
else:
@@ -1242,12 +1244,12 @@ class ToolPaint(FlatCAMTool, Gerber):
#
# self.app.inform.emit("[success] Tool was copied in the Tool Table.")
- def on_tool_delete(self, rows_to_delete=None, all=None):
+ def on_tool_delete(self, rows_to_delete=None, all_tools=None):
self.blockSignals(True)
deleted_tools_list = []
- if all:
+ if all_tools:
self.paint_tools.clear()
self.blockSignals(False)
self.build_ui()
@@ -1316,25 +1318,20 @@ class ToolPaint(FlatCAMTool, Gerber):
self.paint_obj = self.app.collection.get_by_name(str(self.obj_name))
except Exception as e:
log.debug("ToolPaint.on_paint_button_click() --> %s" % str(e))
- self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
- (_("Could not retrieve object: %s"),
- self.obj_name))
+ self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object: %s"), self.obj_name))
return
if self.paint_obj is None:
- self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
- (_("Object not found"),
- self.paint_obj))
+ self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Object not found"), self.paint_obj))
return
# test if the Geometry Object is multigeo and return Fail if True because
# for now Paint don't work on MultiGeo
if self.paint_obj.multigeo is True:
- self.app.inform.emit('[ERROR_NOTCL] %s...' %
- _("Can't do Paint on MultiGeo geometries"))
+ self.app.inform.emit('[ERROR_NOTCL] %s...' % _("Can't do Paint on MultiGeo geometries"))
return 'Fail'
- o_name = '%s_multitool_paint' % self.obj_name
+ self.o_name = '%s_mt_paint' % self.obj_name
# use the selected tools in the tool table; get diameters
self.tooldia_list = list()
@@ -1347,8 +1344,7 @@ class ToolPaint(FlatCAMTool, Gerber):
try:
self.tooldia = float(self.tools_table.item(x.row(), 1).text().replace(',', '.'))
except ValueError:
- self.app.inform.emit('[ERROR_NOTCL] %s' %
- _("Wrong value format entered, use a number."))
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _("Wrong value format entered, use a number."))
continue
self.tooldia_list.append(self.tooldia)
else:
@@ -1401,7 +1397,7 @@ class ToolPaint(FlatCAMTool, Gerber):
# Get source object.
try:
self.bound_obj = self.app.collection.get_by_name(self.bound_obj_name)
- except Exception as e:
+ except Exception:
self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), self.obj_name))
return "Could not retrieve object: %s" % self.obj_name
@@ -1525,14 +1521,14 @@ class ToolPaint(FlatCAMTool, Gerber):
_("Click the end point of the paint area."))
self.cursor_pos = self.app.plotcanvas.translate_coords(event_pos)
- if self.app.grid_status() == True:
+ if self.app.grid_status():
self.cursor_pos = self.app.geo_editor.snap(self.cursor_pos[0], self.cursor_pos[1])
else:
self.app.inform.emit(_("Zone added. Click to start adding next zone or right click to finish."))
self.app.delete_selection_shape()
curr_pos = self.app.plotcanvas.translate_coords(event_pos)
- if self.app.grid_status() == True:
+ if self.app.grid_status():
curr_pos = self.app.geo_editor.snap(curr_pos[0], curr_pos[1])
x0, y0 = self.cursor_pos[0], self.cursor_pos[1]
@@ -1608,7 +1604,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.mouse_is_dragging = False
# update the cursor position
- if self.app.grid_status() == True:
+ if self.app.grid_status():
# Update cursor
curr_pos = self.app.geo_editor.snap(curr_pos[0], curr_pos[1])
@@ -1768,14 +1764,14 @@ class ToolPaint(FlatCAMTool, Gerber):
prog_plot=prog_plot)
except FlatCAMApp.GracefulException:
return "fail"
- except Exception as e:
- log.debug("ToolPaint.paint_poly().gen_paintarea().paint_p() --> %s" % str(e))
+ except Exception as ee:
+ log.debug("ToolPaint.paint_poly().gen_paintarea().paint_p() --> %s" % str(ee))
if cpoly is not None:
geo_obj.solid_geometry += list(cpoly.get_objects())
return cpoly
else:
- app_obj.inform.emit('[ERROR_NOTCL] %s' % _('Geometry could not be painted completely'))
+ app_obj.inform.emit('[ERROR_NOTCL] %s' % _('Geometry could not be painted completely'))
return None
current_uid = int(1)
@@ -1843,7 +1839,11 @@ class ToolPaint(FlatCAMTool, Gerber):
geo_obj.solid_geometry = cascaded_union(tools_storage[current_uid]['solid_geometry'])
try:
- a, b, c, d = geo_obj.solid_geometry.bounds
+ if isinstance(geo_obj.solid_geometry, list):
+ a, b, c, d = MultiPolygon(geo_obj.solid_geometry).bounds
+ else:
+ a, b, c, d = geo_obj.solid_geometry.bounds
+
geo_obj.options['xmin'] = a
geo_obj.options['ymin'] = b
geo_obj.options['xmax'] = c
@@ -2194,7 +2194,8 @@ class ToolPaint(FlatCAMTool, Gerber):
continue
# try:
- # # Polygons are the only really paintable geometries, lines in theory have no area to be painted
+ # # Polygons are the only really paintable geometries,
+ # # lines in theory have no area to be painted
# if not isinstance(geo, Polygon):
# continue
# poly_buf = geo.buffer(-paint_margin)
@@ -3114,7 +3115,6 @@ class ToolPaint(FlatCAMTool, Gerber):
self.sel_rect = []
-
@staticmethod
def paint_bounds(geometry):
def bounds_rec(o):
From 76545de4347e4cc723bba6677cbb00f1354744d9 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Tue, 11 Feb 2020 00:14:50 +0200
Subject: [PATCH 080/209] - working on Tool Punch; finished the geometry update
with the clear geometry for the case of Excellon method
---
README.md | 4 ++++
flatcamTools/ToolPunchGerber.py | 41 ++++++++++++++++++---------------
2 files changed, 26 insertions(+), 19 deletions(-)
diff --git a/README.md b/README.md
index bc8f6675..11009b5a 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+11.02.2020
+
+- working on Tool Punch; finished the geometry update with the clear geometry for the case of Excellon method
+
10.02.2020
- optimized the Paint and NCC Tools. When the Lines type of painting/clearing is used, the lines will try to arrange themselves on the direction that the lines length clearing the polygon are bigger
diff --git a/flatcamTools/ToolPunchGerber.py b/flatcamTools/ToolPunchGerber.py
index 807bbe0c..b78cd9a0 100644
--- a/flatcamTools/ToolPunchGerber.py
+++ b/flatcamTools/ToolPunchGerber.py
@@ -522,38 +522,41 @@ class ToolPunchGerber(FlatCAMTool):
# create the punched Gerber solid_geometry
punched_solid_geometry = grb_solid_geometry.difference(exc_solid_geometry)
- new_apertures = dict()
+ # update the gerber apertures to include the clear geometry so it can be exported successfully
new_apertures = deepcopy(grb_obj.apertures)
+ new_apertures_items = new_apertures.items()
+ # find maximum aperture id
+ new_apid = max([int(x) for x, __ in new_apertures_items])
+
+ # store here the clear geometry, the key is the drill size
holes_apertures = dict()
- for apid, val in new_apertures.items():
+ for apid, val in new_apertures_items:
for elem in val['geometry']:
# make it work only for Gerber Flashes who are Points in 'follow'
if 'solid' in elem and isinstance(elem['follow'], Point):
for drill in exc_obj.drills:
- clear_apid = exc_obj.tools[drill['tool']]['C']
- exc_poly = drill['point'].buffer(clear_apid / 2.0)
- if exc_poly.within(elem['solid']):
+ clear_apid_size = exc_obj.tools[drill['tool']]['C']
- if clear_apid not in holes_apertures or holes_apertures[clear_apid]['type'] != 'C':
- holes_apertures[clear_apid] = dict()
- holes_apertures[clear_apid]['type'] = 'C'
- holes_apertures[clear_apid]['size'] = clear_apid
- holes_apertures[clear_apid]['geometry'] = list()
+ # since there may be drills that do not drill into a pad we test only for drills in a pad
+ if drill['point'].within(elem['solid']):
geo_elem = dict()
- geo_elem['clear'] = exc_poly
- geo_elem['follow'] = exc_poly.centroid
- holes_apertures[clear_apid]['geometry'].append(deepcopy(geo_elem))
+ geo_elem['clear'] = drill['point']
- elem['clear'] = exc_poly.centroid
+ if clear_apid_size not in holes_apertures:
+ holes_apertures[clear_apid_size] = dict()
+ holes_apertures[clear_apid_size]['type'] = 'C'
+ holes_apertures[clear_apid_size]['size'] = clear_apid_size
+ holes_apertures[clear_apid_size]['geometry'] = list()
- for apid, val in new_apertures.items():
- for clear_apid, clear_val in holes_apertures.items():
- if round(clear_apid, self.decimals) == round(val['size'], self.decimals):
- geo_elem = dict()
+ holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem))
- val['geometry'].append(geo_elem)
+ # add the clear geometry to new apertures; it's easier than to test if there are apertures with the same
+ # size and add there the clear geometry
+ for hole_size, ap_val in holes_apertures.items():
+ new_apid += 1
+ new_apertures[str(new_apid)] = deepcopy(ap_val)
def init_func(new_obj, app_obj):
new_obj.options.update(grb_obj.options)
From f9c63c03aaf4b2ab6c861324f7f189ad146cab28 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 12 Feb 2020 02:48:35 +0200
Subject: [PATCH 081/209] - working on Tool Punch; finished the geometry update
with the clear geometry for the case of Fixed Diameter method
---
README.md | 1 +
flatcamTools/ToolPunchGerber.py | 81 ++++++++++++++++++++++++++++++---
2 files changed, 75 insertions(+), 7 deletions(-)
diff --git a/README.md b/README.md
index ece316d7..f1f5f28e 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
11.02.2020
- working on Tool Punch; finished the geometry update with the clear geometry for the case of Excellon method
+- working on Tool Punch; finished the geometry update with the clear geometry for the case of Fixed Diameter method
10.02.2020
diff --git a/flatcamTools/ToolPunchGerber.py b/flatcamTools/ToolPunchGerber.py
index b78cd9a0..10bf4b92 100644
--- a/flatcamTools/ToolPunchGerber.py
+++ b/flatcamTools/ToolPunchGerber.py
@@ -5,15 +5,14 @@
# MIT Licence #
# ##########################################################
-from PyQt5 import QtGui, QtCore, QtWidgets
+from PyQt5 import QtCore, QtWidgets
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, \
- OptionalHideInputSection, OptionalInputSection, FCComboBox
+from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox
from copy import deepcopy
import logging
-from shapely.geometry import Polygon, MultiPolygon, Point
+from shapely.geometry import MultiPolygon, Point
import gettext
import FlatCAMTranslation as fcTranslate
@@ -574,9 +573,13 @@ class ToolPunchGerber(FlatCAMTool):
elif punch_method == 'fixed':
punch_size = float(self.dia_entry.get_value())
+ if punch_size == 0.0:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("The value of the fixed diameter is 0.0. Aborting."))
+ return 'fail'
+
punching_geo = list()
for apid in grb_obj.apertures:
- if grb_obj.apertures[apid]['type'] == 'C':
+ if grb_obj.apertures[apid]['type'] == 'C' and self.circular_cb.get_value():
if punch_size >= float(grb_obj.apertures[apid]['size']):
self.app.inform.emit('[ERROR_NOTCL] %s' %
_(" Could not generate punched hole Gerber because the punch hole size"
@@ -587,18 +590,37 @@ class ToolPunchGerber(FlatCAMTool):
if 'follow' in elem:
if isinstance(elem['follow'], Point):
punching_geo.append(elem['follow'].buffer(punch_size / 2))
- else:
+ elif grb_obj.apertures[apid]['type'] == 'R':
if punch_size >= float(grb_obj.apertures[apid]['width']) or \
punch_size >= float(grb_obj.apertures[apid]['height']):
self.app.inform.emit('[ERROR_NOTCL] %s' %
_("Could not generate punched hole Gerber because the punch hole size"
"is bigger than some of the apertures in the Gerber object."))
return 'fail'
- else:
+ elif round(float(grb_obj.apertures[apid]['width']), self.decimals) == \
+ round(float(grb_obj.apertures[apid]['height']), self.decimals) and \
+ self.square_cb.get_value():
for elem in grb_obj.apertures[apid]['geometry']:
if 'follow' in elem:
if isinstance(elem['follow'], Point):
punching_geo.append(elem['follow'].buffer(punch_size / 2))
+ elif round(float(grb_obj.apertures[apid]['width']), self.decimals) != \
+ round(float(grb_obj.apertures[apid]['height']), self.decimals) and \
+ self.rectangular_cb.get_value():
+ for elem in grb_obj.apertures[apid]['geometry']:
+ if 'follow' in elem:
+ if isinstance(elem['follow'], Point):
+ punching_geo.append(elem['follow'].buffer(punch_size / 2))
+ elif grb_obj.apertures[apid]['type'] == 'O' and self.oblong_cb.get_value():
+ for elem in grb_obj.apertures[apid]['geometry']:
+ if 'follow' in elem:
+ if isinstance(elem['follow'], Point):
+ punching_geo.append(elem['follow'].buffer(punch_size / 2))
+ elif grb_obj.apertures[apid]['type'] not in ['C', 'R', 'O'] and self.other_cb.get_value():
+ for elem in grb_obj.apertures[apid]['geometry']:
+ if 'follow' in elem:
+ if isinstance(elem['follow'], Point):
+ punching_geo.append(elem['follow'].buffer(punch_size / 2))
punching_geo = MultiPolygon(punching_geo)
if isinstance(grb_obj.solid_geometry, list):
@@ -613,8 +635,53 @@ class ToolPunchGerber(FlatCAMTool):
"geometry is the same as the one in the source object geometry..."))
return 'fail'
+ # update the gerber apertures to include the clear geometry so it can be exported successfully
+ new_apertures = deepcopy(grb_obj.apertures)
+ new_apertures_items = new_apertures.items()
+
+ # find maximum aperture id
+ new_apid = max([int(x) for x, __ in new_apertures_items])
+
+ # store here the clear geometry, the key is the drill size
+ holes_apertures = dict()
+
+ for apid, val in new_apertures_items:
+ for elem in val['geometry']:
+ # make it work only for Gerber Flashes who are Points in 'follow'
+ if 'solid' in elem and isinstance(elem['follow'], Point):
+ for geo in punching_geo:
+ clear_apid_size = punch_size
+
+ # since there may be drills that do not drill into a pad we test only for drills in a pad
+ if geo.within(elem['solid']):
+ geo_elem = dict()
+ geo_elem['clear'] = geo.centroid
+
+ if clear_apid_size not in holes_apertures:
+ holes_apertures[clear_apid_size] = dict()
+ holes_apertures[clear_apid_size]['type'] = 'C'
+ holes_apertures[clear_apid_size]['size'] = clear_apid_size
+ holes_apertures[clear_apid_size]['geometry'] = list()
+
+ holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem))
+
+ # add the clear geometry to new apertures; it's easier than to test if there are apertures with the same
+ # size and add there the clear geometry
+ for hole_size, ap_val in holes_apertures.items():
+ new_apid += 1
+ new_apertures[str(new_apid)] = deepcopy(ap_val)
+
def init_func(new_obj, app_obj):
+ new_obj.options.update(grb_obj.options)
+ new_obj.options['name'] = outname
+ new_obj.fill_color = deepcopy(grb_obj.fill_color)
+ new_obj.outline_color = deepcopy(grb_obj.outline_color)
+
+ new_obj.apertures = deepcopy(new_apertures)
+
new_obj.solid_geometry = deepcopy(punched_solid_geometry)
+ new_obj.source_file = self.app.export_gerber(obj_name=outname, filename=None,
+ local_use=new_obj, use_thread=False)
self.app.new_object('gerber', outname, init_func)
elif punch_method == 'ring':
From 67a2350a5925a6ca5536fa84dfd9cdb9b792caa4 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 12 Feb 2020 02:51:15 +0200
Subject: [PATCH 082/209] - minor change in ReadMe file
---
README.md | 130 +++++++++++++++++++++++++++---------------------------
1 file changed, 65 insertions(+), 65 deletions(-)
diff --git a/README.md b/README.md
index f1f5f28e..5c264eac 100644
--- a/README.md
+++ b/README.md
@@ -465,7 +465,7 @@ CAD program, and create G-Code for Isolation routing.
- in Excellon UI fixed bug that did not allow editing of the Offset Z parameter from the Tool table
- in Properties Tool added new information's for the tools in the CNCjob objects
- few bugs solved regarding the newly created empty objects
-- changed everywhere the name "postprocessor" with "preprocessor"
+- changed everywhere the name "preprocessor" with "preprocessor"
- updated the preprocessor files in the toolchange section in order to avoid a graphical representation of travel lines glitch
- fixed a GUI glitch in the Excellon tool table
- added units to some of the parameters in the Properties Tool
@@ -604,7 +604,7 @@ CAD program, and create G-Code for Isolation routing.
16.11.2019
-- fixed issue #341 that affected both postprocessors that have inlined feedrate: marlin and repetier. The used feedrate was the Feedrate X-Y and instead had to be Feedrate Z.
+- fixed issue #341 that affected both preprocessors that have inlined feedrate: marlin and repetier. The used feedrate was the Feedrate X-Y and instead had to be Feedrate Z.
15.11.2019
@@ -614,7 +614,7 @@ CAD program, and create G-Code for Isolation routing.
14.11.2019
-- made sure that the 'default' postprocessor file is always loaded first such that this name is always first in the GUI comboboxes
+- made sure that the 'default' preprocessor file is always loaded first such that this name is always first in the GUI comboboxes
- added a class in GUIElements for a TextEdit box with line numbers and highlight
13.11.2019
@@ -626,7 +626,7 @@ CAD program, and create G-Code for Isolation routing.
12.11.2019
-- added two new postprocessor files for ISEL CNC and for BERTA CNC
+- added two new preprocessor files for ISEL CNC and for BERTA CNC
- clicking on a FCTable GUI element empty space will also clear the focus now
11.11.2019
@@ -1156,7 +1156,7 @@ CAD program, and create G-Code for Isolation routing.
- more GUI optimizations related to being part of the Advanced category or not
- added possibility to change the positive SVG exported file color in Tool Film
- fixed some issues recently introduced in the TclCommands CNCJob, DrillCNCJob and write_gcode; changed some parameters names
-- fixed issue in the Laser postprocessor where the laser was turned on as soon as the GCode started creating an unwanted cut up until the job start
+- fixed issue in the Laser preprocessor where the laser was turned on as soon as the GCode started creating an unwanted cut up until the job start
- added new links in Menu -> Help (Excellon, Gerber specifications and a Report Bug)
- made the splashscreen to be showed on the current monitor on systems with multiple monitors
- added a new entry in Menu -> View -> Redraw All which is doing what the name says: redraw all loaded objects
@@ -1369,7 +1369,7 @@ CAD program, and create G-Code for Isolation routing.
- remade the NCC Tool in preparation for the newly added TclCommand CopperClear
- finished adding the TclCommandCopperClear that can be called with alias: 'ncc'
- added new capability in NCC Tool when the reference object is of Gerber type and fixed some newly introduced errors
-- fixed issue #298. The changes in postprocessors done in Preferences dis not update the object UI layout as it was supposed to. The selection of Marlin postproc. did not unhidden the Feedrate Rapids entry.
+- fixed issue #298. The changes in preprocessors done in Preferences dis not update the object UI layout as it was supposed to. The selection of Marlin postproc. did not unhidden the Feedrate Rapids entry.
- fixed minor issues
- fixed Tcl Command AddPolygon, AddPolyline
- fixed Tcl Command CncJob
@@ -1895,7 +1895,7 @@ CAD program, and create G-Code for Isolation routing.
11.05.2019
- fixed issue in camlib.CNCjob.generate_from_excellon_by_tool() in the drill path optimization algorithm selection when selecting the MH algorithm. The new API's for Google OR-tools required some changes and also the time parameter can be now just an integer therefore I modified the GUI
-- made the Feedrate Rapids parameter to depend on the type of postprocessor choosed. It will be showed only for a postprocessor which the name contain 'marlin' and for any postprocessor's that have 'custom' in the name
+- made the Feedrate Rapids parameter to depend on the type of preprocessor choosed. It will be showed only for a preprocessor which the name contain 'marlin' and for any preprocessor's that have 'custom' in the name
- fixed the camlib.Gerber functions of mirror, scale, offset, skew and rotate to work with the new data structure for apertures geometry
- fixed Gerber Editor selection to work with the new Gerber data structure in self.apertures
- fixed Gerber Editor FCPad class to work with the new Gerber data structure in self.apertures
@@ -2325,7 +2325,7 @@ CAD program, and create G-Code for Isolation routing.
- added a fix in the Gerber parser when adding the geometry in the self.apertures dict for the case that the current aperture is None (Allegro does that)
- finished support for internationalization by adding a set of .po/.mo files for the English language. Unfortunately the final action can be done only when Beta will be out of Beta (no more changes) or when I will decide to stop working on this app.
-- changed the tooltip for 'feedrate_rapids' parameter to point out that this parameter is useful only for the Marlin postprocessor
+- changed the tooltip for 'feedrate_rapids' parameter to point out that this parameter is useful only for the Marlin preprocessor
- fix app crash for the case that there are no translation files
- fixed some forgotten strings to be prepared for internationalization in ToolCalculators
- fixed Tools menu no longer working due of changes
@@ -2364,7 +2364,7 @@ CAD program, and create G-Code for Isolation routing.
5.03.2019
-- modified the grbl-laser postprocessor lift_code()
+- modified the grbl-laser preprocessor lift_code()
- treated an error created by Z_Cut parameter being None
- changed the hover and selection box transparency
@@ -2417,7 +2417,7 @@ CAD program, and create G-Code for Isolation routing.
- because adding shapes to the shapes collection (when doing Mark or Mark All) is time consuming I made the plot_aperture() threaded.
- made the polygon fusing in modified Gerber creation, a list comprehension in an attempt for optimization
- when right clicking the files in Project tab, the Save option for Excellon no longer export it but really save the original.
-- in ToolChange Custom Code replacement, the Text Box in the CNCJob Selected tab will be active only if there is a 'toolchange_custom' in the name of the postprocessor file. This assume that it is, or was created having as template the Toolchange Custom postprocessor file.
+- in ToolChange Custom Code replacement, the Text Box in the CNCJob Selected tab will be active only if there is a 'toolchange_custom' in the name of the preprocessor file. This assume that it is, or was created having as template the Toolchange Custom preprocessor file.
25.02.2019
@@ -2444,7 +2444,7 @@ CAD program, and create G-Code for Isolation routing.
- added all the Tools in a new ToolBar
- fixed bug that after changing the layout all the toolbar actions are no longer working
- fixed bug in Set Origin function
-- fixed a typo in Toolchange_Probe_MACH3 postprocessor
+- fixed a typo in Toolchange_Probe_MACH3 preprocessor
23.02.2019
@@ -2455,7 +2455,7 @@ CAD program, and create G-Code for Isolation routing.
22.02.2019
-- added Repetier postprocessor file
+- added Repetier preprocessor file
- removed "added ability to regenerate objects (it's actually deletion followed by recreation)" because of the way Python pass parameters to functions by reference instead of copy
- added ability to toggle globally the display of ToolTips. Edit -> Preferences -> General -> Enable ToolTips checkbox.
- added true fullscreen support (for Windows OS)
@@ -2484,7 +2484,7 @@ CAD program, and create G-Code for Isolation routing.
- finished added a Tool Table for Tool SolderPaste
- working on multi tool solder paste dispensing
- finished the Edit -> Preferences defaults section
-- finished the UI, created the postprocessor file template
+- finished the UI, created the preprocessor file template
- finished the multi-tool solder paste dispensing: it will start using the biggest nozzle, fill the pads it can, and then go to the next smaller nozzle until there are no pads without solder.
19.02.2019
@@ -2607,12 +2607,12 @@ CAD program, and create G-Code for Isolation routing.
- the SELECTED type of messages are no longer printed to shell from 2 reasons: first, too much spam and second, issue with displaying html
- on set_zero function and creation of new geometry or new excellon there is no longer a zoom fit
- repurposed shortcut key 'Delete' to delete tools in tooltable when the mouse is over the Seleted tab (with Geometry inside) or in Tools tab (when NCC Tool or Paint Tool is inside). Or in Excellon Editor when mouse is hovering the Selected tab selecting a tool, 'Delete' key will delete that tool, if on canvas 'Delete' key will delete a selected shape (drill). In rest, will delete selected objects.
-- adjusted the postprocessor files so the Spindle Off command (M5) is done before the move to Toolchange Z
-- adjusted the Toolchange Manual postprocessor file to have more descriptive messages on the toolchange event
+- adjusted the preprocessor files so the Spindle Off command (M5) is done before the move to Toolchange Z
+- adjusted the Toolchange Manual preprocessor file to have more descriptive messages on the toolchange event
- added a strong focus to the object_name entry in the Selected tab
- the keypad keyPressed are now detected correctly
-- added a pause and message/warning to do a rough zero for the Z axis, in case of Toolchange_Probe_MACH3 postprocessor file
-- changes in Toolchange_Probe_MACH3 postprocessor file
+- added a pause and message/warning to do a rough zero for the Z axis, in case of Toolchange_Probe_MACH3 preprocessor file
+- changes in Toolchange_Probe_MACH3 preprocessor file
9.02.2019
@@ -2678,16 +2678,16 @@ CAD program, and create G-Code for Isolation routing.
- added a text in the Selected Tab which is showed whenever the Selected Tab is selected but without having an object selected to display it's properties
- added an initial text in the Tools tab
- added possibility to use the shortcut key for shortcut list in the Notebook tabs
-- added a way to set the Probe depth if Toolchange_Probe postprocessors are selected
-- finished the postprocessor file for MACH3 tool probing on toolchange event
-- added a new parameter to set the feedrate of the probing in case the used postprocessor does probing (has toolchange_probe in it's name)
-- fixed bug in Marlin postprocessor for the Excellon files; the header and toolchange event always used the parenthesis witch is not compatible with GCode for Marlin
+- added a way to set the Probe depth if Toolchange_Probe preprocessors are selected
+- finished the preprocessor file for MACH3 tool probing on toolchange event
+- added a new parameter to set the feedrate of the probing in case the used preprocessor does probing (has toolchange_probe in it's name)
+- fixed bug in Marlin preprocessor for the Excellon files; the header and toolchange event always used the parenthesis witch is not compatible with GCode for Marlin
- fixed a issue with a move to Z_move before any toolchange
4.02.2019
-- modified the Toolchange_Probe_general postprocessor file to remove any Z moves before the actual toolchange event
-- created a prototype postprocessor file for usage with tool probing in MACH3
+- modified the Toolchange_Probe_general preprocessor file to remove any Z moves before the actual toolchange event
+- created a prototype preprocessor file for usage with tool probing in MACH3
- added the default values for Tool Film and Tool Panelize to the Edit -> Preferences
- added a new parameter in the Tool Film which control the thickness of the stroke width in the resulting SVG. It's a scale parameter.
- whatever was the visibility of the corresponding toolbar when we enter in the Editor, it will be set after exit from the Editor (either Geometry Editor or Excellon Editor).
@@ -2714,14 +2714,14 @@ CAD program, and create G-Code for Isolation routing.
- some GUI structure optimization's
- added protection against entering float numbers with comma separator instead of decimal dot separator in key points of FlatCAM (not everywhere)
- added a choice of plotting the kind of geometry for the CNC plot (all, travel and cut kind of geometries) in CNCJob Selected Tab
-- added a new postprocessor file named: 'probe_from_zmove' which allow probing to be done from z_move position on toolchange event
+- added a new preprocessor file named: 'probe_from_zmove' which allow probing to be done from z_move position on toolchange event
- fixed the snap magnet button in Geometry Editor, restored the checkable property to True
- some more changes in the Editors GUI in deactivate() function
- a fix for saving as empty an edited new and empty Excellon Object
1.02.2019
-- fixed postprocessor files so now the bounds values are right aligned (assuming max string length of 9 chars which means 4 digits and 4 decimals)
+- fixed preprocessor files so now the bounds values are right aligned (assuming max string length of 9 chars which means 4 digits and 4 decimals)
- corrected small type in list_sys Tcl command; added a protection of the Plot Area Tab after a successful edit.
- remade the way FlatCAM saves the GUI position data from a file (previously) to use PyQt QSettings
- added a 'theme' combo selection in Edit -> Preferences. Two themes are available: standard and compact.
@@ -2745,7 +2745,7 @@ CAD program, and create G-Code for Isolation routing.
30.01.2019
-- added a space before Y coordinate in end_code() function in some of the postprocessor files
+- added a space before Y coordinate in end_code() function in some of the preprocessor files
- added in Calculators Tool an Electroplating Calculator.
- remade the App Menu for Editors: now they will be showed only when the respective Editor is active and hidden when the Editor is closed.
- added a traceback report in the TCL Shell for the errors that don't allow creation of an object; useful to trace exceptions/errors
@@ -2753,9 +2753,9 @@ CAD program, and create G-Code for Isolation routing.
- fixed an issue in camlib.CNCJob where tha variable self.toolchange_xy was used for 2 different purposes which created loss of information.
- fixed unit conversion functions in case the toolchange_xy parameter is None
- more fixes in camlib.CNCJob regarding usage of toolchange (in case it is None)
-- fixed postprocessor files to work with toolchange_xy parameter value = None (no values in Edit - Preferences fields)
+- fixed preprocessor files to work with toolchange_xy parameter value = None (no values in Edit - Preferences fields)
- fixed Tcl commands CncJob and DrillCncJob to work with toolchange
-- added to the postprocessor files the command after toolchange to go with G00 (fastest) to "Z Move" value of Z pozition.
+- added to the preprocessor files the command after toolchange to go with G00 (fastest) to "Z Move" value of Z pozition.
29.01.2019
@@ -2788,15 +2788,15 @@ CAD program, and create G-Code for Isolation routing.
- added options for trace segmentation that can be useful for auto-levelling (code snippet from Lei Zheng from a rejected pull request on FlatCAM https://bitbucket.org/realthunder/ )
- added shortcut key 'L' for creating 'New Excellon'
- added shortcut key combo 'SHIFT+S' for Running a Script.
-- modified GRBL_laser postprocessor file so it includes a Sxxxx command on the line with M03 (laser active) whenever a value is enter in the Spindlespeed entry field
+- modified GRBL_laser preprocessor file so it includes a Sxxxx command on the line with M03 (laser active) whenever a value is enter in the Spindlespeed entry field
- remade the EDIT -> PREFERENCES window, the Excellon and Gerber sections. Created a new section named TOOLS
26.01.2019
-- fixed grbl_11 postprocessor in linear_code() function
+- fixed grbl_11 preprocessor in linear_code() function
- added icons to the Project Tab context menu
- added new entries to the Canvas context menu (Copy, Delete, Edit/Save, Move, New Excellon, New Geometry, New Project)
-- fixed GRBL_laser postprocessor file
+- fixed GRBL_laser preprocessor file
- updated function for copy of an Excellon object for the case when the object has slots
- updated FlatCAMExcellon.merge() function to work in case some (or all) of the merged objects have slots
@@ -2816,14 +2816,14 @@ CAD program, and create G-Code for Isolation routing.
- added the Copy entry to the Project context menu
- made the functions behind Disable and Enable project context menu entries, non-threaded to fix a possible issue
- added multiple object selection on Open ... and Import ... (idea and code snippet came from Travers Carter, BitBucket user https://bitbucket.org/travc/)
-- fixed 'GRBL_laser' postprocessor bugs (missing functions)
-- fixed display geometry for 'GRBL_laser' postprocessor
+- fixed 'GRBL_laser' preprocessor bugs (missing functions)
+- fixed display geometry for 'GRBL_laser' preprocessor
- Excellon Editor - added possibility to create an linear drill array rotated at an custom angle
- added the Edit and Properties entries to the Project context menu
23.01.2019
-- added a new postprocessor file named 'line_xyz' which have x, y, z values on the same GCode line
+- added a new preprocessor file named 'line_xyz' which have x, y, z values on the same GCode line
- fixed calculation of total path for Excellon Gcode file
- modified the way FlatCAM preferences are saved. Now they can be saved as new files with .FlatConfig extension by the user and shared.
- added possibility to open the folder where FlatCAM is saving the preferences files
@@ -2840,19 +2840,19 @@ CAD program, and create G-Code for Isolation routing.
- fixed the HPGL code geometry rendering when travel
- fixed the message box layout when asking to save the current work
-- made sure that whenever the HPGL postprocessor is selected the Toolchange is always ON and the MultiDepth is OFF
-- the HPGL postprocessor entry is not allowed in Excellon Object postprocessor selection combobox as it is only applicable for Geometry
+- made sure that whenever the HPGL preprocessor is selected the Toolchange is always ON and the MultiDepth is OFF
+- the HPGL preprocessor entry is not allowed in Excellon Object preprocessor selection combobox as it is only applicable for Geometry
- when saving HPGL code it will be saved as a file with extension .plt
- the units mentioned in HPGL format are only METRIC therefore if FlatCAM units are in INCH they will be transform to METRIC
- the minimum unit in HPGL is 0.025mm therefore the coordinates are rounded to a multiple of 0.025mm
- removed the raise statement in do_worker_task() function as this is fatal in conjunction with PyQt5
- added a try - except clause for the situations when for a font can't be determined the family and name
- moved font parsing to the Geometry Editor: it is done everytime the Text tool is invoked
-- made sure that the HPGL postprocessor is not populated in the Excellon postprocessors in Preferences as it make no sense (HPGL is useful only for Geometries)
+- made sure that the HPGL preprocessor is not populated in the Excellon preprocessors in Preferences as it make no sense (HPGL is useful only for Geometries)
19.01.2019
-- added initial implementation of HPGL postprocessor
+- added initial implementation of HPGL preprocessor
- fixed display HPGL code geometry on canvas
11.01.2019
@@ -2876,9 +2876,9 @@ CAD program, and create G-Code for Isolation routing.
6.01.2019
-- fixed the Marlin postprocessor detection in GCode header
+- fixed the Marlin preprocessor detection in GCode header
- the version date in GCode header is now the one set in FlatCAMApp.App.version_date
-- fixed bug in postprocessor files: number of drills is now calculated only for the Excellon objects in toolchange function (only Excellon objects have drills)
+- fixed bug in preprocessor files: number of drills is now calculated only for the Excellon objects in toolchange function (only Excellon objects have drills)
5.01.2019
@@ -3042,8 +3042,8 @@ now there is a Tool Table in CNC Object UI and each tool GCode can be enabled or
- Geometry Tool Table: new tool added copy all the form fields (data) from the last tool
- finished work on generation of a single CNC Job file (therefore a single GCODE file) even for multiple tools in Geo Tool Table
- GCode header is added only on saving the file therefore the time generation will be reflected in the file
-- modified postprocessors to accommodate the new CNC Job file with multiple tools
-- modified postprocessors so the last X,Y move will be to the toolchange X,Y pos (set in Preferences)
+- modified preprocessors to accommodate the new CNC Job file with multiple tools
+- modified preprocessors so the last X,Y move will be to the toolchange X,Y pos (set in Preferences)
- save_project and load_project now work with the new type of multitool geometry and cncjob objects
10.12.2018
@@ -3112,7 +3112,7 @@ now there is a Tool Table in CNC Object UI and each tool GCode can be enabled or
- added checks for using a Z Cut with positive value. The Z Cut parameter has to be negative so if the app will detect a positive value it will automatically convert it to negative
- started to implement rest-machining for Non Copper clearing Tool - for now the results are not great
-- added Toolchange X,Y position parameters and modified the default and manual_toolchange postprocessor file to use them
+- added Toolchange X,Y position parameters and modified the default and manual_toolchange preprocessor file to use them
For now they are used only for Excellon objects who do have toolchange events
- added Toolchange event selection for Geometry objects; for now it is as before, single tool on each file
- remade the GUI for objects and in Preferences to have uniformity
@@ -3120,14 +3120,14 @@ For now they are used only for Excellon objects who do have toolchange events
- fixed some bugs in Tool Add feature of the new Non Copper Clear Tool
- added some messages in the Non Copper Clear Tool
- added parameters for coordinates no of decimals and for feedrate no of decimals used in the resulting GCODE. They are in EDIT -> Preferences -> CNC Job Options
-- modified the postprocessors to use the "decimals" parameters
+- modified the preprocessors to use the "decimals" parameters
28.11.2018
- added different methods of copper clearing (standard, seed, line_based) and "connect", "contour" options found in Paint function
- remake of the non-copper clearing tool as a separate tool
- modified the "About" menu entry to mention the main contributors to FlatCAM 3000
-- modified Marlin postprocessor according to modifications made by @redbull0174 user from FlatCAM.org forum
+- modified Marlin preprocessor according to modifications made by @redbull0174 user from FlatCAM.org forum
- modified Move Tool so it will detect if there is no object to move and issue a message
27.11.2018
@@ -3146,7 +3146,7 @@ For now they are used only for Excellon objects who do have toolchange events
- restored the selection method in Geometry Editor to the original one found in FlatCAM 8.5
- minor changes in Clear Copper function
-- minor changes in some postprocessors
+- minor changes in some preprocessors
- change Join Geometry menu entry to Join Geo/Gerber
- added menu entry for Toggle Axis in Menu -> View
- added menu entry for Toggle Workspace in Menu -> View
@@ -3162,7 +3162,7 @@ For now they are used only for Excellon objects who do have toolchange events
19.11.2018
-- fixed issue with nested comment in postprocessors
+- fixed issue with nested comment in preprocessors
- fixed issue in Paint All; reverted changes
18.11.2018
@@ -3179,13 +3179,13 @@ For now they are used only for Excellon objects who do have toolchange events
12.11.2018
- fixed bug in Paint Single Polygon
-- added spindle speed in laser postprocessor
+- added spindle speed in laser preprocessor
- added Z start move parameter. It controls the height at which the tool travel on the fist move in the job. Leave it blank if you don't need it.
9.11.2018
- fixed a reported bug generated by a typo for feedrate_z object in camlib.py. Because of that, the project could not be saved.
-- fixed a G01 usage (should be G1) in Marlin postprocessor.
+- fixed a G01 usage (should be G1) in Marlin preprocessor.
- changed the position of the Tool Dia entry in the Object UI and in FlatCAMGUI
- fixed issues in the installer
@@ -3404,9 +3404,9 @@ the setting in the Preferences) and drag the rectangle across the objects you wa
- work on Excellon Editor. Excellon editor working functions are: loading an Excellon object into Editor,
saving an Excellon object from editor to FlatCAM, selecting drills by left click, selection of drills by dragging rectangle, deletion of drills.
- fixed Excellon merge
-- added more Gcode details (depthperpass parameter in Gcode header) in postprocessors
-- deleted the Tool informations from header in postprocessors due to Mach3 not liking the lot of square brackets
-- more corrections in postprocessors
+- added more Gcode details (depthperpass parameter in Gcode header) in preprocessors
+- deleted the Tool informations from header in preprocessors due to Mach3 not liking the lot of square brackets
+- more corrections in preprocessors
28.09.2018
@@ -3481,7 +3481,7 @@ an Excellon file, a G-Code file or a SVG file.
- added new information's in the object properties: all used Tool-Table items
are included in a new entry in self.options dictionary
-- modified the postprocessor files so they now include information's about
+- modified the preprocessor files so they now include information's about
how many drills (or slots) are for each tool. The Gcode will have this
information displayed on the message from ToolChange.
- removed some log.debug and add new log.debug especially for moments when some process is finished
@@ -3519,7 +3519,7 @@ is faster
17.09.2018
- fixed Measuring Tool not working when grid is turned OFF
-- fixed Roland MDX20 postprocessor
+- fixed Roland MDX20 preprocessor
- added a .GBR extension in the open_gerber filter
- added ability to Scale and Offset (for all types of objects) to just
press Enter after entering a value in the Entry just like in Tool Transform
@@ -3533,8 +3533,8 @@ to FlatCAM.py
15.09.2018
-- removed dwell line generator and included dwell generation in the postprocessor files
-- added a proposed RML1 Roland_MDX20 postprocessor file.
+- removed dwell line generator and included dwell generation in the preprocessor files
+- added a proposed RML1 Roland_MDX20 preprocessor file.
- added a limit of 15mm/sec (900mm/min) to the feedrate and to the feedrate_rapid. Anything faster than this
will be capped to 900mm/min regardless what is entered in the program GUI. This is because Roland MDX-20 has
a mechanical limit of the speed to 15mm/sec (900mm/min in GUI)
@@ -3915,7 +3915,7 @@ total number of drills
- modified generate_milling method which had issues from the Python3 port
(it could not sort the tools due of dict to dict comparison no longer
possible).
-- modified the 'default' postprocessor in order to include a space
+- modified the 'default' preprocessor in order to include a space
between the value of Xcoord and the following Y
- made optional the using of threads for the milling command; by default
it is OFF (False) because in the current configuration it creates issues
@@ -3935,7 +3935,7 @@ clicked and Options Combo was in Project Options
- fixed issue with Tcl Shell loosing focus after each command, therefore
needing to click in the edit line before we type a new command (borrowed
from @brainstorm
-- added a header in the postprocessor files mentioning that the GCODE
+- added a header in the preprocessor files mentioning that the GCODE
files were generated by FlatCAM.
- modified the number of decimals in some of the line entries to 4.
- added an alias for the millholes Tcl Command: 'mill'
@@ -4038,14 +4038,14 @@ Delete: Delete Obj
22.05.2018
-- Added Marlin postprocessor
+- Added Marlin preprocessor
- Added a new entry into the Geometry and Excellon Object's UI:
Feedrate rapid: the purpose is to set a feedrate for the G0
command that some firmwares like Marlin don't intepret as
'move with highest speed'
- FlatCAM was not making the conversion from one type of units to
another for a lot of parameters. Corrected that.
-- Modified the Marlin Postprocessor so it will generate the required
+- Modified the Marlin preprocessor so it will generate the required
GCODE.
21.05.2018
@@ -4125,7 +4125,7 @@ make a board cutout from a "any shape" Gerber or Geometry file
parameter value as the toolchangez parameter value and for the endz value
used a default value = 1
-- added postprocessor name into the TCL command "drillcncjob" parameters
+- added preprocessor name into the TCL command "drillcncjob" parameters
- when adding a new geometry the default name is now: "New_Geometry" instead
of "New Geometry". TCL commands don't handle the spaces inside the name and
@@ -4212,19 +4212,19 @@ is less than 6 then the software will multiply by 10 the coordinates
- fixed bug in Geometry CNCJob generation that prevented generating
the object
-- added GRBL 1.1 postprocessor and Laser postprocessor (adapted from
+- added GRBL 1.1 preprocessor and Laser preprocessor (adapted from
the work of MARCO A QUEZADA)
13.05.2018
- added postprocessing in correct form
-- added the possibility to select an postprocessor for Excellon Object
-- added a new postprocessor, manual_toolchange.py. It allows to change
+- added the possibility to select an preprocessor for Excellon Object
+- added a new preprocessor, manual_toolchange.py. It allows to change
the tools and adjust the drill tip to touch the surface manually, always
in the X=0, Y=0, Z = toolchangeZ coordinates.
- fixed drillcncjob TCL command by adding toolchangeZ parameter
-- fixed the posprocessor file template 'default.py' in the toolchange
+- fixed the preprocessor file template 'default.py' in the toolchange
command section
- after I created a feature that the message in infobar is cleared by
moving mouse on canvas, it generated a bug in TCL shell: everytime
From c2373da17ad4fc5873a6d5d6e28670b4a8b79892 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 12 Feb 2020 16:43:13 +0200
Subject: [PATCH 083/209] - working on fixing a bug in FlatCAMGeometry.merge()
---
FlatCAMApp.py | 7 +++--
FlatCAMObj.py | 53 +++++++++++++++++++---------------
README.md | 6 ++++
flatcamTools/ToolProperties.py | 6 +++-
4 files changed, 44 insertions(+), 28 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 8fe6897a..b1eca4af 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -5689,11 +5689,12 @@ class App(QtCore.QObject):
if True in geo_type_set:
def initialize(geo_obj, app):
FlatCAMGeometry.merge(self, geo_list=objs, geo_final=geo_obj, multigeo=True)
- app.inform.emit('[success] %s.' % _("Multigeo. Geometry merging finished"))
+ app.inform.emit('[success] %s.' % _("Geometry merging finished"))
# rename all the ['name] key in obj.tools[tooluid]['data'] to the obj_name_multi
- for v in obj.tools.values():
+ for v in geo_obj.tools.values():
v['data']['name'] = obj_name_multi
+
self.new_object("geometry", obj_name_multi, initialize)
else:
def initialize(geo_obj, app):
@@ -5701,7 +5702,7 @@ class App(QtCore.QObject):
app.inform.emit('[success] %s.' % _("Geometry merging finished"))
# rename all the ['name] key in obj.tools[tooluid]['data'] to the obj_name_multi
- for v in obj.tools.values():
+ for v in geo_obj.tools.values():
v['data']['name'] = obj_name_single
self.new_object("geometry", obj_name_single, initialize)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index da4a2a07..c43e0dbb 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -6268,53 +6268,58 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
"""
if geo_final.solid_geometry is None:
- geo_final.solid_geometry = []
+ geo_final.solid_geometry = list()
- if type(geo_final.solid_geometry) is not list:
+ try:
+ __ = iter(geo_final.solid_geometry)
+ except TypeError:
geo_final.solid_geometry = [geo_final.solid_geometry]
- for geo in geo_list:
- for option in geo.options:
+ new_solid_geometry = list()
+ new_options = dict()
+ new_tools = dict()
+
+ for geo_obj in geo_list:
+ for option in geo_obj.options:
if option is not 'name':
try:
- geo_final.options[option] = deepcopy(geo.options[option])
+ new_options[option] = geo_obj.options[option]
except Exception as e:
log.warning("Failed to copy option %s. Error: %s" % (str(option), str(e)))
# Expand lists
- if type(geo) is list:
- FlatCAMGeometry.merge(self, geo_list=geo, geo_final=geo_final)
+ if type(geo_obj) is list:
+ FlatCAMGeometry.merge(self, geo_list=geo_obj, geo_final=geo_final)
# If not list, just append
else:
- # merge solid_geometry, useful for singletool geometry, for multitool each is empty
if multigeo is None or multigeo is False:
geo_final.multigeo = False
- try:
- geo_final.solid_geometry.append(deepcopy(geo.solid_geometry))
- except Exception as e:
- log.debug("FlatCAMGeometry.merge() --> %s" % str(e))
else:
geo_final.multigeo = True
- # if multigeo the solid_geometry is empty in the object attributes because it now lives in the
- # tools object attribute, as a key value
- geo_final.solid_geometry = []
-
- # find the tool_uid maximum value in the geo_final
- geo_final_uid_list = []
- for key in geo_final.tools:
- geo_final_uid_list.append(int(key))
try:
- max_uid = max(geo_final_uid_list, key=int)
+ new_solid_geometry.append(geo_obj.solid_geometry)
+ except Exception as e:
+ log.debug("FlatCAMGeometry.merge() --> %s" % str(e))
+
+ # find the tool_uid maximum value in the geo_final
+ try:
+ max_uid = max([int(i) for i in new_tools.keys()])
except ValueError:
max_uid = 0
# add and merge tools. If what we try to merge as Geometry is Excellon's and/or Gerber's then don't try
# to merge the obj.tools as it is likely there is none to merge.
- if not isinstance(geo, FlatCAMGerber) and not isinstance(geo, FlatCAMExcellon):
- for tool_uid in geo.tools:
+ if not isinstance(geo_obj, FlatCAMGerber) and not isinstance(geo_obj, FlatCAMExcellon):
+ for tool_uid in geo_obj.tools:
max_uid += 1
- geo_final.tools[max_uid] = deepcopy(geo.tools[tool_uid])
+ new_tools[max_uid] = geo_obj.tools[tool_uid]
+
+ geo_final.options.update(deepcopy(new_options))
+ geo_final.solid_geometry = deepcopy(list(geo_final.flatten_list(new_solid_geometry)))
+ geo_final.tools = deepcopy(new_tools)
+ for td in geo_final.tools:
+ print(td, geo_final.tools[td])
@staticmethod
def get_pts(o):
diff --git a/README.md b/README.md
index 5c264eac..b1fe58ff 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,12 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+12.02.2020
+
+
+- working on fixing a bug in FlatCAMGeometry.merge()
+
+
11.02.2020
- working on Tool Punch; finished the geometry update with the clear geometry for the case of Excellon method
diff --git a/flatcamTools/ToolProperties.py b/flatcamTools/ToolProperties.py
index 6429982e..78e48afc 100644
--- a/flatcamTools/ToolProperties.py
+++ b/flatcamTools/ToolProperties.py
@@ -425,7 +425,11 @@ class Properties(FlatCAMTool):
tools, str(tool), expanded=True, color=QtGui.QColor("#000000"), font=font)
for k, v in value.items():
if k == 'solid_geometry':
- printed_value = _('Present') if v else _('None')
+ # printed_value = _('Present') if v else _('None')
+ try:
+ printed_value = str(len(v))
+ except (TypeError, AttributeError):
+ printed_value = '1'
self.treeWidget.addChild(geo_tool, [str(k), printed_value], True)
elif k == 'data':
tool_data = self.treeWidget.addParent(
From b3ba2d32da5af4871fbe0902476b3368093786a4 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 12 Feb 2020 16:47:11 +0200
Subject: [PATCH 084/209] - working on fixing a bug in FlatCAMGeometry.merge()
- FIXED
---
FlatCAMObj.py | 12 +++++-------
README.md | 2 +-
2 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index c43e0dbb..0d3ca646 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -5618,10 +5618,10 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# find the tool_dia associated with the tooluid_key
# search in the self.tools for the sel_tool_dia and when found see what tooluid has
# on the found tooluid in self.tools we also have the solid_geometry that interest us
- for k, v in self.tools.items():
- if float('%.*f' % (self.decimals, float(v['tooldia']))) == tooldia_val:
- current_uid = int(k)
- break
+ # for k, v in self.tools.items():
+ # if float('%.*f' % (self.decimals, float(v['tooldia']))) == tooldia_val:
+ # current_uid = int(k)
+ # break
if dia_cnc_dict['offset'] == 'in':
tool_offset = -tooldia_val / 2
@@ -5664,7 +5664,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
pp_geometry_name = tools_dict[tooluid_key]['data']["ppname_g"]
spindledir = self.app.defaults['geometry_spindledir']
- tool_solid_geometry = self.tools[current_uid]['solid_geometry']
+ tool_solid_geometry = self.tools[tooluid_key]['solid_geometry']
job_obj.coords_decimals = self.app.defaults["cncjob_coords_decimals"]
job_obj.fr_decimals = self.app.defaults["cncjob_fr_decimals"]
@@ -6318,8 +6318,6 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
geo_final.options.update(deepcopy(new_options))
geo_final.solid_geometry = deepcopy(list(geo_final.flatten_list(new_solid_geometry)))
geo_final.tools = deepcopy(new_tools)
- for td in geo_final.tools:
- print(td, geo_final.tools[td])
@staticmethod
def get_pts(o):
diff --git a/README.md b/README.md
index b1fe58ff..ef44379e 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ CAD program, and create G-Code for Isolation routing.
12.02.2020
-- working on fixing a bug in FlatCAMGeometry.merge()
+- working on fixing a bug in FlatCAMGeometry.merge() - FIXED
11.02.2020
From 8665d4c90da4c95d460fa0195f4ccb38052348ef Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 12 Feb 2020 17:15:34 +0200
Subject: [PATCH 085/209] - added a debug message
---
FlatCAMApp.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index b1eca4af..cbbdee3b 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -7162,8 +7162,10 @@ class App(QtCore.QObject):
try:
obj_active.annotation.clear(update=True)
obj_active.annotation.enabled = False
- except AttributeError:
- pass
+ except AttributeError as e:
+ log.debug(
+ "App.on_delete() --> delete annotations on a FlatCAMCNCJob object. %s" % str(e)
+ )
self.delete_first_selected()
self.inform.emit('%s...' % _("Object(s) deleted"))
From e936e0e1163722c273d62f61d1d66695004fa6d6 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 12 Feb 2020 23:28:21 +0200
Subject: [PATCH 086/209] - fixed bug: when deleting a FlatCAMCNCJob with
annotations enabled, the annotations are not deleted from canvas; - fixed
bug: creating a new project while a project is open and it contain CNCJob
annotations and/or Gerber mark shapes, did not delete them from canvas
---
FlatCAMApp.py | 22 ++++++++++------
FlatCAMObj.py | 12 ++++-----
README.md | 2 ++
camlib.py | 69 ++++++++++++++++++++++++---------------------------
4 files changed, 55 insertions(+), 50 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index cbbdee3b..16c98005 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -7149,8 +7149,7 @@ class App(QtCore.QObject):
if self.collection.get_active():
self.log.debug("App.on_delete()")
- while self.collection.get_active():
- obj_active = self.collection.get_active()
+ for obj_active in self.collection.get_selected():
# if the deleted object is FlatCAMGerber then make sure to delete the possible mark shapes
if isinstance(obj_active, FlatCAMGerber):
for el in obj_active.mark_shapes:
@@ -7160,12 +7159,16 @@ class App(QtCore.QObject):
del el
elif isinstance(obj_active, FlatCAMCNCjob):
try:
+ obj_active.text_col.enabled = False
+ del obj_active.text_col
obj_active.annotation.clear(update=True)
- obj_active.annotation.enabled = False
+ del obj_active.annotation
except AttributeError as e:
log.debug(
"App.on_delete() --> delete annotations on a FlatCAMCNCJob object. %s" % str(e)
)
+
+ while self.collection.get_selected():
self.delete_first_selected()
self.inform.emit('%s...' % _("Object(s) deleted"))
@@ -9280,8 +9283,7 @@ class App(QtCore.QObject):
self.on_file_new()
else:
self.on_file_new()
- self.inform.emit('[success] %s...' %
- _("New Project created"))
+ self.inform.emit('[success] %s...' % _("New Project created"))
def on_file_new(self, cli=None):
"""
@@ -9310,16 +9312,20 @@ class App(QtCore.QObject):
# delete shapes left drawn from mark shape_collections, if any
if isinstance(obj, FlatCAMGerber):
try:
- obj.mark_shapes.enabled = False
- obj.mark_shapes.clear(update=True)
+ for el in obj.mark_shapes:
+ obj.mark_shapes[el].clear(update=True)
+ obj.mark_shapes[el].enabled = False
+ del el
except AttributeError:
pass
# also delete annotation shapes, if any
elif isinstance(obj, FlatCAMCNCjob):
try:
- obj.annotation.enabled = False
+ obj.text_col.enabled = False
+ del obj.text_col
obj.annotation.clear(update=True)
+ del obj.annotation
except AttributeError:
pass
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 0d3ca646..8a1023b7 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -6283,7 +6283,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
for option in geo_obj.options:
if option is not 'name':
try:
- new_options[option] = geo_obj.options[option]
+ new_options[option] = deepcopy(geo_obj.options[option])
except Exception as e:
log.warning("Failed to copy option %s. Error: %s" % (str(option), str(e)))
@@ -6298,7 +6298,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
geo_final.multigeo = True
try:
- new_solid_geometry.append(geo_obj.solid_geometry)
+ new_solid_geometry += deepcopy(geo_obj.solid_geometry)
except Exception as e:
log.debug("FlatCAMGeometry.merge() --> %s" % str(e))
@@ -6313,11 +6313,11 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
if not isinstance(geo_obj, FlatCAMGerber) and not isinstance(geo_obj, FlatCAMExcellon):
for tool_uid in geo_obj.tools:
max_uid += 1
- new_tools[max_uid] = geo_obj.tools[tool_uid]
+ new_tools[max_uid] = deepcopy(geo_obj.tools[tool_uid])
- geo_final.options.update(deepcopy(new_options))
- geo_final.solid_geometry = deepcopy(list(geo_final.flatten_list(new_solid_geometry)))
- geo_final.tools = deepcopy(new_tools)
+ geo_final.options.update(new_options)
+ geo_final.solid_geometry = new_solid_geometry
+ geo_final.tools = new_tools
@staticmethod
def get_pts(o):
diff --git a/README.md b/README.md
index ef44379e..23c5ed06 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,8 @@ CAD program, and create G-Code for Isolation routing.
- working on fixing a bug in FlatCAMGeometry.merge() - FIXED
+- fixed bug: when deleting a FlatCAMCNCJob with annotations enabled, the annotations are not deleted from canvas;
+- fixed bug: creating a new project while a project is open and it contain CNCJob annotations and/or Gerber mark shapes, did not delete them from canvas
11.02.2020
diff --git a/camlib.py b/camlib.py
index 2fb8180e..a939f9a1 100644
--- a/camlib.py
+++ b/camlib.py
@@ -948,7 +948,7 @@ class Geometry(object):
pol_nr += 1
disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
- if old_disp_number < disp_number <= 100:
+ if old_disp_number < disp_number <= 100:
self.app.proc_container.update_view_text(' %s %d: %d%%' %
(_("Pass"), int(passes + 1), int(disp_number)))
old_disp_number = disp_number
@@ -979,8 +979,8 @@ class Geometry(object):
log.debug("Geometry.isolation_geometry() --> Type of isolation not supported")
return "fail"
- def flatten_list(self, list):
- for item in list:
+ def flatten_list(self, obj_list):
+ for item in obj_list:
if isinstance(item, Iterable) and not isinstance(item, (str, bytes)):
yield from self.flatten_list(item)
else:
@@ -1187,7 +1187,6 @@ class Geometry(object):
if boundary is None:
boundary = self.solid_geometry.envelope
return boundary.difference(self.solid_geometry)
-
def clear_polygon(self, polygon, tooldia, steps_per_circle, overlap=0.15, connect=True, contour=True,
prog_plot=False):
@@ -1441,7 +1440,7 @@ class Geometry(object):
try:
margin_poly = polygon.buffer(-tooldia / 1.99999999, (int(steps_per_circle)))
- except Exception as e:
+ except Exception:
log.debug("camlib.Geometry.clear_polygon3() --> Could not buffer the Polygon")
return None
@@ -1571,6 +1570,7 @@ class Geometry(object):
This algorithm draws parallel lines inside the polygon.
:param line: The target line that create painted polygon.
+ :param aperture_size: the size of the aperture that is used to draw the 'line' as a polygon
:type line: shapely.geometry.LineString or shapely.geometry.MultiLineString
:param tooldia: Tool diameter.
:param steps_per_circle: how many linear segments to use to approximate a circle
@@ -1758,7 +1758,7 @@ class Geometry(object):
# storage.get_points = get_pts
#
# for shape in geolist:
- # if shape is not None: # TODO: This shouldn't have happened.
+ # if shape is not None:
# # Make LlinearRings into linestrings otherwise
# # When chaining the coordinates path is messed up.
# storage.insert(LineString(shape))
@@ -2268,8 +2268,7 @@ class Geometry(object):
# variables to display the percentage of work done
self.geo_len = 0
try:
- for g in self.solid_geometry:
- self.geo_len += 1
+ self.geo_len = len(self.solid_geometry)
except TypeError:
self.geo_len = 1
self.old_disp_number = 0
@@ -2355,7 +2354,7 @@ class Geometry(object):
self.solid_geometry = buffer_geom(self.solid_geometry)
- self.app.inform.emit('[success] %s...' % _('Object was buffered'))
+ self.app.inform.emit('[success] %s...' % _('Object was buffered'))
except AttributeError:
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed to buffer. No object selected"))
@@ -2387,8 +2386,8 @@ class CNCjob(Geometry):
defaults = {
"global_zdownrate": None,
- "pp_geometry_name":'default',
- "pp_excellon_name":'default',
+ "pp_geometry_name": 'default',
+ "pp_excellon_name": 'default',
"excellon_optimization_type": "B",
}
@@ -2591,7 +2590,7 @@ class CNCjob(Geometry):
must_visit.remove(nearest)
return path
- def generate_from_excellon_by_tool(self, exobj, tools="all", drillz = 3.0, toolchange=False, toolchangez=0.1,
+ def generate_from_excellon_by_tool(self, exobj, tools="all", drillz=3.0, toolchange=False, toolchangez=0.1,
toolchangexy='', endz=2.0, startz=None, excellon_optimization_type='B'):
"""
Creates gcode for this object from an Excellon object
@@ -2675,7 +2674,7 @@ class CNCjob(Geometry):
sort = []
for k, v in list(exobj.tools.items()):
sort.append((k, v.get('C')))
- sorted_tools = sorted(sort,key=lambda t1: t1[1])
+ sorted_tools = sorted(sort, key=lambda t1: t1[1])
if tools == "all":
tools = [i[0] for i in sorted_tools] # we get a array of ordered tools
@@ -2783,7 +2782,7 @@ class CNCjob(Geometry):
"""Initialize distance array."""
locations = create_data_array()
size = len(locations)
- self.matrix = {}
+ self.matrix = dict()
for from_node in range(size):
self.matrix[from_node] = {}
@@ -2833,7 +2832,7 @@ class CNCjob(Geometry):
log.debug("Using OR-Tools Metaheuristic Guided Local Search drill path optimization.")
if exobj.drills:
for tool in tools:
- self.tool=tool
+ self.tool = tool
self.postdata['toolC'] = exobj.tools[tool]["C"]
self.tooldia = exobj.tools[tool]["C"]
@@ -3019,7 +3018,7 @@ class CNCjob(Geometry):
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
- self.tool=tool
+ self.tool = tool
self.postdata['toolC']=exobj.tools[tool]["C"]
self.tooldia = exobj.tools[tool]["C"]
@@ -3105,7 +3104,6 @@ class CNCjob(Geometry):
# Drillling! for Absolute coordinates type G90
# variables to display the percentage of work done
geo_len = len(node_list)
- disp_number = 0
old_disp_number = 0
log.warning("Number of drills for which to generate GCode: %s" % str(geo_len))
@@ -3237,7 +3235,6 @@ class CNCjob(Geometry):
node_list = self.optimized_travelling_salesman(altPoints)
# variables to display the percentage of work done
geo_len = len(node_list)
- disp_number = 0
old_disp_number = 0
log.warning("Number of drills for which to generate GCode: %s" % str(geo_len))
@@ -3299,7 +3296,7 @@ class CNCjob(Geometry):
self.app.proc_container.update_view_text(' %d%%' % disp_number)
old_disp_number = disp_number
else:
- self.app.inform.emit('[ERROR_NOTCL] %s...' % _('G91 coordinates not implemented'))
+ self.app.inform.emit('[ERROR_NOTCL] %s...' % _('G91 coordinates not implemented'))
return 'fail'
else:
log.debug("camlib.CNCJob.generate_from_excellon_by_tool() --> "
@@ -3564,9 +3561,9 @@ class CNCjob(Geometry):
current_tooldia = float('%.*f' % (self.decimals, float(self.tooldia)))
- self.app.inform.emit( '%s: %s%s.' % (_("Starting G-Code for tool with diameter"),
- str(current_tooldia),
- str(self.units)))
+ self.app.inform.emit('%s: %s%s.' % (_("Starting G-Code for tool with diameter"),
+ str(current_tooldia),
+ str(self.units)))
pt, geo = storage.nearest(current_pt)
@@ -3886,8 +3883,8 @@ class CNCjob(Geometry):
self.gcode += self.doformat(p.feedrate_code) # sets the feed rate
if toolchange is False:
- self.gcode += self.doformat(p.lift_code, x=self.oldx , y=self.oldy ) # Move (up) to travel height
- self.gcode += self.doformat(p.startz_code, x=self.oldx , y=self.oldy )
+ self.gcode += self.doformat(p.lift_code, x=self.oldx, y=self.oldy) # Move (up) to travel height
+ self.gcode += self.doformat(p.startz_code, x=self.oldx , y=self.oldy)
if toolchange:
# if "line_xyz" in self.pp_geometry_name:
@@ -3975,7 +3972,7 @@ class CNCjob(Geometry):
total_travel += abs(distance(pt1=current_pt, pt2=pt))
current_pt = geo.coords[-1]
- pt, geo = storage.nearest(current_pt) # Next
+ pt, geo = storage.nearest(current_pt) # Next
disp_number = int(np.interp(path_count, [0, geo_len], [0, 100]))
if old_disp_number < disp_number <= 100:
@@ -4077,7 +4074,6 @@ class CNCjob(Geometry):
# variables to display the percentage of work done
geo_len = len(flat_geometry)
- disp_number = 0
old_disp_number = 0
pt, geo = storage.nearest(current_pt)
@@ -4141,7 +4137,7 @@ class CNCjob(Geometry):
# Move down to cutting depth
gcode += self.doformat(p.z_feedrate_code)
gcode += self.doformat(p.down_z_start_code)
- gcode += self.doformat(p.spindle_fwd_code) # Start dispensing
+ gcode += self.doformat(p.spindle_fwd_code) # Start dispensing
gcode += self.doformat(p.dwell_fwd_code)
gcode += self.doformat(p.feedrate_z_dispense_code)
gcode += self.doformat(p.lift_z_dispense_code)
@@ -4164,7 +4160,7 @@ class CNCjob(Geometry):
prev_y = next_y
# Up to travelling height.
- gcode += self.doformat(p.spindle_off_code) # Stop dispensing
+ gcode += self.doformat(p.spindle_off_code) # Stop dispensing
gcode += self.doformat(p.spindle_rev_code)
gcode += self.doformat(p.down_z_stop_code)
gcode += self.doformat(p.spindle_off_code)
@@ -4176,7 +4172,7 @@ class CNCjob(Geometry):
gcode += self.doformat(p.feedrate_z_dispense_code)
gcode += self.doformat(p.down_z_start_code)
- gcode += self.doformat(p.spindle_fwd_code) # Start dispensing
+ gcode += self.doformat(p.spindle_fwd_code) # Start dispensing
gcode += self.doformat(p.dwell_fwd_code)
gcode += self.doformat(p.lift_z_dispense_code)
@@ -4191,7 +4187,6 @@ class CNCjob(Geometry):
def create_gcode_single_pass(self, geometry, extracut, extracut_length, tolerance, old_point=(0, 0)):
# G-code. Note: self.linear2gcode() and self.point2gcode() will lower and raise the tool every time.
- gcode_single_pass = ''
if type(geometry) == LineString or type(geometry) == LinearRing:
if extracut is False:
@@ -4574,8 +4569,8 @@ class CNCjob(Geometry):
if geo['kind'][0] == 'C':
obj.add_shape(shape=geo['geom'], color=color['C'][1], visible=visible)
else:
- text = []
- pos = []
+ text = list()
+ pos = list()
self.coordinates_type = self.app.defaults["cncjob_coords_type"]
if self.coordinates_type == "G90":
# For Absolute coordinates type G90
@@ -5084,10 +5079,10 @@ class CNCjob(Geometry):
if self.z_feedrate is not None:
gcode += self.doformat(p.z_feedrate_code)
- gcode += self.doformat(p.down_code, x=first_x, y=first_y, z_cut = self.z_cut)
+ gcode += self.doformat(p.down_code, x=first_x, y=first_y, z_cut=self.z_cut)
gcode += self.doformat(p.feedrate_code)
else:
- gcode += self.doformat(p.down_code, x=first_x, y=first_y, z_cut = self.z_cut) # Start cutting
+ gcode += self.doformat(p.down_code, x=first_x, y=first_y, z_cut=self.z_cut) # Start cutting
gcode += self.doformat(p.lift_code, x=first_x, y=first_y) # Stop cutting
return gcode
@@ -5122,8 +5117,10 @@ class CNCjob(Geometry):
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
- if g['kind'][0] == 'C': cuts.append(g)
- if g['kind'][0] == 'T': travels.append(g)
+ if g['kind'][0] == 'C':
+ cuts.append(g)
+ if g['kind'][0] == 'T':
+ travels.append(g)
# Used to determine the overall board size
self.solid_geometry = cascaded_union([geo['geom'] for geo in self.gcode_parsed])
From 1a2b6501f859456d5db4ab7359c35842bad348dc Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 12 Feb 2020 23:30:28 +0200
Subject: [PATCH 087/209] - updated the ReadMe to update that the latest issues
were fixed
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 23c5ed06..4f826947 100644
--- a/README.md
+++ b/README.md
@@ -12,8 +12,8 @@ CAD program, and create G-Code for Isolation routing.
12.02.2020
-- working on fixing a bug in FlatCAMGeometry.merge() - FIXED
-- fixed bug: when deleting a FlatCAMCNCJob with annotations enabled, the annotations are not deleted from canvas;
+- working on fixing a bug in FlatCAMGeometry.merge() - FIXED issue #380
+- fixed bug: when deleting a FlatCAMCNCJob with annotations enabled, the annotations are not deleted from canvas; fixed issue #379
- fixed bug: creating a new project while a project is open and it contain CNCJob annotations and/or Gerber mark shapes, did not delete them from canvas
From 7c9c390ac3816cd130940225717bbe850b66f1d5 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 13 Feb 2020 21:06:10 +0200
Subject: [PATCH 088/209] - finished Punch Gerber Tool - minor PEP8 changes
---
FlatCAMApp.py | 63 ++++--
README.md | 6 +-
flatcamGUI/FlatCAMGUI.py | 10 +-
flatcamGUI/PreferencesUI.py | 239 ++++++++++++++++++++++-
flatcamTools/ToolExtractDrills.py | 16 +-
flatcamTools/ToolPunchGerber.py | 315 ++++++++++++++++++++++++++++--
6 files changed, 599 insertions(+), 50 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 16c98005..7f3596e3 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -9,7 +9,6 @@
import urllib.request
import urllib.parse
import urllib.error
-import webbrowser
import getopt
import random
@@ -141,7 +140,7 @@ class App(QtCore.QObject):
# ################## Version and VERSION DATE ##############################
# ##########################################################################
version = 8.992
- version_date = "2020/02/12"
+ version_date = "2020/02/22"
beta = True
engine = '3D'
@@ -985,6 +984,21 @@ class App(QtCore.QObject):
"tools_edrills_rectangular": False,
"tools_edrills_others": False,
+ # Punch Gerber Tool
+ "tools_punch_hole_type": 'exc',
+ "tools_punch_hole_fixed_dia": 0.5,
+ "tools_punch_hole_prop_factor": 80.0,
+ "tools_punch_circular_ring": 0.2,
+ "tools_punch_oblong_ring": 0.2,
+ "tools_punch_square_ring": 0.2,
+ "tools_punch_rectangular_ring": 0.2,
+ "tools_punch_others_ring": 0.2,
+ "tools_punch_circular": True,
+ "tools_punch_oblong": False,
+ "tools_punch_square": True,
+ "tools_punch_rectangular": False,
+ "tools_punch_others": False,
+
# Align Objects Tool
"tools_align_objects_align_type": 'sp',
@@ -1637,6 +1651,21 @@ class App(QtCore.QObject):
"tools_edrills_rectangular": self.ui.tools2_defaults_form.tools2_edrills_group.rectangular_cb,
"tools_edrills_others": self.ui.tools2_defaults_form.tools2_edrills_group.other_cb,
+ # Punch Gerber Tool
+ "tools_punch_hole_type": self.ui.tools2_defaults_form.tools2_punch_group.hole_size_radio,
+ "tools_punch_hole_fixed_dia": self.ui.tools2_defaults_form.tools2_punch_group.dia_entry,
+ "tools_punch_hole_prop_factor": self.ui.tools2_defaults_form.tools2_punch_group.factor_entry,
+ "tools_punch_circular_ring": self.ui.tools2_defaults_form.tools2_punch_group.circular_ring_entry,
+ "tools_punch_oblong_ring": self.ui.tools2_defaults_form.tools2_punch_group.oblong_ring_entry,
+ "tools_punch_square_ring": self.ui.tools2_defaults_form.tools2_punch_group.square_ring_entry,
+ "tools_punch_rectangular_ring": self.ui.tools2_defaults_form.tools2_punch_group.rectangular_ring_entry,
+ "tools_punch_others_ring": self.ui.tools2_defaults_form.tools2_punch_group.other_ring_entry,
+ "tools_punch_circular": self.ui.tools2_defaults_form.tools2_punch_group.circular_cb,
+ "tools_punch_oblong": self.ui.tools2_defaults_form.tools2_punch_group.oblong_cb,
+ "tools_punch_square": self.ui.tools2_defaults_form.tools2_punch_group.square_cb,
+ "tools_punch_rectangular": self.ui.tools2_defaults_form.tools2_punch_group.rectangular_cb,
+ "tools_punch_others": self.ui.tools2_defaults_form.tools2_punch_group.other_cb,
+
# Utilities
# File associations
"fa_excellon": self.ui.util_defaults_form.fa_excellon_group.exc_list_text,
@@ -3459,7 +3488,7 @@ class App(QtCore.QObject):
edited_obj.options['xmax'] = xmax
edited_obj.options['ymax'] = ymax
except AttributeError as e:
- self.inform.emit('[WARNING] %s' % _("Object empty after edit."))
+ self.inform.emit('[WARNING] %s' % _("Object empty after edit."))
log.debug("App.editor2object() --> Geometry --> %s" % str(e))
edited_obj.build_ui()
@@ -5972,7 +6001,6 @@ class App(QtCore.QObject):
tools_diameters[t] *= sfactor
self.defaults['geometry_cnctooldia'] += "%.*f," % (self.decimals, tools_diameters[t])
elif dim == 'tools_ncctools':
- ncctools = list()
if type(self.defaults["tools_ncctools"]) == float:
ncctools = [self.defaults["tools_ncctools"]]
else:
@@ -5988,7 +6016,6 @@ class App(QtCore.QObject):
ncctools[t] *= sfactor
self.defaults['tools_ncctools'] += "%.*f," % (self.decimals, ncctools[t])
elif dim == 'tools_solderpaste_tools':
- sptools = list()
if type(self.defaults["tools_solderpaste_tools"]) == float:
sptools = [self.defaults["tools_solderpaste_tools"]]
else:
@@ -6017,7 +6044,6 @@ class App(QtCore.QObject):
elif dim == 'global_gridx' or dim == 'global_gridy':
if new_units == 'IN':
- val = 0.1
try:
val = float(self.defaults[dim]) * sfactor
except Exception as e:
@@ -6026,7 +6052,6 @@ class App(QtCore.QObject):
self.defaults[dim] = float('%.*f' % (self.decimals, val))
else:
- val = 0.1
try:
val = float(self.defaults[dim]) * sfactor
except Exception as e:
@@ -6035,7 +6060,6 @@ class App(QtCore.QObject):
self.defaults[dim] = float('%.*f' % (self.decimals, val))
else:
- val = 0.1
if self.defaults[dim]:
try:
val = float(self.defaults[dim]) * sfactor
@@ -7149,7 +7173,7 @@ class App(QtCore.QObject):
if self.collection.get_active():
self.log.debug("App.on_delete()")
- for obj_active in self.collection.get_selected():
+ for obj_active in self.collection.get_selected():
# if the deleted object is FlatCAMGerber then make sure to delete the possible mark shapes
if isinstance(obj_active, FlatCAMGerber):
for el in obj_active.mark_shapes:
@@ -7692,6 +7716,7 @@ class App(QtCore.QObject):
obj_init.follow_geometry = deepcopy(obj.follow_geometry)
except AttributeError:
pass
+
try:
obj_init.apertures = deepcopy(obj.apertures)
except AttributeError:
@@ -7725,8 +7750,8 @@ class App(QtCore.QObject):
self.new_object("gerber", str(obj_name) + custom_name, initialize_gerber)
elif isinstance(obj, FlatCAMGeometry):
self.new_object("geometry", str(obj_name) + custom_name, initialize_geometry)
- except Exception as e:
- return "Operation failed: %s" % str(e)
+ except Exception as er:
+ return "Operation failed: %s" % str(er)
def on_rename_object(self, text):
self.report_usage("on_rename_object()")
@@ -8761,7 +8786,7 @@ class App(QtCore.QObject):
try: # May fail in case mouse not within axes
pos_canvas = self.plotcanvas.translate_coords(event_pos)
- if self.grid_status() == True:
+ if self.grid_status():
pos = self.geo_editor.snap(pos_canvas[0], pos_canvas[1])
# Update cursor
@@ -8847,7 +8872,7 @@ class App(QtCore.QObject):
right_button = 3
pos_canvas = self.plotcanvas.translate_coords(event_pos)
- if self.grid_status() == True:
+ if self.grid_status():
pos = self.geo_editor.snap(pos_canvas[0], pos_canvas[1])
else:
pos = (pos_canvas[0], pos_canvas[1])
@@ -10446,8 +10471,8 @@ class App(QtCore.QObject):
try:
filename, _f = QtWidgets.QFileDialog.getSaveFileName(
caption=_("Save Project As ..."),
- directory=('{l_save}/{proj}_{date}').format(l_save=str(self.get_last_save_folder()), date=self.date,
- proj=_("Project")),
+ directory='{l_save}/{proj}_{date}'.format(l_save=str(self.get_last_save_folder()), date=self.date,
+ proj=_("Project")),
filter=filter_
)
except TypeError:
@@ -10500,9 +10525,9 @@ class App(QtCore.QObject):
try:
filename, _f = QtWidgets.QFileDialog.getSaveFileName(
caption=_("Save Object as PDF ..."),
- directory=('{l_save}/{obj_name}_{date}').format(l_save=str(self.get_last_save_folder()),
- obj_name=obj_name,
- date=self.date),
+ directory='{l_save}/{obj_name}_{date}'.format(l_save=str(self.get_last_save_folder()),
+ obj_name=obj_name,
+ date=self.date),
filter=filter_
)
except TypeError:
@@ -11484,7 +11509,7 @@ class App(QtCore.QObject):
# # ## Object creation # ##
ret = self.new_object("geometry", name, obj_init, autoselected=False)
if ret == 'fail':
- self.inform.emit('[ERROR_NOTCL]%s' % _(' Open HPGL2 failed. Probable not a HPGL2 file.'))
+ self.inform.emit('[ERROR_NOTCL]%s' % _(' Open HPGL2 failed. Probable not a HPGL2 file.'))
return 'fail'
# Register recent file
diff --git a/README.md b/README.md
index 4f826947..8ab918e5 100644
--- a/README.md
+++ b/README.md
@@ -9,14 +9,16 @@ CAD program, and create G-Code for Isolation routing.
=================================================
-12.02.2020
+13.02.2020
+- finished Punch Gerber Tool
+
+12.02.2020
- working on fixing a bug in FlatCAMGeometry.merge() - FIXED issue #380
- fixed bug: when deleting a FlatCAMCNCJob with annotations enabled, the annotations are not deleted from canvas; fixed issue #379
- fixed bug: creating a new project while a project is open and it contain CNCJob annotations and/or Gerber mark shapes, did not delete them from canvas
-
11.02.2020
- working on Tool Punch; finished the geometry update with the clear geometry for the case of Excellon method
diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py
index b67b4c0e..b8154db7 100644
--- a/flatcamGUI/FlatCAMGUI.py
+++ b/flatcamGUI/FlatCAMGUI.py
@@ -1559,6 +1559,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
| ALT+E |
%s |
+
+ | ALT+H |
+ %s |
+
| ALT+I |
%s |
@@ -1688,7 +1692,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
_("Skew on Y axis"),
# ALT section
_("Align Objects Tool"), _("Calculators Tool"), _("2-Sided PCB Tool"), _("Transformations Tool"),
- _("Extract Drills Tool"), _("Fiducials Tool"),
+ _("Punch Gerber Tool"), _("Extract Drills Tool"), _("Fiducials Tool"),
_("Solder Paste Dispensing Tool"),
_("Film PCB Tool"), _("Non-Copper Clearing Tool"), _("Optimal Tool"),
_("Paint Area Tool"), _("QRCode Tool"), _("Rules Check Tool"),
@@ -2974,6 +2978,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
return
# Align in Object Tool
+ if key == QtCore.Qt.Key_H:
+ self.app.punch_tool.run(toggle=True)
+
+ # Extract Drills Tool
if key == QtCore.Qt.Key_I:
self.app.edrills_tool.run(toggle=True)
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index b003b71c..eeeb413a 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -249,6 +249,9 @@ class Tools2PreferencesUI(QtWidgets.QWidget):
self.tools2_edrills_group = Tools2EDrillsPrefGroupUI(decimals=self.decimals)
self.tools2_edrills_group.setMinimumWidth(220)
+ self.tools2_punch_group = Tools2PunchGerberPrefGroupUI(decimals=self.decimals)
+ self.tools2_punch_group.setMinimumWidth(220)
+
self.vlay = QtWidgets.QVBoxLayout()
self.vlay.addWidget(self.tools2_checkrules_group)
self.vlay.addWidget(self.tools2_optimal_group)
@@ -264,10 +267,14 @@ class Tools2PreferencesUI(QtWidgets.QWidget):
self.vlay3.addWidget(self.tools2_cal_group)
self.vlay3.addWidget(self.tools2_edrills_group)
+ self.vlay4 = QtWidgets.QVBoxLayout()
+ self.vlay4.addWidget(self.tools2_punch_group)
+
self.layout.addLayout(self.vlay)
self.layout.addLayout(self.vlay1)
self.layout.addLayout(self.vlay2)
self.layout.addLayout(self.vlay3)
+ self.layout.addLayout(self.vlay4)
self.layout.addStretch()
@@ -7838,7 +7845,7 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI):
# Circular Aperture Selection
self.circular_cb = FCCheckBox('%s' % _("Circular"))
self.circular_cb.setToolTip(
- _("Create drills from circular pads.")
+ _("Process Circular Pads.")
)
grid_lay.addWidget(self.circular_cb, 3, 0, 1, 2)
@@ -7846,7 +7853,7 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI):
# Oblong Aperture Selection
self.oblong_cb = FCCheckBox('%s' % _("Oblong"))
self.oblong_cb.setToolTip(
- _("Create drills from oblong pads.")
+ _("Process Oblong Pads.")
)
grid_lay.addWidget(self.oblong_cb, 4, 0, 1, 2)
@@ -7854,7 +7861,7 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI):
# Square Aperture Selection
self.square_cb = FCCheckBox('%s' % _("Square"))
self.square_cb.setToolTip(
- _("Create drills from square pads.")
+ _("Process Square Pads.")
)
grid_lay.addWidget(self.square_cb, 5, 0, 1, 2)
@@ -7862,7 +7869,7 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI):
# Rectangular Aperture Selection
self.rectangular_cb = FCCheckBox('%s' % _("Rectangular"))
self.rectangular_cb.setToolTip(
- _("Create drills from rectangular pads.")
+ _("Process Rectangular Pads.")
)
grid_lay.addWidget(self.rectangular_cb, 6, 0, 1, 2)
@@ -7870,7 +7877,7 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI):
# Others type of Apertures Selection
self.other_cb = FCCheckBox('%s' % _("Others"))
self.other_cb.setToolTip(
- _("Create drills from other types of pad shape.")
+ _("Process pads not in the categories above.")
)
grid_lay.addWidget(self.other_cb, 7, 0, 1, 2)
@@ -7891,7 +7898,7 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI):
stretch=False)
self.hole_size_label = QtWidgets.QLabel('%s:' % _("Method"))
self.hole_size_label.setToolTip(
- _("The selected method of extracting the drills. Can be:\n"
+ _("The method for processing pads. Can be:\n"
"- Fixed Diameter -> all holes will have a set size\n"
"- Fixed Annular Ring -> all holes will have a set annular ring\n"
"- Proportional -> each hole size will be a fraction of the pad size"))
@@ -7915,7 +7922,7 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI):
self.dia_entry.set_precision(self.decimals)
self.dia_entry.set_range(0.0000, 9999.9999)
- self.dia_label = QtWidgets.QLabel('%s:' % _("value"))
+ self.dia_label = QtWidgets.QLabel('%s:' % _("Value"))
self.dia_label.setToolTip(
_("Fixed hole diameter.")
)
@@ -7927,7 +7934,7 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI):
self.ring_label = QtWidgets.QLabel('%s' % _("Fixed Annular Ring"))
self.ring_label.setToolTip(
_("The size of annular ring.\n"
- "The copper sliver between the drill hole exterior\n"
+ "The copper sliver between the hole exterior\n"
"and the margin of the copper pad.")
)
grid_lay.addWidget(self.ring_label, 13, 0, 1, 2)
@@ -8009,7 +8016,221 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI):
self.factor_label = QtWidgets.QLabel('%s:' % _("Factor"))
self.factor_label.setToolTip(
_("Proportional Diameter.\n"
- "The drill diameter will be a fraction of the pad size.")
+ "The hole diameter will be a fraction of the pad size.")
+ )
+
+ grid_lay.addWidget(self.factor_label, 20, 0)
+ grid_lay.addWidget(self.factor_entry, 20, 1)
+
+ self.layout.addStretch()
+
+
+class Tools2PunchGerberPrefGroupUI(OptionsGroupUI):
+ def __init__(self, decimals=4, parent=None):
+
+ super(Tools2PunchGerberPrefGroupUI, self).__init__(self)
+
+ self.setTitle(str(_("Punch Gerber Options")))
+ self.decimals = decimals
+
+ # ## Grid Layout
+ grid_lay = QtWidgets.QGridLayout()
+ self.layout.addLayout(grid_lay)
+ grid_lay.setColumnStretch(0, 0)
+ grid_lay.setColumnStretch(1, 1)
+
+ self.param_label = QtWidgets.QLabel('%s:' % _('Parameters'))
+ self.param_label.setToolTip(
+ _("Parameters used for this tool.")
+ )
+ grid_lay.addWidget(self.param_label, 0, 0, 1, 2)
+
+ self.padt_label = QtWidgets.QLabel("%s:" % _("Processed Pads Type"))
+ self.padt_label.setToolTip(
+ _("The type of pads shape to be processed.\n"
+ "If the PCB has many SMD pads with rectangular pads,\n"
+ "disable the Rectangular aperture.")
+ )
+
+ grid_lay.addWidget(self.padt_label, 2, 0, 1, 2)
+
+ # Circular Aperture Selection
+ self.circular_cb = FCCheckBox('%s' % _("Circular"))
+ self.circular_cb.setToolTip(
+ _("Process Circular Pads.")
+ )
+
+ grid_lay.addWidget(self.circular_cb, 3, 0, 1, 2)
+
+ # Oblong Aperture Selection
+ self.oblong_cb = FCCheckBox('%s' % _("Oblong"))
+ self.oblong_cb.setToolTip(
+ _("Process Oblong Pads.")
+ )
+
+ grid_lay.addWidget(self.oblong_cb, 4, 0, 1, 2)
+
+ # Square Aperture Selection
+ self.square_cb = FCCheckBox('%s' % _("Square"))
+ self.square_cb.setToolTip(
+ _("Process Square Pads.")
+ )
+
+ grid_lay.addWidget(self.square_cb, 5, 0, 1, 2)
+
+ # Rectangular Aperture Selection
+ self.rectangular_cb = FCCheckBox('%s' % _("Rectangular"))
+ self.rectangular_cb.setToolTip(
+ _("Process Rectangular Pads.")
+ )
+
+ grid_lay.addWidget(self.rectangular_cb, 6, 0, 1, 2)
+
+ # Others type of Apertures Selection
+ self.other_cb = FCCheckBox('%s' % _("Others"))
+ self.other_cb.setToolTip(
+ _("Process pads not in the categories above.")
+ )
+
+ grid_lay.addWidget(self.other_cb, 7, 0, 1, 2)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid_lay.addWidget(separator_line, 8, 0, 1, 2)
+
+ # ## Axis
+ self.hole_size_radio = RadioSet(
+ [
+ {'label': _("Excellon"), 'value': 'exc'},
+ {'label': _("Fixed Diameter"), 'value': 'fixed'},
+ {'label': _("Fixed Annular Ring"), 'value': 'ring'},
+ {'label': _("Proportional"), 'value': 'prop'}
+ ],
+ orientation='vertical',
+ stretch=False)
+ self.hole_size_label = QtWidgets.QLabel('%s:' % _("Method"))
+ self.hole_size_label.setToolTip(
+ _("The punch hole source can be:\n"
+ "- Excellon Object-> the Excellon object drills center will serve as reference.\n"
+ "- Fixed Diameter -> will try to use the pads center as reference adding fixed diameter holes.\n"
+ "- Fixed Annular Ring -> will try to keep a set annular ring.\n"
+ "- Proportional -> will make a Gerber punch hole having the diameter a percentage of the pad diameter.\n")
+ )
+ grid_lay.addWidget(self.hole_size_label, 9, 0)
+ grid_lay.addWidget(self.hole_size_radio, 9, 1)
+
+ # grid_lay1.addWidget(QtWidgets.QLabel(''))
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid_lay.addWidget(separator_line, 10, 0, 1, 2)
+
+ # Annular Ring
+ self.fixed_label = QtWidgets.QLabel('%s' % _("Fixed Diameter"))
+ grid_lay.addWidget(self.fixed_label, 11, 0, 1, 2)
+
+ # Diameter value
+ self.dia_entry = FCDoubleSpinner()
+ self.dia_entry.set_precision(self.decimals)
+ self.dia_entry.set_range(0.0000, 9999.9999)
+
+ self.dia_label = QtWidgets.QLabel('%s:' % _("Value"))
+ self.dia_label.setToolTip(
+ _("Fixed hole diameter.")
+ )
+
+ grid_lay.addWidget(self.dia_label, 12, 0)
+ grid_lay.addWidget(self.dia_entry, 12, 1)
+
+ # Annular Ring value
+ self.ring_label = QtWidgets.QLabel('%s' % _("Fixed Annular Ring"))
+ self.ring_label.setToolTip(
+ _("The size of annular ring.\n"
+ "The copper sliver between the hole exterior\n"
+ "and the margin of the copper pad.")
+ )
+ grid_lay.addWidget(self.ring_label, 13, 0, 1, 2)
+
+ # Circular Annular Ring Value
+ self.circular_ring_label = QtWidgets.QLabel('%s:' % _("Circular"))
+ self.circular_ring_label.setToolTip(
+ _("The size of annular ring for circular pads.")
+ )
+
+ self.circular_ring_entry = FCDoubleSpinner()
+ self.circular_ring_entry.set_precision(self.decimals)
+ self.circular_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid_lay.addWidget(self.circular_ring_label, 14, 0)
+ grid_lay.addWidget(self.circular_ring_entry, 14, 1)
+
+ # Oblong Annular Ring Value
+ self.oblong_ring_label = QtWidgets.QLabel('%s:' % _("Oblong"))
+ self.oblong_ring_label.setToolTip(
+ _("The size of annular ring for oblong pads.")
+ )
+
+ self.oblong_ring_entry = FCDoubleSpinner()
+ self.oblong_ring_entry.set_precision(self.decimals)
+ self.oblong_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid_lay.addWidget(self.oblong_ring_label, 15, 0)
+ grid_lay.addWidget(self.oblong_ring_entry, 15, 1)
+
+ # Square Annular Ring Value
+ self.square_ring_label = QtWidgets.QLabel('%s:' % _("Square"))
+ self.square_ring_label.setToolTip(
+ _("The size of annular ring for square pads.")
+ )
+
+ self.square_ring_entry = FCDoubleSpinner()
+ self.square_ring_entry.set_precision(self.decimals)
+ self.square_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid_lay.addWidget(self.square_ring_label, 16, 0)
+ grid_lay.addWidget(self.square_ring_entry, 16, 1)
+
+ # Rectangular Annular Ring Value
+ self.rectangular_ring_label = QtWidgets.QLabel('%s:' % _("Rectangular"))
+ self.rectangular_ring_label.setToolTip(
+ _("The size of annular ring for rectangular pads.")
+ )
+
+ self.rectangular_ring_entry = FCDoubleSpinner()
+ self.rectangular_ring_entry.set_precision(self.decimals)
+ self.rectangular_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid_lay.addWidget(self.rectangular_ring_label, 17, 0)
+ grid_lay.addWidget(self.rectangular_ring_entry, 17, 1)
+
+ # Others Annular Ring Value
+ self.other_ring_label = QtWidgets.QLabel('%s:' % _("Others"))
+ self.other_ring_label.setToolTip(
+ _("The size of annular ring for other pads.")
+ )
+
+ self.other_ring_entry = FCDoubleSpinner()
+ self.other_ring_entry.set_precision(self.decimals)
+ self.other_ring_entry.set_range(0.0000, 9999.9999)
+
+ grid_lay.addWidget(self.other_ring_label, 18, 0)
+ grid_lay.addWidget(self.other_ring_entry, 18, 1)
+
+ self.prop_label = QtWidgets.QLabel('%s' % _("Proportional Diameter"))
+ grid_lay.addWidget(self.prop_label, 19, 0, 1, 2)
+
+ # Factor value
+ self.factor_entry = FCDoubleSpinner(suffix='%')
+ self.factor_entry.set_precision(self.decimals)
+ self.factor_entry.set_range(0.0000, 100.0000)
+ self.factor_entry.setSingleStep(0.1)
+
+ self.factor_label = QtWidgets.QLabel('%s:' % _("Factor"))
+ self.factor_label.setToolTip(
+ _("Proportional Diameter.\n"
+ "The hole diameter will be a fraction of the pad size.")
)
grid_lay.addWidget(self.factor_label, 20, 0)
diff --git a/flatcamTools/ToolExtractDrills.py b/flatcamTools/ToolExtractDrills.py
index 7fa1dc98..bc772e42 100644
--- a/flatcamTools/ToolExtractDrills.py
+++ b/flatcamTools/ToolExtractDrills.py
@@ -76,7 +76,7 @@ class ToolExtractDrills(FlatCAMTool):
# Circular Aperture Selection
self.circular_cb = FCCheckBox('%s' % _("Circular"))
self.circular_cb.setToolTip(
- _("Create drills from circular pads.")
+ _("Process Circular Pads.")
)
grid_lay.addWidget(self.circular_cb, 3, 0, 1, 2)
@@ -84,7 +84,7 @@ class ToolExtractDrills(FlatCAMTool):
# Oblong Aperture Selection
self.oblong_cb = FCCheckBox('%s' % _("Oblong"))
self.oblong_cb.setToolTip(
- _("Create drills from oblong pads.")
+ _("Process Oblong Pads.")
)
grid_lay.addWidget(self.oblong_cb, 4, 0, 1, 2)
@@ -92,7 +92,7 @@ class ToolExtractDrills(FlatCAMTool):
# Square Aperture Selection
self.square_cb = FCCheckBox('%s' % _("Square"))
self.square_cb.setToolTip(
- _("Create drills from square pads.")
+ _("Process Square Pads.")
)
grid_lay.addWidget(self.square_cb, 5, 0, 1, 2)
@@ -100,7 +100,7 @@ class ToolExtractDrills(FlatCAMTool):
# Rectangular Aperture Selection
self.rectangular_cb = FCCheckBox('%s' % _("Rectangular"))
self.rectangular_cb.setToolTip(
- _("Create drills from rectangular pads.")
+ _("Process Rectangular Pads.")
)
grid_lay.addWidget(self.rectangular_cb, 6, 0, 1, 2)
@@ -108,7 +108,7 @@ class ToolExtractDrills(FlatCAMTool):
# Others type of Apertures Selection
self.other_cb = FCCheckBox('%s' % _("Others"))
self.other_cb.setToolTip(
- _("Create drills from other types of pad shape.")
+ _("Process pads not in the categories above.")
)
grid_lay.addWidget(self.other_cb, 7, 0, 1, 2)
@@ -126,7 +126,7 @@ class ToolExtractDrills(FlatCAMTool):
self.method_label = QtWidgets.QLabel('%s' % _("Method"))
self.method_label.setToolTip(
- _("The selected method of extracting the drills. Can be:\n"
+ _("The method for processing pads. Can be:\n"
"- Fixed Diameter -> all holes will have a set size\n"
"- Fixed Annular Ring -> all holes will have a set annular ring\n"
"- Proportional -> each hole size will be a fraction of the pad size"))
@@ -191,7 +191,7 @@ class ToolExtractDrills(FlatCAMTool):
self.ring_label = QtWidgets.QLabel('%s' % _("Fixed Annular Ring"))
self.ring_label.setToolTip(
_("The size of annular ring.\n"
- "The copper sliver between the drill hole exterior\n"
+ "The copper sliver between the hole exterior\n"
"and the margin of the copper pad.")
)
grid2.addWidget(self.ring_label, 0, 0, 1, 2)
@@ -284,7 +284,7 @@ class ToolExtractDrills(FlatCAMTool):
self.factor_label = QtWidgets.QLabel('%s:' % _("Value"))
self.factor_label.setToolTip(
_("Proportional Diameter.\n"
- "The drill diameter will be a fraction of the pad size.")
+ "The hole diameter will be a fraction of the pad size.")
)
grid3.addWidget(self.factor_label, 3, 0)
diff --git a/flatcamTools/ToolPunchGerber.py b/flatcamTools/ToolPunchGerber.py
index 10bf4b92..f7378933 100644
--- a/flatcamTools/ToolPunchGerber.py
+++ b/flatcamTools/ToolPunchGerber.py
@@ -87,7 +87,7 @@ class ToolPunchGerber(FlatCAMTool):
# Circular Aperture Selection
self.circular_cb = FCCheckBox('%s' % _("Circular"))
self.circular_cb.setToolTip(
- _("Create drills from circular pads.")
+ _("Process Circular Pads.")
)
grid_lay.addWidget(self.circular_cb, 5, 0, 1, 2)
@@ -95,7 +95,7 @@ class ToolPunchGerber(FlatCAMTool):
# Oblong Aperture Selection
self.oblong_cb = FCCheckBox('%s' % _("Oblong"))
self.oblong_cb.setToolTip(
- _("Create drills from oblong pads.")
+ _("Process Oblong Pads.")
)
grid_lay.addWidget(self.oblong_cb, 6, 0, 1, 2)
@@ -103,7 +103,7 @@ class ToolPunchGerber(FlatCAMTool):
# Square Aperture Selection
self.square_cb = FCCheckBox('%s' % _("Square"))
self.square_cb.setToolTip(
- _("Create drills from square pads.")
+ _("Process Square Pads.")
)
grid_lay.addWidget(self.square_cb, 7, 0, 1, 2)
@@ -111,7 +111,7 @@ class ToolPunchGerber(FlatCAMTool):
# Rectangular Aperture Selection
self.rectangular_cb = FCCheckBox('%s' % _("Rectangular"))
self.rectangular_cb.setToolTip(
- _("Create drills from rectangular pads.")
+ _("Process Rectangular Pads.")
)
grid_lay.addWidget(self.rectangular_cb, 8, 0, 1, 2)
@@ -119,7 +119,7 @@ class ToolPunchGerber(FlatCAMTool):
# Others type of Apertures Selection
self.other_cb = FCCheckBox('%s' % _("Others"))
self.other_cb.setToolTip(
- _("Create drills from other types of pad shape.")
+ _("Process pads not in the categories above.")
)
grid_lay.addWidget(self.other_cb, 9, 0, 1, 2)
@@ -212,7 +212,7 @@ class ToolPunchGerber(FlatCAMTool):
self.ring_label = QtWidgets.QLabel('%s' % _("Fixed Annular Ring"))
self.ring_label.setToolTip(
_("The size of annular ring.\n"
- "The copper sliver between the drill hole exterior\n"
+ "The copper sliver between the hole exterior\n"
"and the margin of the copper pad.")
)
self.ring_box.addWidget(self.ring_label)
@@ -306,7 +306,7 @@ class ToolPunchGerber(FlatCAMTool):
self.factor_label = QtWidgets.QLabel('%s:' % _("Value"))
self.factor_label.setToolTip(
_("Proportional Diameter.\n"
- "The drill diameter will be a fraction of the pad size.")
+ "The hole diameter will be a fraction of the pad size.")
)
grid0.addWidget(self.factor_label, 13, 0)
@@ -429,8 +429,24 @@ class ToolPunchGerber(FlatCAMTool):
self.reset_fields()
self.ui_connect()
- self.method_punch.set_value('exc')
- self.select_all_cb.set_value(True)
+ self.method_punch.set_value(self.app.defaults["tools_punch_hole_type"])
+ self.select_all_cb.set_value(False)
+
+ self.dia_entry.set_value(float(self.app.defaults["tools_punch_hole_fixed_dia"]))
+
+ self.circular_ring_entry.set_value(float(self.app.defaults["tools_punch_circular_ring"]))
+ self.oblong_ring_entry.set_value(float(self.app.defaults["tools_punch_oblong_ring"]))
+ self.square_ring_entry.set_value(float(self.app.defaults["tools_punch_square_ring"]))
+ self.rectangular_ring_entry.set_value(float(self.app.defaults["tools_punch_rectangular_ring"]))
+ self.other_ring_entry.set_value(float(self.app.defaults["tools_punch_others_ring"]))
+
+ self.circular_cb.set_value(self.app.defaults["tools_punch_circular"])
+ self.oblong_cb.set_value(self.app.defaults["tools_punch_oblong"])
+ self.square_cb.set_value(self.app.defaults["tools_punch_square"])
+ self.rectangular_cb.set_value(self.app.defaults["tools_punch_rectangular"])
+ self.other_cb.set_value(self.app.defaults["tools_punch_others"])
+
+ self.factor_entry.set_value(float(self.app.defaults["tools_punch_hole_prop_factor"]))
def on_select_all(self, state):
self.ui_disconnect()
@@ -685,9 +701,286 @@ class ToolPunchGerber(FlatCAMTool):
self.app.new_object('gerber', outname, init_func)
elif punch_method == 'ring':
- pass
+ circ_r_val = self.circular_ring_entry.get_value()
+ oblong_r_val = self.oblong_ring_entry.get_value()
+ square_r_val = self.square_ring_entry.get_value()
+ rect_r_val = self.rectangular_ring_entry.get_value()
+ other_r_val = self.other_ring_entry.get_value()
+
+ dia = None
+
+ if isinstance(grb_obj.solid_geometry, list):
+ temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry)
+ else:
+ temp_solid_geometry = grb_obj.solid_geometry
+
+ punched_solid_geometry = temp_solid_geometry
+
+ new_apertures = deepcopy(grb_obj.apertures)
+ new_apertures_items = new_apertures.items()
+
+ # find maximum aperture id
+ new_apid = max([int(x) for x, __ in new_apertures_items])
+
+ # store here the clear geometry, the key is the new aperture size
+ holes_apertures = dict()
+
+ for apid, apid_value in grb_obj.apertures.items():
+ ap_type = apid_value['type']
+ punching_geo = list()
+
+ if ap_type == 'C' and self.circular_cb.get_value():
+ dia = float(apid_value['size']) - (2 * circ_r_val)
+ for elem in apid_value['geometry']:
+ if 'follow' in elem and isinstance(elem['follow'], Point):
+ punching_geo.append(elem['follow'].buffer(dia / 2))
+
+ elif ap_type == 'O' and self.oblong_cb.get_value():
+ width = float(apid_value['width'])
+ height = float(apid_value['height'])
+
+ if width > height:
+ dia = float(apid_value['height']) - (2 * oblong_r_val)
+ else:
+ dia = float(apid_value['width']) - (2 * oblong_r_val)
+
+ for elem in grb_obj.apertures[apid]['geometry']:
+ if 'follow' in elem:
+ if isinstance(elem['follow'], Point):
+ punching_geo.append(elem['follow'].buffer(dia / 2))
+
+ elif ap_type == 'R':
+ width = float(apid_value['width'])
+ height = float(apid_value['height'])
+
+ # if the height == width (float numbers so the reason for the following)
+ if round(width, self.decimals) == round(height, self.decimals):
+ if self.square_cb.get_value():
+ dia = float(apid_value['height']) - (2 * square_r_val)
+
+ for elem in grb_obj.apertures[apid]['geometry']:
+ if 'follow' in elem:
+ if isinstance(elem['follow'], Point):
+ punching_geo.append(elem['follow'].buffer(dia / 2))
+ elif self.rectangular_cb.get_value():
+ if width > height:
+ dia = float(apid_value['height']) - (2 * rect_r_val)
+ else:
+ dia = float(apid_value['width']) - (2 * rect_r_val)
+
+ for elem in grb_obj.apertures[apid]['geometry']:
+ if 'follow' in elem:
+ if isinstance(elem['follow'], Point):
+ punching_geo.append(elem['follow'].buffer(dia / 2))
+
+ elif self.other_cb.get_value():
+ try:
+ dia = float(apid_value['size']) - (2 * other_r_val)
+ except KeyError:
+ if ap_type == 'AM':
+ pol = apid_value['geometry'][0]['solid']
+ x0, y0, x1, y1 = pol.bounds
+ dx = x1 - x0
+ dy = y1 - y0
+ if dx <= dy:
+ dia = dx - (2 * other_r_val)
+ else:
+ dia = dy - (2 * other_r_val)
+
+ for elem in grb_obj.apertures[apid]['geometry']:
+ if 'follow' in elem:
+ if isinstance(elem['follow'], Point):
+ punching_geo.append(elem['follow'].buffer(dia / 2))
+
+ # if dia is None then none of the above applied so we skip the following
+ if dia is None:
+ continue
+
+ punching_geo = MultiPolygon(punching_geo)
+
+ if punching_geo is None or punching_geo.is_empty:
+ continue
+
+ punched_solid_geometry = punched_solid_geometry.difference(punching_geo)
+
+ # update the gerber apertures to include the clear geometry so it can be exported successfully
+ for elem in apid_value['geometry']:
+ # make it work only for Gerber Flashes who are Points in 'follow'
+ if 'solid' in elem and isinstance(elem['follow'], Point):
+ clear_apid_size = dia
+ for geo in punching_geo:
+
+ # since there may be drills that do not drill into a pad we test only for geos in a pad
+ if geo.within(elem['solid']):
+ geo_elem = dict()
+ geo_elem['clear'] = geo.centroid
+
+ if clear_apid_size not in holes_apertures:
+ holes_apertures[clear_apid_size] = dict()
+ holes_apertures[clear_apid_size]['type'] = 'C'
+ holes_apertures[clear_apid_size]['size'] = clear_apid_size
+ holes_apertures[clear_apid_size]['geometry'] = list()
+
+ holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem))
+
+ # add the clear geometry to new apertures; it's easier than to test if there are apertures with the same
+ # size and add there the clear geometry
+ for hole_size, ap_val in holes_apertures.items():
+ new_apid += 1
+ new_apertures[str(new_apid)] = deepcopy(ap_val)
+
+ def init_func(new_obj, app_obj):
+ new_obj.options.update(grb_obj.options)
+ new_obj.options['name'] = outname
+ new_obj.fill_color = deepcopy(grb_obj.fill_color)
+ new_obj.outline_color = deepcopy(grb_obj.outline_color)
+
+ new_obj.apertures = deepcopy(new_apertures)
+
+ new_obj.solid_geometry = deepcopy(punched_solid_geometry)
+ new_obj.source_file = self.app.export_gerber(obj_name=outname, filename=None,
+ local_use=new_obj, use_thread=False)
+
+ self.app.new_object('gerber', outname, init_func)
+
elif punch_method == 'prop':
- pass
+ prop_factor = self.factor_entry.get_value() / 100.0
+
+ dia = None
+
+ if isinstance(grb_obj.solid_geometry, list):
+ temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry)
+ else:
+ temp_solid_geometry = grb_obj.solid_geometry
+
+ punched_solid_geometry = temp_solid_geometry
+
+ new_apertures = deepcopy(grb_obj.apertures)
+ new_apertures_items = new_apertures.items()
+
+ # find maximum aperture id
+ new_apid = max([int(x) for x, __ in new_apertures_items])
+
+ # store here the clear geometry, the key is the new aperture size
+ holes_apertures = dict()
+
+ for apid, apid_value in grb_obj.apertures.items():
+ ap_type = apid_value['type']
+ punching_geo = list()
+
+ if ap_type == 'C' and self.circular_cb.get_value():
+ dia = float(apid_value['size']) * prop_factor
+ for elem in apid_value['geometry']:
+ if 'follow' in elem and isinstance(elem['follow'], Point):
+ punching_geo.append(elem['follow'].buffer(dia / 2))
+
+ elif ap_type == 'O' and self.oblong_cb.get_value():
+ width = float(apid_value['width'])
+ height = float(apid_value['height'])
+
+ if width > height:
+ dia = float(apid_value['height']) * prop_factor
+ else:
+ dia = float(apid_value['width']) * prop_factor
+
+ for elem in grb_obj.apertures[apid]['geometry']:
+ if 'follow' in elem:
+ if isinstance(elem['follow'], Point):
+ punching_geo.append(elem['follow'].buffer(dia / 2))
+
+ elif ap_type == 'R':
+ width = float(apid_value['width'])
+ height = float(apid_value['height'])
+
+ # if the height == width (float numbers so the reason for the following)
+ if round(width, self.decimals) == round(height, self.decimals):
+ if self.square_cb.get_value():
+ dia = float(apid_value['height']) * prop_factor
+
+ for elem in grb_obj.apertures[apid]['geometry']:
+ if 'follow' in elem:
+ if isinstance(elem['follow'], Point):
+ punching_geo.append(elem['follow'].buffer(dia / 2))
+ elif self.rectangular_cb.get_value():
+ if width > height:
+ dia = float(apid_value['height']) * prop_factor
+ else:
+ dia = float(apid_value['width']) * prop_factor
+
+ for elem in grb_obj.apertures[apid]['geometry']:
+ if 'follow' in elem:
+ if isinstance(elem['follow'], Point):
+ punching_geo.append(elem['follow'].buffer(dia / 2))
+
+ elif self.other_cb.get_value():
+ try:
+ dia = float(apid_value['size']) * prop_factor
+ except KeyError:
+ if ap_type == 'AM':
+ pol = apid_value['geometry'][0]['solid']
+ x0, y0, x1, y1 = pol.bounds
+ dx = x1 - x0
+ dy = y1 - y0
+ if dx <= dy:
+ dia = dx * prop_factor
+ else:
+ dia = dy * prop_factor
+
+ for elem in grb_obj.apertures[apid]['geometry']:
+ if 'follow' in elem:
+ if isinstance(elem['follow'], Point):
+ punching_geo.append(elem['follow'].buffer(dia / 2))
+
+ # if dia is None then none of the above applied so we skip the following
+ if dia is None:
+ continue
+
+ punching_geo = MultiPolygon(punching_geo)
+
+ if punching_geo is None or punching_geo.is_empty:
+ continue
+
+ punched_solid_geometry = punched_solid_geometry.difference(punching_geo)
+
+ # update the gerber apertures to include the clear geometry so it can be exported successfully
+ for elem in apid_value['geometry']:
+ # make it work only for Gerber Flashes who are Points in 'follow'
+ if 'solid' in elem and isinstance(elem['follow'], Point):
+ clear_apid_size = dia
+ for geo in punching_geo:
+
+ # since there may be drills that do not drill into a pad we test only for geos in a pad
+ if geo.within(elem['solid']):
+ geo_elem = dict()
+ geo_elem['clear'] = geo.centroid
+
+ if clear_apid_size not in holes_apertures:
+ holes_apertures[clear_apid_size] = dict()
+ holes_apertures[clear_apid_size]['type'] = 'C'
+ holes_apertures[clear_apid_size]['size'] = clear_apid_size
+ holes_apertures[clear_apid_size]['geometry'] = list()
+
+ holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem))
+
+ # add the clear geometry to new apertures; it's easier than to test if there are apertures with the same
+ # size and add there the clear geometry
+ for hole_size, ap_val in holes_apertures.items():
+ new_apid += 1
+ new_apertures[str(new_apid)] = deepcopy(ap_val)
+
+ def init_func(new_obj, app_obj):
+ new_obj.options.update(grb_obj.options)
+ new_obj.options['name'] = outname
+ new_obj.fill_color = deepcopy(grb_obj.fill_color)
+ new_obj.outline_color = deepcopy(grb_obj.outline_color)
+
+ new_obj.apertures = deepcopy(new_apertures)
+
+ new_obj.solid_geometry = deepcopy(punched_solid_geometry)
+ new_obj.source_file = self.app.export_gerber(obj_name=outname, filename=None,
+ local_use=new_obj, use_thread=False)
+
+ self.app.new_object('gerber', outname, init_func)
def reset_fields(self):
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
From 9417049eefbb0dabb17af9fbc94ad499bcb54125 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 13 Feb 2020 21:11:06 +0200
Subject: [PATCH 089/209] - some updates in the requirements file and in
setup_ubuntu.sh; for now versions higher than 5.12.1 of pyqt5 are not working
---
requirements.txt | 3 ++-
setup_ubuntu.sh | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/requirements.txt b/requirements.txt
index 259ef455..6e58e3f7 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,8 @@
# This file contains python only requirements to be installed with pip
# Python packages that cannot be installed with pip (e.g. PyQt5, GDAL) are not included.
# Usage: pip3 install -r requirements.txt
-numpy >=1.16
+pyqt5==5.12
+numpy>=1.16
matplotlib>=3.1
cycler>=0.10
python-dateutil>=2.1
diff --git a/setup_ubuntu.sh b/setup_ubuntu.sh
index 4830b383..9054a57c 100644
--- a/setup_ubuntu.sh
+++ b/setup_ubuntu.sh
@@ -3,6 +3,7 @@ sudo apt install --reinstall libpng-dev libfreetype6 libfreetype6-dev libgeos-de
sudo apt install --reinstall python3-dev python3-pyqt5 python3-pyqt5.qtopengl python3-gdal python3-simplejson
sudo apt install --reinstall python3-pip python3-tk python3-imaging
+sudo python3 -m pip install --upgrade pyqt5==5.12
sudo python3 -m pip install --upgrade pip numpy scipy shapely rtree tk lxml cycler python-dateutil kiwisolver dill
sudo python3 -m pip install --upgrade vispy pyopengl setuptools svg.path ortools freetype-py fontTools rasterio ezdxf
sudo python3 -m pip install --upgrade matplotlib qrcode reportlab svglib
\ No newline at end of file
From 8ff3248c25b70e69fc7f290d710f878f2d459401 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 13 Feb 2020 21:22:21 +0200
Subject: [PATCH 090/209] - minor changes in the Tool Transform and Tool
Calculators UI to bring them up2date with the other tools
---
README.md | 1 +
flatcamTools/ToolCalculators.py | 14 ++++++++++++++
flatcamTools/ToolTransform.py | 15 +++++++++++++++
3 files changed, 30 insertions(+)
diff --git a/README.md b/README.md
index 8ab918e5..2fb1bf22 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
13.02.2020
- finished Punch Gerber Tool
+- minor changes in the Tool Transform and Tool Calculators UI to bring them up2date with the other tools
12.02.2020
diff --git a/flatcamTools/ToolCalculators.py b/flatcamTools/ToolCalculators.py
index 2cc2551e..3a7ff665 100644
--- a/flatcamTools/ToolCalculators.py
+++ b/flatcamTools/ToolCalculators.py
@@ -242,6 +242,19 @@ class ToolCalculator(FlatCAMTool):
self.layout.addStretch()
+ # ## Reset Tool
+ self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
+ self.reset_button.setToolTip(
+ _("Will reset the tool parameters.")
+ )
+ self.reset_button.setStyleSheet("""
+ QPushButton
+ {
+ font-weight: bold;
+ }
+ """)
+ self.layout.addWidget(self.reset_button)
+
self.units = ''
# ## Signals
@@ -255,6 +268,7 @@ class ToolCalculator(FlatCAMTool):
self.inch_entry.editingFinished.connect(self.on_calculate_mm_units)
self.calculate_plate_button.clicked.connect(self.on_calculate_eplate)
+ self.reset_button.clicked.connect(self.set_tool_ui)
def run(self, toggle=True):
self.app.report_usage("ToolCalculators()")
diff --git a/flatcamTools/ToolTransform.py b/flatcamTools/ToolTransform.py
index aa0a9a1e..04cb1dc8 100644
--- a/flatcamTools/ToolTransform.py
+++ b/flatcamTools/ToolTransform.py
@@ -412,6 +412,19 @@ class ToolTransform(FlatCAMTool):
self.transform_lay.addStretch()
+ # ## Reset Tool
+ self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
+ self.reset_button.setToolTip(
+ _("Will reset the tool parameters.")
+ )
+ self.reset_button.setStyleSheet("""
+ QPushButton
+ {
+ font-weight: bold;
+ }
+ """)
+ self.transform_lay.addWidget(self.reset_button)
+
# ## Signals
self.rotate_button.clicked.connect(self.on_rotate)
self.skewx_button.clicked.connect(self.on_skewx)
@@ -426,6 +439,8 @@ class ToolTransform(FlatCAMTool):
self.buffer_button.clicked.connect(self.on_buffer_by_distance)
self.buffer_factor_button.clicked.connect(self.on_buffer_by_factor)
+ self.reset_button.clicked.connect(self.set_tool_ui)
+
# self.rotate_entry.returnPressed.connect(self.on_rotate)
# self.skewx_entry.returnPressed.connect(self.on_skewx)
# self.skewy_entry.returnPressed.connect(self.on_skewy)
From e8ecf7a83cce9a32ec297e479e89430c606e605a Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 13 Feb 2020 21:45:43 +0200
Subject: [PATCH 091/209] - PEP8 changes
---
FlatCAMObj.py | 47 ++++++++++++++++++++++++-----------------------
1 file changed, 24 insertions(+), 23 deletions(-)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 8a1023b7..e0534d7a 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -35,7 +35,9 @@ import FlatCAMApp
from flatcamGUI.VisPyVisuals import ShapeCollection
import tkinter as tk
-import os, sys, itertools
+import os
+import sys
+import itertools
import ezdxf
import math
@@ -246,7 +248,7 @@ class FlatCAMObj(QtCore.QObject):
self.app.myKeywords.append(new_name)
self.app.shell._edit.set_model_data(self.app.myKeywords)
self.app.ui.code_editor.set_model_data(self.app.myKeywords)
- except Exception as e:
+ except Exception:
log.debug("on_name_activate() --> Could not remove the old object name from auto-completer model list")
self.options["name"] = self.ui.name_entry.get_value()
@@ -791,15 +793,15 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
def on_calculate_tooldia(self):
try:
tdia = float(self.ui.tipdia_spinner.get_value())
- except Exception as e:
+ except Exception:
return
try:
dang = float(self.ui.tipangle_spinner.get_value())
- except Exception as e:
+ except Exception:
return
try:
cutz = float(self.ui.cutz_spinner.get_value())
- except Exception as e:
+ except Exception:
return
cutz *= -1
@@ -1384,13 +1386,13 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
}
})
- for i in range(passes):
- iso_offset = dia * ((2 * i + 1) / 2.0) - (i * overlap * dia)
+ for nr_pass in range(passes):
+ iso_offset = dia * ((2 * nr_pass + 1) / 2.0) - (nr_pass * overlap * dia)
# if milling type is climb then the move is counter-clockwise around features
mill_dir = 1 if milling_type == 'cl' else 0
geom = self.generate_envelope(iso_offset, mill_dir, geometry=work_geo, env_iso_type=iso_t,
- follow=follow, nr_passes=i)
+ follow=follow, nr_passes=nr_pass)
if geom == 'fail':
app_obj.inform.emit('[ERROR_NOTCL] %s' % _("Isolation geometry could not be generated."))
@@ -2380,7 +2382,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
# Attributes to be included in serialization
# Always append to it because it carries contents
# from predecessors.
- self.ser_attrs += ['options', 'kind',]
+ self.ser_attrs += ['options', 'kind']
def merge(self, exc_list, exc_final):
"""
@@ -2425,7 +2427,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
if option is not 'name':
try:
exc_final.options[option] = exc.options[option]
- except Exception as e:
+ except Exception:
exc.app.log.warning("Failed to copy option.", option)
for drill in exc.drills:
@@ -3934,7 +3936,6 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.units = self.app.defaults['units']
- offset = 0
tool_idx = 0
n = len(self.tools)
@@ -4852,7 +4853,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
obj_active.options['ymin'] = ymin
obj_active.options['xmax'] = xmax
obj_active.options['ymax'] = ymax
- except Exception as e:
+ except Exception:
obj_active.options['xmin'] = 0
obj_active.options['ymin'] = 0
obj_active.options['xmax'] = 0
@@ -5036,7 +5037,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
widget_changed = self.sender()
try:
widget_idx = self.ui.grid3.indexOf(widget_changed)
- except Exception as e:
+ except Exception:
return
# those are the indexes for the V-Tip Dia and V-Tip Angle, if edited calculate the new Cut Z
@@ -5887,7 +5888,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
try:
xfactor = float(xfactor)
except Exception:
- self.app.inform.emit('[ERROR_NOTCL] %s' % _("Scale factor has to be a number: integer or float."))
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _("Scale factor has to be a number: integer or float."))
return
if yfactor is None:
@@ -6497,7 +6498,6 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
self.ui_connect()
def build_cnc_tools_table(self):
- offset = 0
tool_idx = 0
n = len(self.cnc_tools)
@@ -6508,9 +6508,9 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
tool_idx += 1
row_no = tool_idx - 1
- id = QtWidgets.QTableWidgetItem('%d' % int(tool_idx))
+ t_id = QtWidgets.QTableWidgetItem('%d' % int(tool_idx))
# id.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
- self.ui.cnc_tools_table.setItem(row_no, 0, id) # Tool name/id
+ self.ui.cnc_tools_table.setItem(row_no, 0, t_id) # Tool name/id
# Make sure that the tool diameter when in MM is with no more than 2 decimals.
# There are no tool bits in MM with more than 2 decimals diameter.
@@ -6524,7 +6524,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
type_item = QtWidgets.QTableWidgetItem(str(dia_value['type']))
tool_type_item = QtWidgets.QTableWidgetItem(str(dia_value['tool_type']))
- id.setFlags(QtCore.Qt.ItemIsEnabled)
+ t_id.setFlags(QtCore.Qt.ItemIsEnabled)
dia_item.setFlags(QtCore.Qt.ItemIsEnabled)
offset_item.setFlags(QtCore.Qt.ItemIsEnabled)
type_item.setFlags(QtCore.Qt.ItemIsEnabled)
@@ -6606,13 +6606,13 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
tool_idx += 1
row_no = tool_idx - 1
- id = QtWidgets.QTableWidgetItem('%d' % int(tool_idx))
+ t_id = QtWidgets.QTableWidgetItem('%d' % int(tool_idx))
dia_item = QtWidgets.QTableWidgetItem('%.*f' % (self.decimals, float(tooldia_key)))
nr_drills_item = QtWidgets.QTableWidgetItem('%d' % int(dia_value['nr_drills']))
nr_slots_item = QtWidgets.QTableWidgetItem('%d' % int(dia_value['nr_slots']))
cutz_item = QtWidgets.QTableWidgetItem('%.*f' % (self.decimals, float(dia_value['offset_z']) + self.z_cut))
- id.setFlags(QtCore.Qt.ItemIsEnabled)
+ t_id.setFlags(QtCore.Qt.ItemIsEnabled)
dia_item.setFlags(QtCore.Qt.ItemIsEnabled)
nr_drills_item.setFlags(QtCore.Qt.ItemIsEnabled)
nr_slots_item.setFlags(QtCore.Qt.ItemIsEnabled)
@@ -6638,7 +6638,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
# TODO until the feature of individual plot for an Excellon tool is implemented
plot_item.setDisabled(True)
- self.ui.exc_cnc_tools_table.setItem(row_no, 0, id) # Tool name/id
+ self.ui.exc_cnc_tools_table.setItem(row_no, 0, t_id) # Tool name/id
self.ui.exc_cnc_tools_table.setItem(row_no, 1, dia_item) # Diameter
self.ui.exc_cnc_tools_table.setItem(row_no, 2, nr_drills_item) # Nr of drills
self.ui.exc_cnc_tools_table.setItem(row_no, 3, nr_slots_item) # Nr of slots
@@ -6935,7 +6935,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
try:
for key in self.cnc_tools:
ppg = self.cnc_tools[key]['data']['ppname_g']
- if 'marlin' in ppg.lower() or 'repetier' in ppg.lower() :
+ if 'marlin' in ppg.lower() or 'repetier' in ppg.lower():
marlin = True
break
if ppg == 'hpgl':
@@ -7711,9 +7711,10 @@ class FlatCAMDocument(FlatCAMObj):
self.source_file = ''
self.doc_code = ''
+ self.font_name = None
self.font_italic = None
self.font_bold = None
- self.font_underline =None
+ self.font_underline = None
self.document_editor_tab = None
From 2369ebe72af51fb5a496138782946fb5922769d1 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 14 Feb 2020 04:18:49 +0200
Subject: [PATCH 092/209] - more PEP8 changes
---
flatcamTools/ToolPaint.py | 40 ++++++++++++++-------------------------
1 file changed, 14 insertions(+), 26 deletions(-)
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 60ff4f07..5d9780f3 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -1630,25 +1630,17 @@ class ToolPaint(FlatCAMTool, Gerber):
self.app.draw_moving_selection_shape(old_coords=(self.cursor_pos[0], self.cursor_pos[1]),
coords=(curr_pos[0], curr_pos[1]))
- def paint_poly(self, obj,
- inside_pt=None,
- poly_list=None,
- tooldia=None,
- overlap=None,
- order=None,
- margin=None,
- method=None,
- outname=None,
- connect=None,
- contour=None,
- tools_storage=None,
- plot=True,
- run_threaded=True):
+ def paint_poly(self, obj, inside_pt=None, poly_list=None, tooldia=None, overlap=None, order=None,
+ margin=None, method=None, outname=None, connect=None, contour=None, tools_storage=None,
+ plot=True, run_threaded=True):
"""
Paints a polygon selected by clicking on its interior or by having a point coordinates given
Note:
* The margin is taken directly from the form.
+ :param run_threaded:
+ :param plot:
+ :param poly_list:
:param obj: painted object
:param inside_pt: [x, y]
:param tooldia: Diameter of the painting tool
@@ -1909,21 +1901,13 @@ class ToolPaint(FlatCAMTool, Gerber):
else:
job_thread(app_obj=self.app)
- def paint_poly_all(self, obj,
- tooldia=None,
- overlap=None,
- order=None,
- margin=None,
- method=None,
- outname=None,
- connect=None,
- contour=None,
- tools_storage=None,
- plot=True,
- run_threaded=True):
+ def paint_poly_all(self, obj, tooldia=None, overlap=None, order=None, margin=None, method=None, outname=None,
+ connect=None, contour=None, tools_storage=None, plot=True, run_threaded=True):
"""
Paints all polygons in this object.
+ :param run_threaded:
+ :param plot:
:param obj: painted object
:param tooldia: a tuple or single element made out of diameters of the tools to be used
:param overlap: value by which the paths will overlap
@@ -2499,6 +2483,8 @@ class ToolPaint(FlatCAMTool, Gerber):
"""
Paints all polygons in this object that are within the sel_obj object
+ :param run_threaded:
+ :param plot:
:param obj: painted object
:param sel_obj: paint only what is inside this object bounds
:param tooldia: a tuple or single element made out of diameters of the tools to be used
@@ -2974,6 +2960,8 @@ class ToolPaint(FlatCAMTool, Gerber):
"""
Paints all polygons in this object that are within the sel_obj object
+ :param run_threaded:
+ :param plot:
:param obj: painted object
:param sel_obj: paint only what is inside this object bounds
:param tooldia: a tuple or single element made out of diameters of the tools to be used
From 6926b5be658bd4eb91c196e9617c3da8a1597e79 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 14 Feb 2020 05:07:11 +0200
Subject: [PATCH 093/209] - adjusted the UI for Excellon and Geometry objects
---
README.md | 4 +
flatcamGUI/ObjectUI.py | 250 ++++++++++++++++++++---------------------
2 files changed, 129 insertions(+), 125 deletions(-)
diff --git a/README.md b/README.md
index 2fb1bf22..076452e3 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+14.02.2020
+
+- adjusted the UI for Excellon and Geometry objects
+
13.02.2020
- finished Punch Gerber Tool
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index 1bac450d..5a2f62c2 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -956,60 +956,6 @@ class ExcellonObjectUI(ObjectUI):
self.grid3.addWidget(self.travelzlabel, 6, 0)
self.grid3.addWidget(self.travelz_entry, 6, 1)
- # Tool change:
- self.toolchange_cb = FCCheckBox('%s:' % _("Tool change Z"))
- self.toolchange_cb.setToolTip(
- _("Include tool-change sequence\n"
- "in G-Code (Pause for tool change).")
- )
-
- self.toolchangez_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.toolchangez_entry.set_precision(self.decimals)
- self.toolchangez_entry.setToolTip(
- _("Z-axis position (height) for\n"
- "tool change.")
- )
- if machinist_setting == 0:
- self.toolchangez_entry.set_range(0.0, 9999.9999)
- else:
- self.toolchangez_entry.set_range(-9999.9999, 9999.9999)
-
- self.toolchangez_entry.setSingleStep(0.1)
- self.ois_tcz_e = OptionalInputSection(self.toolchange_cb, [self.toolchangez_entry])
-
- self.grid3.addWidget(self.toolchange_cb, 8, 0)
- self.grid3.addWidget(self.toolchangez_entry, 8, 1)
-
- # Start move Z:
- self.estartz_label = QtWidgets.QLabel('%s:' % _("Start Z"))
- self.estartz_label.setToolTip(
- _("Height of the tool just after start.\n"
- "Delete the value if you don't need this feature.")
- )
- self.estartz_entry = FloatEntry()
-
- self.grid3.addWidget(self.estartz_label, 9, 0)
- self.grid3.addWidget(self.estartz_entry, 9, 1)
-
- # End move Z:
- self.endz_label = QtWidgets.QLabel('%s:' % _("End move Z"))
- self.endz_label.setToolTip(
- _("Height of the tool after\n"
- "the last move at the end of the job.")
- )
- self.endz_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.endz_entry.set_precision(self.decimals)
-
- if machinist_setting == 0:
- self.endz_entry.set_range(0.0, 9999.9999)
- else:
- self.endz_entry.set_range(-9999.9999, 9999.9999)
-
- self.endz_entry.setSingleStep(0.1)
-
- self.grid3.addWidget(self.endz_label, 11, 0)
- self.grid3.addWidget(self.endz_entry, 11, 1)
-
# Feedrate X-Y
self.frxylabel = QtWidgets.QLabel('%s:' % _('Feedrate X-Y'))
self.frxylabel.setToolTip(
@@ -1236,7 +1182,61 @@ class ExcellonObjectUI(ObjectUI):
)
self.grid5.addWidget(self.gen_param_label, 3, 0, 1, 2)
- # preprocessor selection
+ # Tool change Z:
+ self.toolchange_cb = FCCheckBox('%s:' % _("Tool change Z"))
+ self.toolchange_cb.setToolTip(
+ _("Include tool-change sequence\n"
+ "in G-Code (Pause for tool change).")
+ )
+
+ self.toolchangez_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.toolchangez_entry.set_precision(self.decimals)
+ self.toolchangez_entry.setToolTip(
+ _("Z-axis position (height) for\n"
+ "tool change.")
+ )
+ if machinist_setting == 0:
+ self.toolchangez_entry.set_range(0.0, 9999.9999)
+ else:
+ self.toolchangez_entry.set_range(-9999.9999, 9999.9999)
+
+ self.toolchangez_entry.setSingleStep(0.1)
+ self.ois_tcz_e = OptionalInputSection(self.toolchange_cb, [self.toolchangez_entry])
+
+ self.grid5.addWidget(self.toolchange_cb, 8, 0)
+ self.grid5.addWidget(self.toolchangez_entry, 8, 1)
+
+ # Start move Z:
+ self.estartz_label = QtWidgets.QLabel('%s:' % _("Start Z"))
+ self.estartz_label.setToolTip(
+ _("Height of the tool just after start.\n"
+ "Delete the value if you don't need this feature.")
+ )
+ self.estartz_entry = FloatEntry()
+
+ self.grid5.addWidget(self.estartz_label, 9, 0)
+ self.grid5.addWidget(self.estartz_entry, 9, 1)
+
+ # End move Z:
+ self.endz_label = QtWidgets.QLabel('%s:' % _("End move Z"))
+ self.endz_label.setToolTip(
+ _("Height of the tool after\n"
+ "the last move at the end of the job.")
+ )
+ self.endz_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.endz_entry.set_precision(self.decimals)
+
+ if machinist_setting == 0:
+ self.endz_entry.set_range(0.0, 9999.9999)
+ else:
+ self.endz_entry.set_range(-9999.9999, 9999.9999)
+
+ self.endz_entry.setSingleStep(0.1)
+
+ self.grid5.addWidget(self.endz_label, 11, 0)
+ self.grid5.addWidget(self.endz_entry, 11, 1)
+
+ # Preprocessor selection
pp_excellon_label = QtWidgets.QLabel('%s:' % _("Preprocessor"))
pp_excellon_label.setToolTip(
_("The preprocessor JSON file that dictates\n"
@@ -1244,13 +1244,13 @@ class ExcellonObjectUI(ObjectUI):
)
self.pp_excellon_name_cb = FCComboBox()
self.pp_excellon_name_cb.setFocusPolicy(QtCore.Qt.StrongFocus)
- self.grid5.addWidget(pp_excellon_label, 4, 0)
- self.grid5.addWidget(self.pp_excellon_name_cb, 4, 1)
+ self.grid5.addWidget(pp_excellon_label, 12, 0)
+ self.grid5.addWidget(self.pp_excellon_name_cb, 12, 1)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.grid5.addWidget(separator_line, 5, 0, 1, 2)
+ self.grid5.addWidget(separator_line, 13, 0, 1, 2)
# #################################################################
# ################# GRID LAYOUT 6 ###############################
@@ -1708,64 +1708,6 @@ class GeometryObjectUI(ObjectUI):
self.grid3.addWidget(self.travelzlabel, 5, 0)
self.grid3.addWidget(self.travelz_entry, 5, 1)
- # Tool change
- self.toolchangeg_cb = FCCheckBox('%s:' % _("Tool change Z"))
- self.toolchangeg_cb.setToolTip(
- _(
- "Include tool-change sequence\n"
- "in the Machine Code (Pause for tool change)."
- )
- )
- self.toolchangez_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.toolchangez_entry.set_precision(self.decimals)
- self.toolchangez_entry.setToolTip(
- _(
- "Z-axis position (height) for\n"
- "tool change."
- )
- )
-
- if machinist_setting == 0:
- self.toolchangez_entry.set_range(0, 9999.9999)
- else:
- self.toolchangez_entry.set_range(-9999.9999, 9999.9999)
-
- self.toolchangez_entry.setSingleStep(0.1)
- self.ois_tcz_geo = OptionalInputSection(self.toolchangeg_cb, [self.toolchangez_entry])
-
- self.grid3.addWidget(self.toolchangeg_cb, 6, 0)
- self.grid3.addWidget(self.toolchangez_entry, 6, 1)
-
- # The Z value for the start move
- # startzlabel = QtWidgets.QLabel('Start move Z:')
- # startzlabel.setToolTip(
- # "Tool height just before starting the work.\n"
- # "Delete the value if you don't need this feature."
- #
- # )
- # self.grid3.addWidget(startzlabel, 8, 0)
- # self.gstartz_entry = FloatEntry()
- # self.grid3.addWidget(self.gstartz_entry, 8, 1)
-
- # The Z value for the end move
- self.endz_label = QtWidgets.QLabel('%s:' % _('End move Z'))
- self.endz_label.setToolTip(
- _("Height of the tool after\n"
- "the last move at the end of the job.")
- )
- self.endz_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.endz_entry.set_precision(self.decimals)
-
- if machinist_setting == 0:
- self.endz_entry.set_range(0, 9999.9999)
- else:
- self.endz_entry.set_range(-9999.9999, 9999.9999)
-
- self.endz_entry.setSingleStep(0.1)
-
- self.grid3.addWidget(self.endz_label, 9, 0)
- self.grid3.addWidget(self.endz_entry, 9, 1)
-
# Feedrate X-Y
self.frlabel = QtWidgets.QLabel('%s:' % _('Feedrate X-Y'))
self.frlabel.setToolTip(
@@ -1941,6 +1883,64 @@ class GeometryObjectUI(ObjectUI):
)
self.grid4.addWidget(self.gen_param_label, 3, 0, 1, 2)
+ # Tool change Z
+ self.toolchangeg_cb = FCCheckBox('%s:' % _("Tool change Z"))
+ self.toolchangeg_cb.setToolTip(
+ _(
+ "Include tool-change sequence\n"
+ "in the Machine Code (Pause for tool change)."
+ )
+ )
+ self.toolchangez_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.toolchangez_entry.set_precision(self.decimals)
+ self.toolchangez_entry.setToolTip(
+ _(
+ "Z-axis position (height) for\n"
+ "tool change."
+ )
+ )
+
+ if machinist_setting == 0:
+ self.toolchangez_entry.set_range(0, 9999.9999)
+ else:
+ self.toolchangez_entry.set_range(-9999.9999, 9999.9999)
+
+ self.toolchangez_entry.setSingleStep(0.1)
+ self.ois_tcz_geo = OptionalInputSection(self.toolchangeg_cb, [self.toolchangez_entry])
+
+ self.grid4.addWidget(self.toolchangeg_cb, 6, 0)
+ self.grid4.addWidget(self.toolchangez_entry, 6, 1)
+
+ # The Z value for the start move
+ # startzlabel = QtWidgets.QLabel('Start move Z:')
+ # startzlabel.setToolTip(
+ # "Tool height just before starting the work.\n"
+ # "Delete the value if you don't need this feature."
+ #
+ # )
+ # self.grid3.addWidget(startzlabel, 8, 0)
+ # self.gstartz_entry = FloatEntry()
+ # self.grid3.addWidget(self.gstartz_entry, 8, 1)
+
+ # The Z value for the end move
+ self.endz_label = QtWidgets.QLabel('%s:' % _('End move Z'))
+ self.endz_label.setToolTip(
+ _("Height of the tool after\n"
+ "the last move at the end of the job.")
+ )
+ self.endz_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.endz_entry.set_precision(self.decimals)
+
+ if machinist_setting == 0:
+ self.endz_entry.set_range(0, 9999.9999)
+ else:
+ self.endz_entry.set_range(-9999.9999, 9999.9999)
+
+ self.endz_entry.setSingleStep(0.1)
+
+ self.grid4.addWidget(self.endz_label, 9, 0)
+ self.grid4.addWidget(self.endz_entry, 9, 1)
+
# preprocessor selection
pp_label = QtWidgets.QLabel('%s:' % _("Preprocessor"))
pp_label.setToolTip(
@@ -1950,17 +1950,17 @@ class GeometryObjectUI(ObjectUI):
self.pp_geometry_name_cb = FCComboBox()
self.pp_geometry_name_cb.setFocusPolicy(QtCore.Qt.StrongFocus)
- self.grid4.addWidget(pp_label, 4, 0)
- self.grid4.addWidget(self.pp_geometry_name_cb, 4, 1)
+ self.grid4.addWidget(pp_label, 11, 0)
+ self.grid4.addWidget(self.pp_geometry_name_cb, 11, 1)
- self.grid4.addWidget(QtWidgets.QLabel(''), 5, 0, 1, 2)
+ self.grid4.addWidget(QtWidgets.QLabel(''), 12, 0, 1, 2)
warning_lbl = QtWidgets.QLabel(
_(
"Add / Select at least one tool in the tool-table.\n"
"Click the # header to select all, or Ctrl + LMB\n"
"for custom selection of tools."
))
- self.grid4.addWidget(warning_lbl, 6, 0, 1, 2)
+ self.grid4.addWidget(warning_lbl, 13, 0, 1, 2)
# Button
self.generate_cnc_button = QtWidgets.QPushButton(_('Generate CNCJob object'))
@@ -1973,9 +1973,9 @@ class GeometryObjectUI(ObjectUI):
font-weight: bold;
}
""")
- self.grid4.addWidget(self.generate_cnc_button, 7, 0, 1, 2)
+ self.grid4.addWidget(self.generate_cnc_button, 14, 0, 1, 2)
- self.grid4.addWidget(QtWidgets.QLabel(''), 8, 0, 1, 2)
+ self.grid4.addWidget(QtWidgets.QLabel(''), 15, 0, 1, 2)
# ##############
# Paint area ##
@@ -1984,7 +1984,7 @@ class GeometryObjectUI(ObjectUI):
self.tools_label.setToolTip(
_("Launch Paint Tool in Tools Tab.")
)
- self.grid4.addWidget(self.tools_label, 10, 0, 1, 2)
+ self.grid4.addWidget(self.tools_label, 16, 0, 1, 2)
# Paint Button
self.paint_tool_button = QtWidgets.QPushButton(_('Paint Tool'))
@@ -2002,7 +2002,7 @@ class GeometryObjectUI(ObjectUI):
font-weight: bold;
}
""")
- self.grid4.addWidget(self.paint_tool_button, 12, 0, 1, 2)
+ self.grid4.addWidget(self.paint_tool_button, 17, 0, 1, 2)
# NCC Tool
self.generate_ncc_button = QtWidgets.QPushButton(_('NCC Tool'))
@@ -2016,7 +2016,7 @@ class GeometryObjectUI(ObjectUI):
font-weight: bold;
}
""")
- self.grid4.addWidget(self.generate_ncc_button, 13, 0, 1, 2)
+ self.grid4.addWidget(self.generate_ncc_button, 18, 0, 1, 2)
class CNCObjectUI(ObjectUI):
From 9fc2ba8ffdc085a73c3cd33c074c4f73ccaf0d62 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 14 Feb 2020 17:08:06 +0200
Subject: [PATCH 094/209] - added a new FlatCAM Tool: Gerber Invert Tool. It
will invert the copper features in a Gerber file: where is copper there will
be empty and where is empty it will be copper
---
FlatCAMApp.py | 21 ++-
FlatCAMObj.py | 25 +--
README.md | 1 +
flatcamGUI/FlatCAMGUI.py | 2 +
flatcamParsers/ParseGerber.py | 9 +-
flatcamTools/ToolInvertGerber.py | 274 +++++++++++++++++++++++++++++++
flatcamTools/ToolPaint.py | 1 +
flatcamTools/ToolPunchGerber.py | 10 +-
flatcamTools/ToolSub.py | 6 +-
flatcamTools/__init__.py | 2 +
share/invert16.png | Bin 0 -> 245 bytes
share/invert32.png | Bin 0 -> 374 bytes
12 files changed, 324 insertions(+), 27 deletions(-)
create mode 100644 flatcamTools/ToolInvertGerber.py
create mode 100644 share/invert16.png
create mode 100644 share/invert32.png
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 7f3596e3..06ffbc72 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -14,7 +14,7 @@ import getopt
import random
import simplejson as json
import lzma
-import threading
+# import threading
import shutil
import stat
@@ -26,7 +26,7 @@ import ctypes
from reportlab.graphics import renderPDF
from reportlab.pdfgen import canvas
-from reportlab.graphics import renderPM
+# from reportlab.graphics import renderPM
from reportlab.lib.units import inch, mm
from reportlab.lib.pagesizes import landscape, portrait
from svglib.svglib import svg2rlg
@@ -39,9 +39,9 @@ from xml.dom.minidom import parseString as parse_xml_string
from multiprocessing.connection import Listener, Client
from multiprocessing import Pool
import socket
-from array import array
+# from array import array
-import vispy.scene as scene
+# import vispy.scene as scene
# #######################################
# # Imports part of FlatCAM ##
@@ -1306,7 +1306,7 @@ class App(QtCore.QObject):
# Excellon Options
"excellon_drillz": self.ui.excellon_defaults_form.excellon_opt_group.cutz_entry,
"excellon_multidepth": self.ui.excellon_defaults_form.excellon_opt_group.mpass_cb,
- "excellon_depthperpass":self.ui.excellon_defaults_form.excellon_opt_group.maxdepth_entry,
+ "excellon_depthperpass": self.ui.excellon_defaults_form.excellon_opt_group.maxdepth_entry,
"excellon_travelz": self.ui.excellon_defaults_form.excellon_opt_group.travelz_entry,
"excellon_endz": self.ui.excellon_defaults_form.excellon_opt_group.endz_entry,
"excellon_feedrate": self.ui.excellon_defaults_form.excellon_opt_group.feedrate_z_entry,
@@ -2558,6 +2558,7 @@ class App(QtCore.QObject):
self.edrills_tool = None
self.align_objects_tool = None
self.punch_tool = None
+ self.invert_tool = None
# always install tools only after the shell is initialized because the self.inform.emit() depends on shell
try:
@@ -2724,6 +2725,8 @@ class App(QtCore.QObject):
# this holds a widget that is installed in the Plot Area when View Source option is used
self.source_editor_tab = None
+ self.pagesize = dict()
+
# Storage for shapes, storage that can be used by FlatCAm tools for utility geometry
# VisPy visuals
if self.is_legacy is False:
@@ -3194,6 +3197,9 @@ class App(QtCore.QObject):
self.punch_tool = ToolPunchGerber(self)
self.punch_tool.install(icon=QtGui.QIcon(self.resource_location + '/punch32.png'), pos=self.ui.menutool)
+ self.invert_tool = ToolInvertGerber(self)
+ self.invert_tool.install(icon=QtGui.QIcon(self.resource_location + '/invert32.png'), pos=self.ui.menutool)
+
self.transform_tool = ToolTransform(self)
self.transform_tool.install(icon=QtGui.QIcon(self.resource_location + '/transform.png'),
pos=self.ui.menuoptions, separator=True)
@@ -3338,6 +3344,7 @@ class App(QtCore.QObject):
self.ui.copperfill_btn.triggered.connect(lambda: self.copper_thieving_tool.run(toggle=True))
self.ui.fiducials_btn.triggered.connect(lambda: self.fiducial_tool.run(toggle=True))
self.ui.punch_btn.triggered.connect(lambda: self.punch_tool.run(toggle=True))
+ self.ui.invert_btn.triggered.connect(lambda: self.invert_tool.run(toggle=True))
def object2editor(self):
"""
@@ -8716,14 +8723,14 @@ class App(QtCore.QObject):
else:
event_pos = (event.xdata, event.ydata)
# Matplotlib has the middle and right buttons mapped in reverse compared with VisPy
- pan_button = 3 if self.defaults["global_pan_button"] == '2'else 2
+ pan_button = 3 if self.defaults["global_pan_button"] == '2' else 2
# So it can receive key presses
self.plotcanvas.native.setFocus()
self.pos_canvas = self.plotcanvas.translate_coords(event_pos)
- if self.grid_status() == True:
+ if self.grid_status():
self.pos = self.geo_editor.snap(self.pos_canvas[0], self.pos_canvas[1])
else:
self.pos = (self.pos_canvas[0], self.pos_canvas[1])
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index e0534d7a..159cd1d5 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -2164,14 +2164,17 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
gerber_code += 'D02*\n'
gerber_code += 'G37*\n'
gerber_code += '%LPD*%\n'
+ except Exception as e:
+ log.debug("FlatCAMObj.FlatCAMGerber.export_gerber() '0' aperture --> %s" % str(e))
- for apid in self.apertures:
- if apid == '0':
- continue
- else:
- gerber_code += 'D%s*\n' % str(apid)
- if 'geometry' in self.apertures[apid]:
- for geo_elem in self.apertures[apid]['geometry']:
+ for apid in self.apertures:
+ if apid == '0':
+ continue
+ else:
+ gerber_code += 'D%s*\n' % str(apid)
+ if 'geometry' in self.apertures[apid]:
+ for geo_elem in self.apertures[apid]['geometry']:
+ try:
if 'follow' in geo_elem:
geo = geo_elem['follow']
if not geo.is_empty:
@@ -2212,7 +2215,10 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
prev_coord = coord
# gerber_code += "D02*\n"
+ except Exception as e:
+ log.debug("FlatCAMObj.FlatCAMGerber.export_gerber() 'follow' --> %s" % str(e))
+ try:
if 'clear' in geo_elem:
gerber_code += '%LPC*%\n'
@@ -2256,9 +2262,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
prev_coord = coord
# gerber_code += "D02*\n"
gerber_code += '%LPD*%\n'
-
- except Exception as e:
- log.debug("FlatCAMObj.FlatCAMGerber.export_gerber() --> %s" % str(e))
+ except Exception as e:
+ log.debug("FlatCAMObj.FlatCAMGerber.export_gerber() 'clear' --> %s" % str(e))
if not self.apertures:
log.debug("FlatCAMObj.FlatCAMGerber.export_gerber() --> Gerber Object is empty: no apertures.")
diff --git a/README.md b/README.md
index 076452e3..6ef6dff6 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
14.02.2020
- adjusted the UI for Excellon and Geometry objects
+- added a new FlatCAM Tool: Gerber Invert Tool. It will invert the copper features in a Gerber file: where is copper there will be empty and where is empty it will be copper
13.02.2020
diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py
index b8154db7..82d55bcf 100644
--- a/flatcamGUI/FlatCAMGUI.py
+++ b/flatcamGUI/FlatCAMGUI.py
@@ -928,6 +928,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
QtGui.QIcon(self.app.resource_location + '/calibrate_32.png'), _("Calibration Tool"))
self.punch_btn = self.toolbartools.addAction(
QtGui.QIcon(self.app.resource_location + '/punch32.png'), _("Punch Gerber Tool"))
+ self.invert_btn = self.toolbartools.addAction(
+ QtGui.QIcon(self.app.resource_location + '/invert32.png'), _("Invert Gerber Tool"))
# ########################################################################
# ########################## Excellon Editor Toolbar# ####################
diff --git a/flatcamParsers/ParseGerber.py b/flatcamParsers/ParseGerber.py
index 8acb3482..235521b4 100644
--- a/flatcamParsers/ParseGerber.py
+++ b/flatcamParsers/ParseGerber.py
@@ -1414,9 +1414,12 @@ class Gerber(Geometry):
self.follow_geometry = follow_buffer
# this treats the case when we are storing geometry as solids
-
- if len(poly_buffer) == 0 and len(self.solid_geometry) == 0:
- log.error("Object is not Gerber file or empty. Aborting Object creation.")
+ try:
+ if len(poly_buffer) == 0 and len(self.solid_geometry) == 0:
+ log.error("Object is not Gerber file or empty. Aborting Object creation.")
+ return 'fail'
+ except TypeError as e:
+ log.error("Object is not Gerber file or empty. Aborting Object creation. %s" % str(e))
return 'fail'
log.warning("Joining %d polygons." % len(poly_buffer))
diff --git a/flatcamTools/ToolInvertGerber.py b/flatcamTools/ToolInvertGerber.py
new file mode 100644
index 00000000..8d96419e
--- /dev/null
+++ b/flatcamTools/ToolInvertGerber.py
@@ -0,0 +1,274 @@
+# ##########################################################
+# FlatCAM: 2D Post-processing for Manufacturing #
+# File Author: Marius Adrian Stanciu (c) #
+# Date: 2/14/2020 #
+# MIT Licence #
+# ##########################################################
+
+from PyQt5 import QtWidgets, QtCore
+
+from FlatCAMTool import FlatCAMTool
+from flatcamGUI.GUIElements import FCButton, FCDoubleSpinner
+
+from shapely.geometry import Polygon, MultiPolygon, MultiLineString, LineString, box
+from shapely.ops import cascaded_union
+
+import traceback
+from copy import deepcopy
+import time
+import logging
+import gettext
+import FlatCAMTranslation as fcTranslate
+import builtins
+
+fcTranslate.apply_language('strings')
+if '_' not in builtins.__dict__:
+ _ = gettext.gettext
+
+log = logging.getLogger('base')
+
+
+class ToolInvertGerber(FlatCAMTool):
+
+ toolName = _("Invert Tool")
+
+ def __init__(self, app):
+ self.app = app
+ self.decimals = self.app.decimals
+
+ FlatCAMTool.__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
+ grid0 = QtWidgets.QGridLayout()
+ grid0.setColumnStretch(0, 0)
+ grid0.setColumnStretch(1, 1)
+ self.tools_box.addLayout(grid0)
+
+ grid0.addWidget(QtWidgets.QLabel(''), 0, 0, 1, 2)
+
+ # Target Gerber Object
+ self.gerber_combo = QtWidgets.QComboBox()
+ self.gerber_combo.setModel(self.app.collection)
+ self.gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.gerber_combo.setCurrentIndex(1)
+
+ self.gerber_label = QtWidgets.QLabel('%s:' % _("Gerber Object"))
+ self.gerber_label.setToolTip(
+ _("Gerber object that will be inverted.")
+ )
+
+ grid0.addWidget(self.gerber_label, 1, 0, 1, 2)
+ grid0.addWidget(self.gerber_combo, 2, 0, 1, 2)
+
+ # Margin
+ self.margin_label = QtWidgets.QLabel('%s:' % _('Margin'))
+ self.margin_label.setToolTip(
+ _("Distance by which to avoid\n"
+ "the edges of the Gerber object.")
+ )
+ self.margin_entry = FCDoubleSpinner()
+ self.margin_entry.set_precision(self.decimals)
+ self.margin_entry.set_range(0.0000, 9999.9999)
+ self.margin_entry.setObjectName(_("Margin"))
+
+ grid0.addWidget(self.margin_label, 3, 0)
+ grid0.addWidget(self.margin_entry, 3, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 4, 0, 1, 2)
+
+ self.invert_btn = FCButton(_('Invert Gerber'))
+ self.invert_btn.setToolTip(
+ _("Will invert the Gerber object: areas that have copper\n"
+ "will be emty of copper and previous empty area will be\n"
+ "filled with copper.")
+ )
+ self.invert_btn.setStyleSheet("""
+ QPushButton
+ {
+ font-weight: bold;
+ }
+ """)
+ grid0.addWidget(self.invert_btn, 5, 0, 1, 2)
+
+ self.tools_box.addStretch()
+
+ # ## Reset Tool
+ self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
+ self.reset_button.setToolTip(
+ _("Will reset the tool parameters.")
+ )
+ self.reset_button.setStyleSheet("""
+ QPushButton
+ {
+ font-weight: bold;
+ }
+ """)
+ self.tools_box.addWidget(self.reset_button)
+
+ self.invert_btn.clicked.connect(self.on_grb_invert)
+ self.reset_button.clicked.connect(self.set_tool_ui)
+
+ def install(self, icon=None, separator=None, **kwargs):
+ FlatCAMTool.install(self, icon, separator, shortcut='', **kwargs)
+
+ def run(self, toggle=True):
+ self.app.report_usage("ToolInvertGerber()")
+ log.debug("ToolInvertGerber() is running ...")
+
+ if toggle:
+ # if the splitter is hidden, display it, else hide it but only if the current widget is the same
+ if self.app.ui.splitter.sizes()[0] == 0:
+ self.app.ui.splitter.setSizes([1, 1])
+ else:
+ try:
+ if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
+ # if tab is populated with the tool but it does not have the focus, focus on it
+ if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
+ # focus on Tool Tab
+ self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
+ else:
+ self.app.ui.splitter.setSizes([0, 1])
+ except AttributeError:
+ pass
+ else:
+ if self.app.ui.splitter.sizes()[0] == 0:
+ self.app.ui.splitter.setSizes([1, 1])
+
+ FlatCAMTool.run(self)
+ self.set_tool_ui()
+
+ self.app.ui.notebook.setTabText(2, _("Invert Tool"))
+
+ def set_tool_ui(self):
+ self.margin_entry.set_value(0.0)
+
+ def on_grb_invert(self):
+ margin = self.margin_entry.get_value()
+ if round(margin, self.decimals) == 0.0:
+ margin = 1E-10
+
+ grb_circle_steps = int(self.app.defaults["gerber_circle_steps"])
+ obj_name = self.gerber_combo.currentText()
+
+ outname = obj_name + "_inverted"
+
+ # Get source object.
+ try:
+ grb_obj = self.app.collection.get_by_name(obj_name)
+ except Exception as e:
+ self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), str(obj_name)))
+ return "Could not retrieve object: %s with error: %s" % (obj_name, str(e))
+
+ if grb_obj is None:
+ self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Object not found"), str(obj_name)))
+ return
+
+ xmin, ymin, xmax, ymax = grb_obj.bounds()
+
+ grb_box = box(xmin, ymin, xmax, ymax).buffer(margin, resolution=grb_circle_steps, join_style=2)
+
+ try:
+ __ = iter(grb_obj.solid_geometry)
+ except TypeError:
+ grb_obj.solid_geometry = list(grb_obj.solid_geometry)
+
+ new_solid_geometry = deepcopy(grb_box)
+
+ for poly in grb_obj.solid_geometry:
+ new_solid_geometry = new_solid_geometry.difference(poly)
+
+ new_options = dict()
+ for opt in grb_obj.options:
+ new_options[opt] = deepcopy(grb_obj.options[opt])
+
+ new_apertures = dict()
+
+ # for apid, val in grb_obj.apertures.items():
+ # new_apertures[apid] = dict()
+ # for key in val:
+ # if key == 'geometry':
+ # new_apertures[apid]['geometry'] = list()
+ # for elem in val['geometry']:
+ # geo_elem = dict()
+ # if 'follow' in elem:
+ # try:
+ # geo_elem['clear'] = elem['follow'].buffer(val['size'] / 2.0).exterior
+ # except AttributeError:
+ # # TODO should test if width or height is bigger
+ # geo_elem['clear'] = elem['follow'].buffer(val['width'] / 2.0).exterior
+ # if 'clear' in elem:
+ # if isinstance(elem['clear'], Polygon):
+ # try:
+ # geo_elem['solid'] = elem['clear'].buffer(val['size'] / 2.0, grb_circle_steps)
+ # except AttributeError:
+ # # TODO should test if width or height is bigger
+ # geo_elem['solid'] = elem['clear'].buffer(val['width'] / 2.0, grb_circle_steps)
+ # else:
+ # geo_elem['follow'] = elem['clear']
+ # new_apertures[apid]['geometry'].append(deepcopy(geo_elem))
+ # else:
+ # new_apertures[apid][key] = deepcopy(val[key])
+
+ if '0' not in new_apertures:
+ new_apertures['0'] = dict()
+ new_apertures['0']['type'] = 'C'
+ new_apertures['0']['size'] = 0.0
+ new_apertures['0']['geometry'] = list()
+
+ try:
+ for poly in new_solid_geometry:
+ new_el = dict()
+ new_el['solid'] = poly
+ new_el['follow'] = poly.exterior
+ new_apertures['0']['geometry'].append(new_el)
+ except TypeError:
+ new_el = dict()
+ new_el['solid'] = new_solid_geometry
+ new_el['follow'] = new_solid_geometry.exterior
+ new_apertures['0']['geometry'].append(new_el)
+
+ for td in new_apertures:
+ print(td, new_apertures[td])
+
+ def init_func(new_obj, app_obj):
+ new_obj.options.update(new_options)
+ new_obj.options['name'] = outname
+ new_obj.fill_color = deepcopy(grb_obj.fill_color)
+ new_obj.outline_color = deepcopy(grb_obj.outline_color)
+
+ new_obj.apertures = deepcopy(new_apertures)
+
+ new_obj.solid_geometry = deepcopy(new_solid_geometry)
+ new_obj.source_file = self.app.export_gerber(obj_name=outname, filename=None,
+ local_use=new_obj, use_thread=False)
+
+ self.app.new_object('gerber', outname, init_func)
+
+ def reset_fields(self):
+ self.gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+
+ @staticmethod
+ def poly2rings(poly):
+ return [poly.exterior] + [interior for interior in poly.interiors]
+# end of file
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 5d9780f3..d0a945a1 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -358,6 +358,7 @@ class ToolPaint(FlatCAMTool, Gerber):
)
self.paintmargin_entry = FCDoubleSpinner()
self.paintmargin_entry.set_precision(self.decimals)
+ self.paintmargin_entry.set_range(-9999.9999, 9999.9999)
self.paintmargin_entry.setObjectName(_("Margin"))
grid4.addWidget(marginlabel, 2, 0)
diff --git a/flatcamTools/ToolPunchGerber.py b/flatcamTools/ToolPunchGerber.py
index f7378933..2a5d8ef4 100644
--- a/flatcamTools/ToolPunchGerber.py
+++ b/flatcamTools/ToolPunchGerber.py
@@ -515,6 +515,8 @@ class ToolPunchGerber(FlatCAMTool):
punch_method = self.method_punch.get_value()
+ new_options = deepcopy(grb_obj.options)
+
if punch_method == 'exc':
# get the Excellon file whose geometry will create the punch holes
@@ -574,7 +576,7 @@ class ToolPunchGerber(FlatCAMTool):
new_apertures[str(new_apid)] = deepcopy(ap_val)
def init_func(new_obj, app_obj):
- new_obj.options.update(grb_obj.options)
+ new_obj.options.update(new_options)
new_obj.options['name'] = outname
new_obj.fill_color = deepcopy(grb_obj.fill_color)
new_obj.outline_color = deepcopy(grb_obj.outline_color)
@@ -688,7 +690,7 @@ class ToolPunchGerber(FlatCAMTool):
new_apertures[str(new_apid)] = deepcopy(ap_val)
def init_func(new_obj, app_obj):
- new_obj.options.update(grb_obj.options)
+ new_obj.options.update(new_options)
new_obj.options['name'] = outname
new_obj.fill_color = deepcopy(grb_obj.fill_color)
new_obj.outline_color = deepcopy(grb_obj.outline_color)
@@ -830,7 +832,7 @@ class ToolPunchGerber(FlatCAMTool):
new_apertures[str(new_apid)] = deepcopy(ap_val)
def init_func(new_obj, app_obj):
- new_obj.options.update(grb_obj.options)
+ new_obj.options.update(new_options)
new_obj.options['name'] = outname
new_obj.fill_color = deepcopy(grb_obj.fill_color)
new_obj.outline_color = deepcopy(grb_obj.outline_color)
@@ -969,7 +971,7 @@ class ToolPunchGerber(FlatCAMTool):
new_apertures[str(new_apid)] = deepcopy(ap_val)
def init_func(new_obj, app_obj):
- new_obj.options.update(grb_obj.options)
+ new_obj.options.update(new_options)
new_obj.options['name'] = outname
new_obj.fill_color = deepcopy(grb_obj.fill_color)
new_obj.outline_color = deepcopy(grb_obj.outline_color)
diff --git a/flatcamTools/ToolSub.py b/flatcamTools/ToolSub.py
index 37d47ed3..99cc9fa8 100644
--- a/flatcamTools/ToolSub.py
+++ b/flatcamTools/ToolSub.py
@@ -254,14 +254,14 @@ class ToolSub(FlatCAMTool):
FlatCAMTool.run(self)
self.set_tool_ui()
+ self.app.ui.notebook.setTabText(2, _("Sub Tool"))
+
+ def set_tool_ui(self):
self.new_apertures.clear()
self.new_tools.clear()
self.new_solid_geometry = []
self.target_options.clear()
- self.app.ui.notebook.setTabText(2, _("Sub Tool"))
-
- def set_tool_ui(self):
self.tools_frame.show()
self.close_paths_cb.setChecked(self.app.defaults["tools_sub_close_paths"])
diff --git a/flatcamTools/__init__.py b/flatcamTools/__init__.py
index b503ca38..74d1aff5 100644
--- a/flatcamTools/__init__.py
+++ b/flatcamTools/__init__.py
@@ -39,3 +39,5 @@ from flatcamTools.ToolSub import ToolSub
from flatcamTools.ToolTransform import ToolTransform
from flatcamTools.ToolPunchGerber import ToolPunchGerber
+
+from flatcamTools.ToolInvertGerber import ToolInvertGerber
diff --git a/share/invert16.png b/share/invert16.png
new file mode 100644
index 0000000000000000000000000000000000000000..4246eb5b0a8459c7172e6512f08440d96671b3ae
GIT binary patch
literal 245
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_uJY5_^
zEP9VlGUPjCz~d?}>aBOtxrAw@d%{{Pr9#0&HziITImWZR!BBRVhrIT}Ajzzglahbm
zzP~Xs_hyIew1m~HzU;L*^(u7@)mx+wFp585d{f+@P{o|pdG&zhE!oyW;UBpN800G4
z#5S|8lPu`ky3OI8aH(@YbX^qpJazoTB<9Xi5
p^7vH0>-n$n&5yZ${-<9?O#d(FW*f>~od9$-gQu&X%Q~loCII{8TloM0
literal 0
HcmV?d00001
diff --git a/share/invert32.png b/share/invert32.png
new file mode 100644
index 0000000000000000000000000000000000000000..76e19dff2e2d182b32a97eb7d2b1bb3e041e61b0
GIT binary patch
literal 374
zcmV-+0g3*JP)lcCXnS4)^n@9EjD*{o9c0ysSqzyMz%32DTU
z*frPATux76oB7oi*Z@2GJpkT-p%b&PBUrv29e@e)?P&p1;7C?>SEUsQ0XP67MScQw
z>j0Q2a*d5$#Rm96F1uu&0%x*wQ3;^EhM!V$!8~!k+rU_}uohq+V1Ct0On|cTmzjg|
ze`^7Hf#&enBZ4Iz!Y%nKn36d65cZw;DA#bRG*5x|!kSS4t{tw*{2S=h0bs~F+={Hk
zQrSNQ^C$qO5Hkekz|xKx`Nk6!z<1KMx)~sbxfj6qC_NGQlJV#jc$PeyS8=087lwGZ
U0(5>a?f?J)07*qoM6N<$f)N>><^TWy
literal 0
HcmV?d00001
From 49c82a3e3353ca941764a178503592de275e21fa Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 15 Feb 2020 03:41:11 +0200
Subject: [PATCH 095/209] - added the Preferences entries for the Gerber Invert
Tool
---
FlatCAMApp.py | 8 +++++
README.md | 1 +
flatcamGUI/PreferencesUI.py | 60 ++++++++++++++++++++++++++++++++
flatcamTools/ToolInvertGerber.py | 59 +++++++++++++++++++++++--------
flatcamTools/ToolPunchGerber.py | 4 ++-
5 files changed, 116 insertions(+), 16 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 06ffbc72..3574dcfa 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -1002,6 +1002,10 @@ class App(QtCore.QObject):
# Align Objects Tool
"tools_align_objects_align_type": 'sp',
+ # Invert Gerber Tool
+ "tools_invert_margin": 0.1,
+ "tools_invert_join_style": 's',
+
# Utilities
# file associations
"fa_excellon": 'drd, drl, exc, ncd, tap, xln',
@@ -1666,6 +1670,10 @@ class App(QtCore.QObject):
"tools_punch_rectangular": self.ui.tools2_defaults_form.tools2_punch_group.rectangular_cb,
"tools_punch_others": self.ui.tools2_defaults_form.tools2_punch_group.other_cb,
+ # Invert Gerber Tool
+ "tools_invert_margin": self.ui.tools2_defaults_form.tools2_invert_group.margin_entry,
+ "tools_invert_join_style": self.ui.tools2_defaults_form.tools2_invert_group.join_radio,
+
# Utilities
# File associations
"fa_excellon": self.ui.util_defaults_form.fa_excellon_group.exc_list_text,
diff --git a/README.md b/README.md
index 6ef6dff6..374c683c 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- adjusted the UI for Excellon and Geometry objects
- added a new FlatCAM Tool: Gerber Invert Tool. It will invert the copper features in a Gerber file: where is copper there will be empty and where is empty it will be copper
+- added the Preferences entries for the Gerber Invert Tool
13.02.2020
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index eeeb413a..df1c0021 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -252,6 +252,9 @@ class Tools2PreferencesUI(QtWidgets.QWidget):
self.tools2_punch_group = Tools2PunchGerberPrefGroupUI(decimals=self.decimals)
self.tools2_punch_group.setMinimumWidth(220)
+ self.tools2_invert_group = Tools2InvertPrefGroupUI(decimals=self.decimals)
+ self.tools2_invert_group.setMinimumWidth(220)
+
self.vlay = QtWidgets.QVBoxLayout()
self.vlay.addWidget(self.tools2_checkrules_group)
self.vlay.addWidget(self.tools2_optimal_group)
@@ -269,6 +272,7 @@ class Tools2PreferencesUI(QtWidgets.QWidget):
self.vlay4 = QtWidgets.QVBoxLayout()
self.vlay4.addWidget(self.tools2_punch_group)
+ self.vlay4.addWidget(self.tools2_invert_group)
self.layout.addLayout(self.vlay)
self.layout.addLayout(self.vlay1)
@@ -8239,6 +8243,62 @@ class Tools2PunchGerberPrefGroupUI(OptionsGroupUI):
self.layout.addStretch()
+class Tools2InvertPrefGroupUI(OptionsGroupUI):
+ def __init__(self, decimals=4, parent=None):
+
+ super(Tools2InvertPrefGroupUI, self).__init__(self)
+
+ self.setTitle(str(_("Invert Gerber Tool Options")))
+ self.decimals = decimals
+
+ # ## Subtractor Tool Parameters
+ self.sublabel = QtWidgets.QLabel("%s:" % _("Parameters"))
+ self.sublabel.setToolTip(
+ _("A tool to invert Gerber geometry from positive to negative\n"
+ "and in revers.")
+ )
+ self.layout.addWidget(self.sublabel)
+
+ # Grid Layout
+ grid0 = QtWidgets.QGridLayout()
+ grid0.setColumnStretch(0, 0)
+ grid0.setColumnStretch(1, 1)
+ self.layout.addLayout(grid0)
+
+ # Margin
+ self.margin_label = QtWidgets.QLabel('%s:' % _('Margin'))
+ self.margin_label.setToolTip(
+ _("Distance by which to avoid\n"
+ "the edges of the Gerber object.")
+ )
+ self.margin_entry = FCDoubleSpinner()
+ self.margin_entry.set_precision(self.decimals)
+ self.margin_entry.set_range(0.0000, 9999.9999)
+ self.margin_entry.setObjectName(_("Margin"))
+
+ grid0.addWidget(self.margin_label, 2, 0, 1, 2)
+ grid0.addWidget(self.margin_entry, 3, 0, 1, 2)
+
+ self.join_label = QtWidgets.QLabel('%s:' % _("Lines Join Style"))
+ self.join_label.setToolTip(
+ _("The way that the lines in the object outline will be joined.\n"
+ "Can be:\n"
+ "- rounded -> an arc is added between two joining lines\n"
+ "- square -> the lines meet in 90 degrees angle\n"
+ "- bevel -> the lines are joined by a third line")
+ )
+ self.join_radio = RadioSet([
+ {'label': 'Rounded', 'value': 'r'},
+ {'label': 'Square', 'value': 's'},
+ {'label': 'Bevel', 'value': 'b'}
+ ], orientation='vertical', stretch=False)
+
+ grid0.addWidget(self.join_label, 5, 0, 1, 2)
+ grid0.addWidget(self.join_radio, 7, 0, 1, 2)
+
+ self.layout.addStretch()
+
+
class FAExcPrefGroupUI(OptionsGroupUI):
def __init__(self, decimals=4, parent=None):
# OptionsGroupUI.__init__(self, "Excellon File associations Preferences", parent=None)
diff --git a/flatcamTools/ToolInvertGerber.py b/flatcamTools/ToolInvertGerber.py
index 8d96419e..df1af676 100644
--- a/flatcamTools/ToolInvertGerber.py
+++ b/flatcamTools/ToolInvertGerber.py
@@ -8,14 +8,12 @@
from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import FCButton, FCDoubleSpinner
+from flatcamGUI.GUIElements import FCButton, FCDoubleSpinner, RadioSet
-from shapely.geometry import Polygon, MultiPolygon, MultiLineString, LineString, box
-from shapely.ops import cascaded_union
+from shapely.geometry import box
-import traceback
from copy import deepcopy
-import time
+
import logging
import gettext
import FlatCAMTranslation as fcTranslate
@@ -30,7 +28,7 @@ log = logging.getLogger('base')
class ToolInvertGerber(FlatCAMTool):
- toolName = _("Invert Tool")
+ toolName = _("Invert Gerber Tool")
def __init__(self, app):
self.app = app
@@ -56,7 +54,7 @@ class ToolInvertGerber(FlatCAMTool):
""")
self.tools_box.addWidget(title_label)
- # Form Layout
+ # Grid Layout
grid0 = QtWidgets.QGridLayout()
grid0.setColumnStretch(0, 0)
grid0.setColumnStretch(1, 1)
@@ -70,7 +68,7 @@ class ToolInvertGerber(FlatCAMTool):
self.gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.gerber_combo.setCurrentIndex(1)
- self.gerber_label = QtWidgets.QLabel('%s:' % _("Gerber Object"))
+ self.gerber_label = QtWidgets.QLabel('%s:' % _("GERBER"))
self.gerber_label.setToolTip(
_("Gerber object that will be inverted.")
)
@@ -78,6 +76,13 @@ class ToolInvertGerber(FlatCAMTool):
grid0.addWidget(self.gerber_label, 1, 0, 1, 2)
grid0.addWidget(self.gerber_combo, 2, 0, 1, 2)
+ grid0.addWidget(QtWidgets.QLabel(""), 3, 0, 1, 2)
+
+ self.param_label = QtWidgets.QLabel("%s:" % _("Parameters"))
+ self.param_label.setToolTip('%s.' % _("Parameters for this tool"))
+
+ grid0.addWidget(self.param_label, 4, 0, 1, 2)
+
# Margin
self.margin_label = QtWidgets.QLabel('%s:' % _('Margin'))
self.margin_label.setToolTip(
@@ -89,18 +94,35 @@ class ToolInvertGerber(FlatCAMTool):
self.margin_entry.set_range(0.0000, 9999.9999)
self.margin_entry.setObjectName(_("Margin"))
- grid0.addWidget(self.margin_label, 3, 0)
- grid0.addWidget(self.margin_entry, 3, 1)
+ grid0.addWidget(self.margin_label, 5, 0, 1, 2)
+ grid0.addWidget(self.margin_entry, 6, 0, 1, 2)
+
+ self.join_label = QtWidgets.QLabel('%s:' % _("Lines Join Style"))
+ self.join_label.setToolTip(
+ _("The way that the lines in the object outline will be joined.\n"
+ "Can be:\n"
+ "- rounded -> an arc is added between two joining lines\n"
+ "- square -> the lines meet in 90 degrees angle\n"
+ "- bevel -> the lines are joined by a third line")
+ )
+ self.join_radio = RadioSet([
+ {'label': 'Rounded', 'value': 'r'},
+ {'label': 'Square', 'value': 's'},
+ {'label': 'Bevel', 'value': 'b'}
+ ], orientation='vertical', stretch=False)
+
+ grid0.addWidget(self.join_label, 7, 0, 1, 2)
+ grid0.addWidget(self.join_radio, 8, 0, 1, 2)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid0.addWidget(separator_line, 4, 0, 1, 2)
+ grid0.addWidget(separator_line, 9, 0, 1, 2)
self.invert_btn = FCButton(_('Invert Gerber'))
self.invert_btn.setToolTip(
_("Will invert the Gerber object: areas that have copper\n"
- "will be emty of copper and previous empty area will be\n"
+ "will be empty of copper and previous empty area will be\n"
"filled with copper.")
)
self.invert_btn.setStyleSheet("""
@@ -109,7 +131,7 @@ class ToolInvertGerber(FlatCAMTool):
font-weight: bold;
}
""")
- grid0.addWidget(self.invert_btn, 5, 0, 1, 2)
+ grid0.addWidget(self.invert_btn, 10, 0, 1, 2)
self.tools_box.addStretch()
@@ -161,13 +183,18 @@ class ToolInvertGerber(FlatCAMTool):
self.app.ui.notebook.setTabText(2, _("Invert Tool"))
def set_tool_ui(self):
- self.margin_entry.set_value(0.0)
+ self.margin_entry.set_value(float(self.app.defaults["tools_invert_margin"]))
+ self.join_radio.set_value(self.app.defaults["tools_invert_join_style"])
def on_grb_invert(self):
margin = self.margin_entry.get_value()
if round(margin, self.decimals) == 0.0:
margin = 1E-10
+ join_style = {'r': 1, 'b': 3, 's': 2}[self.join_radio.get_value()]
+ if join_style is None:
+ join_style = 'r'
+
grb_circle_steps = int(self.app.defaults["gerber_circle_steps"])
obj_name = self.gerber_combo.currentText()
@@ -181,12 +208,14 @@ class ToolInvertGerber(FlatCAMTool):
return "Could not retrieve object: %s with error: %s" % (obj_name, str(e))
if grb_obj is None:
+ if obj_name == '':
+ obj_name = 'None'
self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Object not found"), str(obj_name)))
return
xmin, ymin, xmax, ymax = grb_obj.bounds()
- grb_box = box(xmin, ymin, xmax, ymax).buffer(margin, resolution=grb_circle_steps, join_style=2)
+ grb_box = box(xmin, ymin, xmax, ymax).buffer(margin, resolution=grb_circle_steps, join_style=join_style)
try:
__ = iter(grb_obj.solid_geometry)
diff --git a/flatcamTools/ToolPunchGerber.py b/flatcamTools/ToolPunchGerber.py
index 2a5d8ef4..282c20d4 100644
--- a/flatcamTools/ToolPunchGerber.py
+++ b/flatcamTools/ToolPunchGerber.py
@@ -515,7 +515,9 @@ class ToolPunchGerber(FlatCAMTool):
punch_method = self.method_punch.get_value()
- new_options = deepcopy(grb_obj.options)
+ new_options = dict()
+ for opt in grb_obj.options:
+ new_options[opt] = deepcopy(grb_obj.options[opt])
if punch_method == 'exc':
From d24290a2b6fcf648152140cf19d964356ea06cac Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 15 Feb 2020 06:23:39 +0200
Subject: [PATCH 096/209] - in Paint Tool added a new method of painting named
Combo who will pass through all the methods until the polygon is cleared - in
Paint Tool attempting to add a new mode suitable for Laser usage
---
README.md | 5 +
flatcamTools/ToolPaint.py | 326 +++++++++++++++++++++++++++++++++++---
2 files changed, 308 insertions(+), 23 deletions(-)
diff --git a/README.md b/README.md
index 374c683c..f9eca5f7 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+15.02.2020
+
+- in Paint Tool added a new method of painting named Combo who will pass through all the methods until the polygon is cleared
+- in Paint Tool attempting to add a new mode suitable for Laser usage
+
14.02.2020
- adjusted the UI for Excellon and Geometry objects
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index d0a945a1..57a2cc43 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -17,7 +17,7 @@ from camlib import Geometry
from flatcamGUI.GUIElements import FCTable, FCDoubleSpinner, FCCheckBox, FCInputDialog, RadioSet, FCButton
import FlatCAMApp
-from shapely.geometry import base, Polygon, MultiPolygon, LinearRing
+from shapely.geometry import base, Polygon, MultiPolygon, LinearRing, Point
from shapely.ops import cascaded_union
import numpy as np
@@ -370,17 +370,27 @@ class ToolPaint(FlatCAMTool, Gerber):
_("Algorithm for painting:\n"
"- Standard: Fixed step inwards.\n"
"- Seed-based: Outwards from seed.\n"
- "- Line-based: Parallel lines.")
+ "- Line-based: Parallel lines.\n"
+ "- Laser-lines: Active only when Laser Mode is active and only for Gerber objects.\n"
+ "Will create lines that follow the traces.\n"
+ "- Combo: In case of failure a new method will be picked from the above\n"
+ "in the order specified.")
)
self.paintmethod_combo = RadioSet([
{"label": _("Standard"), "value": "standard"},
{"label": _("Seed-based"), "value": "seed"},
- {"label": _("Straight lines"), "value": "lines"}
+ {"label": _("Straight lines"), "value": "lines"},
+ {"label": _("Laser lines"), "value": "laser_lines"},
+ {"label": _("Combo"), "value": "combo"}
], orientation='vertical', stretch=False)
self.paintmethod_combo.setObjectName(_("Method"))
- grid4.addWidget(methodlabel, 3, 0)
- grid4.addWidget(self.paintmethod_combo, 3, 1)
+ for choice in self.paintmethod_combo.choices:
+ if choice['value'] == "laser_lines":
+ choice["radio"].setEnabled(False)
+
+ grid4.addWidget(methodlabel, 7, 0)
+ grid4.addWidget(self.paintmethod_combo, 7, 1)
# Connect lines
self.pathconnect_cb = FCCheckBox('%s' % _("Connect"))
@@ -397,32 +407,32 @@ class ToolPaint(FlatCAMTool, Gerber):
"to trim rough edges.")
)
- grid4.addWidget(self.pathconnect_cb, 4, 0)
- grid4.addWidget(self.paintcontour_cb, 4, 1)
+ grid4.addWidget(self.pathconnect_cb, 10, 0)
+ grid4.addWidget(self.paintcontour_cb, 10, 1)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid4.addWidget(separator_line, 5, 0, 1, 2)
+ grid4.addWidget(separator_line, 11, 0, 1, 2)
self.apply_param_to_all = FCButton(_("Apply parameters to all tools"))
self.apply_param_to_all.setToolTip(
_("The parameters in the current form will be applied\n"
"on all the tools from the Tool Table.")
)
- grid4.addWidget(self.apply_param_to_all, 7, 0, 1, 2)
+ grid4.addWidget(self.apply_param_to_all, 12, 0, 1, 2)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid4.addWidget(separator_line, 8, 0, 1, 2)
+ grid4.addWidget(separator_line, 13, 0, 1, 2)
# General Parameters
self.gen_param_label = QtWidgets.QLabel('%s' % _("Common Parameters"))
self.gen_param_label.setToolTip(
_("Parameters that are common for all tools.")
)
- grid4.addWidget(self.gen_param_label, 10, 0, 1, 2)
+ grid4.addWidget(self.gen_param_label, 15, 0, 1, 2)
self.rest_cb = FCCheckBox('%s' % _("Rest Machining"))
self.rest_cb.setObjectName(_("Rest Machining"))
@@ -435,7 +445,17 @@ class ToolPaint(FlatCAMTool, Gerber):
"no more copper to clear or there are no more tools.\n\n"
"If not checked, use the standard algorithm.")
)
- grid4.addWidget(self.rest_cb, 11, 0, 1, 2)
+ grid4.addWidget(self.rest_cb, 16, 0, 1, 2)
+
+
+ # Laser Mode
+ self.laser_cb = FCCheckBox(_("Laser Mode"))
+ self.laser_cb.setToolTip(
+ _("This control is enabled only for Gerber objects.\n"
+ "If checked then a new method is shown in Methods,\n"
+ "and it is also added to the Combo Method sequence.")
+ )
+ grid4.addWidget(self.laser_cb, 17, 0, 1, 2)
# Polygon selection
selectlabel = QtWidgets.QLabel('%s:' % _('Selection'))
@@ -467,11 +487,11 @@ class ToolPaint(FlatCAMTool, Gerber):
"specified by another object.")
)
- grid4.addWidget(selectlabel, 13, 0, 1, 2)
- grid4.addWidget(self.selectmethod_combo, 14, 0, 1, 2)
+ grid4.addWidget(selectlabel, 18, 0, 1, 2)
+ grid4.addWidget(self.selectmethod_combo, 19, 0, 1, 2)
form1 = QtWidgets.QFormLayout()
- grid4.addLayout(form1, 15, 0, 1, 2)
+ grid4.addLayout(form1, 20, 0, 1, 2)
self.box_combo_type_label = QtWidgets.QLabel('%s:' % _("Ref. Type"))
self.box_combo_type_label.setToolTip(
@@ -617,6 +637,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.box_combo_type.currentIndexChanged.connect(self.on_combo_box_type)
self.type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
+ self.laser_cb.stateChanged.connect(self.on_laser_mode_toggled)
self.reset_button.clicked.connect(self.set_tool_ui)
# #############################################################################
@@ -640,6 +661,21 @@ class ToolPaint(FlatCAMTool, Gerber):
self.obj_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.obj_combo.setCurrentIndex(0)
+ if self.type_obj_combo.currentText().lower() == 'gerber':
+ self.laser_cb.setEnabled(True)
+ else:
+ self.laser_cb.setEnabled(False)
+
+ def on_laser_mode_toggled(self, val):
+ for choice in self.paintmethod_combo.choices:
+ if choice['value'] == "laser_lines":
+ if val:
+ choice["radio"].setEnabled(True)
+ else:
+ choice["radio"].setEnabled(False)
+ if self.paintmethod_combo.get_value() == "laser_lines":
+ self.paintmethod_combo.set_value('lines')
+
def install(self, icon=None, separator=None, **kwargs):
FlatCAMTool.install(self, icon, separator, shortcut='ALT+P', **kwargs)
@@ -938,6 +974,10 @@ class ToolPaint(FlatCAMTool, Gerber):
# make the default object type, "Geometry"
self.type_obj_combo.setCurrentIndex(2)
+
+ # make the Laser Mode disabled because the Geometry object is default
+ self.laser_cb.setEnabled(False)
+
# updated units
self.units = self.app.defaults['units'].upper()
@@ -1486,6 +1526,7 @@ class ToolPaint(FlatCAMTool, Gerber):
if self.poly_dict:
poly_list = deepcopy(list(self.poly_dict.values()))
self.paint_poly(self.paint_obj,
+ inside_pt=(curr_pos[0], curr_pos[1]),
poly_list=poly_list,
tooldia=self.tooldia_list,
overlap=self.overlap,
@@ -1746,7 +1787,7 @@ class ToolPaint(FlatCAMTool, Gerber):
connect=conn,
prog_plot=prog_plot)
- else:
+ elif paint_method == "standard":
# Type(cp) == FlatCAMRTreeStorage | None
cpoly = self.clear_polygon(polyg,
tooldia=tooldiameter,
@@ -1755,12 +1796,73 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont,
connect=conn,
prog_plot=prog_plot)
+ elif paint_method == "laser_lines":
+ line = None
+ aperture_size = None
+
+ # determine the Gerber follow line
+ for apid, apval in obj.apertures.items():
+ for geo_el in apval['geometry']:
+ if 'solid' in geo_el:
+ if Point(inside_pt).within(geo_el['solid']):
+ if not isinstance(geo_el['follow'], Point):
+ line = geo_el['follow']
+
+ if apval['type'] == 'C':
+ aperture_size = apval['size']
+ else:
+ if apval['width'] > apval['height']:
+ aperture_size = apval['height']
+ else:
+ aperture_size = apval['width']
+ print(line, aperture_size)
+ if line:
+ cpoly = self.fill_with_lines(line, aperture_size,
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults["geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ elif paint_method == "combo":
+ self.app.inform.emit(_("Painting polygon with method: lines."))
+ cpoly = self.clear_polygon3(polyg,
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults["geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ if cpoly and cpoly.objects:
+ pass
+ else:
+ self.app.inform.emit(_("Failed. Painting polygon with method: seed."))
+ cpoly = self.clear_polygon2(polyg,
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults["geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+ if cpoly and cpoly.objects:
+ pass
+ else:
+ self.app.inform.emit(_("Failed. Painting polygon with method: standard."))
+ cpoly = self.clear_polygon(polyg,
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults["geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
except FlatCAMApp.GracefulException:
return "fail"
except Exception as ee:
log.debug("ToolPaint.paint_poly().gen_paintarea().paint_p() --> %s" % str(ee))
- if cpoly is not None:
+ if cpoly and cpoly.objects:
geo_obj.solid_geometry += list(cpoly.get_objects())
return cpoly
else:
@@ -2095,6 +2197,7 @@ class ToolPaint(FlatCAMTool, Gerber):
try:
for pol in poly_buf:
if pol is not None and isinstance(pol, Polygon):
+ cp = None
if paint_method == 'standard':
cp = self.clear_polygon(pol,
tooldia=tool_dia,
@@ -2113,7 +2216,7 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont,
connect=conn,
prog_plot=prog_plot)
- else:
+ elif paint_method == "standard":
cp = self.clear_polygon3(pol,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
@@ -2122,7 +2225,44 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont,
connect=conn,
prog_plot=prog_plot)
- if cp:
+ elif paint_method == "combo":
+ self.app.inform.emit(_("Painting polygons with method: lines."))
+ cp = self.clear_polygon3(pol,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ if cp and cp.objects:
+ pass
+ else:
+ self.app.inform.emit(_("Failed. Painting polygons with method: seed."))
+ cp = self.clear_polygon2(pol,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+ if cp and cp.objects:
+ pass
+ else:
+ self.app.inform.emit(
+ _("Failed. Painting polygons with method: standard."))
+
+ cp = self.clear_polygon(pol,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+ if cp and cp.objects:
total_geometry += list(cp.get_objects())
poly_processed.append(True)
else:
@@ -2133,6 +2273,7 @@ class ToolPaint(FlatCAMTool, Gerber):
"It is: %s" % str(type(pol)))
except TypeError:
if isinstance(poly_buf, Polygon):
+ cp = None
if paint_method == 'standard':
cp = self.clear_polygon(poly_buf,
tooldia=tool_dia,
@@ -2151,7 +2292,7 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont,
connect=conn,
prog_plot=prog_plot)
- else:
+ elif paint_method == 'standard':
cp = self.clear_polygon3(poly_buf,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
@@ -2160,6 +2301,41 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont,
connect=conn,
prog_plot=prog_plot)
+ elif paint_method == "combo":
+ self.app.inform.emit(_("Painting polygons with method: lines."))
+ cp = self.clear_polygon3(poly_buf,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ if cp and cp.objects:
+ pass
+ else:
+ self.app.inform.emit(_("Failed. Painting polygons with method: seed."))
+ cp = self.clear_polygon2(poly_buf,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+ if cp and cp.objects:
+ pass
+ else:
+ self.app.inform.emit(_("Failed. Painting polygons with method: standard."))
+ cp = self.clear_polygon(poly_buf,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
if cp:
total_geometry += list(cp.get_objects())
poly_processed.append(True)
@@ -2377,6 +2553,41 @@ class ToolPaint(FlatCAMTool, Gerber):
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over, contour=cont, connect=conn,
prog_plot=prog_plot)
+ elif paint_method == "combo":
+ self.app.inform.emit(_("Painting polygons with method: lines."))
+ cp = self.clear_polygon3(poly_buf,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ if cp and cp.objects:
+ pass
+ else:
+ self.app.inform.emit(_("Failed. Painting polygons with method: seed."))
+ cp = self.clear_polygon2(poly_buf,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+ if cp and cp.objects:
+ pass
+ else:
+ self.app.inform.emit(_("Failed. Painting polygons with method: standard."))
+ cp = self.clear_polygon(poly_buf,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
if cp is not None:
cleared_geo += list(cp.get_objects())
@@ -2666,6 +2877,7 @@ class ToolPaint(FlatCAMTool, Gerber):
continue
poly_buf = geo.buffer(-paint_margin)
+ cp = None
if paint_method == "seed":
# Type(cp) == FlatCAMRTreeStorage | None
cp = self.clear_polygon2(poly_buf,
@@ -2686,7 +2898,7 @@ class ToolPaint(FlatCAMTool, Gerber):
connect=conn,
prog_plot=prog_plot)
- else:
+ elif paint_method == 'standard':
# Type(cp) == FlatCAMRTreeStorage | None
cp = self.clear_polygon(poly_buf,
tooldia=tool_dia,
@@ -2695,8 +2907,42 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont,
connect=conn,
prog_plot=prog_plot)
+ elif paint_method == "combo":
+ self.app.inform.emit(_("Painting polygons with method: lines."))
+ cp = self.clear_polygon3(poly_buf,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
- if cp is not None:
+ if cp and cp.objects:
+ pass
+ else:
+ self.app.inform.emit(_("Failed. Painting polygons with method: seed."))
+ cp = self.clear_polygon2(poly_buf,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+ if cp and cp.objects:
+ pass
+ else:
+ self.app.inform.emit(_("Failed. Painting polygons with method: standard."))
+ cp = self.clear_polygon(poly_buf,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+ if cp and cp.objects:
total_geometry += list(cp.get_objects())
except FlatCAMApp.GracefulException:
return "fail"
@@ -2855,8 +3101,42 @@ class ToolPaint(FlatCAMTool, Gerber):
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over, contour=cont, connect=conn,
prog_plot=prog_plot)
+ elif paint_method == "combo":
+ self.app.inform.emit(_("Painting polygons with method: lines."))
+ cp = self.clear_polygon3(poly_buf,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
- if cp is not None:
+ if cp and cp.objects:
+ pass
+ else:
+ self.app.inform.emit(_("Failed. Painting polygons with method: seed."))
+ cp = self.clear_polygon2(poly_buf,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+ if cp and cp.objects:
+ pass
+ else:
+ self.app.inform.emit(_("Failed. Painting polygons with method: standard."))
+ cp = self.clear_polygon(poly_buf,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+ if cp and cp.objects:
cleared_geo += list(cp.get_objects())
except FlatCAMApp.GracefulException:
return "fail"
From 25c9a31179c5e5fe8c59b0deeedde47a9dec8186 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 15 Feb 2020 21:11:06 +0200
Subject: [PATCH 097/209] - more work in the new Laser Mode in the Paint Tool
---
README.md | 1 +
camlib.py | 90 ++--
flatcamTools/ToolPaint.py | 1005 ++++++++++++++++++++++++++++++++-----
3 files changed, 930 insertions(+), 166 deletions(-)
diff --git a/README.md b/README.md
index f9eca5f7..bf72391f 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- in Paint Tool added a new method of painting named Combo who will pass through all the methods until the polygon is cleared
- in Paint Tool attempting to add a new mode suitable for Laser usage
+- more work in the new Laser Mode in the Paint Tool
14.02.2020
diff --git a/camlib.py b/camlib.py
index a939f9a1..52bd863c 100644
--- a/camlib.py
+++ b/camlib.py
@@ -1582,7 +1582,7 @@ class Geometry(object):
"""
# log.debug("camlib.fill_with_lines()")
- if not isinstance(line, LineString) or not isinstance(line, MultiLineString):
+ if not isinstance(line, LineString) and not isinstance(line, MultiLineString):
log.debug("camlib.Geometry.fill_with_lines() --> Not a LineString/MultiLineString but %s" % str(type(line)))
return None
@@ -1596,10 +1596,10 @@ class Geometry(object):
lines_trimmed = []
- polygon = line.buffer(aperture_size / 1.99999999999999999, int(steps_per_circle))
+ polygon = line.buffer(aperture_size / 2.0, int(steps_per_circle))
try:
- margin_poly = polygon.buffer(-tooldia / 1.99999999, int(steps_per_circle))
+ margin_poly = polygon.buffer(-tooldia / 2.0, int(steps_per_circle))
except Exception:
log.debug("camlib.Geometry.fill_with_lines() --> Could not buffer the Polygon, tool diameter too high")
return None
@@ -1615,41 +1615,51 @@ class Geometry(object):
# provide the app with a way to process the GUI events when in a blocking loop
QtWidgets.QApplication.processEvents()
- line = line.parallel_offset(distance=delta, side='left', resolution=int(steps_per_circle))
- line = line.intersection(margin_poly)
- lines_trimmed.append(line)
+ new_line = line.parallel_offset(distance=delta, side='left', resolution=int(steps_per_circle))
+ new_line = new_line.intersection(margin_poly)
+ lines_trimmed.append(new_line)
- line = line.parallel_offset(distance=delta, side='right', resolution=int(steps_per_circle))
- line = line.intersection(margin_poly)
- lines_trimmed.append(line)
+ new_line = line.parallel_offset(distance=delta, side='right', resolution=int(steps_per_circle))
+ new_line = new_line.intersection(margin_poly)
+ lines_trimmed.append(new_line)
delta += tooldia * (1 - overlap)
if prog_plot:
- self.plot_temp_shapes(line)
+ self.plot_temp_shapes(new_line)
self.temp_shapes.redraw()
# Last line
- delta = aperture_size / 2
+ delta = (aperture_size / 2) - (tooldia / 2.00000001)
- line = line.parallel_offset(distance=delta, side='left', resolution=int(steps_per_circle))
- line = line.intersection(margin_poly)
-
- for ll in line:
- lines_trimmed.append(ll)
- if prog_plot:
- self.plot_temp_shapes(line)
-
- line = line.parallel_offset(distance=delta, side='left', resolution=int(steps_per_circle))
- line = line.intersection(margin_poly)
-
- for ll in line:
- lines_trimmed.append(ll)
- if prog_plot:
- self.plot_temp_shapes(line)
+ new_line = line.parallel_offset(distance=delta, side='left', resolution=int(steps_per_circle))
+ new_line = new_line.intersection(margin_poly)
except Exception as e:
log.debug('camlib.Geometry.fill_with_lines() Processing poly --> %s' % str(e))
return None
+ try:
+ for ll in new_line:
+ lines_trimmed.append(ll)
+ if prog_plot:
+ self.plot_temp_shapes(ll)
+ except TypeError:
+ lines_trimmed.append(new_line)
+ if prog_plot:
+ self.plot_temp_shapes(new_line)
+
+ new_line = line.parallel_offset(distance=delta, side='right', resolution=int(steps_per_circle))
+ new_line = new_line.intersection(margin_poly)
+
+ try:
+ for ll in new_line:
+ lines_trimmed.append(ll)
+ if prog_plot:
+ self.plot_temp_shapes(ll)
+ except TypeError:
+ lines_trimmed.append(new_line)
+ if prog_plot:
+ self.plot_temp_shapes(new_line)
+
if prog_plot:
self.temp_shapes.redraw()
@@ -3434,10 +3444,13 @@ class CNCjob(Geometry):
self.f_plunge = self.app.defaults["geometry_f_plunge"]
if self.z_cut is None:
- self.app.inform.emit('[ERROR_NOTCL] %s' %
- _("Cut_Z parameter is None or zero. Most likely a bad combinations of "
- "other parameters."))
- return 'fail'
+ if 'laser' not in self.pp_geometry_name:
+ self.app.inform.emit('[ERROR_NOTCL] %s' %
+ _("Cut_Z parameter is None or zero. Most likely a bad combinations of "
+ "other parameters."))
+ return 'fail'
+ else:
+ self.z_cut = 0
if self.machinist_setting == 0:
if self.z_cut > 0:
@@ -3448,7 +3461,7 @@ class CNCjob(Geometry):
"therefore the app will convert the value to negative."
"Check the resulting CNC code (Gcode etc)."))
self.z_cut = -self.z_cut
- elif self.z_cut == 0:
+ elif self.z_cut == 0 and 'laser' not in self.pp_geometry_name:
self.app.inform.emit('[WARNING] %s: %s' %
(_("The Cut Z parameter is zero. There will be no cut, skipping file"),
self.options['name']))
@@ -3793,11 +3806,14 @@ class CNCjob(Geometry):
if self.machinist_setting == 0:
if self.z_cut is None:
- self.app.inform.emit(
- '[ERROR_NOTCL] %s' % _("Cut_Z parameter is None or zero. Most likely a bad combinations of "
- "other parameters.")
- )
- return 'fail'
+ if 'laser' not in self.pp_geometry_name:
+ self.app.inform.emit(
+ '[ERROR_NOTCL] %s' % _("Cut_Z parameter is None or zero. Most likely a bad combinations of "
+ "other parameters.")
+ )
+ return 'fail'
+ else:
+ self.z_cut = 0.0
if self.z_cut > 0:
self.app.inform.emit('[WARNING] %s' %
@@ -3807,7 +3823,7 @@ class CNCjob(Geometry):
"therefore the app will convert the value to negative."
"Check the resulting CNC code (Gcode etc)."))
self.z_cut = -self.z_cut
- elif self.z_cut == 0:
+ elif self.z_cut == 0 and 'laser' not in self.pp_geometry_name:
self.app.inform.emit(
'[WARNING] %s: %s' % (_("The Cut Z parameter is zero. There will be no cut, skipping file"),
geometry.options['name'])
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 57a2cc43..8774c137 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -13,12 +13,12 @@ from copy import deepcopy
# from ObjectCollection import *
from flatcamParsers.ParseGerber import Gerber
from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry
-from camlib import Geometry
+from camlib import Geometry, FlatCAMRTreeStorage
from flatcamGUI.GUIElements import FCTable, FCDoubleSpinner, FCCheckBox, FCInputDialog, RadioSet, FCButton
import FlatCAMApp
-from shapely.geometry import base, Polygon, MultiPolygon, LinearRing, Point
-from shapely.ops import cascaded_union
+from shapely.geometry import base, Polygon, MultiPolygon, LinearRing, Point, MultiLineString
+from shapely.ops import cascaded_union, unary_union, linemerge
import numpy as np
import math
@@ -447,7 +447,6 @@ class ToolPaint(FlatCAMTool, Gerber):
)
grid4.addWidget(self.rest_cb, 16, 0, 1, 2)
-
# Laser Mode
self.laser_cb = FCCheckBox(_("Laser Mode"))
self.laser_cb.setToolTip(
@@ -681,6 +680,7 @@ class ToolPaint(FlatCAMTool, Gerber):
def run(self, toggle=True):
self.app.report_usage("ToolPaint()")
+ log.debug("ToolPaint().run() was launched ...")
if toggle:
# if the splitter is hidden, display it, else hide it but only if the current widget is the same
@@ -795,9 +795,9 @@ class ToolPaint(FlatCAMTool, Gerber):
self.blockSignals(True)
- row = self.tools_table.currentRow()
- if row < 0:
- row = 0
+ # row = self.tools_table.currentRow()
+ # if row < 0:
+ # row = 0
# this new dict will hold the actual useful data, another dict that is the value of key 'data'
temp_tools = {}
@@ -952,32 +952,8 @@ class ToolPaint(FlatCAMTool, Gerber):
self.tools_frame.show()
self.reset_fields()
- # ## Init the GUI interface
- self.order_radio.set_value(self.app.defaults["tools_paintorder"])
- self.paintmargin_entry.set_value(self.app.defaults["tools_paintmargin"])
- self.paintmethod_combo.set_value(self.app.defaults["tools_paintmethod"])
- self.selectmethod_combo.set_value(self.app.defaults["tools_selectmethod"])
- self.pathconnect_cb.set_value(self.app.defaults["tools_pathconnect"])
- self.paintcontour_cb.set_value(self.app.defaults["tools_paintcontour"])
- self.paintoverlap_entry.set_value(self.app.defaults["tools_paintoverlap"])
-
- self.cutz_entry.set_value(self.app.defaults["tools_paintcutz"])
- self.tool_type_radio.set_value(self.app.defaults["tools_painttool_type"])
- self.tipdia_entry.set_value(self.app.defaults["tools_painttipdia"])
- self.tipangle_entry.set_value(self.app.defaults["tools_painttipangle"])
- self.addtool_entry.set_value(self.app.defaults["tools_paintnewdia"])
- self.rest_cb.set_value(self.app.defaults["tools_paintrest"])
-
self.old_tool_dia = self.app.defaults["tools_paintnewdia"]
- self.on_tool_type(val=self.tool_type_radio.get_value())
-
- # make the default object type, "Geometry"
- self.type_obj_combo.setCurrentIndex(2)
-
- # make the Laser Mode disabled because the Geometry object is default
- self.laser_cb.setEnabled(False)
-
# updated units
self.units = self.app.defaults['units'].upper()
@@ -1020,6 +996,30 @@ class ToolPaint(FlatCAMTool, Gerber):
"paintrest": self.app.defaults["tools_paintrest"],
})
+ # ## Init the GUI interface
+ self.order_radio.set_value(self.app.defaults["tools_paintorder"])
+ self.paintmargin_entry.set_value(self.app.defaults["tools_paintmargin"])
+ self.paintmethod_combo.set_value(self.app.defaults["tools_paintmethod"])
+ self.selectmethod_combo.set_value(self.app.defaults["tools_selectmethod"])
+ self.pathconnect_cb.set_value(self.app.defaults["tools_pathconnect"])
+ self.paintcontour_cb.set_value(self.app.defaults["tools_paintcontour"])
+ self.paintoverlap_entry.set_value(self.app.defaults["tools_paintoverlap"])
+
+ self.cutz_entry.set_value(self.app.defaults["tools_paintcutz"])
+ self.tool_type_radio.set_value(self.app.defaults["tools_painttool_type"])
+ self.tipdia_entry.set_value(self.app.defaults["tools_painttipdia"])
+ self.tipangle_entry.set_value(self.app.defaults["tools_painttipangle"])
+ self.addtool_entry.set_value(self.app.defaults["tools_paintnewdia"])
+ self.rest_cb.set_value(self.app.defaults["tools_paintrest"])
+
+ self.on_tool_type(val=self.tool_type_radio.get_value())
+
+ # make the default object type, "Geometry"
+ self.type_obj_combo.setCurrentIndex(2)
+
+ # make the Laser Mode disabled because the Geometry object is default
+ self.laser_cb.setEnabled(False)
+
try:
diameters = [float(self.app.defaults["tools_painttooldia"])]
except (ValueError, TypeError):
@@ -1718,7 +1718,7 @@ class ToolPaint(FlatCAMTool, Gerber):
polygon_list = None
if inside_pt and poly_list is None:
polygon_list = [self.find_polygon(point=inside_pt, geoset=obj.solid_geometry)]
- elif inside_pt is None and poly_list:
+ elif (inside_pt is None and poly_list) or (inside_pt and poly_list):
polygon_list = poly_list
# No polygon?
@@ -1797,43 +1797,161 @@ class ToolPaint(FlatCAMTool, Gerber):
connect=conn,
prog_plot=prog_plot)
elif paint_method == "laser_lines":
- line = None
- aperture_size = None
+ # line = None
+ # aperture_size = None
- # determine the Gerber follow line
+ # the key is the aperture type and the val is a list of geo elements
+ flash_el_dict = dict()
+ # the key is the aperture size, the val is a list of geo elements
+ traces_el_dict = dict()
+
+ # find the flashes and the lines that are in the selected polygon and store them separately
for apid, apval in obj.apertures.items():
for geo_el in apval['geometry']:
- if 'solid' in geo_el:
- if Point(inside_pt).within(geo_el['solid']):
- if not isinstance(geo_el['follow'], Point):
- line = geo_el['follow']
+ if apval["size"] == 0.0:
+ if apval["size"] in traces_el_dict:
+ traces_el_dict[apval["size"]].append(geo_el)
+ else:
+ traces_el_dict[apval["size"]] = [geo_el]
- if apval['type'] == 'C':
- aperture_size = apval['size']
+ if 'follow' in geo_el and geo_el['follow'].within(polyg):
+ if isinstance(geo_el['follow'], Point):
+ if apval["type"] == 'C':
+ if 'C' in flash_el_dict:
+ flash_el_dict['C'].append(geo_el)
else:
- if apval['width'] > apval['height']:
- aperture_size = apval['height']
- else:
- aperture_size = apval['width']
- print(line, aperture_size)
- if line:
- cpoly = self.fill_with_lines(line, aperture_size,
- tooldia=tooldiameter,
- steps_per_circle=self.app.defaults["geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
+ flash_el_dict['C'] = [geo_el]
+ elif apval["type"] == 'O':
+ if 'O' in flash_el_dict:
+ flash_el_dict['O'].append(geo_el)
+ else:
+ flash_el_dict['O'] = [geo_el]
+ elif apval["type"] == 'R':
+ if 'R' in flash_el_dict:
+ flash_el_dict['R'].append(geo_el)
+ else:
+ flash_el_dict['R'] = [geo_el]
+ else:
+ aperture_size = apval['size']
+
+ if aperture_size in traces_el_dict:
+ traces_el_dict[aperture_size].append(geo_el)
+ else:
+ traces_el_dict[aperture_size] = [geo_el]
+
+ cpoly = FlatCAMRTreeStorage()
+ pads_lines_list = list()
+
+ # process the flashes found in the selected polygon with the 'lines' method for rectangular
+ # flashes and with 'seed' for oblong and circular flashes
+ # and pads (flahes) need the contour therefore I override the GUI settings with always True
+ for ap_type in flash_el_dict:
+ for elem in flash_el_dict[ap_type]:
+ if 'solid' in elem:
+ if ap_type == 'C':
+ f_o = self.clear_polygon2(elem['solid'],
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ elif ap_type == 'O':
+ f_o = self.clear_polygon2(elem['solid'],
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ elif ap_type == 'R':
+ f_o = self.clear_polygon3(elem['solid'],
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ # add the lines from pads to the storage
+ try:
+ for lin in pads_lines_list:
+ if lin:
+ cpoly.insert(lin)
+ except TypeError:
+ cpoly.insert(pads_lines_list)
+
+ copper_lines_list = list()
+ # process the traces found in the selected polygon using the 'laser_lines' method,
+ # method which will follow the 'follow' line therefore use the longer path possible for the
+ # laser, therefore the acceleration will play a smaller factor
+ for aperture_size in traces_el_dict:
+ for elem in traces_el_dict[aperture_size]:
+ line = elem['follow']
+ if line:
+ t_o = self.fill_with_lines(line, aperture_size,
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ copper_lines_list += [p for p in t_o.get_objects() if p]
+
+ # add the lines from copper features to storage but first try to make as few lines as possible
+ # by trying to fuse them
+ lines_union = linemerge(unary_union(copper_lines_list))
+ try:
+ for lin in lines_union:
+ if lin:
+ cpoly.insert(lin)
+ except TypeError:
+ cpoly.insert(lines_union)
+ # # determine the Gerber follow line
+ # for apid, apval in obj.apertures.items():
+ # for geo_el in apval['geometry']:
+ # if 'solid' in geo_el:
+ # if Point(inside_pt).within(geo_el['solid']):
+ # if not isinstance(geo_el['follow'], Point):
+ # line = geo_el['follow']
+ #
+ # if apval['type'] == 'C':
+ # aperture_size = apval['size']
+ # else:
+ # if apval['width'] > apval['height']:
+ # aperture_size = apval['height']
+ # else:
+ # aperture_size = apval['width']
+ #
+ # if line:
+ # cpoly = self.fill_with_lines(line, aperture_size,
+ # tooldia=tooldiameter,
+ # steps_per_circle=self.app.defaults["geometry_circle_steps"],
+ # overlap=over,
+ # contour=cont,
+ # connect=conn,
+ # prog_plot=prog_plot)
elif paint_method == "combo":
self.app.inform.emit(_("Painting polygon with method: lines."))
cpoly = self.clear_polygon3(polyg,
- tooldia=tooldiameter,
- steps_per_circle=self.app.defaults["geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults["geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
if cpoly and cpoly.objects:
pass
@@ -1851,12 +1969,12 @@ class ToolPaint(FlatCAMTool, Gerber):
else:
self.app.inform.emit(_("Failed. Painting polygon with method: standard."))
cpoly = self.clear_polygon(polyg,
- tooldia=tooldiameter,
- steps_per_circle=self.app.defaults["geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults["geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
except FlatCAMApp.GracefulException:
return "fail"
except Exception as ee:
@@ -2225,29 +2343,155 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont,
connect=conn,
prog_plot=prog_plot)
+ elif paint_method == "laser_lines":
+ # line = None
+ # aperture_size = None
+
+ # the key is the aperture type and the val is a list of geo elements
+ flash_el_dict = dict()
+ # the key is the aperture size, the val is a list of geo elements
+ traces_el_dict = dict()
+
+ # find the flashes and the lines that are in the selected polygon and store
+ # them separately
+ for apid, apval in obj.apertures.items():
+ for geo_el in apval['geometry']:
+ if apval["size"] == 0.0:
+ if apval["size"] in traces_el_dict:
+ traces_el_dict[apval["size"]].append(geo_el)
+ else:
+ traces_el_dict[apval["size"]] = [geo_el]
+
+ if 'follow' in geo_el and geo_el['follow'].within(pol):
+ if isinstance(geo_el['follow'], Point):
+ if apval["type"] == 'C':
+ if 'C' in flash_el_dict:
+ flash_el_dict['C'].append(geo_el)
+ else:
+ flash_el_dict['C'] = [geo_el]
+ elif apval["type"] == 'O':
+ if 'O' in flash_el_dict:
+ flash_el_dict['O'].append(geo_el)
+ else:
+ flash_el_dict['O'] = [geo_el]
+ elif apval["type"] == 'R':
+ if 'R' in flash_el_dict:
+ flash_el_dict['R'].append(geo_el)
+ else:
+ flash_el_dict['R'] = [geo_el]
+ else:
+ aperture_size = apval['size']
+
+ if aperture_size in traces_el_dict:
+ traces_el_dict[aperture_size].append(geo_el)
+ else:
+ traces_el_dict[aperture_size] = [geo_el]
+
+ cp = FlatCAMRTreeStorage()
+ pads_lines_list = list()
+
+ # process the flashes found in the selected polygon with the 'lines' method
+ # for rectangular flashes and with 'seed' for oblong and circular flashes
+ # and pads (flahes) need the contour therefore I override the GUI settings
+ # with always True
+ for ap_type in flash_el_dict:
+ for elem in flash_el_dict[ap_type]:
+ if 'solid' in elem:
+ if ap_type == 'C':
+ f_o = self.clear_polygon2(elem['solid'],
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ elif ap_type == 'O':
+ f_o = self.clear_polygon2(elem['solid'],
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ elif ap_type == 'R':
+ f_o = self.clear_polygon3(elem['solid'],
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ # add the lines from pads to the storage
+ try:
+ for lin in pads_lines_list:
+ if lin:
+ cp.insert(lin)
+ except TypeError:
+ cp.insert(pads_lines_list)
+
+ copper_lines_list = list()
+ # process the traces found in the selected polygon using the 'laser_lines'
+ # method, method which will follow the 'follow' line therefore use the longer
+ # path possible for the laser, therefore the acceleration will play
+ # a smaller factor
+ for aperture_size in traces_el_dict:
+ for elem in traces_el_dict[aperture_size]:
+ line = elem['follow']
+ if line:
+ t_o = self.fill_with_lines(line, aperture_size,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ copper_lines_list += [p for p in t_o.get_objects() if p]
+
+ # add the lines from copper features to storage but first try to make as few
+ # lines as possible
+ # by trying to fuse them
+ lines_union = linemerge(unary_union(copper_lines_list))
+ try:
+ for lin in lines_union:
+ if lin:
+ cp.insert(lin)
+ except TypeError:
+ cp.insert(lines_union)
elif paint_method == "combo":
self.app.inform.emit(_("Painting polygons with method: lines."))
cp = self.clear_polygon3(pol,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
if cp and cp.objects:
pass
else:
self.app.inform.emit(_("Failed. Painting polygons with method: seed."))
cp = self.clear_polygon2(pol,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
if cp and cp.objects:
pass
else:
@@ -2255,13 +2499,13 @@ class ToolPaint(FlatCAMTool, Gerber):
_("Failed. Painting polygons with method: standard."))
cp = self.clear_polygon(pol,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
if cp and cp.objects:
total_geometry += list(cp.get_objects())
poly_processed.append(True)
@@ -2301,16 +2545,142 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont,
connect=conn,
prog_plot=prog_plot)
+ elif paint_method == "laser_lines":
+ # line = None
+ # aperture_size = None
+
+ # the key is the aperture type and the val is a list of geo elements
+ flash_el_dict = dict()
+ # the key is the aperture size, the val is a list of geo elements
+ traces_el_dict = dict()
+
+ # find the flashes and the lines that are in the selected polygon and store
+ # them separately
+ for apid, apval in obj.apertures.items():
+ for geo_el in apval['geometry']:
+ if apval["size"] == 0.0:
+ if apval["size"] in traces_el_dict:
+ traces_el_dict[apval["size"]].append(geo_el)
+ else:
+ traces_el_dict[apval["size"]] = [geo_el]
+
+ if 'follow' in geo_el and geo_el['follow'].within(poly_buf):
+ if isinstance(geo_el['follow'], Point):
+ if apval["type"] == 'C':
+ if 'C' in flash_el_dict:
+ flash_el_dict['C'].append(geo_el)
+ else:
+ flash_el_dict['C'] = [geo_el]
+ elif apval["type"] == 'O':
+ if 'O' in flash_el_dict:
+ flash_el_dict['O'].append(geo_el)
+ else:
+ flash_el_dict['O'] = [geo_el]
+ elif apval["type"] == 'R':
+ if 'R' in flash_el_dict:
+ flash_el_dict['R'].append(geo_el)
+ else:
+ flash_el_dict['R'] = [geo_el]
+ else:
+ aperture_size = apval['size']
+
+ if aperture_size in traces_el_dict:
+ traces_el_dict[aperture_size].append(geo_el)
+ else:
+ traces_el_dict[aperture_size] = [geo_el]
+
+ cp = FlatCAMRTreeStorage()
+ pads_lines_list = list()
+
+ # process the flashes found in the selected polygon with the 'lines' method
+ # for rectangular flashes and with 'seed' for oblong and circular flashes
+ # and pads (flahes) need the contour therefore I override the GUI settings
+ # with always True
+ for ap_type in flash_el_dict:
+ for elem in flash_el_dict[ap_type]:
+ if 'solid' in elem:
+ if ap_type == 'C':
+ f_o = self.clear_polygon2(elem['solid'],
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ elif ap_type == 'O':
+ f_o = self.clear_polygon2(elem['solid'],
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ elif ap_type == 'R':
+ f_o = self.clear_polygon3(elem['solid'],
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ # add the lines from pads to the storage
+ try:
+ for lin in pads_lines_list:
+ if lin:
+ cp.insert(lin)
+ except TypeError:
+ cp.insert(pads_lines_list)
+
+ copper_lines_list = list()
+ # process the traces found in the selected polygon using the 'laser_lines'
+ # method, method which will follow the 'follow' line therefore use the longer
+ # path possible for the laser, therefore the acceleration will play
+ # a smaller factor
+ for aperture_size in traces_el_dict:
+ for elem in traces_el_dict[aperture_size]:
+ line = elem['follow']
+ if line:
+ t_o = self.fill_with_lines(line, aperture_size,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ copper_lines_list += [p for p in t_o.get_objects() if p]
+
+ # add the lines from copper features to storage but first try to make as few
+ # lines as possible
+ # by trying to fuse them
+ lines_union = linemerge(unary_union(copper_lines_list))
+ try:
+ for lin in lines_union:
+ if lin:
+ cp.insert(lin)
+ except TypeError:
+ cp.insert(lines_union)
elif paint_method == "combo":
self.app.inform.emit(_("Painting polygons with method: lines."))
cp = self.clear_polygon3(poly_buf,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
if cp and cp.objects:
pass
@@ -2329,13 +2699,13 @@ class ToolPaint(FlatCAMTool, Gerber):
else:
self.app.inform.emit(_("Failed. Painting polygons with method: standard."))
cp = self.clear_polygon(poly_buf,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
if cp:
total_geometry += list(cp.get_objects())
poly_processed.append(True)
@@ -2553,6 +2923,132 @@ class ToolPaint(FlatCAMTool, Gerber):
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over, contour=cont, connect=conn,
prog_plot=prog_plot)
+ elif paint_method == "laser_lines":
+ # line = None
+ # aperture_size = None
+
+ # the key is the aperture type and the val is a list of geo elements
+ flash_el_dict = dict()
+ # the key is the aperture size, the val is a list of geo elements
+ traces_el_dict = dict()
+
+ # find the flashes and the lines that are in the selected polygon and store
+ # them separately
+ for apid, apval in obj.apertures.items():
+ for geo_el in apval['geometry']:
+ if apval["size"] == 0.0:
+ if apval["size"] in traces_el_dict:
+ traces_el_dict[apval["size"]].append(geo_el)
+ else:
+ traces_el_dict[apval["size"]] = [geo_el]
+
+ if 'follow' in geo_el and geo_el['follow'].within(poly_buf):
+ if isinstance(geo_el['follow'], Point):
+ if apval["type"] == 'C':
+ if 'C' in flash_el_dict:
+ flash_el_dict['C'].append(geo_el)
+ else:
+ flash_el_dict['C'] = [geo_el]
+ elif apval["type"] == 'O':
+ if 'O' in flash_el_dict:
+ flash_el_dict['O'].append(geo_el)
+ else:
+ flash_el_dict['O'] = [geo_el]
+ elif apval["type"] == 'R':
+ if 'R' in flash_el_dict:
+ flash_el_dict['R'].append(geo_el)
+ else:
+ flash_el_dict['R'] = [geo_el]
+ else:
+ aperture_size = apval['size']
+
+ if aperture_size in traces_el_dict:
+ traces_el_dict[aperture_size].append(geo_el)
+ else:
+ traces_el_dict[aperture_size] = [geo_el]
+
+ cp = FlatCAMRTreeStorage()
+ pads_lines_list = list()
+
+ # process the flashes found in the selected polygon with the 'lines' method
+ # for rectangular flashes and with 'seed' for oblong and circular flashes
+ # and pads (flahes) need the contour therefore I override the GUI settings
+ # with always True
+ for ap_type in flash_el_dict:
+ for elem in flash_el_dict[ap_type]:
+ if 'solid' in elem:
+ if ap_type == 'C':
+ f_o = self.clear_polygon2(elem['solid'],
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ elif ap_type == 'O':
+ f_o = self.clear_polygon2(elem['solid'],
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ elif ap_type == 'R':
+ f_o = self.clear_polygon3(elem['solid'],
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ # add the lines from pads to the storage
+ try:
+ for lin in pads_lines_list:
+ if lin:
+ cp.insert(lin)
+ except TypeError:
+ cp.insert(pads_lines_list)
+
+ copper_lines_list = list()
+ # process the traces found in the selected polygon using the 'laser_lines'
+ # method, method which will follow the 'follow' line therefore use the longer
+ # path possible for the laser, therefore the acceleration will play
+ # a smaller factor
+ for aperture_size in traces_el_dict:
+ for elem in traces_el_dict[aperture_size]:
+ line = elem['follow']
+ if line:
+ t_o = self.fill_with_lines(line, aperture_size,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ copper_lines_list += [p for p in t_o.get_objects() if p]
+
+ # add the lines from copper features to storage but first try to make as few
+ # lines as possible
+ # by trying to fuse them
+ lines_union = linemerge(unary_union(copper_lines_list))
+ try:
+ for lin in lines_union:
+ if lin:
+ cp.insert(lin)
+ except TypeError:
+ cp.insert(lines_union)
elif paint_method == "combo":
self.app.inform.emit(_("Painting polygons with method: lines."))
cp = self.clear_polygon3(poly_buf,
@@ -2907,16 +3403,142 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont,
connect=conn,
prog_plot=prog_plot)
+ elif paint_method == "laser_lines":
+ # line = None
+ # aperture_size = None
+
+ # the key is the aperture type and the val is a list of geo elements
+ flash_el_dict = dict()
+ # the key is the aperture size, the val is a list of geo elements
+ traces_el_dict = dict()
+
+ # find the flashes and the lines that are in the selected polygon and store
+ # them separately
+ for apid, apval in obj.apertures.items():
+ for geo_el in apval['geometry']:
+ if apval["size"] == 0.0:
+ if apval["size"] in traces_el_dict:
+ traces_el_dict[apval["size"]].append(geo_el)
+ else:
+ traces_el_dict[apval["size"]] = [geo_el]
+
+ if 'follow' in geo_el and geo_el['follow'].within(poly_buf):
+ if isinstance(geo_el['follow'], Point):
+ if apval["type"] == 'C':
+ if 'C' in flash_el_dict:
+ flash_el_dict['C'].append(geo_el)
+ else:
+ flash_el_dict['C'] = [geo_el]
+ elif apval["type"] == 'O':
+ if 'O' in flash_el_dict:
+ flash_el_dict['O'].append(geo_el)
+ else:
+ flash_el_dict['O'] = [geo_el]
+ elif apval["type"] == 'R':
+ if 'R' in flash_el_dict:
+ flash_el_dict['R'].append(geo_el)
+ else:
+ flash_el_dict['R'] = [geo_el]
+ else:
+ aperture_size = apval['size']
+
+ if aperture_size in traces_el_dict:
+ traces_el_dict[aperture_size].append(geo_el)
+ else:
+ traces_el_dict[aperture_size] = [geo_el]
+
+ cp = FlatCAMRTreeStorage()
+ pads_lines_list = list()
+
+ # process the flashes found in the selected polygon with the 'lines' method
+ # for rectangular flashes and with 'seed' for oblong and circular flashes
+ # and pads (flahes) need the contour therefore I override the GUI settings
+ # with always True
+ for ap_type in flash_el_dict:
+ for elem in flash_el_dict[ap_type]:
+ if 'solid' in elem:
+ if ap_type == 'C':
+ f_o = self.clear_polygon2(elem['solid'],
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ elif ap_type == 'O':
+ f_o = self.clear_polygon2(elem['solid'],
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ elif ap_type == 'R':
+ f_o = self.clear_polygon3(elem['solid'],
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ # add the lines from pads to the storage
+ try:
+ for lin in pads_lines_list:
+ if lin:
+ cp.insert(lin)
+ except TypeError:
+ cp.insert(pads_lines_list)
+
+ copper_lines_list = list()
+ # process the traces found in the selected polygon using the 'laser_lines'
+ # method, method which will follow the 'follow' line therefore use the longer
+ # path possible for the laser, therefore the acceleration will play
+ # a smaller factor
+ for aperture_size in traces_el_dict:
+ for elem in traces_el_dict[aperture_size]:
+ line = elem['follow']
+ if line:
+ t_o = self.fill_with_lines(line, aperture_size,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ copper_lines_list += [p for p in t_o.get_objects() if p]
+
+ # add the lines from copper features to storage but first try to make as few
+ # lines as possible
+ # by trying to fuse them
+ lines_union = linemerge(unary_union(copper_lines_list))
+ try:
+ for lin in lines_union:
+ if lin:
+ cp.insert(lin)
+ except TypeError:
+ cp.insert(lines_union)
elif paint_method == "combo":
self.app.inform.emit(_("Painting polygons with method: lines."))
cp = self.clear_polygon3(poly_buf,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
if cp and cp.objects:
pass
@@ -2935,13 +3557,13 @@ class ToolPaint(FlatCAMTool, Gerber):
else:
self.app.inform.emit(_("Failed. Painting polygons with method: standard."))
cp = self.clear_polygon(poly_buf,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
if cp and cp.objects:
total_geometry += list(cp.get_objects())
except FlatCAMApp.GracefulException:
@@ -3101,16 +3723,141 @@ class ToolPaint(FlatCAMTool, Gerber):
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over, contour=cont, connect=conn,
prog_plot=prog_plot)
+ elif paint_method == "laser_lines":
+ # line = None
+ # aperture_size = None
+
+ # the key is the aperture type and the val is a list of geo elements
+ flash_el_dict = dict()
+ # the key is the aperture size, the val is a list of geo elements
+ copper_el_dict = dict()
+
+ # find the flashes and the lines that are in the selected polygon and store
+ # them separately
+ for apid, apval in obj.apertures.items():
+ for geo_el in apval['geometry']:
+ if apval["size"] == 0.0:
+ if apval["size"] in copper_el_dict:
+ copper_el_dict[apval["size"]].append(geo_el)
+ else:
+ copper_el_dict[apval["size"]] = [geo_el]
+
+ if 'follow' in geo_el and geo_el['follow'].within(poly_buf):
+ if isinstance(geo_el['follow'], Point):
+ if apval["type"] == 'C':
+ if 'C' in flash_el_dict:
+ flash_el_dict['C'].append(geo_el)
+ else:
+ flash_el_dict['C'] = [geo_el]
+ elif apval["type"] == 'O':
+ if 'O' in flash_el_dict:
+ flash_el_dict['O'].append(geo_el)
+ else:
+ flash_el_dict['O'] = [geo_el]
+ elif apval["type"] == 'R':
+ if 'R' in flash_el_dict:
+ flash_el_dict['R'].append(geo_el)
+ else:
+ flash_el_dict['R'] = [geo_el]
+ else:
+ aperture_size = apval['size']
+
+ if aperture_size in copper_el_dict:
+ copper_el_dict[aperture_size].append(geo_el)
+ else:
+ copper_el_dict[aperture_size] = [geo_el]
+
+ cp = FlatCAMRTreeStorage()
+ pads_lines_list = list()
+
+ # process the flashes found in the selected polygon with the 'lines' method
+ # for rectangular flashes and with 'seed' for oblong and circular flashes
+ # and pads (flahes) need the contour therefore I override the GUI settings
+ # with always True
+ for ap_type in flash_el_dict:
+ for elem in flash_el_dict[ap_type]:
+ if 'solid' in elem:
+ if ap_type == 'C':
+ f_o = self.clear_polygon2(elem['solid'],
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ elif ap_type == 'O':
+ f_o = self.clear_polygon2(elem['solid'],
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ elif ap_type == 'R':
+ f_o = self.clear_polygon3(elem['solid'],
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ # add the lines from pads to the storage
+ try:
+ for lin in pads_lines_list:
+ if lin:
+ cp.insert(lin)
+ except TypeError:
+ cp.insert(pads_lines_list)
+
+ copper_lines_list = list()
+ # process the traces found in the selected polygon using the 'laser_lines'
+ # method, method which will follow the 'follow' line therefore use the longer
+ # path possible for the laser, therefore the acceleration will play
+ # a smaller factor
+ for aperture_size in copper_el_dict:
+ for elem in copper_el_dict[aperture_size]:
+ line = elem['follow']
+ if line:
+ t_o = self.fill_with_lines(line, aperture_size,
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ copper_lines_list += [p for p in t_o.get_objects() if p]
+
+ # add the lines from copper features to storage but first try to make as few
+ # lines as possible
+ # by trying to fuse them
+ lines_union = linemerge(unary_union(copper_lines_list))
+ try:
+ for lin in lines_union:
+ if lin:
+ cp.insert(lin)
+ except TypeError:
+ cp.insert(lines_union)
elif paint_method == "combo":
self.app.inform.emit(_("Painting polygons with method: lines."))
cp = self.clear_polygon3(poly_buf,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults["geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
if cp and cp.objects:
pass
@@ -3129,13 +3876,13 @@ class ToolPaint(FlatCAMTool, Gerber):
else:
self.app.inform.emit(_("Failed. Painting polygons with method: standard."))
cp = self.clear_polygon(poly_buf,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
+ tooldia=tool_dia,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
if cp and cp.objects:
cleared_geo += list(cp.get_objects())
except FlatCAMApp.GracefulException:
From 64912949c6a52ee8c7c11ef654206522594f5810 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 16 Feb 2020 03:11:46 +0200
Subject: [PATCH 098/209] - modified the Paint Tool UI
---
FlatCAMApp.py | 2 +-
README.md | 1 +
flatcamGUI/PreferencesUI.py | 26 ++++++----
flatcamTools/ToolPaint.py | 100 ++++++++++++++++--------------------
4 files changed, 64 insertions(+), 65 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 3574dcfa..67fbc5e9 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -799,7 +799,7 @@ class App(QtCore.QObject):
"tools_paintorder": 'rev',
"tools_paintoverlap": 20,
"tools_paintmargin": 0.0,
- "tools_paintmethod": "seed",
+ "tools_paintmethod": _("Seed-based"),
"tools_selectmethod": "all",
"tools_pathconnect": True,
"tools_paintcontour": True,
diff --git a/README.md b/README.md
index bf72391f..ed4827fc 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ CAD program, and create G-Code for Isolation routing.
- in Paint Tool added a new method of painting named Combo who will pass through all the methods until the polygon is cleared
- in Paint Tool attempting to add a new mode suitable for Laser usage
- more work in the new Laser Mode in the Paint Tool
+- modified the Paint Tool UI
14.02.2020
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index df1c0021..305179fd 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -5761,17 +5761,25 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
# Method
methodlabel = QtWidgets.QLabel('%s:' % _('Method'))
methodlabel.setToolTip(
- _("Algorithm for non-copper clearing:
"
- "Standard: Fixed step inwards.
"
- "Seed-based: Outwards from seed.
"
- "Line-based: Parallel lines.")
+ _("Algorithm for painting:\n"
+ "- Standard: Fixed step inwards.\n"
+ "- Seed-based: Outwards from seed.\n"
+ "- Line-based: Parallel lines.\n"
+ "- Laser-lines: Active only for Gerber objects.\n"
+ "Will create lines that follow the traces.\n"
+ "- Combo: In case of failure a new method will be picked from the above\n"
+ "in the order specified.")
)
- self.paintmethod_combo = RadioSet([
- {"label": _("Standard"), "value": "standard"},
- {"label": _("Seed-based"), "value": "seed"},
- {"label": _("Straight lines"), "value": "lines"}
- ], orientation='vertical', stretch=False)
+ # self.paintmethod_combo = RadioSet([
+ # {"label": _("Standard"), "value": "standard"},
+ # {"label": _("Seed-based"), "value": "seed"},
+ # {"label": _("Straight lines"), "value": "lines"}
+ # ], orientation='vertical', stretch=False)
+ self.paintmethod_combo = FCComboBox()
+ self.paintmethod_combo.addItems(
+ [_("Standard"), _("Seed-based"), _("Straight lines"), _("Laser lines"), _("Combo")]
+ )
grid0.addWidget(methodlabel, 11, 0)
grid0.addWidget(self.paintmethod_combo, 11, 1)
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 8774c137..2ae02a41 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -14,7 +14,7 @@ from copy import deepcopy
from flatcamParsers.ParseGerber import Gerber
from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry
from camlib import Geometry, FlatCAMRTreeStorage
-from flatcamGUI.GUIElements import FCTable, FCDoubleSpinner, FCCheckBox, FCInputDialog, RadioSet, FCButton
+from flatcamGUI.GUIElements import FCTable, FCDoubleSpinner, FCCheckBox, FCInputDialog, RadioSet, FCButton, FCComboBox
import FlatCAMApp
from shapely.geometry import base, Polygon, MultiPolygon, LinearRing, Point, MultiLineString
@@ -75,15 +75,6 @@ class ToolPaint(FlatCAMTool, Gerber):
# ################################################
# ##### Type of object to be painted #############
# ################################################
- self.type_obj_combo = QtWidgets.QComboBox()
- self.type_obj_combo.addItem("Gerber")
- self.type_obj_combo.addItem("Excellon")
- self.type_obj_combo.addItem("Geometry")
-
- # we get rid of item1 ("Excellon") as it is not suitable
- self.type_obj_combo.view().setRowHidden(1, True)
- self.type_obj_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
- self.type_obj_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Obj Type"))
self.type_obj_combo_label.setToolTip(
@@ -93,6 +84,10 @@ class ToolPaint(FlatCAMTool, Gerber):
"of objects that will populate the 'Object' combobox.")
)
self.type_obj_combo_label.setMinimumWidth(60)
+
+ self.type_obj_combo = RadioSet([{'label': "Geometry", 'value': 'geometry'},
+ {'label': "Gerber", 'value': 'gerber'}])
+
grid0.addWidget(self.type_obj_combo_label, 1, 0)
grid0.addWidget(self.type_obj_combo, 1, 1)
@@ -371,23 +366,38 @@ class ToolPaint(FlatCAMTool, Gerber):
"- Standard: Fixed step inwards.\n"
"- Seed-based: Outwards from seed.\n"
"- Line-based: Parallel lines.\n"
- "- Laser-lines: Active only when Laser Mode is active and only for Gerber objects.\n"
+ "- Laser-lines: Active only for Gerber objects.\n"
"Will create lines that follow the traces.\n"
"- Combo: In case of failure a new method will be picked from the above\n"
"in the order specified.")
)
- self.paintmethod_combo = RadioSet([
- {"label": _("Standard"), "value": "standard"},
- {"label": _("Seed-based"), "value": "seed"},
- {"label": _("Straight lines"), "value": "lines"},
- {"label": _("Laser lines"), "value": "laser_lines"},
- {"label": _("Combo"), "value": "combo"}
- ], orientation='vertical', stretch=False)
- self.paintmethod_combo.setObjectName(_("Method"))
+ # self.paintmethod_combo = RadioSet([
+ # {"label": _("Standard"), "value": "standard"},
+ # {"label": _("Seed-based"), "value": "seed"},
+ # {"label": _("Straight lines"), "value": "lines"},
+ # {"label": _("Laser lines"), "value": "laser_lines"},
+ # {"label": _("Combo"), "value": "combo"}
+ # ], orientation='vertical', stretch=False)
- for choice in self.paintmethod_combo.choices:
- if choice['value'] == "laser_lines":
- choice["radio"].setEnabled(False)
+ # for choice in self.paintmethod_combo.choices:
+ # if choice['value'] == "laser_lines":
+ # choice["radio"].setEnabled(False)
+
+ self.paintmethod_combo = FCComboBox()
+ self.paintmethod_combo.addItems(
+ [_("Standard"), _("Seed-based"), _("Straight lines"), _("Laser lines"), _("Combo")]
+ )
+ self.p_mth = {
+ _("Standard"): "standard",
+ _("Seed-based"): "seed",
+ _("Straight lines"): "lines",
+ _("Laser lines"): "laser_lines",
+ _("Combo"): "combo"
+ }
+ idx = self.paintmethod_combo.findText(_("Laser lines"))
+ self.paintmethod_combo.model().item(idx).setEnabled(False)
+
+ self.paintmethod_combo.setObjectName(_("Method"))
grid4.addWidget(methodlabel, 7, 0)
grid4.addWidget(self.paintmethod_combo, 7, 1)
@@ -447,15 +457,6 @@ class ToolPaint(FlatCAMTool, Gerber):
)
grid4.addWidget(self.rest_cb, 16, 0, 1, 2)
- # Laser Mode
- self.laser_cb = FCCheckBox(_("Laser Mode"))
- self.laser_cb.setToolTip(
- _("This control is enabled only for Gerber objects.\n"
- "If checked then a new method is shown in Methods,\n"
- "and it is also added to the Combo Method sequence.")
- )
- grid4.addWidget(self.laser_cb, 17, 0, 1, 2)
-
# Polygon selection
selectlabel = QtWidgets.QLabel('%s:' % _('Selection'))
selectlabel.setToolTip(
@@ -635,8 +636,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.rest_cb.stateChanged.connect(self.on_rest_machining_check)
self.box_combo_type.currentIndexChanged.connect(self.on_combo_box_type)
- self.type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
- self.laser_cb.stateChanged.connect(self.on_laser_mode_toggled)
+ self.type_obj_combo.activated_custom.connect(self.on_type_obj_index_changed)
self.reset_button.clicked.connect(self.set_tool_ui)
# #############################################################################
@@ -655,25 +655,18 @@ class ToolPaint(FlatCAMTool, Gerber):
icon=QtGui.QIcon(self.app.resource_location + "/delete32.png")
)
- def on_type_obj_index_changed(self, index):
- obj_type = self.type_obj_combo.currentIndex()
+ def on_type_obj_index_changed(self, val):
+ obj_type = 0 if val == 'gerber' else 2
self.obj_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.obj_combo.setCurrentIndex(0)
- if self.type_obj_combo.currentText().lower() == 'gerber':
- self.laser_cb.setEnabled(True)
+ idx = self.paintmethod_combo.findText(_("Laser lines"))
+ if self.type_obj_combo.get_value().lower() == 'gerber':
+ self.paintmethod_combo.model().item(idx).setEnabled(True)
else:
- self.laser_cb.setEnabled(False)
-
- def on_laser_mode_toggled(self, val):
- for choice in self.paintmethod_combo.choices:
- if choice['value'] == "laser_lines":
- if val:
- choice["radio"].setEnabled(True)
- else:
- choice["radio"].setEnabled(False)
- if self.paintmethod_combo.get_value() == "laser_lines":
- self.paintmethod_combo.set_value('lines')
+ self.paintmethod_combo.model().item(idx).setEnabled(False)
+ if self.paintmethod_combo.get_value() == _("Laser lines"):
+ self.paintmethod_combo.set_value(_("Straight lines"))
def install(self, icon=None, separator=None, **kwargs):
FlatCAMTool.install(self, icon, separator, shortcut='ALT+P', **kwargs)
@@ -1015,10 +1008,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.on_tool_type(val=self.tool_type_radio.get_value())
# make the default object type, "Geometry"
- self.type_obj_combo.setCurrentIndex(2)
-
- # make the Laser Mode disabled because the Geometry object is default
- self.laser_cb.setEnabled(False)
+ self.type_obj_combo.set_value("geometry")
try:
diameters = [float(self.app.defaults["tools_painttooldia"])]
@@ -1727,7 +1717,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.app.inform.emit('[WARNING] %s' % _('No polygon found.'))
return
- paint_method = method if method is not None else self.paintmethod_combo.get_value()
+ paint_method = method if method is not None else self.p_mth[self.paintmethod_combo.get_value()]
paint_margin = float(self.paintmargin_entry.get_value()) if margin is None else margin
# determine if to use the progressive plotting
prog_plot = True if self.app.defaults["tools_paint_plotting"] == 'progressive' else False
@@ -2142,7 +2132,7 @@ class ToolPaint(FlatCAMTool, Gerber):
Usage of the different one is related to when this function is called from a TcL command.
:return:
"""
- paint_method = method if method is not None else self.paintmethod_combo.get_value()
+ paint_method = method if method is not None else self.p_mth[self.paintmethod_combo.get_value()]
if margin is not None:
paint_margin = margin
@@ -3207,7 +3197,7 @@ class ToolPaint(FlatCAMTool, Gerber):
Usage of the different one is related to when this function is called from a TcL command.
:return:
"""
- paint_method = method if method is not None else self.paintmethod_combo.get_value()
+ paint_method = method if method is not None else self.p_mth[self.paintmethod_combo.get_value()]
if margin is not None:
paint_margin = margin
From d1408a3d2c36c2104c19d318dde7503e57f3c8e4 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 16 Feb 2020 16:50:24 +0200
Subject: [PATCH 099/209] - small update to NCC Tool UI
---
README.md | 4 ++++
flatcamTools/ToolNonCopperClear.py | 32 ++++++++++++++++++------------
flatcamTools/ToolPaint.py | 4 ++--
3 files changed, 25 insertions(+), 15 deletions(-)
diff --git a/README.md b/README.md
index ed4827fc..7e948bd3 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+16.02.2020
+
+- small update to NCC Tool UI
+
15.02.2020
- in Paint Tool added a new method of painting named Combo who will pass through all the methods until the polygon is cleared
diff --git a/flatcamTools/ToolNonCopperClear.py b/flatcamTools/ToolNonCopperClear.py
index 7eca4da2..d96ac687 100644
--- a/flatcamTools/ToolNonCopperClear.py
+++ b/flatcamTools/ToolNonCopperClear.py
@@ -8,7 +8,7 @@
from PyQt5 import QtWidgets, QtCore, QtGui
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import FCCheckBox, FCDoubleSpinner, RadioSet, FCTable, FCInputDialog, FCButton
+from flatcamGUI.GUIElements import FCCheckBox, FCDoubleSpinner, RadioSet, FCTable, FCInputDialog, FCButton, FCComboBox
from flatcamParsers.ParseGerber import Gerber
import FlatCAMApp
@@ -70,15 +70,15 @@ class NonCopperClear(FlatCAMTool, Gerber):
# ################################################
# ##### Type of object to be copper cleaned ######
# ################################################
- self.type_obj_combo = QtWidgets.QComboBox()
- self.type_obj_combo.addItem("Gerber")
- self.type_obj_combo.addItem("Excellon")
- self.type_obj_combo.addItem("Geometry")
-
- # we get rid of item1 ("Excellon") as it is not suitable
- self.type_obj_combo.view().setRowHidden(1, True)
- self.type_obj_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
- self.type_obj_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
+ # self.type_obj_combo = QtWidgets.QComboBox()
+ # self.type_obj_combo.addItem("Gerber")
+ # self.type_obj_combo.addItem("Excellon")
+ # self.type_obj_combo.addItem("Geometry")
+ #
+ # # we get rid of item1 ("Excellon") as it is not suitable
+ # self.type_obj_combo.view().setRowHidden(1, True)
+ # self.type_obj_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
+ # self.type_obj_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Obj Type"))
self.type_obj_combo_label.setToolTip(
@@ -88,6 +88,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
"of objects that will populate the 'Object' combobox.")
)
self.type_obj_combo_label.setMinimumWidth(60)
+
+ self.type_obj_combo = RadioSet([{'label': "Geometry", 'value': 'geometry'},
+ {'label': "Gerber", 'value': 'gerber'}])
+
form_layout.addRow(self.type_obj_combo_label, self.type_obj_combo)
# ################################################
@@ -683,11 +687,11 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.ncc_rest_cb.stateChanged.connect(self.on_rest_machining_check)
self.ncc_order_radio.activated_custom[str].connect(self.on_order_changed)
- self.type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
+ self.type_obj_combo.activated_custom.connect(self.on_type_obj_index_changed)
self.reset_button.clicked.connect(self.set_tool_ui)
- def on_type_obj_index_changed(self, index):
- obj_type = self.type_obj_combo.currentIndex()
+ def on_type_obj_index_changed(self, val):
+ obj_type = 0 if val == 'gerber' else 2
self.object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.object_combo.setCurrentIndex(0)
@@ -885,6 +889,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.tools_frame.show()
+ self.type_obj_combo.set_value('gerber')
+
self.ncc_order_radio.set_value(self.app.defaults["tools_nccorder"])
self.ncc_overlap_entry.set_value(self.app.defaults["tools_nccoverlap"])
self.ncc_margin_entry.set_value(self.app.defaults["tools_nccmargin"])
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 2ae02a41..6b64d4f9 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -636,7 +636,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.rest_cb.stateChanged.connect(self.on_rest_machining_check)
self.box_combo_type.currentIndexChanged.connect(self.on_combo_box_type)
- self.type_obj_combo.activated_custom.connect(self.on_type_obj_index_changed)
+ self.type_obj_combo.activated_custom.connect(self.on_type_obj_changed)
self.reset_button.clicked.connect(self.set_tool_ui)
# #############################################################################
@@ -655,7 +655,7 @@ class ToolPaint(FlatCAMTool, Gerber):
icon=QtGui.QIcon(self.app.resource_location + "/delete32.png")
)
- def on_type_obj_index_changed(self, val):
+ def on_type_obj_changed(self, val):
obj_type = 0 if val == 'gerber' else 2
self.obj_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.obj_combo.setCurrentIndex(0)
From 1e9232aeaa6b5de0df113baf4f1e4cd38c29e5e8 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 17 Feb 2020 04:43:01 +0200
Subject: [PATCH 100/209] - updated the Excellon UI to hold data for each tool
- in Excellon UI removed the tools table column for Offset Z and used the UI
form parameter - updated the Excellon Editor to add for each tool a 'data'
dictionary - updated all FlatCAM tools to use the new confirmation message
that show if the entered value is within range or outside
---
FlatCAMApp.py | 22 +-
FlatCAMObj.py | 314 +++++++++++++++++----------
FlatCAMTool.py | 22 ++
README.md | 7 +
camlib.py | 9 +-
flatcamEditors/FlatCAMExcEditor.py | 54 ++++-
flatcamGUI/ObjectUI.py | 180 ++++++++-------
flatcamGUI/PreferencesUI.py | 73 +++++--
flatcamParsers/ParseExcellon.py | 1 +
flatcamTools/ToolCalculators.py | 18 +-
flatcamTools/ToolCalibration.py | 22 +-
flatcamTools/ToolCopperThieving.py | 22 +-
flatcamTools/ToolCutOut.py | 10 +-
flatcamTools/ToolDblSided.py | 10 +-
flatcamTools/ToolExtractDrills.py | 12 +-
flatcamTools/ToolFiducials.py | 6 +-
flatcamTools/ToolFilm.py | 14 +-
flatcamTools/ToolInvertGerber.py | 2 +-
flatcamTools/ToolNonCopperClear.py | 12 +-
flatcamTools/ToolPaint.py | 10 +-
flatcamTools/ToolPanelize.py | 8 +-
flatcamTools/ToolPunchGerber.py | 12 +-
flatcamTools/ToolRulesCheck.py | 20 +-
flatcamTools/ToolSolderPaste.py | 22 +-
flatcamTools/ToolTransform.py | 16 +-
preprocessors/default.py | 7 +
tclCommands/TclCommandDrillcncjob.py | 5 +-
27 files changed, 582 insertions(+), 328 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 67fbc5e9..53dfe415 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -622,7 +622,9 @@ class App(QtCore.QObject):
"excellon_zeros": "L",
"excellon_units": "INCH",
"excellon_update": True,
+
"excellon_optimization_type": 'B',
+
"excellon_search_time": 3,
"excellon_save_filters": "Excellon File (*.txt);;Excellon File (*.drd);;Excellon File (*.drl);;"
"Excellon File (*.exc);;Excellon File (*.ncd);;Excellon File (*.tap);;"
@@ -631,12 +633,17 @@ class App(QtCore.QObject):
"excellon_plot_line": '#750000BF',
# Excellon Options
- "excellon_drillz": -1.7,
+ "excellon_operation": "drill",
+ "excellon_milling_type": "drills",
+
+ "excellon_milling_dia": 0.8,
+
+ "excellon_cutz": -1.7,
"excellon_multidepth": False,
"excellon_depthperpass": 0.7,
"excellon_travelz": 2,
"excellon_endz": 0.5,
- "excellon_feedrate": 300,
+ "excellon_feedrate_z": 300,
"excellon_spindlespeed": 0,
"excellon_dwell": False,
"excellon_dwelltime": 1,
@@ -1308,12 +1315,17 @@ class App(QtCore.QObject):
"excellon_plot_line": self.ui.excellon_defaults_form.excellon_gen_group.line_color_entry,
# Excellon Options
- "excellon_drillz": self.ui.excellon_defaults_form.excellon_opt_group.cutz_entry,
+ "excellon_operation": self.ui.excellon_defaults_form.excellon_opt_group.operation_radio,
+ "excellon_milling_type": self.ui.excellon_defaults_form.excellon_opt_group.milling_type_radio,
+
+ "excellon_milling_dia": self.ui.excellon_defaults_form.excellon_opt_group.mill_dia_entry,
+
+ "excellon_cutz": self.ui.excellon_defaults_form.excellon_opt_group.cutz_entry,
"excellon_multidepth": self.ui.excellon_defaults_form.excellon_opt_group.mpass_cb,
"excellon_depthperpass": self.ui.excellon_defaults_form.excellon_opt_group.maxdepth_entry,
"excellon_travelz": self.ui.excellon_defaults_form.excellon_opt_group.travelz_entry,
"excellon_endz": self.ui.excellon_defaults_form.excellon_opt_group.endz_entry,
- "excellon_feedrate": self.ui.excellon_defaults_form.excellon_opt_group.feedrate_z_entry,
+ "excellon_feedrate_z": self.ui.excellon_defaults_form.excellon_opt_group.feedrate_z_entry,
"excellon_spindlespeed": self.ui.excellon_defaults_form.excellon_opt_group.spindlespeed_entry,
"excellon_dwell": self.ui.excellon_defaults_form.excellon_opt_group.dwell_cb,
"excellon_dwelltime": self.ui.excellon_defaults_form.excellon_opt_group.dwelltime_entry,
@@ -5944,7 +5956,7 @@ class App(QtCore.QObject):
dimensions = ['gerber_isotooldia', 'gerber_noncoppermargin', 'gerber_bboxmargin', "gerber_isooverlap",
"gerber_editor_newsize", "gerber_editor_lin_pitch", "gerber_editor_buff_f",
- 'excellon_drillz', 'excellon_travelz', "excellon_toolchangexy",
+ 'excellon_cutz', 'excellon_travelz', "excellon_toolchangexy", 'excellon_offset',
'excellon_feedrate', 'excellon_feedrate_rapid', 'excellon_toolchangez',
'excellon_tooldia', 'excellon_slot_tooldia', 'excellon_endz', "excellon_feedrate_probe",
"excellon_z_pdepth", "excellon_editor_newdia", "excellon_editor_lin_pitch",
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 159cd1d5..1e0119e5 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -2323,34 +2323,46 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.options.update({
"plot": True,
"solid": False,
- "drillz": -0.1,
+
+ "operation": "drill",
+ "milling_type": "drills",
+
+ "milling_dia": 0.04,
+
+ "cutz": -0.1,
"multidepth": False,
"depthperpass": 0.7,
"travelz": 0.1,
- "feedrate": 5.0,
+ "feedrate": self.app.defaults["geometry_feedrate"],
+ "feedrate_z": 5.0,
"feedrate_rapid": 5.0,
"tooldia": 0.1,
"slot_tooldia": 0.1,
"toolchange": False,
"toolchangez": 1.0,
"toolchangexy": "0.0, 0.0",
+ "extracut": self.app.defaults["geometry_extracut"],
+ "extracut_length":self.app.defaults["geometry_extracut_length"],
"endz": 2.0,
"startz": None,
+ "offset": 0.0,
"spindlespeed": 0,
"dwell": True,
"dwelltime": 1000,
- "ppname_e": 'defaults',
+ "ppname_e": 'default',
+ "ppname_g": self.app.defaults["geometry_ppname_g"],
"z_pdepth": -0.02,
"feedrate_probe": 3.0,
- "optimization_type": "R",
- "gcode_type": "drills"
+ "optimization_type": "B",
})
# TODO: Document this.
self.tool_cbs = dict()
- # dict to hold the tool number as key and tool offset as value
- self.tool_offset = dict()
+ # dict that holds the object names and the option name
+ # the key is the object name (defines in ObjectUI) for each UI element that is a parameter
+ # particular for a tool and the value is the actual name of the option that the UI element is changing
+ self.name2option = dict()
# default set of data to be added to each tool in self.tools as self.tools[tool]['data'] = self.default_data
self.default_data = dict()
@@ -2598,8 +2610,17 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
sorted_tools = sorted(sort, key=lambda t1: t1[1])
tools = [i[0] for i in sorted_tools]
+ new_options = dict()
+ for opt in self.options:
+ new_options[opt] = self.options[opt]
+
for tool_no in tools:
+ # add the data dictionary for each tool with the default values
+ self.tools[tool_no]['data'] = deepcopy(new_options)
+ # self.tools[tool_no]['data']["tooldia"] = self.tools[tool_no]["C"]
+ # self.tools[tool_no]['data']["slot_tooldia"] = self.tools[tool_no]["C"]
+
drill_cnt = 0 # variable to store the nr of drills per tool
slot_cnt = 0 # variable to store the nr of slots per tool
@@ -2631,18 +2652,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
slot_count_item = QtWidgets.QTableWidgetItem(slot_count_str)
slot_count_item.setFlags(QtCore.Qt.ItemIsEnabled)
- try:
- t_offset = self.tool_offset[float('%.*f' % (self.decimals, float(self.tools[tool_no]['C'])))]
- except KeyError:
- t_offset = self.app.defaults['excellon_offset']
-
- tool_offset_item = FCDoubleSpinner()
- tool_offset_item.set_precision(self.decimals)
- tool_offset_item.set_range(-9999.9999, 9999.9999)
- tool_offset_item.setWrapping(True)
- tool_offset_item.setSingleStep(0.1) if self.units == 'MM' else tool_offset_item.setSingleStep(0.01)
- tool_offset_item.set_value(t_offset)
-
plot_item = FCCheckBox()
plot_item.setLayoutDirection(QtCore.Qt.RightToLeft)
if self.ui.plot_cb.isChecked():
@@ -2652,7 +2661,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.ui.tools_table.setItem(self.tool_row, 1, dia_item) # Diameter
self.ui.tools_table.setItem(self.tool_row, 2, drill_count_item) # Number of drills per tool
self.ui.tools_table.setItem(self.tool_row, 3, slot_count_item) # Number of drills per tool
- self.ui.tools_table.setCellWidget(self.tool_row, 4, tool_offset_item) # Tool offset
empty_plot_item = QtWidgets.QTableWidgetItem('')
empty_plot_item.setFlags(~QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
self.ui.tools_table.setItem(self.tool_row, 5, empty_plot_item)
@@ -2679,7 +2687,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.ui.tools_table.setItem(self.tool_row, 1, label_tot_drill_count)
self.ui.tools_table.setItem(self.tool_row, 2, tot_drill_count) # Total number of drills
self.ui.tools_table.setItem(self.tool_row, 3, empty_1_1)
- self.ui.tools_table.setItem(self.tool_row, 4, empty_1_2)
self.ui.tools_table.setItem(self.tool_row, 5, empty_1_3)
font = QtGui.QFont()
@@ -2711,7 +2718,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.ui.tools_table.setItem(self.tool_row, 1, label_tot_slot_count)
self.ui.tools_table.setItem(self.tool_row, 2, empty_2_1)
self.ui.tools_table.setItem(self.tool_row, 3, tot_slot_count) # Total number of slots
- self.ui.tools_table.setItem(self.tool_row, 4, empty_2_2)
self.ui.tools_table.setItem(self.tool_row, 5, empty_2_3)
for kl in [1, 2, 3]:
@@ -2737,13 +2743,11 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
horizontal_header.setDefaultSectionSize(70)
horizontal_header.setSectionResizeMode(0, QtWidgets.QHeaderView.Fixed)
horizontal_header.resizeSection(0, 20)
- if self.app.defaults["global_app_level"] == 'b':
- horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
- else:
- horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
+
+ horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
+
horizontal_header.setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeToContents)
horizontal_header.setSectionResizeMode(3, QtWidgets.QHeaderView.ResizeToContents)
- horizontal_header.setSectionResizeMode(4, QtWidgets.QHeaderView.Stretch)
horizontal_header.setSectionResizeMode(5, QtWidgets.QHeaderView.Fixed)
horizontal_header.resizeSection(5, 17)
self.ui.tools_table.setColumnWidth(5, 17)
@@ -2773,14 +2777,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.ui.slot_tooldia_entry.show()
self.ui.generate_milling_slots_button.show()
- # we reactivate the signals after the after the tool adding as we don't need to see the tool been populated
- for row in range(self.ui.tools_table.rowCount()):
- try:
- offset_spin_widget = self.ui.tools_table.cellWidget(row, 4)
- offset_spin_widget.valueChanged.connect(self.on_tool_offset_edit)
- except (TypeError, AttributeError):
- pass
-
# set the text on tool_data_label after loading the object
sel_rows = list()
sel_items = self.ui.tools_table.selectedItems()
@@ -2811,33 +2807,71 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.form_fields.update({
"plot": self.ui.plot_cb,
"solid": self.ui.solid_cb,
- "drillz": self.ui.cutz_entry,
+
+ "operation": self.ui.operation_radio,
+ "milling_type": self.ui.milling_type_radio,
+
+ "milling_dia": self.ui.mill_dia_entry,
+ "cutz": self.ui.cutz_entry,
"multidepth": self.ui.mpass_cb,
"depthperpass": self.ui.maxdepth_entry,
"travelz": self.ui.travelz_entry,
- "feedrate": self.ui.feedrate_z_entry,
+ "feedrate_z": self.ui.feedrate_z_entry,
+ "feedrate": self.ui.xyfeedrate_entry,
"feedrate_rapid": self.ui.feedrate_rapid_entry,
"tooldia": self.ui.tooldia_entry,
"slot_tooldia": self.ui.slot_tooldia_entry,
"toolchange": self.ui.toolchange_cb,
"toolchangez": self.ui.toolchangez_entry,
+ "extracut": self.ui.extracut_cb,
+ "extracut_length": self.ui.e_cut_entry,
+
"spindlespeed": self.ui.spindlespeed_entry,
"dwell": self.ui.dwell_cb,
"dwelltime": self.ui.dwelltime_entry,
+
"startz": self.ui.estartz_entry,
"endz": self.ui.endz_entry,
+ "offset": self.ui.offset_entry,
+
"ppname_e": self.ui.pp_excellon_name_cb,
+ "ppname_g": self.ui.pp_geo_name_cb,
"z_pdepth": self.ui.pdepth_entry,
"feedrate_probe": self.ui.feedrate_probe_entry,
- "gcode_type": self.ui.excellon_gcode_type_radio
+ # "gcode_type": self.ui.excellon_gcode_type_radio
})
+ self.name2option = {
+ "e_operation": "operation",
+ "e_milling_type": "milling_type",
+ "e_milling_dia": "milling_dia",
+ "e_cutz" : "cutz",
+ "e_multidepth" : "multidepth",
+ "e_depthperpass" : "depthperpass",
+
+ "e_travelz" : "travelz",
+ "e_feedratexy" : "feedrate",
+ "e_feedratez" : "feedrate_z",
+ "e_fr_rapid" : "feedrate_rapid",
+ "e_extracut" : "extracut",
+ "e_extracut_length" : "extracut_length",
+ "e_spindlespeed" : "spindlespeed",
+ "e_dwell" : "dwell",
+ "e_dwelltime" : "dwelltime",
+ "e_offset" : "offset",
+ }
+
+ # populate Excellon preprocessor combobox list
for name in list(self.app.preprocessors.keys()):
# the HPGL preprocessor is only for Geometry not for Excellon job therefore don't add it
if name == 'hpgl':
continue
self.ui.pp_excellon_name_cb.addItem(name)
+ # populate Geometry (milling) preprocessor combobox list
+ for name in list(self.app.preprocessors.keys()):
+ self.ui.pp_geo_name_cb.addItem(name)
+
# Fill form fields
self.to_form()
@@ -2846,13 +2880,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
# self.ui.pp_excellon_name_cb combobox
self.on_pp_changed()
- # initialize the dict that holds the tools offset
- t_default_offset = self.app.defaults["excellon_offset"]
- if not self.tool_offset:
- for value in self.tools.values():
- dia = float('%.*f' % (self.decimals, float(value['C'])))
- self.tool_offset[dia] = t_default_offset
-
# Show/Hide Advanced Options
if self.app.defaults["global_app_level"] == 'b':
self.ui.level.setText('%s' % _('Basic'))
@@ -2895,6 +2922,17 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.ui.tools_table.clicked.connect(self.on_row_selection_change)
self.ui.tools_table.horizontalHeader().sectionClicked.connect(self.on_row_selection_change)
+ # value changed in the particular parameters of a tool
+ for key, option in self.name2option.items():
+ current_widget = self.form_fields[option]
+
+ if isinstance(current_widget, FCCheckBox):
+ current_widget.stateChanged.connect(self.form_to_storage)
+ if isinstance(current_widget, RadioSet):
+ current_widget.activated_custom.connect(self.form_to_storage)
+ elif isinstance(current_widget, FCDoubleSpinner) or isinstance(current_widget, FCSpinner):
+ current_widget.returnPressed.connect(self.form_to_storage)
+
def ui_disconnect(self):
# selective plotting
for row in range(self.ui.tools_table.rowCount()):
@@ -2917,19 +2955,33 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
except (TypeError, AttributeError):
pass
- def on_row_selection_change(self):
- self.update_ui()
+ # value changed in the particular parameters of a tool
+ for key, option in self.name2option.items():
+ current_widget = self.form_fields[option]
- def update_ui(self, row=None):
+ if isinstance(current_widget, FCCheckBox):
+ try:
+ current_widget.stateChanged.disconnect(self.form_to_storage)
+ except (TypeError, ValueError):
+ pass
+ if isinstance(current_widget, RadioSet):
+ try:
+ current_widget.activated_custom.disconnect(self.form_to_storage)
+ except (TypeError, ValueError):
+ pass
+ elif isinstance(current_widget, FCDoubleSpinner) or isinstance(current_widget, FCSpinner):
+ try:
+ current_widget.returnPressed.disconnect(self.form_to_storage)
+ except (TypeError, ValueError):
+ pass
+
+ def on_row_selection_change(self):
self.ui_disconnect()
- if row is None:
- sel_rows = list()
- sel_items = self.ui.tools_table.selectedItems()
- for it in sel_items:
- sel_rows.append(it.row())
- else:
- sel_rows = row if type(row) == list else [row]
+ sel_rows = list()
+ sel_items = self.ui.tools_table.selectedItems()
+ for it in sel_items:
+ sel_rows.append(it.row())
if not sel_rows:
self.ui.tool_data_label.setText(
@@ -2961,7 +3013,8 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
try:
item = self.ui.tools_table.item(c_row, 0)
if type(item) is not None:
- tooluid = int(item.text())
+ tooluid = item.text()
+ self.storage_to_form(self.tools[str(tooluid)]['data'])
else:
self.ui_connect()
return
@@ -2970,23 +3023,49 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.ui_connect()
return
- # try:
- # # set the form with data from the newly selected tool
- # for tooluid_key, tooluid_value in list(self.tools.items()):
- # if int(tooluid_key) == tooluid:
- # for key, value in tooluid_value.items():
- # if key == 'data':
- # form_value_storage = tooluid_value[key]
- # self.update_form(form_value_storage)
- # except Exception as e:
- # log.debug("FlatCAMObj ---> update_ui() " + str(e))
+ self.ui_connect()
+
+ def storage_to_form(self, dict_storage):
+ for form_key in self.form_fields:
+ for storage_key in dict_storage:
+ if form_key == storage_key:
+ try:
+ self.form_fields[form_key].set_value(dict_storage[form_key])
+ except Exception as e:
+ log.debug("FlatCAMExcellon.storage_to_form() --> %s" % str(e))
+ pass
+
+ def form_to_storage(self):
+ if self.ui.tools_table.rowCount() == 0:
+ # there is no tool in tool table so we can't save the GUI elements values to storage
+ return
+
+ self.ui_disconnect()
+
+ widget_changed = self.sender()
+ wdg_objname = widget_changed.objectName()
+ option_changed = self.name2option[wdg_objname]
+
+ row = self.ui.tools_table.currentRow()
+
+ if row < 0:
+ row = 0
+ tooluid_item = int(self.ui.tools_table.item(row, 0).text())
+
+ for tooluid_key, tooluid_val in self.tools.items():
+ if int(tooluid_key) == tooluid_item:
+ new_option_value = self.form_fields[option_changed].get_value()
+ if option_changed in tooluid_val:
+ tooluid_val[option_changed] = new_option_value
+ if option_changed in tooluid_val['data']:
+ tooluid_val['data'][option_changed] = new_option_value
self.ui_connect()
def on_operation_type(self, val):
if val == 'mill':
self.ui.mill_type_label.show()
- self.ui.mill_type_radio.show()
+ self.ui.milling_type_radio.show()
self.ui.mill_dia_label.show()
self.ui.mill_dia_entry.show()
self.ui.frxylabel.show()
@@ -2999,7 +3078,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
# self.ui.maxdepth_entry.show()
else:
self.ui.mill_type_label.hide()
- self.ui.mill_type_radio.hide()
+ self.ui.milling_type_radio.hide()
self.ui.mill_dia_label.hide()
self.ui.mill_dia_entry.hide()
# self.ui.mpass_cb.hide()
@@ -3009,32 +3088,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.ui.extracut_cb.hide()
self.ui.e_cut_entry.hide()
- def on_tool_offset_edit(self):
- # if connected, disconnect the signal from the slot on item_changed as it creates issues
- for row in range(self.ui.tools_table.rowCount()):
- try:
- # if connected, disconnect the signal from the slot on item_changed as it creates issues
- offset_spin_widget = self.ui.tools_table.cellWidget(row, 4)
- offset_spin_widget.valueChanged.disconnect()
- except (TypeError, AttributeError):
- pass
-
- self.units = self.app.defaults['units'].upper()
- self.is_modified = True
-
- row_of_item_changed = self.ui.tools_table.currentRow()
- dia = float('%.*f' % (self.decimals, float(self.ui.tools_table.item(row_of_item_changed, 1).text())))
-
- self.tool_offset[dia] = self.sender().get_value()
-
- # we reactivate the signals after the after the tool editing
- for row in range(self.ui.tools_table.rowCount()):
- try:
- offset_spin_widget = self.ui.tools_table.cellWidget(row, 4)
- offset_spin_widget.valueChanged.connect(self.on_tool_offset_edit)
- except (TypeError, AttributeError):
- pass
-
def get_selected_tools_list(self):
"""
Returns the keys to the self.tools dictionary corresponding
@@ -3590,15 +3643,14 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
job_obj.options['type'] = 'Excellon'
job_obj.options['ppname_e'] = pp_excellon_name
- job_obj.z_cut = float(self.options["drillz"])
+ job_obj.z_cut = float(self.options["cutz"])
job_obj.multidepth = self.options["multidepth"]
job_obj.z_depthpercut = self.options["depthperpass"]
- job_obj.tool_offset = self.tool_offset
job_obj.z_move = float(self.options["travelz"])
- job_obj.feedrate = float(self.options["feedrate"])
- job_obj.z_feedrate = float(self.options["feedrate"])
+ job_obj.feedrate = float(self.options["feedrate_z"])
+ job_obj.z_feedrate = float(self.options["feedrate_z"])
job_obj.feedrate_rapid = float(self.options["feedrate_rapid"])
job_obj.spindlespeed = float(self.options["spindlespeed"]) if self.options["spindlespeed"] != 0 else None
@@ -3627,7 +3679,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
tools_csv = ','.join(tools)
ret_val = job_obj.generate_from_excellon_by_tool(
self, tools_csv,
- drillz=float(self.options['drillz']),
+ drillz=float(self.options['cutz']),
toolchange=self.options["toolchange"],
toolchangexy=self.app.defaults["excellon_toolchangexy"],
toolchangez=float(self.options["toolchangez"]),
@@ -3754,17 +3806,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.ui.plot_cb.setChecked(True)
self.ui_connect()
- # def plot_element(self, element, color='red', visible=None, layer=None):
- #
- # visible = visible if visible else self.options['plot']
- #
- # try:
- # for sub_el in element:
- # self.plot_element(sub_el)
- #
- # except TypeError: # Element is not iterable...
- # self.add_shape(shape=element, color=color, visible=visible, layer=0)
-
def plot(self, visible=None, kind=None):
# Does all the required setup and returns False
@@ -3819,6 +3860,59 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
except (ObjectDeleted, AttributeError):
self.shapes.clear(update=True)
+ def on_apply_param_to_all_clicked(self):
+ if self.tools_table.rowCount() == 0:
+ # there is no tool in tool table so we can't save the GUI elements values to storage
+ log.debug("NonCopperClear.on_apply_param_to_all_clicked() --> no tool in Tools Table, aborting.")
+ return
+
+ self.blockSignals(True)
+
+ row = self.tools_table.currentRow()
+ if row < 0:
+ row = 0
+
+ # store all the data associated with the row parameter to the self.tools storage
+ tooldia_item = float(self.tools_table.item(row, 1).text())
+ type_item = self.tools_table.cellWidget(row, 2).currentText()
+ operation_type_item = self.ui.geo_tools_table.cellWidget(row, 4).currentText()
+
+ nccoffset_item = self.ncc_choice_offset_cb.get_value()
+ nccoffset_value_item = float(self.ncc_offset_spinner.get_value())
+
+ # this new dict will hold the actual useful data, another dict that is the value of key 'data'
+ temp_tools = {}
+ temp_dia = {}
+ temp_data = {}
+
+ for tooluid_key, tooluid_value in self.ncc_tools.items():
+ for key, value in tooluid_value.items():
+ if key == 'data':
+ # update the 'data' section
+ for data_key in tooluid_value[key].keys():
+ for form_key, form_value in self.form_fields.items():
+ if form_key == data_key:
+ temp_data[data_key] = form_value.get_value()
+ # make sure we make a copy of the keys not in the form (we may use 'data' keys that are
+ # updated from self.app.defaults
+ if data_key not in self.form_fields:
+ temp_data[data_key] = value[data_key]
+ temp_dia[key] = deepcopy(temp_data)
+ temp_data.clear()
+
+ elif key == 'solid_geometry':
+ temp_dia[key] = deepcopy(self.tools[tooluid_key]['solid_geometry'])
+ else:
+ temp_dia[key] = deepcopy(value)
+
+ temp_tools[tooluid_key] = deepcopy(temp_dia)
+
+ self.ncc_tools.clear()
+ self.ncc_tools = deepcopy(temp_tools)
+ temp_tools.clear()
+
+ self.blockSignals(False)
+
class FlatCAMGeometry(FlatCAMObj, Geometry):
"""
diff --git a/FlatCAMTool.py b/FlatCAMTool.py
index 6c51ecb9..02bd08bd 100644
--- a/FlatCAMTool.py
+++ b/FlatCAMTool.py
@@ -11,6 +11,14 @@ from PyQt5.QtCore import Qt
from shapely.geometry import Polygon
+import gettext
+import FlatCAMTranslation as fcTranslate
+import builtins
+
+fcTranslate.apply_language('strings')
+if '_' not in builtins.__dict__:
+ _ = gettext.gettext
+
class FlatCAMTool(QtWidgets.QWidget):
@@ -138,3 +146,17 @@ class FlatCAMTool(QtWidgets.QWidget):
def delete_tool_selection_shape(self):
self.app.tool_shapes.clear()
self.app.tool_shapes.redraw()
+
+ def confirmation_message(self, accepted, minval, maxval):
+ if accepted is False:
+ self.app.inform.emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' %
+ (_("Edited value is out of range"), self.decimals, minval, self.decimals, maxval))
+ else:
+ self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
+
+ def confirmation_message_int(self, accepted, minval, maxval):
+ if accepted is False:
+ self.app.inform.emit('[WARNING_NOTCL] %s: [%d, %d]' %
+ (_("Edited value is out of range"), minval, maxval))
+ else:
+ self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
diff --git a/README.md b/README.md
index 7e948bd3..501d28a0 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,13 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+17.02.2020
+
+- updated the Excellon UI to hold data for each tool
+- in Excellon UI removed the tools table column for Offset Z and used the UI form parameter
+- updated the Excellon Editor to add for each tool a 'data' dictionary
+- updated all FlatCAM tools to use the new confirmation message that show if the entered value is within range or outside
+
16.02.2020
- small update to NCC Tool UI
diff --git a/camlib.py b/camlib.py
index 52bd863c..f296b113 100644
--- a/camlib.py
+++ b/camlib.py
@@ -2432,7 +2432,6 @@ class CNCjob(Geometry):
self.units = units
self.z_cut = z_cut
- self.tool_offset = dict()
self.z_move = z_move
@@ -2728,7 +2727,7 @@ class CNCjob(Geometry):
)
try:
- z_off = float(self.tool_offset[it[1]]) * (-1)
+ z_off = float(exobj.tools[it[0]]['data']['offset']) * (-1)
except KeyError:
z_off = 0
@@ -2936,7 +2935,7 @@ class CNCjob(Geometry):
# TODO apply offset only when using the GUI, for TclCommand this will create an error
# because the values for Z offset are created in build_ui()
try:
- z_offset = float(self.tool_offset[current_tooldia]) * (-1)
+ z_offset = float(exobj.tools[tool]['data']['offset']) * (-1)
except KeyError:
z_offset = 0
self.z_cut = z_offset + old_zcut
@@ -3104,7 +3103,7 @@ class CNCjob(Geometry):
# TODO apply offset only when using the GUI, for TclCommand this will create an error
# because the values for Z offset are created in build_ui()
try:
- z_offset = float(self.tool_offset[current_tooldia]) * (-1)
+ z_offset = float(exobj.tools[tool]['data']['offset']) * (-1)
except KeyError:
z_offset = 0
self.z_cut = z_offset + old_zcut
@@ -3230,7 +3229,7 @@ class CNCjob(Geometry):
# TODO apply offset only when using the GUI, for TclCommand this will create an error
# because the values for Z offset are created in build_ui()
try:
- z_offset = float(self.tool_offset[current_tooldia]) * (-1)
+ z_offset = float(exobj.tools[tool]['data']['offset']) * (-1)
except KeyError:
z_offset = 0
self.z_cut = z_offset + old_zcut
diff --git a/flatcamEditors/FlatCAMExcEditor.py b/flatcamEditors/FlatCAMExcEditor.py
index a4136d3c..5897b9cb 100644
--- a/flatcamEditors/FlatCAMExcEditor.py
+++ b/flatcamEditors/FlatCAMExcEditor.py
@@ -2074,7 +2074,6 @@ class FlatCAMExcEditor(QtCore.QObject):
self.new_drills = list()
self.new_tools = dict()
self.new_slots = list()
- self.new_tool_offset = dict()
# dictionary to store the tool_row and diameters in Tool_table
# it will be updated everytime self.build_ui() is called
@@ -2186,6 +2185,42 @@ class FlatCAMExcEditor(QtCore.QObject):
if option in self.app.options:
self.options[option] = self.app.options[option]
+ self.data_defaults = {
+ "plot": self.app.defaults["excellon_plot"],
+ "solid": self.app.defaults["excellon_solid"],
+
+ "operation": self.app.defaults["excellon_operation"],
+ "milling_type": self.app.defaults["excellon_milling_type"],
+
+ "milling_dia":self.app.defaults["excellon_milling_dia"],
+
+ "cutz": self.app.defaults["excellon_cutz"],
+ "multidepth": self.app.defaults["excellon_multidepth"],
+ "depthperpass": self.app.defaults["excellon_depthperpass"],
+ "travelz": self.app.defaults["excellon_travelz"],
+ "feedrate": self.app.defaults["geometry_feedrate"],
+ "feedrate_z": self.app.defaults["excellon_feedrate_z"],
+ "feedrate_rapid": self.app.defaults["excellon_feedrate_rapid"],
+ "tooldia": self.app.defaults["excellon_tooldia"],
+ "slot_tooldia": self.app.defaults["excellon_slot_tooldia"],
+ "toolchange": self.app.defaults["excellon_toolchange"],
+ "toolchangez": self.app.defaults["excellon_toolchangez"],
+ "toolchangexy": self.app.defaults["excellon_toolchangexy"],
+ "extracut": self.app.defaults["geometry_extracut"],
+ "extracut_length": self.app.defaults["geometry_extracut_length"],
+ "endz": self.app.defaults["excellon_endz"],
+ "startz": self.app.defaults["excellon_startz"],
+ "offset": self.app.defaults["excellon_offset"],
+ "spindlespeed": self.app.defaults["excellon_spindlespeed"],
+ "dwell": self.app.defaults["excellon_dwell"],
+ "dwelltime": self.app.defaults["excellon_dwelltime"],
+ "ppname_e": self.app.defaults["excellon_ppname_e"],
+ "ppname_g": self.app.defaults["geometry_ppname_g"],
+ "z_pdepth": self.app.defaults["excellon_z_pdepth"],
+ "feedrate_probe": self.app.defaults["excellon_feedrate_probe"],
+ "optimization_type": self.app.defaults["excellon_optimization_type"]
+ }
+
self.rtree_exc_index = rtindex.Index()
# flag to show if the object was modified
self.is_modified = False
@@ -2592,9 +2627,6 @@ class FlatCAMExcEditor(QtCore.QObject):
for deleted_tool_dia in deleted_tool_dia_list:
- # delete de tool offset
- self.exc_obj.tool_offset.pop(float(deleted_tool_dia), None)
-
# delete the storage used for that tool
storage_elem = FlatCAMGeoEditor.make_storage()
self.storage_dict[deleted_tool_dia] = storage_elem
@@ -2795,7 +2827,7 @@ class FlatCAMExcEditor(QtCore.QObject):
self.new_drills = []
self.new_tools = {}
self.new_slots = []
- self.new_tool_offset = {}
+
self.olddia_newdia = {}
self.shapes.enabled = True
@@ -3036,8 +3068,8 @@ class FlatCAMExcEditor(QtCore.QObject):
self.exc_obj = exc_obj
exc_obj.visible = False
- self.points_edit = {}
- self.slot_points_edit = {}
+ self.points_edit = dict()
+ self.slot_points_edit = dict()
# Set selection tolerance
# DrawToolShape.tolerance = fc_excellon.drawing_tolerance * 10
@@ -3268,7 +3300,6 @@ class FlatCAMExcEditor(QtCore.QObject):
self.edited_obj_name += "_1"
else:
self.edited_obj_name += "_edit"
- self.new_tool_offset = self.exc_obj.tool_offset
self.app.worker_task.emit({'fcn': self.new_edited_excellon,
'params': [self.edited_obj_name,
@@ -3316,9 +3347,14 @@ class FlatCAMExcEditor(QtCore.QObject):
excellon_obj.drills = deepcopy(new_drills)
excellon_obj.tools = deepcopy(new_tools)
excellon_obj.slots = deepcopy(new_slots)
- excellon_obj.tool_offset = self.new_tool_offset
+
excellon_obj.options['name'] = outname
+ # add a 'data' dict for each tool with the default values
+ for tool in excellon_obj.tools:
+ excellon_obj.tools[tool]['data'] = dict()
+ excellon_obj.tools[tool]['data'].update(deepcopy(self.data_defaults))
+
try:
excellon_obj.create_geometry()
except KeyError:
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index 5a2f62c2..ab30498d 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -779,7 +779,7 @@ class ExcellonObjectUI(ObjectUI):
self.tools_table.setColumnCount(6)
self.tools_table.setHorizontalHeaderLabels(['#', _('Diameter'), _('Drills'), _('Slots'),
- _('Offset Z'), 'P'])
+ "NOT USED", 'P'])
self.tools_table.setSortingEnabled(False)
self.tools_table.horizontalHeaderItem(0).setToolTip(
@@ -796,14 +796,13 @@ class ExcellonObjectUI(ObjectUI):
self.tools_table.horizontalHeaderItem(3).setToolTip(
_("The number of Slot holes. Holes that are created by\n"
"milling them with an endmill bit."))
- self.tools_table.horizontalHeaderItem(4).setToolTip(
- _("Some drill bits (the larger ones) need to drill deeper\n"
- "to create the desired exit hole diameter due of the tip shape.\n"
- "The value here can compensate the Cut Z parameter."))
self.tools_table.horizontalHeaderItem(5).setToolTip(
_("Toggle display of the drills for the current tool.\n"
"This does not select the tools for G-code generation."))
+ # this column is not used; reserved for future usage
+ self.tools_table.setColumnHidden(4, True)
+
self.tools_box.addWidget(QtWidgets.QLabel(''))
# ###########################################################
@@ -855,6 +854,7 @@ class ExcellonObjectUI(ObjectUI):
{'label': _("Milling"), 'value': 'mill'}
]
)
+ self.operation_radio.setObjectName("e_operation")
self.grid3.addWidget(self.operation_label, 0, 0)
self.grid3.addWidget(self.operation_radio, 0, 1)
@@ -871,16 +871,17 @@ class ExcellonObjectUI(ObjectUI):
"- Slots -> will mill the slots associated with this tool\n"
"- Both -> will mill both drills and mills or whatever is available")
)
- self.mill_type_radio = RadioSet(
+ self.milling_type_radio = RadioSet(
[
{'label': _('Drills'), 'value': 'drills'},
{'label': _("Slots"), 'value': 'slots'},
{'label': _("Both"), 'value': 'both'},
]
)
+ self.milling_type_radio.setObjectName("e_milling_type")
self.grid3.addWidget(self.mill_type_label, 2, 0)
- self.grid3.addWidget(self.mill_type_radio, 2, 1)
+ self.grid3.addWidget(self.milling_type_radio, 2, 1)
self.mill_dia_label = QtWidgets.QLabel('%s:' % _('Milling Diameter'))
self.mill_dia_label.setToolTip(
@@ -890,6 +891,7 @@ class ExcellonObjectUI(ObjectUI):
self.mill_dia_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.mill_dia_entry.set_precision(self.decimals)
self.mill_dia_entry.set_range(0.0000, 9999.9999)
+ self.mill_dia_entry.setObjectName("e_milling_dia")
self.grid3.addWidget(self.mill_dia_label, 3, 0)
self.grid3.addWidget(self.mill_dia_entry, 3, 1)
@@ -910,6 +912,7 @@ class ExcellonObjectUI(ObjectUI):
self.cutz_entry.set_range(-9999.9999, 9999.9999)
self.cutz_entry.setSingleStep(0.1)
+ self.cutz_entry.setObjectName("e_cutz")
self.grid3.addWidget(self.cutzlabel, 4, 0)
self.grid3.addWidget(self.cutz_entry, 4, 1)
@@ -924,6 +927,7 @@ class ExcellonObjectUI(ObjectUI):
"reached."
)
)
+ self.mpass_cb.setObjectName("e_multidepth")
self.maxdepth_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.maxdepth_entry.set_precision(self.decimals)
@@ -931,6 +935,8 @@ class ExcellonObjectUI(ObjectUI):
self.maxdepth_entry.setSingleStep(0.1)
self.maxdepth_entry.setToolTip(_("Depth of each pass (positive)."))
+ self.maxdepth_entry.setObjectName("e_depthperpass")
+
self.mis_mpass_geo = OptionalInputSection(self.mpass_cb, [self.maxdepth_entry])
self.grid3.addWidget(self.mpass_cb, 5, 0)
@@ -952,6 +958,7 @@ class ExcellonObjectUI(ObjectUI):
self.travelz_entry.set_range(-9999.9999, 9999.9999)
self.travelz_entry.setSingleStep(0.1)
+ self.travelz_entry.setObjectName("e_travelz")
self.grid3.addWidget(self.travelzlabel, 6, 0)
self.grid3.addWidget(self.travelz_entry, 6, 1)
@@ -966,6 +973,7 @@ class ExcellonObjectUI(ObjectUI):
self.xyfeedrate_entry.set_precision(self.decimals)
self.xyfeedrate_entry.set_range(0, 9999.9999)
self.xyfeedrate_entry.setSingleStep(0.1)
+ self.xyfeedrate_entry.setObjectName("e_feedratexy")
self.grid3.addWidget(self.frxylabel, 12, 0)
self.grid3.addWidget(self.xyfeedrate_entry, 12, 1)
@@ -982,6 +990,7 @@ class ExcellonObjectUI(ObjectUI):
self.feedrate_z_entry.set_precision(self.decimals)
self.feedrate_z_entry.set_range(0.0, 99999.9999)
self.feedrate_z_entry.setSingleStep(0.1)
+ self.feedrate_z_entry.setObjectName("e_feedratez")
self.grid3.addWidget(self.frzlabel, 14, 0)
self.grid3.addWidget(self.feedrate_z_entry, 14, 1)
@@ -999,6 +1008,7 @@ class ExcellonObjectUI(ObjectUI):
self.feedrate_rapid_entry.set_precision(self.decimals)
self.feedrate_rapid_entry.set_range(0.0, 99999.9999)
self.feedrate_rapid_entry.setSingleStep(0.1)
+ self.feedrate_rapid_entry.setObjectName("e_fr_rapid")
self.grid3.addWidget(self.feedrate_rapid_label, 16, 0)
self.grid3.addWidget(self.feedrate_rapid_entry, 16, 1)
@@ -1015,6 +1025,7 @@ class ExcellonObjectUI(ObjectUI):
"meet with last cut, we generate an\n"
"extended cut over the first cut section.")
)
+ self.extracut_cb.setObjectName("e_extracut")
self.e_cut_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.e_cut_entry.set_range(0, 99999)
@@ -1027,6 +1038,7 @@ class ExcellonObjectUI(ObjectUI):
"meet with last cut, we generate an\n"
"extended cut over the first cut section.")
)
+ self.e_cut_entry.setObjectName("e_extracut_length")
self.ois_recut = OptionalInputSection(self.extracut_cb, [self.e_cut_entry])
@@ -1043,6 +1055,7 @@ class ExcellonObjectUI(ObjectUI):
self.spindlespeed_entry = FCSpinner(callback=self.confirmation_message_int)
self.spindlespeed_entry.set_range(0, 1000000)
self.spindlespeed_entry.setSingleStep(100)
+ self.spindlespeed_entry.setObjectName("e_spindlespeed")
self.grid3.addWidget(self.spindle_label, 19, 0)
self.grid3.addWidget(self.spindlespeed_entry, 19, 1)
@@ -1053,6 +1066,8 @@ class ExcellonObjectUI(ObjectUI):
_("Pause to allow the spindle to reach its\n"
"speed before cutting.")
)
+ self.dwell_cb.setObjectName("e_dwell")
+
self.dwelltime_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.dwelltime_entry.set_precision(self.decimals)
self.dwelltime_entry.set_range(0.0, 9999.9999)
@@ -1061,47 +1076,13 @@ class ExcellonObjectUI(ObjectUI):
self.dwelltime_entry.setToolTip(
_("Number of time units for spindle to dwell.")
)
+ self.dwelltime_entry.setObjectName("e_dwelltime")
self.grid3.addWidget(self.dwell_cb, 20, 0)
self.grid3.addWidget(self.dwelltime_entry, 20, 1)
self.ois_dwell = OptionalInputSection(self.dwell_cb, [self.dwelltime_entry])
- # Probe depth
- self.pdepth_label = QtWidgets.QLabel('%s:' % _("Probe Z depth"))
- self.pdepth_label.setToolTip(
- _("The maximum depth that the probe is allowed\n"
- "to probe. Negative value, in current units.")
- )
-
- self.pdepth_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.pdepth_entry.set_precision(self.decimals)
- self.pdepth_entry.set_range(-9999.9999, 9999.9999)
- self.pdepth_entry.setSingleStep(0.1)
-
- self.grid3.addWidget(self.pdepth_label, 22, 0)
- self.grid3.addWidget(self.pdepth_entry, 22, 1)
-
- self.pdepth_label.hide()
- self.pdepth_entry.setVisible(False)
-
- # Probe feedrate
- self.feedrate_probe_label = QtWidgets.QLabel('%s:' % _("Feedrate Probe"))
- self.feedrate_probe_label.setToolTip(
- _("The feedrate used while the probe is probing.")
- )
-
- self.feedrate_probe_entry = FCDoubleSpinner(callback=self.confirmation_message)
- self.feedrate_probe_entry.set_precision(self.decimals)
- self.feedrate_probe_entry.set_range(0.0, 9999.9999)
- self.feedrate_probe_entry.setSingleStep(0.1)
-
- self.grid3.addWidget(self.feedrate_probe_label, 24, 0)
- self.grid3.addWidget(self.feedrate_probe_entry, 24, 1)
-
- self.feedrate_probe_label.hide()
- self.feedrate_probe_entry.setVisible(False)
-
# Tool Offset
self.tool_offset_label = QtWidgets.QLabel('%s:' % _('Offset Z'))
self.tool_offset_label.setToolTip(
@@ -1113,6 +1094,7 @@ class ExcellonObjectUI(ObjectUI):
self.offset_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.offset_entry.set_precision(self.decimals)
self.offset_entry.set_range(-9999.9999, 9999.9999)
+ self.offset_entry.setObjectName("e_offset")
self.grid3.addWidget(self.tool_offset_label, 25, 0)
self.grid3.addWidget(self.offset_entry, 25, 1)
@@ -1121,37 +1103,38 @@ class ExcellonObjectUI(ObjectUI):
# ################# GRID LAYOUT 4 ###############################
# #################################################################
- self.grid4 = QtWidgets.QGridLayout()
- self.exc_tools_box.addLayout(self.grid4)
- self.grid4.setColumnStretch(0, 0)
- self.grid4.setColumnStretch(1, 1)
-
- # choose_tools_label = QtWidgets.QLabel(
- # _("Select from the Tools Table above the hole dias to be\n"
- # "drilled. Use the # column to make the selection.")
+ # self.grid4 = QtWidgets.QGridLayout()
+ # self.exc_tools_box.addLayout(self.grid4)
+ # self.grid4.setColumnStretch(0, 0)
+ # self.grid4.setColumnStretch(1, 1)
+ #
+ # # choose_tools_label = QtWidgets.QLabel(
+ # # _("Select from the Tools Table above the hole dias to be\n"
+ # # "drilled. Use the # column to make the selection.")
+ # # )
+ # # grid2.addWidget(choose_tools_label, 0, 0, 1, 3)
+ #
+ # # ### Choose what to use for Gcode creation: Drills, Slots or Both
+ # gcode_type_label = QtWidgets.QLabel('%s' % _('Gcode'))
+ # gcode_type_label.setToolTip(
+ # _("Choose what to use for GCode generation:\n"
+ # "'Drills', 'Slots' or 'Both'.\n"
+ # "When choosing 'Slots' or 'Both', slots will be\n"
+ # "converted to a series of drills.")
# )
- # grid2.addWidget(choose_tools_label, 0, 0, 1, 3)
-
- # ### Choose what to use for Gcode creation: Drills, Slots or Both
- gcode_type_label = QtWidgets.QLabel('%s' % _('Gcode'))
- gcode_type_label.setToolTip(
- _("Choose what to use for GCode generation:\n"
- "'Drills', 'Slots' or 'Both'.\n"
- "When choosing 'Slots' or 'Both', slots will be\n"
- "converted to a series of drills.")
- )
- self.excellon_gcode_type_radio = RadioSet([{'label': 'Drills', 'value': 'drills'},
- {'label': 'Slots', 'value': 'slots'},
- {'label': 'Both', 'value': 'both'}])
- self.grid4.addWidget(gcode_type_label, 1, 0)
- self.grid4.addWidget(self.excellon_gcode_type_radio, 1, 1)
- # temporary action until I finish the feature
- self.excellon_gcode_type_radio.setVisible(False)
- gcode_type_label.hide()
+ # self.excellon_gcode_type_radio = RadioSet([{'label': 'Drills', 'value': 'drills'},
+ # {'label': 'Slots', 'value': 'slots'},
+ # {'label': 'Both', 'value': 'both'}])
+ # self.grid4.addWidget(gcode_type_label, 1, 0)
+ # self.grid4.addWidget(self.excellon_gcode_type_radio, 1, 1)
+ # # temporary action until I finish the feature
+ # self.excellon_gcode_type_radio.setVisible(False)
+ # gcode_type_label.hide()
# #################################################################
# ################# GRID LAYOUT 5 ###############################
# #################################################################
+ # ################# COMMON PARAMETERS #############################
self.grid5 = QtWidgets.QGridLayout()
self.grid5.setColumnStretch(0, 0)
@@ -1236,21 +1219,70 @@ class ExcellonObjectUI(ObjectUI):
self.grid5.addWidget(self.endz_label, 11, 0)
self.grid5.addWidget(self.endz_entry, 11, 1)
- # Preprocessor selection
- pp_excellon_label = QtWidgets.QLabel('%s:' % _("Preprocessor"))
+ # Probe depth
+ self.pdepth_label = QtWidgets.QLabel('%s:' % _("Probe Z depth"))
+ self.pdepth_label.setToolTip(
+ _("The maximum depth that the probe is allowed\n"
+ "to probe. Negative value, in current units.")
+ )
+
+ self.pdepth_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.pdepth_entry.set_precision(self.decimals)
+ self.pdepth_entry.set_range(-9999.9999, 9999.9999)
+ self.pdepth_entry.setSingleStep(0.1)
+
+ self.grid5.addWidget(self.pdepth_label, 12, 0)
+ self.grid5.addWidget(self.pdepth_entry, 12, 1)
+
+ self.pdepth_label.hide()
+ self.pdepth_entry.setVisible(False)
+
+ # Probe feedrate
+ self.feedrate_probe_label = QtWidgets.QLabel('%s:' % _("Feedrate Probe"))
+ self.feedrate_probe_label.setToolTip(
+ _("The feedrate used while the probe is probing.")
+ )
+
+ self.feedrate_probe_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.feedrate_probe_entry.set_precision(self.decimals)
+ self.feedrate_probe_entry.set_range(0.0, 9999.9999)
+ self.feedrate_probe_entry.setSingleStep(0.1)
+ self.feedrate_probe_entry.setObjectName(_("e_fr_probe"))
+
+ self.grid5.addWidget(self.feedrate_probe_label, 13, 0)
+ self.grid5.addWidget(self.feedrate_probe_entry, 13, 1)
+
+ self.feedrate_probe_label.hide()
+ self.feedrate_probe_entry.setVisible(False)
+
+ # Preprocessor Excellon selection
+ pp_excellon_label = QtWidgets.QLabel('%s:' % _("Preprocessor E"))
pp_excellon_label.setToolTip(
_("The preprocessor JSON file that dictates\n"
- "Gcode output.")
+ "Gcode output for Excellon Objects.")
)
self.pp_excellon_name_cb = FCComboBox()
self.pp_excellon_name_cb.setFocusPolicy(QtCore.Qt.StrongFocus)
- self.grid5.addWidget(pp_excellon_label, 12, 0)
- self.grid5.addWidget(self.pp_excellon_name_cb, 12, 1)
+
+ self.grid5.addWidget(pp_excellon_label, 14, 0)
+ self.grid5.addWidget(self.pp_excellon_name_cb, 14, 1)
+
+ # Preprocessor Geometry selection
+ pp_geo_label = QtWidgets.QLabel('%s:' % _("Preprocessor G"))
+ pp_geo_label.setToolTip(
+ _("The preprocessor JSON file that dictates\n"
+ "Gcode output for Geometry (Milling) Objects.")
+ )
+ self.pp_geo_name_cb = FCComboBox()
+ self.pp_geo_name_cb.setFocusPolicy(QtCore.Qt.StrongFocus)
+
+ self.grid5.addWidget(pp_geo_label, 15, 0)
+ self.grid5.addWidget(self.pp_geo_name_cb, 15, 1)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.grid5.addWidget(separator_line, 13, 0, 1, 2)
+ self.grid5.addWidget(separator_line, 16, 0, 1, 2)
# #################################################################
# ################# GRID LAYOUT 6 ###############################
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index 305179fd..e3fd5fff 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -3079,6 +3079,53 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
grid2.setColumnStretch(0, 0)
grid2.setColumnStretch(1, 1)
+ # Operation Type
+ self.operation_label = QtWidgets.QLabel('%s:' % _('Operation'))
+ self.operation_label.setToolTip(
+ _("Operation type:\n"
+ "- Drilling -> will drill the drills/slots associated with this tool\n"
+ "- Milling -> will mill the drills/slots")
+ )
+ self.operation_radio = RadioSet(
+ [
+ {'label': _('Drilling'), 'value': 'drill'},
+ {'label': _("Milling"), 'value': 'mill'}
+ ]
+ )
+
+ grid2.addWidget(self.operation_label, 0, 0)
+ grid2.addWidget(self.operation_radio, 0, 1)
+
+ self.mill_type_label = QtWidgets.QLabel('%s:' % _('Milling Type'))
+ self.mill_type_label.setToolTip(
+ _("Milling type:\n"
+ "- Drills -> will mill the drills associated with this tool\n"
+ "- Slots -> will mill the slots associated with this tool\n"
+ "- Both -> will mill both drills and mills or whatever is available")
+ )
+ self.milling_type_radio = RadioSet(
+ [
+ {'label': _('Drills'), 'value': 'drills'},
+ {'label': _("Slots"), 'value': 'slots'},
+ {'label': _("Both"), 'value': 'both'},
+ ]
+ )
+
+ grid2.addWidget(self.mill_type_label, 1, 0)
+ grid2.addWidget(self.milling_type_radio, 1, 1)
+
+ self.mill_dia_label = QtWidgets.QLabel('%s:' % _('Milling Diameter'))
+ self.mill_dia_label.setToolTip(
+ _("The diameter of the tool who will do the milling")
+ )
+
+ self.mill_dia_entry = FCDoubleSpinner()
+ self.mill_dia_entry.set_precision(self.decimals)
+ self.mill_dia_entry.set_range(0.0000, 9999.9999)
+
+ grid2.addWidget(self.mill_dia_label, 2, 0)
+ grid2.addWidget(self.mill_dia_entry, 2, 1)
+
# Cut Z
cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
cutzlabel.setToolTip(
@@ -3096,8 +3143,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
self.cutz_entry.setSingleStep(0.1)
self.cutz_entry.set_precision(self.decimals)
- grid2.addWidget(cutzlabel, 0, 0)
- grid2.addWidget(self.cutz_entry, 0, 1)
+ grid2.addWidget(cutzlabel, 3, 0)
+ grid2.addWidget(self.cutz_entry, 3, 1)
# Multi-Depth
self.mpass_cb = FCCheckBox('%s:' % _("Multi-Depth"))
@@ -3117,8 +3164,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
self.maxdepth_entry.setToolTip(_("Depth of each pass (positive)."))
- grid2.addWidget(self.mpass_cb, 1, 0)
- grid2.addWidget(self.maxdepth_entry, 1, 1)
+ grid2.addWidget(self.mpass_cb, 4, 0)
+ grid2.addWidget(self.maxdepth_entry, 4, 1)
# Travel Z
travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z'))
@@ -3135,8 +3182,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
else:
self.travelz_entry.set_range(-9999.9999, 9999.9999)
- grid2.addWidget(travelzlabel, 2, 0)
- grid2.addWidget(self.travelz_entry, 2, 1)
+ grid2.addWidget(travelzlabel, 5, 0)
+ grid2.addWidget(self.travelz_entry, 5, 1)
# Tool change:
self.toolchange_cb = FCCheckBox('%s' % _("Tool change"))
@@ -3144,7 +3191,7 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
_("Include tool-change sequence\n"
"in G-Code (Pause for tool change).")
)
- grid2.addWidget(self.toolchange_cb, 3, 0, 1, 2)
+ grid2.addWidget(self.toolchange_cb, 6, 0, 1, 2)
# Tool Change Z
toolchangezlabel = QtWidgets.QLabel('%s:' % _('Toolchange Z'))
@@ -3161,8 +3208,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
else:
self.toolchangez_entry.set_range(-9999.9999, 9999.9999)
- grid2.addWidget(toolchangezlabel, 4, 0)
- grid2.addWidget(self.toolchangez_entry, 4, 1)
+ grid2.addWidget(toolchangezlabel, 7, 0)
+ grid2.addWidget(self.toolchangez_entry, 7, 1)
# End Move Z
endz_label = QtWidgets.QLabel('%s:' % _('End move Z'))
@@ -3178,8 +3225,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
else:
self.endz_entry.set_range(-9999.9999, 9999.9999)
- grid2.addWidget(endz_label, 5, 0)
- grid2.addWidget(self.endz_entry, 5, 1)
+ grid2.addWidget(endz_label, 8, 0)
+ grid2.addWidget(self.endz_entry, 8, 1)
# Feedrate Z
frlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z'))
@@ -3193,8 +3240,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
self.feedrate_z_entry.set_precision(self.decimals)
self.feedrate_z_entry.set_range(0, 99999.9999)
- grid2.addWidget(frlabel, 6, 0)
- grid2.addWidget(self.feedrate_z_entry, 6, 1)
+ grid2.addWidget(frlabel, 9, 0)
+ grid2.addWidget(self.feedrate_z_entry, 9, 1)
# Spindle speed
spdlabel = QtWidgets.QLabel('%s:' % _('Spindle Speed'))
diff --git a/flatcamParsers/ParseExcellon.py b/flatcamParsers/ParseExcellon.py
index a82cf401..059e09f3 100644
--- a/flatcamParsers/ParseExcellon.py
+++ b/flatcamParsers/ParseExcellon.py
@@ -43,6 +43,7 @@ class Excellon(Geometry):
================ ====================================
C Diameter of the tool
solid_geometry Geometry list for each tool
+ data dictionary which holds the options for each tool
Others Not supported (Ignored).
================ ====================================
diff --git a/flatcamTools/ToolCalculators.py b/flatcamTools/ToolCalculators.py
index 3a7ff665..a5b0afca 100644
--- a/flatcamTools/ToolCalculators.py
+++ b/flatcamTools/ToolCalculators.py
@@ -92,7 +92,7 @@ class ToolCalculator(FlatCAMTool):
self.layout.addLayout(form_layout)
self.tipDia_label = QtWidgets.QLabel('%s:' % _("Tip Diameter"))
- self.tipDia_entry = FCDoubleSpinner()
+ self.tipDia_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.tipDia_entry.set_precision(self.decimals)
self.tipDia_entry.set_range(0.0, 9999.9999)
self.tipDia_entry.setSingleStep(0.1)
@@ -112,7 +112,7 @@ class ToolCalculator(FlatCAMTool):
"It is specified by manufacturer."))
self.cutDepth_label = QtWidgets.QLabel('%s:' % _("Cut Z"))
- self.cutDepth_entry = FCDoubleSpinner()
+ self.cutDepth_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.cutDepth_entry.set_range(-9999.9999, 9999.9999)
self.cutDepth_entry.set_precision(self.decimals)
@@ -121,7 +121,7 @@ class ToolCalculator(FlatCAMTool):
"In the CNCJob is the CutZ parameter."))
self.effectiveToolDia_label = QtWidgets.QLabel('%s:' % _("Tool Diameter"))
- self.effectiveToolDia_entry = FCDoubleSpinner()
+ self.effectiveToolDia_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.effectiveToolDia_entry.set_precision(self.decimals)
# self.effectiveToolDia_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
@@ -165,7 +165,7 @@ class ToolCalculator(FlatCAMTool):
self.layout.addLayout(plate_form_layout)
self.pcblengthlabel = QtWidgets.QLabel('%s:' % _("Board Length"))
- self.pcblength_entry = FCDoubleSpinner()
+ self.pcblength_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.pcblength_entry.set_precision(self.decimals)
self.pcblength_entry.set_range(0.0, 9999.9999)
@@ -173,7 +173,7 @@ class ToolCalculator(FlatCAMTool):
self.pcblengthlabel.setToolTip(_('This is the board length. In centimeters.'))
self.pcbwidthlabel = QtWidgets.QLabel('%s:' % _("Board Width"))
- self.pcbwidth_entry = FCDoubleSpinner()
+ self.pcbwidth_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.pcbwidth_entry.set_precision(self.decimals)
self.pcbwidth_entry.set_range(0.0, 9999.9999)
@@ -181,7 +181,7 @@ class ToolCalculator(FlatCAMTool):
self.pcbwidthlabel.setToolTip(_('This is the board width.In centimeters.'))
self.cdensity_label = QtWidgets.QLabel('%s:' % _("Current Density"))
- self.cdensity_entry = FCDoubleSpinner()
+ self.cdensity_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.cdensity_entry.set_precision(self.decimals)
self.cdensity_entry.set_range(0.0, 9999.9999)
self.cdensity_entry.setSingleStep(0.1)
@@ -191,7 +191,7 @@ class ToolCalculator(FlatCAMTool):
"In Amps per Square Feet ASF."))
self.growth_label = QtWidgets.QLabel('%s:' % _("Copper Growth"))
- self.growth_entry = FCDoubleSpinner()
+ self.growth_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.growth_entry.set_precision(self.decimals)
self.growth_entry.set_range(0.0, 9999.9999)
self.growth_entry.setSingleStep(0.01)
@@ -203,7 +203,7 @@ class ToolCalculator(FlatCAMTool):
# self.growth_entry.setEnabled(False)
self.cvaluelabel = QtWidgets.QLabel('%s:' % _("Current Value"))
- self.cvalue_entry = FCDoubleSpinner()
+ self.cvalue_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.cvalue_entry.set_precision(self.decimals)
self.cvalue_entry.set_range(0.0, 9999.9999)
self.cvalue_entry.setSingleStep(0.1)
@@ -214,7 +214,7 @@ class ToolCalculator(FlatCAMTool):
self.cvalue_entry.setReadOnly(True)
self.timelabel = QtWidgets.QLabel('%s:' % _("Time"))
- self.time_entry = FCDoubleSpinner()
+ self.time_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.time_entry.set_precision(self.decimals)
self.time_entry.set_range(0.0, 9999.9999)
self.time_entry.setSingleStep(0.1)
diff --git a/flatcamTools/ToolCalibration.py b/flatcamTools/ToolCalibration.py
index fa533f9e..cc964b1a 100644
--- a/flatcamTools/ToolCalibration.py
+++ b/flatcamTools/ToolCalibration.py
@@ -76,7 +76,7 @@ class ToolCalibration(FlatCAMTool):
_("Height (Z) for travelling between the points.")
)
- self.travelz_entry = FCDoubleSpinner()
+ self.travelz_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.travelz_entry.set_range(-9999.9999, 9999.9999)
self.travelz_entry.set_precision(self.decimals)
self.travelz_entry.setSingleStep(0.1)
@@ -90,7 +90,7 @@ class ToolCalibration(FlatCAMTool):
_("Height (Z) for checking the point.")
)
- self.verz_entry = FCDoubleSpinner()
+ self.verz_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.verz_entry.set_range(-9999.9999, 9999.9999)
self.verz_entry.set_precision(self.decimals)
self.verz_entry.setSingleStep(0.1)
@@ -113,7 +113,7 @@ class ToolCalibration(FlatCAMTool):
_("Height (Z) for mounting the verification probe.")
)
- self.toolchangez_entry = FCDoubleSpinner()
+ self.toolchangez_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.toolchangez_entry.set_range(0.0000, 9999.9999)
self.toolchangez_entry.set_precision(self.decimals)
self.toolchangez_entry.setSingleStep(0.1)
@@ -471,7 +471,7 @@ class ToolCalibration(FlatCAMTool):
self.scalex_label.setToolTip(
_("Factor for Scale action over X axis.")
)
- self.scalex_entry = FCDoubleSpinner()
+ self.scalex_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.scalex_entry.set_range(0, 9999.9999)
self.scalex_entry.set_precision(self.decimals)
self.scalex_entry.setSingleStep(0.1)
@@ -483,7 +483,7 @@ class ToolCalibration(FlatCAMTool):
self.scaley_label.setToolTip(
_("Factor for Scale action over Y axis.")
)
- self.scaley_entry = FCDoubleSpinner()
+ self.scaley_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.scaley_entry.set_range(0, 9999.9999)
self.scaley_entry.set_precision(self.decimals)
self.scaley_entry.setSingleStep(0.1)
@@ -508,7 +508,7 @@ class ToolCalibration(FlatCAMTool):
_("Angle for Skew action, in degrees.\n"
"Float number between -360 and 359.")
)
- self.skewx_entry = FCDoubleSpinner()
+ self.skewx_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.skewx_entry.set_range(-360, 360)
self.skewx_entry.set_precision(self.decimals)
self.skewx_entry.setSingleStep(0.1)
@@ -521,7 +521,7 @@ class ToolCalibration(FlatCAMTool):
_("Angle for Skew action, in degrees.\n"
"Float number between -360 and 359.")
)
- self.skewy_entry = FCDoubleSpinner()
+ self.skewy_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.skewy_entry.set_range(-360, 360)
self.skewy_entry.set_precision(self.decimals)
self.skewy_entry.setSingleStep(0.1)
@@ -552,7 +552,7 @@ class ToolCalibration(FlatCAMTool):
# self.fin_scalex_label.setToolTip(
# _("Final factor for Scale action over X axis.")
# )
- # self.fin_scalex_entry = FCDoubleSpinner()
+ # self.fin_scalex_entry = FCDoubleSpinner(callback=self.confirmation_message)
# self.fin_scalex_entry.set_range(0, 9999.9999)
# self.fin_scalex_entry.set_precision(self.decimals)
# self.fin_scalex_entry.setSingleStep(0.1)
@@ -564,7 +564,7 @@ class ToolCalibration(FlatCAMTool):
# self.fin_scaley_label.setToolTip(
# _("Final factor for Scale action over Y axis.")
# )
- # self.fin_scaley_entry = FCDoubleSpinner()
+ # self.fin_scaley_entry = FCDoubleSpinner(callback=self.confirmation_message)
# self.fin_scaley_entry.set_range(0, 9999.9999)
# self.fin_scaley_entry.set_precision(self.decimals)
# self.fin_scaley_entry.setSingleStep(0.1)
@@ -577,7 +577,7 @@ class ToolCalibration(FlatCAMTool):
# _("Final value for angle for Skew action, in degrees.\n"
# "Float number between -360 and 359.")
# )
- # self.fin_skewx_entry = FCDoubleSpinner()
+ # self.fin_skewx_entry = FCDoubleSpinner(callback=self.confirmation_message)
# self.fin_skewx_entry.set_range(-360, 360)
# self.fin_skewx_entry.set_precision(self.decimals)
# self.fin_skewx_entry.setSingleStep(0.1)
@@ -590,7 +590,7 @@ class ToolCalibration(FlatCAMTool):
# _("Final value for angle for Skew action, in degrees.\n"
# "Float number between -360 and 359.")
# )
- # self.fin_skewy_entry = FCDoubleSpinner()
+ # self.fin_skewy_entry = FCDoubleSpinner(callback=self.confirmation_message)
# self.fin_skewy_entry.set_range(-360, 360)
# self.fin_skewy_entry.set_precision(self.decimals)
# self.fin_skewy_entry.setSingleStep(0.1)
diff --git a/flatcamTools/ToolCopperThieving.py b/flatcamTools/ToolCopperThieving.py
index 38c5ccf7..aa9ab7f1 100644
--- a/flatcamTools/ToolCopperThieving.py
+++ b/flatcamTools/ToolCopperThieving.py
@@ -99,7 +99,7 @@ class ToolCopperThieving(FlatCAMTool):
"(the polygon fill may be split in multiple polygons)\n"
"and the copper traces in the Gerber file.")
)
- self.clearance_entry = FCDoubleSpinner()
+ self.clearance_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.clearance_entry.set_range(0.00001, 9999.9999)
self.clearance_entry.set_precision(self.decimals)
self.clearance_entry.setSingleStep(0.1)
@@ -112,7 +112,7 @@ class ToolCopperThieving(FlatCAMTool):
self.margin_label.setToolTip(
_("Bounding box margin.")
)
- self.margin_entry = FCDoubleSpinner()
+ self.margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.margin_entry.set_range(0.0, 9999.9999)
self.margin_entry.set_precision(self.decimals)
self.margin_entry.setSingleStep(0.1)
@@ -221,7 +221,7 @@ class ToolCopperThieving(FlatCAMTool):
self.dotdia_label.setToolTip(
_("Dot diameter in Dots Grid.")
)
- self.dot_dia_entry = FCDoubleSpinner()
+ self.dot_dia_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.dot_dia_entry.set_range(0.0, 9999.9999)
self.dot_dia_entry.set_precision(self.decimals)
self.dot_dia_entry.setSingleStep(0.1)
@@ -234,7 +234,7 @@ class ToolCopperThieving(FlatCAMTool):
self.dotspacing_label.setToolTip(
_("Distance between each two dots in Dots Grid.")
)
- self.dot_spacing_entry = FCDoubleSpinner()
+ self.dot_spacing_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.dot_spacing_entry.set_range(0.0, 9999.9999)
self.dot_spacing_entry.set_precision(self.decimals)
self.dot_spacing_entry.setSingleStep(0.1)
@@ -261,7 +261,7 @@ class ToolCopperThieving(FlatCAMTool):
self.square_size_label.setToolTip(
_("Square side size in Squares Grid.")
)
- self.square_size_entry = FCDoubleSpinner()
+ self.square_size_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.square_size_entry.set_range(0.0, 9999.9999)
self.square_size_entry.set_precision(self.decimals)
self.square_size_entry.setSingleStep(0.1)
@@ -274,7 +274,7 @@ class ToolCopperThieving(FlatCAMTool):
self.squares_spacing_label.setToolTip(
_("Distance between each two squares in Squares Grid.")
)
- self.squares_spacing_entry = FCDoubleSpinner()
+ self.squares_spacing_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.squares_spacing_entry.set_range(0.0, 9999.9999)
self.squares_spacing_entry.set_precision(self.decimals)
self.squares_spacing_entry.setSingleStep(0.1)
@@ -301,7 +301,7 @@ class ToolCopperThieving(FlatCAMTool):
self.line_size_label.setToolTip(
_("Line thickness size in Lines Grid.")
)
- self.line_size_entry = FCDoubleSpinner()
+ self.line_size_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.line_size_entry.set_range(0.0, 9999.9999)
self.line_size_entry.set_precision(self.decimals)
self.line_size_entry.setSingleStep(0.1)
@@ -314,7 +314,7 @@ class ToolCopperThieving(FlatCAMTool):
self.lines_spacing_label.setToolTip(
_("Distance between each two lines in Lines Grid.")
)
- self.lines_spacing_entry = FCDoubleSpinner()
+ self.lines_spacing_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.lines_spacing_entry.set_range(0.0, 9999.9999)
self.lines_spacing_entry.set_precision(self.decimals)
self.lines_spacing_entry.setSingleStep(0.1)
@@ -362,7 +362,7 @@ class ToolCopperThieving(FlatCAMTool):
self.rb_margin_label.setToolTip(
_("Bounding box margin for robber bar.")
)
- self.rb_margin_entry = FCDoubleSpinner()
+ self.rb_margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.rb_margin_entry.set_range(-9999.9999, 9999.9999)
self.rb_margin_entry.set_precision(self.decimals)
self.rb_margin_entry.setSingleStep(0.1)
@@ -375,7 +375,7 @@ class ToolCopperThieving(FlatCAMTool):
self.rb_thickness_label.setToolTip(
_("The robber bar thickness.")
)
- self.rb_thickness_entry = FCDoubleSpinner()
+ self.rb_thickness_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.rb_thickness_entry.set_range(0.0000, 9999.9999)
self.rb_thickness_entry.set_precision(self.decimals)
self.rb_thickness_entry.setSingleStep(0.1)
@@ -431,7 +431,7 @@ class ToolCopperThieving(FlatCAMTool):
_("The distance between the possible copper thieving elements\n"
"and/or robber bar and the actual openings in the mask.")
)
- self.clearance_ppm_entry = FCDoubleSpinner()
+ self.clearance_ppm_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.clearance_ppm_entry.set_range(-9999.9999, 9999.9999)
self.clearance_ppm_entry.set_precision(self.decimals)
self.clearance_ppm_entry.setSingleStep(0.1)
diff --git a/flatcamTools/ToolCutOut.py b/flatcamTools/ToolCutOut.py
index 2e0d7924..32e799b1 100644
--- a/flatcamTools/ToolCutOut.py
+++ b/flatcamTools/ToolCutOut.py
@@ -123,7 +123,7 @@ class CutOut(FlatCAMTool):
grid0.addWidget(self.param_label, 6, 0, 1, 2)
# Tool Diameter
- self.dia = FCDoubleSpinner()
+ self.dia = FCDoubleSpinner(callback=self.confirmation_message)
self.dia.set_precision(self.decimals)
self.dia.set_range(0.0000, 9999.9999)
@@ -143,7 +143,7 @@ class CutOut(FlatCAMTool):
"below the copper surface."
)
)
- self.cutz_entry = FCDoubleSpinner()
+ self.cutz_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.cutz_entry.set_precision(self.decimals)
if machinist_setting == 0:
@@ -167,7 +167,7 @@ class CutOut(FlatCAMTool):
)
)
- self.maxdepth_entry = FCDoubleSpinner()
+ self.maxdepth_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.maxdepth_entry.set_precision(self.decimals)
self.maxdepth_entry.setRange(0, 9999.9999)
self.maxdepth_entry.setSingleStep(0.1)
@@ -183,7 +183,7 @@ class CutOut(FlatCAMTool):
grid0.addWidget(self.maxdepth_entry, 10, 1)
# Margin
- self.margin = FCDoubleSpinner()
+ self.margin = FCDoubleSpinner(callback=self.confirmation_message)
self.margin.set_range(-9999.9999, 9999.9999)
self.margin.setSingleStep(0.1)
self.margin.set_precision(self.decimals)
@@ -198,7 +198,7 @@ class CutOut(FlatCAMTool):
grid0.addWidget(self.margin, 11, 1)
# Gapsize
- self.gapsize = FCDoubleSpinner()
+ self.gapsize = FCDoubleSpinner(callback=self.confirmation_message)
self.gapsize.set_precision(self.decimals)
self.gapsize_label = QtWidgets.QLabel('%s:' % _("Gap size"))
diff --git a/flatcamTools/ToolDblSided.py b/flatcamTools/ToolDblSided.py
index dc1bbd9f..b7c975d9 100644
--- a/flatcamTools/ToolDblSided.py
+++ b/flatcamTools/ToolDblSided.py
@@ -254,7 +254,7 @@ class DblSidedTool(FlatCAMTool):
grid_lay2.addWidget(self.bv_label, 6, 0, 1, 2)
# Xmin value
- self.xmin_entry = FCDoubleSpinner()
+ self.xmin_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.xmin_entry.set_precision(self.decimals)
self.xmin_entry.set_range(-9999.9999, 9999.9999)
@@ -268,7 +268,7 @@ class DblSidedTool(FlatCAMTool):
grid_lay2.addWidget(self.xmin_entry, 7, 1)
# Ymin value
- self.ymin_entry = FCDoubleSpinner()
+ self.ymin_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.ymin_entry.set_precision(self.decimals)
self.ymin_entry.set_range(-9999.9999, 9999.9999)
@@ -282,7 +282,7 @@ class DblSidedTool(FlatCAMTool):
grid_lay2.addWidget(self.ymin_entry, 8, 1)
# Xmax value
- self.xmax_entry = FCDoubleSpinner()
+ self.xmax_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.xmax_entry.set_precision(self.decimals)
self.xmax_entry.set_range(-9999.9999, 9999.9999)
@@ -296,7 +296,7 @@ class DblSidedTool(FlatCAMTool):
grid_lay2.addWidget(self.xmax_entry, 9, 1)
# Ymax value
- self.ymax_entry = FCDoubleSpinner()
+ self.ymax_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.ymax_entry.set_precision(self.decimals)
self.ymax_entry.set_range(-9999.9999, 9999.9999)
@@ -359,7 +359,7 @@ class DblSidedTool(FlatCAMTool):
_("Diameter of the drill for the alignment holes.")
)
- self.drill_dia = FCDoubleSpinner()
+ self.drill_dia = FCDoubleSpinner(callback=self.confirmation_message)
self.drill_dia.setToolTip(
_("Diameter of the drill for the alignment holes.")
)
diff --git a/flatcamTools/ToolExtractDrills.py b/flatcamTools/ToolExtractDrills.py
index bc772e42..05c1e2d0 100644
--- a/flatcamTools/ToolExtractDrills.py
+++ b/flatcamTools/ToolExtractDrills.py
@@ -156,7 +156,7 @@ class ToolExtractDrills(FlatCAMTool):
grid1.addWidget(self.fixed_label, 6, 0, 1, 2)
# Diameter value
- self.dia_entry = FCDoubleSpinner()
+ self.dia_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.dia_entry.set_precision(self.decimals)
self.dia_entry.set_range(0.0000, 9999.9999)
@@ -202,7 +202,7 @@ class ToolExtractDrills(FlatCAMTool):
_("The size of annular ring for circular pads.")
)
- self.circular_ring_entry = FCDoubleSpinner()
+ self.circular_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.circular_ring_entry.set_precision(self.decimals)
self.circular_ring_entry.set_range(0.0000, 9999.9999)
@@ -215,7 +215,7 @@ class ToolExtractDrills(FlatCAMTool):
_("The size of annular ring for oblong pads.")
)
- self.oblong_ring_entry = FCDoubleSpinner()
+ self.oblong_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.oblong_ring_entry.set_precision(self.decimals)
self.oblong_ring_entry.set_range(0.0000, 9999.9999)
@@ -228,7 +228,7 @@ class ToolExtractDrills(FlatCAMTool):
_("The size of annular ring for square pads.")
)
- self.square_ring_entry = FCDoubleSpinner()
+ self.square_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.square_ring_entry.set_precision(self.decimals)
self.square_ring_entry.set_range(0.0000, 9999.9999)
@@ -241,7 +241,7 @@ class ToolExtractDrills(FlatCAMTool):
_("The size of annular ring for rectangular pads.")
)
- self.rectangular_ring_entry = FCDoubleSpinner()
+ self.rectangular_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.rectangular_ring_entry.set_precision(self.decimals)
self.rectangular_ring_entry.set_range(0.0000, 9999.9999)
@@ -254,7 +254,7 @@ class ToolExtractDrills(FlatCAMTool):
_("The size of annular ring for other pads.")
)
- self.other_ring_entry = FCDoubleSpinner()
+ self.other_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.other_ring_entry.set_precision(self.decimals)
self.other_ring_entry.set_range(0.0000, 9999.9999)
diff --git a/flatcamTools/ToolFiducials.py b/flatcamTools/ToolFiducials.py
index 6b4d1d85..33113dac 100644
--- a/flatcamTools/ToolFiducials.py
+++ b/flatcamTools/ToolFiducials.py
@@ -159,7 +159,7 @@ class ToolFiducials(FlatCAMTool):
"otherwise is the size of the fiducial.\n"
"The soldermask opening is double than that.")
)
- self.fid_size_entry = FCDoubleSpinner()
+ self.fid_size_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.fid_size_entry.set_range(1.0000, 3.0000)
self.fid_size_entry.set_precision(self.decimals)
self.fid_size_entry.setWrapping(True)
@@ -173,7 +173,7 @@ class ToolFiducials(FlatCAMTool):
self.margin_label.setToolTip(
_("Bounding box margin.")
)
- self.margin_entry = FCDoubleSpinner()
+ self.margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.margin_entry.set_range(-9999.9999, 9999.9999)
self.margin_entry.set_precision(self.decimals)
self.margin_entry.setSingleStep(0.1)
@@ -236,7 +236,7 @@ class ToolFiducials(FlatCAMTool):
self.line_thickness_label.setToolTip(
_("Bounding box margin.")
)
- self.line_thickness_entry = FCDoubleSpinner()
+ self.line_thickness_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.line_thickness_entry.set_range(0.00001, 9999.9999)
self.line_thickness_entry.set_precision(self.decimals)
self.line_thickness_entry.setSingleStep(0.1)
diff --git a/flatcamTools/ToolFilm.py b/flatcamTools/ToolFilm.py
index a3542e29..4772d0ad 100644
--- a/flatcamTools/ToolFilm.py
+++ b/flatcamTools/ToolFilm.py
@@ -160,7 +160,7 @@ class Film(FlatCAMTool):
grid0.addWidget(self.film_scale_cb, 6, 0, 1, 2)
self.film_scalex_label = QtWidgets.QLabel('%s:' % _("X factor"))
- self.film_scalex_entry = FCDoubleSpinner()
+ self.film_scalex_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.film_scalex_entry.set_range(-999.9999, 999.9999)
self.film_scalex_entry.set_precision(self.decimals)
self.film_scalex_entry.setSingleStep(0.01)
@@ -169,7 +169,7 @@ class Film(FlatCAMTool):
grid0.addWidget(self.film_scalex_entry, 7, 1)
self.film_scaley_label = QtWidgets.QLabel('%s:' % _("Y factor"))
- self.film_scaley_entry = FCDoubleSpinner()
+ self.film_scaley_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.film_scaley_entry.set_range(-999.9999, 999.9999)
self.film_scaley_entry.set_precision(self.decimals)
self.film_scaley_entry.setSingleStep(0.01)
@@ -199,7 +199,7 @@ class Film(FlatCAMTool):
grid0.addWidget(self.film_skew_cb, 10, 0, 1, 2)
self.film_skewx_label = QtWidgets.QLabel('%s:' % _("X angle"))
- self.film_skewx_entry = FCDoubleSpinner()
+ self.film_skewx_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.film_skewx_entry.set_range(-999.9999, 999.9999)
self.film_skewx_entry.set_precision(self.decimals)
self.film_skewx_entry.setSingleStep(0.01)
@@ -208,7 +208,7 @@ class Film(FlatCAMTool):
grid0.addWidget(self.film_skewx_entry, 11, 1)
self.film_skewy_label = QtWidgets.QLabel('%s:' % _("Y angle"))
- self.film_skewy_entry = FCDoubleSpinner()
+ self.film_skewy_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.film_skewy_entry.set_range(-999.9999, 999.9999)
self.film_skewy_entry.set_precision(self.decimals)
self.film_skewy_entry.setSingleStep(0.01)
@@ -275,7 +275,7 @@ class Film(FlatCAMTool):
grid0.addWidget(self.film_param_label, 18, 0, 1, 2)
# Scale Stroke size
- self.film_scale_stroke_entry = FCDoubleSpinner()
+ self.film_scale_stroke_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.film_scale_stroke_entry.set_range(-999.9999, 999.9999)
self.film_scale_stroke_entry.setSingleStep(0.01)
self.film_scale_stroke_entry.set_precision(self.decimals)
@@ -308,7 +308,7 @@ class Film(FlatCAMTool):
grid0.addWidget(self.film_type, 21, 1)
# Boundary for negative film generation
- self.boundary_entry = FCDoubleSpinner()
+ self.boundary_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.boundary_entry.set_range(-999.9999, 999.9999)
self.boundary_entry.setSingleStep(0.01)
self.boundary_entry.set_precision(self.decimals)
@@ -378,7 +378,7 @@ class Film(FlatCAMTool):
self.punch_size_label = QtWidgets.QLabel('%s:' % _("Punch Size"))
self.punch_size_label.setToolTip(_("The value here will control how big is the punch hole in the pads."))
- self.punch_size_spinner = FCDoubleSpinner()
+ self.punch_size_spinner = FCDoubleSpinner(callback=self.confirmation_message)
self.punch_size_spinner.set_range(0, 999.9999)
self.punch_size_spinner.setSingleStep(0.1)
self.punch_size_spinner.set_precision(self.decimals)
diff --git a/flatcamTools/ToolInvertGerber.py b/flatcamTools/ToolInvertGerber.py
index df1af676..c4338b79 100644
--- a/flatcamTools/ToolInvertGerber.py
+++ b/flatcamTools/ToolInvertGerber.py
@@ -89,7 +89,7 @@ class ToolInvertGerber(FlatCAMTool):
_("Distance by which to avoid\n"
"the edges of the Gerber object.")
)
- self.margin_entry = FCDoubleSpinner()
+ self.margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.margin_entry.set_precision(self.decimals)
self.margin_entry.set_range(0.0000, 9999.9999)
self.margin_entry.setObjectName(_("Margin"))
diff --git a/flatcamTools/ToolNonCopperClear.py b/flatcamTools/ToolNonCopperClear.py
index d96ac687..6a03bdf6 100644
--- a/flatcamTools/ToolNonCopperClear.py
+++ b/flatcamTools/ToolNonCopperClear.py
@@ -251,7 +251,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.tipdialabel = QtWidgets.QLabel('%s:' % _('V-Tip Dia'))
self.tipdialabel.setToolTip(
_("The tip diameter for V-Shape Tool"))
- self.tipdia_entry = FCDoubleSpinner()
+ self.tipdia_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.tipdia_entry.set_precision(self.decimals)
self.tipdia_entry.set_range(0.0000, 9999.9999)
self.tipdia_entry.setSingleStep(0.1)
@@ -265,7 +265,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.tipanglelabel.setToolTip(
_("The tip angle for V-Shape Tool.\n"
"In degree."))
- self.tipangle_entry = FCDoubleSpinner()
+ self.tipangle_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.tipangle_entry.set_precision(self.decimals)
self.tipangle_entry.set_range(0.0000, 180.0000)
self.tipangle_entry.setSingleStep(5)
@@ -280,7 +280,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
_("Depth of cut into material. Negative value.\n"
"In FlatCAM units.")
)
- self.cutz_entry = FCDoubleSpinner()
+ self.cutz_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.cutz_entry.set_precision(self.decimals)
self.cutz_entry.set_range(-99999.9999, 0.0000)
self.cutz_entry.setObjectName(_("Cut Z"))
@@ -299,7 +299,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
"If the tool is V-shape type then this value is automatically\n"
"calculated from the other parameters.")
)
- self.addtool_entry = FCDoubleSpinner()
+ self.addtool_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.addtool_entry.set_precision(self.decimals)
self.addtool_entry.set_range(0.000, 9999.9999)
self.addtool_entry.setObjectName(_("Tool Dia"))
@@ -381,7 +381,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
nccmarginlabel.setToolTip(
_("Bounding box margin.")
)
- self.ncc_margin_entry = FCDoubleSpinner()
+ self.ncc_margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.ncc_margin_entry.set_precision(self.decimals)
self.ncc_margin_entry.set_range(-9999.9999, 9999.9999)
self.ncc_margin_entry.setObjectName(_("Margin"))
@@ -447,7 +447,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
# "from the copper features.\n"
# "The value can be between 0 and 10 FlatCAM units.")
# )
- self.ncc_offset_spinner = FCDoubleSpinner()
+ self.ncc_offset_spinner = FCDoubleSpinner(callback=self.confirmation_message)
self.ncc_offset_spinner.set_range(0.00, 10.00)
self.ncc_offset_spinner.set_precision(4)
self.ncc_offset_spinner.setWrapping(True)
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 6b64d4f9..abfa7364 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -214,7 +214,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.tipdialabel = QtWidgets.QLabel('%s:' % _('V-Tip Dia'))
self.tipdialabel.setToolTip(
_("The tip diameter for V-Shape Tool"))
- self.tipdia_entry = FCDoubleSpinner()
+ self.tipdia_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.tipdia_entry.set_precision(self.decimals)
self.tipdia_entry.set_range(0.0000, 9999.9999)
self.tipdia_entry.setSingleStep(0.1)
@@ -228,7 +228,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.tipanglelabel.setToolTip(
_("The tip angle for V-Shape Tool.\n"
"In degree."))
- self.tipangle_entry = FCDoubleSpinner()
+ self.tipangle_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.tipangle_entry.set_precision(self.decimals)
self.tipangle_entry.set_range(0.0000, 180.0000)
self.tipangle_entry.setSingleStep(5)
@@ -243,7 +243,7 @@ class ToolPaint(FlatCAMTool, Gerber):
_("Depth of cut into material. Negative value.\n"
"In FlatCAM units.")
)
- self.cutz_entry = FCDoubleSpinner()
+ self.cutz_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.cutz_entry.set_precision(self.decimals)
self.cutz_entry.set_range(-99999.9999, 0.0000)
self.cutz_entry.setObjectName(_("Cut Z"))
@@ -262,7 +262,7 @@ class ToolPaint(FlatCAMTool, Gerber):
"If the tool is V-shape type then this value is automatically\n"
"calculated from the other parameters.")
)
- self.addtool_entry = FCDoubleSpinner()
+ self.addtool_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.addtool_entry.set_precision(self.decimals)
self.addtool_entry.set_range(0.000, 9999.9999)
self.addtool_entry.setObjectName(_("Tool Dia"))
@@ -351,7 +351,7 @@ class ToolPaint(FlatCAMTool, Gerber):
"the edges of the polygon to\n"
"be painted.")
)
- self.paintmargin_entry = FCDoubleSpinner()
+ self.paintmargin_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.paintmargin_entry.set_precision(self.decimals)
self.paintmargin_entry.set_range(-9999.9999, 9999.9999)
self.paintmargin_entry.setObjectName(_("Margin"))
diff --git a/flatcamTools/ToolPanelize.py b/flatcamTools/ToolPanelize.py
index a836d320..9a1e5f7a 100644
--- a/flatcamTools/ToolPanelize.py
+++ b/flatcamTools/ToolPanelize.py
@@ -158,7 +158,7 @@ class Panelize(FlatCAMTool):
form_layout.addRow(panel_data_label)
# Spacing Columns
- self.spacing_columns = FCDoubleSpinner()
+ self.spacing_columns = FCDoubleSpinner(callback=self.confirmation_message)
self.spacing_columns.set_range(0, 9999)
self.spacing_columns.set_precision(4)
@@ -170,7 +170,7 @@ class Panelize(FlatCAMTool):
form_layout.addRow(self.spacing_columns_label, self.spacing_columns)
# Spacing Rows
- self.spacing_rows = FCDoubleSpinner()
+ self.spacing_rows = FCDoubleSpinner(callback=self.confirmation_message)
self.spacing_rows.set_range(0, 9999)
self.spacing_rows.set_precision(4)
@@ -225,7 +225,7 @@ class Panelize(FlatCAMTool):
)
form_layout.addRow(self.constrain_cb)
- self.x_width_entry = FCDoubleSpinner()
+ self.x_width_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.x_width_entry.set_precision(4)
self.x_width_entry.set_range(0, 9999)
@@ -236,7 +236,7 @@ class Panelize(FlatCAMTool):
)
form_layout.addRow(self.x_width_lbl, self.x_width_entry)
- self.y_height_entry = FCDoubleSpinner()
+ self.y_height_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.y_height_entry.set_range(0, 9999)
self.y_height_entry.set_precision(4)
diff --git a/flatcamTools/ToolPunchGerber.py b/flatcamTools/ToolPunchGerber.py
index 282c20d4..75bf2495 100644
--- a/flatcamTools/ToolPunchGerber.py
+++ b/flatcamTools/ToolPunchGerber.py
@@ -183,7 +183,7 @@ class ToolPunchGerber(FlatCAMTool):
grid0.addWidget(self.fixed_label, 6, 0, 1, 2)
# Diameter value
- self.dia_entry = FCDoubleSpinner()
+ self.dia_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.dia_entry.set_precision(self.decimals)
self.dia_entry.set_range(0.0000, 9999.9999)
@@ -229,7 +229,7 @@ class ToolPunchGerber(FlatCAMTool):
_("The size of annular ring for circular pads.")
)
- self.circular_ring_entry = FCDoubleSpinner()
+ self.circular_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.circular_ring_entry.set_precision(self.decimals)
self.circular_ring_entry.set_range(0.0000, 9999.9999)
@@ -242,7 +242,7 @@ class ToolPunchGerber(FlatCAMTool):
_("The size of annular ring for oblong pads.")
)
- self.oblong_ring_entry = FCDoubleSpinner()
+ self.oblong_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.oblong_ring_entry.set_precision(self.decimals)
self.oblong_ring_entry.set_range(0.0000, 9999.9999)
@@ -255,7 +255,7 @@ class ToolPunchGerber(FlatCAMTool):
_("The size of annular ring for square pads.")
)
- self.square_ring_entry = FCDoubleSpinner()
+ self.square_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.square_ring_entry.set_precision(self.decimals)
self.square_ring_entry.set_range(0.0000, 9999.9999)
@@ -268,7 +268,7 @@ class ToolPunchGerber(FlatCAMTool):
_("The size of annular ring for rectangular pads.")
)
- self.rectangular_ring_entry = FCDoubleSpinner()
+ self.rectangular_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.rectangular_ring_entry.set_precision(self.decimals)
self.rectangular_ring_entry.set_range(0.0000, 9999.9999)
@@ -281,7 +281,7 @@ class ToolPunchGerber(FlatCAMTool):
_("The size of annular ring for other pads.")
)
- self.other_ring_entry = FCDoubleSpinner()
+ self.other_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.other_ring_entry.set_precision(self.decimals)
self.other_ring_entry.set_range(0.0000, 9999.9999)
diff --git a/flatcamTools/ToolRulesCheck.py b/flatcamTools/ToolRulesCheck.py
index bad1f902..39561ef2 100644
--- a/flatcamTools/ToolRulesCheck.py
+++ b/flatcamTools/ToolRulesCheck.py
@@ -260,7 +260,7 @@ class RulesCheck(FlatCAMTool):
self.form_layout_1.addRow(self.trace_size_cb)
# Trace size value
- self.trace_size_entry = FCDoubleSpinner()
+ 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)
@@ -282,7 +282,7 @@ class RulesCheck(FlatCAMTool):
self.form_layout_1.addRow(self.clearance_copper2copper_cb)
# Copper2copper clearance value
- self.clearance_copper2copper_entry = FCDoubleSpinner()
+ 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)
@@ -305,7 +305,7 @@ class RulesCheck(FlatCAMTool):
self.form_layout_1.addRow(self.clearance_copper2ol_cb)
# Copper2outline clearance value
- self.clearance_copper2ol_entry = FCDoubleSpinner()
+ 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)
@@ -328,7 +328,7 @@ class RulesCheck(FlatCAMTool):
self.form_layout_1.addRow(self.clearance_silk2silk_cb)
# Copper2silkscreen clearance value
- self.clearance_silk2silk_entry = FCDoubleSpinner()
+ 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)
@@ -351,7 +351,7 @@ class RulesCheck(FlatCAMTool):
self.form_layout_1.addRow(self.clearance_silk2sm_cb)
# Silkscreen2soldermask clearance value
- self.clearance_silk2sm_entry = FCDoubleSpinner()
+ 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)
@@ -374,7 +374,7 @@ class RulesCheck(FlatCAMTool):
self.form_layout_1.addRow(self.clearance_silk2ol_cb)
# Silk2outline clearance value
- self.clearance_silk2ol_entry = FCDoubleSpinner()
+ 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)
@@ -397,7 +397,7 @@ class RulesCheck(FlatCAMTool):
self.form_layout_1.addRow(self.clearance_sm2sm_cb)
# Soldermask2soldermask clearance value
- self.clearance_sm2sm_entry = FCDoubleSpinner()
+ 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)
@@ -420,7 +420,7 @@ class RulesCheck(FlatCAMTool):
self.form_layout_1.addRow(self.ring_integrity_cb)
# Ring integrity value
- self.ring_integrity_entry = FCDoubleSpinner()
+ 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)
@@ -445,7 +445,7 @@ class RulesCheck(FlatCAMTool):
self.form_layout_1.addRow(self.clearance_d2d_cb)
# Hole2Hole clearance value
- self.clearance_d2d_entry = FCDoubleSpinner()
+ 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)
@@ -468,7 +468,7 @@ class RulesCheck(FlatCAMTool):
self.form_layout_1.addRow(self.drill_size_cb)
# Drile holes value
- self.drill_size_entry = FCDoubleSpinner()
+ 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)
diff --git a/flatcamTools/ToolSolderPaste.py b/flatcamTools/ToolSolderPaste.py
index af227bd3..9f268a3e 100644
--- a/flatcamTools/ToolSolderPaste.py
+++ b/flatcamTools/ToolSolderPaste.py
@@ -105,7 +105,7 @@ class SolderPaste(FlatCAMTool):
self.addtool_entry_lbl.setToolTip(
_("Diameter for the new Nozzle tool to add in the Tool Table")
)
- self.addtool_entry = FCDoubleSpinner()
+ self.addtool_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.addtool_entry.set_range(0.0000001, 9999.9999)
self.addtool_entry.set_precision(self.decimals)
self.addtool_entry.setSingleStep(0.1)
@@ -174,7 +174,7 @@ class SolderPaste(FlatCAMTool):
self.gcode_box.addLayout(self.gcode_form_layout)
# Z dispense start
- self.z_start_entry = FCDoubleSpinner()
+ self.z_start_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.z_start_entry.set_range(0.0000001, 9999.9999)
self.z_start_entry.set_precision(self.decimals)
self.z_start_entry.setSingleStep(0.1)
@@ -186,7 +186,7 @@ class SolderPaste(FlatCAMTool):
self.gcode_form_layout.addRow(self.z_start_label, self.z_start_entry)
# Z dispense
- self.z_dispense_entry = FCDoubleSpinner()
+ self.z_dispense_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.z_dispense_entry.set_range(0.0000001, 9999.9999)
self.z_dispense_entry.set_precision(self.decimals)
self.z_dispense_entry.setSingleStep(0.1)
@@ -198,7 +198,7 @@ class SolderPaste(FlatCAMTool):
self.gcode_form_layout.addRow(self.z_dispense_label, self.z_dispense_entry)
# Z dispense stop
- self.z_stop_entry = FCDoubleSpinner()
+ self.z_stop_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.z_stop_entry.set_range(0.0000001, 9999.9999)
self.z_stop_entry.set_precision(self.decimals)
self.z_stop_entry.setSingleStep(0.1)
@@ -210,7 +210,7 @@ class SolderPaste(FlatCAMTool):
self.gcode_form_layout.addRow(self.z_stop_label, self.z_stop_entry)
# Z travel
- self.z_travel_entry = FCDoubleSpinner()
+ self.z_travel_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.z_travel_entry.set_range(0.0000001, 9999.9999)
self.z_travel_entry.set_precision(self.decimals)
self.z_travel_entry.setSingleStep(0.1)
@@ -223,7 +223,7 @@ class SolderPaste(FlatCAMTool):
self.gcode_form_layout.addRow(self.z_travel_label, self.z_travel_entry)
# Z toolchange location
- self.z_toolchange_entry = FCDoubleSpinner()
+ self.z_toolchange_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.z_toolchange_entry.set_range(0.0000001, 9999.9999)
self.z_toolchange_entry.set_precision(self.decimals)
self.z_toolchange_entry.setSingleStep(0.1)
@@ -244,7 +244,7 @@ class SolderPaste(FlatCAMTool):
self.gcode_form_layout.addRow(self.xy_toolchange_label, self.xy_toolchange_entry)
# Feedrate X-Y
- self.frxy_entry = FCDoubleSpinner()
+ self.frxy_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.frxy_entry.set_range(0.0000, 99999.9999)
self.frxy_entry.set_precision(self.decimals)
self.frxy_entry.setSingleStep(0.1)
@@ -256,7 +256,7 @@ class SolderPaste(FlatCAMTool):
self.gcode_form_layout.addRow(self.frxy_label, self.frxy_entry)
# Feedrate Z
- self.frz_entry = FCDoubleSpinner()
+ self.frz_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.frz_entry.set_range(0.0000, 99999.9999)
self.frz_entry.set_precision(self.decimals)
self.frz_entry.setSingleStep(0.1)
@@ -269,7 +269,7 @@ class SolderPaste(FlatCAMTool):
self.gcode_form_layout.addRow(self.frz_label, self.frz_entry)
# Feedrate Z Dispense
- self.frz_dispense_entry = FCDoubleSpinner()
+ self.frz_dispense_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.frz_dispense_entry.set_range(0.0000, 99999.9999)
self.frz_dispense_entry.set_precision(self.decimals)
self.frz_dispense_entry.setSingleStep(0.1)
@@ -294,7 +294,7 @@ class SolderPaste(FlatCAMTool):
self.gcode_form_layout.addRow(self.speedfwd_label, self.speedfwd_entry)
# Dwell Forward
- self.dwellfwd_entry = FCDoubleSpinner()
+ self.dwellfwd_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.dwellfwd_entry.set_range(0.0000001, 9999.9999)
self.dwellfwd_entry.set_precision(self.decimals)
self.dwellfwd_entry.setSingleStep(0.1)
@@ -318,7 +318,7 @@ class SolderPaste(FlatCAMTool):
self.gcode_form_layout.addRow(self.speedrev_label, self.speedrev_entry)
# Dwell Reverse
- self.dwellrev_entry = FCDoubleSpinner()
+ self.dwellrev_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.dwellrev_entry.set_range(0.0000001, 9999.9999)
self.dwellrev_entry.set_precision(self.decimals)
self.dwellrev_entry.setSingleStep(0.1)
diff --git a/flatcamTools/ToolTransform.py b/flatcamTools/ToolTransform.py
index 04cb1dc8..aa5bd6c7 100644
--- a/flatcamTools/ToolTransform.py
+++ b/flatcamTools/ToolTransform.py
@@ -68,7 +68,7 @@ class ToolTransform(FlatCAMTool):
"Negative numbers for CCW motion.")
)
- self.rotate_entry = FCDoubleSpinner()
+ 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)
@@ -103,7 +103,7 @@ class ToolTransform(FlatCAMTool):
_("Angle for Skew action, in degrees.\n"
"Float number between -360 and 360.")
)
- self.skewx_entry = FCDoubleSpinner()
+ 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)
@@ -125,7 +125,7 @@ class ToolTransform(FlatCAMTool):
_("Angle for Skew action, in degrees.\n"
"Float number between -360 and 360.")
)
- self.skewy_entry = FCDoubleSpinner()
+ 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)
@@ -155,7 +155,7 @@ class ToolTransform(FlatCAMTool):
self.scalex_label.setToolTip(
_("Factor for scaling on X axis.")
)
- self.scalex_entry = FCDoubleSpinner()
+ 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)
@@ -176,7 +176,7 @@ class ToolTransform(FlatCAMTool):
self.scaley_label.setToolTip(
_("Factor for scaling on Y axis.")
)
- self.scaley_entry = FCDoubleSpinner()
+ 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)
@@ -228,7 +228,7 @@ class ToolTransform(FlatCAMTool):
self.offx_label.setToolTip(
_("Distance to offset on X axis. In current units.")
)
- self.offx_entry = FCDoubleSpinner()
+ 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)
@@ -249,7 +249,7 @@ class ToolTransform(FlatCAMTool):
self.offy_label.setToolTip(
_("Distance to offset on Y axis. In current units.")
)
- self.offy_entry = FCDoubleSpinner()
+ 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)
@@ -353,7 +353,7 @@ class ToolTransform(FlatCAMTool):
"or decreased with the 'distance'.")
)
- self.buffer_entry = FCDoubleSpinner()
+ 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)
diff --git a/preprocessors/default.py b/preprocessors/default.py
index 216ba98e..640620f6 100644
--- a/preprocessors/default.py
+++ b/preprocessors/default.py
@@ -37,6 +37,13 @@ class default(FlatCAMPostProc):
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
+ if str(p['options']['type']) == 'Excellon':
+ gcode += '\n(Tools Offset: )\n'
+ for tool, val in p['exc_cnc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(val['tool']) + 'Dia: %s -> ' % str(tool) + \
+ 'Offset Z: %s' % str(val['offset_z']) + ')\n'
+ gcode += '\n'
+
if p['multidepth'] is True:
gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
diff --git a/tclCommands/TclCommandDrillcncjob.py b/tclCommands/TclCommandDrillcncjob.py
index a420f2ae..64404fde 100644
--- a/tclCommands/TclCommandDrillcncjob.py
+++ b/tclCommands/TclCommandDrillcncjob.py
@@ -169,7 +169,7 @@ class TclCommandDrillcncjob(TclCommandSignaled):
else:
return "fail"
- drillz = args["drillz"] if "drillz" in args and args["drillz"] is not None else obj.options["drillz"]
+ drillz = args["drillz"] if "drillz" in args and args["drillz"] is not None else obj.options["cutz"]
if "toolchangez" in args:
toolchange = True
@@ -229,9 +229,6 @@ class TclCommandDrillcncjob(TclCommandSignaled):
float(job_obj.exc_cnc_tools[t_item]['offset_z']) + float(drillz)
job_obj.exc_cnc_tools[t_item]['data']['ppname_e'] = obj.options['ppname_e']
- # for now there is no tool offset support in this Tcl Command so we write the 0.0 value here
- job_obj.tool_offset[t_item] = 0.0
-
job_obj.origin_kind = 'excellon'
job_obj.gcode_parse()
From ea1b99242c155a54dae5d63282c180fa5d89d66d Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 17 Feb 2020 04:56:57 +0200
Subject: [PATCH 101/209] - updated all FlatCAM tools to use the new
confirmation message for QSpinBoxes, too
---
README.md | 1 +
flatcamTools/ToolCalculators.py | 2 +-
flatcamTools/ToolExtractDrills.py | 2 +-
flatcamTools/ToolImage.py | 10 +++++-----
flatcamTools/ToolNonCopperClear.py | 2 +-
flatcamTools/ToolOptimal.py | 2 +-
flatcamTools/ToolPaint.py | 2 +-
flatcamTools/ToolPanelize.py | 4 ++--
flatcamTools/ToolPcbWizard.py | 4 ++--
flatcamTools/ToolPunchGerber.py | 2 +-
flatcamTools/ToolQRCode.py | 6 +++---
flatcamTools/ToolSolderPaste.py | 4 ++--
flatcamTools/ToolTransform.py | 2 +-
13 files changed, 22 insertions(+), 21 deletions(-)
diff --git a/README.md b/README.md
index 501d28a0..09b4835c 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ CAD program, and create G-Code for Isolation routing.
- in Excellon UI removed the tools table column for Offset Z and used the UI form parameter
- updated the Excellon Editor to add for each tool a 'data' dictionary
- updated all FlatCAM tools to use the new confirmation message that show if the entered value is within range or outside
+- updated all FlatCAM tools to use the new confirmation message for QSpinBoxes, too
16.02.2020
diff --git a/flatcamTools/ToolCalculators.py b/flatcamTools/ToolCalculators.py
index a5b0afca..a7dbda2e 100644
--- a/flatcamTools/ToolCalculators.py
+++ b/flatcamTools/ToolCalculators.py
@@ -103,7 +103,7 @@ class ToolCalculator(FlatCAMTool):
"It is specified by manufacturer.")
)
self.tipAngle_label = QtWidgets.QLabel('%s:' % _("Tip Angle"))
- self.tipAngle_entry = FCSpinner()
+ self.tipAngle_entry = FCSpinner(callback=self.confirmation_message_int)
self.tipAngle_entry.set_range(0,180)
self.tipAngle_entry.setSingleStep(5)
diff --git a/flatcamTools/ToolExtractDrills.py b/flatcamTools/ToolExtractDrills.py
index 05c1e2d0..5a693300 100644
--- a/flatcamTools/ToolExtractDrills.py
+++ b/flatcamTools/ToolExtractDrills.py
@@ -276,7 +276,7 @@ class ToolExtractDrills(FlatCAMTool):
grid3.addWidget(self.prop_label, 2, 0, 1, 2)
# Diameter value
- self.factor_entry = FCDoubleSpinner(suffix='%')
+ self.factor_entry = FCDoubleSpinner(callback=self.confirmation_message, suffix='%')
self.factor_entry.set_precision(self.decimals)
self.factor_entry.set_range(0.0000, 100.0000)
self.factor_entry.setSingleStep(0.1)
diff --git a/flatcamTools/ToolImage.py b/flatcamTools/ToolImage.py
index a87d7d4b..3e8f2d57 100644
--- a/flatcamTools/ToolImage.py
+++ b/flatcamTools/ToolImage.py
@@ -61,7 +61,7 @@ class ToolImage(FlatCAMTool):
ti_form_layout.addRow(self.tf_type_obj_combo_label, self.tf_type_obj_combo)
# DPI value of the imported image
- self.dpi_entry = FCSpinner()
+ self.dpi_entry = FCSpinner(callback=self.confirmation_message_int)
self.dpi_entry.set_range(0, 99999)
self.dpi_label = QtWidgets.QLabel('%s:' % _("DPI value"))
self.dpi_label.setToolTip(_("Specify a DPI value for the image.") )
@@ -87,7 +87,7 @@ class ToolImage(FlatCAMTool):
ti2_form_layout.addRow(self.image_type_label, self.image_type)
# Mask value of the imported image when image monochrome
- self.mask_bw_entry = FCSpinner()
+ self.mask_bw_entry = FCSpinner(callback=self.confirmation_message_int)
self.mask_bw_entry.set_range(0, 255)
self.mask_bw_label = QtWidgets.QLabel("%s B/W:" % _('Mask value'))
@@ -102,7 +102,7 @@ class ToolImage(FlatCAMTool):
ti2_form_layout.addRow(self.mask_bw_label, self.mask_bw_entry)
# Mask value of the imported image for RED color when image color
- self.mask_r_entry = FCSpinner()
+ self.mask_r_entry = FCSpinner(callback=self.confirmation_message_int)
self.mask_r_entry.set_range(0, 255)
self.mask_r_label = QtWidgets.QLabel("%s R:" % _('Mask value'))
@@ -115,7 +115,7 @@ class ToolImage(FlatCAMTool):
ti2_form_layout.addRow(self.mask_r_label, self.mask_r_entry)
# Mask value of the imported image for GREEN color when image color
- self.mask_g_entry = FCSpinner()
+ self.mask_g_entry = FCSpinner(callback=self.confirmation_message_int)
self.mask_g_entry.set_range(0, 255)
self.mask_g_label = QtWidgets.QLabel("%s G:" % _('Mask value'))
@@ -128,7 +128,7 @@ class ToolImage(FlatCAMTool):
ti2_form_layout.addRow(self.mask_g_label, self.mask_g_entry)
# Mask value of the imported image for BLUE color when image color
- self.mask_b_entry = FCSpinner()
+ self.mask_b_entry = FCSpinner(callback=self.confirmation_message_int)
self.mask_b_entry.set_range(0, 255)
self.mask_b_label = QtWidgets.QLabel("%s B:" % _('Mask value'))
diff --git a/flatcamTools/ToolNonCopperClear.py b/flatcamTools/ToolNonCopperClear.py
index 6a03bdf6..b1c5c65e 100644
--- a/flatcamTools/ToolNonCopperClear.py
+++ b/flatcamTools/ToolNonCopperClear.py
@@ -366,7 +366,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
"Higher values = slow processing and slow execution on CNC\n"
"due of too many paths.")
)
- self.ncc_overlap_entry = FCDoubleSpinner(suffix='%')
+ self.ncc_overlap_entry = FCDoubleSpinner(callback=self.confirmation_message, suffix='%')
self.ncc_overlap_entry.set_precision(self.decimals)
self.ncc_overlap_entry.setWrapping(True)
self.ncc_overlap_entry.setRange(0.000, 99.9999)
diff --git a/flatcamTools/ToolOptimal.py b/flatcamTools/ToolOptimal.py
index c5cd509d..876b0ded 100644
--- a/flatcamTools/ToolOptimal.py
+++ b/flatcamTools/ToolOptimal.py
@@ -78,7 +78,7 @@ class ToolOptimal(FlatCAMTool):
self.precision_label = QtWidgets.QLabel('%s:' % _("Precision"))
self.precision_label.setToolTip(_("Number of decimals kept for found distances."))
- self.precision_spinner = FCSpinner()
+ self.precision_spinner = FCSpinner(callback=self.confirmation_message_int)
self.precision_spinner.set_range(2, 10)
self.precision_spinner.setWrapping(True)
form_lay.addRow(self.precision_label, self.precision_spinner)
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index abfa7364..d1524a96 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -334,7 +334,7 @@ class ToolPaint(FlatCAMTool, Gerber):
"Higher values = slow processing and slow execution on CNC\n"
"due of too many paths.")
)
- self.paintoverlap_entry = FCDoubleSpinner(suffix='%')
+ self.paintoverlap_entry = FCDoubleSpinner(callback=self.confirmation_message, suffix='%')
self.paintoverlap_entry.set_precision(3)
self.paintoverlap_entry.setWrapping(True)
self.paintoverlap_entry.setRange(0.0000, 99.9999)
diff --git a/flatcamTools/ToolPanelize.py b/flatcamTools/ToolPanelize.py
index 9a1e5f7a..8aeddabf 100644
--- a/flatcamTools/ToolPanelize.py
+++ b/flatcamTools/ToolPanelize.py
@@ -182,7 +182,7 @@ class Panelize(FlatCAMTool):
form_layout.addRow(self.spacing_rows_label, self.spacing_rows)
# Columns
- self.columns = FCSpinner()
+ self.columns = FCSpinner(callback=self.confirmation_message_int)
self.columns.set_range(0, 9999)
self.columns_label = QtWidgets.QLabel('%s:' % _("Columns"))
@@ -192,7 +192,7 @@ class Panelize(FlatCAMTool):
form_layout.addRow(self.columns_label, self.columns)
# Rows
- self.rows = FCSpinner()
+ self.rows = FCSpinner(callback=self.confirmation_message_int)
self.rows.set_range(0, 9999)
self.rows_label = QtWidgets.QLabel('%s:' % _("Rows"))
diff --git a/flatcamTools/ToolPcbWizard.py b/flatcamTools/ToolPcbWizard.py
index 753b6667..fbd57896 100644
--- a/flatcamTools/ToolPcbWizard.py
+++ b/flatcamTools/ToolPcbWizard.py
@@ -90,7 +90,7 @@ class PcbWizard(FlatCAMTool):
self.layout.addLayout(form_layout1)
# Integral part of the coordinates
- self.int_entry = FCSpinner()
+ self.int_entry = FCSpinner(callback=self.confirmation_message_int)
self.int_entry.set_range(1, 10)
self.int_label = QtWidgets.QLabel('%s:' % _("Int. digits"))
self.int_label.setToolTip(
@@ -99,7 +99,7 @@ class PcbWizard(FlatCAMTool):
form_layout1.addRow(self.int_label, self.int_entry)
# Fractional part of the coordinates
- self.frac_entry = FCSpinner()
+ self.frac_entry = FCSpinner(callback=self.confirmation_message_int)
self.frac_entry.set_range(1, 10)
self.frac_label = QtWidgets.QLabel('%s:' % _("Frac. digits"))
self.frac_label.setToolTip(
diff --git a/flatcamTools/ToolPunchGerber.py b/flatcamTools/ToolPunchGerber.py
index 75bf2495..b0f5c326 100644
--- a/flatcamTools/ToolPunchGerber.py
+++ b/flatcamTools/ToolPunchGerber.py
@@ -298,7 +298,7 @@ class ToolPunchGerber(FlatCAMTool):
grid0.addWidget(self.prop_label, 12, 0, 1, 2)
# Diameter value
- self.factor_entry = FCDoubleSpinner(suffix='%')
+ self.factor_entry = FCDoubleSpinner(callback=self.confirmation_message, suffix='%')
self.factor_entry.set_precision(self.decimals)
self.factor_entry.set_range(0.0000, 100.0000)
self.factor_entry.setSingleStep(0.1)
diff --git a/flatcamTools/ToolQRCode.py b/flatcamTools/ToolQRCode.py
index 7e5aac40..a70b1f63 100644
--- a/flatcamTools/ToolQRCode.py
+++ b/flatcamTools/ToolQRCode.py
@@ -101,7 +101,7 @@ class QRCode(FlatCAMTool):
_("QRCode version can have values from 1 (21x21 boxes)\n"
"to 40 (177x177 boxes).")
)
- self.version_entry = FCSpinner()
+ self.version_entry = FCSpinner(callback=self.confirmation_message_int)
self.version_entry.set_range(1, 40)
self.version_entry.setWrapping(True)
@@ -137,7 +137,7 @@ class QRCode(FlatCAMTool):
_("Box size control the overall size of the QRcode\n"
"by adjusting the size of each box in the code.")
)
- self.bsize_entry = FCSpinner()
+ self.bsize_entry = FCSpinner(callback=self.confirmation_message_int)
self.bsize_entry.set_range(1, 9999)
self.bsize_entry.setWrapping(True)
@@ -150,7 +150,7 @@ class QRCode(FlatCAMTool):
_("Size of the QRCode border. How many boxes thick is the border.\n"
"Default value is 4. The width of the clearance around the QRCode.")
)
- self.border_size_entry = FCSpinner()
+ self.border_size_entry = FCSpinner(callback=self.confirmation_message_int)
self.border_size_entry.set_range(1, 9999)
self.border_size_entry.setWrapping(True)
self.border_size_entry.set_value(4)
diff --git a/flatcamTools/ToolSolderPaste.py b/flatcamTools/ToolSolderPaste.py
index 9f268a3e..0626a4c9 100644
--- a/flatcamTools/ToolSolderPaste.py
+++ b/flatcamTools/ToolSolderPaste.py
@@ -282,7 +282,7 @@ class SolderPaste(FlatCAMTool):
self.gcode_form_layout.addRow(self.frz_dispense_label, self.frz_dispense_entry)
# Spindle Speed Forward
- self.speedfwd_entry = FCSpinner()
+ self.speedfwd_entry = FCSpinner(callback=self.confirmation_message_int)
self.speedfwd_entry.set_range(0, 999999)
self.speedfwd_entry.setSingleStep(1000)
@@ -306,7 +306,7 @@ class SolderPaste(FlatCAMTool):
self.gcode_form_layout.addRow(self.dwellfwd_label, self.dwellfwd_entry)
# Spindle Speed Reverse
- self.speedrev_entry = FCSpinner()
+ self.speedrev_entry = FCSpinner(callback=self.confirmation_message_int)
self.speedrev_entry.set_range(0, 999999)
self.speedrev_entry.setSingleStep(1000)
diff --git a/flatcamTools/ToolTransform.py b/flatcamTools/ToolTransform.py
index aa5bd6c7..cebe6953 100644
--- a/flatcamTools/ToolTransform.py
+++ b/flatcamTools/ToolTransform.py
@@ -380,7 +380,7 @@ class ToolTransform(FlatCAMTool):
"of the initial dimension.")
)
- self.buffer_factor_entry = FCDoubleSpinner(suffix='%')
+ 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)
From ae22ddb516a9090c8c8f60e3af1b9e258f367511 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 17 Feb 2020 05:19:21 +0200
Subject: [PATCH 102/209] - in Excellon UI protected the values that are common
parameters from change on tool selection change
---
FlatCAMObj.py | 3 ++-
README.md | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 1e0119e5..4c71180b 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -3028,7 +3028,8 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
def storage_to_form(self, dict_storage):
for form_key in self.form_fields:
for storage_key in dict_storage:
- if form_key == storage_key:
+ if form_key == storage_key and form_key not in \
+ ["toolchangez", "startz", "endz", "ppname_e", "ppname_g"]:
try:
self.form_fields[form_key].set_value(dict_storage[form_key])
except Exception as e:
diff --git a/README.md b/README.md
index 09b4835c..a1c37433 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,7 @@ CAD program, and create G-Code for Isolation routing.
- updated the Excellon Editor to add for each tool a 'data' dictionary
- updated all FlatCAM tools to use the new confirmation message that show if the entered value is within range or outside
- updated all FlatCAM tools to use the new confirmation message for QSpinBoxes, too
+- in Excellon UI protected the values that are common parameters from change on tool selection change
16.02.2020
From 7292a30b9ef91b403d6374a58bc95bbc6e030ff0 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 17 Feb 2020 14:27:45 +0200
Subject: [PATCH 103/209] - fixed some issues realted to the usage of the new
confirmation message in FlatCAM Tools - made sure that the FlatCAM Tools UI
initialization is done only in set_tool_ui() method and not in the
constructor
---
FlatCAMCommon.py | 2 +-
README.md | 2 ++
flatcamGUI/GUIElements.py | 7 +++++++
flatcamGUI/ObjectUI.py | 5 +++--
flatcamGUI/PreferencesUI.py | 29 +++++++++++++++--------------
flatcamTools/ToolCalculators.py | 2 +-
flatcamTools/ToolCalibration.py | 5 +++--
flatcamTools/ToolDistanceMin.py | 9 ---------
flatcamTools/ToolOptimal.py | 6 +++---
flatcamTools/ToolQRCode.py | 3 ++-
flatcamTools/ToolSolderPaste.py | 4 ++--
flatcamTools/ToolTransform.py | 31 ++++++++++++++++---------------
12 files changed, 55 insertions(+), 50 deletions(-)
diff --git a/FlatCAMCommon.py b/FlatCAMCommon.py
index d4a7f0ff..2bc95131 100644
--- a/FlatCAMCommon.py
+++ b/FlatCAMCommon.py
@@ -927,7 +927,7 @@ class ToolsDB(QtWidgets.QWidget):
spindlespeed_item = FCSpinner()
spindlespeed_item.set_range(0, 1000000)
spindlespeed_item.set_value(int(data['spindlespeed']))
- spindlespeed_item.setSingleStep(100)
+ spindlespeed_item.set_step(100)
widget.setCellWidget(row, 16, spindlespeed_item)
dwell_item = FCCheckBox()
diff --git a/README.md b/README.md
index a1c37433..be19c4c3 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,8 @@ CAD program, and create G-Code for Isolation routing.
- updated all FlatCAM tools to use the new confirmation message that show if the entered value is within range or outside
- updated all FlatCAM tools to use the new confirmation message for QSpinBoxes, too
- in Excellon UI protected the values that are common parameters from change on tool selection change
+- fixed some issues realted to the usage of the new confirmation message in FlatCAM Tools
+- made sure that the FlatCAM Tools UI initialization is done only in set_tool_ui() method and not in the constructor
16.02.2020
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index de4fd34f..d53575d2 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -670,7 +670,14 @@ class FCSpinner(QtWidgets.QSpinBox):
return QtGui.QValidator.Acceptable, p_str, p_int
def set_range(self, min_val, max_val):
+ self.blockSignals(True)
self.setRange(min_val, max_val)
+ self.blockSignals(False)
+
+ def set_step(self, p_int):
+ self.blockSignals(True)
+ self.setSingleStep(p_int)
+ self.blockSignals(False)
# def sizeHint(self):
# default_hint_size = super(FCSpinner, self).sizeHint()
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index ab30498d..c4204765 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -386,6 +386,7 @@ class GerberObjectUI(ObjectUI):
passlabel.setMinimumWidth(90)
self.iso_width_entry = FCSpinner(callback=self.confirmation_message_int)
self.iso_width_entry.set_range(1, 999)
+
grid1.addWidget(passlabel, 5, 0)
grid1.addWidget(self.iso_width_entry, 5, 1, 1, 2)
@@ -1054,7 +1055,7 @@ class ExcellonObjectUI(ObjectUI):
self.spindlespeed_entry = FCSpinner(callback=self.confirmation_message_int)
self.spindlespeed_entry.set_range(0, 1000000)
- self.spindlespeed_entry.setSingleStep(100)
+ self.spindlespeed_entry.set_step(100)
self.spindlespeed_entry.setObjectName("e_spindlespeed")
self.grid3.addWidget(self.spindle_label, 19, 0)
@@ -1823,7 +1824,7 @@ class GeometryObjectUI(ObjectUI):
)
self.cncspindlespeed_entry = FCSpinner(callback=self.confirmation_message_int)
self.cncspindlespeed_entry.set_range(0, 1000000)
- self.cncspindlespeed_entry.setSingleStep(100)
+ self.cncspindlespeed_entry.set_step(100)
self.grid3.addWidget(self.spindle_label, 14, 0)
self.grid3.addWidget(self.cncspindlespeed_entry, 14, 1)
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index e3fd5fff..0c5537c8 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -1133,7 +1133,7 @@ class GeneralAPPSetGroupUI(OptionsGroupUI):
)
self.notebook_font_size_spinner = FCSpinner()
- self.notebook_font_size_spinner.setRange(8, 40)
+ self.notebook_font_size_spinner.set_range(8, 40)
self.notebook_font_size_spinner.setWrapping(True)
settings = QSettings("Open Source", "FlatCAM")
@@ -1152,7 +1152,7 @@ class GeneralAPPSetGroupUI(OptionsGroupUI):
)
self.axis_font_size_spinner = FCSpinner()
- self.axis_font_size_spinner.setRange(0, 40)
+ self.axis_font_size_spinner.set_range(0, 40)
self.axis_font_size_spinner.setWrapping(True)
settings = QSettings("Open Source", "FlatCAM")
@@ -1172,7 +1172,7 @@ class GeneralAPPSetGroupUI(OptionsGroupUI):
)
self.textbox_font_size_spinner = FCSpinner()
- self.textbox_font_size_spinner.setRange(8, 40)
+ self.textbox_font_size_spinner.set_range(8, 40)
self.textbox_font_size_spinner.setWrapping(True)
settings = QSettings("Open Source", "FlatCAM")
@@ -1342,6 +1342,7 @@ class GeneralAPPSetGroupUI(OptionsGroupUI):
# Bookmarks Limit in the Help Menu
self.bm_limit_spinner = FCSpinner()
+ self.bm_limit_spinner.set_range(0, 9999)
self.bm_limit_label = QtWidgets.QLabel('%s:' % _('Bookmarks limit'))
self.bm_limit_label.setToolTip(
_("The maximum number of bookmarks that may be installed in the menu.\n"
@@ -2040,7 +2041,7 @@ class GerberOptPrefGroupUI(OptionsGroupUI):
"number (integer) of tool widths.")
)
self.iso_width_entry = FCSpinner()
- self.iso_width_entry.setRange(1, 999)
+ self.iso_width_entry.set_range(1, 999)
grid0.addWidget(passlabel, 1, 0)
grid0.addWidget(self.iso_width_entry, 1, 1)
@@ -2247,7 +2248,7 @@ class GerberAdvOptPrefGroupUI(OptionsGroupUI):
)
self.tipangle_spinner = FCSpinner()
self.tipangle_spinner.set_range(1, 180)
- self.tipangle_spinner.setSingleStep(5)
+ self.tipangle_spinner.set_step(5)
self.tipangle_spinner.setWrapping(True)
grid0.addWidget(self.tipanglelabel, 5, 0)
grid0.addWidget(self.tipangle_spinner, 5, 1, 1, 2)
@@ -2379,7 +2380,7 @@ class GerberExpPrefGroupUI(OptionsGroupUI):
self.format_whole_entry = FCSpinner()
self.format_whole_entry.set_range(0, 9)
- self.format_whole_entry.setSingleStep(1)
+ self.format_whole_entry.set_step(1)
self.format_whole_entry.setWrapping(True)
self.format_whole_entry.setMinimumWidth(30)
@@ -2395,7 +2396,7 @@ class GerberExpPrefGroupUI(OptionsGroupUI):
self.format_dec_entry = FCSpinner()
self.format_dec_entry.set_range(0, 9)
- self.format_dec_entry.setSingleStep(1)
+ self.format_dec_entry.set_step(1)
self.format_dec_entry.setWrapping(True)
self.format_dec_entry.setMinimumWidth(30)
@@ -3252,7 +3253,7 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
self.spindlespeed_entry = FCSpinner()
self.spindlespeed_entry.set_range(0, 1000000)
- self.spindlespeed_entry.setSingleStep(100)
+ self.spindlespeed_entry.set_step(100)
grid2.addWidget(spdlabel, 10, 0)
grid2.addWidget(self.spindlespeed_entry, 10, 1)
@@ -4207,7 +4208,7 @@ class GeometryOptPrefGroupUI(OptionsGroupUI):
grid1.addWidget(spdlabel, 9, 0)
self.cncspindlespeed_entry = FCSpinner()
self.cncspindlespeed_entry.set_range(0, 1000000)
- self.cncspindlespeed_entry.setSingleStep(100)
+ self.cncspindlespeed_entry.set_step(100)
grid1.addWidget(self.cncspindlespeed_entry, 9, 1)
@@ -6258,7 +6259,7 @@ class ToolsPanelizePrefGroupUI(OptionsGroupUI):
# ## Columns
self.pcolumns = FCSpinner()
self.pcolumns.set_range(1, 1000)
- self.pcolumns.setSingleStep(1)
+ self.pcolumns.set_step(1)
self.columns_label = QtWidgets.QLabel('%s:' % _("Columns"))
self.columns_label.setToolTip(
@@ -6270,7 +6271,7 @@ class ToolsPanelizePrefGroupUI(OptionsGroupUI):
# ## Rows
self.prows = FCSpinner()
self.prows.set_range(1, 1000)
- self.prows.setSingleStep(1)
+ self.prows.set_step(1)
self.rows_label = QtWidgets.QLabel('%s:' % _("Rows"))
self.rows_label.setToolTip(
@@ -6848,7 +6849,7 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
# Spindle Speed Forward
self.speedfwd_entry = FCSpinner()
self.speedfwd_entry.set_range(0, 99999)
- self.speedfwd_entry.setSingleStep(1000)
+ self.speedfwd_entry.set_step(1000)
self.speedfwd_label = QtWidgets.QLabel('%s:' % _("Spindle Speed FWD"))
self.speedfwd_label.setToolTip(
@@ -6874,7 +6875,7 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
# Spindle Speed Reverse
self.speedrev_entry = FCSpinner()
self.speedrev_entry.set_range(0, 999999)
- self.speedrev_entry.setSingleStep(1000)
+ self.speedrev_entry.set_step(1000)
self.speedrev_label = QtWidgets.QLabel('%s:' % _("Spindle Speed REV"))
self.speedrev_label.setToolTip(
@@ -7180,7 +7181,7 @@ class Tools2OptimalPrefGroupUI(OptionsGroupUI):
self.precision_sp = FCSpinner()
self.precision_sp.set_range(2, 10)
- self.precision_sp.setSingleStep(1)
+ self.precision_sp.set_step(1)
self.precision_sp.setWrapping(True)
self.precision_lbl = QtWidgets.QLabel('%s:' % _("Precision"))
diff --git a/flatcamTools/ToolCalculators.py b/flatcamTools/ToolCalculators.py
index a7dbda2e..086ab83e 100644
--- a/flatcamTools/ToolCalculators.py
+++ b/flatcamTools/ToolCalculators.py
@@ -105,7 +105,7 @@ class ToolCalculator(FlatCAMTool):
self.tipAngle_label = QtWidgets.QLabel('%s:' % _("Tip Angle"))
self.tipAngle_entry = FCSpinner(callback=self.confirmation_message_int)
self.tipAngle_entry.set_range(0,180)
- self.tipAngle_entry.setSingleStep(5)
+ self.tipAngle_entry.set_step(5)
# self.tipAngle_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.tipAngle_label.setToolTip(_("This is the angle of the tip of the tool.\n"
diff --git a/flatcamTools/ToolCalibration.py b/flatcamTools/ToolCalibration.py
index cc964b1a..ae83edb6 100644
--- a/flatcamTools/ToolCalibration.py
+++ b/flatcamTools/ToolCalibration.py
@@ -263,8 +263,6 @@ class ToolCalibration(FlatCAMTool):
self.bottom_left_coordy_found = EvalEntry()
self.points_table.setCellWidget(row, 3, self.bottom_left_coordy_found)
- self.bottom_left_coordx_found.set_value(_("Origin"))
- self.bottom_left_coordy_found.set_value(_("Origin"))
self.bottom_left_coordx_found.setDisabled(True)
self.bottom_left_coordy_found.setDisabled(True)
row += 1
@@ -770,6 +768,9 @@ class ToolCalibration(FlatCAMTool):
if self.local_connected is True:
self.disconnect_cal_events()
+ self.bottom_left_coordx_found.set_value(_("Origin"))
+ self.bottom_left_coordy_found.set_value(_("Origin"))
+
self.reset_calibration_points()
self.cal_source_radio.set_value(self.app.defaults['tools_cal_calsource'])
diff --git a/flatcamTools/ToolDistanceMin.py b/flatcamTools/ToolDistanceMin.py
index 08bfc62f..485fca3b 100644
--- a/flatcamTools/ToolDistanceMin.py
+++ b/flatcamTools/ToolDistanceMin.py
@@ -128,15 +128,6 @@ class DistanceMin(FlatCAMTool):
form_layout.addRow(self.total_distance_label, self.total_distance_entry)
form_layout.addRow(self.half_point_label, self.half_point_entry)
- # 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.layout.addStretch()
self.h_point = (0, 0)
diff --git a/flatcamTools/ToolOptimal.py b/flatcamTools/ToolOptimal.py
index 876b0ded..5160fc81 100644
--- a/flatcamTools/ToolOptimal.py
+++ b/flatcamTools/ToolOptimal.py
@@ -282,9 +282,6 @@ class ToolOptimal(FlatCAMTool):
def run(self, toggle=True):
self.app.report_usage("ToolOptimal()")
- self.result_entry.set_value(0.0)
- self.freq_entry.set_value('0')
-
if toggle:
# if the splitter is hidden, display it, else hide it but only if the current widget is the same
if self.app.ui.splitter.sizes()[0] == 0:
@@ -310,6 +307,9 @@ class ToolOptimal(FlatCAMTool):
self.app.ui.notebook.setTabText(2, _("Optimal Tool"))
def set_tool_ui(self):
+ self.result_entry.set_value(0.0)
+ self.freq_entry.set_value('0')
+
self.precision_spinner.set_value(int(self.app.defaults["tools_opt_precision"]))
self.locations_textb.clear()
# new cursor - select all document
diff --git a/flatcamTools/ToolQRCode.py b/flatcamTools/ToolQRCode.py
index a70b1f63..5e9b8ff0 100644
--- a/flatcamTools/ToolQRCode.py
+++ b/flatcamTools/ToolQRCode.py
@@ -153,7 +153,6 @@ class QRCode(FlatCAMTool):
self.border_size_entry = FCSpinner(callback=self.confirmation_message_int)
self.border_size_entry.set_range(1, 9999)
self.border_size_entry.setWrapping(True)
- self.border_size_entry.set_value(4)
grid_lay.addWidget(self.border_size_label, 4, 0)
grid_lay.addWidget(self.border_size_entry, 4, 1)
@@ -386,6 +385,8 @@ class QRCode(FlatCAMTool):
def set_tool_ui(self):
self.units = self.app.defaults['units']
+ self.border_size_entry.set_value(4)
+
self.version_entry.set_value(int(self.app.defaults["tools_qrcode_version"]))
self.error_radio.set_value(self.app.defaults["tools_qrcode_error"])
self.bsize_entry.set_value(int(self.app.defaults["tools_qrcode_box_size"]))
diff --git a/flatcamTools/ToolSolderPaste.py b/flatcamTools/ToolSolderPaste.py
index 0626a4c9..655ab3aa 100644
--- a/flatcamTools/ToolSolderPaste.py
+++ b/flatcamTools/ToolSolderPaste.py
@@ -284,7 +284,7 @@ class SolderPaste(FlatCAMTool):
# Spindle Speed Forward
self.speedfwd_entry = FCSpinner(callback=self.confirmation_message_int)
self.speedfwd_entry.set_range(0, 999999)
- self.speedfwd_entry.setSingleStep(1000)
+ self.speedfwd_entry.set_step(1000)
self.speedfwd_label = QtWidgets.QLabel('%s:' % _("Spindle Speed FWD"))
self.speedfwd_label.setToolTip(
@@ -308,7 +308,7 @@ class SolderPaste(FlatCAMTool):
# Spindle Speed Reverse
self.speedrev_entry = FCSpinner(callback=self.confirmation_message_int)
self.speedrev_entry.set_range(0, 999999)
- self.speedrev_entry.setSingleStep(1000)
+ self.speedrev_entry.set_step(1000)
self.speedrev_label = QtWidgets.QLabel('%s:' % _("Spindle Speed REV"))
self.speedrev_label.setToolTip(
diff --git a/flatcamTools/ToolTransform.py b/flatcamTools/ToolTransform.py
index cebe6953..8ce0eff5 100644
--- a/flatcamTools/ToolTransform.py
+++ b/flatcamTools/ToolTransform.py
@@ -77,7 +77,6 @@ class ToolTransform(FlatCAMTool):
# self.rotate_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.rotate_button = FCButton()
- self.rotate_button.set_value(_("Rotate"))
self.rotate_button.setToolTip(
_("Rotate the selected object(s).\n"
"The point of reference is the middle of\n"
@@ -109,7 +108,6 @@ class ToolTransform(FlatCAMTool):
self.skewx_entry.set_range(-360, 360)
self.skewx_button = FCButton()
- self.skewx_button.set_value(_("Skew X"))
self.skewx_button.setToolTip(
_("Skew/shear the selected object(s).\n"
"The point of reference is the middle of\n"
@@ -131,7 +129,6 @@ class ToolTransform(FlatCAMTool):
self.skewy_entry.set_range(-360, 360)
self.skewy_button = FCButton()
- self.skewy_button.set_value(_("Skew Y"))
self.skewy_button.setToolTip(
_("Skew/shear the selected object(s).\n"
"The point of reference is the middle of\n"
@@ -161,7 +158,6 @@ class ToolTransform(FlatCAMTool):
self.scalex_entry.setMinimum(-1e6)
self.scalex_button = FCButton()
- self.scalex_button.set_value(_("Scale X"))
self.scalex_button.setToolTip(
_("Scale the selected object(s).\n"
"The point of reference depends on \n"
@@ -182,7 +178,6 @@ class ToolTransform(FlatCAMTool):
self.scaley_entry.setMinimum(-1e6)
self.scaley_button = FCButton()
- self.scaley_button.set_value(_("Scale Y"))
self.scaley_button.setToolTip(
_("Scale the selected object(s).\n"
"The point of reference depends on \n"
@@ -194,7 +189,6 @@ class ToolTransform(FlatCAMTool):
grid0.addWidget(self.scaley_button, 9, 2)
self.scale_link_cb = FCCheckBox()
- self.scale_link_cb.set_value(True)
self.scale_link_cb.setText(_("Link"))
self.scale_link_cb.setToolTip(
_("Scale the selected object(s)\n"
@@ -202,7 +196,6 @@ class ToolTransform(FlatCAMTool):
)
self.scale_zero_ref_cb = FCCheckBox()
- self.scale_zero_ref_cb.set_value(True)
self.scale_zero_ref_cb.setText('%s' % _("Scale Reference"))
self.scale_zero_ref_cb.setToolTip(
_("Scale the selected object(s)\n"
@@ -234,7 +227,6 @@ class ToolTransform(FlatCAMTool):
self.offx_entry.setMinimum(-1e6)
self.offx_button = FCButton()
- self.offx_button.set_value(_("Offset X"))
self.offx_button.setToolTip(
_("Offset the selected object(s).\n"
"The point of reference is the middle of\n"
@@ -255,7 +247,6 @@ class ToolTransform(FlatCAMTool):
self.offy_entry.setMinimum(-1e6)
self.offy_button = FCButton()
- self.offy_button.set_value(_("Offset Y"))
self.offy_button.setToolTip(
_("Offset the selected object(s).\n"
"The point of reference is the middle of\n"
@@ -276,13 +267,11 @@ class ToolTransform(FlatCAMTool):
grid0.addWidget(flip_title_label, 16, 0, 1, 3)
self.flipx_button = FCButton()
- self.flipx_button.set_value(_("Flip on X"))
self.flipx_button.setToolTip(
_("Flip the selected object(s) over the X axis.")
)
self.flipy_button = FCButton()
- self.flipy_button.set_value(_("Flip on Y"))
self.flipy_button.setToolTip(
_("Flip the selected object(s) over the X axis.")
)
@@ -294,7 +283,6 @@ class ToolTransform(FlatCAMTool):
hlay0.addWidget(self.flipy_button)
self.flip_ref_cb = FCCheckBox()
- self.flip_ref_cb.set_value(True)
self.flip_ref_cb.setText('%s' % _("Mirror Reference"))
self.flip_ref_cb.setToolTip(
_("Flip the selected object(s)\n"
@@ -320,7 +308,6 @@ class ToolTransform(FlatCAMTool):
# self.flip_ref_entry.setFixedWidth(70)
self.flip_ref_button = FCButton()
- self.flip_ref_button.set_value(_("Add"))
self.flip_ref_button.setToolTip(
_("The point coordinates can be captured by\n"
"left click on canvas together with pressing\n"
@@ -360,7 +347,6 @@ class ToolTransform(FlatCAMTool):
self.buffer_entry.set_range(-9999.9999, 9999.9999)
self.buffer_button = FCButton()
- self.buffer_button.set_value(_("Buffer D"))
self.buffer_button.setToolTip(
_("Create the buffer effect on each geometry,\n"
"element from the selected object, using the distance.")
@@ -387,7 +373,6 @@ class ToolTransform(FlatCAMTool):
self.buffer_factor_entry.setSingleStep(1)
self.buffer_factor_button = FCButton()
- self.buffer_factor_button.set_value(_("Buffer F"))
self.buffer_factor_button.setToolTip(
_("Create the buffer effect on each geometry,\n"
"element from the selected object, using the factor.")
@@ -481,6 +466,22 @@ class ToolTransform(FlatCAMTool):
FlatCAMTool.install(self, icon, separator, shortcut='ALT+T', **kwargs)
def set_tool_ui(self):
+ self.rotate_button.set_value(_("Rotate"))
+ self.skewx_button.set_value(_("Skew X"))
+ self.skewy_button.set_value(_("Skew Y"))
+ self.scalex_button.set_value(_("Scale X"))
+ self.scaley_button.set_value(_("Scale Y"))
+ self.scale_link_cb.set_value(True)
+ self.scale_zero_ref_cb.set_value(True)
+ self.offx_button.set_value(_("Offset X"))
+ self.offy_button.set_value(_("Offset Y"))
+ self.flipx_button.set_value(_("Flip on X"))
+ self.flipy_button.set_value(_("Flip on Y"))
+ self.flip_ref_cb.set_value(True)
+ self.flip_ref_button.set_value(_("Add"))
+ self.buffer_button.set_value(_("Buffer D"))
+ self.buffer_factor_button.set_value(_("Buffer F"))
+
# ## Initialize form
if self.app.defaults["tools_transform_rotate"]:
self.rotate_entry.set_value(self.app.defaults["tools_transform_rotate"])
From 124ba6cdc684b95672967117e4faf0663d2cd93a Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 17 Feb 2020 16:35:09 +0200
Subject: [PATCH 104/209] - adapted the GCode generation from Excellon to work
with multiple tools data and modified the preprocessors header
---
FlatCAMObj.py | 20 ++-
README.md | 1 +
camlib.py | 170 ++++++++++++++++++------
preprocessors/Berta_CNC.py | 57 ++++++--
preprocessors/ISEL_CNC.py | 61 ++++++---
preprocessors/ISEL_ICP_CNC.py | 85 ++++++++----
preprocessors/Marlin.py | 67 +++++++---
preprocessors/Repetier.py | 67 +++++++---
preprocessors/Toolchange_Custom.py | 63 ++++++---
preprocessors/Toolchange_Probe_MACH3.py | 65 ++++++---
preprocessors/Toolchange_manual.py | 63 ++++++---
preprocessors/default.py | 62 ++++++---
preprocessors/grbl_11.py | 69 +++++++---
preprocessors/line_xyz.py | 65 ++++++---
14 files changed, 663 insertions(+), 252 deletions(-)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 4c71180b..f451f30d 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -3673,20 +3673,16 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
job_obj.z_pdepth = float(self.options["z_pdepth"])
job_obj.feedrate_probe = float(self.options["feedrate_probe"])
- # There could be more than one drill size...
- # job_obj.tooldia = # TODO: duplicate variable!
- # job_obj.options["tooldia"] =
+ job_obj.z_cut = float(self.options['cutz'])
+ job_obj.toolchange = self.options["toolchange"]
+ job_obj.xy_toolchange = self.app.defaults["excellon_toolchangexy"]
+ job_obj.z_toolchange = float(self.options["toolchangez"])
+ job_obj.startz = float(self.options["startz"]) if self.options["startz"] else None
+ job_obj.endz = float(self.options["endz"])
+ job_obj.excellon_optimization_type = self.app.defaults["excellon_optimization_type"]
tools_csv = ','.join(tools)
- ret_val = job_obj.generate_from_excellon_by_tool(
- self, tools_csv,
- drillz=float(self.options['cutz']),
- toolchange=self.options["toolchange"],
- toolchangexy=self.app.defaults["excellon_toolchangexy"],
- toolchangez=float(self.options["toolchangez"]),
- startz=float(self.options["startz"]) if self.options["startz"] else None,
- endz=float(self.options["endz"]),
- excellon_optimization_type=self.app.defaults["excellon_optimization_type"])
+ ret_val = job_obj.generate_from_excellon_by_tool(self, tools_csv, use_ui=True)
if ret_val == 'fail':
return 'fail'
diff --git a/README.md b/README.md
index be19c4c3..08c2b639 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,7 @@ CAD program, and create G-Code for Isolation routing.
- in Excellon UI protected the values that are common parameters from change on tool selection change
- fixed some issues realted to the usage of the new confirmation message in FlatCAM Tools
- made sure that the FlatCAM Tools UI initialization is done only in set_tool_ui() method and not in the constructor
+- adapted the GCode generation from Excellon to work with multiple tools data and modified the preprocessors header
16.02.2020
diff --git a/camlib.py b/camlib.py
index f296b113..46877405 100644
--- a/camlib.py
+++ b/camlib.py
@@ -2428,11 +2428,9 @@ class CNCjob(Geometry):
Geometry.__init__(self, geo_steps_per_circle=self.steps_per_circle)
self.kind = kind
-
self.units = units
self.z_cut = z_cut
-
self.z_move = z_move
self.feedrate = feedrate
@@ -2440,6 +2438,7 @@ class CNCjob(Geometry):
self.feedrate_rapid = feedrate_rapid
self.tooldia = tooldia
+ self.toolchange = False
self.z_toolchange = toolchangez
self.xy_toolchange = toolchange_xy
self.toolchange_xy_type = None
@@ -2452,6 +2451,11 @@ class CNCjob(Geometry):
self.multidepth = False
self.z_depthpercut = depthpercut
+ self.excellon_optimization_type = 'B'
+
+ # if set True then the GCode generation will use UI; used in Excellon GVode for now
+ self.use_ui = False
+
self.unitcode = {"IN": "G20", "MM": "G21"}
self.feedminutecode = "G94"
@@ -2504,6 +2508,7 @@ class CNCjob(Geometry):
# used for creating drill CCode geometry; will be updated in the generate_from_excellon_by_tool()
self.exc_drills = None
+ # store here the Excellon source object tools to be accessible locally
self.exc_tools = None
# search for toolchange parameters in the Toolchange Custom Code
@@ -2599,8 +2604,7 @@ class CNCjob(Geometry):
must_visit.remove(nearest)
return path
- def generate_from_excellon_by_tool(self, exobj, tools="all", drillz=3.0, toolchange=False, toolchangez=0.1,
- toolchangexy='', endz=2.0, startz=None, excellon_optimization_type='B'):
+ def generate_from_excellon_by_tool(self, exobj, tools="all", use_ui=False):
"""
Creates gcode for this object from an Excellon object
for the specified tools.
@@ -2609,21 +2613,7 @@ class CNCjob(Geometry):
:type exobj: Excellon
:param tools: Comma separated tool names
:type: tools: str
- :param drillz: drill Z depth
- :type drillz: float
- :param toolchange: Use tool change sequence between tools.
- :type toolchange: bool
- :param toolchangez: Height at which to perform the tool change.
- :type toolchangez: float
- :param toolchangexy: Toolchange X,Y position
- :type toolchangexy: String containing 2 floats separated by comma
- :param startz: Z position just before starting the job
- :type startz: float
- :param endz: final Z position to move to at the end of the CNC job
- :type endz: float
- :param excellon_optimization_type: Single character that defines which drill re-ordering optimisation algorithm
- is to be used: 'M' for meta-heuristic and 'B' for basic
- :type excellon_optimization_type: string
+ :param use_ui: Bool, if True the method will use parameters set in UI
:return: None
:rtype: None
"""
@@ -2632,31 +2622,31 @@ class CNCjob(Geometry):
self.exc_drills = deepcopy(exobj.drills)
self.exc_tools = deepcopy(exobj.tools)
- self.z_cut = deepcopy(drillz)
- old_zcut = deepcopy(drillz)
+ # the Excellon GCode preprocessor will use this info in the start_code() method
+ self.use_ui = True if use_ui else False
+
+ old_zcut = deepcopy(self.z_cut)
if self.machinist_setting == 0:
- if drillz > 0:
+ if self.z_cut > 0:
self.app.inform.emit('[WARNING] %s' %
_("The Cut Z parameter has positive value. "
"It is the depth value to drill into material.\n"
"The Cut Z parameter needs to have a negative value, assuming it is a typo "
"therefore the app will convert the value to negative. "
"Check the resulting CNC code (Gcode etc)."))
- self.z_cut = -drillz
- elif drillz == 0:
+ self.z_cut = -self.z_cut
+ elif self.z_cut == 0:
self.app.inform.emit('[WARNING] %s: %s' %
(_("The Cut Z parameter is zero. There will be no cut, skipping file"),
exobj.options['name']))
return 'fail'
- self.z_toolchange = toolchangez
-
try:
- if toolchangexy == '':
+ if self.xy_toolchange == '':
self.xy_toolchange = None
else:
- self.xy_toolchange = [float(eval(a)) for a in toolchangexy.split(",")]
+ self.xy_toolchange = [float(eval(a)) for a in self.xy_toolchange.split(",")]
if len(self.xy_toolchange) < 2:
self.app.inform.emit('[ERROR]%s' %
_("The Toolchange X,Y field in Edit -> Preferences has to be "
@@ -2666,9 +2656,6 @@ class CNCjob(Geometry):
log.debug("camlib.CNCJob.generate_from_excellon_by_tool() --> %s" % str(e))
pass
- self.startz = startz
- self.z_end = endz
-
self.pp_excellon = self.app.preprocessors[self.pp_excellon_name]
p = self.pp_excellon
@@ -2751,6 +2738,7 @@ class CNCjob(Geometry):
)
self.app.inform.emit(_("Creating a list of points to drill..."))
+
# Points (Group by tool)
points = dict()
for drill in exobj.drills:
@@ -2773,9 +2761,10 @@ class CNCjob(Geometry):
# Initialization
gcode = self.doformat(p.start_code)
- gcode += self.doformat(p.feedrate_code)
+ if not use_ui:
+ gcode += self.doformat(p.z_feedrate_code)
- if toolchange is False:
+ if self.toolchange is False:
if self.xy_toolchange is not None:
gcode += self.doformat(p.lift_code, x=self.xy_toolchange[0], y=self.xy_toolchange[1])
gcode += self.doformat(p.startz_code, x=self.xy_toolchange[0], y=self.xy_toolchange[1])
@@ -2836,18 +2825,50 @@ class CNCjob(Geometry):
current_platform = platform.architecture()[0]
if current_platform == '64bit':
- used_excellon_optimization_type = excellon_optimization_type
+ used_excellon_optimization_type = self.excellon_optimization_type
if used_excellon_optimization_type == 'M':
log.debug("Using OR-Tools Metaheuristic Guided Local Search drill path optimization.")
if exobj.drills:
for tool in tools:
+ if self.app.abort_flag:
+ # graceful abort requested by the user
+ raise FlatCAMApp.GracefulException
+
self.tool = tool
self.postdata['toolC'] = exobj.tools[tool]["C"]
self.tooldia = exobj.tools[tool]["C"]
- if self.app.abort_flag:
- # graceful abort requested by the user
- raise FlatCAMApp.GracefulException
+ if use_ui:
+ self.z_feedrate = exobj.tools[tool]['data']['feedrate_z']
+ self.feedrate = exobj.tools[tool]['data']['feedrate']
+ gcode += self.doformat(p.z_feedrate_code)
+
+ self.z_cut = exobj.tools[tool]['data']['cutz']
+
+ if self.machinist_setting == 0:
+ if self.z_cut > 0:
+ self.app.inform.emit('[WARNING] %s' %
+ _("The Cut Z parameter has positive value. "
+ "It is the depth value to drill into material.\n"
+ "The Cut Z parameter needs to have a negative value, assuming it is a typo "
+ "therefore the app will convert the value to negative. "
+ "Check the resulting CNC code (Gcode etc)."))
+ self.z_cut = -self.z_cut
+ elif self.z_cut == 0:
+ self.app.inform.emit('[WARNING] %s: %s' %
+ (_(
+ "The Cut Z parameter is zero. There will be no cut, skipping file"),
+ exobj.options['name']))
+ return 'fail'
+
+ old_zcut = deepcopy(self.z_cut)
+
+ self.z_move = exobj.tools[tool]['data']['travelz']
+ self.spindlespeed = exobj.tools[tool]['data']['spindlespeed']
+ self.dwell = exobj.tools[tool]['data']['dwell']
+ self.dwelltime = exobj.tools[tool]['data']['dwelltime']
+ self.multidepth = exobj.tools[tool]['data']['multidepth']
+ self.z_depthpercut = exobj.tools[tool]['data']['depthperpass']
# ###############################################
# ############ Create the data. #################
@@ -2914,7 +2935,7 @@ class CNCjob(Geometry):
raise FlatCAMApp.GracefulException
# Tool change sequence (optional)
- if toolchange:
+ if self.toolchange:
gcode += self.doformat(p.toolchange_code, toolchangexy=(self.oldx, self.oldy))
gcode += self.doformat(p.spindle_code) # Spindle start
if self.dwell is True:
@@ -3031,7 +3052,42 @@ class CNCjob(Geometry):
self.postdata['toolC']=exobj.tools[tool]["C"]
self.tooldia = exobj.tools[tool]["C"]
- # ############################################# ##
+ if use_ui:
+ self.z_feedrate = exobj.tools[tool]['data']['feedrate_z']
+ self.feedrate = exobj.tools[tool]['data']['feedrate']
+ gcode += self.doformat(p.z_feedrate_code)
+ self.z_cut = exobj.tools[tool]['data']['cutz']
+
+ if self.machinist_setting == 0:
+ if self.z_cut > 0:
+ self.app.inform.emit('[WARNING] %s' %
+ _("The Cut Z parameter has positive value. "
+ "It is the depth value to drill into material.\n"
+ "The Cut Z parameter needs to have a negative value, assuming it is a typo "
+ "therefore the app will convert the value to negative. "
+ "Check the resulting CNC code (Gcode etc)."))
+ self.z_cut = -self.z_cut
+ elif self.z_cut == 0:
+ self.app.inform.emit('[WARNING] %s: %s' %
+ (_(
+ "The Cut Z parameter is zero. There will be no cut, skipping file"),
+ exobj.options['name']))
+ return 'fail'
+
+ old_zcut = deepcopy(self.z_cut)
+
+ self.z_move = exobj.tools[tool]['data']['travelz']
+ print(self.z_move)
+ self.spindlespeed = exobj.tools[tool]['data']['spindlespeed']
+ self.dwell = exobj.tools[tool]['data']['dwell']
+ self.dwelltime = exobj.tools[tool]['data']['dwelltime']
+ self.multidepth = exobj.tools[tool]['data']['multidepth']
+ self.z_depthpercut = exobj.tools[tool]['data']['depthperpass']
+
+ # ###############################################
+ # ############ Create the data. #################
+ # ###############################################
+
node_list = []
locations = create_data_array()
tsp_size = len(locations)
@@ -3082,7 +3138,7 @@ class CNCjob(Geometry):
raise FlatCAMApp.GracefulException
# Tool change sequence (optional)
- if toolchange:
+ if self.toolchange:
gcode += self.doformat(p.toolchange_code, toolchangexy=(self.oldx, self.oldy))
gcode += self.doformat(p.spindle_code) # Spindle start)
if self.dwell is True:
@@ -3201,6 +3257,38 @@ class CNCjob(Geometry):
self.postdata['toolC'] = exobj.tools[tool]["C"]
self.tooldia = exobj.tools[tool]["C"]
+ if use_ui:
+ self.z_feedrate = exobj.tools[tool]['data']['feedrate_z']
+ self.feedrate = exobj.tools[tool]['data']['feedrate']
+ gcode += self.doformat(p.z_feedrate_code)
+
+ self.z_cut = exobj.tools[tool]['data']['cutz']
+
+ if self.machinist_setting == 0:
+ if self.z_cut > 0:
+ self.app.inform.emit('[WARNING] %s' %
+ _("The Cut Z parameter has positive value. "
+ "It is the depth value to drill into material.\n"
+ "The Cut Z parameter needs to have a negative value, assuming it is a typo "
+ "therefore the app will convert the value to negative. "
+ "Check the resulting CNC code (Gcode etc)."))
+ self.z_cut = -self.z_cut
+ elif self.z_cut == 0:
+ self.app.inform.emit('[WARNING] %s: %s' %
+ (_(
+ "The Cut Z parameter is zero. There will be no cut, skipping file"),
+ exobj.options['name']))
+ return 'fail'
+
+ old_zcut = deepcopy(self.z_cut)
+
+ self.z_move = exobj.tools[tool]['data']['travelz']
+ self.spindlespeed = exobj.tools[tool]['data']['spindlespeed']
+ self.dwell = exobj.tools[tool]['data']['dwell']
+ self.dwelltime = exobj.tools[tool]['data']['dwelltime']
+ self.multidepth = exobj.tools[tool]['data']['multidepth']
+ self.z_depthpercut = exobj.tools[tool]['data']['depthperpass']
+
# Only if tool has points.
if tool in points:
if self.app.abort_flag:
@@ -3208,7 +3296,7 @@ class CNCjob(Geometry):
raise FlatCAMApp.GracefulException
# Tool change sequence (optional)
- if toolchange:
+ if self.toolchange:
gcode += self.doformat(p.toolchange_code, toolchangexy=(self.oldx, self.oldy))
gcode += self.doformat(p.spindle_code) # Spindle start)
if self.dwell is True:
diff --git a/preprocessors/Berta_CNC.py b/preprocessors/Berta_CNC.py
index 6da9d5d6..18f84578 100644
--- a/preprocessors/Berta_CNC.py
+++ b/preprocessors/Berta_CNC.py
@@ -35,24 +35,57 @@ class Berta_CNC(FlatCAMPostProc):
gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n'
if str(p['options']['type']) == 'Geometry':
+ gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n'
+ gcode += '(Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + ')\n'
gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n'
-
- gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
- gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
-
- if str(p['options']['type']) == 'Geometry':
+ gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
+ gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
if p['multidepth'] is True:
gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
- gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
- gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
+ elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
+ gcode += '\n(TOOLS DIAMETER: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + ')\n'
- if coords_xy is not None:
- gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
- p.decimals, coords_xy[1]) + units + ')\n'
- else:
- gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
+ gcode += '\n(FEEDRATE Z: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
+
+ gcode += '\n(FEEDRATE RAPIDS: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
+ str(val['data']["feedrate_rapid"]) + ')\n'
+
+ gcode += '\n(Z_CUT: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + ')\n'
+
+ gcode += '\n(Tools Offset: )\n'
+ for tool, val in p['exc_cnc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + ')\n'
+
+ if p['multidepth'] is True:
+ gcode += '\n(DEPTH_PER_CUT: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
+ str(val['data']["depthperpass"]) + ')\n'
+
+ gcode += '\n(Z_MOVE: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + ')\n'
+ gcode += '\n'
+
+ if p['toolchange'] is True:
+ gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
+
+ if coords_xy is not None:
+ gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
+ p.decimals, coords_xy[1]) + units + ')\n'
+ else:
+ gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
gcode += '(Z Start: ' + str(p['startz']) + units + ')\n'
gcode += '(Z End: ' + str(p['z_end']) + units + ')\n'
diff --git a/preprocessors/ISEL_CNC.py b/preprocessors/ISEL_CNC.py
index 2e20c06e..e8225b8e 100644
--- a/preprocessors/ISEL_CNC.py
+++ b/preprocessors/ISEL_CNC.py
@@ -26,27 +26,56 @@ class ISEL_CNC(FlatCAMPostProc):
if str(p['options']['type']) == 'Geometry':
gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n'
-
- gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n'
-
- if str(p['options']['type']) == 'Geometry':
+ gcode += '(Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + ')\n'
gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n'
+ gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
+ gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
+ if p['multidepth'] is True:
+ gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
- gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
- gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
+ elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
+ gcode += '\n(TOOLS DIAMETER: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + ')\n'
- if p['multidepth'] is True:
- gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ gcode += '\n(FEEDRATE Z: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
- gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
- gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
+ gcode += '\n(FEEDRATE RAPIDS: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
+ str(val['data']["feedrate_rapid"]) + ')\n'
- if coords_xy is not None:
- gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
- p.decimals, coords_xy[1]) + units + ')\n'
- else:
- gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
+ gcode += '\n(Z_CUT: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + ')\n'
+
+ gcode += '\n(Tools Offset: )\n'
+ for tool, val in p['exc_cnc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + ')\n'
+
+ if p['multidepth'] is True:
+ gcode += '\n(DEPTH_PER_CUT: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
+ str(val['data']["depthperpass"]) + ')\n'
+
+ gcode += '\n(Z_MOVE: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + ')\n'
+ gcode += '\n'
+
+ if p['toolchange'] is True:
+ gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
+
+ if coords_xy is not None:
+ gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
+ p.decimals, coords_xy[1]) + units + ')\n'
+ else:
+ gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
gcode += '(Z Start: ' + str(p['startz']) + units + ')\n'
gcode += '(Z End: ' + str(p['z_end']) + units + ')\n'
diff --git a/preprocessors/ISEL_ICP_CNC.py b/preprocessors/ISEL_ICP_CNC.py
index 92a08691..a6a137f8 100644
--- a/preprocessors/ISEL_ICP_CNC.py
+++ b/preprocessors/ISEL_ICP_CNC.py
@@ -25,36 +25,71 @@ class ISEL_ICP_CNC(FlatCAMPostProc):
gcode += 'IMF_PBL flatcam\n\n'
if str(p['options']['type']) == 'Geometry':
- gcode += '; TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + '\n'
- gcode += '; Spindle Speed: %s RPM\n' % str(p['spindlespeed'])
- gcode += '; Feedrate: ' + str(p['feedrate']) + units + '/min' + '\n'
- if str(p['options']['type']) == 'Geometry':
- gcode += '; Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + '\n'
- gcode += '\n'
- gcode += '; Z_Cut: ' + str(p['z_cut']) + units + '\n'
+ gcode += ';TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + '\n'
+ gcode += ';Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + '\n'
+ gcode += ';Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + '\n'
+ gcode += ';Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + '\n' + '\n'
+ gcode += ';Z_Cut: ' + str(p['z_cut']) + units + '\n'
+ if p['multidepth'] is True:
+ gcode += ';DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + '\n'
+ gcode += ';Z_Move: ' + str(p['z_move']) + units + '\n'
- if p['multidepth'] is True:
- gcode += '; DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + '\n'
+ elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
+ gcode += '\n;TOOLS DIAMETER: \n'
+ for tool, val in p['exc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + '\n'
+
+ gcode += '\n;FEEDRATE Z: \n'
+ for tool, val in p['exc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + '\n'
+
+ gcode += '\n;FEEDRATE RAPIDS: \n'
+ for tool, val in p['exc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
+ str(val['data']["feedrate_rapid"]) + '\n'
+
+ gcode += '\n;Z_CUT: \n'
+ for tool, val in p['exc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + '\n'
+
+ gcode += '\n;Tools Offset: \n'
+ for tool, val in p['exc_cnc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + '\n'
+
+ if p['multidepth'] is True:
+ gcode += '\n;DEPTH_PER_CUT: \n'
+ for tool, val in p['exc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
+ str(val['data']["depthperpass"]) + '\n'
+
+ gcode += '\n;Z_MOVE: \n'
+ for tool, val in p['exc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + '\n'
+ gcode += '\n'
+
+ if p['toolchange'] is True:
+ gcode += ';Z Toolchange: ' + str(p['z_toolchange']) + units + '\n'
+
+ if coords_xy is not None:
+ gcode += ';X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
+ p.decimals, coords_xy[1]) + units + '\n'
+ else:
+ gcode += ';X,Y Toolchange: ' + "None" + units + '\n'
+
+ gcode += ';Z Start: ' + str(p['startz']) + units + '\n'
+ gcode += ';Z End: ' + str(p['z_end']) + units + '\n'
+ gcode += ';Steps per circle: ' + str(p['steps_per_circle']) + '\n'
- gcode += '; Z_Move: ' + str(p['z_move']) + units + '\n'
- gcode += '; Z Toolchange: ' + str(p['z_toolchange']) + units + '\n'
- if coords_xy is not None:
- gcode += '; X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
- p.decimals, coords_xy[1]) + units + '\n'
- else:
- gcode += '; X,Y Toolchange: ' + "None" + units + '\n'
- gcode += '; Z Start: ' + str(p['startz']) + units + '\n'
- gcode += '; Z End: ' + str(p['z_end']) + units + '\n'
- gcode += '; Steps per circle: ' + str(p['steps_per_circle']) + '\n'
if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
- gcode += '; Preprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n'
+ gcode += ';Preprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n' + '\n'
else:
- gcode += '; Preprocessor Geometry: ' + str(p['pp_geometry_name']) + '\n'
- gcode += '\n'
+ gcode += ';Preprocessor Geometry: ' + str(p['pp_geometry_name']) + '\n' + '\n'
- gcode += '; X range: ' + '{: >9s}'.format(xmin) + ' ... ' + '{: >9s}'.format(xmax) + ' ' + units + '\n'
- gcode += '; Y range: ' + '{: >9s}'.format(ymin) + ' ... ' + '{: >9s}'.format(ymax) + ' ' + units + '\n'
+ gcode += ';X range: ' + '{: >9s}'.format(xmin) + ' ... ' + '{: >9s}'.format(xmax) + ' ' + units + '\n'
+ gcode += ';Y range: ' + '{: >9s}'.format(ymin) + ' ... ' + '{: >9s}'.format(ymax) + ' ' + units + '\n\n'
+
+ gcode += ';Spindle Speed: %s RPM)\n' % str(p['spindlespeed'])
return gcode
diff --git a/preprocessors/Marlin.py b/preprocessors/Marlin.py
index d5144d59..aaf9079d 100644
--- a/preprocessors/Marlin.py
+++ b/preprocessors/Marlin.py
@@ -27,42 +27,71 @@ class Marlin(FlatCAMPostProc):
ymax = '%.*f' % (p.coords_decimals, p['options']['ymax'])
if str(p['options']['type']) == 'Geometry':
- gcode += ';TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + '\n' + '\n'
-
- gcode += ';Feedrate: ' + str(p['feedrate']) + units + '/min' + '\n'
-
- if str(p['options']['type']) == 'Geometry':
+ gcode += ';TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + '\n'
+ gcode += ';Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + '\n'
gcode += ';Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + '\n'
+ gcode += ';Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + '\n' + '\n'
+ gcode += ';Z_Cut: ' + str(p['z_cut']) + units + '\n'
+ if p['multidepth'] is True:
+ gcode += ';DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + '\n'
+ gcode += ';Z_Move: ' + str(p['z_move']) + units + '\n'
- gcode += ';Feedrate rapids: ' + str(p['feedrate_rapid']) + units + '/min' + '\n' + '\n'
- gcode += ';Z_Cut: ' + str(p['z_cut']) + units + '\n'
+ elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
+ gcode += '\n;TOOLS DIAMETER: \n'
+ for tool, val in p['exc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + '\n'
- if p['multidepth'] is True:
- gcode += ';DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + '\n'
+ gcode += '\n;FEEDRATE Z: \n'
+ for tool, val in p['exc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + '\n'
- gcode += ';Z_Move: ' + str(p['z_move']) + units + '\n'
- gcode += ';Z Toolchange: ' + str(p['z_toolchange']) + units + '\n'
+ gcode += '\n;FEEDRATE RAPIDS: \n'
+ for tool, val in p['exc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
+ str(val['data']["feedrate_rapid"]) + '\n'
- if coords_xy is not None:
- gcode += ';X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
- p.decimals, coords_xy[1]) + units + '\n'
- else:
- gcode += ';X,Y Toolchange: ' + "None" + units + '\n'
+ gcode += '\n;Z_CUT: \n'
+ for tool, val in p['exc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + '\n'
+
+ gcode += '\n;Tools Offset: \n'
+ for tool, val in p['exc_cnc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + '\n'
+
+ if p['multidepth'] is True:
+ gcode += '\n;DEPTH_PER_CUT: \n'
+ for tool, val in p['exc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
+ str(val['data']["depthperpass"]) + '\n'
+
+ gcode += '\n;Z_MOVE: \n'
+ for tool, val in p['exc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + '\n'
+ gcode += '\n'
+
+ if p['toolchange'] is True:
+ gcode += ';Z Toolchange: ' + str(p['z_toolchange']) + units + '\n'
+
+ if coords_xy is not None:
+ gcode += ';X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
+ p.decimals, coords_xy[1]) + units + '\n'
+ else:
+ gcode += ';X,Y Toolchange: ' + "None" + units + '\n'
gcode += ';Z Start: ' + str(p['startz']) + units + '\n'
gcode += ';Z End: ' + str(p['z_end']) + units + '\n'
gcode += ';Steps per circle: ' + str(p['steps_per_circle']) + '\n'
if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
- gcode += ';Preprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n'
+ gcode += ';Preprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n' + '\n'
else:
gcode += ';Preprocessor Geometry: ' + str(p['pp_geometry_name']) + '\n' + '\n'
gcode += ';X range: ' + '{: >9s}'.format(xmin) + ' ... ' + '{: >9s}'.format(xmax) + ' ' + units + '\n'
gcode += ';Y range: ' + '{: >9s}'.format(ymin) + ' ... ' + '{: >9s}'.format(ymax) + ' ' + units + '\n\n'
- gcode += ';Spindle Speed: ' + str(p['spindlespeed']) + ' RPM' + '\n' + '\n'
+ gcode += ';Spindle Speed: %s RPM)\n' % str(p['spindlespeed'])
gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n"
gcode += 'G90'
diff --git a/preprocessors/Repetier.py b/preprocessors/Repetier.py
index 3d31a176..ea15317e 100644
--- a/preprocessors/Repetier.py
+++ b/preprocessors/Repetier.py
@@ -27,42 +27,71 @@ class Repetier(FlatCAMPostProc):
ymax = '%.*f' % (p.coords_decimals, p['options']['ymax'])
if str(p['options']['type']) == 'Geometry':
- gcode += ';TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + '\n' + '\n'
-
- gcode += ';Feedrate: ' + str(p['feedrate']) + units + '/min' + '\n'
-
- if str(p['options']['type']) == 'Geometry':
+ gcode += ';TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + '\n'
+ gcode += ';Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + '\n'
gcode += ';Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + '\n'
+ gcode += ';Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + '\n' + '\n'
+ gcode += ';Z_Cut: ' + str(p['z_cut']) + units + '\n'
+ if p['multidepth'] is True:
+ gcode += ';DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + '\n'
+ gcode += ';Z_Move: ' + str(p['z_move']) + units + '\n'
- gcode += ';Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + '\n' + '\n'
- gcode += ';Z_Cut: ' + str(p['z_cut']) + units + '\n'
+ elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
+ gcode += '\n;TOOLS DIAMETER: \n'
+ for tool, val in p['exc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + '\n'
- if p['multidepth'] is True:
- gcode += ';DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + '\n'
+ gcode += '\n;FEEDRATE Z: \n'
+ for tool, val in p['exc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + '\n'
- gcode += ';Z_Move: ' + str(p['z_move']) + units + '\n'
- gcode += ';Z Toolchange: ' + str(p['z_toolchange']) + units + '\n'
+ gcode += '\n;FEEDRATE RAPIDS: \n'
+ for tool, val in p['exc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
+ str(val['data']["feedrate_rapid"]) + '\n'
- if coords_xy is not None:
- gcode += ';X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
- p.decimals, coords_xy[1]) + units + '\n'
- else:
- gcode += ';X,Y Toolchange: ' + "None" + units + '\n'
+ gcode += '\n;Z_CUT: \n'
+ for tool, val in p['exc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + '\n'
+
+ gcode += '\n;Tools Offset: \n'
+ for tool, val in p['exc_cnc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + '\n'
+
+ if p['multidepth'] is True:
+ gcode += '\n;DEPTH_PER_CUT: \n'
+ for tool, val in p['exc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
+ str(val['data']["depthperpass"]) + '\n'
+
+ gcode += '\n;Z_MOVE: \n'
+ for tool, val in p['exc_tools'].items():
+ gcode += ';Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + '\n'
+ gcode += '\n'
+
+ if p['toolchange'] is True:
+ gcode += ';Z Toolchange: ' + str(p['z_toolchange']) + units + '\n'
+
+ if coords_xy is not None:
+ gcode += ';X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
+ p.decimals, coords_xy[1]) + units + '\n'
+ else:
+ gcode += ';X,Y Toolchange: ' + "None" + units + '\n'
gcode += ';Z Start: ' + str(p['startz']) + units + '\n'
gcode += ';Z End: ' + str(p['z_end']) + units + '\n'
gcode += ';Steps per circle: ' + str(p['steps_per_circle']) + '\n'
if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
- gcode += ';Preprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n'
+ gcode += ';Preprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n' + '\n'
else:
gcode += ';Preprocessor Geometry: ' + str(p['pp_geometry_name']) + '\n' + '\n'
gcode += ';X range: ' + '{: >9s}'.format(xmin) + ' ... ' + '{: >9s}'.format(xmax) + ' ' + units + '\n'
gcode += ';Y range: ' + '{: >9s}'.format(ymin) + ' ... ' + '{: >9s}'.format(ymax) + ' ' + units + '\n\n'
- gcode += ';Spindle Speed: ' + str(p['spindlespeed']) + ' RPM' + '\n' + '\n'
+ gcode += ';Spindle Speed: %s RPM)\n' % str(p['spindlespeed'])
gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n"
gcode += 'G90\n'
diff --git a/preprocessors/Toolchange_Custom.py b/preprocessors/Toolchange_Custom.py
index 162defbb..5c22b85a 100644
--- a/preprocessors/Toolchange_Custom.py
+++ b/preprocessors/Toolchange_Custom.py
@@ -27,34 +27,63 @@ class Toolchange_Custom(FlatCAMPostProc):
if str(p['options']['type']) == 'Geometry':
gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n'
-
- gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n'
-
- if str(p['options']['type']) == 'Geometry':
+ gcode += '(Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + ')\n'
gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n'
+ gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
+ gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
+ if p['multidepth'] is True:
+ gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
- gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
- gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
+ elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
+ gcode += '\n(TOOLS DIAMETER: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + ')\n'
- if p['multidepth'] is True:
- gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ gcode += '\n(FEEDRATE Z: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
- gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
- gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
+ gcode += '\n(FEEDRATE RAPIDS: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
+ str(val['data']["feedrate_rapid"]) + ')\n'
- if coords_xy is not None:
- gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
- p.decimals, coords_xy[1]) + units + ')\n'
- else:
- gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
+ gcode += '\n(Z_CUT: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + ')\n'
+
+ gcode += '\n(Tools Offset: )\n'
+ for tool, val in p['exc_cnc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + ')\n'
+
+ if p['multidepth'] is True:
+ gcode += '\n(DEPTH_PER_CUT: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
+ str(val['data']["depthperpass"]) + ')\n'
+
+ gcode += '\n(Z_MOVE: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + ')\n'
+ gcode += '\n'
+
+ if p['toolchange'] is True:
+ gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
+
+ if coords_xy is not None:
+ gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
+ p.decimals, coords_xy[1]) + units + ')\n'
+ else:
+ gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
gcode += '(Z Start: ' + str(p['startz']) + units + ')\n'
gcode += '(Z End: ' + str(p['z_end']) + units + ')\n'
gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n'
if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
- gcode += '(Preprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n'
+ gcode += '(Preprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n' + '\n'
else:
gcode += '(Preprocessor Geometry: ' + str(p['pp_geometry_name']) + ')\n' + '\n'
diff --git a/preprocessors/Toolchange_Probe_MACH3.py b/preprocessors/Toolchange_Probe_MACH3.py
index 3f0bb7c8..3d4c95f8 100644
--- a/preprocessors/Toolchange_Probe_MACH3.py
+++ b/preprocessors/Toolchange_Probe_MACH3.py
@@ -27,36 +27,63 @@ class Toolchange_Probe_MACH3(FlatCAMPostProc):
if str(p['options']['type']) == 'Geometry':
gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n'
-
- gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n'
-
- if str(p['options']['type']) == 'Geometry':
+ gcode += '(Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + ')\n'
gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n'
+ gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
+ gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
+ if p['multidepth'] is True:
+ gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
- gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
- gcode += '(Feedrate Probe ' + str(p['feedrate_probe']) + units + '/min' + ')\n' + '\n'
- gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
+ elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
+ gcode += '\n(TOOLS DIAMETER: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + ')\n'
- if p['multidepth'] is True:
- gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ gcode += '\n(FEEDRATE Z: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
- gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
- gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
+ gcode += '\n(FEEDRATE RAPIDS: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
+ str(val['data']["feedrate_rapid"]) + ')\n'
- if coords_xy is not None:
- gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
- p.decimals, coords_xy[1]) + units + ')\n'
- else:
- gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
+ gcode += '\n(Z_CUT: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + ')\n'
+
+ gcode += '\n(Tools Offset: )\n'
+ for tool, val in p['exc_cnc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + ')\n'
+
+ if p['multidepth'] is True:
+ gcode += '\n(DEPTH_PER_CUT: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
+ str(val['data']["depthperpass"]) + ')\n'
+
+ gcode += '\n(Z_MOVE: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + ')\n'
+ gcode += '\n'
+
+ if p['toolchange'] is True:
+ gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
+
+ if coords_xy is not None:
+ gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
+ p.decimals, coords_xy[1]) + units + ')\n'
+ else:
+ gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
gcode += '(Z Start: ' + str(p['startz']) + units + ')\n'
gcode += '(Z End: ' + str(p['z_end']) + units + ')\n'
- gcode += '(Z Probe Depth: ' + str(p['z_pdepth']) + units + ')\n'
gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n'
if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
- gcode += '(Preprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n'
+ gcode += '(Preprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n' + '\n'
else:
gcode += '(Preprocessor Geometry: ' + str(p['pp_geometry_name']) + ')\n' + '\n'
diff --git a/preprocessors/Toolchange_manual.py b/preprocessors/Toolchange_manual.py
index f096ab25..fceef14c 100644
--- a/preprocessors/Toolchange_manual.py
+++ b/preprocessors/Toolchange_manual.py
@@ -27,26 +27,57 @@ class Toolchange_manual(FlatCAMPostProc):
if str(p['options']['type']) == 'Geometry':
gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n'
-
- gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n'
-
- if str(p['options']['type']) == 'Geometry':
+ gcode += '(Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + ')\n'
gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n'
+ gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
+ gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
+ if p['multidepth'] is True:
+ gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
- gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
- gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
+ elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
+ gcode += '\n(TOOLS DIAMETER: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + ')\n'
- if p['multidepth'] is True:
- gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ gcode += '\n(FEEDRATE Z: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
+
+ gcode += '\n(FEEDRATE RAPIDS: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
+ str(val['data']["feedrate_rapid"]) + ')\n'
+
+ gcode += '\n(Z_CUT: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + ')\n'
+
+ gcode += '\n(Tools Offset: )\n'
+ for tool, val in p['exc_cnc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + ')\n'
+
+ if p['multidepth'] is True:
+ gcode += '\n(DEPTH_PER_CUT: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
+ str(val['data']["depthperpass"]) + ')\n'
+
+ gcode += '\n(Z_MOVE: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + ')\n'
+ gcode += '\n'
+
+ if p['toolchange'] is True:
+ gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
+
+ if coords_xy is not None:
+ gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
+ p.decimals, coords_xy[1]) + units + ')\n'
+ else:
+ gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
- gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
- gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
- if coords_xy is not None:
- gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
- p.decimals, coords_xy[1]) + units + ')\n'
- else:
- gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
gcode += '(Z Start: ' + str(p['startz']) + units + ')\n'
gcode += '(Z End: ' + str(p['z_end']) + units + ')\n'
gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n'
diff --git a/preprocessors/default.py b/preprocessors/default.py
index 640620f6..f46ff824 100644
--- a/preprocessors/default.py
+++ b/preprocessors/default.py
@@ -28,34 +28,56 @@ class default(FlatCAMPostProc):
if str(p['options']['type']) == 'Geometry':
gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n'
-
- gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n'
-
- if str(p['options']['type']) == 'Geometry':
+ gcode += '(Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + ')\n'
gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n'
+ gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
+ gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
+ if p['multidepth'] is True:
+ gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
- gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
- gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
+ elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
+ gcode += '\n(TOOLS DIAMETER: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + ')\n'
+
+ gcode += '\n(FEEDRATE Z: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
+
+ gcode += '\n(FEEDRATE RAPIDS: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
+ str(val['data']["feedrate_rapid"]) + ')\n'
+
+ gcode += '\n(Z_CUT: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + ')\n'
- if str(p['options']['type']) == 'Excellon':
gcode += '\n(Tools Offset: )\n'
for tool, val in p['exc_cnc_tools'].items():
- gcode += '(Tool: %s -> ' % str(val['tool']) + 'Dia: %s -> ' % str(tool) + \
- 'Offset Z: %s' % str(val['offset_z']) + ')\n'
+ gcode += '(Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + ')\n'
+
+ if p['multidepth'] is True:
+ gcode += '\n(DEPTH_PER_CUT: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
+ str(val['data']["depthperpass"]) + ')\n'
+
+ gcode += '\n(Z_MOVE: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + ')\n'
gcode += '\n'
- if p['multidepth'] is True:
- gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ if p['toolchange'] is True:
+ gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
- gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
- gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
-
- if coords_xy is not None:
- gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
- p.decimals, coords_xy[1]) + units + ')\n'
- else:
- gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
+ if coords_xy is not None:
+ gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
+ p.decimals, coords_xy[1]) + units + ')\n'
+ else:
+ gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
gcode += '(Z Start: ' + str(p['startz']) + units + ')\n'
gcode += '(Z End: ' + str(p['z_end']) + units + ')\n'
diff --git a/preprocessors/grbl_11.py b/preprocessors/grbl_11.py
index 9fc8676b..0d4cf868 100644
--- a/preprocessors/grbl_11.py
+++ b/preprocessors/grbl_11.py
@@ -27,40 +27,71 @@ class grbl_11(FlatCAMPostProc):
ymax = '%.*f' % (p.coords_decimals, p['options']['ymax'])
if str(p['options']['type']) == 'Geometry':
- gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n' + '\n'
-
- gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n'
-
- if str(p['options']['type']) == 'Geometry':
+ gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n'
+ gcode += '(Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + ')\n'
gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n'
+ gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
+ gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
+ if p['multidepth'] is True:
+ gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
- gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
- gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
+ elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
+ gcode += '\n(TOOLS DIAMETER: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + ')\n'
- if p['multidepth'] is True:
- gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ gcode += '\n(FEEDRATE Z: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
+
+ gcode += '\n(FEEDRATE RAPIDS: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
+ str(val['data']["feedrate_rapid"]) + ')\n'
+
+ gcode += '\n(Z_CUT: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + ')\n'
+
+ gcode += '\n(Tools Offset: )\n'
+ for tool, val in p['exc_cnc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + ')\n'
+
+ if p['multidepth'] is True:
+ gcode += '\n(DEPTH_PER_CUT: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
+ str(val['data']["depthperpass"]) + ')\n'
+
+ gcode += '\n(Z_MOVE: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + ')\n'
+ gcode += '\n'
+
+ if p['toolchange'] is True:
+ gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
+
+ if coords_xy is not None:
+ gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
+ p.decimals, coords_xy[1]) + units + ')\n'
+ else:
+ gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
- gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
- gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
- if coords_xy is not None:
- gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
- p.decimals, coords_xy[1]) + units + ')\n'
- else:
- gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
gcode += '(Z Start: ' + str(p['startz']) + units + ')\n'
gcode += '(Z End: ' + str(p['z_end']) + units + ')\n'
gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n'
if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
- gcode += '(Preprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n'
+ gcode += '(Preprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n' + '\n'
else:
gcode += '(Preprocessor Geometry: ' + str(p['pp_geometry_name']) + ')\n' + '\n'
gcode += '(X range: ' + '{: >9s}'.format(xmin) + ' ... ' + '{: >9s}'.format(xmax) + ' ' + units + ')\n'
gcode += '(Y range: ' + '{: >9s}'.format(ymin) + ' ... ' + '{: >9s}'.format(ymax) + ' ' + units + ')\n\n'
- gcode += '(Spindle Speed: ' + str(p['spindlespeed']) + ' RPM' + ')\n' + '\n'
+ gcode += '(Spindle Speed: %s RPM)\n' % str(p['spindlespeed'])
gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n"
gcode += 'G90\n'
diff --git a/preprocessors/line_xyz.py b/preprocessors/line_xyz.py
index b6130729..d7cebb7f 100644
--- a/preprocessors/line_xyz.py
+++ b/preprocessors/line_xyz.py
@@ -27,32 +27,63 @@ class line_xyz(FlatCAMPostProc):
if str(p['options']['type']) == 'Geometry':
gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n'
-
- gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n'
-
- if str(p['options']['type']) == 'Geometry':
+ gcode += '(Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + ')\n'
gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n'
+ gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
+ gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
+ if p['multidepth'] is True:
+ gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
+ str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
- gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
- gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
+ elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
+ gcode += '\n(TOOLS DIAMETER: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + ')\n'
- if p['multidepth'] is True:
- gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
- str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
+ gcode += '\n(FEEDRATE Z: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
+
+ gcode += '\n(FEEDRATE RAPIDS: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
+ str(val['data']["feedrate_rapid"]) + ')\n'
+
+ gcode += '\n(Z_CUT: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + ')\n'
+
+ gcode += '\n(Tools Offset: )\n'
+ for tool, val in p['exc_cnc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + ')\n'
+
+ if p['multidepth'] is True:
+ gcode += '\n(DEPTH_PER_CUT: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
+ str(val['data']["depthperpass"]) + ')\n'
+
+ gcode += '\n(Z_MOVE: )\n'
+ for tool, val in p['exc_tools'].items():
+ gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + ')\n'
+ gcode += '\n'
+
+ if p['toolchange'] is True:
+ gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
+
+ if coords_xy is not None:
+ gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
+ p.decimals, coords_xy[1]) + units + ')\n'
+ else:
+ gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
- gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
- gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
- if coords_xy is not None:
- gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
- p.decimals, coords_xy[1]) + units + ')\n'
- else:
- gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
gcode += '(Z Start: ' + str(p['startz']) + units + ')\n'
gcode += '(Z End: ' + str(p['z_end']) + units + ')\n'
gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n'
if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
- gcode += '(Preprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n'
+ gcode += '(Preprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n' + '\n'
else:
gcode += '(Preprocessor Geometry: ' + str(p['pp_geometry_name']) + ')\n' + '\n'
From a9c6db73bf2fcd4b7e59736fe75a6427cf1003b2 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Tue, 18 Feb 2020 04:12:23 +0200
Subject: [PATCH 105/209] - when multiple tools are selected in Excellon UI and
parameters are modified it will applied to all selected - in Excellon UI,
Paint Tool and NCC Tool finished the "Apply parameters to all tools"
functionality - updated Paint Tool and NCC Tool in the UI functionality
---
FlatCAMApp.py | 2 +-
FlatCAMObj.py | 159 ++++++--------
README.md | 5 +-
flatcamGUI/PreferencesUI.py | 2 +-
flatcamTools/ToolNonCopperClear.py | 159 +++++++-------
flatcamTools/ToolPaint.py | 341 +++++++++++++++--------------
6 files changed, 328 insertions(+), 340 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 53dfe415..e1be9814 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -806,7 +806,7 @@ class App(QtCore.QObject):
"tools_paintorder": 'rev',
"tools_paintoverlap": 20,
"tools_paintmargin": 0.0,
- "tools_paintmethod": _("Seed-based"),
+ "tools_paintmethod": _("Seed"),
"tools_selectmethod": "all",
"tools_pathconnect": True,
"tools_paintcontour": True,
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index f451f30d..8073b9da 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -2778,10 +2778,8 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.ui.generate_milling_slots_button.show()
# set the text on tool_data_label after loading the object
- sel_rows = list()
sel_items = self.ui.tools_table.selectedItems()
- for it in sel_items:
- sel_rows.append(it.row())
+ sel_rows = [it.row() for it in sel_items]
if len(sel_rows) > 1:
self.ui.tool_data_label.setText(
"%s: %s" % (_('Parameters for'), _("Multiple Tools"))
@@ -2909,8 +2907,17 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.ui.operation_radio.activated_custom.connect(self.on_operation_type)
self.ui.pp_excellon_name_cb.activated.connect(self.on_pp_changed)
+
+ self.ui.apply_param_to_all.clicked.connect(self.on_apply_param_to_all_clicked)
+
self.units_found = self.app.defaults['units']
+ # ########################################
+ # #######3 TEMP SETTINGS #################
+ # ########################################
+ self.ui.operation_radio.set_value("drill")
+ self.ui.operation_radio.setEnabled(False)
+
def ui_connect(self):
# selective plotting
@@ -3029,7 +3036,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
for form_key in self.form_fields:
for storage_key in dict_storage:
if form_key == storage_key and form_key not in \
- ["toolchangez", "startz", "endz", "ppname_e", "ppname_g"]:
+ ["toolchange", "toolchangez", "startz", "endz", "ppname_e", "ppname_g"]:
try:
self.form_fields[form_key].set_value(dict_storage[form_key])
except Exception as e:
@@ -3047,19 +3054,20 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
wdg_objname = widget_changed.objectName()
option_changed = self.name2option[wdg_objname]
- row = self.ui.tools_table.currentRow()
+ # row = self.ui.tools_table.currentRow()
+ rows = sorted(set(index.row() for index in self.ui.tools_table.selectedIndexes()))
+ for row in rows:
+ if row < 0:
+ row = 0
+ tooluid_item = int(self.ui.tools_table.item(row, 0).text())
- if row < 0:
- row = 0
- tooluid_item = int(self.ui.tools_table.item(row, 0).text())
-
- for tooluid_key, tooluid_val in self.tools.items():
- if int(tooluid_key) == tooluid_item:
- new_option_value = self.form_fields[option_changed].get_value()
- if option_changed in tooluid_val:
- tooluid_val[option_changed] = new_option_value
- if option_changed in tooluid_val['data']:
- tooluid_val['data'][option_changed] = new_option_value
+ for tooluid_key, tooluid_val in self.tools.items():
+ if int(tooluid_key) == tooluid_item:
+ new_option_value = self.form_fields[option_changed].get_value()
+ if option_changed in tooluid_val:
+ tooluid_val[option_changed] = new_option_value
+ if option_changed in tooluid_val['data']:
+ tooluid_val['data'][option_changed] = new_option_value
self.ui_connect()
@@ -3858,57 +3866,33 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.shapes.clear(update=True)
def on_apply_param_to_all_clicked(self):
- if self.tools_table.rowCount() == 0:
+ if self.ui.tools_table.rowCount() == 0:
# there is no tool in tool table so we can't save the GUI elements values to storage
- log.debug("NonCopperClear.on_apply_param_to_all_clicked() --> no tool in Tools Table, aborting.")
+ log.debug("FlatCAMExcellon.on_apply_param_to_all_clicked() --> no tool in Tools Table, aborting.")
return
- self.blockSignals(True)
+ self.ui_disconnect()
- row = self.tools_table.currentRow()
+ row = self.ui.tools_table.currentRow()
if row < 0:
row = 0
- # store all the data associated with the row parameter to the self.tools storage
- tooldia_item = float(self.tools_table.item(row, 1).text())
- type_item = self.tools_table.cellWidget(row, 2).currentText()
- operation_type_item = self.ui.geo_tools_table.cellWidget(row, 4).currentText()
+ tooluid_item = int(self.ui.tools_table.item(row, 0).text())
+ temp_tool_data = dict()
- nccoffset_item = self.ncc_choice_offset_cb.get_value()
- nccoffset_value_item = float(self.ncc_offset_spinner.get_value())
+ for tooluid_key, tooluid_val in self.tools.items():
+ if int(tooluid_key) == tooluid_item:
+ # this will hold the 'data' key of the self.tools[tool] dictionary that corresponds to
+ # the current row in the tool table
+ temp_tool_data = tooluid_val['data']
+ break
- # this new dict will hold the actual useful data, another dict that is the value of key 'data'
- temp_tools = {}
- temp_dia = {}
- temp_data = {}
+ for tooluid_key, tooluid_val in self.tools.items():
+ tooluid_val['data'] = deepcopy(temp_tool_data)
- for tooluid_key, tooluid_value in self.ncc_tools.items():
- for key, value in tooluid_value.items():
- if key == 'data':
- # update the 'data' section
- for data_key in tooluid_value[key].keys():
- for form_key, form_value in self.form_fields.items():
- if form_key == data_key:
- temp_data[data_key] = form_value.get_value()
- # make sure we make a copy of the keys not in the form (we may use 'data' keys that are
- # updated from self.app.defaults
- if data_key not in self.form_fields:
- temp_data[data_key] = value[data_key]
- temp_dia[key] = deepcopy(temp_data)
- temp_data.clear()
+ self.app.inform.emit('[success] %s' % _("Current Tool parameters were applied to all tools."))
- elif key == 'solid_geometry':
- temp_dia[key] = deepcopy(self.tools[tooluid_key]['solid_geometry'])
- else:
- temp_dia[key] = deepcopy(value)
-
- temp_tools[tooluid_key] = deepcopy(temp_dia)
-
- self.ncc_tools.clear()
- self.ncc_tools = deepcopy(temp_tools)
- temp_tools.clear()
-
- self.blockSignals(False)
+ self.ui_connect()
class FlatCAMGeometry(FlatCAMObj, Geometry):
@@ -4584,42 +4568,43 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.tool_data_label.setText(
"%s: %s %d" % (_('Parameters for'), _("Tool"), tooluid)
)
+
+ # update the form with the V-Shape fields if V-Shape selected in the geo_tool_table
+ # also modify the Cut Z form entry to reflect the calculated Cut Z from values got from V-Shape Fields
+ try:
+ item = self.ui.geo_tools_table.cellWidget(current_row, 4)
+ if item is not None:
+ tool_type_txt = item.currentText()
+ self.ui_update_v_shape(tool_type_txt=tool_type_txt)
+ else:
+ self.ui_connect()
+ return
+ except Exception as e:
+ log.debug("Tool missing in ui_update_v_shape(). Add a tool in Geo Tool Table. %s" % str(e))
+ return
+
+ try:
+ # set the form with data from the newly selected tool
+ for tooluid_key, tooluid_value in self.tools.items():
+ if int(tooluid_key) == tooluid:
+ for key, value in tooluid_value.items():
+ if key == 'data':
+ form_value_storage = tooluid_value['data']
+ self.update_form(form_value_storage)
+ if key == 'offset_value':
+ # update the offset value in the entry even if the entry is hidden
+ self.ui.tool_offset_entry.set_value(tooluid_value['offset_value'])
+
+ if key == 'tool_type' and value == 'V':
+ self.update_cutz()
+ except Exception as e:
+ log.debug("FlatCAMGeometry.update_ui() -> %s " % str(e))
+
else:
self.ui.tool_data_label.setText(
"%s: %s" % (_('Parameters for'), _("Multiple Tools"))
)
- # update the form with the V-Shape fields if V-Shape selected in the geo_tool_table
- # also modify the Cut Z form entry to reflect the calculated Cut Z from values got from V-Shape Fields
- try:
- item = self.ui.geo_tools_table.cellWidget(current_row, 4)
- if item is not None:
- tool_type_txt = item.currentText()
- self.ui_update_v_shape(tool_type_txt=tool_type_txt)
- else:
- self.ui_connect()
- return
- except Exception as e:
- log.debug("Tool missing in ui_update_v_shape(). Add a tool in Geo Tool Table. %s" % str(e))
- return
-
- try:
- # set the form with data from the newly selected tool
- for tooluid_key, tooluid_value in self.tools.items():
- if int(tooluid_key) == tooluid:
- for key, value in tooluid_value.items():
- if key == 'data':
- form_value_storage = tooluid_value['data']
- self.update_form(form_value_storage)
- if key == 'offset_value':
- # update the offset value in the entry even if the entry is hidden
- self.ui.tool_offset_entry.set_value(tooluid_value['offset_value'])
-
- if key == 'tool_type' and value == 'V':
- self.update_cutz()
- except Exception as e:
- log.debug("FlatCAMGeometry.update_ui() -> %s " % str(e))
-
self.ui_connect()
def on_tool_add(self, dia=None):
diff --git a/README.md b/README.md
index 08c2b639..6a9c7726 100644
--- a/README.md
+++ b/README.md
@@ -17,9 +17,12 @@ CAD program, and create G-Code for Isolation routing.
- updated all FlatCAM tools to use the new confirmation message that show if the entered value is within range or outside
- updated all FlatCAM tools to use the new confirmation message for QSpinBoxes, too
- in Excellon UI protected the values that are common parameters from change on tool selection change
-- fixed some issues realted to the usage of the new confirmation message in FlatCAM Tools
+- fixed some issues related to the usage of the new confirmation message in FlatCAM Tools
- made sure that the FlatCAM Tools UI initialization is done only in set_tool_ui() method and not in the constructor
- adapted the GCode generation from Excellon to work with multiple tools data and modified the preprocessors header
+- when multiple tools are selected in Excellon UI and parameters are modified it will applied to all selected
+- in Excellon UI, Paint Tool and NCC Tool finished the "Apply parameters to all tools" functionality
+- updated Paint Tool and NCC Tool in the UI functionality
16.02.2020
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index 0c5537c8..7f8f9ec6 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -5826,7 +5826,7 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
# ], orientation='vertical', stretch=False)
self.paintmethod_combo = FCComboBox()
self.paintmethod_combo.addItems(
- [_("Standard"), _("Seed-based"), _("Straight lines"), _("Laser lines"), _("Combo")]
+ [_("Standard"), _("Seed"), _("Lines"), _("Laser_lines"), _("Combo")]
)
grid0.addWidget(methodlabel, 11, 0)
diff --git a/flatcamTools/ToolNonCopperClear.py b/flatcamTools/ToolNonCopperClear.py
index b1c5c65e..89889a5d 100644
--- a/flatcamTools/ToolNonCopperClear.py
+++ b/flatcamTools/ToolNonCopperClear.py
@@ -8,7 +8,8 @@
from PyQt5 import QtWidgets, QtCore, QtGui
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import FCCheckBox, FCDoubleSpinner, RadioSet, FCTable, FCInputDialog, FCButton, FCComboBox
+from flatcamGUI.GUIElements import FCCheckBox, FCDoubleSpinner, RadioSet, FCTable, FCInputDialog, FCButton, FCComboBox, \
+ OptionalInputSection
from flatcamParsers.ParseGerber import Gerber
import FlatCAMApp
@@ -70,7 +71,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
# ################################################
# ##### Type of object to be copper cleaned ######
# ################################################
- # self.type_obj_combo = QtWidgets.QComboBox()
+ # self.type_obj_combo = FCComboBox()
# self.type_obj_combo.addItem("Gerber")
# self.type_obj_combo.addItem("Excellon")
# self.type_obj_combo.addItem("Geometry")
@@ -97,7 +98,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
# ################################################
# ##### The object to be copper cleaned ##########
# ################################################
- self.object_combo = QtWidgets.QComboBox()
+ 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.setCurrentIndex(1)
@@ -439,14 +440,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
)
self.grid3.addWidget(self.ncc_choice_offset_cb, 19, 0)
- # ## NCC Offset value
- # self.ncc_offset_label = QtWidgets.QLabel('%s:' % _("Offset value"))
- # self.ncc_offset_label.setToolTip(
- # _("If used, it will add an offset to the copper features.\n"
- # "The copper clearing will finish to a distance\n"
- # "from the copper features.\n"
- # "The value can be between 0 and 10 FlatCAM units.")
- # )
+ # ## NCC Offset Entry
self.ncc_offset_spinner = FCDoubleSpinner(callback=self.confirmation_message)
self.ncc_offset_spinner.set_range(0.00, 10.00)
self.ncc_offset_spinner.set_precision(4)
@@ -459,12 +453,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
else:
self.ncc_offset_spinner.setSingleStep(0.01)
- # self.grid3.addWidget(self.ncc_offset_label, 20, 0)
self.grid3.addWidget(self.ncc_offset_spinner, 19, 1)
-
- # self.ncc_offset_label.hide()
- self.ncc_offset_spinner.setEnabled(False)
-
+
+ self.ois_ncc_offset = OptionalInputSection(self.ncc_choice_offset_cb, [self.ncc_offset_spinner])
+
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
@@ -530,7 +522,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
_("The type of FlatCAM object to be used as non copper clearing reference.\n"
"It can be Gerber, Excellon or Geometry.")
)
- self.box_combo_type = QtWidgets.QComboBox()
+ self.box_combo_type = FCComboBox()
self.box_combo_type.addItem(_("Reference Gerber"))
self.box_combo_type.addItem(_("Reference Excellon"))
self.box_combo_type.addItem(_("Reference Geometry"))
@@ -540,7 +532,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.box_combo_label.setToolTip(
_("The FlatCAM object to be used as non copper clearing reference.")
)
- self.box_combo = QtWidgets.QComboBox()
+ self.box_combo = FCComboBox()
self.box_combo.setModel(self.app.collection)
self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.box_combo.setCurrentIndex(1)
@@ -683,11 +675,14 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.box_combo_type.currentIndexChanged.connect(self.on_combo_box_type)
self.reference_radio.group_toggle_fn = self.on_toggle_reference
- self.ncc_choice_offset_cb.stateChanged.connect(self.on_offset_choice)
+
self.ncc_rest_cb.stateChanged.connect(self.on_rest_machining_check)
self.ncc_order_radio.activated_custom[str].connect(self.on_order_changed)
self.type_obj_combo.activated_custom.connect(self.on_type_obj_index_changed)
+
+ self.apply_param_to_all.clicked.connect(self.on_apply_param_to_all_clicked)
+
self.reset_button.clicked.connect(self.set_tool_ui)
def on_type_obj_index_changed(self, val):
@@ -696,48 +691,46 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.object_combo.setCurrentIndex(0)
def on_row_selection_change(self):
- self.update_ui()
-
- def update_ui(self, row=None):
self.blockSignals(True)
- if row is None:
+ sel_rows = [it.row() for it in self.tools_table.selectedItems()]
+ # sel_rows = sorted(set(index.row() for index in self.tools_table.selectedIndexes()))
+
+ if not sel_rows:
+ sel_rows = [0]
+
+ for current_row in sel_rows:
+ # populate the form with the data from the tool associated with the row parameter
try:
- current_row = self.tools_table.currentRow()
- except Exception:
- current_row = 0
- else:
- current_row = row
-
- if current_row < 0:
- current_row = 0
-
- # populate the form with the data from the tool associated with the row parameter
- try:
- item = self.tools_table.item(current_row, 3)
- if item is not None:
- tooluid = int(item.text())
- else:
+ item = self.tools_table.item(current_row, 3)
+ if item is not None:
+ tooluid = int(item.text())
+ else:
+ return
+ except Exception as e:
+ log.debug("Tool missing. Add a tool in the Tool Table. %s" % str(e))
return
- except Exception as e:
- log.debug("Tool missing. Add a tool in the Tool Table. %s" % str(e))
- return
- # update the QLabel that shows for which Tool we have the parameters in the UI form
- self.tool_data_label.setText(
- "%s: %s %d" % (_('Parameters for'), _("Tool"), (current_row + 1))
- )
-
- try:
- # set the form with data from the newly selected tool
- for tooluid_key, tooluid_value in list(self.ncc_tools.items()):
- if int(tooluid_key) == tooluid:
- for key, value in tooluid_value.items():
- if key == 'data':
- form_value_storage = tooluid_value[key]
- self.storage_to_form(form_value_storage)
- except Exception as e:
- log.debug("NonCopperClear ---> update_ui() " + str(e))
+ # update the QLabel that shows for which Tool we have the parameters in the UI form
+ if len(sel_rows) == 1:
+ cr = current_row + 1
+ self.tool_data_label.setText(
+ "%s: %s %d" % (_('Parameters for'), _("Tool"), cr)
+ )
+ try:
+ # set the form with data from the newly selected tool
+ for tooluid_key, tooluid_value in list(self.ncc_tools.items()):
+ if int(tooluid_key) == tooluid:
+ for key, value in tooluid_value.items():
+ if key == 'data':
+ form_value_storage = tooluid_value[key]
+ self.storage_to_form(form_value_storage)
+ except Exception as e:
+ log.debug("NonCopperClear ---> update_ui() " + str(e))
+ else:
+ self.tool_data_label.setText(
+ "%s: %s" % (_('Parameters for'), _("Multiple Tools"))
+ )
self.blockSignals(False)
@@ -761,19 +754,20 @@ class NonCopperClear(FlatCAMTool, Gerber):
wdg_objname = widget_changed.objectName()
option_changed = self.name2option[wdg_objname]
- row = self.tools_table.currentRow()
+ # row = self.tools_table.currentRow()
+ rows = sorted(set(index.row() for index in self.tools_table.selectedIndexes()))
+ for row in rows:
+ if row < 0:
+ row = 0
+ tooluid_item = int(self.tools_table.item(row, 3).text())
- if row < 0:
- row = 0
- tooluid_item = int(self.tools_table.item(row, 3).text())
-
- for tooluid_key, tooluid_val in self.ncc_tools.items():
- if int(tooluid_key) == tooluid_item:
- new_option_value = self.form_fields[option_changed].get_value()
- if option_changed in tooluid_val:
- tooluid_val[option_changed] = new_option_value
- if option_changed in tooluid_val['data']:
- tooluid_val['data'][option_changed] = new_option_value
+ for tooluid_key, tooluid_val in self.ncc_tools.items():
+ if int(tooluid_key) == tooluid_item:
+ new_option_value = self.form_fields[option_changed].get_value()
+ if option_changed in tooluid_val:
+ tooluid_val[option_changed] = new_option_value
+ if option_changed in tooluid_val['data']:
+ tooluid_val['data'][option_changed] = new_option_value
self.blockSignals(False)
@@ -828,6 +822,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.ncc_tools = deepcopy(temp_tools)
temp_tools.clear()
+ self.app.inform.emit('[success] %s' % _("Current Tool parameters were applied to all tools."))
+
self.blockSignals(False)
def on_add_tool_by_key(self):
@@ -1027,16 +1023,16 @@ class NonCopperClear(FlatCAMTool, Gerber):
dia.setFlags(QtCore.Qt.ItemIsEnabled)
- tool_type_item = QtWidgets.QComboBox()
- for item in self.tool_type_item_options:
- tool_type_item.addItem(item)
+ tool_type_item = FCComboBox()
+ tool_type_item.addItems(self.tool_type_item_options)
+
# tool_type_item.setStyleSheet('background-color: rgb(255,255,255)')
idx = tool_type_item.findText(tooluid_value['tool_type'])
tool_type_item.setCurrentIndex(idx)
tool_uid_item = QtWidgets.QTableWidgetItem(str(int(tooluid_key)))
- operation_type = QtWidgets.QComboBox()
+ operation_type = FCComboBox()
operation_type.addItem('iso_op')
# operation_type.setStyleSheet('background-color: rgb(255,255,255)')
operation_type.addItem('clear_op')
@@ -1082,6 +1078,16 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.ui_connect()
+ # set the text on tool_data_label after loading the object
+ sel_rows = list()
+ sel_items = self.tools_table.selectedItems()
+ for it in sel_items:
+ sel_rows.append(it.row())
+ if len(sel_rows) > 1:
+ self.tool_data_label.setText(
+ "%s: %s" % (_('Parameters for'), _("Multiple Tools"))
+ )
+
def ui_connect(self):
self.tools_table.itemChanged.connect(self.on_tool_edit)
@@ -1222,15 +1228,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.box_combo_type.show()
self.box_combo_type_label.show()
- def on_offset_choice(self, state):
- # if state:
- # self.ncc_offset_label.show()
- # self.ncc_offset_spinner.show()
- # else:
- # self.ncc_offset_label.hide()
- # self.ncc_offset_spinner.hide()
- self.ncc_offset_spinner.setEnabled(state)
-
def on_order_changed(self, order):
if order != 'no':
self.build_ui()
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index d1524a96..21eaf8a0 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -205,7 +205,7 @@ class ToolPaint(FlatCAMTool, Gerber):
"- 'V-shape'\n"
"- Circular")
)
- self.tool_type_radio.setObjectName(_("Tool Type"))
+ self.tool_type_radio.setObjectName('p_tool_type')
self.grid3.addWidget(self.tool_type_label, 2, 0)
self.grid3.addWidget(self.tool_type_radio, 2, 1)
@@ -218,7 +218,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.tipdia_entry.set_precision(self.decimals)
self.tipdia_entry.set_range(0.0000, 9999.9999)
self.tipdia_entry.setSingleStep(0.1)
- self.tipdia_entry.setObjectName(_("V-Tip Dia"))
+ self.tipdia_entry.setObjectName('p_vtip_dia')
self.grid3.addWidget(self.tipdialabel, 3, 0)
self.grid3.addWidget(self.tipdia_entry, 3, 1)
@@ -232,7 +232,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.tipangle_entry.set_precision(self.decimals)
self.tipangle_entry.set_range(0.0000, 180.0000)
self.tipangle_entry.setSingleStep(5)
- self.tipangle_entry.setObjectName(_("V-Tip Angle"))
+ self.tipangle_entry.setObjectName('p_vtip_angle')
self.grid3.addWidget(self.tipanglelabel, 4, 0)
self.grid3.addWidget(self.tipangle_entry, 4, 1)
@@ -246,7 +246,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.cutz_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.cutz_entry.set_precision(self.decimals)
self.cutz_entry.set_range(-99999.9999, 0.0000)
- self.cutz_entry.setObjectName(_("Cut Z"))
+ self.cutz_entry.setObjectName('p_cutz')
self.cutz_entry.setToolTip(
_("Depth of cut into material. Negative value.\n"
@@ -265,7 +265,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.addtool_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.addtool_entry.set_precision(self.decimals)
self.addtool_entry.set_range(0.000, 9999.9999)
- self.addtool_entry.setObjectName(_("Tool Dia"))
+ self.addtool_entry.setObjectName('p_tool_dia')
self.grid3.addWidget(self.addtool_entry_lbl, 6, 0)
self.grid3.addWidget(self.addtool_entry, 6, 1)
@@ -339,7 +339,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.paintoverlap_entry.setWrapping(True)
self.paintoverlap_entry.setRange(0.0000, 99.9999)
self.paintoverlap_entry.setSingleStep(0.1)
- self.paintoverlap_entry.setObjectName(_("Overlap"))
+ self.paintoverlap_entry.setObjectName('p_overlap')
grid4.addWidget(ovlabel, 1, 0)
grid4.addWidget(self.paintoverlap_entry, 1, 1)
@@ -354,7 +354,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.paintmargin_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.paintmargin_entry.set_precision(self.decimals)
self.paintmargin_entry.set_range(-9999.9999, 9999.9999)
- self.paintmargin_entry.setObjectName(_("Margin"))
+ self.paintmargin_entry.setObjectName('p_margin')
grid4.addWidget(marginlabel, 2, 0)
grid4.addWidget(self.paintmargin_entry, 2, 1)
@@ -373,45 +373,38 @@ class ToolPaint(FlatCAMTool, Gerber):
)
# self.paintmethod_combo = RadioSet([
# {"label": _("Standard"), "value": "standard"},
- # {"label": _("Seed-based"), "value": "seed"},
- # {"label": _("Straight lines"), "value": "lines"},
- # {"label": _("Laser lines"), "value": "laser_lines"},
- # {"label": _("Combo"), "value": "combo"}
+ # {"label": _("Seed-based"), "value": _("Seed")},
+ # {"label": _("Straight lines"), "value": _("Lines")},
+ # {"label": _("Laser lines"), "value": _("Laser_lines")},
+ # {"label": _("Combo"), "value": _("Combo")}
# ], orientation='vertical', stretch=False)
# for choice in self.paintmethod_combo.choices:
- # if choice['value'] == "laser_lines":
+ # if choice['value'] == _("Laser_lines"):
# choice["radio"].setEnabled(False)
self.paintmethod_combo = FCComboBox()
self.paintmethod_combo.addItems(
- [_("Standard"), _("Seed-based"), _("Straight lines"), _("Laser lines"), _("Combo")]
+ [_("Standard"), _("Seed"), _("Lines"), _("Laser_lines"), _("Combo")]
)
- self.p_mth = {
- _("Standard"): "standard",
- _("Seed-based"): "seed",
- _("Straight lines"): "lines",
- _("Laser lines"): "laser_lines",
- _("Combo"): "combo"
- }
- idx = self.paintmethod_combo.findText(_("Laser lines"))
+ idx = self.paintmethod_combo.findText(_("Laser_lines"))
self.paintmethod_combo.model().item(idx).setEnabled(False)
- self.paintmethod_combo.setObjectName(_("Method"))
+ self.paintmethod_combo.setObjectName('p_method')
grid4.addWidget(methodlabel, 7, 0)
grid4.addWidget(self.paintmethod_combo, 7, 1)
# Connect lines
self.pathconnect_cb = FCCheckBox('%s' % _("Connect"))
- self.pathconnect_cb.setObjectName(_("Connect"))
+ self.pathconnect_cb.setObjectName('p_connect')
self.pathconnect_cb.setToolTip(
_("Draw lines between resulting\n"
"segments to minimize tool lifts.")
)
self.paintcontour_cb = FCCheckBox('%s' % _("Contour"))
- self.paintcontour_cb.setObjectName(_("Contour"))
+ self.paintcontour_cb.setObjectName('p_contour')
self.paintcontour_cb.setToolTip(
_("Cut around the perimeter of the polygon\n"
"to trim rough edges.")
@@ -445,7 +438,7 @@ class ToolPaint(FlatCAMTool, Gerber):
grid4.addWidget(self.gen_param_label, 15, 0, 1, 2)
self.rest_cb = FCCheckBox('%s' % _("Rest Machining"))
- self.rest_cb.setObjectName(_("Rest Machining"))
+ self.rest_cb.setObjectName('p_rest_machining')
self.rest_cb.setToolTip(
_("If checked, use 'rest machining'.\n"
"Basically it will clear copper outside PCB features,\n"
@@ -476,7 +469,7 @@ class ToolPaint(FlatCAMTool, Gerber):
{"label": _("All Polygons"), "value": "all"},
{"label": _("Reference Object"), "value": "ref"}
], orientation='vertical', stretch=False)
- self.selectmethod_combo.setObjectName(_("Selection"))
+ self.selectmethod_combo.setObjectName('p_selection')
self.selectmethod_combo.setToolTip(
_("How to select Polygons to be painted.\n"
"- 'Polygon Selection' - left mouse click to add/remove polygons to be painted.\n"
@@ -574,7 +567,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.select_method = None
self.units = ''
- self.paint_tools = {}
+ self.paint_tools = dict()
self.tooluid = 0
self.first_click = False
self.cursor_pos = None
@@ -584,7 +577,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.mp = None
self.mr = None
- self.sel_rect = []
+ self.sel_rect = list()
# store here if the grid snapping is active
self.grid_status_memory = False
@@ -606,11 +599,11 @@ class ToolPaint(FlatCAMTool, Gerber):
}
self.name2option = {
- _('Overlap'): "paintoverlap",
- _('Margin'): "paintmargin",
- _('Method'): "paintmethod",
- _("Connect"): "pathconnect",
- _("Contour"): "paintcontour",
+ 'p_overlap': "paintoverlap",
+ 'p_margin': "paintmargin",
+ 'p_method': "paintmethod",
+ 'p_connect': "pathconnect",
+ 'p_contour': "paintcontour",
}
self.old_tool_dia = None
@@ -628,7 +621,7 @@ class ToolPaint(FlatCAMTool, Gerber):
# self.copytool_btn.clicked.connect(lambda: self.on_tool_copy())
# self.tools_table.itemChanged.connect(self.on_tool_edit)
- self.tools_table.currentItemChanged.connect(self.on_row_selection_change)
+ self.tools_table.clicked.connect(self.on_row_selection_change)
self.generate_paint_button.clicked.connect(self.on_paint_button_click)
self.selectmethod_combo.activated_custom.connect(self.on_radio_selection)
@@ -637,6 +630,9 @@ class ToolPaint(FlatCAMTool, Gerber):
self.box_combo_type.currentIndexChanged.connect(self.on_combo_box_type)
self.type_obj_combo.activated_custom.connect(self.on_type_obj_changed)
+
+ self.apply_param_to_all.clicked.connect(self.on_apply_param_to_all_clicked)
+
self.reset_button.clicked.connect(self.set_tool_ui)
# #############################################################################
@@ -660,13 +656,13 @@ class ToolPaint(FlatCAMTool, Gerber):
self.obj_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.obj_combo.setCurrentIndex(0)
- idx = self.paintmethod_combo.findText(_("Laser lines"))
+ idx = self.paintmethod_combo.findText(_("Laser_lines"))
if self.type_obj_combo.get_value().lower() == 'gerber':
self.paintmethod_combo.model().item(idx).setEnabled(True)
else:
self.paintmethod_combo.model().item(idx).setEnabled(False)
- if self.paintmethod_combo.get_value() == _("Laser lines"):
- self.paintmethod_combo.set_value(_("Straight lines"))
+ if self.paintmethod_combo.get_value() == _("Laser_lines"):
+ self.paintmethod_combo.set_value(_("Lines"))
def install(self, icon=None, separator=None, **kwargs):
FlatCAMTool.install(self, icon, separator, shortcut='ALT+P', **kwargs)
@@ -700,48 +696,46 @@ class ToolPaint(FlatCAMTool, Gerber):
self.app.ui.notebook.setTabText(2, _("Paint Tool"))
def on_row_selection_change(self):
- self.update_ui()
-
- def update_ui(self, row=None):
self.blockSignals(True)
- if row is None:
+ sel_rows = [it.row() for it in self.tools_table.selectedItems()]
+ # sel_rows = sorted(set(index.row() for index in self.tools_table.selectedIndexes()))
+
+ if not sel_rows:
+ sel_rows = [0]
+
+ for current_row in sel_rows:
+ # populate the form with the data from the tool associated with the row parameter
try:
- current_row = self.tools_table.currentRow()
- except Exception:
- current_row = 0
- else:
- current_row = row
-
- if current_row < 0:
- current_row = 0
-
- # populate the form with the data from the tool associated with the row parameter
- try:
- item = self.tools_table.item(current_row, 3)
- if item is not None:
+ item = self.tools_table.item(current_row, 3)
+ if item is None:
+ return 'fail'
tooluid = int(item.text())
- else:
+ except Exception as e:
+ log.debug("Tool missing. Add a tool in the Tool Table. %s" % str(e))
return
- except Exception as e:
- log.debug("Tool missing. Add a tool in the Tool Table. %s" % str(e))
- return
- # update the QLabel that shows for which Tool we have the parameters in the UI form
- self.tool_data_label.setText(
- "%s: %s %d" % (_('Parameters for'), _("Tool"), (current_row + 1))
- )
+ # update the QLabel that shows for which Tool we have the parameters in the UI form
+ if len(sel_rows) == 1:
+ cr = self.tools_table.item(current_row, 0).text()
+ self.tool_data_label.setText(
+ "%s: %s %s" % (_('Parameters for'), _("Tool"), cr)
+ )
- try:
- # set the form with data from the newly selected tool
- for tooluid_key, tooluid_value in list(self.paint_tools.items()):
- if int(tooluid_key) == tooluid:
- for key, value in tooluid_value.items():
- if key == 'data':
- form_value_storage = tooluid_value[key]
- self.storage_to_form(form_value_storage)
- except Exception as e:
- log.debug("ToolPaint ---> update_ui() " + str(e))
+ try:
+ # set the form with data from the newly selected tool
+ for tooluid_key, tooluid_value in list(self.paint_tools.items()):
+ if int(tooluid_key) == tooluid:
+ for key, value in tooluid_value.items():
+ if key == 'data':
+ form_value_storage = tooluid_value[key]
+ self.storage_to_form(form_value_storage)
+ except Exception as e:
+ log.debug("ToolPaint ---> update_ui() " + str(e))
+ else:
+ self.tool_data_label.setText(
+ "%s: %s" % (_('Parameters for'), _("Multiple Tools"))
+ )
self.blockSignals(False)
@@ -765,18 +759,20 @@ class ToolPaint(FlatCAMTool, Gerber):
wdg_objname = widget_changed.objectName()
option_changed = self.name2option[wdg_objname]
- row = self.tools_table.currentRow()
- if row < 0:
- row = 0
- tooluid_item = int(self.tools_table.item(row, 3).text())
+ # row = self.tools_table.currentRow()
+ rows = sorted(set(index.row() for index in self.tools_table.selectedIndexes()))
+ for row in rows:
+ if row < 0:
+ row = 0
+ tooluid_item = int(self.tools_table.item(row, 3).text())
- for tooluid_key, tooluid_val in self.paint_tools.items():
- if int(tooluid_key) == tooluid_item:
- new_option_value = self.form_fields[option_changed].get_value()
- if option_changed in tooluid_val:
- tooluid_val[option_changed] = new_option_value
- if option_changed in tooluid_val['data']:
- tooluid_val['data'][option_changed] = new_option_value
+ for tooluid_key, tooluid_val in self.paint_tools.items():
+ if int(tooluid_key) == tooluid_item:
+ new_option_value = self.form_fields[option_changed].get_value()
+ if option_changed in tooluid_val:
+ tooluid_val[option_changed] = new_option_value
+ if option_changed in tooluid_val['data']:
+ tooluid_val['data'][option_changed] = new_option_value
self.blockSignals(False)
@@ -788,40 +784,24 @@ class ToolPaint(FlatCAMTool, Gerber):
self.blockSignals(True)
- # row = self.tools_table.currentRow()
- # if row < 0:
- # row = 0
+ row = self.tools_table.currentRow()
+ if row < 0:
+ row = 0
- # this new dict will hold the actual useful data, another dict that is the value of key 'data'
- temp_tools = {}
- temp_dia = {}
- temp_data = {}
+ tooluid_item = int(self.tools_table.item(row, 3).text())
+ temp_tool_data = dict()
- for tooluid_key, tooluid_value in self.paint_tools.items():
- for key, value in tooluid_value.items():
- if key == 'data':
- # update the 'data' section
- for data_key in tooluid_value[key].keys():
- for form_key, form_value in self.form_fields.items():
- if form_key == data_key:
- temp_data[data_key] = form_value.get_value()
- # make sure we make a copy of the keys not in the form (we may use 'data' keys that are
- # updated from self.app.defaults
- if data_key not in self.form_fields:
- temp_data[data_key] = value[data_key]
- temp_dia[key] = deepcopy(temp_data)
- temp_data.clear()
+ for tooluid_key, tooluid_val in self.paint_tools.items():
+ if int(tooluid_key) == tooluid_item:
+ # this will hold the 'data' key of the self.tools[tool] dictionary that corresponds to
+ # the current row in the tool table
+ temp_tool_data = tooluid_val['data']
+ break
- elif key == 'solid_geometry':
- temp_dia[key] = deepcopy(self.tools[tooluid_key]['solid_geometry'])
- else:
- temp_dia[key] = deepcopy(value)
+ for tooluid_key, tooluid_val in self.paint_tools.items():
+ tooluid_val['data'] = deepcopy(temp_tool_data)
- temp_tools[tooluid_key] = deepcopy(temp_dia)
-
- self.paint_tools.clear()
- self.paint_tools = deepcopy(temp_tools)
- temp_tools.clear()
+ self.app.inform.emit('[success] %s' % _("Current Tool parameters were applied to all tools."))
self.blockSignals(False)
@@ -1682,7 +1662,7 @@ class ToolPaint(FlatCAMTool, Gerber):
:param outname: Name of the resulting Geometry Object.
:param connect: Connect lines to avoid tool lifts.
:param contour: Paint around the edges.
- :param method: choice out of 'seed', 'normal', 'lines'
+ :param method: choice out of _("Seed"), 'normal', 'lines'
:param tools_storage: whether to use the current tools_storage self.paints_tools or a different one.
Usage of the different one is related to when this function is called from a TcL command.
:return: None
@@ -1717,7 +1697,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.app.inform.emit('[WARNING] %s' % _('No polygon found.'))
return
- paint_method = method if method is not None else self.p_mth[self.paintmethod_combo.get_value()]
+ paint_method = method if method is not None else self.paintmethod_combo.get_value()
paint_margin = float(self.paintmargin_entry.get_value()) if margin is None else margin
# determine if to use the progressive plotting
prog_plot = True if self.app.defaults["tools_paint_plotting"] == 'progressive' else False
@@ -1757,7 +1737,17 @@ class ToolPaint(FlatCAMTool, Gerber):
def paint_p(polyg, tooldiameter):
cpoly = None
try:
- if paint_method == "seed":
+ if paint_method == _("Standard"):
+ # Type(cp) == FlatCAMRTreeStorage | None
+ cpoly = self.clear_polygon(polyg,
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults["geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ elif paint_method == _("Seed"):
# Type(cp) == FlatCAMRTreeStorage | None
cpoly = self.clear_polygon2(polyg,
tooldia=tooldiameter,
@@ -1767,7 +1757,7 @@ class ToolPaint(FlatCAMTool, Gerber):
connect=conn,
prog_plot=prog_plot)
- elif paint_method == "lines":
+ elif paint_method == _("Lines"):
# Type(cp) == FlatCAMRTreeStorage | None
cpoly = self.clear_polygon3(polyg,
tooldia=tooldiameter,
@@ -1777,16 +1767,7 @@ class ToolPaint(FlatCAMTool, Gerber):
connect=conn,
prog_plot=prog_plot)
- elif paint_method == "standard":
- # Type(cp) == FlatCAMRTreeStorage | None
- cpoly = self.clear_polygon(polyg,
- tooldia=tooldiameter,
- steps_per_circle=self.app.defaults["geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
- elif paint_method == "laser_lines":
+ elif paint_method == _("Laser_lines"):
# line = None
# aperture_size = None
@@ -1833,7 +1814,7 @@ class ToolPaint(FlatCAMTool, Gerber):
pads_lines_list = list()
# process the flashes found in the selected polygon with the 'lines' method for rectangular
- # flashes and with 'seed' for oblong and circular flashes
+ # flashes and with _("Seed") for oblong and circular flashes
# and pads (flahes) need the contour therefore I override the GUI settings with always True
for ap_type in flash_el_dict:
for elem in flash_el_dict[ap_type]:
@@ -1933,7 +1914,7 @@ class ToolPaint(FlatCAMTool, Gerber):
# connect=conn,
# prog_plot=prog_plot)
- elif paint_method == "combo":
+ elif paint_method == _("Combo"):
self.app.inform.emit(_("Painting polygon with method: lines."))
cpoly = self.clear_polygon3(polyg,
tooldia=tooldiameter,
@@ -2127,12 +2108,12 @@ class ToolPaint(FlatCAMTool, Gerber):
:param outname: name of the resulting object
:param connect: Connect lines to avoid tool lifts.
:param contour: Paint around the edges.
- :param method: choice out of 'seed', 'normal', 'lines'
+ :param method: choice out of _("Seed"), 'normal', 'lines'
:param tools_storage: whether to use the current tools_storage self.paints_tools or a different one.
Usage of the different one is related to when this function is called from a TcL command.
:return:
"""
- paint_method = method if method is not None else self.p_mth[self.paintmethod_combo.get_value()]
+ paint_method = method if method is not None else self.paintmethod_combo.get_value()
if margin is not None:
paint_margin = margin
@@ -2306,7 +2287,7 @@ class ToolPaint(FlatCAMTool, Gerber):
for pol in poly_buf:
if pol is not None and isinstance(pol, Polygon):
cp = None
- if paint_method == 'standard':
+ if paint_method == _("Standard"):
cp = self.clear_polygon(pol,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
@@ -2315,7 +2296,7 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont,
connect=conn,
prog_plot=prog_plot)
- elif paint_method == 'seed':
+ elif paint_method == _("Seed"):
cp = self.clear_polygon2(pol,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
@@ -2324,7 +2305,7 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont,
connect=conn,
prog_plot=prog_plot)
- elif paint_method == "standard":
+ elif paint_method == _("Lines"):
cp = self.clear_polygon3(pol,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
@@ -2333,7 +2314,7 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont,
connect=conn,
prog_plot=prog_plot)
- elif paint_method == "laser_lines":
+ elif paint_method == _("Laser_lines"):
# line = None
# aperture_size = None
@@ -2381,7 +2362,7 @@ class ToolPaint(FlatCAMTool, Gerber):
pads_lines_list = list()
# process the flashes found in the selected polygon with the 'lines' method
- # for rectangular flashes and with 'seed' for oblong and circular flashes
+ # for rectangular flashes and with _("Seed") for oblong and circular flashes
# and pads (flahes) need the contour therefore I override the GUI settings
# with always True
for ap_type in flash_el_dict:
@@ -2459,7 +2440,7 @@ class ToolPaint(FlatCAMTool, Gerber):
cp.insert(lin)
except TypeError:
cp.insert(lines_union)
- elif paint_method == "combo":
+ elif paint_method == _("Combo"):
self.app.inform.emit(_("Painting polygons with method: lines."))
cp = self.clear_polygon3(pol,
tooldia=tool_dia,
@@ -2508,7 +2489,7 @@ class ToolPaint(FlatCAMTool, Gerber):
except TypeError:
if isinstance(poly_buf, Polygon):
cp = None
- if paint_method == 'standard':
+ if paint_method == _("Standard"):
cp = self.clear_polygon(poly_buf,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
@@ -2517,7 +2498,7 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont,
connect=conn,
prog_plot=prog_plot)
- elif paint_method == 'seed':
+ elif paint_method == _("Seed"):
cp = self.clear_polygon2(poly_buf,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
@@ -2526,7 +2507,7 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont,
connect=conn,
prog_plot=prog_plot)
- elif paint_method == 'standard':
+ elif paint_method == _("Lines"):
cp = self.clear_polygon3(poly_buf,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
@@ -2535,7 +2516,7 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont,
connect=conn,
prog_plot=prog_plot)
- elif paint_method == "laser_lines":
+ elif paint_method == _("Laser_lines"):
# line = None
# aperture_size = None
@@ -2583,7 +2564,7 @@ class ToolPaint(FlatCAMTool, Gerber):
pads_lines_list = list()
# process the flashes found in the selected polygon with the 'lines' method
- # for rectangular flashes and with 'seed' for oblong and circular flashes
+ # for rectangular flashes and with _("Seed") for oblong and circular flashes
# and pads (flahes) need the contour therefore I override the GUI settings
# with always True
for ap_type in flash_el_dict:
@@ -2661,7 +2642,7 @@ class ToolPaint(FlatCAMTool, Gerber):
cp.insert(lin)
except TypeError:
cp.insert(lines_union)
- elif paint_method == "combo":
+ elif paint_method == _("Combo"):
self.app.inform.emit(_("Painting polygons with method: lines."))
cp = self.clear_polygon3(poly_buf,
tooldia=tool_dia,
@@ -2721,7 +2702,7 @@ class ToolPaint(FlatCAMTool, Gerber):
# continue
# poly_buf = geo.buffer(-paint_margin)
#
- # if paint_method == "seed":
+ # if paint_method == _("Seed"):
# # Type(cp) == FlatCAMRTreeStorage | None
# cp = self.clear_polygon2(poly_buf,
# tooldia=tool_dia,
@@ -2731,7 +2712,7 @@ class ToolPaint(FlatCAMTool, Gerber):
# connect=conn,
# prog_plot=prog_plot)
#
- # elif paint_method == "lines":
+ # elif paint_method == _("Lines"):
# # Type(cp) == FlatCAMRTreeStorage | None
# cp = self.clear_polygon3(poly_buf,
# tooldia=tool_dia,
@@ -2893,27 +2874,27 @@ class ToolPaint(FlatCAMTool, Gerber):
poly_buf = geo.buffer(-paint_margin)
cp = None
- if paint_method == "standard":
+ if paint_method == _("Standard"):
# Type(cp) == FlatCAMRTreeStorage | None
cp = self.clear_polygon(poly_buf, tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over, contour=cont, connect=conn,
prog_plot=prog_plot)
- elif paint_method == "seed":
+ elif paint_method == _("Seed"):
# Type(cp) == FlatCAMRTreeStorage | None
cp = self.clear_polygon2(poly_buf, tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over, contour=cont, connect=conn,
prog_plot=prog_plot)
- elif paint_method == "lines":
+ elif paint_method == _("Lines"):
# Type(cp) == FlatCAMRTreeStorage | None
cp = self.clear_polygon3(poly_buf, tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over, contour=cont, connect=conn,
prog_plot=prog_plot)
- elif paint_method == "laser_lines":
+ elif paint_method == _("Laser_lines"):
# line = None
# aperture_size = None
@@ -2961,7 +2942,7 @@ class ToolPaint(FlatCAMTool, Gerber):
pads_lines_list = list()
# process the flashes found in the selected polygon with the 'lines' method
- # for rectangular flashes and with 'seed' for oblong and circular flashes
+ # for rectangular flashes and with _("Seed") for oblong and circular flashes
# and pads (flahes) need the contour therefore I override the GUI settings
# with always True
for ap_type in flash_el_dict:
@@ -3039,7 +3020,7 @@ class ToolPaint(FlatCAMTool, Gerber):
cp.insert(lin)
except TypeError:
cp.insert(lines_union)
- elif paint_method == "combo":
+ elif paint_method == _("Combo"):
self.app.inform.emit(_("Painting polygons with method: lines."))
cp = self.clear_polygon3(poly_buf,
tooldia=tool_dia,
@@ -3192,12 +3173,12 @@ class ToolPaint(FlatCAMTool, Gerber):
:param outname: name of the resulting object
:param connect: Connect lines to avoid tool lifts.
:param contour: Paint around the edges.
- :param method: choice out of 'seed', 'normal', 'lines'
+ :param method: choice out of _("Seed"), 'normal', 'lines'
:param tools_storage: whether to use the current tools_storage self.paints_tools or a different one.
Usage of the different one is related to when this function is called from a TcL command.
:return:
"""
- paint_method = method if method is not None else self.p_mth[self.paintmethod_combo.get_value()]
+ paint_method = method if method is not None else self.paintmethod_combo.get_value()
if margin is not None:
paint_margin = margin
@@ -3364,7 +3345,7 @@ class ToolPaint(FlatCAMTool, Gerber):
poly_buf = geo.buffer(-paint_margin)
cp = None
- if paint_method == "seed":
+ if paint_method == _("Seed"):
# Type(cp) == FlatCAMRTreeStorage | None
cp = self.clear_polygon2(poly_buf,
tooldia=tool_dia,
@@ -3374,7 +3355,7 @@ class ToolPaint(FlatCAMTool, Gerber):
connect=conn,
prog_plot=prog_plot)
- elif paint_method == "lines":
+ elif paint_method == _("Lines"):
# Type(cp) == FlatCAMRTreeStorage | None
cp = self.clear_polygon3(poly_buf,
tooldia=tool_dia,
@@ -3384,7 +3365,7 @@ class ToolPaint(FlatCAMTool, Gerber):
connect=conn,
prog_plot=prog_plot)
- elif paint_method == 'standard':
+ elif paint_method == _("Standard"):
# Type(cp) == FlatCAMRTreeStorage | None
cp = self.clear_polygon(poly_buf,
tooldia=tool_dia,
@@ -3393,7 +3374,7 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont,
connect=conn,
prog_plot=prog_plot)
- elif paint_method == "laser_lines":
+ elif paint_method == _("Laser_lines"):
# line = None
# aperture_size = None
@@ -3441,7 +3422,7 @@ class ToolPaint(FlatCAMTool, Gerber):
pads_lines_list = list()
# process the flashes found in the selected polygon with the 'lines' method
- # for rectangular flashes and with 'seed' for oblong and circular flashes
+ # for rectangular flashes and with _("Seed") for oblong and circular flashes
# and pads (flahes) need the contour therefore I override the GUI settings
# with always True
for ap_type in flash_el_dict:
@@ -3519,7 +3500,7 @@ class ToolPaint(FlatCAMTool, Gerber):
cp.insert(lin)
except TypeError:
cp.insert(lines_union)
- elif paint_method == "combo":
+ elif paint_method == _("Combo"):
self.app.inform.emit(_("Painting polygons with method: lines."))
cp = self.clear_polygon3(poly_buf,
tooldia=tool_dia,
@@ -3693,27 +3674,27 @@ class ToolPaint(FlatCAMTool, Gerber):
poly_buf = geo.buffer(-paint_margin)
cp = None
- if paint_method == "standard":
+ if paint_method == _("Standard"):
# Type(cp) == FlatCAMRTreeStorage | None
cp = self.clear_polygon(poly_buf, tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over, contour=cont, connect=conn,
prog_plot=prog_plot)
- elif paint_method == "seed":
+ elif paint_method == _("Seed"):
# Type(cp) == FlatCAMRTreeStorage | None
cp = self.clear_polygon2(poly_buf, tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over, contour=cont, connect=conn,
prog_plot=prog_plot)
- elif paint_method == "lines":
+ elif paint_method == _("Lines"):
# Type(cp) == FlatCAMRTreeStorage | None
cp = self.clear_polygon3(poly_buf, tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over, contour=cont, connect=conn,
prog_plot=prog_plot)
- elif paint_method == "laser_lines":
+ elif paint_method == _("Laser_lines"):
# line = None
# aperture_size = None
@@ -3761,7 +3742,7 @@ class ToolPaint(FlatCAMTool, Gerber):
pads_lines_list = list()
# process the flashes found in the selected polygon with the 'lines' method
- # for rectangular flashes and with 'seed' for oblong and circular flashes
+ # for rectangular flashes and with _("Seed") for oblong and circular flashes
# and pads (flahes) need the contour therefore I override the GUI settings
# with always True
for ap_type in flash_el_dict:
@@ -3839,7 +3820,7 @@ class ToolPaint(FlatCAMTool, Gerber):
cp.insert(lin)
except TypeError:
cp.insert(lines_union)
- elif paint_method == "combo":
+ elif paint_method == _("Combo"):
self.app.inform.emit(_("Painting polygons with method: lines."))
cp = self.clear_polygon3(poly_buf,
tooldia=tool_dia,
@@ -3989,7 +3970,7 @@ class ToolPaint(FlatCAMTool, Gerber):
:param outname: name of the resulting object
:param connect: Connect lines to avoid tool lifts.
:param contour: Paint around the edges.
- :param method: choice out of 'seed', 'normal', 'lines'
+ :param method: choice out of _("Seed"), 'normal', 'lines'
:param tools_storage: whether to use the current tools_storage self.paints_tools or a different one.
Usage of the different one is related to when this function is called from a TcL command.
:return:
@@ -4027,6 +4008,10 @@ class ToolPaint(FlatCAMTool, Gerber):
def ui_connect(self):
self.tools_table.itemChanged.connect(self.on_tool_edit)
+ # rows selected
+ self.tools_table.clicked.connect(self.on_row_selection_change)
+ self.tools_table.horizontalHeader().sectionClicked.connect(self.on_row_selection_change)
+
for row in range(self.tools_table.rowCount()):
try:
self.tools_table.cellWidget(row, 2).currentIndexChanged.connect(self.on_tooltable_cellwidget_change)
@@ -4068,6 +4053,8 @@ class ToolPaint(FlatCAMTool, Gerber):
current_widget.activated_custom.connect(self.form_to_storage)
elif isinstance(current_widget, FCDoubleSpinner):
current_widget.returnPressed.connect(self.form_to_storage)
+ elif isinstance(current_widget, FCComboBox):
+ current_widget.currentIndexChanged.connect(self.form_to_storage)
self.rest_cb.stateChanged.connect(self.on_rest_machining_check)
self.order_radio.activated_custom[str].connect(self.on_order_changed)
@@ -4079,6 +4066,17 @@ class ToolPaint(FlatCAMTool, Gerber):
except (TypeError, AttributeError):
pass
+ # rows selected
+ try:
+ self.tools_table.clicked.disconnect(self.on_row_selection_change)
+ except (TypeError, AttributeError):
+ pass
+
+ try:
+ self.tools_table.horizontalHeader().sectionClicked.disconnect(self.on_row_selection_change)
+ except (TypeError, AttributeError):
+ pass
+
try:
# if connected, disconnect the signal from the slot on item_changed as it creates issues
self.tool_type_radio.activated_custom.disconnect()
@@ -4096,17 +4094,22 @@ class ToolPaint(FlatCAMTool, Gerber):
current_widget = self.form_fields[opt]
if isinstance(current_widget, FCCheckBox):
try:
- current_widget.stateChanged.disconnect()
+ current_widget.stateChanged.disconnect(self.form_to_storage)
except (TypeError, ValueError):
pass
if isinstance(current_widget, RadioSet):
try:
- current_widget.activated_custom.disconnect()
+ current_widget.activated_custom.disconnect(self.form_to_storage)
except (TypeError, ValueError):
pass
elif isinstance(current_widget, FCDoubleSpinner):
try:
- current_widget.returnPressed.disconnect()
+ current_widget.returnPressed.disconnect(self.form_to_storage)
+ except (TypeError, ValueError):
+ pass
+ elif isinstance(current_widget, FCComboBox):
+ try:
+ current_widget.currentIndexChanged.connect(self.form_to_storage)
except (TypeError, ValueError):
pass
From 042dc26cfa69eddb086d09d23b4f010137036f14 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Tue, 18 Feb 2020 04:26:53 +0200
Subject: [PATCH 106/209] - fixed the Offset spinbox not being controller by
offset checkbox in NCC Tool
---
README.md | 1 +
flatcamTools/ToolNonCopperClear.py | 42 +++++++-----------------------
2 files changed, 11 insertions(+), 32 deletions(-)
diff --git a/README.md b/README.md
index 6a9c7726..4be267f1 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,7 @@ CAD program, and create G-Code for Isolation routing.
- when multiple tools are selected in Excellon UI and parameters are modified it will applied to all selected
- in Excellon UI, Paint Tool and NCC Tool finished the "Apply parameters to all tools" functionality
- updated Paint Tool and NCC Tool in the UI functionality
+- fixed the Offset spinbox not being controller by offset checkbox in NCC Tool
16.02.2020
diff --git a/flatcamTools/ToolNonCopperClear.py b/flatcamTools/ToolNonCopperClear.py
index 89889a5d..d07b9b63 100644
--- a/flatcamTools/ToolNonCopperClear.py
+++ b/flatcamTools/ToolNonCopperClear.py
@@ -1108,35 +1108,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.tool_type_radio.activated_custom.connect(self.on_tool_type)
- # first disconnect
- for opt in self.form_fields:
- current_widget = self.form_fields[opt]
- if isinstance(current_widget, FCCheckBox):
- try:
- current_widget.stateChanged.disconnect()
- except (TypeError, ValueError):
- pass
- if isinstance(current_widget, RadioSet):
- try:
- current_widget.activated_custom.disconnect()
- except (TypeError, ValueError):
- pass
- elif isinstance(current_widget, FCDoubleSpinner):
- try:
- current_widget.returnPressed.disconnect()
- except (TypeError, ValueError):
- pass
-
- try:
- self.ncc_rest_cb.stateChanged.disconnect()
- except (TypeError, ValueError):
- pass
- try:
- self.ncc_order_radio.activated_custom[str].disconnect()
- except (TypeError, ValueError):
- pass
-
- # then reconnect
for opt in self.form_fields:
current_widget = self.form_fields[opt]
if isinstance(current_widget, FCCheckBox):
@@ -1145,6 +1116,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
current_widget.activated_custom.connect(self.form_to_storage)
elif isinstance(current_widget, FCDoubleSpinner):
current_widget.returnPressed.connect(self.form_to_storage)
+ elif isinstance(current_widget, FCComboBox):
+ current_widget.currentIndexChanged.connect(self.form_to_storage)
self.ncc_rest_cb.stateChanged.connect(self.on_rest_machining_check)
self.ncc_order_radio.activated_custom[str].connect(self.on_order_changed)
@@ -1174,17 +1147,22 @@ class NonCopperClear(FlatCAMTool, Gerber):
current_widget = self.form_fields[opt]
if isinstance(current_widget, FCCheckBox):
try:
- current_widget.stateChanged.disconnect()
+ current_widget.stateChanged.disconnect(self.form_to_storage)
except (TypeError, ValueError):
pass
if isinstance(current_widget, RadioSet):
try:
- current_widget.activated_custom.disconnect()
+ current_widget.activated_custom.disconnect(self.form_to_storage)
except (TypeError, ValueError):
pass
elif isinstance(current_widget, FCDoubleSpinner):
try:
- current_widget.returnPressed.disconnect()
+ current_widget.returnPressed.disconnect(self.form_to_storage)
+ except (TypeError, ValueError):
+ pass
+ elif isinstance(current_widget, FCComboBox):
+ try:
+ current_widget.currentIndexChanged.disconnect(self.form_to_storage)
except (TypeError, ValueError):
pass
From f8f337526d07a1cd87e8a417f83b6e9e2470e7af Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 19 Feb 2020 14:15:06 +0200
Subject: [PATCH 107/209] - fixed some issues in the Geometry Editor; the jump
sigmal disconnect was failing for repeated Editor tool operation
---
README.md | 4 ++
camlib.py | 18 ++++---
flatcamEditors/FlatCAMGeoEditor.py | 83 ++++++++++++++++++++++++------
3 files changed, 84 insertions(+), 21 deletions(-)
diff --git a/README.md b/README.md
index 4be267f1..8b646712 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+19.02.2020
+
+- fixed some issues in the Geometry Editor; the jump sigmal disconnect was failing for repeated Editor tool operation
+
17.02.2020
- updated the Excellon UI to hold data for each tool
diff --git a/camlib.py b/camlib.py
index 46877405..bb402eb8 100644
--- a/camlib.py
+++ b/camlib.py
@@ -2850,14 +2850,16 @@ class CNCjob(Geometry):
self.app.inform.emit('[WARNING] %s' %
_("The Cut Z parameter has positive value. "
"It is the depth value to drill into material.\n"
- "The Cut Z parameter needs to have a negative value, assuming it is a typo "
+ "The Cut Z parameter needs to have a negative value, "
+ "assuming it is a typo "
"therefore the app will convert the value to negative. "
"Check the resulting CNC code (Gcode etc)."))
self.z_cut = -self.z_cut
elif self.z_cut == 0:
self.app.inform.emit('[WARNING] %s: %s' %
(_(
- "The Cut Z parameter is zero. There will be no cut, skipping file"),
+ "The Cut Z parameter is zero. There will be no cut, "
+ "skipping file"),
exobj.options['name']))
return 'fail'
@@ -3063,14 +3065,16 @@ class CNCjob(Geometry):
self.app.inform.emit('[WARNING] %s' %
_("The Cut Z parameter has positive value. "
"It is the depth value to drill into material.\n"
- "The Cut Z parameter needs to have a negative value, assuming it is a typo "
+ "The Cut Z parameter needs to have a negative value, "
+ "assuming it is a typo "
"therefore the app will convert the value to negative. "
"Check the resulting CNC code (Gcode etc)."))
self.z_cut = -self.z_cut
elif self.z_cut == 0:
self.app.inform.emit('[WARNING] %s: %s' %
(_(
- "The Cut Z parameter is zero. There will be no cut, skipping file"),
+ "The Cut Z parameter is zero. There will be no cut, "
+ "skipping file"),
exobj.options['name']))
return 'fail'
@@ -3269,14 +3273,16 @@ class CNCjob(Geometry):
self.app.inform.emit('[WARNING] %s' %
_("The Cut Z parameter has positive value. "
"It is the depth value to drill into material.\n"
- "The Cut Z parameter needs to have a negative value, assuming it is a typo "
+ "The Cut Z parameter needs to have a negative value, "
+ "assuming it is a typo "
"therefore the app will convert the value to negative. "
"Check the resulting CNC code (Gcode etc)."))
self.z_cut = -self.z_cut
elif self.z_cut == 0:
self.app.inform.emit('[WARNING] %s: %s' %
(_(
- "The Cut Z parameter is zero. There will be no cut, skipping file"),
+ "The Cut Z parameter is zero. There will be no cut, "
+ "skipping file"),
exobj.options['name']))
return 'fail'
diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py
index 604227b1..26fb2615 100644
--- a/flatcamEditors/FlatCAMGeoEditor.py
+++ b/flatcamEditors/FlatCAMGeoEditor.py
@@ -1924,6 +1924,12 @@ class FCCircle(FCShapeTool):
self.steps_per_circ = self.draw_app.app.defaults["geometry_circle_steps"]
def click(self, point):
+ try:
+ self.draw_app.app.jump_signal.disconnect()
+ except (TypeError, AttributeError):
+ pass
+ self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
+
self.points.append(point)
if len(self.points) == 1:
@@ -2003,6 +2009,12 @@ class FCArc(FCShapeTool):
self.steps_per_circ = self.draw_app.app.defaults["geometry_circle_steps"]
def click(self, point):
+ try:
+ self.draw_app.app.jump_signal.disconnect()
+ except (TypeError, AttributeError):
+ pass
+ self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
+
self.points.append(point)
if len(self.points) == 1:
@@ -2227,6 +2239,12 @@ class FCRectangle(FCShapeTool):
self.draw_app.app.inform.emit(_("Click on 1st corner ..."))
def click(self, point):
+ try:
+ self.draw_app.app.jump_signal.disconnect()
+ except (TypeError, AttributeError):
+ pass
+ self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
+
self.points.append(point)
if len(self.points) == 1:
@@ -2294,6 +2312,12 @@ class FCPolygon(FCShapeTool):
self.draw_app.app.inform.emit(_("Click on 1st corner ..."))
def click(self, point):
+ try:
+ self.draw_app.app.jump_signal.disconnect()
+ except (TypeError, AttributeError):
+ pass
+ self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
+
self.draw_app.in_action = True
self.points.append(point)
@@ -2609,6 +2633,7 @@ class FCMove(FCShapeTool):
return
else:
self.draw_app.app.inform.emit(_(" MOVE: Click on reference point ..."))
+
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
def set_origin(self, origin):
@@ -2616,6 +2641,12 @@ class FCMove(FCShapeTool):
self.origin = origin
def click(self, point):
+ try:
+ self.draw_app.app.jump_signal.disconnect()
+ except (TypeError, AttributeError):
+ pass
+ self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
+
if len(self.draw_app.get_selected()) == 0:
# self.complete = True
# self.draw_app.app.inform.emit(_("[WARNING_NOTCL] Move cancelled. No shape selected."))
@@ -2647,7 +2678,10 @@ class FCMove(FCShapeTool):
self.draw_app.delete_selected()
self.complete = True
self.draw_app.app.inform.emit('[success] %s' % _("Done. Geometry(s) Move completed."))
- self.draw_app.app.jump_signal.disconnect()
+ try:
+ self.draw_app.app.jump_signal.disconnect()
+ except TypeError:
+ pass
def selection_bbox(self):
geo_list = []
@@ -2777,7 +2811,10 @@ class FCCopy(FCMove):
for geom in self.draw_app.get_selected()]
self.complete = True
self.draw_app.app.inform.emit('[success] %s' % _("Done. Geometry(s) Copy completed."))
- self.draw_app.app.jump_signal.disconnect()
+ try:
+ self.draw_app.app.jump_signal.disconnect()
+ except (TypeError, AttributeError):
+ pass
def clean_up(self):
self.draw_app.selected = list()
@@ -2812,6 +2849,12 @@ class FCText(FCShapeTool):
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
def click(self, point):
+ try:
+ self.draw_app.app.jump_signal.disconnect()
+ except (TypeError, AttributeError):
+ pass
+ self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
+
# Create new geometry
dx = point[0]
dy = point[1]
@@ -2831,7 +2874,10 @@ class FCText(FCShapeTool):
return
else:
self.draw_app.app.inform.emit('[WARNING_NOTCL] %s' % _("No text to add."))
- self.draw_app.app.jump_signal.disconnect()
+ try:
+ self.draw_app.app.jump_signal.disconnect()
+ except (TypeError, AttributeError):
+ pass
return
self.text_gui.text_path = []
@@ -2909,13 +2955,11 @@ class FCBuffer(FCShapeTool):
self.disactivate()
if ret_val == 'fail':
return
- self.draw_app.app.inform.emit('[success] %s' %
- _("Done. Buffer Tool completed."))
+ self.draw_app.app.inform.emit('[success] %s' % _("Done. Buffer Tool completed."))
def on_buffer_int(self):
if not self.draw_app.selected:
- self.app.inform.emit('[WARNING_NOTCL] %s' %
- _("Buffer cancelled. No shape selected."))
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Buffer cancelled. No shape selected."))
return
try:
@@ -2939,13 +2983,11 @@ class FCBuffer(FCShapeTool):
self.disactivate()
if ret_val == 'fail':
return
- self.draw_app.app.inform.emit('[success] %s' %
- _("Done. Buffer Int Tool completed."))
+ self.draw_app.app.inform.emit('[success] %s' % _("Done. Buffer Int Tool completed."))
def on_buffer_ext(self):
if not self.draw_app.selected:
- self.app.inform.emit('[WARNING_NOTCL] %s' %
- _("Buffer cancelled. No shape selected."))
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Buffer cancelled. No shape selected."))
return
try:
@@ -2969,8 +3011,7 @@ class FCBuffer(FCShapeTool):
self.disactivate()
if ret_val == 'fail':
return
- self.draw_app.app.inform.emit('[success] %s' %
- _("Done. Buffer Ext Tool completed."))
+ self.draw_app.app.inform.emit('[success] %s' % _("Done. Buffer Ext Tool completed."))
def activate(self):
self.buff_tool.buffer_button.clicked.disconnect()
@@ -2992,6 +3033,10 @@ class FCBuffer(FCShapeTool):
self.complete = True
self.draw_app.select_tool("select")
self.buff_tool.hide_tool()
+ try:
+ self.draw_app.app.jump_signal.disconnect()
+ except (TypeError, AttributeError):
+ pass
def clean_up(self):
self.draw_app.selected = list()
@@ -3003,7 +3048,6 @@ class FCBuffer(FCShapeTool):
pass
-
class FCEraser(FCShapeTool):
def __init__(self, draw_app):
DrawTool.__init__(self, draw_app)
@@ -3031,6 +3075,12 @@ class FCEraser(FCShapeTool):
self.origin = origin
def click(self, point):
+ try:
+ self.draw_app.app.jump_signal.disconnect()
+ except (TypeError, AttributeError):
+ pass
+ self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
+
if len(self.draw_app.get_selected()) == 0:
for obj_shape in self.storage.get_objects():
try:
@@ -3078,7 +3128,10 @@ class FCEraser(FCShapeTool):
self.draw_app.delete_utility_geometry()
self.draw_app.plot_all()
self.draw_app.app.inform.emit('[success] %s' % _("Done. Eraser tool action completed."))
- self.draw_app.app.jump_signal.disconnect()
+ try:
+ self.draw_app.app.jump_signal.disconnect()
+ except (TypeError, AttributeError):
+ pass
def utility_geometry(self, data=None):
"""
From 6a24c8e20432a8c649a4aab078679af5dd6c87f6 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 19 Feb 2020 16:57:36 +0200
Subject: [PATCH 108/209] - fixed an issue in Gerber Editor where the
multiprocessing pool was reported as closed and an ValueError exception was
raised in a certain scneraio
---
README.md | 1 +
flatcamEditors/FlatCAMGrbEditor.py | 189 +++++++++++++++++------------
2 files changed, 112 insertions(+), 78 deletions(-)
diff --git a/README.md b/README.md
index 8b646712..4d15d52e 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
19.02.2020
- fixed some issues in the Geometry Editor; the jump sigmal disconnect was failing for repeated Editor tool operation
+- fixed an issue in Gerber Editor where the multiprocessing pool was reported as closed and an ValueError exception was raised in a certain scneraio
17.02.2020
diff --git a/flatcamEditors/FlatCAMGrbEditor.py b/flatcamEditors/FlatCAMGrbEditor.py
index e1006725..c10c98a1 100644
--- a/flatcamEditors/FlatCAMGrbEditor.py
+++ b/flatcamEditors/FlatCAMGrbEditor.py
@@ -3045,6 +3045,9 @@ class FlatCAMGrbEditor(QtCore.QObject):
# A QTimer
self.plot_thread = None
+ # a QThread for the edit process
+ self.thread = QtCore.QThread()
+
# store the status of the editor so the Delete at object level will not work until the edit is finished
self.editor_active = False
@@ -3106,6 +3109,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
def pool_recreated(self, pool):
self.shapes.pool = pool
self.tool_shape.pool = pool
+ self.pool = pool
def set_ui(self):
# updated units
@@ -3927,96 +3931,125 @@ class FlatCAMGrbEditor(QtCore.QObject):
# # and add the first aperture to have something to play with
# self.on_aperture_add('10')
- def worker_job(app_obj):
- with app_obj.app.proc_container.new('%s ...' % _("Loading Gerber into Editor")):
- # ############################################################# ##
- # APPLY CLEAR_GEOMETRY on the SOLID_GEOMETRY
- # ############################################################# ##
+ # self.app.worker_task.emit({'fcn': worker_job, 'params': [self]})
- # list of clear geos that are to be applied to the entire file
- global_clear_geo = []
+ class Execute_Edit(QtCore.QObject):
- # create one big geometry made out of all 'negative' (clear) polygons
- for apid in app_obj.gerber_obj.apertures:
- # first check if we have any clear_geometry (LPC) and if yes added it to the global_clear_geo
- if 'geometry' in app_obj.gerber_obj.apertures[apid]:
- for elem in app_obj.gerber_obj.apertures[apid]['geometry']:
- if 'clear' in elem:
- global_clear_geo.append(elem['clear'])
- log.warning("Found %d clear polygons." % len(global_clear_geo))
+ start = QtCore.pyqtSignal(str)
- global_clear_geo = MultiPolygon(global_clear_geo)
- if isinstance(global_clear_geo, Polygon):
- global_clear_geo = list(global_clear_geo)
+ def __init__(self, app):
+ super(Execute_Edit, self).__init__()
+ self.app = app
+ self.start.connect(self.run)
- # we subtract the big "negative" (clear) geometry from each solid polygon but only the part of
- # clear geometry that fits inside the solid. otherwise we may loose the solid
- for apid in app_obj.gerber_obj.apertures:
- temp_solid_geometry = []
- if 'geometry' in app_obj.gerber_obj.apertures[apid]:
- # for elem in self.gerber_obj.apertures[apid]['geometry']:
- # if 'solid' in elem:
- # solid_geo = elem['solid']
- # for clear_geo in global_clear_geo:
- # # Make sure that the clear_geo is within the solid_geo otherwise we loose
- # # the solid_geometry. We want for clear_geometry just to cut into solid_geometry not to
- # # delete it
- # if clear_geo.within(solid_geo):
- # solid_geo = solid_geo.difference(clear_geo)
- # try:
- # for poly in solid_geo:
- # new_elem = dict()
- #
- # new_elem['solid'] = poly
- # if 'clear' in elem:
- # new_elem['clear'] = poly
- # if 'follow' in elem:
- # new_elem['follow'] = poly
- # temp_elem.append(deepcopy(new_elem))
- # except TypeError:
- # new_elem = dict()
- # new_elem['solid'] = solid_geo
- # if 'clear' in elem:
- # new_elem['clear'] = solid_geo
- # if 'follow' in elem:
- # new_elem['follow'] = solid_geo
- # temp_elem.append(deepcopy(new_elem))
- for elem in app_obj.gerber_obj.apertures[apid]['geometry']:
- new_elem = dict()
- if 'solid' in elem:
- solid_geo = elem['solid']
+ @staticmethod
+ def worker_job(app_obj):
+ with app_obj.app.proc_container.new('%s ...' % _("Loading Gerber into Editor")):
+ # ############################################################# ##
+ # APPLY CLEAR_GEOMETRY on the SOLID_GEOMETRY
+ # ############################################################# ##
- for clear_geo in global_clear_geo:
- # Make sure that the clear_geo is within the solid_geo otherwise we loose
- # the solid_geometry. We want for clear_geometry just to cut into solid_geometry
- # not to delete it
- if clear_geo.within(solid_geo):
- solid_geo = solid_geo.difference(clear_geo)
+ # list of clear geos that are to be applied to the entire file
+ global_clear_geo = list()
- new_elem['solid'] = solid_geo
- if 'clear' in elem:
- new_elem['clear'] = elem['clear']
- if 'follow' in elem:
- new_elem['follow'] = elem['follow']
- temp_solid_geometry.append(deepcopy(new_elem))
+ # create one big geometry made out of all 'negative' (clear) polygons
+ for apid in app_obj.gerber_obj.apertures:
+ # first check if we have any clear_geometry (LPC) and if yes added it to the global_clear_geo
+ if 'geometry' in app_obj.gerber_obj.apertures[apid]:
+ for elem in app_obj.gerber_obj.apertures[apid]['geometry']:
+ if 'clear' in elem:
+ global_clear_geo.append(elem['clear'])
+ log.warning("Found %d clear polygons." % len(global_clear_geo))
- app_obj.gerber_obj.apertures[apid]['geometry'] = deepcopy(temp_solid_geometry)
- log.warning("Polygon difference done for %d apertures." % len(app_obj.gerber_obj.apertures))
+ if global_clear_geo:
+ global_clear_geo = MultiPolygon(global_clear_geo)
+ if isinstance(global_clear_geo, Polygon):
+ global_clear_geo = list(global_clear_geo)
- # Loading the Geometry into Editor Storage
- for ap_id, ap_dict in app_obj.gerber_obj.apertures.items():
- app_obj.results.append(app_obj.pool.apply_async(app_obj.add_apertures, args=(ap_id, ap_dict)))
+ # we subtract the big "negative" (clear) geometry from each solid polygon but only the part of
+ # clear geometry that fits inside the solid. otherwise we may loose the solid
+ for apid in app_obj.gerber_obj.apertures:
+ temp_solid_geometry = list()
+ if 'geometry' in app_obj.gerber_obj.apertures[apid]:
+ # for elem in self.gerber_obj.apertures[apid]['geometry']:
+ # if 'solid' in elem:
+ # solid_geo = elem['solid']
+ # for clear_geo in global_clear_geo:
+ # # Make sure that the clear_geo is within the solid_geo otherwise we loose
+ # # the solid_geometry. We want for clear_geometry just to cut into solid_geometry not to
+ # # delete it
+ # if clear_geo.within(solid_geo):
+ # solid_geo = solid_geo.difference(clear_geo)
+ # try:
+ # for poly in solid_geo:
+ # new_elem = dict()
+ #
+ # new_elem['solid'] = poly
+ # if 'clear' in elem:
+ # new_elem['clear'] = poly
+ # if 'follow' in elem:
+ # new_elem['follow'] = poly
+ # temp_elem.append(deepcopy(new_elem))
+ # except TypeError:
+ # new_elem = dict()
+ # new_elem['solid'] = solid_geo
+ # if 'clear' in elem:
+ # new_elem['clear'] = solid_geo
+ # if 'follow' in elem:
+ # new_elem['follow'] = solid_geo
+ # temp_elem.append(deepcopy(new_elem))
+ for elem in app_obj.gerber_obj.apertures[apid]['geometry']:
+ new_elem = dict()
+ if 'solid' in elem:
+ solid_geo = elem['solid']
+ if not global_clear_geo or global_clear_geo.is_empty:
+ pass
+ else:
+ for clear_geo in global_clear_geo:
+ # Make sure that the clear_geo is within the solid_geo otherwise we loose
+ # the solid_geometry. We want for clear_geometry just to cut into
+ # solid_geometry not to delete it
+ if clear_geo.within(solid_geo):
+ solid_geo = solid_geo.difference(clear_geo)
- output = list()
- for p in app_obj.results:
- output.append(p.get())
+ new_elem['solid'] = solid_geo
+ if 'clear' in elem:
+ new_elem['clear'] = elem['clear']
+ if 'follow' in elem:
+ new_elem['follow'] = elem['follow']
+ temp_solid_geometry.append(deepcopy(new_elem))
- for elem in output:
- app_obj.storage_dict[elem[0]] = deepcopy(elem[1])
+ app_obj.gerber_obj.apertures[apid]['geometry'] = deepcopy(temp_solid_geometry)
+ log.warning("Polygon difference done for %d apertures." % len(app_obj.gerber_obj.apertures))
- app_obj.mp_finished.emit(output)
+ try:
+ # Loading the Geometry into Editor Storage
+ for ap_id, ap_dict in app_obj.gerber_obj.apertures.items():
+ app_obj.results.append(
+ app_obj.pool.apply_async(app_obj.add_apertures, args=(ap_id, ap_dict))
+ )
+ except Exception as e:
+ log.debug(
+ "FlatCAMGrbEditor.edit_fcgerber.worker_job() Adding processes to pool --> %s" % str(e))
+ traceback.print_exc()
- self.app.worker_task.emit({'fcn': worker_job, 'params': [self]})
+ output = list()
+ for p in app_obj.results:
+ output.append(p.get())
+
+ for elem in output:
+ app_obj.storage_dict[elem[0]] = deepcopy(elem[1])
+
+ app_obj.mp_finished.emit(output)
+
+ def run(self):
+ self.worker_job(self.app)
+
+ self.thread.start(QtCore.QThread.NormalPriority)
+
+ executable_edit = Execute_Edit(app=self)
+ executable_edit.moveToThread(self.thread)
+ executable_edit.start.emit("Started")
@staticmethod
def add_apertures(aperture_id, aperture_dict):
From 72ce53182dabe614606a4d8142bb1d3fd28a51af Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 19 Feb 2020 21:26:08 +0200
Subject: [PATCH 109/209] - on Set Origin, Move to Origin and Move actions for
Gerber and Excellon objects the source file will be also updated (the export
functions will export an updated object)
---
FlatCAMApp.py | 26 +++++++++++++++++++++++++-
README.md | 1 +
flatcamTools/ToolMove.py | 10 ++++++++++
3 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index e1be9814..e06a211e 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -7307,7 +7307,9 @@ class App(QtCore.QObject):
def worker_task():
with self.proc_container.new(_("Setting Origin...")):
- for obj in self.collection.get_list():
+ obj_list = self.collection.get_list()
+
+ for obj in obj_list:
obj.offset((x, y))
self.object_changed.emit(obj)
@@ -7318,6 +7320,17 @@ class App(QtCore.QObject):
obj.options['xmax'] = c
obj.options['ymax'] = d
self.inform.emit('[success] %s...' % _('Origin set'))
+
+ for obj in obj_list:
+ out_name = obj.options["name"]
+
+ if obj.kind == 'gerber':
+ obj.source_file = self.export_gerber(
+ obj_name=out_name, filename=None, local_use=obj, use_thread=False)
+ elif obj.kind == 'excellon':
+ obj.source_file = self.export_excellon(
+ obj_name=out_name, filename=None, local_use=obj, use_thread=False)
+
if noplot_sig is False:
self.replot_signal.emit([])
@@ -7400,6 +7413,17 @@ class App(QtCore.QObject):
for obj in obj_list:
obj.plot()
+
+ for obj in obj_list:
+ out_name = obj.options["name"]
+
+ if obj.kind == 'gerber':
+ obj.source_file = self.export_gerber(
+ obj_name=out_name, filename=None, local_use=obj, use_thread=False)
+ elif obj.kind == 'excellon':
+ obj.source_file = self.export_excellon(
+ obj_name=out_name, filename=None, local_use=obj, use_thread=False)
+
self.inform.emit('[success] %s...' % _('Origin set'))
if use_thread is True:
diff --git a/README.md b/README.md
index 4d15d52e..c4358a4f 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- fixed some issues in the Geometry Editor; the jump sigmal disconnect was failing for repeated Editor tool operation
- fixed an issue in Gerber Editor where the multiprocessing pool was reported as closed and an ValueError exception was raised in a certain scneraio
+- on Set Origin, Move to Origin and Move actions for Gerber and Excellon objects the source file will be also updated (the export functions will export an updated object)
17.02.2020
diff --git a/flatcamTools/ToolMove.py b/flatcamTools/ToolMove.py
index 7b6f9079..9b21c2da 100644
--- a/flatcamTools/ToolMove.py
+++ b/flatcamTools/ToolMove.py
@@ -188,6 +188,16 @@ class ToolMove(FlatCAMTool):
sel_obj.options['ymin'] = b
sel_obj.options['xmax'] = c
sel_obj.options['ymax'] = d
+
+ # update the source_file with the new positions
+ for sel_obj in obj_list:
+ out_name = sel_obj.options["name"]
+ if sel_obj.kind == 'gerber':
+ sel_obj.source_file = self.app.export_gerber(
+ obj_name=out_name, filename=None, local_use=sel_obj, use_thread=False)
+ elif sel_obj.kind == 'excellon':
+ sel_obj.source_file = self.app.export_excellon(
+ obj_name=out_name, filename=None, local_use=sel_obj, use_thread=False)
except Exception as e:
log.debug('[ERROR_NOTCL] %s --> %s' % ('ToolMove.on_left_click()', str(e)))
return "fail"
From dab46ef3aef9acf442e96046ca8f3bbf072891c9 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 19 Feb 2020 22:09:32 +0200
Subject: [PATCH 110/209] - in FlatCAMObj.export_gerber() method took into
account the possibility of polygons of type 'clear' (the ones found in the
Gerber files under the LPC command)
---
FlatCAMObj.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++
README.md | 1 +
2 files changed, 58 insertions(+)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 8073b9da..6d8f640a 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -2233,6 +2233,63 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
x_formatted, y_formatted = lz_format(geo.x, geo.y, factor)
gerber_code += "X{xform}Y{yform}D03*\n".format(xform=x_formatted,
yform=y_formatted)
+ elif isinstance(geo, Polygon):
+ geo_coords = list(geo.exterior.coords)
+ # first command is a move with pen-up D02 at the beginning of the geo
+ if g_zeros == 'T':
+ x_formatted, y_formatted = tz_format(
+ geo_coords[0][0], geo_coords[0][1], factor)
+ gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted,
+ yform=y_formatted)
+ else:
+ x_formatted, y_formatted = lz_format(
+ geo_coords[0][0], geo_coords[0][1], factor)
+ gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted,
+ yform=y_formatted)
+
+ prev_coord = geo_coords[0]
+ for coord in geo_coords[1:]:
+ if coord != prev_coord:
+ if g_zeros == 'T':
+ x_formatted, y_formatted = tz_format(coord[0], coord[1], factor)
+ gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted,
+ yform=y_formatted)
+ else:
+ x_formatted, y_formatted = lz_format(coord[0], coord[1], factor)
+ gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted,
+ yform=y_formatted)
+
+ prev_coord = coord
+
+ for geo_int in geo.interiors:
+ geo_coords = list(geo_int.coords)
+ # first command is a move with pen-up D02 at the beginning of the geo
+ if g_zeros == 'T':
+ x_formatted, y_formatted = tz_format(
+ geo_coords[0][0], geo_coords[0][1], factor)
+ gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted,
+ yform=y_formatted)
+ else:
+ x_formatted, y_formatted = lz_format(
+ geo_coords[0][0], geo_coords[0][1], factor)
+ gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted,
+ yform=y_formatted)
+
+ prev_coord = geo_coords[0]
+ for coord in geo_coords[1:]:
+ if coord != prev_coord:
+ if g_zeros == 'T':
+ x_formatted, y_formatted = tz_format(coord[0], coord[1], factor)
+ gerber_code += "X{xform}Y{yform}D01*\n".format(
+ xform=x_formatted,
+ yform=y_formatted)
+ else:
+ x_formatted, y_formatted = lz_format(coord[0], coord[1], factor)
+ gerber_code += "X{xform}Y{yform}D01*\n".format(
+ xform=x_formatted,
+ yform=y_formatted)
+
+ prev_coord = coord
else:
geo_coords = list(geo.coords)
# first command is a move with pen-up D02 at the beginning of the geo
diff --git a/README.md b/README.md
index c4358a4f..128613cd 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ CAD program, and create G-Code for Isolation routing.
- fixed some issues in the Geometry Editor; the jump sigmal disconnect was failing for repeated Editor tool operation
- fixed an issue in Gerber Editor where the multiprocessing pool was reported as closed and an ValueError exception was raised in a certain scneraio
- on Set Origin, Move to Origin and Move actions for Gerber and Excellon objects the source file will be also updated (the export functions will export an updated object)
+- in FlatCAMObj.export_gerber() method took into account the possibility of polygons of type 'clear' (the ones found in the Gerber files under the LPC command)
17.02.2020
From a2c0244e1884f51b056451543d3ba9c44ff5e954 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 20 Feb 2020 05:14:48 +0200
Subject: [PATCH 111/209] - in Paint Tool replaced the Selection radio with a
combobox GUI element that is more compact
---
FlatCAMApp.py | 2 +-
README.md | 6 +++-
flatcamGUI/PreferencesUI.py | 23 ++++++++------
flatcamTools/ToolPaint.py | 60 ++++++++++++++++++++-----------------
4 files changed, 53 insertions(+), 38 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index e06a211e..6c3b07b3 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -807,7 +807,7 @@ class App(QtCore.QObject):
"tools_paintoverlap": 20,
"tools_paintmargin": 0.0,
"tools_paintmethod": _("Seed"),
- "tools_selectmethod": "all",
+ "tools_selectmethod": _("All Polygons"),
"tools_pathconnect": True,
"tools_paintcontour": True,
"tools_paint_plotting": 'normal',
diff --git a/README.md b/README.md
index 128613cd..1dd45c89 100644
--- a/README.md
+++ b/README.md
@@ -9,9 +9,13 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+20.02.2020
+
+- in Paint Tool replaced the Selection radio with a combobox GUI element that is more compact
+
19.02.2020
-- fixed some issues in the Geometry Editor; the jump sigmal disconnect was failing for repeated Editor tool operation
+- fixed some issues in the Geometry Editor; the jump signal disconnect was failing for repeated Editor tool operation
- fixed an issue in Gerber Editor where the multiprocessing pool was reported as closed and an ValueError exception was raised in a certain scneraio
- on Set Origin, Move to Origin and Move actions for Gerber and Excellon objects the source file will be also updated (the export functions will export an updated object)
- in FlatCAMObj.export_gerber() method took into account the possibility of polygons of type 'clear' (the ones found in the Gerber files under the LPC command)
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index 7f8f9ec6..44de467e 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -5877,16 +5877,21 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
"- 'Reference Object' - will do non copper clearing within the area\n"
"specified by another object.")
)
- self.selectmethod_combo = RadioSet(
- [
- {"label": _("Polygon Selection"), "value": "single"},
- {"label": _("Area Selection"), "value": "area"},
- {"label": _("All Polygons"), "value": "all"},
- {"label": _("Reference Object"), "value": "ref"}
- ],
- orientation='vertical',
- stretch=None
+ # self.selectmethod_combo = RadioSet(
+ # [
+ # {"label": _("Polygon Selection"), "value": "single"},
+ # {"label": _("Area Selection"), "value": "area"},
+ # {"label": _("All Polygons"), "value": "all"},
+ # {"label": _("Reference Object"), "value": "ref"}
+ # ],
+ # orientation='vertical',
+ # stretch=None
+ # )
+ self.selectmethod_combo = FCComboBox()
+ self.selectmethod_combo.addItems(
+ [_("Polygon Selection"), _("Area Selection"), _("All Polygons"), _("Reference Object")]
)
+
grid0.addWidget(selectlabel, 15, 0)
grid0.addWidget(self.selectmethod_combo, 15, 1)
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 21eaf8a0..2e633d1e 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -463,25 +463,31 @@ class ToolPaint(FlatCAMTool, Gerber):
)
# grid3 = QtWidgets.QGridLayout()
- self.selectmethod_combo = RadioSet([
- {"label": _("Polygon Selection"), "value": "single"},
- {"label": _("Area Selection"), "value": "area"},
- {"label": _("All Polygons"), "value": "all"},
- {"label": _("Reference Object"), "value": "ref"}
- ], orientation='vertical', stretch=False)
- self.selectmethod_combo.setObjectName('p_selection')
- self.selectmethod_combo.setToolTip(
- _("How to select Polygons to be painted.\n"
- "- 'Polygon Selection' - left mouse click to add/remove polygons to be painted.\n"
- "- 'Area Selection' - left mouse click to start selection of the area to be painted.\n"
- "Keeping a modifier key pressed (CTRL or SHIFT) will allow to add multiple areas.\n"
- "- 'All Polygons' - the Paint will start after click.\n"
- "- 'Reference Object' - will do non copper clearing within the area\n"
- "specified by another object.")
- )
+ # self.selectmethod_combo = RadioSet([
+ # {"label": _("Polygon Selection"), "value": "single"},
+ # {"label": _("Area Selection"), "value": "area"},
+ # {"label": _("All Polygons"), "value": "all"},
+ # {"label": _("Reference Object"), "value": "ref"}
+ # ], orientation='vertical', stretch=False)
+ # self.selectmethod_combo.setObjectName('p_selection')
+ # self.selectmethod_combo.setToolTip(
+ # _("How to select Polygons to be painted.\n"
+ # "- 'Polygon Selection' - left mouse click to add/remove polygons to be painted.\n"
+ # "- 'Area Selection' - left mouse click to start selection of the area to be painted.\n"
+ # "Keeping a modifier key pressed (CTRL or SHIFT) will allow to add multiple areas.\n"
+ # "- 'All Polygons' - the Paint will start after click.\n"
+ # "- 'Reference Object' - will do non copper clearing within the area\n"
+ # "specified by another object.")
+ # )
- grid4.addWidget(selectlabel, 18, 0, 1, 2)
- grid4.addWidget(self.selectmethod_combo, 19, 0, 1, 2)
+ self.selectmethod_combo = FCComboBox()
+ self.selectmethod_combo.addItems(
+ [_("Polygon Selection"), _("Area Selection"), _("All Polygons"), _("Reference Object")]
+ )
+ self.selectmethod_combo.setObjectName('p_selection')
+
+ grid4.addWidget(selectlabel, 18, 0)
+ grid4.addWidget(self.selectmethod_combo, 18, 1)
form1 = QtWidgets.QFormLayout()
grid4.addLayout(form1, 20, 0, 1, 2)
@@ -624,7 +630,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.tools_table.clicked.connect(self.on_row_selection_change)
self.generate_paint_button.clicked.connect(self.on_paint_button_click)
- self.selectmethod_combo.activated_custom.connect(self.on_radio_selection)
+ self.selectmethod_combo.currentIndexChanged.connect(self.on_selection)
self.order_radio.activated_custom[str].connect(self.on_order_changed)
self.rest_cb.stateChanged.connect(self.on_rest_machining_check)
@@ -881,8 +887,8 @@ class ToolPaint(FlatCAMTool, Gerber):
else:
return float(self.addtool_entry.get_value())
- def on_radio_selection(self):
- if self.selectmethod_combo.get_value() == "ref":
+ def on_selection(self):
+ if self.selectmethod_combo.get_value() == _("Reference Object"):
self.box_combo.show()
self.box_combo_label.show()
self.box_combo_type.show()
@@ -893,11 +899,11 @@ class ToolPaint(FlatCAMTool, Gerber):
self.box_combo_type.hide()
self.box_combo_type_label.hide()
- if self.selectmethod_combo.get_value() == 'single':
+ if self.selectmethod_combo.get_value() == _("Polygon Selection"):
# disable rest-machining for single polygon painting
self.rest_cb.set_value(False)
self.rest_cb.setDisabled(True)
- if self.selectmethod_combo.get_value() == 'area':
+ if self.selectmethod_combo.get_value() == _("Area Selection"):
# disable rest-machining for single polygon painting
self.rest_cb.set_value(False)
self.rest_cb.setDisabled(True)
@@ -1362,7 +1368,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.app.inform.emit('[ERROR_NOTCL] %s' % _("No selected tools in Tool Table."))
return
- if self.select_method == "all":
+ if self.select_method == _("All Polygons"):
self.paint_poly_all(self.paint_obj,
tooldia=self.tooldia_list,
outname=self.o_name,
@@ -1370,7 +1376,7 @@ class ToolPaint(FlatCAMTool, Gerber):
connect=self.connect,
contour=self.contour)
- elif self.select_method == "single":
+ elif self.select_method == _("Polygon Selection"):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click on a polygon to paint it."))
# disengage the grid snapping since it may be hard to click on polygons with grid snapping on
@@ -1389,7 +1395,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.app.plotcanvas.graph_event_disconnect(self.app.mr)
self.app.plotcanvas.graph_event_disconnect(self.app.mp)
- elif self.select_method == "area":
+ elif self.select_method == _("Area Selection"):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click the start point of the paint area."))
if self.app.is_legacy is False:
@@ -1403,7 +1409,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.mr = self.app.plotcanvas.graph_event_connect('mouse_release', self.on_mouse_release)
self.mm = self.app.plotcanvas.graph_event_connect('mouse_move', self.on_mouse_move)
- elif self.select_method == 'ref':
+ elif self.select_method == _("Reference Object"):
self.bound_obj_name = self.box_combo.currentText()
# Get source object.
try:
From b6663ddd43814801201bed9224f84186cf620de7 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 20 Feb 2020 06:14:17 +0200
Subject: [PATCH 112/209] - in NCC Tool modified the UI
---
FlatCAMApp.py | 1 +
README.md | 1 +
flatcamTools/ToolNonCopperClear.py | 276 +++++++++++++++++------------
3 files changed, 167 insertions(+), 111 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 6c3b07b3..b242074c 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -773,6 +773,7 @@ class App(QtCore.QObject):
# NCC Tool
"tools_ncctools": "1.0, 0.5",
"tools_nccorder": 'rev',
+ "tools_nccoperation": 'clear',
"tools_nccoverlap": 40,
"tools_nccmargin": 1.0,
"tools_nccmethod": "seed",
diff --git a/README.md b/README.md
index 1dd45c89..ece4cbd9 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
20.02.2020
- in Paint Tool replaced the Selection radio with a combobox GUI element that is more compact
+- in NCC Tool modified the UI
19.02.2020
diff --git a/flatcamTools/ToolNonCopperClear.py b/flatcamTools/ToolNonCopperClear.py
index d07b9b63..d497c81b 100644
--- a/flatcamTools/ToolNonCopperClear.py
+++ b/flatcamTools/ToolNonCopperClear.py
@@ -124,8 +124,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.tools_table = FCTable()
self.tools_box.addWidget(self.tools_table)
- self.tools_table.setColumnCount(5)
- self.tools_table.setHorizontalHeaderLabels(['#', _('Diameter'), _('TT'), '', _("Operation")])
+ self.tools_table.setColumnCount(4)
+ self.tools_table.setHorizontalHeaderLabels(['#', _('Diameter'), _('TT'), ''])
self.tools_table.setColumnHidden(3, True)
self.tools_table.setSortingEnabled(False)
# self.tools_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
@@ -155,37 +155,17 @@ class NonCopperClear(FlatCAMTool, Gerber):
"Choosing the 'V-Shape' Tool Type automatically will select the Operation Type\n"
"in the resulting geometry as Isolation."))
- self.tools_table.horizontalHeaderItem(4).setToolTip(
- _("The 'Operation' can be:\n"
- "- Isolation -> will ensure that the non-copper clearing is always complete.\n"
- "If it's not successful then the non-copper clearing will fail, too.\n"
- "- Clear -> the regular non-copper clearing."))
+ # self.tools_table.horizontalHeaderItem(4).setToolTip(
+ # _("The 'Operation' can be:\n"
+ # "- Isolation -> will ensure that the non-copper clearing is always complete.\n"
+ # "If it's not successful then the non-copper clearing will fail, too.\n"
+ # "- Clear -> the regular non-copper clearing."))
grid1 = QtWidgets.QGridLayout()
self.tools_box.addLayout(grid1)
grid1.setColumnStretch(0, 0)
grid1.setColumnStretch(1, 1)
- # Milling Type Radio Button
- self.milling_type_label = QtWidgets.QLabel('%s:' % _('Milling Type'))
- self.milling_type_label.setToolTip(
- _("Milling type when the selected tool is of type: 'iso_op':\n"
- "- climb / best for precision milling and to reduce tool usage\n"
- "- conventional / useful when there is no backlash compensation")
- )
-
- self.milling_type_radio = RadioSet([{'label': _('Climb'), 'value': 'cl'},
- {'label': _('Conventional'), 'value': 'cv'}])
- self.milling_type_radio.setToolTip(
- _("Milling type when the selected tool is of type: 'iso_op':\n"
- "- climb / best for precision milling and to reduce tool usage\n"
- "- conventional / useful when there is no backlash compensation")
- )
- self.milling_type_radio.setObjectName(_("Milling Type"))
-
- grid1.addWidget(self.milling_type_label, 0, 0)
- grid1.addWidget(self.milling_type_radio, 0, 1)
-
# Tool order
self.ncc_order_label = QtWidgets.QLabel('%s:' % _('Tool order'))
self.ncc_order_label.setToolTip(_("This set the way that the tools in the tools table are used.\n"
@@ -213,9 +193,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
grid1.addWidget(separator_line, 2, 0, 1, 2)
- self.milling_type_label.hide()
- self.milling_type_radio.hide()
-
# #############################################################
# ############### Tool selection ##############################
# #############################################################
@@ -356,6 +333,47 @@ class NonCopperClear(FlatCAMTool, Gerber):
)
self.grid3.addWidget(self.tool_data_label, 12, 0, 1, 2)
+ # Operation
+ op_label = QtWidgets.QLabel('%s:' % _('Operation'))
+ op_label.setToolTip(
+ _("The 'Operation' can be:\n"
+ "- Isolation -> will ensure that the non-copper clearing is always complete.\n"
+ "If it's not successful then the non-copper clearing will fail, too.\n"
+ "- Clear -> the regular non-copper clearing.")
+ )
+
+ self.op_radio = RadioSet([
+ {"label": _("Clear"), "value": "clear"},
+ {"label": _("Isolation"), "value": "iso"}
+ ], orientation='horizontal', stretch=False)
+ self.op_radio.setObjectName("n_operation")
+
+ self.grid3.addWidget(op_label, 13, 0)
+ self.grid3.addWidget(self.op_radio, 13, 1)
+
+ # Milling Type Radio Button
+ self.milling_type_label = QtWidgets.QLabel('%s:' % _('Milling Type'))
+ self.milling_type_label.setToolTip(
+ _("Milling type when the selected tool is of type: 'iso_op':\n"
+ "- climb / best for precision milling and to reduce tool usage\n"
+ "- conventional / useful when there is no backlash compensation")
+ )
+
+ self.milling_type_radio = RadioSet([{'label': _('Climb'), 'value': 'cl'},
+ {'label': _('Conventional'), 'value': 'cv'}])
+ self.milling_type_radio.setToolTip(
+ _("Milling type when the selected tool is of type: 'iso_op':\n"
+ "- climb / best for precision milling and to reduce tool usage\n"
+ "- conventional / useful when there is no backlash compensation")
+ )
+ self.milling_type_radio.setObjectName("n_milling_type")
+
+ self.milling_type_label.setEnabled(False)
+ self.milling_type_radio.setEnabled(False)
+
+ self.grid3.addWidget(self.milling_type_label, 14, 0)
+ self.grid3.addWidget(self.milling_type_radio, 14, 1)
+
# Overlap Entry
nccoverlabel = QtWidgets.QLabel('%s:' % _('Overlap'))
nccoverlabel.setToolTip(
@@ -372,10 +390,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.ncc_overlap_entry.setWrapping(True)
self.ncc_overlap_entry.setRange(0.000, 99.9999)
self.ncc_overlap_entry.setSingleStep(0.1)
- self.ncc_overlap_entry.setObjectName(_("Overlap"))
+ self.ncc_overlap_entry.setObjectName("n_overlap")
- self.grid3.addWidget(nccoverlabel, 13, 0)
- self.grid3.addWidget(self.ncc_overlap_entry, 13, 1)
+ self.grid3.addWidget(nccoverlabel, 15, 0)
+ self.grid3.addWidget(self.ncc_overlap_entry, 15, 1)
# Margin
nccmarginlabel = QtWidgets.QLabel('%s:' % _('Margin'))
@@ -385,10 +403,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.ncc_margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.ncc_margin_entry.set_precision(self.decimals)
self.ncc_margin_entry.set_range(-9999.9999, 9999.9999)
- self.ncc_margin_entry.setObjectName(_("Margin"))
+ self.ncc_margin_entry.setObjectName("n_margin")
- self.grid3.addWidget(nccmarginlabel, 14, 0)
- self.grid3.addWidget(self.ncc_margin_entry, 14, 1)
+ self.grid3.addWidget(nccmarginlabel, 16, 0)
+ self.grid3.addWidget(self.ncc_margin_entry, 16, 1)
# Method
methodlabel = QtWidgets.QLabel('%s:' % _('Method'))
@@ -403,34 +421,34 @@ class NonCopperClear(FlatCAMTool, Gerber):
{"label": _("Seed-based"), "value": "seed"},
{"label": _("Straight lines"), "value": "lines"}
], orientation='vertical', stretch=False)
- self.ncc_method_radio.setObjectName(_("Method"))
+ self.ncc_method_radio.setObjectName("n_method")
- self.grid3.addWidget(methodlabel, 15, 0)
- self.grid3.addWidget(self.ncc_method_radio, 15, 1)
+ self.grid3.addWidget(methodlabel, 17, 0)
+ self.grid3.addWidget(self.ncc_method_radio, 17, 1)
# Connect lines
self.ncc_connect_cb = FCCheckBox('%s' % _("Connect"))
- self.ncc_connect_cb.setObjectName(_("Connect"))
+ self.ncc_connect_cb.setObjectName("n_connect")
self.ncc_connect_cb.setToolTip(
_("Draw lines between resulting\n"
"segments to minimize tool lifts.")
)
- self.grid3.addWidget(self.ncc_connect_cb, 16, 0)
+ self.grid3.addWidget(self.ncc_connect_cb, 18, 0)
# Contour
self.ncc_contour_cb = FCCheckBox('%s' % _("Contour"))
- self.ncc_contour_cb.setObjectName(_("Contour"))
+ self.ncc_contour_cb.setObjectName("n_contour")
self.ncc_contour_cb.setToolTip(
_("Cut around the perimeter of the polygon\n"
"to trim rough edges.")
)
- self.grid3.addWidget(self.ncc_contour_cb, 16, 1)
+ self.grid3.addWidget(self.ncc_contour_cb, 18, 1)
# ## NCC Offset choice
self.ncc_choice_offset_cb = FCCheckBox('%s' % _("Offset"))
- self.ncc_choice_offset_cb.setObjectName(_("Offset"))
+ self.ncc_choice_offset_cb.setObjectName("n_offset")
self.ncc_choice_offset_cb.setToolTip(
_("If used, it will add an offset to the copper features.\n"
@@ -445,7 +463,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.ncc_offset_spinner.set_range(0.00, 10.00)
self.ncc_offset_spinner.set_precision(4)
self.ncc_offset_spinner.setWrapping(True)
- self.ncc_offset_spinner.setObjectName(_("Offset value"))
+ self.ncc_offset_spinner.setObjectName("n_offset_value")
units = self.app.defaults['units'].upper()
if units == 'MM':
@@ -483,7 +501,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
# Rest Machining
self.ncc_rest_cb = FCCheckBox('%s' % _("Rest Machining"))
- self.ncc_rest_cb.setObjectName(_("Rest Machining"))
+ self.ncc_rest_cb.setObjectName("n_rest_machining")
self.ncc_rest_cb.setToolTip(
_("If checked, use 'rest machining'.\n"
@@ -503,7 +521,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
{"label": _("Area Selection"), "value": "area"},
{'label': _("Reference Object"), 'value': 'box'}
], orientation='vertical', stretch=False)
- self.reference_radio.setObjectName(_("Reference"))
+ self.reference_radio.setObjectName("n_reference")
self.reference_label = QtWidgets.QLabel('%s:' % _("Reference"))
self.reference_label.setToolTip(
@@ -638,6 +656,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.tooldia = None
self.form_fields = {
+ "nccoperation":self.op_radio,
"nccoverlap": self.ncc_overlap_entry,
"nccmargin": self.ncc_margin_entry,
"nccmethod": self.ncc_method_radio,
@@ -649,14 +668,15 @@ class NonCopperClear(FlatCAMTool, Gerber):
}
self.name2option = {
- _('Overlap'): "nccoverlap",
- _('Margin'): "nccmargin",
- _('Method'): "nccmethod",
- _("Connect"): "nccconnect",
- _("Contour"): "ncccontour",
- _("Offset"): "nccoffset",
- _("Offset value"): "nccoffset_value",
- _('Milling Type'): "milling_type",
+ "n_operation": "nccoperation",
+ "n_overlap": "nccoverlap",
+ "n_margin": "nccmargin",
+ "n_method": "nccmethod",
+ "n_connect": "nccconnect",
+ "n_contour": "ncccontour",
+ "n_offset": "nccoffset",
+ "n_offset_value": "nccoffset_value",
+ "n_milling_type": "milling_type",
}
self.old_tool_dia = None
@@ -673,6 +693,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.tipangle_entry.returnPressed.connect(self.on_calculate_tooldia)
self.cutz_entry.returnPressed.connect(self.on_calculate_tooldia)
+ self.op_radio.activated_custom.connect(self.on_operation_change)
+
self.box_combo_type.currentIndexChanged.connect(self.on_combo_box_type)
self.reference_radio.group_toggle_fn = self.on_toggle_reference
@@ -690,6 +712,21 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.object_combo.setCurrentIndex(0)
+ def on_operation_change(self, val):
+ if val == 'iso':
+ self.milling_type_label.setEnabled(True)
+ self.milling_type_radio.setEnabled(True)
+ else:
+ self.milling_type_label.setEnabled(False)
+ self.milling_type_radio.setEnabled(False)
+
+ current_row = self.tools_table.currentRow()
+ try:
+ current_uid = int(self.tools_table.item(current_row, 3).text())
+ self.ncc_tools[current_uid]['data']['nccoperation'] = val
+ except AttributeError:
+ return
+
def on_row_selection_change(self):
self.blockSignals(True)
@@ -740,7 +777,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
if form_key == storage_key:
try:
self.form_fields[form_key].set_value(dict_storage[form_key])
- except Exception:
+ except Exception as e:
+ log.debug("NonCopperClear.storage_to_form() --> %s" % str(e))
pass
def form_to_storage(self):
@@ -783,6 +821,20 @@ class NonCopperClear(FlatCAMTool, Gerber):
if row < 0:
row = 0
+ tooluid_item = int(self.tools_table.item(row, 3).text())
+ temp_tool_data = dict()
+
+ for tooluid_key, tooluid_val in self.ncc_tools.items():
+ if int(tooluid_key) == tooluid_item:
+ # this will hold the 'data' key of the self.tools[tool] dictionary that corresponds to
+ # the current row in the tool table
+ temp_tool_data = tooluid_val['data']
+ break
+
+ for tooluid_key, tooluid_val in self.ncc_tools.items():
+ tooluid_val['data'] = deepcopy(temp_tool_data)
+
+
# store all the data associated with the row parameter to the self.tools storage
tooldia_item = float(self.tools_table.item(row, 1).text())
type_item = self.tools_table.cellWidget(row, 2).currentText()
@@ -792,35 +844,35 @@ class NonCopperClear(FlatCAMTool, Gerber):
nccoffset_value_item = float(self.ncc_offset_spinner.get_value())
# this new dict will hold the actual useful data, another dict that is the value of key 'data'
- temp_tools = {}
- temp_dia = {}
- temp_data = {}
-
- for tooluid_key, tooluid_value in self.ncc_tools.items():
- for key, value in tooluid_value.items():
- if key == 'data':
- # update the 'data' section
- for data_key in tooluid_value[key].keys():
- for form_key, form_value in self.form_fields.items():
- if form_key == data_key:
- temp_data[data_key] = form_value.get_value()
- # make sure we make a copy of the keys not in the form (we may use 'data' keys that are
- # updated from self.app.defaults
- if data_key not in self.form_fields:
- temp_data[data_key] = value[data_key]
- temp_dia[key] = deepcopy(temp_data)
- temp_data.clear()
-
- elif key == 'solid_geometry':
- temp_dia[key] = deepcopy(self.tools[tooluid_key]['solid_geometry'])
- else:
- temp_dia[key] = deepcopy(value)
-
- temp_tools[tooluid_key] = deepcopy(temp_dia)
-
- self.ncc_tools.clear()
- self.ncc_tools = deepcopy(temp_tools)
- temp_tools.clear()
+ # temp_tools = {}
+ # temp_dia = {}
+ # temp_data = {}
+ #
+ # for tooluid_key, tooluid_value in self.ncc_tools.items():
+ # for key, value in tooluid_value.items():
+ # if key == 'data':
+ # # update the 'data' section
+ # for data_key in tooluid_value[key].keys():
+ # for form_key, form_value in self.form_fields.items():
+ # if form_key == data_key:
+ # temp_data[data_key] = form_value.get_value()
+ # # make sure we make a copy of the keys not in the form (we may use 'data' keys that are
+ # # updated from self.app.defaults
+ # if data_key not in self.form_fields:
+ # temp_data[data_key] = value[data_key]
+ # temp_dia[key] = deepcopy(temp_data)
+ # temp_data.clear()
+ #
+ # elif key == 'solid_geometry':
+ # temp_dia[key] = deepcopy(self.tools[tooluid_key]['solid_geometry'])
+ # else:
+ # temp_dia[key] = deepcopy(value)
+ #
+ # temp_tools[tooluid_key] = deepcopy(temp_dia)
+ #
+ # self.ncc_tools.clear()
+ # self.ncc_tools = deepcopy(temp_tools)
+ # temp_tools.clear()
self.app.inform.emit('[success] %s' % _("Current Tool parameters were applied to all tools."))
@@ -887,6 +939,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.type_obj_combo.set_value('gerber')
+ self.op_radio.set_value(self.app.defaults["tools_nccoperation"])
self.ncc_order_radio.set_value(self.app.defaults["tools_nccorder"])
self.ncc_overlap_entry.set_value(self.app.defaults["tools_nccoverlap"])
self.ncc_margin_entry.set_value(self.app.defaults["tools_nccmargin"])
@@ -935,6 +988,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
"toolchangexy": self.app.defaults["geometry_toolchangexy"],
"startz": self.app.defaults["geometry_startz"],
+ "nccoperation": self.app.defaults["tools_nccoperation"],
"nccmargin": self.app.defaults["tools_nccmargin"],
"nccmethod": self.app.defaults["tools_nccmethod"],
"nccconnect": self.app.defaults["tools_nccconnect"],
@@ -968,7 +1022,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
'offset_value': 0.0,
'type': 'Iso',
'tool_type': self.tool_type_radio.get_value(),
- 'operation': 'clear_op',
'data': deepcopy(self.default_data),
'solid_geometry': []
}
@@ -1032,13 +1085,12 @@ class NonCopperClear(FlatCAMTool, Gerber):
tool_uid_item = QtWidgets.QTableWidgetItem(str(int(tooluid_key)))
- operation_type = FCComboBox()
- operation_type.addItem('iso_op')
- # operation_type.setStyleSheet('background-color: rgb(255,255,255)')
- operation_type.addItem('clear_op')
- # operation_type.setStyleSheet('background-color: rgb(255,255,255)')
- op_idx = operation_type.findText(tooluid_value['operation'])
- operation_type.setCurrentIndex(op_idx)
+ # operation_type = FCComboBox()
+ # operation_type.addItems(['iso_op', 'clear_op'])
+ #
+ # # operation_type.setStyleSheet('background-color: rgb(255,255,255)')
+ # op_idx = operation_type.findText(tooluid_value['operation'])
+ # operation_type.setCurrentIndex(op_idx)
self.tools_table.setItem(row_no, 1, dia) # Diameter
self.tools_table.setCellWidget(row_no, 2, tool_type_item)
@@ -1046,7 +1098,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
# ## REMEMBER: THIS COLUMN IS HIDDEN IN OBJECTUI.PY # ##
self.tools_table.setItem(row_no, 3, tool_uid_item) # Tool unique ID
- self.tools_table.setCellWidget(row_no, 4, operation_type)
+ # self.tools_table.setCellWidget(row_no, 4, operation_type)
# make the diameter column editable
for row in range(tool_id):
@@ -1237,19 +1289,19 @@ class NonCopperClear(FlatCAMTool, Gerber):
'tool_type': tt,
})
- if cw_col == 4:
- op = cw.currentText()
-
- if op == 'iso_op':
- self.milling_type_label.show()
- self.milling_type_radio.show()
- else:
- self.milling_type_label.hide()
- self.milling_type_radio.hide()
-
- self.ncc_tools[current_uid].update({
- 'operation': op
- })
+ # if cw_col == 4:
+ # op = cw.currentText()
+ #
+ # if op == 'iso_op':
+ # self.milling_type_label.show()
+ # self.milling_type_radio.show()
+ # else:
+ # self.milling_type_label.hide()
+ # self.milling_type_radio.hide()
+ #
+ # self.ncc_tools[current_uid].update({
+ # 'operation': op
+ # })
def on_tool_type(self, val):
if val == 'V':
@@ -1350,7 +1402,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
'offset_value': 0.0,
'type': 'Iso',
'tool_type': self.tool_type_radio.get_value(),
- 'operation': 'clear_op',
'data': deepcopy(self.default_data),
'solid_geometry': []
}
@@ -2022,9 +2073,12 @@ class NonCopperClear(FlatCAMTool, Gerber):
else:
sorted_tools = ncctooldia
else:
- for row in range(self.tools_table.rowCount()):
- if self.tools_table.cellWidget(row, 1).currentText() == 'clear_op':
- sorted_tools.append(float(self.tools_table.item(row, 1).text()))
+ # for row in range(self.tools_table.rowCount()):
+ # if self.tools_table.cellWidget(row, 1).currentText() == 'clear_op':
+ # sorted_tools.append(float(self.tools_table.item(row, 1).text()))
+ for tooluid in self.ncc_tools:
+ if self.ncc_tools[tooluid]['data']['nccoperation'] == 'clear':
+ sorted_tools.append(self.ncc_tools[tooluid]['tooldia'])
# ########################################################################################################
# set the name for the future Geometry object
From 522b98fef330aa621271c277835165dea5e27ca0 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Tue, 25 Feb 2020 21:22:51 +0200
Subject: [PATCH 113/209] - fixed bug in Gerber parser: it tried to calculate a
len() for a single element and not a list - a Gerber generated by Eagle
exhibited this
---
README.md | 4 ++
flatcamParsers/ParseGerber.py | 93 +++++++++++++++++++++++++++++------
2 files changed, 83 insertions(+), 14 deletions(-)
diff --git a/README.md b/README.md
index ece4cbd9..96d1605c 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+25.02.2020
+
+- fixed bug in Gerber parser: it tried to calculate a len() for a single element and not a list - a Gerber generated by Eagle exhibited this
+
20.02.2020
- in Paint Tool replaced the Selection radio with a combobox GUI element that is more compact
diff --git a/flatcamParsers/ParseGerber.py b/flatcamParsers/ParseGerber.py
index 235521b4..bfa36a4b 100644
--- a/flatcamParsers/ParseGerber.py
+++ b/flatcamParsers/ParseGerber.py
@@ -456,7 +456,12 @@ class Gerber(Geometry):
new_polarity = match.group(1)
# log.info("Polarity CHANGE, LPC = %s, poly_buff = %s" % (self.is_lpc, poly_buffer))
self.is_lpc = True if new_polarity == 'C' else False
- if len(path) > 1 and current_polarity != new_polarity:
+ try:
+ path_length = len(path)
+ except TypeError:
+ path_length = 1
+
+ if path_length > 1 and current_polarity != new_polarity:
# finish the current path and add it to the storage
# --- Buffered ----
@@ -491,7 +496,12 @@ class Gerber(Geometry):
# --- Apply buffer ---
# If added for testing of bug #83
# TODO: Remove when bug fixed
- if len(poly_buffer) > 0:
+ try:
+ buff_length = len(poly_buffer)
+ except TypeError:
+ buff_length = 1
+
+ if buff_length > 0:
if current_polarity == 'D':
self.solid_geometry = self.solid_geometry.union(cascaded_union(poly_buffer))
@@ -714,7 +724,12 @@ class Gerber(Geometry):
# log.debug(self.apertures[current_aperture])
# Take care of the current path with the previous tool
- if len(path) > 1:
+ try:
+ path_length = len(path)
+ except TypeError:
+ path_length = 1
+
+ if path_length > 1:
if self.apertures[last_path_aperture]["type"] == 'R':
# do nothing because 'R' type moving aperture is none at once
pass
@@ -751,7 +766,12 @@ class Gerber(Geometry):
# ################ G36* - Begin region ########################
# ################################################################
if self.regionon_re.search(gline):
- if len(path) > 1:
+ try:
+ path_length = len(path)
+ except TypeError:
+ path_length = 1
+
+ if path_length > 1:
# Take care of what is left in the path
geo_dict = dict()
@@ -799,7 +819,12 @@ class Gerber(Geometry):
# if D02 happened before G37 we now have a path with 1 element only; we have to add the current
# geo to the poly_buffer otherwise we loose it
if current_operation_code == 2:
- if len(path) == 1:
+ try:
+ path_length = len(path)
+ except TypeError:
+ path_length = 1
+
+ if path_length == 1:
# this means that the geometry was prepared previously and we just need to add it
geo_dict = dict()
if geo_f:
@@ -825,7 +850,12 @@ class Gerber(Geometry):
# Only one path defines region?
# This can happen if D02 happened before G37 and
# is not and error.
- if len(path) < 3:
+ try:
+ path_length = len(path)
+ except TypeError:
+ path_length = 1
+
+ if path_length < 3:
# print "ERROR: Path contains less than 3 points:"
# path = [[current_x, current_y]]
continue
@@ -974,7 +1004,12 @@ class Gerber(Geometry):
_("GERBER file might be CORRUPT. Check the file !!!"))
elif current_operation_code == 2:
- if len(path) > 1:
+ try:
+ path_length = len(path)
+ except TypeError:
+ path_length = 1
+
+ if path_length > 1:
geo_s = None
geo_dict = dict()
@@ -1073,7 +1108,12 @@ class Gerber(Geometry):
elif current_operation_code == 3:
# Create path draw so far.
- if len(path) > 1:
+ try:
+ path_length = len(path)
+ except TypeError:
+ path_length = 1
+
+ if path_length > 1:
# --- Buffered ----
geo_dict = dict()
@@ -1229,7 +1269,12 @@ class Gerber(Geometry):
# Nothing created! Pen Up.
if current_operation_code == 2:
log.warning("Arc with D2. (%d)" % line_num)
- if len(path) > 1:
+ try:
+ path_length = len(path)
+ except TypeError:
+ path_length = 1
+
+ if path_length > 1:
geo_dict = dict()
if last_path_aperture is None:
@@ -1372,7 +1417,12 @@ class Gerber(Geometry):
# ################################################################
log.warning("Line ignored (%d): %s" % (line_num, gline))
- if len(path) > 1:
+ try:
+ path_length = len(path)
+ except TypeError:
+ path_length = 1
+
+ if path_length > 1:
# In case that G01 (moving) aperture is rectangular, there is no need to still create
# another geo since we already created a shapely box using the start and end coordinates found in
# path variable. We do it only for other apertures than 'R' type
@@ -1415,15 +1465,25 @@ class Gerber(Geometry):
# this treats the case when we are storing geometry as solids
try:
- if len(poly_buffer) == 0 and len(self.solid_geometry) == 0:
+ buff_length = len(poly_buffer)
+ except TypeError:
+ buff_length = 1
+
+ try:
+ sol_geo_length = len(self.solid_geometry)
+ except TypeError:
+ sol_geo_length = 1
+
+ try:
+ if buff_length == 0 and sol_geo_length == 0:
log.error("Object is not Gerber file or empty. Aborting Object creation.")
return 'fail'
except TypeError as e:
log.error("Object is not Gerber file or empty. Aborting Object creation. %s" % str(e))
return 'fail'
- log.warning("Joining %d polygons." % len(poly_buffer))
- self.app.inform.emit('%s: %d.' % (_("Gerber processing. Joining polygons"), len(poly_buffer)))
+ log.warning("Joining %d polygons." % buff_length)
+ self.app.inform.emit('%s: %d.' % (_("Gerber processing. Joining polygons"), buff_length))
if self.use_buffer_for_union:
log.debug("Union by buffer...")
@@ -1729,7 +1789,12 @@ class Gerber(Geometry):
if type(geos) == list:
# HACK for importing QRCODE exported by FlatCAM
- if len(geos) == 1:
+ try:
+ geos_length = len(geos)
+ except TypeError:
+ geos_length = 1
+
+ if geos_length == 1:
geo_qrcode = list()
geo_qrcode.append(Polygon(geos[0].exterior))
for i_el in geos[0].interiors:
From 8a6ada1984cc4821a20e51e319257c88d018a354 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 26 Feb 2020 04:43:54 +0200
Subject: [PATCH 114/209] - added a new parameter named 'End Move X,Y' for the
Geometry and Excellon objects. Adding a tuple of coordinates in this field
will control the X,Y position of the final move; not entering a value there
will cause not to make an end move
---
FlatCAMApp.py | 26 ++++++-
FlatCAMObj.py | 18 ++++-
README.md | 1 +
camlib.py | 27 ++++++-
flatcamEditors/FlatCAMExcEditor.py | 1 +
flatcamGUI/GUIElements.py | 2 +
flatcamGUI/ObjectUI.py | 42 ++++++++---
flatcamGUI/PreferencesUI.py | 70 +++++++++++++------
flatcamParsers/ParseHPGL2.py | 2 +
flatcamTools/ToolNonCopperClear.py | 2 +
flatcamTools/ToolPaint.py | 2 +
preprocessors/Berta_CNC.py | 4 +-
preprocessors/GRBL_laser.py | 4 +-
preprocessors/ISEL_CNC.py | 4 +-
preprocessors/Marlin.py | 4 +-
preprocessors/Marlin_laser_use_FAN_pin.py | 4 +-
preprocessors/Marlin_laser_use_Spindle_pin.py | 4 +-
preprocessors/Paste_1.py | 4 +-
preprocessors/Repetier.py | 4 +-
preprocessors/Toolchange_Custom.py | 4 +-
preprocessors/Toolchange_Probe_MACH3.py | 4 +-
preprocessors/Toolchange_manual.py | 7 +-
preprocessors/default.py | 6 +-
preprocessors/grbl_11.py | 4 +-
preprocessors/line_xyz.py | 4 +-
tclCommands/TclCommandCopperClear.py | 1 +
tclCommands/TclCommandPaint.py | 2 +
27 files changed, 189 insertions(+), 68 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index b242074c..a9d4cbca 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -643,6 +643,7 @@ class App(QtCore.QObject):
"excellon_depthperpass": 0.7,
"excellon_travelz": 2,
"excellon_endz": 0.5,
+ "excellon_endxy": None,
"excellon_feedrate_z": 300,
"excellon_spindlespeed": 0,
"excellon_dwell": False,
@@ -710,6 +711,8 @@ class App(QtCore.QObject):
"geometry_toolchange": False,
"geometry_toolchangez": 15.0,
"geometry_endz": 15.0,
+ "geometry_endxy": None,
+
"geometry_feedrate": 120,
"geometry_feedrate_z": 60,
"geometry_spindlespeed": 0,
@@ -1326,6 +1329,8 @@ class App(QtCore.QObject):
"excellon_depthperpass": self.ui.excellon_defaults_form.excellon_opt_group.maxdepth_entry,
"excellon_travelz": self.ui.excellon_defaults_form.excellon_opt_group.travelz_entry,
"excellon_endz": self.ui.excellon_defaults_form.excellon_opt_group.endz_entry,
+ "excellon_endxy": self.ui.excellon_defaults_form.excellon_opt_group.endxy_entry,
+
"excellon_feedrate_z": self.ui.excellon_defaults_form.excellon_opt_group.feedrate_z_entry,
"excellon_spindlespeed": self.ui.excellon_defaults_form.excellon_opt_group.spindlespeed_entry,
"excellon_dwell": self.ui.excellon_defaults_form.excellon_opt_group.dwell_cb,
@@ -1404,6 +1409,7 @@ class App(QtCore.QObject):
"geometry_toolchange": self.ui.geometry_defaults_form.geometry_opt_group.toolchange_cb,
"geometry_toolchangez": self.ui.geometry_defaults_form.geometry_opt_group.toolchangez_entry,
"geometry_endz": self.ui.geometry_defaults_form.geometry_opt_group.endz_entry,
+ "geometry_endxy": self.ui.geometry_defaults_form.geometry_opt_group.endxy_entry,
"geometry_depthperpass": self.ui.geometry_defaults_form.geometry_opt_group.depthperpass_entry,
"geometry_multidepth": self.ui.geometry_defaults_form.geometry_opt_group.multidepth_cb,
@@ -5959,13 +5965,15 @@ class App(QtCore.QObject):
'excellon_cutz', 'excellon_travelz', "excellon_toolchangexy", 'excellon_offset',
'excellon_feedrate', 'excellon_feedrate_rapid', 'excellon_toolchangez',
- 'excellon_tooldia', 'excellon_slot_tooldia', 'excellon_endz', "excellon_feedrate_probe",
+ 'excellon_tooldia', 'excellon_slot_tooldia', 'excellon_endz', 'excellon_endxy',
+ "excellon_feedrate_probe",
"excellon_z_pdepth", "excellon_editor_newdia", "excellon_editor_lin_pitch",
"excellon_editor_slot_lin_pitch",
'geometry_cutz', "geometry_depthperpass", 'geometry_travelz', 'geometry_feedrate',
'geometry_feedrate_rapid', "geometry_toolchangez", "geometry_feedrate_z",
- "geometry_toolchangexy", 'geometry_cnctooldia', 'geometry_endz', "geometry_z_pdepth",
+ "geometry_toolchangexy", 'geometry_cnctooldia', 'geometry_endz', 'geometry_endxy',
+ "geometry_z_pdepth",
"geometry_feedrate_probe", "geometry_startz",
'cncjob_tooldia',
@@ -6013,6 +6021,20 @@ class App(QtCore.QObject):
coords_xy[1] *= sfactor
self.defaults['geometry_toolchangexy'] = "%.*f, %.*f" % (self.decimals, coords_xy[0],
self.decimals, coords_xy[1])
+ elif dim == 'excellon_endxy':
+ coordinates = self.defaults["excellon_endxy"].split(",")
+ end_coords_xy = [float(eval(a)) for a in coordinates if a != '']
+ end_coords_xy[0] *= sfactor
+ end_coords_xy[1] *= sfactor
+ self.defaults['excellon_endxy'] = "%.*f, %.*f" % (self.decimals, end_coords_xy[0],
+ self.decimals, end_coords_xy[1])
+ elif dim == 'geometry_endxy':
+ coordinates = self.defaults["geometry_endxy"].split(",")
+ end_coords_xy = [float(eval(a)) for a in coordinates if a != '']
+ end_coords_xy[0] *= sfactor
+ end_coords_xy[1] *= sfactor
+ self.defaults['geometry_endxy'] = "%.*f, %.*f" % (self.decimals, end_coords_xy[0],
+ self.decimals, end_coords_xy[1])
elif dim == 'geometry_cnctooldia':
if type(self.defaults["geometry_cnctooldia"]) == float:
tools_diameters = [self.defaults["geometry_cnctooldia"]]
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 6d8f640a..7734e4b5 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -2401,6 +2401,8 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
"extracut": self.app.defaults["geometry_extracut"],
"extracut_length":self.app.defaults["geometry_extracut_length"],
"endz": 2.0,
+ "endxy": '',
+
"startz": None,
"offset": 0.0,
"spindlespeed": 0,
@@ -2887,6 +2889,8 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
"startz": self.ui.estartz_entry,
"endz": self.ui.endz_entry,
+ "endxy": self.ui.endxy_entry,
+
"offset": self.ui.offset_entry,
"ppname_e": self.ui.pp_excellon_name_cb,
@@ -3744,6 +3748,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
job_obj.z_toolchange = float(self.options["toolchangez"])
job_obj.startz = float(self.options["startz"]) if self.options["startz"] else None
job_obj.endz = float(self.options["endz"])
+ job_obj.xy_end = self.options["endxy"]
job_obj.excellon_optimization_type = self.app.defaults["excellon_optimization_type"]
tools_csv = ','.join(tools)
@@ -3987,6 +3992,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
"extracut": False,
"extracut_length": 0.1,
"endz": 2.0,
+ "endxy": '',
+
"startz": None,
"toolchange": False,
"toolchangez": 1.0,
@@ -4259,6 +4266,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
"toolchange": self.ui.toolchangeg_cb,
"toolchangez": self.ui.toolchangez_entry,
"endz": self.ui.endz_entry,
+ "endxy": self.ui.endxy_entry,
"cnctooldia": self.ui.addtool_entry
})
@@ -4298,6 +4306,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
"toolchange": None,
"toolchangez": None,
"endz": None,
+ "endxy": '',
"spindlespeed": 0,
"toolchangexy": None,
"startz": None
@@ -5645,6 +5654,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
toolchangexy = tools_dict[tooluid_key]['data']["toolchangexy"]
startz = tools_dict[tooluid_key]['data']["startz"]
endz = tools_dict[tooluid_key]['data']["endz"]
+ endxy = self.options["endxy"]
spindlespeed = tools_dict[tooluid_key]['data']["spindlespeed"]
dwell = tools_dict[tooluid_key]['data']["dwell"]
dwelltime = tools_dict[tooluid_key]['data']["dwelltime"]
@@ -5670,7 +5680,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
feedrate=feedrate, feedrate_z=feedrate_z, feedrate_rapid=feedrate_rapid,
spindlespeed=spindlespeed, spindledir=spindledir, dwell=dwell, dwelltime=dwelltime,
multidepth=multidepth, depthpercut=depthpercut,
- extracut=extracut, extracut_length=extracut_length, startz=startz, endz=endz,
+ extracut=extracut, extracut_length=extracut_length, startz=startz, endz=endz, endxy=endxy,
toolchange=toolchange, toolchangez=toolchangez, toolchangexy=toolchangexy,
pp_geometry_name=pp_geometry_name,
tool_no=tool_cnt)
@@ -5797,6 +5807,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
toolchangexy = tools_dict[tooluid_key]['data']["toolchangexy"]
startz = tools_dict[tooluid_key]['data']["startz"]
endz = tools_dict[tooluid_key]['data']["endz"]
+ endxy = self.options["endxy"]
spindlespeed = tools_dict[tooluid_key]['data']["spindlespeed"]
dwell = tools_dict[tooluid_key]['data']["dwell"]
dwelltime = tools_dict[tooluid_key]['data']["dwelltime"]
@@ -5822,7 +5833,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
feedrate=feedrate, feedrate_z=feedrate_z, feedrate_rapid=feedrate_rapid,
spindlespeed=spindlespeed, spindledir=spindledir, dwell=dwell, dwelltime=dwelltime,
multidepth=multidepth, depthpercut=depthpercut,
- extracut=extracut, extracut_length=extracut_length, startz=startz, endz=endz,
+ extracut=extracut, extracut_length=extracut_length, startz=startz, endz=endz, endxy=endxy,
toolchange=toolchange, toolchangez=toolchangez, toolchangexy=toolchangexy,
pp_geometry_name=pp_geometry_name,
tool_no=tool_cnt)
@@ -5932,6 +5943,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
startz = startz if startz is not None else self.options["startz"]
endz = endz if endz is not None else float(self.options["endz"])
+ endxy = self.options["endxy"]
toolchangez = toolchangez if toolchangez else float(self.options["toolchangez"])
toolchangexy = toolchangexy if toolchangexy else self.options["toolchangexy"]
@@ -5981,7 +5993,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
spindlespeed=spindlespeed, dwell=dwell, dwelltime=dwelltime,
multidepth=multidepth, depthpercut=depthperpass,
toolchange=toolchange, toolchangez=toolchangez, toolchangexy=toolchangexy,
- extracut=extracut, extracut_length=extracut_length, startz=startz, endz=endz,
+ extracut=extracut, extracut_length=extracut_length, startz=startz, endz=endz, endxy=endxy,
pp_geometry_name=ppname_g
)
diff --git a/README.md b/README.md
index 96d1605c..3c172ff0 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
25.02.2020
- fixed bug in Gerber parser: it tried to calculate a len() for a single element and not a list - a Gerber generated by Eagle exhibited this
+- added a new parameter named 'End Move X,Y' for the Geometry and Excellon objects. Adding a tuple of coordinates in this field will control the X,Y position of the final move; not entering a value there will cause not to make an end move
20.02.2020
diff --git a/camlib.py b/camlib.py
index bb402eb8..b56d65f5 100644
--- a/camlib.py
+++ b/camlib.py
@@ -2415,7 +2415,7 @@ class CNCjob(Geometry):
depthpercut=0.1, z_pdepth=-0.02,
spindlespeed=None, spindledir='CW', dwell=True, dwelltime=1000,
toolchangez=0.787402, toolchange_xy=[0.0, 0.0],
- endz=2.0,
+ endz=2.0, endxy='',
segx=None,
segy=None,
steps_per_circle=None):
@@ -2447,6 +2447,7 @@ class CNCjob(Geometry):
self.startz = None
self.z_end = endz
+ self.xy_end = endxy
self.multidepth = False
self.z_depthpercut = depthpercut
@@ -2656,6 +2657,12 @@ class CNCjob(Geometry):
log.debug("camlib.CNCJob.generate_from_excellon_by_tool() --> %s" % str(e))
pass
+ self.xy_end = [float(eval(a)) for a in self.xy_end.split(",")]
+ if len(self.xy_end) < 2:
+ self.app.inform.emit('[ERROR] %s' % _("The End Move X,Y field in Edit -> Preferences has to be "
+ "in the format (x, y) but now there is only one value, not two."))
+ return 'fail'
+
self.pp_excellon = self.app.preprocessors[self.pp_excellon_name]
p = self.pp_excellon
@@ -3438,7 +3445,7 @@ class CNCjob(Geometry):
spindlespeed=None, spindledir='CW', dwell=False, dwelltime=1.0,
multidepth=False, depthpercut=None,
toolchange=False, toolchangez=1.0, toolchangexy="0.0, 0.0", extracut=False, extracut_length=0.2,
- startz=None, endz=2.0, pp_geometry_name=None, tool_no=1):
+ startz=None, endz=2.0, endxy='', pp_geometry_name=None, tool_no=1):
"""
Algorithm to generate from multitool Geometry.
@@ -3472,6 +3479,7 @@ class CNCjob(Geometry):
:param extracut_length: Extra cut legth at the end of the path
:param startz:
:param endz:
+ :param endxy:
:param pp_geometry_name:
:param tool_no:
:return: GCode - string
@@ -3511,6 +3519,12 @@ class CNCjob(Geometry):
self.startz = float(startz) if startz is not None else None
self.z_end = float(endz) if endz is not None else None
+ self.xy_end = [float(eval(a)) for a in endxy.split(",")]
+ if len(self.xy_end) < 2:
+ self.app.inform.emit('[ERROR] %s' % _("The End Move X,Y field in Edit -> Preferences has to be "
+ "in the format (x, y) but now there is only one value, not two."))
+ return 'fail'
+
self.z_depthpercut = float(depthpercut) if depthpercut else None
self.multidepth = multidepth
@@ -3747,7 +3761,7 @@ class CNCjob(Geometry):
spindlespeed=None, spindledir='CW', dwell=False, dwelltime=None,
multidepth=False, depthpercut=None,
toolchange=False, toolchangez=None, toolchangexy="0.0, 0.0",
- extracut=False, extracut_length=None, startz=None, endz=None,
+ extracut=False, extracut_length=None, startz=None, endz=None, endxy='',
pp_geometry_name=None, tool_no=1):
"""
Second algorithm to generate from Geometry.
@@ -3872,6 +3886,13 @@ class CNCjob(Geometry):
self.startz = float(startz) if startz is not None else self.app.defaults["geometry_startz"]
self.z_end = float(endz) if endz is not None else self.app.defaults["geometry_endz"]
+ self.xy_end = endxy if endxy != '' else self.app.defaults["geometry_endxy"]
+ self.xy_end = [float(eval(a)) for a in self.xy_end.split(",")]
+ if len(self.xy_end) < 2:
+ self.app.inform.emit('[ERROR] %s' % _("The End Move X,Y field in Edit -> Preferences has to be "
+ "in the format (x, y) but now there is only one value, not two."))
+ return 'fail'
+
self.z_depthpercut = float(depthpercut) if depthpercut is not None else 0.0
self.multidepth = multidepth
self.z_toolchange = float(toolchangez) if toolchangez is not None else self.app.defaults["geometry_toolchangez"]
diff --git a/flatcamEditors/FlatCAMExcEditor.py b/flatcamEditors/FlatCAMExcEditor.py
index 5897b9cb..1be311ba 100644
--- a/flatcamEditors/FlatCAMExcEditor.py
+++ b/flatcamEditors/FlatCAMExcEditor.py
@@ -2209,6 +2209,7 @@ class FlatCAMExcEditor(QtCore.QObject):
"extracut": self.app.defaults["geometry_extracut"],
"extracut_length": self.app.defaults["geometry_extracut_length"],
"endz": self.app.defaults["excellon_endz"],
+ "endxy": self.app.defaults["excellon_endxy"],
"startz": self.app.defaults["excellon_startz"],
"offset": self.app.defaults["excellon_offset"],
"spindlespeed": self.app.defaults["excellon_spindlespeed"],
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index d53575d2..fd144564 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -444,6 +444,8 @@ class FCEntry(QtWidgets.QLineEdit):
decimal_digits = decimals if decimals is not None else self.decimals
if type(val) is float:
self.setText('%.*f' % (decimal_digits, val))
+ elif val is None:
+ self.setText('')
else:
self.setText(str(val))
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index c4204765..e819f4a3 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -1220,6 +1220,18 @@ class ExcellonObjectUI(ObjectUI):
self.grid5.addWidget(self.endz_label, 11, 0)
self.grid5.addWidget(self.endz_entry, 11, 1)
+ # End Move X,Y
+ endmove_xy_label = QtWidgets.QLabel('%s:' % _('End move X,Y'))
+ endmove_xy_label.setToolTip(
+ _("End move X,Y position.\n"
+ "If no value is entered then there is no move\n"
+ "on X,Y plane at the end of the job.")
+ )
+ self.endxy_entry = FCEntry()
+
+ self.grid5.addWidget(endmove_xy_label, 12, 0)
+ self.grid5.addWidget(self.endxy_entry, 12, 1)
+
# Probe depth
self.pdepth_label = QtWidgets.QLabel('%s:' % _("Probe Z depth"))
self.pdepth_label.setToolTip(
@@ -1232,8 +1244,8 @@ class ExcellonObjectUI(ObjectUI):
self.pdepth_entry.set_range(-9999.9999, 9999.9999)
self.pdepth_entry.setSingleStep(0.1)
- self.grid5.addWidget(self.pdepth_label, 12, 0)
- self.grid5.addWidget(self.pdepth_entry, 12, 1)
+ self.grid5.addWidget(self.pdepth_label, 13, 0)
+ self.grid5.addWidget(self.pdepth_entry, 13, 1)
self.pdepth_label.hide()
self.pdepth_entry.setVisible(False)
@@ -1250,8 +1262,8 @@ class ExcellonObjectUI(ObjectUI):
self.feedrate_probe_entry.setSingleStep(0.1)
self.feedrate_probe_entry.setObjectName(_("e_fr_probe"))
- self.grid5.addWidget(self.feedrate_probe_label, 13, 0)
- self.grid5.addWidget(self.feedrate_probe_entry, 13, 1)
+ self.grid5.addWidget(self.feedrate_probe_label, 14, 0)
+ self.grid5.addWidget(self.feedrate_probe_entry, 14, 1)
self.feedrate_probe_label.hide()
self.feedrate_probe_entry.setVisible(False)
@@ -1265,8 +1277,8 @@ class ExcellonObjectUI(ObjectUI):
self.pp_excellon_name_cb = FCComboBox()
self.pp_excellon_name_cb.setFocusPolicy(QtCore.Qt.StrongFocus)
- self.grid5.addWidget(pp_excellon_label, 14, 0)
- self.grid5.addWidget(self.pp_excellon_name_cb, 14, 1)
+ self.grid5.addWidget(pp_excellon_label, 15, 0)
+ self.grid5.addWidget(self.pp_excellon_name_cb, 15, 1)
# Preprocessor Geometry selection
pp_geo_label = QtWidgets.QLabel('%s:' % _("Preprocessor G"))
@@ -1277,13 +1289,13 @@ class ExcellonObjectUI(ObjectUI):
self.pp_geo_name_cb = FCComboBox()
self.pp_geo_name_cb.setFocusPolicy(QtCore.Qt.StrongFocus)
- self.grid5.addWidget(pp_geo_label, 15, 0)
- self.grid5.addWidget(self.pp_geo_name_cb, 15, 1)
+ self.grid5.addWidget(pp_geo_label, 16, 0)
+ self.grid5.addWidget(self.pp_geo_name_cb, 16, 1)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.grid5.addWidget(separator_line, 16, 0, 1, 2)
+ self.grid5.addWidget(separator_line, 17, 0, 1, 2)
# #################################################################
# ################# GRID LAYOUT 6 ###############################
@@ -1974,6 +1986,18 @@ class GeometryObjectUI(ObjectUI):
self.grid4.addWidget(self.endz_label, 9, 0)
self.grid4.addWidget(self.endz_entry, 9, 1)
+ # End Move X,Y
+ endmove_xy_label = QtWidgets.QLabel('%s:' % _('End move X,Y'))
+ endmove_xy_label.setToolTip(
+ _("End move X,Y position.\n"
+ "If no value is entered then there is no move\n"
+ "on X,Y plane at the end of the job.")
+ )
+ self.endxy_entry = FCEntry()
+
+ self.grid4.addWidget(endmove_xy_label, 10, 0)
+ self.grid4.addWidget(self.endxy_entry, 10, 1)
+
# preprocessor selection
pp_label = QtWidgets.QLabel('%s:' % _("Preprocessor"))
pp_label.setToolTip(
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index 44de467e..6c7781b7 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -3229,6 +3229,18 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
grid2.addWidget(endz_label, 8, 0)
grid2.addWidget(self.endz_entry, 8, 1)
+ # End Move X,Y
+ endmove_xy_label = QtWidgets.QLabel('%s:' % _('End move X,Y'))
+ endmove_xy_label.setToolTip(
+ _("End move X,Y position.\n"
+ "If no value is entered then there is no move\n"
+ "on X,Y plane at the end of the job.")
+ )
+ self.endxy_entry = FCEntry()
+
+ grid2.addWidget(endmove_xy_label, 9, 0)
+ grid2.addWidget(self.endxy_entry, 9, 1)
+
# Feedrate Z
frlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z'))
frlabel.setToolTip(
@@ -3241,8 +3253,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
self.feedrate_z_entry.set_precision(self.decimals)
self.feedrate_z_entry.set_range(0, 99999.9999)
- grid2.addWidget(frlabel, 9, 0)
- grid2.addWidget(self.feedrate_z_entry, 9, 1)
+ grid2.addWidget(frlabel, 10, 0)
+ grid2.addWidget(self.feedrate_z_entry, 10, 1)
# Spindle speed
spdlabel = QtWidgets.QLabel('%s:' % _('Spindle Speed'))
@@ -3255,8 +3267,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
self.spindlespeed_entry.set_range(0, 1000000)
self.spindlespeed_entry.set_step(100)
- grid2.addWidget(spdlabel, 10, 0)
- grid2.addWidget(self.spindlespeed_entry, 10, 1)
+ grid2.addWidget(spdlabel, 11, 0)
+ grid2.addWidget(self.spindlespeed_entry, 11, 1)
# Dwell
self.dwell_cb = FCCheckBox('%s' % _('Enable Dwell'))
@@ -3265,7 +3277,7 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
"speed before cutting.")
)
- grid2.addWidget(self.dwell_cb, 11, 0, 1, 2)
+ grid2.addWidget(self.dwell_cb, 12, 0, 1, 2)
# Dwell Time
dwelltime = QtWidgets.QLabel('%s:' % _('Duration'))
@@ -3274,8 +3286,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
self.dwelltime_entry.set_precision(self.decimals)
self.dwelltime_entry.set_range(0, 99999.9999)
- grid2.addWidget(dwelltime, 12, 0)
- grid2.addWidget(self.dwelltime_entry, 12, 1)
+ grid2.addWidget(dwelltime, 13, 0)
+ grid2.addWidget(self.dwelltime_entry, 13, 1)
self.ois_dwell_exc = OptionalInputSection(self.dwell_cb, [self.dwelltime_entry])
@@ -3367,6 +3379,7 @@ class ExcellonAdvOptPrefGroupUI(OptionsGroupUI):
grid1 = QtWidgets.QGridLayout()
self.layout.addLayout(grid1)
+ # Offset Z
offsetlabel = QtWidgets.QLabel('%s:' % _('Offset Z'))
offsetlabel.setToolTip(
_("Some drill bits (the larger ones) need to drill deeper\n"
@@ -3379,21 +3392,25 @@ class ExcellonAdvOptPrefGroupUI(OptionsGroupUI):
grid1.addWidget(offsetlabel, 0, 0)
grid1.addWidget(self.offset_entry, 0, 1)
+ # ToolChange X,Y
toolchange_xy_label = QtWidgets.QLabel('%s:' % _('Toolchange X,Y'))
toolchange_xy_label.setToolTip(
_("Toolchange X,Y position.")
)
- grid1.addWidget(toolchange_xy_label, 1, 0)
self.toolchangexy_entry = FCEntry()
+
+ grid1.addWidget(toolchange_xy_label, 1, 0)
grid1.addWidget(self.toolchangexy_entry, 1, 1)
+ # Start Z
startzlabel = QtWidgets.QLabel('%s:' % _('Start Z'))
startzlabel.setToolTip(
_("Height of the tool just after start.\n"
"Delete the value if you don't need this feature.")
)
- grid1.addWidget(startzlabel, 2, 0)
self.estartz_entry = FloatEntry()
+
+ grid1.addWidget(startzlabel, 2, 0)
grid1.addWidget(self.estartz_entry, 2, 1)
# Feedrate Rapids
@@ -4165,6 +4182,18 @@ class GeometryOptPrefGroupUI(OptionsGroupUI):
grid1.addWidget(endz_label, 6, 0)
grid1.addWidget(self.endz_entry, 6, 1)
+ # End Move X,Y
+ endmove_xy_label = QtWidgets.QLabel('%s:' % _('End move X,Y'))
+ endmove_xy_label.setToolTip(
+ _("End move X,Y position.\n"
+ "If no value is entered then there is no move\n"
+ "on X,Y plane at the end of the job.")
+ )
+ self.endxy_entry = FCEntry()
+
+ grid1.addWidget(endmove_xy_label, 7, 0)
+ grid1.addWidget(self.endxy_entry, 7, 1)
+
# Feedrate X-Y
frlabel = QtWidgets.QLabel('%s:' % _('Feedrate X-Y'))
frlabel.setToolTip(
@@ -4177,8 +4206,8 @@ class GeometryOptPrefGroupUI(OptionsGroupUI):
self.cncfeedrate_entry.setSingleStep(0.1)
self.cncfeedrate_entry.setWrapping(True)
- grid1.addWidget(frlabel, 7, 0)
- grid1.addWidget(self.cncfeedrate_entry, 7, 1)
+ grid1.addWidget(frlabel, 8, 0)
+ grid1.addWidget(self.cncfeedrate_entry, 8, 1)
# Feedrate Z (Plunge)
frz_label = QtWidgets.QLabel('%s:' % _('Feedrate Z'))
@@ -4193,8 +4222,8 @@ class GeometryOptPrefGroupUI(OptionsGroupUI):
self.feedrate_z_entry.setSingleStep(0.1)
self.feedrate_z_entry.setWrapping(True)
- grid1.addWidget(frz_label, 8, 0)
- grid1.addWidget(self.feedrate_z_entry, 8, 1)
+ grid1.addWidget(frz_label, 9, 0)
+ grid1.addWidget(self.feedrate_z_entry, 9, 1)
# Spindle Speed
spdlabel = QtWidgets.QLabel('%s:' % _('Spindle speed'))
@@ -4205,12 +4234,12 @@ class GeometryOptPrefGroupUI(OptionsGroupUI):
"this value is the power of laser."
)
)
- grid1.addWidget(spdlabel, 9, 0)
self.cncspindlespeed_entry = FCSpinner()
self.cncspindlespeed_entry.set_range(0, 1000000)
self.cncspindlespeed_entry.set_step(100)
- grid1.addWidget(self.cncspindlespeed_entry, 9, 1)
+ grid1.addWidget(spdlabel, 10, 0)
+ grid1.addWidget(self.cncspindlespeed_entry, 10, 1)
# Dwell
self.dwell_cb = FCCheckBox(label='%s' % _('Enable Dwell'))
@@ -4228,9 +4257,9 @@ class GeometryOptPrefGroupUI(OptionsGroupUI):
self.dwelltime_entry.setSingleStep(0.1)
self.dwelltime_entry.setWrapping(True)
- grid1.addWidget(self.dwell_cb, 10, 0)
- grid1.addWidget(dwelltime, 11, 0)
- grid1.addWidget(self.dwelltime_entry, 11, 1)
+ grid1.addWidget(self.dwell_cb, 11, 0)
+ grid1.addWidget(dwelltime, 12, 0)
+ grid1.addWidget(self.dwelltime_entry, 12, 1)
self.ois_dwell = OptionalInputSection(self.dwell_cb, [self.dwelltime_entry])
@@ -4240,10 +4269,11 @@ class GeometryOptPrefGroupUI(OptionsGroupUI):
_("The Preprocessor file that dictates\n"
"the Machine Code (like GCode, RML, HPGL) output.")
)
- grid1.addWidget(pp_label, 12, 0)
self.pp_geometry_name_cb = FCComboBox()
self.pp_geometry_name_cb.setFocusPolicy(Qt.StrongFocus)
- grid1.addWidget(self.pp_geometry_name_cb, 12, 1)
+
+ grid1.addWidget(pp_label, 13, 0)
+ grid1.addWidget(self.pp_geometry_name_cb, 13, 1)
self.layout.addStretch()
diff --git a/flatcamParsers/ParseHPGL2.py b/flatcamParsers/ParseHPGL2.py
index d2b96d48..546825c4 100644
--- a/flatcamParsers/ParseHPGL2.py
+++ b/flatcamParsers/ParseHPGL2.py
@@ -72,6 +72,8 @@ class HPGL2:
"toolchange": self.app.defaults["geometry_toolchange"],
"toolchangez": self.app.defaults["geometry_toolchangez"],
"endz": self.app.defaults["geometry_endz"],
+ "endxy": self.app.defaults["geometry_endxy"],
+
"spindlespeed": self.app.defaults["geometry_spindlespeed"],
"toolchangexy": self.app.defaults["geometry_toolchangexy"],
"startz": self.app.defaults["geometry_startz"],
diff --git a/flatcamTools/ToolNonCopperClear.py b/flatcamTools/ToolNonCopperClear.py
index d497c81b..45ea96e8 100644
--- a/flatcamTools/ToolNonCopperClear.py
+++ b/flatcamTools/ToolNonCopperClear.py
@@ -984,6 +984,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
"toolchange": self.app.defaults["geometry_toolchange"],
"toolchangez": self.app.defaults["geometry_toolchangez"],
"endz": self.app.defaults["geometry_endz"],
+ "endxy": self.app.defaults["geometry_endxy"],
+
"spindlespeed": self.app.defaults["geometry_spindlespeed"],
"toolchangexy": self.app.defaults["geometry_toolchangexy"],
"startz": self.app.defaults["geometry_startz"],
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 2e633d1e..310a6208 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -961,6 +961,8 @@ class ToolPaint(FlatCAMTool, Gerber):
"toolchange": self.app.defaults["geometry_toolchange"],
"toolchangez": float(self.app.defaults["geometry_toolchangez"]),
"endz": float(self.app.defaults["geometry_endz"]),
+ "endxy": self.app.defaults["geometry_endxy"],
+
"spindlespeed": self.app.defaults["geometry_spindlespeed"],
"toolchangexy": self.app.defaults["geometry_toolchangexy"],
"startz": self.app.defaults["geometry_startz"],
diff --git a/preprocessors/Berta_CNC.py b/preprocessors/Berta_CNC.py
index 18f84578..59ed4e20 100644
--- a/preprocessors/Berta_CNC.py
+++ b/preprocessors/Berta_CNC.py
@@ -227,10 +227,10 @@ M0""".format(z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolcha
return ('G01 ' + self.position_code(p)).format(**p)
def end_code(self, p):
- coords_xy = p['xy_toolchange']
+ coords_xy = p['xy_end']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
- if coords_xy is not None:
+ if coords_xy != '':
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
gcode += '(Berta)\n'
diff --git a/preprocessors/GRBL_laser.py b/preprocessors/GRBL_laser.py
index 6c7a7c34..c6ddb280 100644
--- a/preprocessors/GRBL_laser.py
+++ b/preprocessors/GRBL_laser.py
@@ -83,10 +83,10 @@ class GRBL_laser(FlatCAMPostProc):
' F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
def end_code(self, p):
- coords_xy = p['xy_toolchange']
+ coords_xy = p['xy_end']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
- if coords_xy is not None:
+ if coords_xy != '':
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
diff --git a/preprocessors/ISEL_CNC.py b/preprocessors/ISEL_CNC.py
index e8225b8e..805cf35a 100644
--- a/preprocessors/ISEL_CNC.py
+++ b/preprocessors/ISEL_CNC.py
@@ -157,10 +157,10 @@ M01""".format(tool=int(p.tool), toolC=toolC_formatted)
return ('G01 ' + self.position_code(p)).format(**p)
def end_code(self, p):
- coords_xy = p['xy_toolchange']
+ coords_xy = p['xy_end']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
- if coords_xy is not None:
+ if coords_xy != '':
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
diff --git a/preprocessors/Marlin.py b/preprocessors/Marlin.py
index aaf9079d..2f46183f 100644
--- a/preprocessors/Marlin.py
+++ b/preprocessors/Marlin.py
@@ -215,10 +215,10 @@ G0 Z{z_toolchange}
return ('G1 ' + self.position_code(p)).format(**p) + " " + self.inline_feedrate_code(p)
def end_code(self, p):
- coords_xy = p['xy_toolchange']
+ coords_xy = p['xy_end']
gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + " " + self.feedrate_rapid_code(p) + "\n")
- if coords_xy is not None:
+ if coords_xy != '':
gcode += 'G0 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + " " + self.feedrate_rapid_code(p) + "\n"
return gcode
diff --git a/preprocessors/Marlin_laser_use_FAN_pin.py b/preprocessors/Marlin_laser_use_FAN_pin.py
index 36d958a4..9e5f33a7 100644
--- a/preprocessors/Marlin_laser_use_FAN_pin.py
+++ b/preprocessors/Marlin_laser_use_FAN_pin.py
@@ -85,10 +85,10 @@ class Marlin_laser_use_FAN_pin(FlatCAMPostProc):
return ('G1 ' + self.position_code(p)).format(**p) + " " + self.inline_feedrate_code(p)
def end_code(self, p):
- coords_xy = p['xy_toolchange']
+ coords_xy = p['xy_end']
gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + " " + self.feedrate_rapid_code(p) + "\n")
- if coords_xy is not None:
+ if coords_xy != '':
gcode += 'G0 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + " " + self.feedrate_rapid_code(p) + "\n"
return gcode
diff --git a/preprocessors/Marlin_laser_use_Spindle_pin.py b/preprocessors/Marlin_laser_use_Spindle_pin.py
index a1f7fb1e..7f40bca4 100644
--- a/preprocessors/Marlin_laser_use_Spindle_pin.py
+++ b/preprocessors/Marlin_laser_use_Spindle_pin.py
@@ -86,10 +86,10 @@ class Marlin_laser_use_Spindle_pin(FlatCAMPostProc):
return ('G1 ' + self.position_code(p)).format(**p) + " " + self.inline_feedrate_code(p)
def end_code(self, p):
- coords_xy = p['xy_toolchange']
+ coords_xy = p['xy_end']
gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + " " + self.feedrate_rapid_code(p) + "\n")
- if coords_xy is not None:
+ if coords_xy != '':
gcode += 'G0 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + " " + self.feedrate_rapid_code(p) + "\n"
return gcode
diff --git a/preprocessors/Paste_1.py b/preprocessors/Paste_1.py
index 87403017..b12d0f67 100644
--- a/preprocessors/Paste_1.py
+++ b/preprocessors/Paste_1.py
@@ -122,10 +122,10 @@ G00 Z{z_toolchange}
return ('G01 ' + self.position_code(p)).format(**p)
def end_code(self, p):
- coords_xy = [float(eval(a)) for a in p['xy_toolchange'].split(",") if a != '']
+ coords_xy = [float(eval(a)) for a in p['xy_end'].split(",") if a != '']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, float(p['z_toolchange'])) + "\n")
- if coords_xy is not None:
+ if coords_xy != '':
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
diff --git a/preprocessors/Repetier.py b/preprocessors/Repetier.py
index ea15317e..4bdca261 100644
--- a/preprocessors/Repetier.py
+++ b/preprocessors/Repetier.py
@@ -206,10 +206,10 @@ G0 Z{z_toolchange}
return ('G1 ' + self.position_code(p)).format(**p) + " " + self.inline_feedrate_code(p)
def end_code(self, p):
- coords_xy = p['xy_toolchange']
+ coords_xy = p['xy_end']
gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + " " + self.feedrate_rapid_code(p) + "\n")
- if coords_xy is not None:
+ if coords_xy != '':
gcode += 'G0 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + " " + self.feedrate_rapid_code(p) + "\n"
return gcode
diff --git a/preprocessors/Toolchange_Custom.py b/preprocessors/Toolchange_Custom.py
index 5c22b85a..39468d5d 100644
--- a/preprocessors/Toolchange_Custom.py
+++ b/preprocessors/Toolchange_Custom.py
@@ -173,10 +173,10 @@ M6
return ('G01 ' + self.position_code(p)).format(**p)
def end_code(self, p):
- coords_xy = p['xy_toolchange']
+ coords_xy = p['xy_end']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
- if coords_xy is not None:
+ if coords_xy != '':
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
diff --git a/preprocessors/Toolchange_Probe_MACH3.py b/preprocessors/Toolchange_Probe_MACH3.py
index 3d4c95f8..1cfa0baa 100644
--- a/preprocessors/Toolchange_Probe_MACH3.py
+++ b/preprocessors/Toolchange_Probe_MACH3.py
@@ -272,10 +272,10 @@ M0
return ('G01 ' + self.position_code(p)).format(**p)
def end_code(self, p):
- coords_xy = p['xy_toolchange']
+ coords_xy = p['xy_end']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
- if coords_xy is not None:
+ if coords_xy != '':
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
diff --git a/preprocessors/Toolchange_manual.py b/preprocessors/Toolchange_manual.py
index fceef14c..7b2eb561 100644
--- a/preprocessors/Toolchange_manual.py
+++ b/preprocessors/Toolchange_manual.py
@@ -235,12 +235,11 @@ M0
return ('G01 ' + self.position_code(p)).format(**p)
def end_code(self, p):
- coords_xy = p['xy_toolchange']
+ coords_xy = p['xy_end']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
- if coords_xy is not None:
+
+ if coords_xy != '':
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
- else:
- gcode += 'G00 X0 Y0' + "\n"
return gcode
def feedrate_code(self, p):
diff --git a/preprocessors/default.py b/preprocessors/default.py
index f46ff824..f7fadddc 100644
--- a/preprocessors/default.py
+++ b/preprocessors/default.py
@@ -217,11 +217,11 @@ G00 Z{z_toolchange}
return ('G01 ' + self.position_code(p)).format(**p)
def end_code(self, p):
- coords_xy = p['xy_toolchange']
+ end_coords_xy = p['xy_end']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
- if coords_xy is not None:
- gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
+ if end_coords_xy != '':
+ gcode += 'G00 X{x} Y{y}'.format(x=end_coords_xy[0], y=end_coords_xy[1]) + "\n"
return gcode
def feedrate_code(self, p):
diff --git a/preprocessors/grbl_11.py b/preprocessors/grbl_11.py
index 0d4cf868..1bd28189 100644
--- a/preprocessors/grbl_11.py
+++ b/preprocessors/grbl_11.py
@@ -218,10 +218,10 @@ G00 Z{z_toolchange}
' F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
def end_code(self, p):
- coords_xy = p['xy_toolchange']
+ coords_xy = p['xy_end']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
- if coords_xy is not None:
+ if coords_xy != '':
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
diff --git a/preprocessors/line_xyz.py b/preprocessors/line_xyz.py
index d7cebb7f..6187c1ae 100644
--- a/preprocessors/line_xyz.py
+++ b/preprocessors/line_xyz.py
@@ -206,8 +206,8 @@ M0""".format(x_toolchange=self.coordinate_format % (p.coords_decimals, x_toolcha
return g
def end_code(self, p):
- coords_xy = p['xy_toolchange']
- if coords_xy is not None:
+ coords_xy = p['xy_end']
+ if coords_xy != '':
g = 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
else:
g = ('G00 ' + self.position_code(p)).format(**p)
diff --git a/tclCommands/TclCommandCopperClear.py b/tclCommands/TclCommandCopperClear.py
index c57aa8a2..d6f58989 100644
--- a/tclCommands/TclCommandCopperClear.py
+++ b/tclCommands/TclCommandCopperClear.py
@@ -175,6 +175,7 @@ class TclCommandCopperClear(TclCommand):
"toolchange": self.app.defaults["geometry_toolchange"],
"toolchangez": self.app.defaults["geometry_toolchangez"],
"endz": self.app.defaults["geometry_endz"],
+ "endxy": self.app.defaults["geometry_endxy"],
"spindlespeed": self.app.defaults["geometry_spindlespeed"],
"toolchangexy": self.app.defaults["geometry_toolchangexy"],
"startz": self.app.defaults["geometry_startz"],
diff --git a/tclCommands/TclCommandPaint.py b/tclCommands/TclCommandPaint.py
index 2594904a..f44dcef2 100644
--- a/tclCommands/TclCommandPaint.py
+++ b/tclCommands/TclCommandPaint.py
@@ -164,6 +164,8 @@ class TclCommandPaint(TclCommand):
"toolchange": self.app.defaults["geometry_toolchange"],
"toolchangez": self.app.defaults["geometry_toolchangez"],
"endz": self.app.defaults["geometry_endz"],
+ "endxy": self.app.defaults["geometry_endxy"],
+
"spindlespeed": self.app.defaults["geometry_spindlespeed"],
"toolchangexy": self.app.defaults["geometry_toolchangexy"],
"startz": self.app.defaults["geometry_startz"],
From 84570bf6fe057c96ee581cf0d7f21b03f06cd18c Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 26 Feb 2020 05:00:23 +0200
Subject: [PATCH 115/209] - some tooltip changes
---
flatcamGUI/ObjectUI.py | 4 ++--
flatcamGUI/PreferencesUI.py | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index e819f4a3..ca99e6c4 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -1223,7 +1223,7 @@ class ExcellonObjectUI(ObjectUI):
# End Move X,Y
endmove_xy_label = QtWidgets.QLabel('%s:' % _('End move X,Y'))
endmove_xy_label.setToolTip(
- _("End move X,Y position.\n"
+ _("End move X,Y position. In format (x,y).\n"
"If no value is entered then there is no move\n"
"on X,Y plane at the end of the job.")
)
@@ -1989,7 +1989,7 @@ class GeometryObjectUI(ObjectUI):
# End Move X,Y
endmove_xy_label = QtWidgets.QLabel('%s:' % _('End move X,Y'))
endmove_xy_label.setToolTip(
- _("End move X,Y position.\n"
+ _("End move X,Y position. In format (x,y).\n"
"If no value is entered then there is no move\n"
"on X,Y plane at the end of the job.")
)
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index 6c7781b7..fdd29b3b 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -3232,7 +3232,7 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
# End Move X,Y
endmove_xy_label = QtWidgets.QLabel('%s:' % _('End move X,Y'))
endmove_xy_label.setToolTip(
- _("End move X,Y position.\n"
+ _("End move X,Y position. In format (x,y).\n"
"If no value is entered then there is no move\n"
"on X,Y plane at the end of the job.")
)
@@ -4185,7 +4185,7 @@ class GeometryOptPrefGroupUI(OptionsGroupUI):
# End Move X,Y
endmove_xy_label = QtWidgets.QLabel('%s:' % _('End move X,Y'))
endmove_xy_label.setToolTip(
- _("End move X,Y position.\n"
+ _("End move X,Y position. In format (x,y).\n"
"If no value is entered then there is no move\n"
"on X,Y plane at the end of the job.")
)
From 69607816d0aea3341365f1159c675581d37c59ee Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 28 Feb 2020 01:12:39 +0200
Subject: [PATCH 116/209] - some small changes in preprocessors
---
README.md | 4 ++++
...{Marlin_laser_use_FAN_pin.py => Marlin_laser_FAN_pin.py} | 6 +++---
...laser_use_Spindle_pin.py => Marlin_laser_Spindle_pin.py} | 2 +-
.../{Toolchange_manual.py => Toolchange_Manual.py} | 2 +-
4 files changed, 9 insertions(+), 5 deletions(-)
rename preprocessors/{Marlin_laser_use_FAN_pin.py => Marlin_laser_FAN_pin.py} (96%)
rename preprocessors/{Marlin_laser_use_Spindle_pin.py => Marlin_laser_Spindle_pin.py} (98%)
rename preprocessors/{Toolchange_manual.py => Toolchange_Manual.py} (99%)
diff --git a/README.md b/README.md
index 3c172ff0..df9ef53c 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+28.02.2020
+
+- some small changes in preprocessors
+
25.02.2020
- fixed bug in Gerber parser: it tried to calculate a len() for a single element and not a list - a Gerber generated by Eagle exhibited this
diff --git a/preprocessors/Marlin_laser_use_FAN_pin.py b/preprocessors/Marlin_laser_FAN_pin.py
similarity index 96%
rename from preprocessors/Marlin_laser_use_FAN_pin.py
rename to preprocessors/Marlin_laser_FAN_pin.py
index 9e5f33a7..fb515d5f 100644
--- a/preprocessors/Marlin_laser_use_FAN_pin.py
+++ b/preprocessors/Marlin_laser_FAN_pin.py
@@ -9,7 +9,7 @@
from FlatCAMPostProc import *
-class Marlin_laser_use_FAN_pin(FlatCAMPostProc):
+class Marlin_laser_FAN_pin(FlatCAMPostProc):
include_header = True
coordinate_format = "%.*f"
@@ -107,7 +107,7 @@ class Marlin_laser_use_FAN_pin(FlatCAMPostProc):
def spindle_code(self, p):
if p.spindlespeed:
- return '%s S%s' % ('M106 ', str(p.spindlespeed))
+ return 'M106 S%s' % str(p.spindlespeed)
else:
return 'M106'
@@ -116,5 +116,5 @@ class Marlin_laser_use_FAN_pin(FlatCAMPostProc):
def spindle_stop_code(self, p):
gcode = 'M400\n'
- gcode += 'M107'
+ gcode += 'M106 S0'
return gcode
diff --git a/preprocessors/Marlin_laser_use_Spindle_pin.py b/preprocessors/Marlin_laser_Spindle_pin.py
similarity index 98%
rename from preprocessors/Marlin_laser_use_Spindle_pin.py
rename to preprocessors/Marlin_laser_Spindle_pin.py
index 7f40bca4..370d0c33 100644
--- a/preprocessors/Marlin_laser_use_Spindle_pin.py
+++ b/preprocessors/Marlin_laser_Spindle_pin.py
@@ -9,7 +9,7 @@
from FlatCAMPostProc import *
-class Marlin_laser_use_Spindle_pin(FlatCAMPostProc):
+class Marlin_laser_Spindle_pin(FlatCAMPostProc):
include_header = True
coordinate_format = "%.*f"
diff --git a/preprocessors/Toolchange_manual.py b/preprocessors/Toolchange_Manual.py
similarity index 99%
rename from preprocessors/Toolchange_manual.py
rename to preprocessors/Toolchange_Manual.py
index 7b2eb561..432a0013 100644
--- a/preprocessors/Toolchange_manual.py
+++ b/preprocessors/Toolchange_Manual.py
@@ -9,7 +9,7 @@
from FlatCAMPostProc import *
-class Toolchange_manual(FlatCAMPostProc):
+class Toolchange_Manual(FlatCAMPostProc):
include_header = True
coordinate_format = "%.*f"
From c5e4d72db8689aaeb9c18bd9552c8ff32fc77000 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 28 Feb 2020 17:59:15 +0200
Subject: [PATCH 117/209] - solved issue #381 where there was an error when
trying to generate CNCJob out of an Excellon file that have a tool with only
slots and no drills - solved some issues in the preprocessors regarding the
newly introduced feature that allow control of the final move X,Y positions
---
README.md | 2 +
camlib.py | 88 +++++++++++++++--------
preprocessors/Berta_CNC.py | 2 +-
preprocessors/GRBL_laser.py | 2 +-
preprocessors/ISEL_CNC.py | 2 +-
preprocessors/Marlin.py | 2 +-
preprocessors/Marlin_laser_FAN_pin.py | 2 +-
preprocessors/Marlin_laser_Spindle_pin.py | 2 +-
preprocessors/Paste_1.py | 2 +-
preprocessors/Repetier.py | 2 +-
preprocessors/Toolchange_Custom.py | 2 +-
preprocessors/Toolchange_Manual.py | 2 +-
preprocessors/Toolchange_Probe_MACH3.py | 2 +-
preprocessors/default.py | 2 +-
preprocessors/grbl_11.py | 2 +-
preprocessors/line_xyz.py | 2 +-
16 files changed, 73 insertions(+), 45 deletions(-)
diff --git a/README.md b/README.md
index df9ef53c..b0e69180 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,8 @@ CAD program, and create G-Code for Isolation routing.
28.02.2020
- some small changes in preprocessors
+- solved issue #381 where there was an error when trying to generate CNCJob out of an Excellon file that have a tool with only slots and no drills
+- solved some issues in the preprocessors regarding the newly introduced feature that allow control of the final move X,Y positions
25.02.2020
diff --git a/camlib.py b/camlib.py
index b56d65f5..a1ca1375 100644
--- a/camlib.py
+++ b/camlib.py
@@ -2647,8 +2647,8 @@ class CNCjob(Geometry):
if self.xy_toolchange == '':
self.xy_toolchange = None
else:
- self.xy_toolchange = [float(eval(a)) for a in self.xy_toolchange.split(",")]
- if len(self.xy_toolchange) < 2:
+ self.xy_toolchange = [float(eval(a)) for a in self.xy_toolchange.split(",") if self.xy_toolchange != '']
+ if self.xy_toolchange and len(self.xy_toolchange) < 2:
self.app.inform.emit('[ERROR]%s' %
_("The Toolchange X,Y field in Edit -> Preferences has to be "
"in the format (x, y) \nbut now there is only one value, not two. "))
@@ -2657,8 +2657,8 @@ class CNCjob(Geometry):
log.debug("camlib.CNCJob.generate_from_excellon_by_tool() --> %s" % str(e))
pass
- self.xy_end = [float(eval(a)) for a in self.xy_end.split(",")]
- if len(self.xy_end) < 2:
+ self.xy_end = [float(eval(a)) for a in self.xy_end.split(",") if self.xy_end != '']
+ if self.xy_end and len(self.xy_end) < 2:
self.app.inform.emit('[ERROR] %s' % _("The End Move X,Y field in Edit -> Preferences has to be "
"in the format (x, y) but now there is only one value, not two."))
return 'fail'
@@ -2783,23 +2783,25 @@ class CNCjob(Geometry):
class CreateDistanceCallback(object):
"""Create callback to calculate distances between points."""
- def __init__(self):
+ def __init__(self, tool):
"""Initialize distance array."""
- locations = create_data_array()
- size = len(locations)
+ locations = create_data_array(tool)
self.matrix = dict()
- for from_node in range(size):
- self.matrix[from_node] = {}
- for to_node in range(size):
- if from_node == to_node:
- self.matrix[from_node][to_node] = 0
- else:
- x1 = locations[from_node][0]
- y1 = locations[from_node][1]
- x2 = locations[to_node][0]
- y2 = locations[to_node][1]
- self.matrix[from_node][to_node] = distance_euclidian(x1, y1, x2, y2)
+ if locations:
+ size = len(locations)
+
+ for from_node in range(size):
+ self.matrix[from_node] = {}
+ for to_node in range(size):
+ if from_node == to_node:
+ self.matrix[from_node][to_node] = 0
+ else:
+ x1 = locations[from_node][0]
+ y1 = locations[from_node][1]
+ x2 = locations[to_node][0]
+ y2 = locations[to_node][1]
+ self.matrix[from_node][to_node] = distance_euclidian(x1, y1, x2, y2)
# def Distance(self, from_node, to_node):
# return int(self.matrix[from_node][to_node])
@@ -2810,11 +2812,15 @@ class CNCjob(Geometry):
return self.matrix[from_node][to_node]
# Create the data.
- def create_data_array():
- locations = []
+ def create_data_array(tool):
+ loc_list = list()
+
+ if tool not in points:
+ return None
+
for point in points[tool]:
- locations.append((point.coords.xy[0][0], point.coords.xy[1][0]))
- return locations
+ loc_list.append((point.coords.xy[0][0], point.coords.xy[1][0]))
+ return loc_list
if self.xy_toolchange is not None:
self.oldx = self.xy_toolchange[0]
@@ -2884,7 +2890,12 @@ class CNCjob(Geometry):
# ###############################################
node_list = []
- locations = create_data_array()
+ locations = create_data_array(tool=tool)
+
+ # if there are no locations then go to the next tool
+ if not locations:
+ continue
+
tsp_size = len(locations)
num_routes = 1 # The number of routes, which is 1 in the TSP.
# Nodes are indexed from 0 to tsp_size - 1. The depot is the starting node of the route.
@@ -2906,7 +2917,12 @@ class CNCjob(Geometry):
# Callback to the distance function. The callback takes two
# arguments (the from and to node indices) and returns the distance between them.
- dist_between_locations = CreateDistanceCallback()
+ dist_between_locations = CreateDistanceCallback(tool=tool)
+
+ # if there are no distances then go to the next tool
+ if not dist_between_locations:
+ continue
+
dist_callback = dist_between_locations.Distance
transit_callback_index = routing.RegisterTransitCallback(dist_callback)
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
@@ -3088,7 +3104,7 @@ class CNCjob(Geometry):
old_zcut = deepcopy(self.z_cut)
self.z_move = exobj.tools[tool]['data']['travelz']
- print(self.z_move)
+
self.spindlespeed = exobj.tools[tool]['data']['spindlespeed']
self.dwell = exobj.tools[tool]['data']['dwell']
self.dwelltime = exobj.tools[tool]['data']['dwelltime']
@@ -3100,7 +3116,12 @@ class CNCjob(Geometry):
# ###############################################
node_list = []
- locations = create_data_array()
+ locations = create_data_array(tool=tool)
+
+ # if there are no locations then go to the next tool
+ if not locations:
+ continue
+
tsp_size = len(locations)
num_routes = 1 # The number of routes, which is 1 in the TSP.
@@ -3115,7 +3136,12 @@ class CNCjob(Geometry):
# Callback to the distance function. The callback takes two
# arguments (the from and to node indices) and returns the distance between them.
- dist_between_locations = CreateDistanceCallback()
+ dist_between_locations = CreateDistanceCallback(tool=tool)
+
+ # if there are no distances then go to the next tool
+ if not dist_between_locations:
+ continue
+
dist_callback = dist_between_locations.Distance
transit_callback_index = routing.RegisterTransitCallback(dist_callback)
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
@@ -3519,8 +3545,8 @@ class CNCjob(Geometry):
self.startz = float(startz) if startz is not None else None
self.z_end = float(endz) if endz is not None else None
- self.xy_end = [float(eval(a)) for a in endxy.split(",")]
- if len(self.xy_end) < 2:
+ self.xy_end = [float(eval(a)) for a in endxy.split(",") if endxy != '']
+ if self.xy_end and len(self.xy_end) < 2:
self.app.inform.emit('[ERROR] %s' % _("The End Move X,Y field in Edit -> Preferences has to be "
"in the format (x, y) but now there is only one value, not two."))
return 'fail'
@@ -3887,8 +3913,8 @@ class CNCjob(Geometry):
self.startz = float(startz) if startz is not None else self.app.defaults["geometry_startz"]
self.z_end = float(endz) if endz is not None else self.app.defaults["geometry_endz"]
self.xy_end = endxy if endxy != '' else self.app.defaults["geometry_endxy"]
- self.xy_end = [float(eval(a)) for a in self.xy_end.split(",")]
- if len(self.xy_end) < 2:
+ self.xy_end = [float(eval(a)) for a in self.xy_end.split(",") if self.xy_end != '']
+ if self.xy_end and len(self.xy_end) < 2:
self.app.inform.emit('[ERROR] %s' % _("The End Move X,Y field in Edit -> Preferences has to be "
"in the format (x, y) but now there is only one value, not two."))
return 'fail'
diff --git a/preprocessors/Berta_CNC.py b/preprocessors/Berta_CNC.py
index 59ed4e20..8239d0e9 100644
--- a/preprocessors/Berta_CNC.py
+++ b/preprocessors/Berta_CNC.py
@@ -230,7 +230,7 @@ M0""".format(z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolcha
coords_xy = p['xy_end']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
- if coords_xy != '':
+ if coords_xy and coords_xy != '':
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
gcode += '(Berta)\n'
diff --git a/preprocessors/GRBL_laser.py b/preprocessors/GRBL_laser.py
index c6ddb280..9caf4f39 100644
--- a/preprocessors/GRBL_laser.py
+++ b/preprocessors/GRBL_laser.py
@@ -86,7 +86,7 @@ class GRBL_laser(FlatCAMPostProc):
coords_xy = p['xy_end']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
- if coords_xy != '':
+ if coords_xy and coords_xy != '':
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
diff --git a/preprocessors/ISEL_CNC.py b/preprocessors/ISEL_CNC.py
index 805cf35a..8c7c9ed0 100644
--- a/preprocessors/ISEL_CNC.py
+++ b/preprocessors/ISEL_CNC.py
@@ -160,7 +160,7 @@ M01""".format(tool=int(p.tool), toolC=toolC_formatted)
coords_xy = p['xy_end']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
- if coords_xy != '':
+ if coords_xy and coords_xy != '':
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
diff --git a/preprocessors/Marlin.py b/preprocessors/Marlin.py
index 2f46183f..d53a257f 100644
--- a/preprocessors/Marlin.py
+++ b/preprocessors/Marlin.py
@@ -218,7 +218,7 @@ G0 Z{z_toolchange}
coords_xy = p['xy_end']
gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + " " + self.feedrate_rapid_code(p) + "\n")
- if coords_xy != '':
+ if coords_xy and coords_xy != '':
gcode += 'G0 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + " " + self.feedrate_rapid_code(p) + "\n"
return gcode
diff --git a/preprocessors/Marlin_laser_FAN_pin.py b/preprocessors/Marlin_laser_FAN_pin.py
index fb515d5f..2d06d23d 100644
--- a/preprocessors/Marlin_laser_FAN_pin.py
+++ b/preprocessors/Marlin_laser_FAN_pin.py
@@ -88,7 +88,7 @@ class Marlin_laser_FAN_pin(FlatCAMPostProc):
coords_xy = p['xy_end']
gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + " " + self.feedrate_rapid_code(p) + "\n")
- if coords_xy != '':
+ if coords_xy and coords_xy != '':
gcode += 'G0 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + " " + self.feedrate_rapid_code(p) + "\n"
return gcode
diff --git a/preprocessors/Marlin_laser_Spindle_pin.py b/preprocessors/Marlin_laser_Spindle_pin.py
index 370d0c33..151e9dc4 100644
--- a/preprocessors/Marlin_laser_Spindle_pin.py
+++ b/preprocessors/Marlin_laser_Spindle_pin.py
@@ -89,7 +89,7 @@ class Marlin_laser_Spindle_pin(FlatCAMPostProc):
coords_xy = p['xy_end']
gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + " " + self.feedrate_rapid_code(p) + "\n")
- if coords_xy != '':
+ if coords_xy and coords_xy != '':
gcode += 'G0 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + " " + self.feedrate_rapid_code(p) + "\n"
return gcode
diff --git a/preprocessors/Paste_1.py b/preprocessors/Paste_1.py
index b12d0f67..cbb0b19f 100644
--- a/preprocessors/Paste_1.py
+++ b/preprocessors/Paste_1.py
@@ -125,7 +125,7 @@ G00 Z{z_toolchange}
coords_xy = [float(eval(a)) for a in p['xy_end'].split(",") if a != '']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, float(p['z_toolchange'])) + "\n")
- if coords_xy != '':
+ if coords_xy and coords_xy != '':
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
diff --git a/preprocessors/Repetier.py b/preprocessors/Repetier.py
index 4bdca261..bb17f9ee 100644
--- a/preprocessors/Repetier.py
+++ b/preprocessors/Repetier.py
@@ -209,7 +209,7 @@ G0 Z{z_toolchange}
coords_xy = p['xy_end']
gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + " " + self.feedrate_rapid_code(p) + "\n")
- if coords_xy != '':
+ if coords_xy and coords_xy != '':
gcode += 'G0 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + " " + self.feedrate_rapid_code(p) + "\n"
return gcode
diff --git a/preprocessors/Toolchange_Custom.py b/preprocessors/Toolchange_Custom.py
index 39468d5d..1c2eeffc 100644
--- a/preprocessors/Toolchange_Custom.py
+++ b/preprocessors/Toolchange_Custom.py
@@ -176,7 +176,7 @@ M6
coords_xy = p['xy_end']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
- if coords_xy != '':
+ if coords_xy and coords_xy != '':
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
diff --git a/preprocessors/Toolchange_Manual.py b/preprocessors/Toolchange_Manual.py
index 432a0013..27aaec22 100644
--- a/preprocessors/Toolchange_Manual.py
+++ b/preprocessors/Toolchange_Manual.py
@@ -238,7 +238,7 @@ M0
coords_xy = p['xy_end']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
- if coords_xy != '':
+ if coords_xy and coords_xy != '':
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
diff --git a/preprocessors/Toolchange_Probe_MACH3.py b/preprocessors/Toolchange_Probe_MACH3.py
index 1cfa0baa..f5f8c9c3 100644
--- a/preprocessors/Toolchange_Probe_MACH3.py
+++ b/preprocessors/Toolchange_Probe_MACH3.py
@@ -275,7 +275,7 @@ M0
coords_xy = p['xy_end']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
- if coords_xy != '':
+ if coords_xy and coords_xy != '':
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
diff --git a/preprocessors/default.py b/preprocessors/default.py
index f7fadddc..7c5cf1c6 100644
--- a/preprocessors/default.py
+++ b/preprocessors/default.py
@@ -220,7 +220,7 @@ G00 Z{z_toolchange}
end_coords_xy = p['xy_end']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
- if end_coords_xy != '':
+ if end_coords_xy and end_coords_xy != '':
gcode += 'G00 X{x} Y{y}'.format(x=end_coords_xy[0], y=end_coords_xy[1]) + "\n"
return gcode
diff --git a/preprocessors/grbl_11.py b/preprocessors/grbl_11.py
index 1bd28189..b002b2b2 100644
--- a/preprocessors/grbl_11.py
+++ b/preprocessors/grbl_11.py
@@ -221,7 +221,7 @@ G00 Z{z_toolchange}
coords_xy = p['xy_end']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
- if coords_xy != '':
+ if coords_xy and coords_xy != '':
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
diff --git a/preprocessors/line_xyz.py b/preprocessors/line_xyz.py
index 6187c1ae..900d7fab 100644
--- a/preprocessors/line_xyz.py
+++ b/preprocessors/line_xyz.py
@@ -207,7 +207,7 @@ M0""".format(x_toolchange=self.coordinate_format % (p.coords_decimals, x_toolcha
def end_code(self, p):
coords_xy = p['xy_end']
- if coords_xy != '':
+ if coords_xy and coords_xy != '':
g = 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
else:
g = ('G00 ' + self.position_code(p)).format(**p)
From 2c7dff5dbe9b01998df63204dccbdfa1cd97d965 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 29 Feb 2020 19:05:00 +0200
Subject: [PATCH 118/209] - compacted the NCC Tool UI by replacing some Radio
buttons with Combo boxes due of too many elements
---
FlatCAMApp.py | 8 +-
README.md | 4 +
flatcamEditors/FlatCAMGeoEditor.py | 43 +++----
flatcamGUI/PreferencesUI.py | 54 +++++----
.../{ToolNonCopperClear.py => ToolNCC.py} | 106 ++++++++++--------
flatcamTools/__init__.py | 2 +-
6 files changed, 119 insertions(+), 98 deletions(-)
rename flatcamTools/{ToolNonCopperClear.py => ToolNCC.py} (98%)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index a9d4cbca..285e8315 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -779,13 +779,13 @@ class App(QtCore.QObject):
"tools_nccoperation": 'clear',
"tools_nccoverlap": 40,
"tools_nccmargin": 1.0,
- "tools_nccmethod": "seed",
+ "tools_nccmethod": _("Seed"),
"tools_nccconnect": True,
"tools_ncccontour": True,
"tools_nccrest": False,
"tools_ncc_offset_choice": False,
"tools_ncc_offset_value": 0.0000,
- "tools_nccref": 'itself',
+ "tools_nccref": _('Itself'),
"tools_ncc_plotting": 'normal',
"tools_nccmilling_type": 'cl',
"tools_ncctool_type": 'C1',
@@ -1461,13 +1461,13 @@ class App(QtCore.QObject):
"tools_nccorder": self.ui.tools_defaults_form.tools_ncc_group.ncc_order_radio,
"tools_nccoverlap": self.ui.tools_defaults_form.tools_ncc_group.ncc_overlap_entry,
"tools_nccmargin": self.ui.tools_defaults_form.tools_ncc_group.ncc_margin_entry,
- "tools_nccmethod": self.ui.tools_defaults_form.tools_ncc_group.ncc_method_radio,
+ "tools_nccmethod": self.ui.tools_defaults_form.tools_ncc_group.ncc_method_combo,
"tools_nccconnect": self.ui.tools_defaults_form.tools_ncc_group.ncc_connect_cb,
"tools_ncccontour": self.ui.tools_defaults_form.tools_ncc_group.ncc_contour_cb,
"tools_nccrest": self.ui.tools_defaults_form.tools_ncc_group.ncc_rest_cb,
"tools_ncc_offset_choice": self.ui.tools_defaults_form.tools_ncc_group.ncc_choice_offset_cb,
"tools_ncc_offset_value": self.ui.tools_defaults_form.tools_ncc_group.ncc_offset_spinner,
- "tools_nccref": self.ui.tools_defaults_form.tools_ncc_group.reference_radio,
+ "tools_nccref": self.ui.tools_defaults_form.tools_ncc_group.select_combo,
"tools_ncc_plotting": self.ui.tools_defaults_form.tools_ncc_group.ncc_plotting_radio,
"tools_nccmilling_type": self.ui.tools_defaults_form.tools_ncc_group.milling_type_radio,
"tools_ncctool_type": self.ui.tools_defaults_form.tools_ncc_group.tool_type_radio,
diff --git a/README.md b/README.md
index b0e69180..28be59a2 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+29.02.2020
+
+- compacted the NCC Tool UI by replacing some Radio buttons with Combo boxes due of too many elements
+
28.02.2020
- some small changes in preprocessors
diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py
index 26fb2615..17027775 100644
--- a/flatcamEditors/FlatCAMGeoEditor.py
+++ b/flatcamEditors/FlatCAMGeoEditor.py
@@ -487,15 +487,20 @@ class PaintOptionsTool(FlatCAMTool):
# Method
methodlabel = QtWidgets.QLabel('%s:' % _('Method'))
methodlabel.setToolTip(
- _("Algorithm to paint the polygon:
"
- "Standard: Fixed step inwards.
"
- "Seed-based: Outwards from seed.")
+ _("Algorithm to paint the polygons:\n"
+ "- Standard: Fixed step inwards.\n"
+ "- Seed-based: Outwards from seed.\n"
+ "- Line-based: Parallel lines.")
+ )
+ # self.paintmethod_combo = RadioSet([
+ # {"label": _("Standard"), "value": "standard"},
+ # {"label": _("Seed-based"), "value": "seed"},
+ # {"label": _("Straight lines"), "value": "lines"}
+ # ], orientation='vertical', stretch=False)
+ self.paintmethod_combo = FCComboBox()
+ self.paintmethod_combo.addItems(
+ [_("Standard"), _("Seed"), _("Lines")]
)
- self.paintmethod_combo = RadioSet([
- {"label": _("Standard"), "value": "standard"},
- {"label": _("Seed-based"), "value": "seed"},
- {"label": _("Straight lines"), "value": "lines"}
- ], orientation='vertical', stretch=False)
grid.addWidget(methodlabel, 3, 0)
grid.addWidget(self.paintmethod_combo, 3, 1)
@@ -564,7 +569,7 @@ class PaintOptionsTool(FlatCAMTool):
if self.app.defaults["tools_paintmethod"]:
self.paintmethod_combo.set_value(self.app.defaults["tools_paintmethod"])
else:
- self.paintmethod_combo.set_value("seed")
+ self.paintmethod_combo.set_value(_("Seed"))
if self.app.defaults["tools_pathconnect"]:
self.pathconnect_cb.set_value(self.app.defaults["tools_pathconnect"])
@@ -578,8 +583,7 @@ class PaintOptionsTool(FlatCAMTool):
def on_paint(self):
if not self.fcdraw.selected:
- self.app.inform.emit('[WARNING_NOTCL] %s' %
- _("Paint cancelled. No shape selected."))
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Paint cancelled. No shape selected."))
return
tooldia = self.painttooldia_entry.get_value()
@@ -5037,11 +5041,11 @@ class FlatCAMGeoEditor(QtCore.QObject):
else:
poly_buf = Polygon(geo_obj).buffer(-margin)
- if method == "seed":
+ if method == _("Seed"):
cp = Geometry.clear_polygon2(self, polygon_to_clear=poly_buf, tooldia=tooldia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=overlap, contour=contour, connect=connect)
- elif method == "lines":
+ elif method == _("Lines"):
cp = Geometry.clear_polygon3(self, polygon=poly_buf, tooldia=tooldia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=overlap, contour=contour, connect=connect)
@@ -5054,12 +5058,10 @@ class FlatCAMGeoEditor(QtCore.QObject):
local_results += list(cp.get_objects())
except Exception as e:
log.debug("Could not Paint the polygons. %s" % str(e))
- self.app.inform.emit('[ERROR] %s\n%s' %
- (_("Could not do Paint. Try a different combination of"
- " parameters. Or a different method of Paint"),
- str(e)
- )
- )
+ self.app.inform.emit(
+ '[ERROR] %s\n%s' % (_("Could not do Paint. Try a different combination of parameters. "
+ "Or a different method of Paint"), str(e))
+ )
return
# add the result to the results list
@@ -5068,8 +5070,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
# This is a dirty patch:
for r in results:
self.add_shape(DrawToolShape(r))
- self.app.inform.emit(
- '[success] %s' % _("Paint done."))
+ self.app.inform.emit('[success] %s' % _("Paint done."))
self.replot()
def flatten(self, geometry, orient_val=1, reset=True, pathonly=False):
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index fdd29b3b..7d6767cd 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -5313,20 +5313,24 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
# Method
methodlabel = QtWidgets.QLabel('%s:' % _('Method'))
methodlabel.setToolTip(
- _("Algorithm for non-copper clearing:
"
- "Standard: Fixed step inwards.
"
- "Seed-based: Outwards from seed.
"
- "Line-based: Parallel lines.")
+ _("Algorithm for copper clearing:\n"
+ "- Standard: Fixed step inwards.\n"
+ "- Seed-based: Outwards from seed.\n"
+ "- Line-based: Parallel lines.")
)
- self.ncc_method_radio = RadioSet([
- {"label": _("Standard"), "value": "standard"},
- {"label": _("Seed-based"), "value": "seed"},
- {"label": _("Straight lines"), "value": "lines"}
- ], orientation='vertical', stretch=False)
+ # self.ncc_method_radio = RadioSet([
+ # {"label": _("Standard"), "value": "standard"},
+ # {"label": _("Seed-based"), "value": "seed"},
+ # {"label": _("Straight lines"), "value": "lines"}
+ # ], orientation='vertical', stretch=False)
+ self.ncc_method_combo = FCComboBox()
+ self.ncc_method_combo.addItems(
+ [_("Standard"), _("Seed"), _("Lines")]
+ )
grid0.addWidget(methodlabel, 12, 0)
- grid0.addWidget(self.ncc_method_radio, 12, 1)
+ grid0.addWidget(self.ncc_method_combo, 12, 1)
# Connect lines
self.ncc_connect_cb = FCCheckBox('%s' % _("Connect"))
@@ -5394,23 +5398,25 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.ncc_rest_cb, 17, 0, 1, 2)
# ## Reference
- self.reference_radio = RadioSet([{'label': _('Itself'), 'value': 'itself'},
- {"label": _("Area Selection"), "value": "area"},
- {'label': _('Reference Object'), 'value': 'box'}],
- orientation='vertical',
- stretch=None)
- reference_label = QtWidgets.QLabel('%s:' % _("Reference"))
- reference_label.setToolTip(
- _("- 'Itself' - the non copper clearing extent\n"
- "is based on the object that is copper cleared.\n "
+ # self.reference_radio = RadioSet([{'label': _('Itself'), 'value': 'itself'},
+ # {"label": _("Area Selection"), "value": "area"},
+ # {'label': _('Reference Object'), 'value': 'box'}],
+ # orientation='vertical',
+ # stretch=None)
+ self.select_combo = FCComboBox()
+ self.select_combo.addItems(
+ [_("Itself"), _("Area Selection"), _("Reference Object")]
+ )
+ select_label = QtWidgets.QLabel('%s:' % _("Reference"))
+ select_label.setToolTip(
+ _("Selection of area to be cleared of copper."
+ "- 'Itself' - the non copper clearing extent is based on the object that is copper cleared.\n "
"- 'Area Selection' - left mouse click to start selection of the area to be painted.\n"
- "Keeping a modifier key pressed (CTRL or SHIFT) will allow to add multiple areas.\n"
- "- 'Reference Object' - will do non copper clearing within the area\n"
- "specified by another object.")
+ "- 'Reference Object' - will do non copper clearing within the area specified by another object.")
)
- grid0.addWidget(reference_label, 18, 0)
- grid0.addWidget(self.reference_radio, 18, 1)
+ grid0.addWidget(select_label, 18, 0)
+ grid0.addWidget(self.select_combo, 18, 1)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
diff --git a/flatcamTools/ToolNonCopperClear.py b/flatcamTools/ToolNCC.py
similarity index 98%
rename from flatcamTools/ToolNonCopperClear.py
rename to flatcamTools/ToolNCC.py
index 45ea96e8..9caddcc3 100644
--- a/flatcamTools/ToolNonCopperClear.py
+++ b/flatcamTools/ToolNCC.py
@@ -411,20 +411,25 @@ class NonCopperClear(FlatCAMTool, Gerber):
# Method
methodlabel = QtWidgets.QLabel('%s:' % _('Method'))
methodlabel.setToolTip(
- _("Algorithm for non-copper clearing:
"
- "Standard: Fixed step inwards.
"
- "Seed-based: Outwards from seed.
"
- "Line-based: Parallel lines.")
+ _("Algorithm for copper clearing:\n"
+ "- Standard: Fixed step inwards.\n"
+ "- Seed-based: Outwards from seed.\n"
+ "- Line-based: Parallel lines.")
)
- self.ncc_method_radio = RadioSet([
- {"label": _("Standard"), "value": "standard"},
- {"label": _("Seed-based"), "value": "seed"},
- {"label": _("Straight lines"), "value": "lines"}
- ], orientation='vertical', stretch=False)
- self.ncc_method_radio.setObjectName("n_method")
+ # self.ncc_method_radio = RadioSet([
+ # {"label": _("Standard"), "value": "standard"},
+ # {"label": _("Seed-based"), "value": "seed"},
+ # {"label": _("Straight lines"), "value": "lines"}
+ # ], orientation='vertical', stretch=False)
+
+ self.ncc_method_combo = FCComboBox()
+ self.ncc_method_combo.addItems(
+ [_("Standard"), _("Seed"), _("Lines")]
+ )
+ self.ncc_method_combo.setObjectName("n_method")
self.grid3.addWidget(methodlabel, 17, 0)
- self.grid3.addWidget(self.ncc_method_radio, 17, 1)
+ self.grid3.addWidget(self.ncc_method_combo, 17, 1)
# Connect lines
self.ncc_connect_cb = FCCheckBox('%s' % _("Connect"))
@@ -516,21 +521,26 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.grid3.addWidget(self.ncc_rest_cb, 25, 0, 1, 2)
# ## Reference
- self.reference_radio = RadioSet([
- {'label': _('Itself'), 'value': 'itself'},
- {"label": _("Area Selection"), "value": "area"},
- {'label': _("Reference Object"), 'value': 'box'}
- ], orientation='vertical', stretch=False)
- self.reference_radio.setObjectName("n_reference")
+ # self.select_radio = RadioSet([
+ # {'label': _('Itself'), 'value': 'itself'},
+ # {"label": _("Area Selection"), "value": "area"},
+ # {'label': _("Reference Object"), 'value': 'box'}
+ # ], orientation='vertical', stretch=False)
+ self.select_combo = FCComboBox()
+ self.select_combo.addItems(
+ [_("Itself"), _("Area Selection"), _("Reference Object")]
+ )
+ self.select_combo.setObjectName("n_selection")
- self.reference_label = QtWidgets.QLabel('%s:' % _("Reference"))
- self.reference_label.setToolTip(
- _("- 'Itself' - the non copper clearing extent is based on the object that is copper cleared.\n "
+ self.select_label = QtWidgets.QLabel('%s:' % _("Selection"))
+ self.select_label.setToolTip(
+ _("Selection of area to be cleared of copper."
+ "- 'Itself' - the non copper clearing extent is based on the object that is copper cleared.\n "
"- 'Area Selection' - left mouse click to start selection of the area to be painted.\n"
"- 'Reference Object' - will do non copper clearing within the area specified by another object.")
)
- self.grid3.addWidget(self.reference_label, 26, 0, 1, 2)
- self.grid3.addWidget(self.reference_radio, 27, 0, 1, 2)
+ self.grid3.addWidget(self.select_label, 26, 0,)
+ self.grid3.addWidget(self.select_combo, 26, 1)
form1 = QtWidgets.QFormLayout()
self.grid3.addLayout(form1, 28, 0, 1, 2)
@@ -659,7 +669,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
"nccoperation":self.op_radio,
"nccoverlap": self.ncc_overlap_entry,
"nccmargin": self.ncc_margin_entry,
- "nccmethod": self.ncc_method_radio,
+ "nccmethod": self.ncc_method_combo,
"nccconnect": self.ncc_connect_cb,
"ncccontour": self.ncc_contour_cb,
"nccoffset": self.ncc_choice_offset_cb,
@@ -696,7 +706,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.op_radio.activated_custom.connect(self.on_operation_change)
self.box_combo_type.currentIndexChanged.connect(self.on_combo_box_type)
- self.reference_radio.group_toggle_fn = self.on_toggle_reference
+ self.select_combo.group_toggle_fn = self.on_toggle_reference
self.ncc_rest_cb.stateChanged.connect(self.on_rest_machining_check)
self.ncc_order_radio.activated_custom[str].connect(self.on_order_changed)
@@ -943,14 +953,14 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.ncc_order_radio.set_value(self.app.defaults["tools_nccorder"])
self.ncc_overlap_entry.set_value(self.app.defaults["tools_nccoverlap"])
self.ncc_margin_entry.set_value(self.app.defaults["tools_nccmargin"])
- self.ncc_method_radio.set_value(self.app.defaults["tools_nccmethod"])
+ self.ncc_method_combo.set_value(self.app.defaults["tools_nccmethod"])
self.ncc_connect_cb.set_value(self.app.defaults["tools_nccconnect"])
self.ncc_contour_cb.set_value(self.app.defaults["tools_ncccontour"])
self.ncc_rest_cb.set_value(self.app.defaults["tools_nccrest"])
self.ncc_choice_offset_cb.set_value(self.app.defaults["tools_ncc_offset_choice"])
self.ncc_offset_spinner.set_value(self.app.defaults["tools_ncc_offset_value"])
- self.reference_radio.set_value(self.app.defaults["tools_nccref"])
+ self.select_combo.set_value(self.app.defaults["tools_nccref"])
self.milling_type_radio.set_value(self.app.defaults["tools_nccmilling_type"])
self.cutz_entry.set_value(self.app.defaults["tools_ncccutz"])
self.tool_type_radio.set_value(self.app.defaults["tools_ncctool_type"])
@@ -1249,7 +1259,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.box_combo.setCurrentIndex(0)
def on_toggle_reference(self):
- if self.reference_radio.get_value() == "itself" or self.reference_radio.get_value() == "area":
+ if self.select_combo.get_value() == _("Itself") or self.select_combo.get_value() == _("Area Selection"):
self.box_combo.hide()
self.box_combo_label.hide()
self.box_combo_type.hide()
@@ -1566,8 +1576,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.o_name = '%s_ncc' % self.obj_name
- self.select_method = self.reference_radio.get_value()
- if self.select_method == 'itself':
+ self.select_method = self.select_combo.get_value()
+ if self.select_method == _('Itself'):
self.bound_obj_name = self.object_combo.currentText()
# Get source object.
try:
@@ -1580,7 +1590,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
ncctooldia=self.ncc_dia_list,
isotooldia=self.iso_dia_list,
outname=self.o_name)
- elif self.select_method == 'area':
+ elif self.select_method == _("Area Selection"):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click the start point of the area."))
if self.app.is_legacy is False:
@@ -1743,7 +1753,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
box_kind = box_obj.kind if box_obj is not None else None
env_obj = None
- if ncc_select == 'itself':
+ if ncc_select == _('Itself'):
geo_n = ncc_obj.solid_geometry
try:
@@ -1759,13 +1769,13 @@ class NonCopperClear(FlatCAMTool, Gerber):
log.debug("NonCopperClear.envelope_object() 'itself' --> %s" % str(e))
self.app.inform.emit('[ERROR_NOTCL] %s' % _("No object available."))
return None
- elif ncc_select == 'area':
+ elif ncc_select == _("Area Selection"):
env_obj = cascaded_union(self.sel_rect)
try:
__ = iter(env_obj)
except Exception:
env_obj = [env_obj]
- elif ncc_select == 'box':
+ elif ncc_select == _("Reference Object"):
if box_obj is None:
return None, None
@@ -1807,14 +1817,14 @@ class NonCopperClear(FlatCAMTool, Gerber):
return 'fail'
bounding_box = None
- if ncc_select == 'itself':
+ if ncc_select == _('Itself'):
try:
bounding_box = env_obj.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre)
except Exception as e:
log.debug("NonCopperClear.envelope_object_to_tool_bounding_box() 'itself' --> %s" % str(e))
self.app.inform.emit('[ERROR_NOTCL] %s' % _("No object available."))
return 'fail'
- elif ncc_select == 'area':
+ elif ncc_select == _("Area Selection"):
geo_buff_list = []
for poly in env_obj:
if self.app.abort_flag:
@@ -1822,7 +1832,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
raise FlatCAMApp.GracefulException
geo_buff_list.append(poly.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre))
bounding_box = cascaded_union(geo_buff_list)
- elif ncc_select == 'box':
+ elif ncc_select == _("Reference Object"):
if box_kind == 'geometry':
geo_buff_list = list()
for poly in env_obj:
@@ -2055,7 +2065,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
units = self.app.defaults['units']
order = order if order else self.ncc_order_radio.get_value()
- ncc_select = self.reference_radio.get_value()
+ ncc_select = self.select_combo.get_value()
rest_machining_choice = self.ncc_rest_cb.get_value()
# determine if to use the progressive plotting
@@ -2217,13 +2227,13 @@ class NonCopperClear(FlatCAMTool, Gerber):
try:
for pol in p:
if pol is not None and isinstance(pol, Polygon):
- if ncc_method == 'standard':
+ if ncc_method == _("Standard"):
cp = self.clear_polygon(pol, tool,
self.grb_circle_steps,
overlap=ncc_overlap, contour=ncc_contour,
connect=ncc_connect,
prog_plot=prog_plot)
- elif ncc_method == 'seed':
+ elif ncc_method == _("Seed"):
cp = self.clear_polygon2(pol, tool,
self.grb_circle_steps,
overlap=ncc_overlap, contour=ncc_contour,
@@ -2246,12 +2256,12 @@ class NonCopperClear(FlatCAMTool, Gerber):
"It is: %s" % str(type(pol)))
except TypeError:
if isinstance(p, Polygon):
- if ncc_method == 'standard':
+ if ncc_method == _("Standard"):
cp = self.clear_polygon(p, tool, self.grb_circle_steps,
overlap=ncc_overlap, contour=ncc_contour,
connect=ncc_connect,
prog_plot=prog_plot)
- elif ncc_method == 'seed':
+ elif ncc_method == _("Seed"):
cp = self.clear_polygon2(p, tool, self.grb_circle_steps,
overlap=ncc_overlap, contour=ncc_contour,
connect=ncc_connect,
@@ -2515,13 +2525,13 @@ class NonCopperClear(FlatCAMTool, Gerber):
if isinstance(p, Polygon):
try:
- if ncc_method == 'standard':
+ if ncc_method == _("Standard"):
cp = self.clear_polygon(p, tool_used,
self.grb_circle_steps,
overlap=ncc_overlap, contour=ncc_contour,
connect=ncc_connect,
prog_plot=prog_plot)
- elif ncc_method == 'seed':
+ elif ncc_method == _("Seed"):
cp = self.clear_polygon2(p, tool_used,
self.grb_circle_steps,
overlap=ncc_overlap, contour=ncc_contour,
@@ -2547,13 +2557,13 @@ class NonCopperClear(FlatCAMTool, Gerber):
QtWidgets.QApplication.processEvents()
try:
- if ncc_method == 'standard':
+ if ncc_method == _("Standard"):
cp = self.clear_polygon(poly, tool_used,
self.grb_circle_steps,
overlap=ncc_overlap, contour=ncc_contour,
connect=ncc_connect,
prog_plot=prog_plot)
- elif ncc_method == 'seed':
+ elif ncc_method == _("Seed"):
cp = self.clear_polygon2(poly, tool_used,
self.grb_circle_steps,
overlap=ncc_overlap, contour=ncc_contour,
@@ -2789,7 +2799,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.app.inform.emit(_("NCC Tool. Preparing non-copper polygons."))
try:
- if sel_obj is None or sel_obj == 'itself':
+ if sel_obj is None or sel_obj == _('Itself'):
ncc_sel_obj = ncc_obj
else:
ncc_sel_obj = sel_obj
@@ -2798,7 +2808,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
return 'fail'
bounding_box = None
- if ncc_select == 'itself':
+ if ncc_select == _('Itself'):
geo_n = ncc_sel_obj.solid_geometry
try:
@@ -2951,7 +2961,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
milling_type = self.app.defaults["tools_nccmilling_type"]
for tool_iso in isotooldia:
- new_geometry = []
+ new_geometry = list()
if milling_type == 'cl':
isolated_geo = self.generate_envelope(tool_iso / 2, 1)
diff --git a/flatcamTools/__init__.py b/flatcamTools/__init__.py
index 74d1aff5..bdd7e58b 100644
--- a/flatcamTools/__init__.py
+++ b/flatcamTools/__init__.py
@@ -17,7 +17,7 @@ from flatcamTools.ToolDistanceMin import DistanceMin
from flatcamTools.ToolMove import ToolMove
-from flatcamTools.ToolNonCopperClear import NonCopperClear
+from flatcamTools.ToolNCC import NonCopperClear
from flatcamTools.ToolPaint import ToolPaint
from flatcamTools.ToolOptimal import ToolOptimal
From acc61d460b75799a57d3d616a450edf192334984 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 29 Feb 2020 22:21:09 +0200
Subject: [PATCH 119/209] - fixed error in CutOut Tool when trying to create a
FreeFrom Cutout out of a Gerber object with the Convex Shape checked
---
README.md | 1 +
flatcamGUI/PreferencesUI.py | 22 +++++++++++-----------
flatcamTools/ToolCutOut.py | 16 +++++++++++-----
flatcamTools/ToolNCC.py | 8 ++++----
flatcamTools/ToolPaint.py | 11 +++++------
5 files changed, 32 insertions(+), 26 deletions(-)
diff --git a/README.md b/README.md
index 28be59a2..9d3bab8c 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
29.02.2020
- compacted the NCC Tool UI by replacing some Radio buttons with Combo boxes due of too many elements
+- fixed error in CutOut Tool when trying to create a FreeFrom Cutout out of a Gerber object with the Convex Shape checked
28.02.2020
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index 7d6767cd..89dcbfd0 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -5407,12 +5407,12 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
self.select_combo.addItems(
[_("Itself"), _("Area Selection"), _("Reference Object")]
)
- select_label = QtWidgets.QLabel('%s:' % _("Reference"))
+ select_label = QtWidgets.QLabel('%s:' % _("Selection"))
select_label.setToolTip(
- _("Selection of area to be cleared of copper."
- "- 'Itself' - the non copper clearing extent is based on the object that is copper cleared.\n "
- "- 'Area Selection' - left mouse click to start selection of the area to be painted.\n"
- "- 'Reference Object' - will do non copper clearing within the area specified by another object.")
+ _("Selection of area to be processed.\n"
+ "- 'Itself' - the processing extent is based on the object that is processed.\n "
+ "- 'Area Selection' - left mouse click to start selection of the area to be processed.\n"
+ "- 'Reference Object' - will process the area specified by another object.")
)
grid0.addWidget(select_label, 18, 0)
@@ -5905,14 +5905,14 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
# Polygon selection
selectlabel = QtWidgets.QLabel('%s:' % _('Selection'))
selectlabel.setToolTip(
- _("How to select Polygons to be painted.\n"
- "- 'Polygon Selection' - left mouse click to add/remove polygons to be painted.\n"
- "- 'Area Selection' - left mouse click to start selection of the area to be painted.\n"
+ _("Selection of area to be processed.\n"
+ "- 'Polygon Selection' - left mouse click to add/remove polygons to be processed.\n"
+ "- 'Area Selection' - left mouse click to start selection of the area to be processed.\n"
"Keeping a modifier key pressed (CTRL or SHIFT) will allow to add multiple areas.\n"
- "- 'All Polygons' - the Paint will start after click.\n"
- "- 'Reference Object' - will do non copper clearing within the area\n"
- "specified by another object.")
+ "- 'All Polygons' - the process will start after click.\n"
+ "- 'Reference Object' - will process the area specified by another object.")
)
+
# self.selectmethod_combo = RadioSet(
# [
# {"label": _("Polygon Selection"), "value": "single"},
diff --git a/flatcamTools/ToolCutOut.py b/flatcamTools/ToolCutOut.py
index 32e799b1..87ebafc3 100644
--- a/flatcamTools/ToolCutOut.py
+++ b/flatcamTools/ToolCutOut.py
@@ -521,13 +521,19 @@ class CutOut(FlatCAMTool):
gapsize = gapsize / 2 + (dia / 2)
def geo_init(geo_obj, app_obj):
- solid_geo = []
+ solid_geo = list()
if isinstance(cutout_obj, FlatCAMGerber):
- if convex_box:
- object_geo = cutout_obj.solid_geometry.convex_hull
- else:
- object_geo = cutout_obj.solid_geometry
+ if isinstance(cutout_obj.solid_geometry, list):
+ cutout_obj.solid_geometry = MultiPolygon(cutout_obj.solid_geometry)
+
+ try:
+ if convex_box:
+ object_geo = cutout_obj.solid_geometry.convex_hull
+ else:
+ object_geo = cutout_obj.solid_geometry
+ except Exception as e:
+ log.debug("CutOut.on_freeform_cutout().geo_init() --> %s" % str(e))
else:
object_geo = cutout_obj.solid_geometry
diff --git a/flatcamTools/ToolNCC.py b/flatcamTools/ToolNCC.py
index 9caddcc3..021788eb 100644
--- a/flatcamTools/ToolNCC.py
+++ b/flatcamTools/ToolNCC.py
@@ -534,10 +534,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.select_label = QtWidgets.QLabel('%s:' % _("Selection"))
self.select_label.setToolTip(
- _("Selection of area to be cleared of copper."
- "- 'Itself' - the non copper clearing extent is based on the object that is copper cleared.\n "
- "- 'Area Selection' - left mouse click to start selection of the area to be painted.\n"
- "- 'Reference Object' - will do non copper clearing within the area specified by another object.")
+ _("Selection of area to be processed.\n"
+ "- 'Itself' - the processing extent is based on the object that is processed.\n "
+ "- 'Area Selection' - left mouse click to start selection of the area to be processed.\n"
+ "- 'Reference Object' - will process the area specified by another object.")
)
self.grid3.addWidget(self.select_label, 26, 0,)
self.grid3.addWidget(self.select_combo, 26, 1)
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 310a6208..8cb957b9 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -453,13 +453,12 @@ class ToolPaint(FlatCAMTool, Gerber):
# Polygon selection
selectlabel = QtWidgets.QLabel('%s:' % _('Selection'))
selectlabel.setToolTip(
- _("How to select Polygons to be painted.\n"
- "- 'Polygon Selection' - left mouse click to add/remove polygons to be painted.\n"
- "- 'Area Selection' - left mouse click to start selection of the area to be painted.\n"
+ _("Selection of area to be processed.\n"
+ "- 'Polygon Selection' - left mouse click to add/remove polygons to be processed.\n"
+ "- 'Area Selection' - left mouse click to start selection of the area to be processed.\n"
"Keeping a modifier key pressed (CTRL or SHIFT) will allow to add multiple areas.\n"
- "- 'All Polygons' - the Paint will start after click.\n"
- "- 'Reference Object' - will do non copper clearing within the area\n"
- "specified by another object.")
+ "- 'All Polygons' - the process will start after click.\n"
+ "- 'Reference Object' - will process the area specified by another object.")
)
# grid3 = QtWidgets.QGridLayout()
From 70d3895799c41131995637755595712b08121317 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 1 Mar 2020 00:52:24 +0200
Subject: [PATCH 120/209] - working on a new type of database
---
FlatCAMApp.py | 42 +-
FlatCAMCommon.py | 964 ++++++++++++++++++++++++++-
FlatCAMObj.py | 62 +-
README.md | 1 +
camlib.py | 36 +-
flatcamEditors/FlatCAMExcEditor.py | 46 +-
flatcamEditors/FlatCAMGeoEditor.py | 38 +-
flatcamEditors/FlatCAMGrbEditor.py | 130 ++--
flatcamGUI/GUIElements.py | 36 +-
flatcamGUI/PlotCanvas.py | 2 +-
flatcamGUI/PlotCanvasLegacy.py | 6 +-
flatcamGUI/PreferencesUI.py | 4 +-
flatcamParsers/ParseExcellon.py | 14 +-
flatcamParsers/ParseGerber.py | 72 +-
flatcamParsers/ParseHPGL2.py | 8 +-
flatcamParsers/ParseSVG.py | 4 +-
flatcamTools/ToolAlignObjects.py | 6 +-
flatcamTools/ToolCalibration.py | 2 +-
flatcamTools/ToolCopperThieving.py | 60 +-
flatcamTools/ToolCutOut.py | 6 +-
flatcamTools/ToolDblSided.py | 8 +-
flatcamTools/ToolDistance.py | 2 +-
flatcamTools/ToolExtractDrills.py | 10 +-
flatcamTools/ToolFiducials.py | 48 +-
flatcamTools/ToolFilm.py | 4 +-
flatcamTools/ToolImage.py | 2 +-
flatcamTools/ToolInvertGerber.py | 18 +-
flatcamTools/ToolNCC.py | 38 +-
flatcamTools/ToolOptimal.py | 6 +-
flatcamTools/ToolPDF.py | 80 +--
flatcamTools/ToolPaint.py | 70 +-
flatcamTools/ToolPanelize.py | 10 +-
flatcamTools/ToolProperties.py | 4 +-
flatcamTools/ToolPunchGerber.py | 40 +-
flatcamTools/ToolQRCode.py | 20 +-
flatcamTools/ToolRulesCheck.py | 124 ++--
flatcamTools/ToolSub.py | 18 +-
tclCommands/TclCommand.py | 2 +-
tclCommands/TclCommandBounds.py | 4 +-
tclCommands/TclCommandCopperClear.py | 2 +-
tclCommands/TclCommandPaint.py | 2 +-
tclCommands/TclCommandPanelize.py | 2 +-
tclCommands/TclCommandSetOrigin.py | 2 +-
43 files changed, 1515 insertions(+), 540 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 285e8315..e4c098c4 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -54,7 +54,7 @@ from flatcamGUI.PlotCanvas import *
from flatcamGUI.PlotCanvasLegacy import *
from flatcamGUI.FlatCAMGUI import *
-from FlatCAMCommon import LoudDict, BookmarkManager, ToolsDB, color_variant
+from FlatCAMCommon import LoudDict, BookmarkManager, ToolsDB, ToolsDB2, color_variant
from FlatCAMPostProc import load_preprocessors
from flatcamEditors.FlatCAMGeoEditor import FlatCAMGeoEditor
@@ -1076,7 +1076,7 @@ class App(QtCore.QObject):
self.current_units = self.defaults['units']
# store here the current self.defaults so it can be restored if Preferences changes are cancelled
- self.current_defaults = dict()
+ self.current_defaults = {}
self.current_defaults.update(self.defaults)
# ##########################################################################
@@ -1755,7 +1755,7 @@ class App(QtCore.QObject):
# make sure that always the 'default' preprocessor is the first item in the dictionary
if 'default' in self.preprocessors.keys():
- new_ppp_dict = dict()
+ new_ppp_dict = {}
# add the 'default' name first in the dict after removing from the preprocessor's dictionary
default_pp = self.preprocessors.pop('default')
@@ -2673,10 +2673,10 @@ class App(QtCore.QObject):
# List to store the objects that are currently loaded in FlatCAM
# This list is updated on each object creation or object delete
- self.all_objects_list = list()
+ self.all_objects_list = []
# List to store the objects that are selected
- self.sel_objects_list = list()
+ self.sel_objects_list = []
# holds the key modifier if pressed (CTRL, SHIFT or ALT)
self.key_modifiers = None
@@ -2752,7 +2752,7 @@ class App(QtCore.QObject):
# this holds a widget that is installed in the Plot Area when View Source option is used
self.source_editor_tab = None
- self.pagesize = dict()
+ self.pagesize = {}
# Storage for shapes, storage that can be used by FlatCAm tools for utility geometry
# VisPy visuals
@@ -7410,8 +7410,8 @@ class App(QtCore.QObject):
self.inform.emit('[ERROR_NOTCL] %s' % _("Failed. No object(s) selected..."))
return
- xminlist = list()
- yminlist = list()
+ xminlist = []
+ yminlist = []
# first get a bounding box to fit all
for obj in obj_list:
@@ -7896,7 +7896,7 @@ class App(QtCore.QObject):
apertures[str(apid)] = {}
apertures[str(apid)]['geometry'] = []
for obj_orig in obj.solid_geometry:
- new_elem = dict()
+ new_elem = {}
new_elem['solid'] = obj_orig
try:
new_elem['follow'] = obj_orig.exterior
@@ -7917,7 +7917,7 @@ class App(QtCore.QObject):
apertures[str(apid)] = {}
apertures[str(apid)]['geometry'] = []
for geo in obj.tools[tool]['solid_geometry']:
- new_el = dict()
+ new_el = {}
new_el['solid'] = geo
new_el['follow'] = geo.exterior
apertures[str(apid)]['geometry'].append(deepcopy(new_el))
@@ -8072,7 +8072,7 @@ class App(QtCore.QObject):
# there can be only one instance of Tools Database at one time
return
- self.tools_db_tab = ToolsDB(
+ self.tools_db_tab = ToolsDB2(
app=self,
parent=self.ui,
callback_on_edited=self.on_tools_db_edited,
@@ -8458,7 +8458,7 @@ class App(QtCore.QObject):
return
# get the name of the selected objects and add them to a list
- name_list = list()
+ name_list = []
for obj in self.collection.get_selected():
name_list.append(obj.options['name'])
@@ -8495,12 +8495,12 @@ class App(QtCore.QObject):
pass
self.ui.menuobjects.clear()
- gerber_list = list()
- exc_list = list()
- cncjob_list = list()
- geo_list = list()
- script_list = list()
- doc_list = list()
+ gerber_list = []
+ exc_list = []
+ cncjob_list = []
+ geo_list = []
+ script_list = []
+ doc_list = []
for name in self.collection.get_names():
obj_named = self.collection.get_by_name(name)
@@ -8780,7 +8780,7 @@ class App(QtCore.QObject):
was clicked, the pixel coordinates and the axes coordinates.
:return: None
"""
- self.pos = list()
+ self.pos = []
if self.is_legacy is False:
event_pos = event.pos
@@ -10631,7 +10631,7 @@ class App(QtCore.QObject):
color = 'black'
transparency_level = 1.0
- self.pagesize = dict()
+ self.pagesize = {}
self.pagesize.update(
{
'Bounds': None,
@@ -10685,7 +10685,7 @@ class App(QtCore.QObject):
}
)
- exported_svg = list()
+ exported_svg = []
for obj in obj_selection:
svg_obj = obj.export_svg(scale_stroke_factor=0.0,
scale_factor_x=None, scale_factor_y=None,
diff --git a/FlatCAMCommon.py b/FlatCAMCommon.py
index 2bc95131..4a68cdaa 100644
--- a/FlatCAMCommon.py
+++ b/FlatCAMCommon.py
@@ -12,7 +12,8 @@
# ##########################################################
from PyQt5 import QtGui, QtCore, QtWidgets
-from flatcamGUI.GUIElements import FCTable, FCEntry, FCButton, FCDoubleSpinner, FCComboBox, FCCheckBox, FCSpinner
+from flatcamGUI.GUIElements import FCTable, FCEntry, FCButton, FCDoubleSpinner, FCComboBox, FCCheckBox, FCSpinner, \
+ FCTree
from camlib import to_dict
import sys
@@ -332,7 +333,7 @@ class BookmarkManager(QtWidgets.QWidget):
# house keeping: it pays to have keys increased by one
new_key = 0
- new_dict = dict()
+ new_dict = {}
for k, v in self.bm_dict.items():
# we start with key 1 so we can use the len(self.bm_dict)
# when adding bookmarks (keys in bm_dict)
@@ -492,7 +493,7 @@ class ToolsDB(QtWidgets.QWidget):
}
}
'''
- self.db_tool_dict = dict()
+ self.db_tool_dict = {}
# layouts
layout = QtWidgets.QVBoxLayout()
@@ -994,7 +995,7 @@ class ToolsDB(QtWidgets.QWidget):
:return: None
"""
- default_data = dict()
+ default_data = {}
default_data.update({
"cutz": float(self.app.defaults["geometry_cutz"]),
"multidepth": self.app.defaults["geometry_multidepth"],
@@ -1018,7 +1019,7 @@ class ToolsDB(QtWidgets.QWidget):
"endz": float(self.app.defaults["geometry_endz"])
})
- dict_elem = dict()
+ dict_elem = {}
dict_elem['name'] = 'new_tool'
if type(self.app.defaults["geometry_cnctooldia"]) == float:
dict_elem['tooldia'] = self.app.defaults["geometry_cnctooldia"]
@@ -1266,8 +1267,955 @@ class ToolsDB(QtWidgets.QWidget):
# update the dictionary storage self.db_tool_dict
self.db_tool_dict.clear()
- dict_elem = dict()
- default_data = dict()
+ dict_elem = {}
+ default_data = {}
+
+ for row in range(self.table_widget.rowCount()):
+ new_toolid = row + 1
+ for col in range(self.table_widget.columnCount()):
+ column_header_text = self.table_widget.horizontalHeaderItem(col).text()
+ if column_header_text == _('Tool Name'):
+ dict_elem['name'] = self.table_widget.item(row, col).text()
+ elif column_header_text == _('Tool Dia'):
+ dict_elem['tooldia'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('Tool Offset'):
+ dict_elem['offset'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('Custom Offset'):
+ dict_elem['offset_value'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('Tool Type'):
+ dict_elem['type'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('Tool Shape'):
+ dict_elem['tool_type'] = self.table_widget.cellWidget(row, col).get_value()
+ else:
+ if column_header_text == _('Cut Z'):
+ default_data['cutz'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('MultiDepth'):
+ default_data['multidepth'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('DPP'):
+ default_data['depthperpass'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('V-Dia'):
+ default_data['vtipdia'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('V-Angle'):
+ default_data['vtipangle'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('Travel Z'):
+ default_data['travelz'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('FR'):
+ default_data['feedrate'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('FR Z'):
+ default_data['feedrate_z'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('FR Rapids'):
+ default_data['feedrate_rapid'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('Spindle Speed'):
+ default_data['spindlespeed'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('Dwell'):
+ default_data['dwell'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('Dwelltime'):
+ default_data['dwelltime'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('Preprocessor'):
+ default_data['ppname_g'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('ExtraCut'):
+ default_data['extracut'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _("E-Cut Length"):
+ default_data['extracut_length'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('Toolchange'):
+ default_data['toolchange'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('Toolchange XY'):
+ default_data['toolchangexy'] = self.table_widget.item(row, col).text()
+ elif column_header_text == _('Toolchange Z'):
+ default_data['toolchangez'] = self.table_widget.cellWidget(row, col).get_value()
+ elif column_header_text == _('Start Z'):
+ default_data['startz'] = float(self.table_widget.item(row, col).text()) \
+ if self.table_widget.item(row, col).text() is not '' else None
+ elif column_header_text == _('End Z'):
+ default_data['endz'] = self.table_widget.cellWidget(row, col).get_value()
+
+ dict_elem['data'] = default_data
+ self.db_tool_dict.update(
+ {
+ new_toolid: deepcopy(dict_elem)
+ }
+ )
+
+ self.callback_app()
+
+ def on_tool_requested_from_app(self):
+ if not self.table_widget.selectionModel().selectedRows():
+ self.app.inform.emit('[WARNING_NOTCL] %s...' % _("No Tool/row selected in the Tools Database table"))
+ return
+
+ model_index_list = self.table_widget.selectionModel().selectedRows()
+ for model_index in model_index_list:
+ selected_row = model_index.row()
+ tool_uid = selected_row + 1
+ for key in self.db_tool_dict.keys():
+ if str(key) == str(tool_uid):
+ selected_tool = self.db_tool_dict[key]
+ self.on_tool_request(tool=selected_tool)
+
+ def on_cancel_tool(self):
+ for idx in range(self.app.ui.plot_tab_area.count()):
+ if self.app.ui.plot_tab_area.tabText(idx) == _("Tools Database"):
+ wdg = self.app.ui.plot_tab_area.widget(idx)
+ wdg.deleteLater()
+ self.app.ui.plot_tab_area.removeTab(idx)
+ self.app.inform.emit('%s' % _("Cancelled adding tool from DB."))
+
+ def resize_new_tool_table_widget(self, min_size, max_size):
+ """
+ Resize the table widget responsible for adding new tool in the Tool Database
+
+ :param min_size: passed by rangeChanged signal or the self.new_tool_table_widget.horizontalScrollBar()
+ :param max_size: passed by rangeChanged signal or the self.new_tool_table_widget.horizontalScrollBar()
+ :return:
+ """
+ t_height = self.t_height
+ if max_size > min_size:
+ t_height = self.t_height + self.new_tool_table_widget.verticalScrollBar().height()
+
+ self.new_tool_table_widget.setMaximumHeight(t_height)
+
+ def closeEvent(self, QCloseEvent):
+ super().closeEvent(QCloseEvent)
+
+
+class ToolsDB2(QtWidgets.QWidget):
+
+ mark_tools_rows = QtCore.pyqtSignal()
+
+ def __init__(self, app, callback_on_edited, callback_on_tool_request, parent=None):
+ super(ToolsDB2, self).__init__(parent)
+
+ self.app = app
+ self.decimals = self.app.decimals
+ self.callback_app = callback_on_edited
+
+ self.on_tool_request = callback_on_tool_request
+
+ self.offset_item_options = ["Path", "In", "Out", "Custom"]
+ self.type_item_options = ["Iso", "Rough", "Finish"]
+ self.tool_type_item_options = ["C1", "C2", "C3", "C4", "B", "V"]
+
+ '''
+ dict to hold all the tools in the Tools DB
+ format:
+ {
+ tool_id: {
+ 'name': 'new_tool'
+ 'tooldia': self.app.defaults["geometry_cnctooldia"]
+ 'offset': 'Path'
+ 'offset_value': 0.0
+ 'type': _('Rough'),
+ 'tool_type': 'C1'
+ 'data': dict()
+ }
+ }
+ '''
+ self.db_tool_dict = {}
+
+ # layouts
+ grid_layout = QtWidgets.QGridLayout()
+ grid_layout.setColumnStretch(0, 0)
+ grid_layout.setColumnStretch(1, 1)
+
+ self.setLayout(grid_layout)
+
+ tree_layout = QtWidgets.QVBoxLayout()
+ grid_layout.addLayout(tree_layout, 0, 0)
+
+ self.tree_widget = FCTree(columns=2, header_hidden=False)
+ self.tree_widget.setHeaderLabels(["ID", "Tool Name"])
+ self.tree_widget.setIndentation(0)
+ self.tree_widget.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
+ tree_layout.addWidget(self.tree_widget)
+
+ table_hlay = QtWidgets.QHBoxLayout()
+ grid_layout.addLayout(table_hlay, 0, 1)
+
+ self.table_widget = FCTable(drag_drop=True)
+ self.table_widget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
+ table_hlay.addWidget(self.table_widget)
+
+ # set the number of columns and the headers tool tips
+ self.configure_table()
+
+ new_vlay = QtWidgets.QVBoxLayout()
+ grid_layout.addLayout(new_vlay, 1, 0, 1, 2)
+
+ # new_tool_lbl = QtWidgets.QLabel('%s' % _("New Tool"))
+ # new_vlay.addWidget(new_tool_lbl, alignment=QtCore.Qt.AlignBottom)
+
+ self.buttons_frame = QtWidgets.QFrame()
+ self.buttons_frame.setContentsMargins(0, 0, 0, 0)
+ new_vlay.addWidget(self.buttons_frame)
+ self.buttons_box = QtWidgets.QHBoxLayout()
+ self.buttons_box.setContentsMargins(0, 0, 0, 0)
+ self.buttons_frame.setLayout(self.buttons_box)
+ self.buttons_frame.show()
+
+ add_entry_btn = FCButton(_("Add Geometry Tool in DB"))
+ add_entry_btn.setToolTip(
+ _("Add a new tool in the Tools Database.\n"
+ "It will be used in the Geometry UI.\n"
+ "You can edit it after it is added.")
+ )
+ self.buttons_box.addWidget(add_entry_btn)
+
+ # add_fct_entry_btn = FCButton(_("Add Paint/NCC Tool in DB"))
+ # add_fct_entry_btn.setToolTip(
+ # _("Add a new tool in the Tools Database.\n"
+ # "It will be used in the Paint/NCC Tools UI.\n"
+ # "You can edit it after it is added.")
+ # )
+ # self.buttons_box.addWidget(add_fct_entry_btn)
+
+ remove_entry_btn = FCButton(_("Delete Tool from DB"))
+ remove_entry_btn.setToolTip(
+ _("Remove a selection of tools in the Tools Database.")
+ )
+ self.buttons_box.addWidget(remove_entry_btn)
+
+ export_db_btn = FCButton(_("Export DB"))
+ export_db_btn.setToolTip(
+ _("Save the Tools Database to a custom text file.")
+ )
+ self.buttons_box.addWidget(export_db_btn)
+
+ import_db_btn = FCButton(_("Import DB"))
+ import_db_btn.setToolTip(
+ _("Load the Tools Database information's from a custom text file.")
+ )
+ self.buttons_box.addWidget(import_db_btn)
+
+ self.add_tool_from_db = FCButton(_("Add Tool from Tools DB"))
+ self.add_tool_from_db.setToolTip(
+ _("Add a new tool in the Tools Table of the\n"
+ "active Geometry object after selecting a tool\n"
+ "in the Tools Database.")
+ )
+ self.add_tool_from_db.hide()
+
+ self.cancel_tool_from_db = FCButton(_("Cancel"))
+ self.cancel_tool_from_db.hide()
+
+ hlay = QtWidgets.QHBoxLayout()
+ tree_layout.addLayout(hlay)
+ hlay.addWidget(self.add_tool_from_db)
+ hlay.addWidget(self.cancel_tool_from_db)
+ hlay.addStretch()
+
+ # ##############################################################################
+ # ######################## SIGNALS #############################################
+ # ##############################################################################
+
+ add_entry_btn.clicked.connect(self.on_tool_add)
+ remove_entry_btn.clicked.connect(self.on_tool_delete)
+ export_db_btn.clicked.connect(self.on_export_tools_db_file)
+ import_db_btn.clicked.connect(self.on_import_tools_db_file)
+ # closebtn.clicked.connect(self.accept)
+
+ self.add_tool_from_db.clicked.connect(self.on_tool_requested_from_app)
+ self.cancel_tool_from_db.clicked.connect(self.on_cancel_tool)
+
+ self.tree_widget.selectionModel().selectionChanged.connect(self.on_list_selection_change)
+ self.tree_widget.itemChanged.connect(self.on_list_item_edited)
+ self.setup_db_ui()
+
+ def on_list_selection_change(self, current):
+ return
+ for idx in current.indexes():
+ print(idx.data())
+
+ def on_list_item_edited(self, item, idx):
+ row = int(item.text(0)) - 1
+ self.table_widget.item(row, 1).setText(item.text(1))
+
+ def configure_table(self):
+ self.table_widget.setColumnCount(27)
+ # self.table_widget.setColumnWidth(0, 20)
+ self.table_widget.setHorizontalHeaderLabels(
+ [
+ '#',
+ _("Tool Name"),
+ _("Tool Dia"),
+ _("Tool Offset"),
+ _("Custom Offset"),
+ _("Tool Type"),
+ _("Tool Shape"),
+ _("Cut Z"),
+ _("MultiDepth"),
+ _("DPP"),
+ _("V-Dia"),
+ _("V-Angle"),
+ _("Travel Z"),
+ _("FR"),
+ _("FR Z"),
+ _("FR Rapids"),
+ _("Spindle Speed"),
+ _("Dwell"),
+ _("Dwelltime"),
+ _("Preprocessor"),
+ _("ExtraCut"),
+ _("E-Cut Length"),
+ _("Toolchange"),
+ _("Toolchange XY"),
+ _("Toolchange Z"),
+ _("Start Z"),
+ _("End Z"),
+ ]
+ )
+ self.table_widget.horizontalHeaderItem(0).setToolTip(
+ _("Tool Index."))
+ self.table_widget.horizontalHeaderItem(1).setToolTip(
+ _("Tool name.\n"
+ "This is not used in the app, it's function\n"
+ "is to serve as a note for the user."))
+ self.table_widget.horizontalHeaderItem(2).setToolTip(
+ _("Tool Diameter."))
+ self.table_widget.horizontalHeaderItem(3).setToolTip(
+ _("Tool Offset.\n"
+ "Can be of a few types:\n"
+ "Path = zero offset\n"
+ "In = offset inside by half of tool diameter\n"
+ "Out = offset outside by half of tool diameter\n"
+ "Custom = custom offset using the Custom Offset value"))
+ self.table_widget.horizontalHeaderItem(4).setToolTip(
+ _("Custom Offset.\n"
+ "A value to be used as offset from the current path."))
+ self.table_widget.horizontalHeaderItem(5).setToolTip(
+ _("Tool Type.\n"
+ "Can be:\n"
+ "Iso = isolation cut\n"
+ "Rough = rough cut, low feedrate, multiple passes\n"
+ "Finish = finishing cut, high feedrate"))
+ self.table_widget.horizontalHeaderItem(6).setToolTip(
+ _("Tool Shape. \n"
+ "Can be:\n"
+ "C1 ... C4 = circular tool with x flutes\n"
+ "B = ball tip milling tool\n"
+ "V = v-shape milling tool"))
+ self.table_widget.horizontalHeaderItem(7).setToolTip(
+ _("Cutting Depth.\n"
+ "The depth at which to cut into material."))
+ self.table_widget.horizontalHeaderItem(8).setToolTip(
+ _("Multi Depth.\n"
+ "Selecting this will allow cutting in multiple passes,\n"
+ "each pass adding a DPP parameter depth."))
+ self.table_widget.horizontalHeaderItem(9).setToolTip(
+ _("DPP. Depth per Pass.\n"
+ "The value used to cut into material on each pass."))
+ self.table_widget.horizontalHeaderItem(10).setToolTip(
+ _("V-Dia.\n"
+ "Diameter of the tip for V-Shape Tools."))
+ self.table_widget.horizontalHeaderItem(11).setToolTip(
+ _("V-Agle.\n"
+ "Angle at the tip for the V-Shape Tools."))
+ self.table_widget.horizontalHeaderItem(12).setToolTip(
+ _("Clearance Height.\n"
+ "Height at which the milling bit will travel between cuts,\n"
+ "above the surface of the material, avoiding all fixtures."))
+ self.table_widget.horizontalHeaderItem(13).setToolTip(
+ _("FR. Feedrate\n"
+ "The speed on XY plane used while cutting into material."))
+ self.table_widget.horizontalHeaderItem(14).setToolTip(
+ _("FR Z. Feedrate Z\n"
+ "The speed on Z plane."))
+ self.table_widget.horizontalHeaderItem(15).setToolTip(
+ _("FR Rapids. Feedrate Rapids\n"
+ "Speed used while moving as fast as possible.\n"
+ "This is used only by some devices that can't use\n"
+ "the G0 g-code command. Mostly 3D printers."))
+ self.table_widget.horizontalHeaderItem(16).setToolTip(
+ _("Spindle Speed.\n"
+ "If it's left empty it will not be used.\n"
+ "The speed of the spindle in RPM."))
+ self.table_widget.horizontalHeaderItem(17).setToolTip(
+ _("Dwell.\n"
+ "Check this if a delay is needed to allow\n"
+ "the spindle motor to reach it's set speed."))
+ self.table_widget.horizontalHeaderItem(18).setToolTip(
+ _("Dwell Time.\n"
+ "A delay used to allow the motor spindle reach it's set speed."))
+ self.table_widget.horizontalHeaderItem(19).setToolTip(
+ _("Preprocessor.\n"
+ "A selection of files that will alter the generated G-code\n"
+ "to fit for a number of use cases."))
+ self.table_widget.horizontalHeaderItem(20).setToolTip(
+ _("Extra Cut.\n"
+ "If checked, after a isolation is finished an extra cut\n"
+ "will be added where the start and end of isolation meet\n"
+ "such as that this point is covered by this extra cut to\n"
+ "ensure a complete isolation."))
+ self.table_widget.horizontalHeaderItem(21).setToolTip(
+ _("Extra Cut length.\n"
+ "If checked, after a isolation is finished an extra cut\n"
+ "will be added where the start and end of isolation meet\n"
+ "such as that this point is covered by this extra cut to\n"
+ "ensure a complete isolation. This is the length of\n"
+ "the extra cut."))
+ self.table_widget.horizontalHeaderItem(22).setToolTip(
+ _("Toolchange.\n"
+ "It will create a toolchange event.\n"
+ "The kind of toolchange is determined by\n"
+ "the preprocessor file."))
+ self.table_widget.horizontalHeaderItem(23).setToolTip(
+ _("Toolchange XY.\n"
+ "A set of coordinates in the format (x, y).\n"
+ "Will determine the cartesian position of the point\n"
+ "where the tool change event take place."))
+ self.table_widget.horizontalHeaderItem(24).setToolTip(
+ _("Toolchange Z.\n"
+ "The position on Z plane where the tool change event take place."))
+ self.table_widget.horizontalHeaderItem(25).setToolTip(
+ _("Start Z.\n"
+ "If it's left empty it will not be used.\n"
+ "A position on Z plane to move immediately after job start."))
+ self.table_widget.horizontalHeaderItem(26).setToolTip(
+ _("End Z.\n"
+ "A position on Z plane to move immediately after job stop."))
+
+ def setup_db_ui(self):
+ filename = self.app.data_path + '/geo_tools_db.FlatDB'
+
+ # load the database tools from the file
+ try:
+ with open(filename) as f:
+ tools = f.read()
+ except IOError:
+ self.app.log.error("Could not load tools DB file.")
+ self.app.inform.emit('[ERROR] %s' % _("Could not load Tools DB file."))
+ return
+
+ try:
+ self.db_tool_dict = json.loads(tools)
+ except Exception:
+ e = sys.exc_info()[0]
+ self.app.log.error(str(e))
+ self.app.inform.emit('[ERROR] %s' % _("Failed to parse Tools DB file."))
+ return
+
+ self.app.inform.emit('[success] %s: %s' % (_("Loaded FlatCAM Tools DB from"), filename))
+
+ self.build_db_ui()
+
+ self.table_widget.setupContextMenu()
+ self.table_widget.addContextMenu(
+ _("Add to DB"), self.on_tool_add, icon=QtGui.QIcon(self.app.resource_location + "/plus16.png"))
+ self.table_widget.addContextMenu(
+ _("Copy from DB"), self.on_tool_copy, icon=QtGui.QIcon(self.app.resource_location + "/copy16.png"))
+ self.table_widget.addContextMenu(
+ _("Delete from DB"), self.on_tool_delete, icon=QtGui.QIcon(self.app.resource_location + "/delete32.png"))
+
+ def build_db_ui(self):
+ self.ui_disconnect()
+ self.table_widget.setRowCount(len(self.db_tool_dict))
+
+ nr_crt = 0
+
+ parent = self.tree_widget
+ self.tree_widget.blockSignals(True)
+ self.tree_widget.clear()
+ self.tree_widget.blockSignals(False)
+
+ for toolid, dict_val in self.db_tool_dict.items():
+ row = nr_crt
+ nr_crt += 1
+
+ t_name = dict_val['name']
+ try:
+ self.add_tool_table_line(row, name=t_name, widget=self.table_widget, tooldict=dict_val)
+ self.tree_widget.blockSignals(True)
+ try:
+ self.tree_widget.addParentEditable(parent=parent, title=[str(row+1), t_name], editable=True)
+ except Exception as e:
+ print('FlatCAMCoomn.ToolDB2.build_db_ui() -> ', str(e))
+ self.tree_widget.blockSignals(False)
+ except Exception as e:
+ self.app.log.debug("ToolDB.build_db_ui.add_tool_table_line() --> %s" % str(e))
+ vertical_header = self.table_widget.verticalHeader()
+ vertical_header.hide()
+
+ horizontal_header = self.table_widget.horizontalHeader()
+ horizontal_header.setMinimumSectionSize(10)
+ horizontal_header.setDefaultSectionSize(70)
+
+ self.table_widget.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
+ for x in range(27):
+ self.table_widget.resizeColumnToContents(x)
+
+ horizontal_header.setSectionResizeMode(0, QtWidgets.QHeaderView.Fixed)
+ # horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
+ # horizontal_header.setSectionResizeMode(13, QtWidgets.QHeaderView.Fixed)
+
+ horizontal_header.resizeSection(0, 20)
+ # horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
+ # horizontal_header.setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch)
+
+ self.ui_connect()
+
+ def add_tool_table_line(self, row, name, widget, tooldict):
+ data = tooldict['data']
+
+ nr_crt = row + 1
+ id_item = QtWidgets.QTableWidgetItem('%d' % int(nr_crt))
+ # id_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
+ flags = id_item.flags() & ~QtCore.Qt.ItemIsEditable
+ id_item.setFlags(flags)
+ widget.setItem(row, 0, id_item) # Tool name/id
+
+ tool_name_item = QtWidgets.QTableWidgetItem(name)
+ widget.setItem(row, 1, tool_name_item)
+
+ dia_item = FCDoubleSpinner()
+ dia_item.set_precision(self.decimals)
+ dia_item.setSingleStep(0.1)
+ dia_item.set_range(0.0, 9999.9999)
+ dia_item.set_value(float(tooldict['tooldia']))
+ widget.setCellWidget(row, 2, dia_item)
+
+ tool_offset_item = FCComboBox()
+ for item in self.offset_item_options:
+ tool_offset_item.addItem(item)
+ tool_offset_item.set_value(tooldict['offset'])
+ widget.setCellWidget(row, 3, tool_offset_item)
+
+ c_offset_item = FCDoubleSpinner()
+ c_offset_item.set_precision(self.decimals)
+ c_offset_item.setSingleStep(0.1)
+ c_offset_item.set_range(-9999.9999, 9999.9999)
+ c_offset_item.set_value(float(tooldict['offset_value']))
+ widget.setCellWidget(row, 4, c_offset_item)
+
+ tt_item = FCComboBox()
+ for item in self.type_item_options:
+ tt_item.addItem(item)
+ tt_item.set_value(tooldict['type'])
+ widget.setCellWidget(row, 5, tt_item)
+
+ tshape_item = FCComboBox()
+ for item in self.tool_type_item_options:
+ tshape_item.addItem(item)
+ tshape_item.set_value(tooldict['tool_type'])
+ widget.setCellWidget(row, 6, tshape_item)
+
+ cutz_item = FCDoubleSpinner()
+ cutz_item.set_precision(self.decimals)
+ cutz_item.setSingleStep(0.1)
+ if self.app.defaults['global_machinist_setting']:
+ cutz_item.set_range(-9999.9999, 9999.9999)
+ else:
+ cutz_item.set_range(-9999.9999, -0.0000)
+
+ cutz_item.set_value(float(data['cutz']))
+ widget.setCellWidget(row, 7, cutz_item)
+
+ multidepth_item = FCCheckBox()
+ multidepth_item.set_value(data['multidepth'])
+ widget.setCellWidget(row, 8, multidepth_item)
+
+ # to make the checkbox centered but it can no longer have it's value accessed - needs a fix using findchild()
+ # multidepth_item = QtWidgets.QWidget()
+ # cb = FCCheckBox()
+ # cb.set_value(data['multidepth'])
+ # qhboxlayout = QtWidgets.QHBoxLayout(multidepth_item)
+ # qhboxlayout.addWidget(cb)
+ # qhboxlayout.setAlignment(QtCore.Qt.AlignCenter)
+ # qhboxlayout.setContentsMargins(0, 0, 0, 0)
+ # widget.setCellWidget(row, 8, multidepth_item)
+
+ depth_per_pass_item = FCDoubleSpinner()
+ depth_per_pass_item.set_precision(self.decimals)
+ depth_per_pass_item.setSingleStep(0.1)
+ depth_per_pass_item.set_range(0.0, 9999.9999)
+ depth_per_pass_item.set_value(float(data['depthperpass']))
+ widget.setCellWidget(row, 9, depth_per_pass_item)
+
+ vtip_dia_item = FCDoubleSpinner()
+ vtip_dia_item.set_precision(self.decimals)
+ vtip_dia_item.setSingleStep(0.1)
+ vtip_dia_item.set_range(0.0, 9999.9999)
+ vtip_dia_item.set_value(float(data['vtipdia']))
+ widget.setCellWidget(row, 10, vtip_dia_item)
+
+ vtip_angle_item = FCDoubleSpinner()
+ vtip_angle_item.set_precision(self.decimals)
+ vtip_angle_item.setSingleStep(0.1)
+ vtip_angle_item.set_range(-360.0, 360.0)
+ vtip_angle_item.set_value(float(data['vtipangle']))
+ widget.setCellWidget(row, 11, vtip_angle_item)
+
+ travelz_item = FCDoubleSpinner()
+ travelz_item.set_precision(self.decimals)
+ travelz_item.setSingleStep(0.1)
+ if self.app.defaults['global_machinist_setting']:
+ travelz_item.set_range(-9999.9999, 9999.9999)
+ else:
+ travelz_item.set_range(0.0000, 9999.9999)
+
+ travelz_item.set_value(float(data['travelz']))
+ widget.setCellWidget(row, 12, travelz_item)
+
+ fr_item = FCDoubleSpinner()
+ fr_item.set_precision(self.decimals)
+ fr_item.set_range(0.0, 9999.9999)
+ fr_item.set_value(float(data['feedrate']))
+ widget.setCellWidget(row, 13, fr_item)
+
+ frz_item = FCDoubleSpinner()
+ frz_item.set_precision(self.decimals)
+ frz_item.set_range(0.0, 9999.9999)
+ frz_item.set_value(float(data['feedrate_z']))
+ widget.setCellWidget(row, 14, frz_item)
+
+ frrapids_item = FCDoubleSpinner()
+ frrapids_item.set_precision(self.decimals)
+ frrapids_item.set_range(0.0, 9999.9999)
+ frrapids_item.set_value(float(data['feedrate_rapid']))
+ widget.setCellWidget(row, 15, frrapids_item)
+
+ spindlespeed_item = FCSpinner()
+ spindlespeed_item.set_range(0, 1000000)
+ spindlespeed_item.set_value(int(data['spindlespeed']))
+ spindlespeed_item.set_step(100)
+ widget.setCellWidget(row, 16, spindlespeed_item)
+
+ dwell_item = FCCheckBox()
+ dwell_item.set_value(data['dwell'])
+ widget.setCellWidget(row, 17, dwell_item)
+
+ dwelltime_item = FCDoubleSpinner()
+ dwelltime_item.set_precision(self.decimals)
+ dwelltime_item.set_range(0.0000, 9999.9999)
+ dwelltime_item.set_value(float(data['dwelltime']))
+ widget.setCellWidget(row, 18, dwelltime_item)
+
+ pp_item = FCComboBox()
+ for item in self.app.preprocessors:
+ pp_item.addItem(item)
+ pp_item.set_value(data['ppname_g'])
+ widget.setCellWidget(row, 19, pp_item)
+
+ ecut_item = FCCheckBox()
+ ecut_item.set_value(data['extracut'])
+ widget.setCellWidget(row, 20, ecut_item)
+
+ ecut_length_item = FCDoubleSpinner()
+ ecut_length_item.set_precision(self.decimals)
+ ecut_length_item.set_range(0.0000, 9999.9999)
+ ecut_length_item.set_value(data['extracut_length'])
+ widget.setCellWidget(row, 21, ecut_length_item)
+
+ toolchange_item = FCCheckBox()
+ toolchange_item.set_value(data['toolchange'])
+ widget.setCellWidget(row, 22, toolchange_item)
+
+ toolchangexy_item = QtWidgets.QTableWidgetItem(str(data['toolchangexy']) if data['toolchangexy'] else '')
+ widget.setItem(row, 23, toolchangexy_item)
+
+ toolchangez_item = FCDoubleSpinner()
+ toolchangez_item.set_precision(self.decimals)
+ toolchangez_item.setSingleStep(0.1)
+ if self.app.defaults['global_machinist_setting']:
+ toolchangez_item.set_range(-9999.9999, 9999.9999)
+ else:
+ toolchangez_item.set_range(0.0000, 9999.9999)
+
+ toolchangez_item.set_value(float(data['toolchangez']))
+ widget.setCellWidget(row, 24, toolchangez_item)
+
+ startz_item = QtWidgets.QTableWidgetItem(str(data['startz']) if data['startz'] else '')
+ widget.setItem(row, 25, startz_item)
+
+ endz_item = FCDoubleSpinner()
+ endz_item.set_precision(self.decimals)
+ endz_item.setSingleStep(0.1)
+ if self.app.defaults['global_machinist_setting']:
+ endz_item.set_range(-9999.9999, 9999.9999)
+ else:
+ endz_item.set_range(0.0000, 9999.9999)
+
+ endz_item.set_value(float(data['endz']))
+ widget.setCellWidget(row, 26, endz_item)
+
+ def on_tool_add(self):
+ """
+ Add a tool in the DB Tool Table
+ :return: None
+ """
+
+ default_data = {}
+ default_data.update({
+ "cutz": float(self.app.defaults["geometry_cutz"]),
+ "multidepth": self.app.defaults["geometry_multidepth"],
+ "depthperpass": float(self.app.defaults["geometry_depthperpass"]),
+ "vtipdia": float(self.app.defaults["geometry_vtipdia"]),
+ "vtipangle": float(self.app.defaults["geometry_vtipangle"]),
+ "travelz": float(self.app.defaults["geometry_travelz"]),
+ "feedrate": float(self.app.defaults["geometry_feedrate"]),
+ "feedrate_z": float(self.app.defaults["geometry_feedrate_z"]),
+ "feedrate_rapid": float(self.app.defaults["geometry_feedrate_rapid"]),
+ "spindlespeed": self.app.defaults["geometry_spindlespeed"],
+ "dwell": self.app.defaults["geometry_dwell"],
+ "dwelltime": float(self.app.defaults["geometry_dwelltime"]),
+ "ppname_g": self.app.defaults["geometry_ppname_g"],
+ "extracut": self.app.defaults["geometry_extracut"],
+ "extracut_length": float(self.app.defaults["geometry_extracut_length"]),
+ "toolchange": self.app.defaults["geometry_toolchange"],
+ "toolchangexy": self.app.defaults["geometry_toolchangexy"],
+ "toolchangez": float(self.app.defaults["geometry_toolchangez"]),
+ "startz": self.app.defaults["geometry_startz"],
+ "endz": float(self.app.defaults["geometry_endz"])
+ })
+
+ dict_elem = {}
+ dict_elem['name'] = 'new_tool'
+ if type(self.app.defaults["geometry_cnctooldia"]) == float:
+ dict_elem['tooldia'] = self.app.defaults["geometry_cnctooldia"]
+ else:
+ try:
+ tools_string = self.app.defaults["geometry_cnctooldia"].split(",")
+ tools_diameters = [eval(a) for a in tools_string if a != '']
+ dict_elem['tooldia'] = tools_diameters[0] if tools_diameters else 0.0
+ except Exception as e:
+ self.app.log.debug("ToolDB.on_tool_add() --> %s" % str(e))
+ return
+
+ dict_elem['offset'] = 'Path'
+ dict_elem['offset_value'] = 0.0
+ dict_elem['type'] = 'Rough'
+ dict_elem['tool_type'] = 'C1'
+ dict_elem['data'] = default_data
+
+ new_toolid = len(self.db_tool_dict) + 1
+ self.db_tool_dict[new_toolid] = deepcopy(dict_elem)
+
+ # add the new entry to the Tools DB table
+ self.build_db_ui()
+ self.callback_on_edited()
+ self.app.inform.emit('[success] %s' % _("Tool added to DB."))
+
+ def on_tool_copy(self):
+ """
+ Copy a selection of Tools in the Tools DB table
+ :return:
+ """
+ new_tool_id = self.table_widget.rowCount() + 1
+ for model_index in self.table_widget.selectionModel().selectedRows():
+ # index = QtCore.QPersistentModelIndex(model_index)
+ old_tool_id = self.table_widget.item(model_index.row(), 0).text()
+ new_tool_id += 1
+
+ for toolid, dict_val in list(self.db_tool_dict.items()):
+ if int(old_tool_id) == int(toolid):
+ self.db_tool_dict.update({
+ new_tool_id: deepcopy(dict_val)
+ })
+
+ self.build_db_ui()
+ self.callback_on_edited()
+ self.app.inform.emit('[success] %s' % _("Tool copied from Tools DB."))
+
+ def on_tool_delete(self):
+ """
+ Delete a selection of Tools in the Tools DB table
+ :return:
+ """
+ for model_index in self.table_widget.selectionModel().selectedRows():
+ # index = QtCore.QPersistentModelIndex(model_index)
+ toolname_to_remove = self.table_widget.item(model_index.row(), 0).text()
+
+ for toolid, dict_val in list(self.db_tool_dict.items()):
+ if int(toolname_to_remove) == int(toolid):
+ # remove from the storage
+ self.db_tool_dict.pop(toolid, None)
+
+ self.build_db_ui()
+ self.callback_on_edited()
+ self.app.inform.emit('[success] %s' % _("Tool removed from Tools DB."))
+
+ def on_export_tools_db_file(self):
+ self.app.report_usage("on_export_tools_db_file")
+ self.app.log.debug("on_export_tools_db_file()")
+
+ date = str(datetime.today()).rpartition('.')[0]
+ date = ''.join(c for c in date if c not in ':-')
+ date = date.replace(' ', '_')
+
+ filter__ = "Text File (*.TXT);;All Files (*.*)"
+ filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export Tools Database"),
+ directory='{l_save}/FlatCAM_{n}_{date}'.format(
+ l_save=str(self.app.get_last_save_folder()),
+ n=_("Tools_Database"),
+ date=date),
+ filter=filter__)
+
+ filename = str(filename)
+
+ if filename == "":
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("FlatCAM Tools DB export cancelled."))
+ return
+ else:
+ try:
+ f = open(filename, 'w')
+ f.close()
+ except PermissionError:
+ self.app.inform.emit('[WARNING] %s' %
+ _("Permission denied, saving not possible.\n"
+ "Most likely another app is holding the file open and not accessible."))
+ return
+ except IOError:
+ self.app.log.debug('Creating a new Tools DB file ...')
+ f = open(filename, 'w')
+ f.close()
+ except Exception:
+ e = sys.exc_info()[0]
+ self.app.log.error("Could not load Tools DB file.")
+ self.app.log.error(str(e))
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _("Could not load Tools DB file."))
+ return
+
+ # Save update options
+ try:
+ # Save Tools DB in a file
+ try:
+ with open(filename, "w") as f:
+ json.dump(self.db_tool_dict, f, default=to_dict, indent=2)
+ except Exception as e:
+ self.app.log.debug("App.on_save_tools_db() --> %s" % str(e))
+ self.inform.emit('[ERROR_NOTCL] %s' % _("Failed to write Tools DB to file."))
+ return
+ except Exception:
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed to write Tools DB to file."))
+ return
+
+ self.app.inform.emit('[success] %s: %s' % (_("Exported Tools DB to"), filename))
+
+ def on_import_tools_db_file(self):
+ self.app.report_usage("on_import_tools_db_file")
+ self.app.log.debug("on_import_tools_db_file()")
+
+ filter__ = "Text File (*.TXT);;All Files (*.*)"
+ filename, _f = QtWidgets.QFileDialog.getOpenFileName(caption=_("Import FlatCAM Tools DB"), filter=filter__)
+
+ if filename == "":
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("FlatCAM Tools DB import cancelled."))
+ else:
+ try:
+ with open(filename) as f:
+ tools_in_db = f.read()
+ except IOError:
+ self.app.log.error("Could not load Tools DB file.")
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _("Could not load Tools DB file."))
+ return
+
+ try:
+ self.db_tool_dict = json.loads(tools_in_db)
+ except Exception:
+ e = sys.exc_info()[0]
+ self.app.log.error(str(e))
+ self.app.inform.emit('[ERROR] %s' % _("Failed to parse Tools DB file."))
+ return
+
+ self.app.inform.emit('[success] %s: %s' % (_("Loaded FlatCAM Tools DB from"), filename))
+ self.build_db_ui()
+ self.callback_on_edited()
+
+ def on_save_tools_db(self, silent=False):
+ self.app.log.debug("ToolsDB.on_save_button() --> Saving Tools Database to file.")
+
+ filename = self.app.data_path + "/geo_tools_db.FlatDB"
+
+ # Preferences save, update the color of the Tools DB Tab text
+ for idx in range(self.app.ui.plot_tab_area.count()):
+ if self.app.ui.plot_tab_area.tabText(idx) == _("Tools Database"):
+ self.app.ui.plot_tab_area.tabBar.setTabTextColor(idx, QtGui.QColor('black'))
+
+ # Save Tools DB in a file
+ try:
+ f = open(filename, "w")
+ json.dump(self.db_tool_dict, f, default=to_dict, indent=2)
+ f.close()
+ except Exception as e:
+ self.app.log.debug("ToolsDB.on_save_tools_db() --> %s" % str(e))
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed to write Tools DB to file."))
+ return
+
+ if not silent:
+ self.app.inform.emit('[success] %s' % _("Saved Tools DB."))
+
+ def ui_connect(self):
+ try:
+ try:
+ self.table_widget.itemChanged.disconnect(self.callback_on_edited)
+ except (TypeError, AttributeError):
+ pass
+ self.table_widget.itemChanged.connect(self.callback_on_edited)
+ except AttributeError:
+ pass
+
+ for row in range(self.table_widget.rowCount()):
+ for col in range(self.table_widget.columnCount()):
+ # ComboBox
+ try:
+ try:
+ self.table_widget.cellWidget(row, col).currentIndexChanged.disconnect(self.callback_on_edited)
+ except (TypeError, AttributeError):
+ pass
+ self.table_widget.cellWidget(row, col).currentIndexChanged.connect(self.callback_on_edited)
+ except AttributeError:
+ pass
+
+ # CheckBox
+ try:
+ try:
+ self.table_widget.cellWidget(row, col).toggled.disconnect(self.callback_on_edited)
+ except (TypeError, AttributeError):
+ pass
+ self.table_widget.cellWidget(row, col).toggled.connect(self.callback_on_edited)
+ except AttributeError:
+ pass
+
+ # SpinBox, DoubleSpinBox
+ try:
+ try:
+ self.table_widget.cellWidget(row, col).valueChanged.disconnect(self.callback_on_edited)
+ except (TypeError, AttributeError):
+ pass
+ self.table_widget.cellWidget(row, col).valueChanged.connect(self.callback_on_edited)
+ except AttributeError:
+ pass
+
+ def ui_disconnect(self):
+ try:
+ self.table_widget.itemChanged.disconnect(self.callback_on_edited)
+ except (TypeError, AttributeError):
+ pass
+
+ for row in range(self.table_widget.rowCount()):
+ for col in range(self.table_widget.columnCount()):
+ # ComboBox
+ try:
+ self.table_widget.cellWidget(row, col).currentIndexChanged.disconnect(self.callback_on_edited)
+ except (TypeError, AttributeError):
+ pass
+
+ # CheckBox
+ try:
+ self.table_widget.cellWidget(row, col).toggled.disconnect(self.callback_on_edited)
+ except (TypeError, AttributeError):
+ pass
+
+ # SpinBox, DoubleSpinBox
+ try:
+ self.table_widget.cellWidget(row, col).valueChanged.disconnect(self.callback_on_edited)
+ except (TypeError, AttributeError):
+ pass
+
+ def callback_on_edited(self):
+
+ # update the dictionary storage self.db_tool_dict
+ self.db_tool_dict.clear()
+ dict_elem = {}
+ default_data = {}
for row in range(self.table_widget.rowCount()):
new_toolid = row + 1
@@ -1396,7 +2344,7 @@ def color_variant(hex_color, bright_factor=1):
bright_factor = 0.0
rgb_hex = [hex_color[x:x + 2] for x in [1, 3, 5]]
- new_rgb = list()
+ new_rgb = []
for hex_value in rgb_hex:
# adjust each color channel and turn it into a INT suitable as argument for hex()
mod_color = round(int(hex_value, 16) * bright_factor)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 7734e4b5..2c4dcfdc 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -114,7 +114,7 @@ class FlatCAMObj(QtCore.QObject):
else:
self.shapes = ShapeCollectionLegacy(obj=self, app=self.app, name=name)
- self.mark_shapes = dict()
+ self.mark_shapes = {}
self.item = None # Link with project view item
@@ -654,7 +654,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
self.mp = None
# dict to store the polygons selected for isolation; key is the shape added to be plotted and value is the poly
- self.poly_dict = dict()
+ self.poly_dict = {}
# store the status of grid snapping
self.grid_status_memory = None
@@ -1331,7 +1331,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
geo_obj.options["cnctooldia"] = str(self.options["isotooldia"])
geo_obj.tool_type = self.ui.tool_type_radio.get_value().upper()
- geo_obj.solid_geometry = list()
+ geo_obj.solid_geometry = []
# transfer the Cut Z and Vtip and VAngle values in case that we use the V-Shape tool in Gerber UI
if self.ui.tool_type_radio.get_value() == 'v':
@@ -1372,8 +1372,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
"startz": self.app.defaults['geometry_startz']
})
- geo_obj.tools = dict()
- geo_obj.tools['1'] = dict()
+ geo_obj.tools = {}
+ geo_obj.tools['1'] = {}
geo_obj.tools.update({
'1': {
'tooldia': float(self.options["isotooldia"]),
@@ -1520,8 +1520,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
"startz": self.app.defaults['geometry_startz']
})
- geo_obj.tools = dict()
- geo_obj.tools['1'] = dict()
+ geo_obj.tools = {}
+ geo_obj.tools['1'] = {}
geo_obj.tools.update({
'1': {
'tooldia': float(self.options["isotooldia"]),
@@ -2416,15 +2416,15 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
})
# TODO: Document this.
- self.tool_cbs = dict()
+ self.tool_cbs = {}
# dict that holds the object names and the option name
# the key is the object name (defines in ObjectUI) for each UI element that is a parameter
# particular for a tool and the value is the actual name of the option that the UI element is changing
- self.name2option = dict()
+ self.name2option = {}
# default set of data to be added to each tool in self.tools as self.tools[tool]['data'] = self.default_data
- self.default_data = dict()
+ self.default_data = {}
# fill in self.default_data values from self.options
for opt_key, opt_val in self.app.options.items():
@@ -2629,7 +2629,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
)
# delete the exc_final tools, drills and slots
- exc_final.tools = dict()
+ exc_final.tools = {}
exc_final.drills[:] = []
exc_final.slots[:] = []
@@ -2669,7 +2669,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
sorted_tools = sorted(sort, key=lambda t1: t1[1])
tools = [i[0] for i in sorted_tools]
- new_options = dict()
+ new_options = {}
for opt in self.options:
new_options[opt] = self.options[opt]
@@ -3046,7 +3046,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
def on_row_selection_change(self):
self.ui_disconnect()
- sel_rows = list()
+ sel_rows = []
sel_items = self.ui.tools_table.selectedItems()
for it in sel_items:
sel_rows.append(it.row())
@@ -3181,7 +3181,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
# from the columnCount we subtract a value of 1 which represent the last column (plot column)
# which does not have text
txt = ''
- elem = list()
+ elem = []
for column in range(0, self.ui.tools_table.columnCount() - 1):
try:
@@ -3940,7 +3940,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
row = 0
tooluid_item = int(self.ui.tools_table.item(row, 0).text())
- temp_tool_data = dict()
+ temp_tool_data = {}
for tooluid_key, tooluid_val in self.tools.items():
if int(tooluid_key) == tooluid_item:
@@ -4220,7 +4220,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.e_cut_entry.setDisabled(True)
# set the text on tool_data_label after loading the object
- sel_rows = list()
+ sel_rows = []
sel_items = self.ui.geo_tools_table.selectedItems()
for it in sel_items:
sel_rows.append(it.row())
@@ -4285,7 +4285,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.cutz_entry.setDisabled(False)
# store here the default data for Geometry Data
- self.default_data = dict()
+ self.default_data = {}
self.default_data.update({
"name": None,
"plot": None,
@@ -4603,7 +4603,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui_disconnect()
if row is None:
- sel_rows = list()
+ sel_rows = []
sel_items = self.ui.geo_tools_table.selectedItems()
for it in sel_items:
sel_rows.append(it.row())
@@ -4684,7 +4684,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
tooldia = float(self.ui.addtool_entry.get_value())
# construct a list of all 'tooluid' in the self.tools
- # tool_uid_list = list()
+ # tool_uid_list = []
# for tooluid_key in self.tools:
# tool_uid_list.append(int(tooluid_key))
tool_uid_list = [int(tooluid_key) for tooluid_key in self.tools]
@@ -5329,7 +5329,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
table_tools_items = []
if self.multigeo:
for x in self.ui.geo_tools_table.selectedItems():
- elem = list()
+ elem = []
txt = ''
for column in range(0, self.ui.geo_tools_table.columnCount()):
@@ -5482,7 +5482,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# this reads the values in the UI form to the self.options dictionary
self.read_form()
- self.sel_tools = dict()
+ self.sel_tools = {}
try:
if self.special_group:
@@ -5588,7 +5588,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# count the tools
tool_cnt = 0
- dia_cnc_dict = dict()
+ dia_cnc_dict = {}
# this turn on the FlatCAMCNCJob plot for multiple tools
job_obj.multitool = True
@@ -5731,7 +5731,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# count the tools
tool_cnt = 0
- dia_cnc_dict = dict()
+ dia_cnc_dict = {}
# this turn on the FlatCAMCNCJob plot for multiple tools
job_obj.multitool = True
@@ -6065,7 +6065,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
def scale_recursion(geom):
if type(geom) is list:
- geoms = list()
+ geoms = []
for local_geom in geom:
geoms.append(scale_recursion(local_geom))
return geoms
@@ -6142,7 +6142,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
def translate_recursion(geom):
if type(geom) is list:
- geoms = list()
+ geoms = []
for local_geom in geom:
geoms.append(translate_recursion(local_geom))
return geoms
@@ -6419,16 +6419,16 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
"""
if geo_final.solid_geometry is None:
- geo_final.solid_geometry = list()
+ geo_final.solid_geometry = []
try:
__ = iter(geo_final.solid_geometry)
except TypeError:
geo_final.solid_geometry = [geo_final.solid_geometry]
- new_solid_geometry = list()
- new_options = dict()
- new_tools = dict()
+ new_solid_geometry = []
+ new_options = {}
+ new_tools = {}
for geo_obj in geo_list:
for option in geo_obj.options:
@@ -6564,7 +6564,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
It is populated in the FlatCAMGeometry.mtool_gen_cncjob()
BEWARE: I rely on the ordered nature of the Python 3.7 dictionary. Things might change ...
'''
- self.cnc_tools = dict()
+ self.cnc_tools = {}
'''
This is a dict of dictionaries. Each dict is associated with a tool present in the file. The key is the
@@ -6585,7 +6585,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
it's done in camlib.CNCJob.generate_from_excellon_by_tool()
BEWARE: I rely on the ordered nature of the Python 3.7 dictionary. Things might change ...
'''
- self.exc_cnc_tools = dict()
+ self.exc_cnc_tools = {}
# flag to store if the CNCJob is part of a special group of CNCJob objects that can't be processed by the
# default engine of FlatCAM. They generated by some of tools and are special cases of CNCJob objects.
diff --git a/README.md b/README.md
index 9d3bab8c..3ebe0a9e 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- compacted the NCC Tool UI by replacing some Radio buttons with Combo boxes due of too many elements
- fixed error in CutOut Tool when trying to create a FreeFrom Cutout out of a Gerber object with the Convex Shape checked
+- working on a new type of database
28.02.2020
diff --git a/camlib.py b/camlib.py
index a1ca1375..88a62488 100644
--- a/camlib.py
+++ b/camlib.py
@@ -917,7 +917,7 @@ class Geometry(object):
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
- geo_iso = list()
+ geo_iso = []
if follow:
return geometry
@@ -1016,7 +1016,7 @@ class Geometry(object):
# Add to object
if self.solid_geometry is None:
- self.solid_geometry = list()
+ self.solid_geometry = []
if type(self.solid_geometry) is list:
if type(geos) is list:
@@ -1031,7 +1031,7 @@ class Geometry(object):
geos_text = getsvgtext(svg_root, object_type, units=units)
if geos_text is not None:
- geos_text_f = list()
+ geos_text_f = []
if flip:
# Change origin to bottom left
for i in geos_text:
@@ -1100,8 +1100,8 @@ class Geometry(object):
scale_factor = 25.4 / dpi if units.lower() == 'mm' else 1 / dpi
- geos = list()
- unscaled_geos = list()
+ geos = []
+ unscaled_geos = []
with rasterio.open(filename) as src:
# if filename.lower().rpartition('.')[-1] == 'bmp':
@@ -1148,7 +1148,7 @@ class Geometry(object):
# Add to object
if self.solid_geometry is None:
- self.solid_geometry = list()
+ self.solid_geometry = []
if type(self.solid_geometry) is list:
# self.solid_geometry.append(cascaded_union(geos))
@@ -2694,7 +2694,7 @@ class CNCjob(Geometry):
# running this method from a Tcl Command
build_tools_in_use_list = False
if 'Tools_in_use' not in self.options:
- self.options['Tools_in_use'] = list()
+ self.options['Tools_in_use'] = []
# if the list is empty (either we just added the key or it was already there but empty) signal to build it
if not self.options['Tools_in_use']:
@@ -2705,7 +2705,7 @@ class CNCjob(Geometry):
for to_ol in tools:
if to_ol == it[0]:
drill_no = 0
- sol_geo = list()
+ sol_geo = []
for dr in exobj.drills:
if dr['tool'] == it[0]:
drill_no += 1
@@ -2725,11 +2725,11 @@ class CNCjob(Geometry):
except KeyError:
z_off = 0
- default_data = dict()
+ default_data = {}
for k, v in list(self.options.items()):
default_data[k] = deepcopy(v)
- self.exc_cnc_tools[it[1]] = dict()
+ self.exc_cnc_tools[it[1]] = {}
self.exc_cnc_tools[it[1]]['tool'] = it[0]
self.exc_cnc_tools[it[1]]['nr_drills'] = drill_no
self.exc_cnc_tools[it[1]]['nr_slots'] = slot_no
@@ -2747,7 +2747,7 @@ class CNCjob(Geometry):
self.app.inform.emit(_("Creating a list of points to drill..."))
# Points (Group by tool)
- points = dict()
+ points = {}
for drill in exobj.drills:
if self.app.abort_flag:
# graceful abort requested by the user
@@ -2761,7 +2761,7 @@ class CNCjob(Geometry):
# log.debug("Found %d drills." % len(points))
- self.gcode = list()
+ self.gcode = []
self.f_plunge = self.app.defaults["excellon_f_plunge"]
self.f_retract = self.app.defaults["excellon_f_retract"]
@@ -2786,7 +2786,7 @@ class CNCjob(Geometry):
def __init__(self, tool):
"""Initialize distance array."""
locations = create_data_array(tool)
- self.matrix = dict()
+ self.matrix = {}
if locations:
size = len(locations)
@@ -2813,7 +2813,7 @@ class CNCjob(Geometry):
# Create the data.
def create_data_array(tool):
- loc_list = list()
+ loc_list = []
if tool not in points:
return None
@@ -3820,7 +3820,7 @@ class CNCjob(Geometry):
'[ERROR_NOTCL] %s' % _("Trying to generate a CNC Job from a Geometry object without solid_geometry.")
)
- temp_solid_geometry = list()
+ temp_solid_geometry = []
def bounds_rec(obj):
if type(obj) is list:
@@ -4725,8 +4725,8 @@ class CNCjob(Geometry):
if geo['kind'][0] == 'C':
obj.add_shape(shape=geo['geom'], color=color['C'][1], visible=visible)
else:
- text = list()
- pos = list()
+ text = []
+ pos = []
self.coordinates_type = self.app.defaults["cncjob_coords_type"]
if self.coordinates_type == "G90":
# For Absolute coordinates type G90
@@ -6156,7 +6156,7 @@ def dict2obj(d):
# cells[pIdx].append((startIdx, endIdx))
#
# # then, form polygons by storing vertex indices in (counter-)clockwise order
-# polys = dict()
+# polys = {}
# for pIdx, lineIndices_ in cells.items():
# # get a directed graph which contains both directions and arbitrarily follow one of both
# directedGraph = lineIndices_ + [(i2, i1) for (i1, i2) in lineIndices_]
diff --git a/flatcamEditors/FlatCAMExcEditor.py b/flatcamEditors/FlatCAMExcEditor.py
index 1be311ba..b53c0006 100644
--- a/flatcamEditors/FlatCAMExcEditor.py
+++ b/flatcamEditors/FlatCAMExcEditor.py
@@ -124,7 +124,7 @@ class FCDrillAdd(FCShapeTool):
self.draw_app.app.jump_signal.disconnect()
def clean_up(self):
- self.draw_app.selected = list()
+ self.draw_app.selected = []
self.draw_app.tools_table_exc.clearSelection()
self.draw_app.plot_all()
@@ -359,7 +359,7 @@ class FCDrillArray(FCShapeTool):
self.draw_app.app.jump_signal.disconnect()
def clean_up(self):
- self.draw_app.selected = list()
+ self.draw_app.selected = []
self.draw_app.tools_table_exc.clearSelection()
self.draw_app.plot_all()
@@ -562,7 +562,7 @@ class FCSlot(FCShapeTool):
self.draw_app.app.jump_signal.disconnect()
def clean_up(self):
- self.draw_app.selected = list()
+ self.draw_app.selected = []
self.draw_app.tools_table_exc.clearSelection()
self.draw_app.plot_all()
@@ -888,7 +888,7 @@ class FCSlotArray(FCShapeTool):
self.draw_app.app.jump_signal.disconnect()
def clean_up(self):
- self.draw_app.selected = list()
+ self.draw_app.selected = []
self.draw_app.tools_table_exc.clearSelection()
self.draw_app.plot_all()
@@ -1128,7 +1128,7 @@ class FCDrillResize(FCShapeTool):
self.draw_app.select_tool("drill_select")
def clean_up(self):
- self.draw_app.selected = list()
+ self.draw_app.selected = []
self.draw_app.tools_table_exc.clearSelection()
self.draw_app.plot_all()
@@ -1268,7 +1268,7 @@ class FCDrillMove(FCShapeTool):
return DrawToolUtilityShape(ss_el)
def clean_up(self):
- self.draw_app.selected = list()
+ self.draw_app.selected = []
self.draw_app.tools_table_exc.clearSelection()
self.draw_app.plot_all()
@@ -1323,7 +1323,7 @@ class FCDrillCopy(FCDrillMove):
self.draw_app.app.jump_signal.disconnect()
def clean_up(self):
- self.draw_app.selected = list()
+ self.draw_app.selected = []
self.draw_app.tools_table_exc.clearSelection()
self.draw_app.plot_all()
@@ -1371,7 +1371,7 @@ class FCDrillSelect(DrawTool):
if mod_key == self.exc_editor_app.app.defaults["global_mselect_key"]:
pass
else:
- self.exc_editor_app.selected = list()
+ self.exc_editor_app.selected = []
def click_release(self, pos):
self.exc_editor_app.tools_table_exc.clearSelection()
@@ -1425,7 +1425,7 @@ class FCDrillSelect(DrawTool):
else:
self.exc_editor_app.selected.append(closest_shape)
else:
- self.exc_editor_app.selected = list()
+ self.exc_editor_app.selected = []
self.exc_editor_app.selected.append(closest_shape)
# select the diameter of the selected shape in the tool table
@@ -2060,31 +2060,31 @@ class FlatCAMExcEditor(QtCore.QObject):
self.in_action = False
- self.storage_dict = dict()
+ self.storage_dict = {}
- self.current_storage = list()
+ self.current_storage = []
# build the data from the Excellon point into a dictionary
# {tool_dia: [geometry_in_points]}
- self.points_edit = dict()
- self.slot_points_edit = dict()
+ self.points_edit = {}
+ self.slot_points_edit = {}
- self.sorted_diameters = list()
+ self.sorted_diameters = []
- self.new_drills = list()
- self.new_tools = dict()
- self.new_slots = list()
+ self.new_drills = []
+ self.new_tools = {}
+ self.new_slots = []
# dictionary to store the tool_row and diameters in Tool_table
# it will be updated everytime self.build_ui() is called
- self.olddia_newdia = dict()
+ self.olddia_newdia = {}
- self.tool2tooldia = dict()
+ self.tool2tooldia = {}
# this will store the value for the last selected tool, for use after clicking on canvas when the selection
# is cleared but as a side effect also the selected tool is cleared
self.last_tool_selected = None
- self.utility = list()
+ self.utility = []
# this will flag if the Editor "tools" are launched from key shortcuts (True) or from menu toolbar (False)
self.launched_from_shortcuts = False
@@ -3069,8 +3069,8 @@ class FlatCAMExcEditor(QtCore.QObject):
self.exc_obj = exc_obj
exc_obj.visible = False
- self.points_edit = dict()
- self.slot_points_edit = dict()
+ self.points_edit = {}
+ self.slot_points_edit = {}
# Set selection tolerance
# DrawToolShape.tolerance = fc_excellon.drawing_tolerance * 10
@@ -3353,7 +3353,7 @@ class FlatCAMExcEditor(QtCore.QObject):
# add a 'data' dict for each tool with the default values
for tool in excellon_obj.tools:
- excellon_obj.tools[tool]['data'] = dict()
+ excellon_obj.tools[tool]['data'] = {}
excellon_obj.tools[tool]['data'].update(deepcopy(self.data_defaults))
try:
diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py
index 17027775..a1a13b9b 100644
--- a/flatcamEditors/FlatCAMGeoEditor.py
+++ b/flatcamEditors/FlatCAMGeoEditor.py
@@ -1755,7 +1755,7 @@ class DrawToolShape(object):
def translate_recursion(geom):
if type(geom) == list:
- geoms = list()
+ geoms = []
for local_geom in geom:
geoms.append(translate_recursion(local_geom))
return geoms
@@ -1802,7 +1802,7 @@ class DrawToolShape(object):
def scale_recursion(geom):
if type(geom) == list:
- geoms = list()
+ geoms = []
for local_geom in geom:
geoms.append(scale_recursion(local_geom))
return geoms
@@ -1972,7 +1972,7 @@ class FCCircle(FCShapeTool):
self.draw_app.app.inform.emit('[success] %s' % _("Done. Adding Circle completed."))
def clean_up(self):
- self.draw_app.selected = list()
+ self.draw_app.selected = []
self.draw_app.plot_all()
try:
@@ -2212,7 +2212,7 @@ class FCArc(FCShapeTool):
self.draw_app.app.inform.emit('[success] %s' % _("Done. Arc completed."))
def clean_up(self):
- self.draw_app.selected = list()
+ self.draw_app.selected = []
self.draw_app.plot_all()
try:
@@ -2285,7 +2285,7 @@ class FCRectangle(FCShapeTool):
self.draw_app.app.inform.emit('[success] %s' % _("Done. Rectangle completed."))
def clean_up(self):
- self.draw_app.selected = list()
+ self.draw_app.selected = []
self.draw_app.plot_all()
try:
@@ -2374,7 +2374,7 @@ class FCPolygon(FCShapeTool):
return _("Backtracked one point ...")
def clean_up(self):
- self.draw_app.selected = list()
+ self.draw_app.selected = []
self.draw_app.plot_all()
try:
@@ -2439,7 +2439,7 @@ class FCPath(FCPolygon):
return _("Backtracked one point ...")
def clean_up(self):
- self.draw_app.selected = list()
+ self.draw_app.selected = []
self.draw_app.plot_all()
try:
@@ -2573,8 +2573,8 @@ class FCExplode(FCShapeTool):
self.make()
def make(self):
- to_be_deleted_list = list()
- lines = list()
+ to_be_deleted_list = []
+ lines = []
for shape in self.draw_app.get_selected():
to_be_deleted_list.append(shape)
@@ -2596,7 +2596,7 @@ class FCExplode(FCShapeTool):
if shape in self.draw_app.selected:
self.draw_app.selected.remove(shape)
- geo_list = list()
+ geo_list = []
for line in lines:
geo_list.append(DrawToolShape(line))
self.geometry = geo_list
@@ -2604,7 +2604,7 @@ class FCExplode(FCShapeTool):
self.draw_app.app.inform.emit('[success] %s...' % _("Done. Polygons exploded into lines."))
def clean_up(self):
- self.draw_app.selected = list()
+ self.draw_app.selected = []
self.draw_app.plot_all()
try:
@@ -2793,7 +2793,7 @@ class FCMove(FCShapeTool):
raise
def clean_up(self):
- self.draw_app.selected = list()
+ self.draw_app.selected = []
self.draw_app.plot_all()
try:
@@ -2821,7 +2821,7 @@ class FCCopy(FCMove):
pass
def clean_up(self):
- self.draw_app.selected = list()
+ self.draw_app.selected = []
self.draw_app.plot_all()
try:
@@ -2906,7 +2906,7 @@ class FCText(FCShapeTool):
return
def clean_up(self):
- self.draw_app.selected = list()
+ self.draw_app.selected = []
self.draw_app.plot_all()
try:
@@ -3043,7 +3043,7 @@ class FCBuffer(FCShapeTool):
pass
def clean_up(self):
- self.draw_app.selected = list()
+ self.draw_app.selected = []
self.draw_app.plot_all()
try:
@@ -3165,7 +3165,7 @@ class FCEraser(FCShapeTool):
return DrawToolUtilityShape(geo_list)
def clean_up(self):
- self.draw_app.selected = list()
+ self.draw_app.selected = []
self.draw_app.plot_all()
try:
@@ -3484,7 +3484,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
# pass
iterator = QtWidgets.QTreeWidgetItemIterator(self.geo_parent)
- to_delete = list()
+ to_delete = []
while iterator.value():
item = iterator.value()
to_delete.append(item)
@@ -3521,7 +3521,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
pass
def on_tree_selection_change(self):
- self.selected = list()
+ self.selected = []
selected_tree_items = self.tw.selectedItems()
for sel in selected_tree_items:
for obj_shape in self.storage.get_objects():
@@ -4528,7 +4528,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
log.debug("FlatCAMGeoEditor.on_shape_complete() Error --> %s" % str(e))
return 'fail'
- shape_list = list()
+ shape_list = []
try:
for geo in geom:
shape_list.append(DrawToolShape(geo))
diff --git a/flatcamEditors/FlatCAMGrbEditor.py b/flatcamEditors/FlatCAMGrbEditor.py
index c10c98a1..73fc0afa 100644
--- a/flatcamEditors/FlatCAMGrbEditor.py
+++ b/flatcamEditors/FlatCAMGrbEditor.py
@@ -288,14 +288,14 @@ class FCPad(FCShapeTool):
ap_type = self.draw_app.storage_dict[self.draw_app.last_aperture_selected]['type']
if ap_type == 'C':
- new_geo_el = dict()
+ new_geo_el = {}
center = Point([point_x, point_y])
new_geo_el['solid'] = center.buffer(self.radius)
new_geo_el['follow'] = center
return new_geo_el
elif ap_type == 'R':
- new_geo_el = dict()
+ new_geo_el = {}
p1 = (point_x - self.half_width, point_y - self.half_height)
p2 = (point_x + self.half_width, point_y - self.half_height)
@@ -307,7 +307,7 @@ class FCPad(FCShapeTool):
return new_geo_el
elif ap_type == 'O':
geo = []
- new_geo_el = dict()
+ new_geo_el = {}
if self.half_height > self.half_width:
p1 = (point_x - self.half_width, point_y - self.half_height + self.half_width)
@@ -545,7 +545,7 @@ class FCPadArray(FCShapeTool):
)
if static is None or static is False:
- new_geo_el = dict()
+ new_geo_el = {}
if 'solid' in geo_el:
new_geo_el['solid'] = affinity.translate(
@@ -602,14 +602,14 @@ class FCPadArray(FCShapeTool):
ap_type = self.draw_app.storage_dict[self.draw_app.last_aperture_selected]['type']
if ap_type == 'C':
- new_geo_el = dict()
+ new_geo_el = {}
center = Point([point_x, point_y])
new_geo_el['solid'] = center.buffer(self.radius)
new_geo_el['follow'] = center
return new_geo_el
elif ap_type == 'R':
- new_geo_el = dict()
+ new_geo_el = {}
p1 = (point_x - self.half_width, point_y - self.half_height)
p2 = (point_x + self.half_width, point_y - self.half_height)
@@ -620,7 +620,7 @@ class FCPadArray(FCShapeTool):
return new_geo_el
elif ap_type == 'O':
geo = []
- new_geo_el = dict()
+ new_geo_el = {}
if self.half_height > self.half_width:
p1 = (point_x - self.half_width, point_y - self.half_height + self.half_width)
@@ -812,7 +812,7 @@ class FCPoligonize(FCShapeTool):
except KeyError:
self.draw_app.on_aperture_add(apid='0')
current_storage = self.draw_app.storage_dict['0']['geometry']
- new_el = dict()
+ new_el = {}
new_el['solid'] = geo
new_el['follow'] = geo.exterior
self.draw_app.on_grb_shape_complete(current_storage, specific_shape=DrawToolShape(deepcopy(new_el)))
@@ -827,7 +827,7 @@ class FCPoligonize(FCShapeTool):
self.draw_app.on_aperture_add(apid='0')
current_storage = self.draw_app.storage_dict['0']['geometry']
- new_el = dict()
+ new_el = {}
new_el['solid'] = fused_geo
new_el['follow'] = fused_geo.exterior
self.draw_app.on_grb_shape_complete(current_storage, specific_shape=DrawToolShape(deepcopy(new_el)))
@@ -915,7 +915,7 @@ class FCRegion(FCShapeTool):
self.gridy_size = float(self.draw_app.app.ui.grid_gap_y_entry.get_value())
def utility_geometry(self, data=None):
- new_geo_el = dict()
+ new_geo_el = {}
x = data[0]
y = data[1]
@@ -983,7 +983,7 @@ class FCRegion(FCShapeTool):
self.inter_point = data
self.temp_points.append(data)
- new_geo_el = dict()
+ new_geo_el = {}
if len(self.temp_points) > 1:
try:
@@ -1049,7 +1049,7 @@ class FCRegion(FCShapeTool):
self.temp_points.append(self.inter_point)
self.temp_points.append(data)
- new_geo_el = dict()
+ new_geo_el = {}
new_geo_el['solid'] = LinearRing(self.temp_points).buffer(self.buf_val,
resolution=int(self.steps_per_circle / 4),
@@ -1070,7 +1070,7 @@ class FCRegion(FCShapeTool):
else:
self.draw_app.last_aperture_selected = '0'
- new_geo_el = dict()
+ new_geo_el = {}
new_geo_el['solid'] = Polygon(self.points).buffer(self.buf_val,
resolution=int(self.steps_per_circle / 4),
@@ -1183,7 +1183,7 @@ class FCTrack(FCRegion):
self.draw_app.app.inform.emit(_('Track Mode 1: 45 degrees ...'))
def make(self):
- new_geo_el = dict()
+ new_geo_el = {}
if len(self.temp_points) == 1:
new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val,
resolution=int(self.steps_per_circle / 4))
@@ -1219,7 +1219,7 @@ class FCTrack(FCRegion):
except IndexError:
self.points.append(point)
- new_geo_el = dict()
+ new_geo_el = {}
if len(self.temp_points) == 1:
new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val,
@@ -1242,7 +1242,7 @@ class FCTrack(FCRegion):
def utility_geometry(self, data=None):
self.update_grid_info()
- new_geo_el = dict()
+ new_geo_el = {}
if len(self.points) == 0:
new_geo_el['solid'] = Point(data).buffer(self.buf_val,
@@ -1427,10 +1427,10 @@ class FCDisc(FCShapeTool):
if '0' in self.draw_app.storage_dict:
self.storage_obj = self.draw_app.storage_dict['0']['geometry']
else:
- self.draw_app.storage_dict['0'] = dict()
+ self.draw_app.storage_dict['0'] = {}
self.draw_app.storage_dict['0']['type'] = 'C'
self.draw_app.storage_dict['0']['size'] = 0.0
- self.draw_app.storage_dict['0']['geometry'] = list()
+ self.draw_app.storage_dict['0']['geometry'] = []
self.storage_obj = self.draw_app.storage_dict['0']['geometry']
self.draw_app.app.inform.emit(_("Click on Center point ..."))
@@ -1453,7 +1453,7 @@ class FCDisc(FCShapeTool):
return ""
def utility_geometry(self, data=None):
- new_geo_el = dict()
+ new_geo_el = {}
if len(self.points) == 1:
p1 = self.points[0]
p2 = data
@@ -1464,7 +1464,7 @@ class FCDisc(FCShapeTool):
return None
def make(self):
- new_geo_el = dict()
+ new_geo_el = {}
try:
QtGui.QGuiApplication.restoreOverrideCursor()
@@ -1530,10 +1530,10 @@ class FCSemiDisc(FCShapeTool):
if '0' in self.draw_app.storage_dict:
self.storage_obj = self.draw_app.storage_dict['0']['geometry']
else:
- self.draw_app.storage_dict['0'] = dict()
+ self.draw_app.storage_dict['0'] = {}
self.draw_app.storage_dict['0']['type'] = 'C'
self.draw_app.storage_dict['0']['size'] = 0.0
- self.draw_app.storage_dict['0']['geometry'] = list()
+ self.draw_app.storage_dict['0']['geometry'] = []
self.storage_obj = self.draw_app.storage_dict['0']['geometry']
self.steps_per_circ = self.draw_app.app.defaults["gerber_circle_steps"]
@@ -1592,10 +1592,10 @@ class FCSemiDisc(FCShapeTool):
return _('Mode: Center -> Start -> Stop. Click on Center point ...')
def utility_geometry(self, data=None):
- new_geo_el = dict()
- new_geo_el_pt1 = dict()
- new_geo_el_pt2 = dict()
- new_geo_el_pt3 = dict()
+ new_geo_el = {}
+ new_geo_el_pt1 = {}
+ new_geo_el_pt2 = {}
+ new_geo_el_pt3 = {}
if len(self.points) == 1: # Show the radius
center = self.points[0]
@@ -1681,7 +1681,7 @@ class FCSemiDisc(FCShapeTool):
def make(self):
self.draw_app.current_storage = self.storage_obj
- new_geo_el = dict()
+ new_geo_el = {}
if self.mode == 'c12':
center = self.points[0]
@@ -2031,7 +2031,7 @@ class FCApertureMove(FCShapeTool):
for select_shape in self.draw_app.get_selected():
if select_shape in self.current_storage:
geometric_data = select_shape.geo
- new_geo_el = dict()
+ new_geo_el = {}
if 'solid' in geometric_data:
new_geo_el['solid'] = affinity.translate(geometric_data['solid'], xoff=dx, yoff=dy)
if 'follow' in geometric_data:
@@ -2084,7 +2084,7 @@ class FCApertureMove(FCShapeTool):
if len(self.draw_app.get_selected()) <= self.sel_limit:
for geom in self.draw_app.get_selected():
- new_geo_el = dict()
+ new_geo_el = {}
if 'solid' in geom.geo:
new_geo_el['solid'] = affinity.translate(geom.geo['solid'], xoff=dx, yoff=dy)
if 'follow' in geom.geo:
@@ -2094,7 +2094,7 @@ class FCApertureMove(FCShapeTool):
geo_list.append(deepcopy(new_geo_el))
return DrawToolUtilityShape(geo_list)
else:
- ss_el = dict()
+ ss_el = {}
ss_el['solid'] = affinity.translate(self.selection_shape, xoff=dx, yoff=dy)
return DrawToolUtilityShape(ss_el)
@@ -2115,7 +2115,7 @@ class FCApertureCopy(FCApertureMove):
for select_shape in self.draw_app.get_selected():
if select_shape in self.current_storage:
geometric_data = select_shape.geo
- new_geo_el = dict()
+ new_geo_el = {}
if 'solid' in geometric_data:
new_geo_el['solid'] = affinity.translate(geometric_data['solid'], xoff=dx, yoff=dy)
if 'follow' in geometric_data:
@@ -2274,7 +2274,7 @@ class FCEraser(FCShapeTool):
dy = data[1] - self.origin[1]
for geom in self.draw_app.get_selected():
- new_geo_el = dict()
+ new_geo_el = {}
if 'solid' in geom.geo:
new_geo_el['solid'] = affinity.translate(geom.geo['solid'], xoff=dx, yoff=dy)
if 'follow' in geom.geo:
@@ -2303,7 +2303,7 @@ class FCApertureSelect(DrawTool):
self.grb_editor_app.bend_mode = 1
# here store the selected apertures
- self.sel_aperture = list()
+ self.sel_aperture = []
try:
self.grb_editor_app.apertures_table.clearSelection()
@@ -2922,30 +2922,30 @@ class FlatCAMGrbEditor(QtCore.QObject):
# # ## Data
self.active_tool = None
- self.storage_dict = dict()
- self.current_storage = list()
+ self.storage_dict = {}
+ self.current_storage = []
- self.sorted_apid = list()
+ self.sorted_apid = []
- self.new_apertures = dict()
- self.new_aperture_macros = dict()
+ self.new_apertures = {}
+ self.new_aperture_macros = {}
# store here the plot promises, if empty the delayed plot will be activated
- self.grb_plot_promises = list()
+ self.grb_plot_promises = []
# dictionary to store the tool_row and aperture codes in Tool_table
# it will be updated everytime self.build_ui() is called
- self.olddia_newdia = dict()
+ self.olddia_newdia = {}
- self.tool2tooldia = dict()
+ self.tool2tooldia = {}
# this will store the value for the last selected tool, for use after clicking on canvas when the selection
# is cleared but as a side effect also the selected tool is cleared
self.last_aperture_selected = None
- self.utility = list()
+ self.utility = []
# this will store the polygons marked by mark are to be perhaps deleted
- self.geo_to_delete = list()
+ self.geo_to_delete = []
# this will flag if the Editor "tools" are launched from key shortcuts (True) or from menu toolbar (False)
self.launched_from_shortcuts = False
@@ -2957,7 +2957,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.apdim_lbl.hide()
self.apdim_entry.hide()
self.gerber_obj = None
- self.gerber_obj_options = dict()
+ self.gerber_obj_options = {}
# VisPy Visuals
if self.app.is_legacy is False:
@@ -3040,7 +3040,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.pool = self.app.pool
# Multiprocessing results
- self.results = list()
+ self.results = []
# A QTimer
self.plot_thread = None
@@ -3434,7 +3434,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
# I've added this flag_del variable because dictionary don't like
# having keys deleted while iterating through them
- flag_del = list()
+ flag_del = []
for deleted_tool in self.tool2tooldia:
if self.tool2tooldia[deleted_tool] == deleted_aperture:
flag_del.append(deleted_tool)
@@ -3504,7 +3504,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
geometry = []
for geo_el in self.storage_dict[dia_changed]:
geometric_data = geo_el.geo
- new_geo_el = dict()
+ new_geo_el = {}
if 'solid' in geometric_data:
new_geo_el['solid'] = deepcopy(affinity.scale(geometric_data['solid'],
xfact=factor, yfact=factor))
@@ -3950,7 +3950,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
# ############################################################# ##
# list of clear geos that are to be applied to the entire file
- global_clear_geo = list()
+ global_clear_geo = []
# create one big geometry made out of all 'negative' (clear) polygons
for apid in app_obj.gerber_obj.apertures:
@@ -3969,7 +3969,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
# we subtract the big "negative" (clear) geometry from each solid polygon but only the part of
# clear geometry that fits inside the solid. otherwise we may loose the solid
for apid in app_obj.gerber_obj.apertures:
- temp_solid_geometry = list()
+ temp_solid_geometry = []
if 'geometry' in app_obj.gerber_obj.apertures[apid]:
# for elem in self.gerber_obj.apertures[apid]['geometry']:
# if 'solid' in elem:
@@ -3982,7 +3982,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
# solid_geo = solid_geo.difference(clear_geo)
# try:
# for poly in solid_geo:
- # new_elem = dict()
+ # new_elem = {}
#
# new_elem['solid'] = poly
# if 'clear' in elem:
@@ -3991,7 +3991,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
# new_elem['follow'] = poly
# temp_elem.append(deepcopy(new_elem))
# except TypeError:
- # new_elem = dict()
+ # new_elem = {}
# new_elem['solid'] = solid_geo
# if 'clear' in elem:
# new_elem['clear'] = solid_geo
@@ -3999,7 +3999,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
# new_elem['follow'] = solid_geo
# temp_elem.append(deepcopy(new_elem))
for elem in app_obj.gerber_obj.apertures[apid]['geometry']:
- new_elem = dict()
+ new_elem = {}
if 'solid' in elem:
solid_geo = elem['solid']
if not global_clear_geo or global_clear_geo.is_empty:
@@ -4033,7 +4033,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
"FlatCAMGrbEditor.edit_fcgerber.worker_job() Adding processes to pool --> %s" % str(e))
traceback.print_exc()
- output = list()
+ output = []
for p in app_obj.results:
output.append(p.get())
@@ -4053,8 +4053,8 @@ class FlatCAMGrbEditor(QtCore.QObject):
@staticmethod
def add_apertures(aperture_id, aperture_dict):
- storage_elem = list()
- storage_dict = dict()
+ storage_elem = []
+ storage_dict = {}
for k, v in list(aperture_dict.items()):
try:
@@ -4113,7 +4113,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
def update_options(obj):
try:
if not obj.options:
- obj.options = dict()
+ obj.options = {}
obj.options['xmin'] = 0
obj.options['ymin'] = 0
obj.options['xmax'] = 0
@@ -4122,7 +4122,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
else:
return False
except AttributeError:
- obj.options = dict()
+ obj.options = {}
return True
def new_edited_gerber(self, outname, aperture_storage):
@@ -4141,7 +4141,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
out_name = outname
storage_dict = aperture_storage
- local_storage_dict = dict()
+ local_storage_dict = {}
for aperture in storage_dict:
if 'geometry' in storage_dict[aperture]:
# add aperture only if it has geometry
@@ -4162,7 +4162,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
grb_obj.apertures[storage_apid][k] = []
for geo_el in val:
geometric_data = geo_el.geo
- new_geo_el = dict()
+ new_geo_el = {}
if 'solid' in geometric_data:
new_geo_el['solid'] = geometric_data['solid']
poly_buffer.append(deepcopy(new_geo_el['solid']))
@@ -4237,12 +4237,12 @@ class FlatCAMGrbEditor(QtCore.QObject):
except Exception as e:
log.error("Error on Edited object creation: %s" % str(e))
# make sure to clean the previous results
- self.results = list()
+ self.results = []
return
self.app.inform.emit('[success] %s' % _("Done. Gerber editing finished."))
# make sure to clean the previous results
- self.results = list()
+ self.results = []
def on_tool_select(self, tool):
"""
@@ -4952,14 +4952,14 @@ class FlatCAMGrbEditor(QtCore.QObject):
def buffer_recursion(geom_el, selection):
if type(geom_el) == list:
- geoms = list()
+ geoms = []
for local_geom in geom_el:
geoms.append(buffer_recursion(local_geom, selection=selection))
return geoms
else:
if geom_el in selection:
geometric_data = geom_el.geo
- buffered_geom_el = dict()
+ buffered_geom_el = {}
if 'solid' in geometric_data:
buffered_geom_el['solid'] = geometric_data['solid'].buffer(buff_value, join_style=join_style)
if 'follow' in geometric_data:
@@ -5008,14 +5008,14 @@ class FlatCAMGrbEditor(QtCore.QObject):
def scale_recursion(geom_el, selection):
if type(geom_el) == list:
- geoms = list()
+ geoms = []
for local_geom in geom_el:
geoms.append(scale_recursion(local_geom, selection=selection))
return geoms
else:
if geom_el in selection:
geometric_data = geom_el.geo
- scaled_geom_el = dict()
+ scaled_geom_el = {}
if 'solid' in geometric_data:
scaled_geom_el['solid'] = affinity.scale(
geometric_data['solid'], scale_factor, scale_factor, origin='center'
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index fd144564..144280c9 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -176,8 +176,34 @@ class FCTree(QtWidgets.QTreeWidget):
item.setFont(0, font)
return item
- def addChild(self, parent, title, column1=None, font=None, font_items=None):
+ def addParentEditable(self, parent, title, color=None, font=None, font_items=None, editable=False):
item = QtWidgets.QTreeWidgetItem(parent)
+ item.setChildIndicatorPolicy(QtWidgets.QTreeWidgetItem.DontShowIndicator)
+ if editable:
+ item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
+
+ for t in range(len(title)):
+ item.setText(t, title[t])
+
+ if color is not None:
+ # item.setTextColor(0, color) # PyQt4
+ item.setForeground(0, QtGui.QBrush(color))
+
+ if font and font_items:
+ try:
+ for fi in font_items:
+ item.setFont(fi, font)
+ except TypeError:
+ item.setFont(font_items, font)
+ elif font:
+ item.setFont(0, font)
+ return item
+
+ def addChild(self, parent, title, column1=None, font=None, font_items=None, editable=False):
+ item = QtWidgets.QTreeWidgetItem(parent)
+ if editable:
+ item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
+
item.setText(0, str(title[0]))
if column1 is not None:
item.setText(1, str(title[1]))
@@ -2108,7 +2134,7 @@ class FCTable(QtWidgets.QTableWidget):
self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
- self.rows_not_for_drag_and_drop = list()
+ self.rows_not_for_drag_and_drop = []
if protected_rows:
try:
for r in protected_rows:
@@ -2116,7 +2142,7 @@ class FCTable(QtWidgets.QTableWidget):
except TypeError:
self.rows_not_for_drag_and_drop = [protected_rows]
- self.rows_to_move = list()
+ self.rows_to_move = []
def sizeHint(self):
default_hint_size = super(FCTable, self).sizeHint()
@@ -2172,7 +2198,7 @@ class FCTable(QtWidgets.QTableWidget):
# # ]
# self.rows_to_move[:] = []
# for row_index in rows:
- # row_items = list()
+ # row_items = []
# for column_index in range(self.columnCount()):
# r_item = self.item(row_index, column_index)
# w_item = self.cellWidget(row_index, column_index)
@@ -2253,7 +2279,7 @@ class FCTable(QtWidgets.QTableWidget):
for _ in range(len(rows)):
self.insertRow(targetRow)
- rowMapping = dict() # Src row to target row.
+ rowMapping = {} # Src row to target row.
for idx, row in enumerate(rows):
if row < targetRow:
rowMapping[row] = targetRow + idx
diff --git a/flatcamGUI/PlotCanvas.py b/flatcamGUI/PlotCanvas.py
index b2fd945a..cfb24039 100644
--- a/flatcamGUI/PlotCanvas.py
+++ b/flatcamGUI/PlotCanvas.py
@@ -62,7 +62,7 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
# self.b_line, self.r_line, self.t_line, self.l_line = None, None, None, None
self.workspace_line = None
- self.pagesize_dict = dict()
+ self.pagesize_dict = {}
self.pagesize_dict.update(
{
'A0': (841, 1189),
diff --git a/flatcamGUI/PlotCanvasLegacy.py b/flatcamGUI/PlotCanvasLegacy.py
index c49d3ebe..ed62d9a0 100644
--- a/flatcamGUI/PlotCanvasLegacy.py
+++ b/flatcamGUI/PlotCanvasLegacy.py
@@ -158,7 +158,7 @@ class PlotCanvasLegacy(QtCore.QObject):
# self.b_line, self.r_line, self.t_line, self.l_line = None, None, None, None
self.workspace_line = None
- self.pagesize_dict = dict()
+ self.pagesize_dict = {}
self.pagesize_dict.update(
{
'A0': (841, 1189),
@@ -959,8 +959,8 @@ class ShapeCollectionLegacy:
self.app = app
self.annotation_job = annotation_job
- self._shapes = dict()
- self.shape_dict = dict()
+ self._shapes = {}
+ self.shape_dict = {}
self.shape_id = 0
self._color = None
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index 89dcbfd0..acca4dfc 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -1037,7 +1037,7 @@ class GeneralAPPSetGroupUI(OptionsGroupUI):
grid0.addWidget(self.workspace_type_lbl, 7, 0)
grid0.addWidget(self.wk_cb, 7, 1)
- self.pagesize = dict()
+ self.pagesize = {}
self.pagesize.update(
{
'A0': (841, 1189),
@@ -6184,7 +6184,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI):
self.pagesize_combo = FCComboBox()
- self.pagesize = dict()
+ self.pagesize = {}
self.pagesize.update(
{
'Bounds': None,
diff --git a/flatcamParsers/ParseExcellon.py b/flatcamParsers/ParseExcellon.py
index 059e09f3..7dc9ee35 100644
--- a/flatcamParsers/ParseExcellon.py
+++ b/flatcamParsers/ParseExcellon.py
@@ -95,11 +95,11 @@ class Excellon(Geometry):
Geometry.__init__(self, geo_steps_per_circle=int(geo_steps_per_circle))
# dictionary to store tools, see above for description
- self.tools = dict()
+ self.tools = {}
# list to store the drills, see above for description
- self.drills = list()
+ self.drills = []
# self.slots (list) to store the slots; each is a dictionary
- self.slots = list()
+ self.slots = []
self.source_file = ''
@@ -110,8 +110,8 @@ class Excellon(Geometry):
self.match_routing_start = None
self.match_routing_stop = None
- self.num_tools = list() # List for keeping the tools sorted
- self.index_per_tool = dict() # Dictionary to store the indexed points for each tool
+ self.num_tools = [] # List for keeping the tools sorted
+ self.index_per_tool = {} # Dictionary to store the indexed points for each tool
# ## IN|MM -> Units are inherited from Geometry
self.units = self.app.defaults['units']
@@ -962,8 +962,8 @@ class Excellon(Geometry):
try:
# clear the solid_geometry in self.tools
for tool in self.tools:
- self.tools[tool]['solid_geometry'] = list()
- self.tools[tool]['data'] = dict()
+ self.tools[tool]['solid_geometry'] = []
+ self.tools[tool]['data'] = {}
for drill in self.drills:
# poly = drill['point'].buffer(self.tools[drill['tool']]["C"]/2.0)
diff --git a/flatcamParsers/ParseGerber.py b/flatcamParsers/ParseGerber.py
index bfa36a4b..54091259 100644
--- a/flatcamParsers/ParseGerber.py
+++ b/flatcamParsers/ParseGerber.py
@@ -467,7 +467,7 @@ class Gerber(Geometry):
# --- Buffered ----
width = self.apertures[last_path_aperture]["size"]
- geo_dict = dict()
+ geo_dict = {}
geo_f = LineString(path)
if not geo_f.is_empty:
follow_buffer.append(geo_f)
@@ -486,7 +486,7 @@ class Gerber(Geometry):
geo_dict['solid'] = geo_s
if last_path_aperture not in self.apertures:
- self.apertures[last_path_aperture] = dict()
+ self.apertures[last_path_aperture] = {}
if 'geometry' not in self.apertures[last_path_aperture]:
self.apertures[last_path_aperture]['geometry'] = []
self.apertures[last_path_aperture]['geometry'].append(deepcopy(geo_dict))
@@ -677,7 +677,7 @@ class Gerber(Geometry):
# --- Buffered ---
try:
# log.debug("Bare op-code %d." % current_operation_code)
- geo_dict = dict()
+ geo_dict = {}
flash = self.create_flash_geometry(
Point(current_x, current_y), self.apertures[current_aperture],
self.steps_per_circle)
@@ -695,7 +695,7 @@ class Gerber(Geometry):
geo_dict['solid'] = flash
if current_aperture not in self.apertures:
- self.apertures[current_aperture] = dict()
+ self.apertures[current_aperture] = {}
if 'geometry' not in self.apertures[current_aperture]:
self.apertures[current_aperture]['geometry'] = []
self.apertures[current_aperture]['geometry'].append(deepcopy(geo_dict))
@@ -734,7 +734,7 @@ class Gerber(Geometry):
# do nothing because 'R' type moving aperture is none at once
pass
else:
- geo_dict = dict()
+ geo_dict = {}
geo_f = LineString(path)
if not geo_f.is_empty:
follow_buffer.append(geo_f)
@@ -754,7 +754,7 @@ class Gerber(Geometry):
geo_dict['solid'] = geo_s
if last_path_aperture not in self.apertures:
- self.apertures[last_path_aperture] = dict()
+ self.apertures[last_path_aperture] = {}
if 'geometry' not in self.apertures[last_path_aperture]:
self.apertures[last_path_aperture]['geometry'] = []
self.apertures[last_path_aperture]['geometry'].append(deepcopy(geo_dict))
@@ -774,7 +774,7 @@ class Gerber(Geometry):
if path_length > 1:
# Take care of what is left in the path
- geo_dict = dict()
+ geo_dict = {}
geo_f = LineString(path)
if not geo_f.is_empty:
follow_buffer.append(geo_f)
@@ -794,7 +794,7 @@ class Gerber(Geometry):
geo_dict['solid'] = geo_s
if last_path_aperture not in self.apertures:
- self.apertures[last_path_aperture] = dict()
+ self.apertures[last_path_aperture] = {}
if 'geometry' not in self.apertures[last_path_aperture]:
self.apertures[last_path_aperture]['geometry'] = []
self.apertures[last_path_aperture]['geometry'].append(deepcopy(geo_dict))
@@ -814,7 +814,7 @@ class Gerber(Geometry):
self.apertures['0'] = {}
self.apertures['0']['type'] = 'REG'
self.apertures['0']['size'] = 0.0
- self.apertures['0']['geometry'] = list()
+ self.apertures['0']['geometry'] = []
# if D02 happened before G37 we now have a path with 1 element only; we have to add the current
# geo to the poly_buffer otherwise we loose it
@@ -826,7 +826,7 @@ class Gerber(Geometry):
if path_length == 1:
# this means that the geometry was prepared previously and we just need to add it
- geo_dict = dict()
+ geo_dict = {}
if geo_f:
if not geo_f.is_empty:
follow_buffer.append(geo_f)
@@ -863,7 +863,7 @@ class Gerber(Geometry):
# For regions we may ignore an aperture that is None
# --- Buffered ---
- geo_dict = dict()
+ geo_dict = {}
if current_aperture in self.apertures:
# the following line breaks loading of Circuit Studio Gerber files
# buff_value = float(self.apertures[current_aperture]['size']) / 2.0
@@ -965,7 +965,7 @@ class Gerber(Geometry):
maxy = max(path[0][1], path[1][1]) + height / 2
log.debug("Coords: %s - %s - %s - %s" % (minx, miny, maxx, maxy))
- geo_dict = dict()
+ geo_dict = {}
geo_f = Point([current_x, current_y])
follow_buffer.append(geo_f)
geo_dict['follow'] = geo_f
@@ -982,7 +982,7 @@ class Gerber(Geometry):
geo_dict['solid'] = geo_s
if current_aperture not in self.apertures:
- self.apertures[current_aperture] = dict()
+ self.apertures[current_aperture] = {}
if 'geometry' not in self.apertures[current_aperture]:
self.apertures[current_aperture]['geometry'] = []
self.apertures[current_aperture]['geometry'].append(deepcopy(geo_dict))
@@ -1012,7 +1012,7 @@ class Gerber(Geometry):
if path_length > 1:
geo_s = None
- geo_dict = dict()
+ geo_dict = {}
# --- BUFFERED ---
# this treats the case when we are storing geometry as paths only
if making_region:
@@ -1089,7 +1089,7 @@ class Gerber(Geometry):
geo_dict['solid'] = geo_s
if last_path_aperture not in self.apertures:
- self.apertures[last_path_aperture] = dict()
+ self.apertures[last_path_aperture] = {}
if 'geometry' not in self.apertures[last_path_aperture]:
self.apertures[last_path_aperture]['geometry'] = []
self.apertures[last_path_aperture]['geometry'].append(deepcopy(geo_dict))
@@ -1115,7 +1115,7 @@ class Gerber(Geometry):
if path_length > 1:
# --- Buffered ----
- geo_dict = dict()
+ geo_dict = {}
# this treats the case when we are storing geometry as paths
geo_f = LineString(path)
@@ -1156,7 +1156,7 @@ class Gerber(Geometry):
geo_dict['solid'] = geo_s
if last_path_aperture not in self.apertures:
- self.apertures[last_path_aperture] = dict()
+ self.apertures[last_path_aperture] = {}
if 'geometry' not in self.apertures[last_path_aperture]:
self.apertures[last_path_aperture]['geometry'] = []
self.apertures[last_path_aperture]['geometry'].append(deepcopy(geo_dict))
@@ -1167,7 +1167,7 @@ class Gerber(Geometry):
# --- BUFFERED ---
# Draw the flash
# this treats the case when we are storing geometry as paths
- geo_dict = dict()
+ geo_dict = {}
geo_flash = Point([linear_x, linear_y])
follow_buffer.append(geo_flash)
geo_dict['follow'] = geo_flash
@@ -1190,7 +1190,7 @@ class Gerber(Geometry):
geo_dict['solid'] = flash
if current_aperture not in self.apertures:
- self.apertures[current_aperture] = dict()
+ self.apertures[current_aperture] = {}
if 'geometry' not in self.apertures[current_aperture]:
self.apertures[current_aperture]['geometry'] = []
self.apertures[current_aperture]['geometry'].append(deepcopy(geo_dict))
@@ -1275,7 +1275,7 @@ class Gerber(Geometry):
path_length = 1
if path_length > 1:
- geo_dict = dict()
+ geo_dict = {}
if last_path_aperture is None:
log.warning("No aperture defined for curent path. (%d)" % line_num)
@@ -1303,7 +1303,7 @@ class Gerber(Geometry):
geo_dict['solid'] = buffered
if last_path_aperture not in self.apertures:
- self.apertures[last_path_aperture] = dict()
+ self.apertures[last_path_aperture] = {}
if 'geometry' not in self.apertures[last_path_aperture]:
self.apertures[last_path_aperture]['geometry'] = []
self.apertures[last_path_aperture]['geometry'].append(deepcopy(geo_dict))
@@ -1432,7 +1432,7 @@ class Gerber(Geometry):
# EOF, create shapely LineString if something still in path
# ## --- Buffered ---
- geo_dict = dict()
+ geo_dict = {}
# this treats the case when we are storing geometry as paths
geo_f = LineString(path)
if not geo_f.is_empty:
@@ -1454,7 +1454,7 @@ class Gerber(Geometry):
geo_dict['solid'] = geo_s
if last_path_aperture not in self.apertures:
- self.apertures[last_path_aperture] = dict()
+ self.apertures[last_path_aperture] = {}
if 'geometry' not in self.apertures[last_path_aperture]:
self.apertures[last_path_aperture]['geometry'] = []
self.apertures[last_path_aperture]['geometry'].append(deepcopy(geo_dict))
@@ -1525,7 +1525,7 @@ class Gerber(Geometry):
# it use a filled bounding box polygon to which add clear polygons (negative) to isolate the copper
# features
if self.app.defaults['gerber_extra_buffering']:
- candidate_geo = list()
+ candidate_geo = []
try:
for p in self.solid_geometry:
candidate_geo.append(p.buffer(-0.0000001))
@@ -1777,7 +1777,7 @@ class Gerber(Geometry):
# Add to object
if self.solid_geometry is None:
- self.solid_geometry = list()
+ self.solid_geometry = []
# if type(self.solid_geometry) == list:
# if type(geos) == list:
@@ -1795,7 +1795,7 @@ class Gerber(Geometry):
geos_length = 1
if geos_length == 1:
- geo_qrcode = list()
+ geo_qrcode = []
geo_qrcode.append(Polygon(geos[0].exterior))
for i_el in geos[0].interiors:
geo_qrcode.append(Polygon(i_el).buffer(0))
@@ -1822,13 +1822,13 @@ class Gerber(Geometry):
self.solid_geometry = [self.solid_geometry]
if '0' not in self.apertures:
- self.apertures['0'] = dict()
+ self.apertures['0'] = {}
self.apertures['0']['type'] = 'REG'
self.apertures['0']['size'] = 0.0
- self.apertures['0']['geometry'] = list()
+ self.apertures['0']['geometry'] = []
for pol in self.solid_geometry:
- new_el = dict()
+ new_el = {}
new_el['solid'] = pol
new_el['follow'] = pol.exterior
self.apertures['0']['geometry'].append(deepcopy(new_el))
@@ -1917,10 +1917,10 @@ class Gerber(Geometry):
# we need to scale the geometry stored in the Gerber apertures, too
try:
for apid in self.apertures:
- new_geometry = list()
+ new_geometry = []
if 'geometry' in self.apertures[apid]:
for geo_el in self.apertures[apid]['geometry']:
- new_geo_el = dict()
+ new_geo_el = {}
if 'solid' in geo_el:
new_geo_el['solid'] = scale_geom(geo_el['solid'])
if 'follow' in geo_el:
@@ -2313,10 +2313,10 @@ class Gerber(Geometry):
# we need to buffer the geometry stored in the Gerber apertures, too
try:
for apid in self.apertures:
- new_geometry = list()
+ new_geometry = []
if 'geometry' in self.apertures[apid]:
for geo_el in self.apertures[apid]['geometry']:
- new_geo_el = dict()
+ new_geo_el = {}
if 'solid' in geo_el:
new_geo_el['solid'] = buffer_geom(geo_el['solid'])
if 'follow' in geo_el:
@@ -2364,10 +2364,10 @@ class Gerber(Geometry):
except KeyError:
pass
- new_geometry = list()
+ new_geometry = []
if 'geometry' in self.apertures[apid]:
for geo_el in self.apertures[apid]['geometry']:
- new_geo_el = dict()
+ new_geo_el = {}
if 'follow' in geo_el:
new_geo_el['follow'] = geo_el['follow']
size = float(self.apertures[apid]['size'])
@@ -2405,7 +2405,7 @@ class Gerber(Geometry):
return 'fail'
# make the new solid_geometry
- new_solid_geo = list()
+ new_solid_geo = []
for apid in self.apertures:
if 'geometry' in self.apertures[apid]:
new_solid_geo += [geo_el['solid'] for geo_el in self.apertures[apid]['geometry']]
diff --git a/flatcamParsers/ParseHPGL2.py b/flatcamParsers/ParseHPGL2.py
index 546825c4..ead2a67c 100644
--- a/flatcamParsers/ParseHPGL2.py
+++ b/flatcamParsers/ParseHPGL2.py
@@ -49,9 +49,9 @@ class HPGL2:
self.units = 'MM'
# storage for the tools
- self.tools = dict()
+ self.tools = {}
- self.default_data = dict()
+ self.default_data = {}
self.default_data.update({
"name": '_ncc',
"plot": self.app.defaults["geometry_plot"],
@@ -153,7 +153,7 @@ class HPGL2:
"""
# Coordinates of the current path, each is [x, y]
- path = list()
+ path = []
geo_buffer = []
@@ -209,7 +209,7 @@ class HPGL2:
match = self.sp_re.search(gline)
if match:
tool = match.group(1)
- # self.tools[tool] = dict()
+ # self.tools[tool] = {}
self.tools.update({
tool: {
'tooldia': float('%.*f' %
diff --git a/flatcamParsers/ParseSVG.py b/flatcamParsers/ParseSVG.py
index 2aa5db2d..edff621f 100644
--- a/flatcamParsers/ParseSVG.py
+++ b/flatcamParsers/ParseSVG.py
@@ -135,7 +135,7 @@ def path2shapely(path, object_type, res=1.0):
try:
geo_element = Polygon(rings[0], rings[1:])
except Exception:
- coords = list()
+ coords = []
for line in rings:
coords.append(line.coords[0])
coords.append(line.coords[1])
@@ -305,7 +305,7 @@ def getsvggeo(node, object_type, root=None):
root = node
kind = re.search('(?:\{.*\})?(.*)$', node.tag).group(1)
- geo = list()
+ geo = []
# Recurse
if len(node) > 0:
diff --git a/flatcamTools/ToolAlignObjects.py b/flatcamTools/ToolAlignObjects.py
index 9cc4c196..1ffbe1e5 100644
--- a/flatcamTools/ToolAlignObjects.py
+++ b/flatcamTools/ToolAlignObjects.py
@@ -206,7 +206,7 @@ class AlignObjects(FlatCAMTool):
self.target_obj = None
# here store the alignment points
- self.clicked_points = list()
+ self.clicked_points = []
self.align_type = None
@@ -249,7 +249,7 @@ class AlignObjects(FlatCAMTool):
def set_tool_ui(self):
self.reset_fields()
- self.clicked_points = list()
+ self.clicked_points = []
self.target_obj = None
self.aligned_obj = None
self.aligner_obj = None
@@ -373,7 +373,7 @@ class AlignObjects(FlatCAMTool):
elif event.button == right_button and self.app.event_is_dragging is False:
self.reset_color()
- self.clicked_points = list()
+ self.clicked_points = []
self.disconnect_cal_events()
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled by user request."))
diff --git a/flatcamTools/ToolCalibration.py b/flatcamTools/ToolCalibration.py
index ae83edb6..6f9b015c 100644
--- a/flatcamTools/ToolCalibration.py
+++ b/flatcamTools/ToolCalibration.py
@@ -926,7 +926,7 @@ class ToolCalibration(FlatCAMTool):
self.disconnect_cal_events()
def reset_calibration_points(self):
- self.click_points = list()
+ self.click_points = []
self.bottom_left_coordx_tgt.set_value('')
self.bottom_left_coordy_tgt.set_value('')
diff --git a/flatcamTools/ToolCopperThieving.py b/flatcamTools/ToolCopperThieving.py
index aa9ab7f1..295aed5a 100644
--- a/flatcamTools/ToolCopperThieving.py
+++ b/flatcamTools/ToolCopperThieving.py
@@ -494,11 +494,11 @@ class ToolCopperThieving(FlatCAMTool):
# Objects involved in Copper thieving
self.grb_object = None
self.ref_obj = None
- self.sel_rect = list()
+ self.sel_rect = []
self.sm_object = None
# store the flattened geometry here:
- self.flat_geometry = list()
+ self.flat_geometry = []
# Events ID
self.mr = None
@@ -517,7 +517,7 @@ class ToolCopperThieving(FlatCAMTool):
self.geo_steps_per_circle = 128
# Thieving geometry storage
- self.new_solid_geometry = list()
+ self.new_solid_geometry = []
# Robber bar geometry storage
self.robber_geo = None
@@ -681,7 +681,7 @@ class ToolCopperThieving(FlatCAMTool):
break
if aperture_found:
- geo_elem = dict()
+ geo_elem = {}
geo_elem['solid'] = self.robber_geo
geo_elem['follow'] = self.robber_line
self.grb_object.apertures[aperture_found]['geometry'].append(deepcopy(geo_elem))
@@ -692,19 +692,19 @@ class ToolCopperThieving(FlatCAMTool):
else:
new_apid = '10'
- self.grb_object.apertures[new_apid] = dict()
+ self.grb_object.apertures[new_apid] = {}
self.grb_object.apertures[new_apid]['type'] = 'C'
self.grb_object.apertures[new_apid]['size'] = self.rb_thickness
- self.grb_object.apertures[new_apid]['geometry'] = list()
+ self.grb_object.apertures[new_apid]['geometry'] = []
- geo_elem = dict()
+ geo_elem = {}
geo_elem['solid'] = self.robber_geo
geo_elem['follow'] = self.robber_line
self.grb_object.apertures[new_apid]['geometry'].append(deepcopy(geo_elem))
geo_obj = self.grb_object.solid_geometry
if isinstance(geo_obj, MultiPolygon):
- s_list = list()
+ s_list = []
for pol in geo_obj.geoms:
s_list.append(pol)
s_list.append(self.robber_geo)
@@ -1127,7 +1127,7 @@ class ToolCopperThieving(FlatCAMTool):
if fill_type == 'dot' or fill_type == 'square':
# build the MultiPolygon of dots/squares that will fill the entire bounding box
- thieving_list = list()
+ thieving_list = []
if fill_type == 'dot':
radius = dot_dia / 2.0
@@ -1169,7 +1169,7 @@ class ToolCopperThieving(FlatCAMTool):
except TypeError:
thieving_box_geo = [thieving_box_geo]
- thieving_geo = list()
+ thieving_geo = []
for dot_geo in thieving_box_geo:
for geo_t in app_obj.new_solid_geometry:
if dot_geo.within(geo_t):
@@ -1212,7 +1212,7 @@ class ToolCopperThieving(FlatCAMTool):
app_obj.app.proc_container.update_view_text(' %s' % _("Buffering"))
outline_geometry = unary_union(outline_geometry)
- outline_line = list()
+ outline_line = []
try:
for geo_o in outline_geometry:
outline_line.append(
@@ -1238,7 +1238,7 @@ class ToolCopperThieving(FlatCAMTool):
)
bx0, by0, bx1, by1 = box_outline_geo.bounds
- thieving_lines_geo = list()
+ thieving_lines_geo = []
new_x = bx0
new_y = by0
while new_x <= x1 - half_thick_line:
@@ -1258,7 +1258,7 @@ class ToolCopperThieving(FlatCAMTool):
new_y += line_size + line_spacing
# merge everything together
- diff_lines_geo = list()
+ diff_lines_geo = []
for line_poly in thieving_lines_geo:
rest_line = line_poly.difference(clearance_geometry)
diff_lines_geo.append(rest_line)
@@ -1271,8 +1271,8 @@ class ToolCopperThieving(FlatCAMTool):
geo_list = list(app_obj.grb_object.solid_geometry.geoms)
if '0' not in app_obj.grb_object.apertures:
- app_obj.grb_object.apertures['0'] = dict()
- app_obj.grb_object.apertures['0']['geometry'] = list()
+ app_obj.grb_object.apertures['0'] = {}
+ app_obj.grb_object.apertures['0']['geometry'] = []
app_obj.grb_object.apertures['0']['type'] = 'REG'
app_obj.grb_object.apertures['0']['size'] = 0.0
@@ -1282,7 +1282,7 @@ class ToolCopperThieving(FlatCAMTool):
geo_list.append(poly)
# append into the '0' aperture
- geo_elem = dict()
+ geo_elem = {}
geo_elem['solid'] = poly
geo_elem['follow'] = poly.exterior
app_obj.grb_object.apertures['0']['geometry'].append(deepcopy(geo_elem))
@@ -1291,7 +1291,7 @@ class ToolCopperThieving(FlatCAMTool):
geo_list.append(app_obj.new_solid_geometry)
# append into the '0' aperture
- geo_elem = dict()
+ geo_elem = {}
geo_elem['solid'] = app_obj.new_solid_geometry
geo_elem['follow'] = app_obj.new_solid_geometry.exterior
app_obj.grb_object.apertures['0']['geometry'].append(deepcopy(geo_elem))
@@ -1350,7 +1350,7 @@ class ToolCopperThieving(FlatCAMTool):
# if the clearance is negative apply it to the original soldermask too
if ppm_clearance < 0:
- temp_geo_list = list()
+ temp_geo_list = []
for geo in geo_list:
temp_geo_list.append(geo.buffer(ppm_clearance))
geo_list = temp_geo_list
@@ -1372,11 +1372,11 @@ class ToolCopperThieving(FlatCAMTool):
def obj_init(grb_obj, app_obj):
grb_obj.multitool = False
- grb_obj.source_file = list()
+ grb_obj.source_file = []
grb_obj.multigeo = False
grb_obj.follow = False
- grb_obj.apertures = dict()
- grb_obj.solid_geometry = list()
+ grb_obj.apertures = {}
+ grb_obj.solid_geometry = []
# try:
# grb_obj.options['xmin'] = 0
@@ -1389,8 +1389,8 @@ class ToolCopperThieving(FlatCAMTool):
# if we have copper thieving geometry, add it
if thieving_solid_geo:
if '0' not in grb_obj.apertures:
- grb_obj.apertures['0'] = dict()
- grb_obj.apertures['0']['geometry'] = list()
+ grb_obj.apertures['0'] = {}
+ grb_obj.apertures['0']['geometry'] = []
grb_obj.apertures['0']['type'] = 'REG'
grb_obj.apertures['0']['size'] = 0.0
@@ -1402,7 +1402,7 @@ class ToolCopperThieving(FlatCAMTool):
geo_list.append(poly_b)
# append into the '0' aperture
- geo_elem = dict()
+ geo_elem = {}
geo_elem['solid'] = poly_b
geo_elem['follow'] = poly_b.exterior
grb_obj.apertures['0']['geometry'].append(deepcopy(geo_elem))
@@ -1411,7 +1411,7 @@ class ToolCopperThieving(FlatCAMTool):
geo_list.append(thieving_solid_geo.buffer(ppm_clearance))
# append into the '0' aperture
- geo_elem = dict()
+ geo_elem = {}
geo_elem['solid'] = thieving_solid_geo.buffer(ppm_clearance)
geo_elem['follow'] = thieving_solid_geo.buffer(ppm_clearance).exterior
grb_obj.apertures['0']['geometry'].append(deepcopy(geo_elem))
@@ -1425,7 +1425,7 @@ class ToolCopperThieving(FlatCAMTool):
break
if aperture_found:
- geo_elem = dict()
+ geo_elem = {}
geo_elem['solid'] = robber_solid_geo
geo_elem['follow'] = robber_line
grb_obj.apertures[aperture_found]['geometry'].append(deepcopy(geo_elem))
@@ -1437,12 +1437,12 @@ class ToolCopperThieving(FlatCAMTool):
else:
new_apid = '10'
- grb_obj.apertures[new_apid] = dict()
+ grb_obj.apertures[new_apid] = {}
grb_obj.apertures[new_apid]['type'] = 'C'
grb_obj.apertures[new_apid]['size'] = rb_thickness + ppm_clearance
- grb_obj.apertures[new_apid]['geometry'] = list()
+ grb_obj.apertures[new_apid]['geometry'] = []
- geo_elem = dict()
+ geo_elem = {}
geo_elem['solid'] = robber_solid_geo.buffer(ppm_clearance)
geo_elem['follow'] = Polygon(robber_line).buffer(ppm_clearance / 2.0).exterior
grb_obj.apertures[new_apid]['geometry'].append(deepcopy(geo_elem))
@@ -1510,7 +1510,7 @@ class ToolCopperThieving(FlatCAMTool):
self.grb_object = None
self.sm_object = None
self.ref_obj = None
- self.sel_rect = list()
+ self.sel_rect = []
# Events ID
self.mr = None
diff --git a/flatcamTools/ToolCutOut.py b/flatcamTools/ToolCutOut.py
index 87ebafc3..0033d149 100644
--- a/flatcamTools/ToolCutOut.py
+++ b/flatcamTools/ToolCutOut.py
@@ -521,7 +521,7 @@ class CutOut(FlatCAMTool):
gapsize = gapsize / 2 + (dia / 2)
def geo_init(geo_obj, app_obj):
- solid_geo = list()
+ solid_geo = []
if isinstance(cutout_obj, FlatCAMGerber):
if isinstance(cutout_obj.solid_geometry, list):
@@ -639,7 +639,7 @@ class CutOut(FlatCAMTool):
cutout_obj.plot()
self.app.inform.emit('[success] %s' % _("Any form CutOut operation finished."))
- self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
+ # self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
self.app.should_we_save = True
def on_rectangular_cutout(self):
@@ -798,7 +798,7 @@ class CutOut(FlatCAMTool):
# cutout_obj.plot()
self.app.inform.emit('[success] %s' %
_("Any form CutOut operation finished."))
- self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
+ # self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
self.app.should_we_save = True
def on_manual_gap_click(self):
diff --git a/flatcamTools/ToolDblSided.py b/flatcamTools/ToolDblSided.py
index b7c975d9..56602125 100644
--- a/flatcamTools/ToolDblSided.py
+++ b/flatcamTools/ToolDblSided.py
@@ -606,10 +606,10 @@ class DblSidedTool(FlatCAMTool):
_("No value or wrong format in Drill Dia entry. Add it and retry."))
return
- tools = dict()
- tools["1"] = dict()
+ tools = {}
+ tools["1"] = {}
tools["1"]["C"] = dia
- tools["1"]['solid_geometry'] = list()
+ tools["1"]['solid_geometry'] = []
# holes = self.alignment_holes.get_value()
holes = eval('[{}]'.format(self.alignment_holes.text()))
@@ -618,7 +618,7 @@ class DblSidedTool(FlatCAMTool):
"Add them and retry."))
return
- drills = list()
+ drills = []
for hole in holes:
point = Point(hole)
diff --git a/flatcamTools/ToolDistance.py b/flatcamTools/ToolDistance.py
index 84a6c547..59f6f9d4 100644
--- a/flatcamTools/ToolDistance.py
+++ b/flatcamTools/ToolDistance.py
@@ -433,7 +433,7 @@ class Distance(FlatCAMTool):
pos = (center_pt.x, center_pt.y)
elif self.original_call_source == 'grb_editor':
- clicked_pads = list()
+ clicked_pads = []
for storage in self.app.grb_editor.storage_dict:
try:
for shape_stored in self.app.grb_editor.storage_dict[storage]['geometry']:
diff --git a/flatcamTools/ToolExtractDrills.py b/flatcamTools/ToolExtractDrills.py
index 5a693300..287a1571 100644
--- a/flatcamTools/ToolExtractDrills.py
+++ b/flatcamTools/ToolExtractDrills.py
@@ -423,8 +423,8 @@ class ToolExtractDrills(FlatCAMTool):
prop_factor = self.factor_entry.get_value() / 100.0
- drills = list()
- tools = dict()
+ drills = []
+ tools = {}
selection_index = self.gerber_object_combo.currentIndex()
model_index = self.app.collection.index(selection_index, 0, self.gerber_object_combo.rootModelIndex())
@@ -469,7 +469,7 @@ class ToolExtractDrills(FlatCAMTool):
if 'follow' in geo_el and isinstance(geo_el['follow'], Point):
drills.append({"point": geo_el['follow'], "tool": "1"})
if 'solid_geometry' not in tools["1"]:
- tools["1"]['solid_geometry'] = list()
+ tools["1"]['solid_geometry'] = []
else:
tools["1"]['solid_geometry'].append(geo_el['follow'])
@@ -548,7 +548,7 @@ class ToolExtractDrills(FlatCAMTool):
drills.append({"point": geo_el['follow'], "tool": tool_in_drills})
if 'solid_geometry' not in tools[tool_in_drills]:
- tools[tool_in_drills]['solid_geometry'] = list()
+ tools[tool_in_drills]['solid_geometry'] = []
else:
tools[tool_in_drills]['solid_geometry'].append(geo_el['follow'])
@@ -633,7 +633,7 @@ class ToolExtractDrills(FlatCAMTool):
drills.append({"point": geo_el['follow'], "tool": tool_in_drills})
if 'solid_geometry' not in tools[tool_in_drills]:
- tools[tool_in_drills]['solid_geometry'] = list()
+ tools[tool_in_drills]['solid_geometry'] = []
else:
tools[tool_in_drills]['solid_geometry'].append(geo_el['follow'])
diff --git a/flatcamTools/ToolFiducials.py b/flatcamTools/ToolFiducials.py
index 33113dac..342f1d5c 100644
--- a/flatcamTools/ToolFiducials.py
+++ b/flatcamTools/ToolFiducials.py
@@ -333,7 +333,7 @@ class ToolFiducials(FlatCAMTool):
self.sm_obj_set = set()
# store the flattened geometry here:
- self.flat_geometry = list()
+ self.flat_geometry = []
# Events ID
self.mr = None
@@ -353,7 +353,7 @@ class ToolFiducials(FlatCAMTool):
self.sec_position = None
self.geo_steps_per_circle = 128
- self.click_points = list()
+ self.click_points = []
# SIGNALS
self.add_cfid_button.clicked.connect(self.add_fiducials)
@@ -404,7 +404,7 @@ class ToolFiducials(FlatCAMTool):
self.fid_type_radio.set_value(self.app.defaults["tools_fiducials_type"])
self.line_thickness_entry.set_value(float(self.app.defaults["tools_fiducials_line_thickness"]))
- self.click_points = list()
+ self.click_points = []
self.bottom_left_coords_entry.set_value('')
self.top_right_coords_entry.set_value('')
self.sec_points_coords_entry.set_value('')
@@ -429,7 +429,7 @@ class ToolFiducials(FlatCAMTool):
:return: None
"""
if val == 'auto':
- self.click_points = list()
+ self.click_points = []
try:
self.disconnect_event_handlers()
@@ -451,7 +451,7 @@ class ToolFiducials(FlatCAMTool):
self.sec_position = self.pos_radio.get_value()
fid_type = self.fid_type_radio.get_value()
- self.click_points = list()
+ self.click_points = []
# get the Gerber object on which the Fiducial will be inserted
selection_index = self.grb_object_combo.currentIndex()
@@ -547,7 +547,7 @@ class ToolFiducials(FlatCAMTool):
if aperture_found:
for geo in geo_list:
- dict_el = dict()
+ dict_el = {}
dict_el['follow'] = geo.centroid
dict_el['solid'] = geo
g_obj.apertures[aperture_found]['geometry'].append(deepcopy(dict_el))
@@ -558,18 +558,18 @@ class ToolFiducials(FlatCAMTool):
else:
new_apid = '10'
- g_obj.apertures[new_apid] = dict()
+ g_obj.apertures[new_apid] = {}
g_obj.apertures[new_apid]['type'] = 'C'
g_obj.apertures[new_apid]['size'] = fid_size
- g_obj.apertures[new_apid]['geometry'] = list()
+ g_obj.apertures[new_apid]['geometry'] = []
for geo in geo_list:
- dict_el = dict()
+ dict_el = {}
dict_el['follow'] = geo.centroid
dict_el['solid'] = geo
g_obj.apertures[new_apid]['geometry'].append(deepcopy(dict_el))
- s_list = list()
+ s_list = []
if g_obj.solid_geometry:
try:
for poly in g_obj.solid_geometry:
@@ -580,7 +580,7 @@ class ToolFiducials(FlatCAMTool):
s_list += geo_list
g_obj.solid_geometry = MultiPolygon(s_list)
elif fid_type == 'cross':
- geo_list = list()
+ geo_list = []
for pt in points_list:
x = pt[0]
@@ -599,7 +599,7 @@ class ToolFiducials(FlatCAMTool):
aperture_found = ap_id
break
- geo_buff_list = list()
+ geo_buff_list = []
if aperture_found:
for geo in geo_list:
geo_buff_h = geo[0].buffer(line_thickness / 2.0)
@@ -607,7 +607,7 @@ class ToolFiducials(FlatCAMTool):
geo_buff_list.append(geo_buff_h)
geo_buff_list.append(geo_buff_v)
- dict_el = dict()
+ dict_el = {}
dict_el['follow'] = geo_buff_h.centroid
dict_el['solid'] = geo_buff_h
g_obj.apertures[aperture_found]['geometry'].append(deepcopy(dict_el))
@@ -621,10 +621,10 @@ class ToolFiducials(FlatCAMTool):
else:
new_apid = '10'
- g_obj.apertures[new_apid] = dict()
+ g_obj.apertures[new_apid] = {}
g_obj.apertures[new_apid]['type'] = 'C'
g_obj.apertures[new_apid]['size'] = line_thickness
- g_obj.apertures[new_apid]['geometry'] = list()
+ g_obj.apertures[new_apid]['geometry'] = []
for geo in geo_list:
geo_buff_h = geo[0].buffer(line_thickness / 2.0)
@@ -632,7 +632,7 @@ class ToolFiducials(FlatCAMTool):
geo_buff_list.append(geo_buff_h)
geo_buff_list.append(geo_buff_v)
- dict_el = dict()
+ dict_el = {}
dict_el['follow'] = geo_buff_h.centroid
dict_el['solid'] = geo_buff_h
g_obj.apertures[new_apid]['geometry'].append(deepcopy(dict_el))
@@ -640,7 +640,7 @@ class ToolFiducials(FlatCAMTool):
dict_el['solid'] = geo_buff_v
g_obj.apertures[new_apid]['geometry'].append(deepcopy(dict_el))
- s_list = list()
+ s_list = []
if g_obj.solid_geometry:
try:
for poly in g_obj.solid_geometry:
@@ -655,7 +655,7 @@ class ToolFiducials(FlatCAMTool):
g_obj.solid_geometry = MultiPolygon(s_list)
else:
# chess pattern fiducial type
- geo_list = list()
+ geo_list = []
def make_square_poly(center_pt, side_size):
half_s = side_size / 2
@@ -684,12 +684,12 @@ class ToolFiducials(FlatCAMTool):
aperture_found = ap_id
break
- geo_buff_list = list()
+ geo_buff_list = []
if aperture_found:
for geo in geo_list:
geo_buff_list.append(geo)
- dict_el = dict()
+ dict_el = {}
dict_el['follow'] = geo.centroid
dict_el['solid'] = geo
g_obj.apertures[aperture_found]['geometry'].append(deepcopy(dict_el))
@@ -700,22 +700,22 @@ class ToolFiducials(FlatCAMTool):
else:
new_apid = '10'
- g_obj.apertures[new_apid] = dict()
+ g_obj.apertures[new_apid] = {}
g_obj.apertures[new_apid]['type'] = 'R'
g_obj.apertures[new_apid]['size'] = new_ap_size
g_obj.apertures[new_apid]['width'] = fid_size
g_obj.apertures[new_apid]['height'] = fid_size
- g_obj.apertures[new_apid]['geometry'] = list()
+ g_obj.apertures[new_apid]['geometry'] = []
for geo in geo_list:
geo_buff_list.append(geo)
- dict_el = dict()
+ dict_el = {}
dict_el['follow'] = geo.centroid
dict_el['solid'] = geo
g_obj.apertures[new_apid]['geometry'].append(deepcopy(dict_el))
- s_list = list()
+ s_list = []
if g_obj.solid_geometry:
try:
for poly in g_obj.solid_geometry:
diff --git a/flatcamTools/ToolFilm.py b/flatcamTools/ToolFilm.py
index 4772d0ad..bf3af64a 100644
--- a/flatcamTools/ToolFilm.py
+++ b/flatcamTools/ToolFilm.py
@@ -434,7 +434,7 @@ class Film(FlatCAMTool):
self.pagesize_combo = FCComboBox()
- self.pagesize = dict()
+ self.pagesize = {}
self.pagesize.update(
{
'Bounds': None,
@@ -786,7 +786,7 @@ class Film(FlatCAMTool):
punch_size = float(self.punch_size_spinner.get_value())
- punching_geo = list()
+ punching_geo = []
for apid in film_obj.apertures:
if film_obj.apertures[apid]['type'] == 'C':
if punch_size >= float(film_obj.apertures[apid]['size']):
diff --git a/flatcamTools/ToolImage.py b/flatcamTools/ToolImage.py
index 3e8f2d57..8ac9ed89 100644
--- a/flatcamTools/ToolImage.py
+++ b/flatcamTools/ToolImage.py
@@ -223,7 +223,7 @@ class ToolImage(FlatCAMTool):
:type type_of_obj: str
:return: None
"""
- mask = list()
+ mask = []
self.app.log.debug("on_file_importimage()")
_filter = "Image Files(*.BMP *.PNG *.JPG *.JPEG);;" \
diff --git a/flatcamTools/ToolInvertGerber.py b/flatcamTools/ToolInvertGerber.py
index c4338b79..4d8e62c8 100644
--- a/flatcamTools/ToolInvertGerber.py
+++ b/flatcamTools/ToolInvertGerber.py
@@ -227,19 +227,19 @@ class ToolInvertGerber(FlatCAMTool):
for poly in grb_obj.solid_geometry:
new_solid_geometry = new_solid_geometry.difference(poly)
- new_options = dict()
+ new_options = {}
for opt in grb_obj.options:
new_options[opt] = deepcopy(grb_obj.options[opt])
- new_apertures = dict()
+ new_apertures = {}
# for apid, val in grb_obj.apertures.items():
- # new_apertures[apid] = dict()
+ # new_apertures[apid] = {}
# for key in val:
# if key == 'geometry':
- # new_apertures[apid]['geometry'] = list()
+ # new_apertures[apid]['geometry'] = []
# for elem in val['geometry']:
- # geo_elem = dict()
+ # geo_elem = {}
# if 'follow' in elem:
# try:
# geo_elem['clear'] = elem['follow'].buffer(val['size'] / 2.0).exterior
@@ -260,19 +260,19 @@ class ToolInvertGerber(FlatCAMTool):
# new_apertures[apid][key] = deepcopy(val[key])
if '0' not in new_apertures:
- new_apertures['0'] = dict()
+ new_apertures['0'] = {}
new_apertures['0']['type'] = 'C'
new_apertures['0']['size'] = 0.0
- new_apertures['0']['geometry'] = list()
+ new_apertures['0']['geometry'] = []
try:
for poly in new_solid_geometry:
- new_el = dict()
+ new_el = {}
new_el['solid'] = poly
new_el['follow'] = poly.exterior
new_apertures['0']['geometry'].append(new_el)
except TypeError:
- new_el = dict()
+ new_el = {}
new_el['solid'] = new_solid_geometry
new_el['follow'] = new_solid_geometry.exterior
new_apertures['0']['geometry'].append(new_el)
diff --git a/flatcamTools/ToolNCC.py b/flatcamTools/ToolNCC.py
index 021788eb..4b7c7253 100644
--- a/flatcamTools/ToolNCC.py
+++ b/flatcamTools/ToolNCC.py
@@ -625,22 +625,22 @@ class NonCopperClear(FlatCAMTool, Gerber):
# ########################## VARIABLES ########################################
# #############################################################################
self.units = ''
- self.ncc_tools = dict()
+ self.ncc_tools = {}
self.tooluid = 0
# store here the default data for Geometry Data
- self.default_data = dict()
+ self.default_data = {}
self.obj_name = ""
self.ncc_obj = None
- self.sel_rect = list()
+ self.sel_rect = []
self.bound_obj_name = ""
self.bound_obj = None
- self.ncc_dia_list = list()
- self.iso_dia_list = list()
+ self.ncc_dia_list = []
+ self.iso_dia_list = []
self.has_offset = None
self.o_name = None
self.overlap = None
@@ -656,10 +656,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.mr = None
# store here solid_geometry when there are tool with isolation job
- self.solid_geometry = list()
+ self.solid_geometry = []
self.select_method = None
- self.tool_type_item_options = list()
+ self.tool_type_item_options = []
self.grb_circle_steps = int(self.app.defaults["gerber_circle_steps"])
@@ -832,7 +832,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
row = 0
tooluid_item = int(self.tools_table.item(row, 3).text())
- temp_tool_data = dict()
+ temp_tool_data = {}
for tooluid_key, tooluid_val in self.ncc_tools.items():
if int(tooluid_key) == tooluid_item:
@@ -1143,7 +1143,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.ui_connect()
# set the text on tool_data_label after loading the object
- sel_rows = list()
+ sel_rows = []
sel_items = self.tools_table.selectedItems()
for it in sel_items:
sel_rows.append(it.row())
@@ -1550,9 +1550,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
return
# use the selected tools in the tool table; get diameters for non-copper clear
- self.iso_dia_list = list()
+ self.iso_dia_list = []
# use the selected tools in the tool table; get diameters for non-copper clear
- self.ncc_dia_list = list()
+ self.ncc_dia_list = []
if self.tools_table.selectedItems():
for x in self.tools_table.selectedItems():
try:
@@ -1834,7 +1834,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
bounding_box = cascaded_union(geo_buff_list)
elif ncc_select == _("Reference Object"):
if box_kind == 'geometry':
- geo_buff_list = list()
+ geo_buff_list = []
for poly in env_obj:
if self.app.abort_flag:
# graceful abort requested by the user
@@ -2223,7 +2223,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
p = p.buffer(0)
if p is not None and p.is_valid:
- poly_processed = list()
+ poly_processed = []
try:
for pol in p:
if pol is not None and isinstance(pol, Polygon):
@@ -2368,7 +2368,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
return
# create the solid_geometry
- geo_obj.solid_geometry = list()
+ geo_obj.solid_geometry = []
for tooluid in geo_obj.tools:
if geo_obj.tools[tooluid]['solid_geometry']:
try:
@@ -2653,7 +2653,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
return
# create the solid_geometry
- geo_obj.solid_geometry = list()
+ geo_obj.solid_geometry = []
for tooluid in geo_obj.tools:
if geo_obj.tools[tooluid]['solid_geometry']:
try:
@@ -2961,7 +2961,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
milling_type = self.app.defaults["tools_nccmilling_type"]
for tool_iso in isotooldia:
- new_geometry = list()
+ new_geometry = []
if milling_type == 'cl':
isolated_geo = self.generate_envelope(tool_iso / 2, 1)
@@ -3129,7 +3129,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
p = p.buffer(0)
if p is not None and p.is_valid:
- poly_processed = list()
+ poly_processed = []
try:
for pol in p:
if pol is not None and isinstance(pol, Polygon):
@@ -3267,7 +3267,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
return
# create the solid_geometry
- geo_obj.solid_geometry = list()
+ geo_obj.solid_geometry = []
for tooluid in geo_obj.tools:
if geo_obj.tools[tooluid]['solid_geometry']:
try:
@@ -3650,7 +3650,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
return
# create the solid_geometry
- geo_obj.solid_geometry = list()
+ geo_obj.solid_geometry = []
for tooluid in geo_obj.tools:
if geo_obj.tools[tooluid]['solid_geometry']:
try:
diff --git a/flatcamTools/ToolOptimal.py b/flatcamTools/ToolOptimal.py
index 5160fc81..16c00efa 100644
--- a/flatcamTools/ToolOptimal.py
+++ b/flatcamTools/ToolOptimal.py
@@ -259,7 +259,7 @@ class ToolOptimal(FlatCAMTool):
# dict to hold the distances between every two elements in Gerber as keys and the actual locations where that
# distances happen as values
- self.min_dict = dict()
+ self.min_dict = {}
# ############################################################################
# ############################ Signals #######################################
@@ -354,7 +354,7 @@ class ToolOptimal(FlatCAMTool):
old_disp_number = 0
pol_nr = 0
app_obj.proc_container.update_view_text(' %d%%' % 0)
- total_geo = list()
+ total_geo = []
for ap in list(fcobj.apertures.keys()):
if 'geometry' in fcobj.apertures[ap]:
@@ -388,7 +388,7 @@ class ToolOptimal(FlatCAMTool):
'%s: %s' % (_("Optimal Tool. Finding the distances between each two elements. Iterations"),
str(geo_len)))
- self.min_dict = dict()
+ self.min_dict = {}
idx = 1
for geo in total_geo:
for s_geo in total_geo[idx:]:
diff --git a/flatcamTools/ToolPDF.py b/flatcamTools/ToolPDF.py
index 9c8c1812..e5db0001 100644
--- a/flatcamTools/ToolPDF.py
+++ b/flatcamTools/ToolPDF.py
@@ -105,7 +105,7 @@ class ToolPDF(FlatCAMTool):
self.restore_gs_re = re.compile(r'^.*Q.*$')
# graphic stack where we save parameters like transformation, line_width
- self.gs = dict()
+ self.gs = {}
# each element is a list composed of sublist elements
# (each sublist has 2 lists each having 2 elements: first is offset like:
# offset_geo = [off_x, off_y], second element is scale list with 2 elements, like: scale_geo = [sc_x, sc_yy])
@@ -434,12 +434,12 @@ class ToolPDF(FlatCAMTool):
traceback.print_exc()
def parse_pdf(self, pdf_content):
- path = dict()
+ path = {}
path['lines'] = [] # it's a list of lines subpaths
path['bezier'] = [] # it's a list of bezier arcs subpaths
path['rectangle'] = [] # it's a list of rectangle subpaths
- subpath = dict()
+ subpath = {}
subpath['lines'] = [] # it's a list of points
subpath['bezier'] = [] # it's a list of sublists each like this [start, c1, c2, stop]
subpath['rectangle'] = [] # it's a list of sublists of points
@@ -473,9 +473,9 @@ class ToolPDF(FlatCAMTool):
# store the apertures with clear geometry here
# we are interested only in the circular geometry (drill holes) therefore we target only Bezier subpaths
- clear_apertures_dict = dict()
+ clear_apertures_dict = {}
# everything will be stored in the '0' aperture since we are dealing with clear polygons not strokes
- clear_apertures_dict['0'] = dict()
+ clear_apertures_dict['0'] = {}
clear_apertures_dict['0']['size'] = 0.0
clear_apertures_dict['0']['type'] = 'C'
clear_apertures_dict['0']['geometry'] = []
@@ -515,7 +515,7 @@ class ToolPDF(FlatCAMTool):
apertures_dict.clear()
layer_nr += 1
- object_dict[layer_nr] = dict()
+ object_dict[layer_nr] = {}
old_color = copy(color)
# we make sure that the following geometry is added to the right storage
flag_clear_geo = False
@@ -778,7 +778,7 @@ class ToolPDF(FlatCAMTool):
if match:
# scale the size here; some PDF printers apply transformation after the size is declared
applied_size = size * scale_geo[0] * self.point_to_unit_factor
- path_geo = list()
+ path_geo = []
if current_subpath == 'lines':
if path['lines']:
for subp in path['lines']:
@@ -859,12 +859,12 @@ class ToolPDF(FlatCAMTool):
for pdf_geo in path_geo:
if isinstance(pdf_geo, MultiPolygon):
for poly in pdf_geo:
- new_el = dict()
+ new_el = {}
new_el['solid'] = poly
new_el['follow'] = poly.exterior
apertures_dict[copy(found_aperture)]['geometry'].append(deepcopy(new_el))
else:
- new_el = dict()
+ new_el = {}
new_el['solid'] = pdf_geo
new_el['follow'] = pdf_geo.exterior
apertures_dict[copy(found_aperture)]['geometry'].append(deepcopy(new_el))
@@ -879,12 +879,12 @@ class ToolPDF(FlatCAMTool):
for pdf_geo in path_geo:
if isinstance(pdf_geo, MultiPolygon):
for poly in pdf_geo:
- new_el = dict()
+ new_el = {}
new_el['solid'] = poly
new_el['follow'] = poly.exterior
apertures_dict[str(aperture)]['geometry'].append(deepcopy(new_el))
else:
- new_el = dict()
+ new_el = {}
new_el['solid'] = pdf_geo
new_el['follow'] = pdf_geo.exterior
apertures_dict[str(aperture)]['geometry'].append(deepcopy(new_el))
@@ -896,12 +896,12 @@ class ToolPDF(FlatCAMTool):
for pdf_geo in path_geo:
if isinstance(pdf_geo, MultiPolygon):
for poly in pdf_geo:
- new_el = dict()
+ new_el = {}
new_el['solid'] = poly
new_el['follow'] = poly.exterior
apertures_dict[str(aperture)]['geometry'].append(deepcopy(new_el))
else:
- new_el = dict()
+ new_el = {}
new_el['solid'] = pdf_geo
new_el['follow'] = pdf_geo.exterior
apertures_dict[str(aperture)]['geometry'].append(deepcopy(new_el))
@@ -913,7 +913,7 @@ class ToolPDF(FlatCAMTool):
if match:
# scale the size here; some PDF printers apply transformation after the size is declared
applied_size = size * scale_geo[0] * self.point_to_unit_factor
- path_geo = list()
+ path_geo = []
if current_subpath == 'lines':
if path['lines']:
@@ -1007,11 +1007,11 @@ class ToolPDF(FlatCAMTool):
if path_geo:
try:
for g in path_geo:
- new_el = dict()
+ new_el = {}
new_el['clear'] = g
clear_apertures_dict['0']['geometry'].append(new_el)
except TypeError:
- new_el = dict()
+ new_el = {}
new_el['clear'] = path_geo
clear_apertures_dict['0']['geometry'].append(new_el)
@@ -1022,11 +1022,11 @@ class ToolPDF(FlatCAMTool):
for pdf_geo in path_geo:
if isinstance(pdf_geo, MultiPolygon):
for poly in pdf_geo:
- new_el = dict()
+ new_el = {}
new_el['clear'] = poly
apertures_dict['0']['geometry'].append(deepcopy(new_el))
else:
- new_el = dict()
+ new_el = {}
new_el['clear'] = pdf_geo
apertures_dict['0']['geometry'].append(deepcopy(new_el))
except KeyError:
@@ -1038,11 +1038,11 @@ class ToolPDF(FlatCAMTool):
for pdf_geo in path_geo:
if isinstance(pdf_geo, MultiPolygon):
for poly in pdf_geo:
- new_el = dict()
+ new_el = {}
new_el['clear'] = poly
apertures_dict['0']['geometry'].append(deepcopy(new_el))
else:
- new_el = dict()
+ new_el = {}
new_el['clear'] = pdf_geo
apertures_dict['0']['geometry'].append(deepcopy(new_el))
else:
@@ -1051,12 +1051,12 @@ class ToolPDF(FlatCAMTool):
for pdf_geo in path_geo:
if isinstance(pdf_geo, MultiPolygon):
for poly in pdf_geo:
- new_el = dict()
+ new_el = {}
new_el['solid'] = poly
new_el['follow'] = poly.exterior
apertures_dict['0']['geometry'].append(deepcopy(new_el))
else:
- new_el = dict()
+ new_el = {}
new_el['solid'] = pdf_geo
new_el['follow'] = pdf_geo.exterior
apertures_dict['0']['geometry'].append(deepcopy(new_el))
@@ -1069,12 +1069,12 @@ class ToolPDF(FlatCAMTool):
for pdf_geo in path_geo:
if isinstance(pdf_geo, MultiPolygon):
for poly in pdf_geo:
- new_el = dict()
+ new_el = {}
new_el['solid'] = poly
new_el['follow'] = poly.exterior
apertures_dict['0']['geometry'].append(deepcopy(new_el))
else:
- new_el = dict()
+ new_el = {}
new_el['solid'] = pdf_geo
new_el['follow'] = pdf_geo.exterior
apertures_dict['0']['geometry'].append(deepcopy(new_el))
@@ -1085,8 +1085,8 @@ class ToolPDF(FlatCAMTool):
if match:
# scale the size here; some PDF printers apply transformation after the size is declared
applied_size = size * scale_geo[0] * self.point_to_unit_factor
- path_geo = list()
- fill_geo = list()
+ path_geo = []
+ fill_geo = []
if current_subpath == 'lines':
if path['lines']:
@@ -1222,12 +1222,12 @@ class ToolPDF(FlatCAMTool):
for pdf_geo in path_geo:
if isinstance(pdf_geo, MultiPolygon):
for poly in pdf_geo:
- new_el = dict()
+ new_el = {}
new_el['solid'] = poly
new_el['follow'] = poly.exterior
apertures_dict[copy(found_aperture)]['geometry'].append(deepcopy(new_el))
else:
- new_el = dict()
+ new_el = {}
new_el['solid'] = pdf_geo
new_el['follow'] = pdf_geo.exterior
apertures_dict[copy(found_aperture)]['geometry'].append(deepcopy(new_el))
@@ -1242,12 +1242,12 @@ class ToolPDF(FlatCAMTool):
for pdf_geo in path_geo:
if isinstance(pdf_geo, MultiPolygon):
for poly in pdf_geo:
- new_el = dict()
+ new_el = {}
new_el['solid'] = poly
new_el['follow'] = poly.exterior
apertures_dict[str(aperture)]['geometry'].append(deepcopy(new_el))
else:
- new_el = dict()
+ new_el = {}
new_el['solid'] = pdf_geo
new_el['follow'] = pdf_geo.exterior
apertures_dict[str(aperture)]['geometry'].append(deepcopy(new_el))
@@ -1259,12 +1259,12 @@ class ToolPDF(FlatCAMTool):
for pdf_geo in path_geo:
if isinstance(pdf_geo, MultiPolygon):
for poly in pdf_geo:
- new_el = dict()
+ new_el = {}
new_el['solid'] = poly
new_el['follow'] = poly.exterior
apertures_dict[str(aperture)]['geometry'].append(deepcopy(new_el))
else:
- new_el = dict()
+ new_el = {}
new_el['solid'] = pdf_geo
new_el['follow'] = pdf_geo.exterior
apertures_dict[str(aperture)]['geometry'].append(deepcopy(new_el))
@@ -1279,11 +1279,11 @@ class ToolPDF(FlatCAMTool):
for pdf_geo in path_geo:
if isinstance(pdf_geo, MultiPolygon):
for poly in fill_geo:
- new_el = dict()
+ new_el = {}
new_el['clear'] = poly
apertures_dict['0']['geometry'].append(deepcopy(new_el))
else:
- new_el = dict()
+ new_el = {}
new_el['clear'] = pdf_geo
apertures_dict['0']['geometry'].append(deepcopy(new_el))
except KeyError:
@@ -1295,11 +1295,11 @@ class ToolPDF(FlatCAMTool):
for pdf_geo in fill_geo:
if isinstance(pdf_geo, MultiPolygon):
for poly in pdf_geo:
- new_el = dict()
+ new_el = {}
new_el['clear'] = poly
apertures_dict['0']['geometry'].append(deepcopy(new_el))
else:
- new_el = dict()
+ new_el = {}
new_el['clear'] = pdf_geo
apertures_dict['0']['geometry'].append(deepcopy(new_el))
else:
@@ -1307,12 +1307,12 @@ class ToolPDF(FlatCAMTool):
for pdf_geo in path_geo:
if isinstance(pdf_geo, MultiPolygon):
for poly in fill_geo:
- new_el = dict()
+ new_el = {}
new_el['solid'] = poly
new_el['follow'] = poly.exterior
apertures_dict['0']['geometry'].append(deepcopy(new_el))
else:
- new_el = dict()
+ new_el = {}
new_el['solid'] = pdf_geo
new_el['follow'] = pdf_geo.exterior
apertures_dict['0']['geometry'].append(deepcopy(new_el))
@@ -1325,12 +1325,12 @@ class ToolPDF(FlatCAMTool):
for pdf_geo in fill_geo:
if isinstance(pdf_geo, MultiPolygon):
for poly in pdf_geo:
- new_el = dict()
+ new_el = {}
new_el['solid'] = poly
new_el['follow'] = poly.exterior
apertures_dict['0']['geometry'].append(deepcopy(new_el))
else:
- new_el = dict()
+ new_el = {}
new_el['solid'] = pdf_geo
new_el['follow'] = pdf_geo.exterior
apertures_dict['0']['geometry'].append(deepcopy(new_el))
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 8cb957b9..7f9a8c27 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -561,7 +561,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.bound_obj_name = ""
self.bound_obj = None
- self.tooldia_list = list()
+ self.tooldia_list = []
self.tooldia = None
self.sel_rect = None
@@ -572,7 +572,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.select_method = None
self.units = ''
- self.paint_tools = dict()
+ self.paint_tools = {}
self.tooluid = 0
self.first_click = False
self.cursor_pos = None
@@ -582,16 +582,16 @@ class ToolPaint(FlatCAMTool, Gerber):
self.mp = None
self.mr = None
- self.sel_rect = list()
+ self.sel_rect = []
# store here if the grid snapping is active
self.grid_status_memory = False
# dict to store the polygons selected for painting; key is the shape added to be plotted and value is the poly
- self.poly_dict = dict()
+ self.poly_dict = {}
# store here the default data for Geometry Data
- self.default_data = dict()
+ self.default_data = {}
self.tool_type_item_options = ["C1", "C2", "C3", "C4", "B", "V"]
@@ -794,7 +794,7 @@ class ToolPaint(FlatCAMTool, Gerber):
row = 0
tooluid_item = int(self.tools_table.item(row, 3).text())
- temp_tool_data = dict()
+ temp_tool_data = {}
for tooluid_key, tooluid_val in self.paint_tools.items():
if int(tooluid_key) == tooluid_item:
@@ -1352,7 +1352,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.o_name = '%s_mt_paint' % self.obj_name
# use the selected tools in the tool table; get diameters
- self.tooldia_list = list()
+ self.tooldia_list = []
if self.tools_table.selectedItems():
for x in self.tools_table.selectedItems():
try:
@@ -1739,7 +1739,7 @@ class ToolPaint(FlatCAMTool, Gerber):
# Initializes the new geometry object
def gen_paintarea(geo_obj, app_obj):
- geo_obj.solid_geometry = list()
+ geo_obj.solid_geometry = []
def paint_p(polyg, tooldiameter):
cpoly = None
@@ -1779,9 +1779,9 @@ class ToolPaint(FlatCAMTool, Gerber):
# aperture_size = None
# the key is the aperture type and the val is a list of geo elements
- flash_el_dict = dict()
+ flash_el_dict = {}
# the key is the aperture size, the val is a list of geo elements
- traces_el_dict = dict()
+ traces_el_dict = {}
# find the flashes and the lines that are in the selected polygon and store them separately
for apid, apval in obj.apertures.items():
@@ -1818,7 +1818,7 @@ class ToolPaint(FlatCAMTool, Gerber):
traces_el_dict[aperture_size] = [geo_el]
cpoly = FlatCAMRTreeStorage()
- pads_lines_list = list()
+ pads_lines_list = []
# process the flashes found in the selected polygon with the 'lines' method for rectangular
# flashes and with _("Seed") for oblong and circular flashes
@@ -1868,7 +1868,7 @@ class ToolPaint(FlatCAMTool, Gerber):
except TypeError:
cpoly.insert(pads_lines_list)
- copper_lines_list = list()
+ copper_lines_list = []
# process the traces found in the selected polygon using the 'laser_lines' method,
# method which will follow the 'follow' line therefore use the longer path possible for the
# laser, therefore the acceleration will play a smaller factor
@@ -1976,14 +1976,14 @@ class ToolPaint(FlatCAMTool, Gerber):
try:
poly_buf = [pol.buffer(-paint_margin) for pol in polygon_list]
- cp = list()
+ cp = []
try:
for pp in poly_buf:
cp.append(paint_p(pp, tooldiameter=tool_dia))
except TypeError:
cp = paint_p(poly_buf, tooldiameter=tool_dia)
- total_geometry = list()
+ total_geometry = []
if cp:
try:
for x in cp:
@@ -2289,7 +2289,7 @@ class ToolPaint(FlatCAMTool, Gerber):
poly_buf = geo.buffer(-paint_margin)
if geo is not None and geo.is_valid:
- poly_processed = list()
+ poly_processed = []
try:
for pol in poly_buf:
if pol is not None and isinstance(pol, Polygon):
@@ -2326,9 +2326,9 @@ class ToolPaint(FlatCAMTool, Gerber):
# aperture_size = None
# the key is the aperture type and the val is a list of geo elements
- flash_el_dict = dict()
+ flash_el_dict = {}
# the key is the aperture size, the val is a list of geo elements
- traces_el_dict = dict()
+ traces_el_dict = {}
# find the flashes and the lines that are in the selected polygon and store
# them separately
@@ -2366,7 +2366,7 @@ class ToolPaint(FlatCAMTool, Gerber):
traces_el_dict[aperture_size] = [geo_el]
cp = FlatCAMRTreeStorage()
- pads_lines_list = list()
+ pads_lines_list = []
# process the flashes found in the selected polygon with the 'lines' method
# for rectangular flashes and with _("Seed") for oblong and circular flashes
@@ -2417,7 +2417,7 @@ class ToolPaint(FlatCAMTool, Gerber):
except TypeError:
cp.insert(pads_lines_list)
- copper_lines_list = list()
+ copper_lines_list = []
# process the traces found in the selected polygon using the 'laser_lines'
# method, method which will follow the 'follow' line therefore use the longer
# path possible for the laser, therefore the acceleration will play
@@ -2528,9 +2528,9 @@ class ToolPaint(FlatCAMTool, Gerber):
# aperture_size = None
# the key is the aperture type and the val is a list of geo elements
- flash_el_dict = dict()
+ flash_el_dict = {}
# the key is the aperture size, the val is a list of geo elements
- traces_el_dict = dict()
+ traces_el_dict = {}
# find the flashes and the lines that are in the selected polygon and store
# them separately
@@ -2568,7 +2568,7 @@ class ToolPaint(FlatCAMTool, Gerber):
traces_el_dict[aperture_size] = [geo_el]
cp = FlatCAMRTreeStorage()
- pads_lines_list = list()
+ pads_lines_list = []
# process the flashes found in the selected polygon with the 'lines' method
# for rectangular flashes and with _("Seed") for oblong and circular flashes
@@ -2619,7 +2619,7 @@ class ToolPaint(FlatCAMTool, Gerber):
except TypeError:
cp.insert(pads_lines_list)
- copper_lines_list = list()
+ copper_lines_list = []
# process the traces found in the selected polygon using the 'laser_lines'
# method, method which will follow the 'follow' line therefore use the longer
# path possible for the laser, therefore the acceleration will play
@@ -2906,9 +2906,9 @@ class ToolPaint(FlatCAMTool, Gerber):
# aperture_size = None
# the key is the aperture type and the val is a list of geo elements
- flash_el_dict = dict()
+ flash_el_dict = {}
# the key is the aperture size, the val is a list of geo elements
- traces_el_dict = dict()
+ traces_el_dict = {}
# find the flashes and the lines that are in the selected polygon and store
# them separately
@@ -2946,7 +2946,7 @@ class ToolPaint(FlatCAMTool, Gerber):
traces_el_dict[aperture_size] = [geo_el]
cp = FlatCAMRTreeStorage()
- pads_lines_list = list()
+ pads_lines_list = []
# process the flashes found in the selected polygon with the 'lines' method
# for rectangular flashes and with _("Seed") for oblong and circular flashes
@@ -2997,7 +2997,7 @@ class ToolPaint(FlatCAMTool, Gerber):
except TypeError:
cp.insert(pads_lines_list)
- copper_lines_list = list()
+ copper_lines_list = []
# process the traces found in the selected polygon using the 'laser_lines'
# method, method which will follow the 'follow' line therefore use the longer
# path possible for the laser, therefore the acceleration will play
@@ -3386,9 +3386,9 @@ class ToolPaint(FlatCAMTool, Gerber):
# aperture_size = None
# the key is the aperture type and the val is a list of geo elements
- flash_el_dict = dict()
+ flash_el_dict = {}
# the key is the aperture size, the val is a list of geo elements
- traces_el_dict = dict()
+ traces_el_dict = {}
# find the flashes and the lines that are in the selected polygon and store
# them separately
@@ -3426,7 +3426,7 @@ class ToolPaint(FlatCAMTool, Gerber):
traces_el_dict[aperture_size] = [geo_el]
cp = FlatCAMRTreeStorage()
- pads_lines_list = list()
+ pads_lines_list = []
# process the flashes found in the selected polygon with the 'lines' method
# for rectangular flashes and with _("Seed") for oblong and circular flashes
@@ -3477,7 +3477,7 @@ class ToolPaint(FlatCAMTool, Gerber):
except TypeError:
cp.insert(pads_lines_list)
- copper_lines_list = list()
+ copper_lines_list = []
# process the traces found in the selected polygon using the 'laser_lines'
# method, method which will follow the 'follow' line therefore use the longer
# path possible for the laser, therefore the acceleration will play
@@ -3706,9 +3706,9 @@ class ToolPaint(FlatCAMTool, Gerber):
# aperture_size = None
# the key is the aperture type and the val is a list of geo elements
- flash_el_dict = dict()
+ flash_el_dict = {}
# the key is the aperture size, the val is a list of geo elements
- copper_el_dict = dict()
+ copper_el_dict = {}
# find the flashes and the lines that are in the selected polygon and store
# them separately
@@ -3746,7 +3746,7 @@ class ToolPaint(FlatCAMTool, Gerber):
copper_el_dict[aperture_size] = [geo_el]
cp = FlatCAMRTreeStorage()
- pads_lines_list = list()
+ pads_lines_list = []
# process the flashes found in the selected polygon with the 'lines' method
# for rectangular flashes and with _("Seed") for oblong and circular flashes
@@ -3797,7 +3797,7 @@ class ToolPaint(FlatCAMTool, Gerber):
except TypeError:
cp.insert(pads_lines_list)
- copper_lines_list = list()
+ copper_lines_list = []
# process the traces found in the selected polygon using the 'laser_lines'
# method, method which will follow the 'follow' line therefore use the longer
# path possible for the laser, therefore the acceleration will play
diff --git a/flatcamTools/ToolPanelize.py b/flatcamTools/ToolPanelize.py
index 8aeddabf..9494c2d0 100644
--- a/flatcamTools/ToolPanelize.py
+++ b/flatcamTools/ToolPanelize.py
@@ -473,13 +473,13 @@ class Panelize(FlatCAMTool):
if isinstance(panel_obj, FlatCAMExcellon) or isinstance(panel_obj, FlatCAMGeometry):
# make a copy of the panelized Excellon or Geometry tools
- copied_tools = dict()
+ copied_tools = {}
for tt, tt_val in list(panel_obj.tools.items()):
copied_tools[tt] = deepcopy(tt_val)
if isinstance(panel_obj, FlatCAMGerber):
# make a copy of the panelized Gerber apertures
- copied_apertures = dict()
+ copied_apertures = {}
for tt, tt_val in list(panel_obj.apertures.items()):
copied_apertures[tt] = deepcopy(tt_val)
@@ -577,7 +577,7 @@ class Panelize(FlatCAMTool):
def translate_recursion(geom):
if type(geom) == list:
- geoms = list()
+ geoms = []
for local_geom in geom:
res_geo = translate_recursion(local_geom)
try:
@@ -600,7 +600,7 @@ class Panelize(FlatCAMTool):
elif isinstance(panel_obj, FlatCAMGerber):
obj_fin.apertures = copied_apertures
for ap in obj_fin.apertures:
- obj_fin.apertures[ap]['geometry'] = list()
+ obj_fin.apertures[ap]['geometry'] = []
# find the number of polygons in the source solid_geometry
geo_len = 0
@@ -736,7 +736,7 @@ class Panelize(FlatCAMTool):
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
- new_el = dict()
+ new_el = {}
if 'solid' in el:
geo_aper = translate_recursion(el['solid'])
new_el['solid'] = geo_aper
diff --git a/flatcamTools/ToolProperties.py b/flatcamTools/ToolProperties.py
index 78e48afc..b09d6e19 100644
--- a/flatcamTools/ToolProperties.py
+++ b/flatcamTools/ToolProperties.py
@@ -277,7 +277,7 @@ class Properties(FlatCAMTool):
# calculate copper area
# create a complete solid_geometry from the tools
- geo_tools = list()
+ geo_tools = []
for tool_k in obj_prop.tools:
if 'solid_geometry' in obj_prop.tools[tool_k]:
for geo_el in obj_prop.tools[tool_k]['solid_geometry']:
@@ -351,7 +351,7 @@ class Properties(FlatCAMTool):
# Items that depend on the object type
if obj.kind.lower() == 'gerber':
- temp_ap = dict()
+ temp_ap = {}
for ap in obj.apertures:
temp_ap.clear()
temp_ap = deepcopy(obj.apertures[ap])
diff --git a/flatcamTools/ToolPunchGerber.py b/flatcamTools/ToolPunchGerber.py
index b0f5c326..660dae7f 100644
--- a/flatcamTools/ToolPunchGerber.py
+++ b/flatcamTools/ToolPunchGerber.py
@@ -515,7 +515,7 @@ class ToolPunchGerber(FlatCAMTool):
punch_method = self.method_punch.get_value()
- new_options = dict()
+ new_options = {}
for opt in grb_obj.options:
new_options[opt] = deepcopy(grb_obj.options[opt])
@@ -549,7 +549,7 @@ class ToolPunchGerber(FlatCAMTool):
new_apid = max([int(x) for x, __ in new_apertures_items])
# store here the clear geometry, the key is the drill size
- holes_apertures = dict()
+ holes_apertures = {}
for apid, val in new_apertures_items:
for elem in val['geometry']:
@@ -560,14 +560,14 @@ class ToolPunchGerber(FlatCAMTool):
# since there may be drills that do not drill into a pad we test only for drills in a pad
if drill['point'].within(elem['solid']):
- geo_elem = dict()
+ geo_elem = {}
geo_elem['clear'] = drill['point']
if clear_apid_size not in holes_apertures:
- holes_apertures[clear_apid_size] = dict()
+ holes_apertures[clear_apid_size] = {}
holes_apertures[clear_apid_size]['type'] = 'C'
holes_apertures[clear_apid_size]['size'] = clear_apid_size
- holes_apertures[clear_apid_size]['geometry'] = list()
+ holes_apertures[clear_apid_size]['geometry'] = []
holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem))
@@ -597,7 +597,7 @@ class ToolPunchGerber(FlatCAMTool):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("The value of the fixed diameter is 0.0. Aborting."))
return 'fail'
- punching_geo = list()
+ punching_geo = []
for apid in grb_obj.apertures:
if grb_obj.apertures[apid]['type'] == 'C' and self.circular_cb.get_value():
if punch_size >= float(grb_obj.apertures[apid]['size']):
@@ -663,7 +663,7 @@ class ToolPunchGerber(FlatCAMTool):
new_apid = max([int(x) for x, __ in new_apertures_items])
# store here the clear geometry, the key is the drill size
- holes_apertures = dict()
+ holes_apertures = {}
for apid, val in new_apertures_items:
for elem in val['geometry']:
@@ -674,14 +674,14 @@ class ToolPunchGerber(FlatCAMTool):
# since there may be drills that do not drill into a pad we test only for drills in a pad
if geo.within(elem['solid']):
- geo_elem = dict()
+ geo_elem = {}
geo_elem['clear'] = geo.centroid
if clear_apid_size not in holes_apertures:
- holes_apertures[clear_apid_size] = dict()
+ holes_apertures[clear_apid_size] = {}
holes_apertures[clear_apid_size]['type'] = 'C'
holes_apertures[clear_apid_size]['size'] = clear_apid_size
- holes_apertures[clear_apid_size]['geometry'] = list()
+ holes_apertures[clear_apid_size]['geometry'] = []
holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem))
@@ -727,11 +727,11 @@ class ToolPunchGerber(FlatCAMTool):
new_apid = max([int(x) for x, __ in new_apertures_items])
# store here the clear geometry, the key is the new aperture size
- holes_apertures = dict()
+ holes_apertures = {}
for apid, apid_value in grb_obj.apertures.items():
ap_type = apid_value['type']
- punching_geo = list()
+ punching_geo = []
if ap_type == 'C' and self.circular_cb.get_value():
dia = float(apid_value['size']) - (2 * circ_r_val)
@@ -816,14 +816,14 @@ class ToolPunchGerber(FlatCAMTool):
# since there may be drills that do not drill into a pad we test only for geos in a pad
if geo.within(elem['solid']):
- geo_elem = dict()
+ geo_elem = {}
geo_elem['clear'] = geo.centroid
if clear_apid_size not in holes_apertures:
- holes_apertures[clear_apid_size] = dict()
+ holes_apertures[clear_apid_size] = {}
holes_apertures[clear_apid_size]['type'] = 'C'
holes_apertures[clear_apid_size]['size'] = clear_apid_size
- holes_apertures[clear_apid_size]['geometry'] = list()
+ holes_apertures[clear_apid_size]['geometry'] = []
holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem))
@@ -866,11 +866,11 @@ class ToolPunchGerber(FlatCAMTool):
new_apid = max([int(x) for x, __ in new_apertures_items])
# store here the clear geometry, the key is the new aperture size
- holes_apertures = dict()
+ holes_apertures = {}
for apid, apid_value in grb_obj.apertures.items():
ap_type = apid_value['type']
- punching_geo = list()
+ punching_geo = []
if ap_type == 'C' and self.circular_cb.get_value():
dia = float(apid_value['size']) * prop_factor
@@ -955,14 +955,14 @@ class ToolPunchGerber(FlatCAMTool):
# since there may be drills that do not drill into a pad we test only for geos in a pad
if geo.within(elem['solid']):
- geo_elem = dict()
+ geo_elem = {}
geo_elem['clear'] = geo.centroid
if clear_apid_size not in holes_apertures:
- holes_apertures[clear_apid_size] = dict()
+ holes_apertures[clear_apid_size] = {}
holes_apertures[clear_apid_size]['type'] = 'C'
holes_apertures[clear_apid_size]['size'] = clear_apid_size
- holes_apertures[clear_apid_size]['geometry'] = list()
+ holes_apertures[clear_apid_size]['geometry'] = []
holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem))
diff --git a/flatcamTools/ToolQRCode.py b/flatcamTools/ToolQRCode.py
index 5e9b8ff0..2486ba7f 100644
--- a/flatcamTools/ToolQRCode.py
+++ b/flatcamTools/ToolQRCode.py
@@ -496,7 +496,7 @@ class QRCode(FlatCAMTool):
mask_geo = box(a, b, c, d).buffer(buff_val, join_style=2)
# update the solid geometry with the cutout (if it is the case)
- new_solid_geometry = list()
+ new_solid_geometry = []
offset_mask_geo = translate(mask_geo, xoff=pos[0], yoff=pos[1])
for poly in geo_list:
if poly.contains(offset_mask_geo):
@@ -523,7 +523,7 @@ class QRCode(FlatCAMTool):
box_size = float(self.bsize_entry.get_value()) / 10.0
- sort_apid = list()
+ sort_apid = []
new_apid = '10'
if self.grb_object.apertures:
for k, v in list(self.grb_object.apertures.items()):
@@ -537,8 +537,8 @@ class QRCode(FlatCAMTool):
# don't know if the condition is required since I already made sure above that the new_apid is a new one
if new_apid not in self.grb_object.apertures:
- self.grb_object.apertures[new_apid] = dict()
- self.grb_object.apertures[new_apid]['geometry'] = list()
+ self.grb_object.apertures[new_apid] = {}
+ self.grb_object.apertures[new_apid]['geometry'] = []
self.grb_object.apertures[new_apid]['type'] = 'R'
# TODO: HACK
# I've artificially added 1% to the height and width because otherwise after loading the
@@ -549,14 +549,14 @@ class QRCode(FlatCAMTool):
self.grb_object.apertures[new_apid]['size'] = deepcopy(math.sqrt(box_size ** 2 + box_size ** 2))
if '0' not in self.grb_object.apertures:
- self.grb_object.apertures['0'] = dict()
- self.grb_object.apertures['0']['geometry'] = list()
+ self.grb_object.apertures['0'] = {}
+ self.grb_object.apertures['0']['geometry'] = []
self.grb_object.apertures['0']['type'] = 'REG'
self.grb_object.apertures['0']['size'] = 0.0
# in case that the QRCode geometry is dropped onto a copper region (found in the '0' aperture)
# make sure that I place a cutout there
- zero_elem = dict()
+ zero_elem = {}
zero_elem['clear'] = offset_mask_geo
self.grb_object.apertures['0']['geometry'].append(deepcopy(zero_elem))
@@ -571,12 +571,12 @@ class QRCode(FlatCAMTool):
try:
for geo in self.qrcode_geometry:
- geo_elem = dict()
+ geo_elem = {}
geo_elem['solid'] = translate(geo, xoff=pos[0], yoff=pos[1])
geo_elem['follow'] = translate(geo.centroid, xoff=pos[0], yoff=pos[1])
self.grb_object.apertures[new_apid]['geometry'].append(deepcopy(geo_elem))
except TypeError:
- geo_elem = dict()
+ geo_elem = {}
geo_elem['solid'] = self.qrcode_geometry
self.grb_object.apertures[new_apid]['geometry'].append(deepcopy(geo_elem))
@@ -592,7 +592,7 @@ class QRCode(FlatCAMTool):
# face = '#0000FF' + str(hex(int(0.2 * 255)))[2:]
outline = '#0000FFAF'
- offset_geo = list()
+ offset_geo = []
# I use the len of self.qrcode_geometry instead of the utility one because the complexity of the polygons is
# better seen in this (bit what if the sel.qrcode_geometry is just one geo element? len will fail ...
diff --git a/flatcamTools/ToolRulesCheck.py b/flatcamTools/ToolRulesCheck.py
index 39561ef2..ffd5844d 100644
--- a/flatcamTools/ToolRulesCheck.py
+++ b/flatcamTools/ToolRulesCheck.py
@@ -655,8 +655,8 @@ class RulesCheck(FlatCAMTool):
rule_title = rule
- violations = list()
- obj_violations = dict()
+ violations = []
+ obj_violations = {}
obj_violations.update({
'name': '',
'points': list()
@@ -667,8 +667,8 @@ class RulesCheck(FlatCAMTool):
obj_violations['name'] = gerber_obj['name']
- solid_geo = list()
- clear_geo = list()
+ solid_geo = []
+ clear_geo = []
for apid in gerber_obj['apertures']:
if 'geometry' in gerber_obj['apertures'][apid]:
geometry = gerber_obj['apertures'][apid]['geometry']
@@ -679,7 +679,7 @@ class RulesCheck(FlatCAMTool):
clear_geo.append(geo_el['clear'])
if clear_geo:
- total_geo = list()
+ total_geo = []
for geo_c in clear_geo:
for geo_s in solid_geo:
if geo_c.within(geo_s):
@@ -696,7 +696,7 @@ class RulesCheck(FlatCAMTool):
iterations = (iterations * (iterations - 1)) / 2
log.debug("RulesCheck.check_gerber_clearance(). Iterations: %s" % str(iterations))
- min_dict = dict()
+ min_dict = {}
idx = 1
for geo in total_geo:
for s_geo in total_geo[idx:]:
@@ -729,8 +729,8 @@ class RulesCheck(FlatCAMTool):
log.debug("RulesCheck.check_gerber_clearance()")
rule_title = rule
- violations = list()
- obj_violations = dict()
+ violations = []
+ obj_violations = {}
obj_violations.update({
'name': '',
'points': list()
@@ -739,7 +739,7 @@ class RulesCheck(FlatCAMTool):
if len(gerber_list) == 2:
gerber_1 = gerber_list[0]
# added it so I won't have errors of using before declaring
- gerber_2 = dict()
+ gerber_2 = {}
gerber_3 = gerber_list[1]
elif len(gerber_list) == 3:
@@ -749,7 +749,7 @@ class RulesCheck(FlatCAMTool):
else:
return 'Fail. Not enough Gerber objects to check Gerber 2 Gerber clearance'
- total_geo_grb_1 = list()
+ total_geo_grb_1 = []
for apid in gerber_1['apertures']:
if 'geometry' in gerber_1['apertures'][apid]:
geometry = gerber_1['apertures'][apid]['geometry']
@@ -766,7 +766,7 @@ class RulesCheck(FlatCAMTool):
if 'solid' in geo_el and geo_el['solid'] is not None:
total_geo_grb_1.append(geo_el['solid'])
- total_geo_grb_3 = list()
+ total_geo_grb_3 = []
for apid in gerber_3['apertures']:
if 'geometry' in gerber_3['apertures'][apid]:
geometry = gerber_3['apertures'][apid]['geometry']
@@ -795,7 +795,7 @@ class RulesCheck(FlatCAMTool):
iterations = len_1 * len_3
log.debug("RulesCheck.check_gerber_clearance(). Iterations: %s" % str(iterations))
- min_dict = dict()
+ min_dict = {}
for geo in total_geo_grb_1:
for s_geo in total_geo_grb_3:
# minimize the number of distances by not taking into considerations those that are too small
@@ -817,7 +817,7 @@ class RulesCheck(FlatCAMTool):
for location in min_dict[dist]:
points_list.add(location)
- name_list = list()
+ name_list = []
if gerber_1:
name_list.append(gerber_1['name'])
if gerber_2:
@@ -837,8 +837,8 @@ class RulesCheck(FlatCAMTool):
rule = _("Hole Size")
- violations = list()
- obj_violations = dict()
+ violations = []
+ obj_violations = {}
obj_violations.update({
'name': '',
'dia': list()
@@ -863,14 +863,14 @@ class RulesCheck(FlatCAMTool):
log.debug("RulesCheck.check_holes_clearance()")
rule = _("Hole to Hole Clearance")
- violations = list()
- obj_violations = dict()
+ violations = []
+ obj_violations = {}
obj_violations.update({
'name': '',
'points': list()
})
- total_geo = list()
+ total_geo = []
for elem in elements:
for tool in elem['tools']:
if 'solid_geometry' in elem['tools'][tool]:
@@ -878,7 +878,7 @@ class RulesCheck(FlatCAMTool):
for geo in geometry:
total_geo.append(geo)
- min_dict = dict()
+ min_dict = {}
idx = 1
for geo in total_geo:
for s_geo in total_geo[idx:]:
@@ -903,7 +903,7 @@ class RulesCheck(FlatCAMTool):
for location in min_dict[dist]:
points_list.add(location)
- name_list = list()
+ name_list = []
for elem in elements:
name_list.append(elem['name'])
@@ -919,8 +919,8 @@ class RulesCheck(FlatCAMTool):
rule = _("Trace Size")
- violations = list()
- obj_violations = dict()
+ violations = []
+ obj_violations = {}
obj_violations.update({
'name': '',
'size': list(),
@@ -957,18 +957,18 @@ class RulesCheck(FlatCAMTool):
def check_gerber_annular_ring(obj_list, size, rule):
rule_title = rule
- violations = list()
- obj_violations = dict()
+ violations = []
+ obj_violations = {}
obj_violations.update({
'name': '',
'points': list()
})
# added it so I won't have errors of using before declaring
- gerber_obj = dict()
- gerber_extra_obj = dict()
- exc_obj = dict()
- exc_extra_obj = dict()
+ gerber_obj = {}
+ gerber_extra_obj = {}
+ exc_obj = {}
+ exc_extra_obj = {}
if len(obj_list) == 2:
gerber_obj = obj_list[0]
@@ -997,7 +997,7 @@ class RulesCheck(FlatCAMTool):
else:
return 'Fail. Not enough objects to check Minimum Annular Ring'
- total_geo_grb = list()
+ total_geo_grb = []
for apid in gerber_obj['apertures']:
if 'geometry' in gerber_obj['apertures'][apid]:
geometry = gerber_obj['apertures'][apid]['geometry']
@@ -1017,7 +1017,7 @@ class RulesCheck(FlatCAMTool):
total_geo_grb = MultiPolygon(total_geo_grb)
total_geo_grb = total_geo_grb.buffer(0)
- total_geo_exc = list()
+ total_geo_exc = []
for tool in exc_obj['tools']:
if 'solid_geometry' in exc_obj['tools'][tool]:
geometry = exc_obj['tools'][tool]['solid_geometry']
@@ -1047,7 +1047,7 @@ class RulesCheck(FlatCAMTool):
iterations = len_1 * len_2
log.debug("RulesCheck.check_gerber_annular_ring(). Iterations: %s" % str(iterations))
- min_dict = dict()
+ min_dict = {}
dist = None
for geo in total_geo_grb:
for s_geo in total_geo_exc:
@@ -1075,12 +1075,12 @@ class RulesCheck(FlatCAMTool):
else:
min_dict[dist] = [s_geo.representative_point()]
- points_list = list()
+ points_list = []
for dist in min_dict.keys():
for location in min_dict[dist]:
points_list.append(location)
- name_list = list()
+ name_list = []
try:
if gerber_obj:
name_list.append(gerber_obj['name'])
@@ -1110,7 +1110,7 @@ class RulesCheck(FlatCAMTool):
return rule_title, violations
def execute(self):
- self.results = list()
+ self.results = []
log.debug("RuleCheck() executing")
@@ -1119,17 +1119,17 @@ class RulesCheck(FlatCAMTool):
# RULE: Check Trace Size
if self.trace_size_cb.get_value():
- copper_list = list()
+ copper_list = []
copper_name_1 = self.copper_t_object.currentText()
if copper_name_1 is not '' and self.copper_t_cb.get_value():
- elem_dict = dict()
+ 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 is not '' and self.copper_b_cb.get_value():
- elem_dict = dict()
+ 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)
@@ -1151,7 +1151,7 @@ class RulesCheck(FlatCAMTool):
if self.copper_t_cb.get_value():
copper_t_obj = self.copper_t_object.currentText()
- copper_t_dict = dict()
+ copper_t_dict = {}
if copper_t_obj is not '':
copper_t_dict['name'] = deepcopy(copper_t_obj)
@@ -1163,7 +1163,7 @@ class RulesCheck(FlatCAMTool):
_("TOP -> Copper to Copper clearance"))))
if self.copper_b_cb.get_value():
copper_b_obj = self.copper_b_object.currentText()
- copper_b_dict = dict()
+ copper_b_dict = {}
if copper_b_obj is not '':
copper_b_dict['name'] = deepcopy(copper_b_obj)
copper_b_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_b_obj).apertures)
@@ -1181,9 +1181,9 @@ class RulesCheck(FlatCAMTool):
# RULE: Check Copper to Outline Clearance
if self.clearance_copper2ol_cb.get_value() and self.out_cb.get_value():
- top_dict = dict()
- bottom_dict = dict()
- outline_dict = dict()
+ top_dict = {}
+ bottom_dict = {}
+ outline_dict = {}
copper_top = self.copper_t_object.currentText()
if copper_top is not '' and self.copper_t_cb.get_value():
@@ -1235,7 +1235,7 @@ class RulesCheck(FlatCAMTool):
# RULE: Check Silk to Silk Clearance
if self.clearance_silk2silk_cb.get_value():
- silk_dict = dict()
+ silk_dict = {}
try:
silk_silk_clearance = float(self.clearance_silk2silk_entry.get_value())
@@ -1275,10 +1275,10 @@ class RulesCheck(FlatCAMTool):
# RULE: Check Silk to Solder Mask Clearance
if self.clearance_silk2sm_cb.get_value():
- silk_t_dict = dict()
- sm_t_dict = dict()
- silk_b_dict = dict()
- sm_b_dict = dict()
+ silk_t_dict = {}
+ sm_t_dict = {}
+ silk_b_dict = {}
+ sm_b_dict = {}
top_ss = False
bottom_ss = False
@@ -1344,9 +1344,9 @@ class RulesCheck(FlatCAMTool):
# RULE: Check Silk to Outline Clearance
if self.clearance_silk2ol_cb.get_value():
- top_dict = dict()
- bottom_dict = dict()
- outline_dict = dict()
+ top_dict = {}
+ bottom_dict = {}
+ outline_dict = {}
silk_top = self.ss_t_object.currentText()
if silk_top is not '' and self.ss_t_cb.get_value():
@@ -1399,7 +1399,7 @@ class RulesCheck(FlatCAMTool):
# RULE: Check Minimum Solder Mask Sliver
if self.clearance_silk2silk_cb.get_value():
- sm_dict = dict()
+ sm_dict = {}
try:
sm_sm_clearance = float(self.clearance_sm2sm_entry.get_value())
@@ -1439,10 +1439,10 @@ class RulesCheck(FlatCAMTool):
# RULE: Check Minimum Annular Ring
if self.ring_integrity_cb.get_value():
- top_dict = dict()
- bottom_dict = dict()
- exc_1_dict = dict()
- exc_2_dict = dict()
+ top_dict = {}
+ bottom_dict = {}
+ exc_1_dict = {}
+ exc_2_dict = {}
copper_top = self.copper_t_object.currentText()
if copper_top is not '' and self.copper_t_cb.get_value():
@@ -1504,17 +1504,17 @@ class RulesCheck(FlatCAMTool):
# RULE: Check Hole to Hole Clearance
if self.clearance_d2d_cb.get_value():
- exc_list = list()
+ exc_list = []
exc_name_1 = self.e1_object.currentText()
if exc_name_1 is not '' and self.e1_cb.get_value():
- elem_dict = dict()
+ 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 is not '' and self.e2_cb.get_value():
- elem_dict = dict()
+ 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)
@@ -1524,17 +1524,17 @@ class RulesCheck(FlatCAMTool):
# RULE: Check Holes Size
if self.drill_size_cb.get_value():
- exc_list = list()
+ exc_list = []
exc_name_1 = self.e1_object.currentText()
if exc_name_1 is not '' and self.e1_cb.get_value():
- elem_dict = dict()
+ 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 is not '' and self.e2_cb.get_value():
- elem_dict = dict()
+ 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)
@@ -1542,7 +1542,7 @@ class RulesCheck(FlatCAMTool):
drill_size = float(self.drill_size_entry.get_value())
self.results.append(self.pool.apply_async(self.check_holes_size, args=(exc_list, drill_size)))
- output = list()
+ output = []
for p in self.results:
output.append(p.get())
diff --git a/flatcamTools/ToolSub.py b/flatcamTools/ToolSub.py
index 99cc9fa8..9d547ed5 100644
--- a/flatcamTools/ToolSub.py
+++ b/flatcamTools/ToolSub.py
@@ -303,14 +303,14 @@ class ToolSub(FlatCAMTool):
# crate the new_apertures dict structure
for apid in self.target_grb_obj.apertures:
- self.new_apertures[apid] = dict()
+ self.new_apertures[apid] = {}
self.new_apertures[apid]['type'] = 'C'
self.new_apertures[apid]['size'] = self.target_grb_obj.apertures[apid]['size']
- self.new_apertures[apid]['geometry'] = list()
+ self.new_apertures[apid]['geometry'] = []
- geo_solid_union_list = list()
- geo_follow_union_list = list()
- geo_clear_union_list = list()
+ geo_solid_union_list = []
+ geo_follow_union_list = []
+ geo_clear_union_list = []
for apid1 in self.sub_grb_obj.apertures:
if 'geometry' in self.sub_grb_obj.apertures[apid1]:
@@ -339,14 +339,14 @@ class ToolSub(FlatCAMTool):
self.app.worker_task.emit({'fcn': self.aperture_intersection, 'params': [apid, geo]})
def aperture_intersection(self, apid, geo):
- new_geometry = list()
+ new_geometry = []
log.debug("Working on promise: %s" % str(apid))
with self.app.proc_container.new('%s: %s...' % (_("Parsing geometry for aperture"), str(apid))):
for geo_el in geo:
- new_el = dict()
+ new_el = {}
if 'solid' in geo_el:
work_geo = geo_el['solid']
@@ -513,14 +513,14 @@ class ToolSub(FlatCAMTool):
return
# create the target_options obj
- # self.target_options = dict()
+ # self.target_options = {}
# for k, v in self.target_geo_obj.options.items():
# if k != 'name':
# self.target_options[k] = v
# crate the new_tools dict structure
for tool in self.target_geo_obj.tools:
- self.new_tools[tool] = dict()
+ self.new_tools[tool] = {}
for key in self.target_geo_obj.tools[tool]:
if key == 'solid_geometry':
self.new_tools[tool][key] = []
diff --git a/tclCommands/TclCommand.py b/tclCommands/TclCommand.py
index 719b3c71..fd3058c9 100644
--- a/tclCommands/TclCommand.py
+++ b/tclCommands/TclCommand.py
@@ -78,7 +78,7 @@ class TclCommand(object):
:return: current command
"""
- command_string = list()
+ command_string = []
command_string.append(self.aliases[0])
if self.original_args is not None:
diff --git a/tclCommands/TclCommandBounds.py b/tclCommands/TclCommandBounds.py
index 6736f458..e4d53c7b 100644
--- a/tclCommands/TclCommandBounds.py
+++ b/tclCommands/TclCommandBounds.py
@@ -52,7 +52,7 @@ class TclCommandBounds(TclCommand):
:return:
"""
- obj_list = list()
+ obj_list = []
if 'objects' in args:
try:
obj_list = [str(obj_name) for obj_name in str(args['objects']).split(",") if obj_name != '']
@@ -68,7 +68,7 @@ class TclCommandBounds(TclCommand):
_("Expected a list of objects names separated by comma. Got"), str(args['objects'])))
return 'fail'
- result_list = list()
+ result_list = []
for name in obj_list:
obj = self.app.collection.get_by_name(name)
diff --git a/tclCommands/TclCommandCopperClear.py b/tclCommands/TclCommandCopperClear.py
index d6f58989..f80bc5a9 100644
--- a/tclCommands/TclCommandCopperClear.py
+++ b/tclCommands/TclCommandCopperClear.py
@@ -188,7 +188,7 @@ class TclCommandCopperClear(TclCommand):
"paintcontour": self.app.defaults["tools_paintcontour"],
"paintoverlap": self.app.defaults["tools_paintoverlap"]
})
- ncc_tools = dict()
+ ncc_tools = {}
tooluid = 0
for tool in tools:
diff --git a/tclCommands/TclCommandPaint.py b/tclCommands/TclCommandPaint.py
index f44dcef2..e300e0c5 100644
--- a/tclCommands/TclCommandPaint.py
+++ b/tclCommands/TclCommandPaint.py
@@ -178,7 +178,7 @@ class TclCommandPaint(TclCommand):
"paintcontour": self.app.defaults["tools_paintcontour"],
"paintoverlap": self.app.defaults["tools_paintoverlap"]
})
- paint_tools = dict()
+ paint_tools = {}
tooluid = 0
for tool in tools:
diff --git a/tclCommands/TclCommandPanelize.py b/tclCommands/TclCommandPanelize.py
index 2a8c7c05..140c5e55 100644
--- a/tclCommands/TclCommandPanelize.py
+++ b/tclCommands/TclCommandPanelize.py
@@ -228,7 +228,7 @@ class TclCommandPanelize(TclCommand):
def translate_recursion(geom):
if type(geom) == list:
- geoms = list()
+ geoms = []
for local_geom in geom:
geoms.append(translate_recursion(local_geom))
return geoms
diff --git a/tclCommands/TclCommandSetOrigin.py b/tclCommands/TclCommandSetOrigin.py
index 27f883ce..52974dd2 100644
--- a/tclCommands/TclCommandSetOrigin.py
+++ b/tclCommands/TclCommandSetOrigin.py
@@ -66,7 +66,7 @@ class TclCommandSetOrigin(TclCommand):
:return:
"""
- loc = list()
+ loc = []
if 'auto' in args:
if bool(args['auto']) is True:
objs = self.app.collection.get_list()
From 77e01825c2d10c7e6692e73d507995c0cc2fabd6 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 1 Mar 2020 01:55:35 +0200
Subject: [PATCH 121/209] - wip on the new tools database
---
FlatCAMCommon.py | 26 +++++++++++++++++++-------
flatcamGUI/GUIElements.py | 16 +++++++++++++++-
2 files changed, 34 insertions(+), 8 deletions(-)
diff --git a/FlatCAMCommon.py b/FlatCAMCommon.py
index 4a68cdaa..f324fe4c 100644
--- a/FlatCAMCommon.py
+++ b/FlatCAMCommon.py
@@ -1422,9 +1422,16 @@ class ToolsDB2(QtWidgets.QWidget):
tree_layout = QtWidgets.QVBoxLayout()
grid_layout.addLayout(tree_layout, 0, 0)
- self.tree_widget = FCTree(columns=2, header_hidden=False)
+ self.tree_widget = FCTree(columns=2, header_hidden=False, protected_column=[0])
self.tree_widget.setHeaderLabels(["ID", "Tool Name"])
self.tree_widget.setIndentation(0)
+
+ # set alternating colors
+ # self.tree_widget.setAlternatingRowColors(True)
+ # p = QtGui.QPalette()
+ # p.setColor(QtGui.QPalette.AlternateBase, QtGui.QColor(226, 237, 253) )
+ # self.tree_widget.setPalette(p)
+
self.tree_widget.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
tree_layout.addWidget(self.tree_widget)
@@ -1516,16 +1523,21 @@ class ToolsDB2(QtWidgets.QWidget):
self.add_tool_from_db.clicked.connect(self.on_tool_requested_from_app)
self.cancel_tool_from_db.clicked.connect(self.on_cancel_tool)
- self.tree_widget.selectionModel().selectionChanged.connect(self.on_list_selection_change)
+ # self.tree_widget.selectionModel().selectionChanged.connect(self.on_list_selection_change)
+ self.tree_widget.currentItemChanged.connect(self.on_list_selection_change)
self.tree_widget.itemChanged.connect(self.on_list_item_edited)
+
self.setup_db_ui()
- def on_list_selection_change(self, current):
- return
- for idx in current.indexes():
- print(idx.data())
+ def on_list_selection_change(self, current, previous):
+ # for idx in current.indexes():
+ # print(idx.data())
+ print(current.text(0))
+ self.table_widget.selectRow(int(current.text(0))-1)
- def on_list_item_edited(self, item, idx):
+ def on_list_item_edited(self, item, column):
+ if column == 0:
+ return
row = int(item.text(0)) - 1
self.table_widget.item(row, 1).setText(item.text(1))
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index 144280c9..da536279 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -154,7 +154,7 @@ class RadioSet(QtWidgets.QWidget):
class FCTree(QtWidgets.QTreeWidget):
- def __init__(self, parent=None, columns=2, header_hidden=True, extended_sel=False):
+ def __init__(self, parent=None, columns=2, header_hidden=True, extended_sel=False, protected_column=None):
super(FCTree, self).__init__(parent)
self.setColumnCount(columns)
@@ -165,6 +165,20 @@ class FCTree(QtWidgets.QTreeWidget):
if extended_sel:
self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
+ self.protected_column = protected_column
+ self.itemDoubleClicked.connect(self.on_double_click)
+
+ def on_double_click(self, item, column):
+ # from here: https://stackoverflow.com/questions/2801959/making-only-one-column-of-a-qtreewidgetitem-editable
+ tmp_flags = item.flags()
+ if self.is_editable(column):
+ item.setFlags(tmp_flags | QtCore.Qt.ItemIsEditable)
+ elif tmp_flags & QtCore.Qt.ItemIsEditable:
+ item.setFlags(tmp_flags ^ QtCore.Qt.ItemIsEditable)
+
+ def is_editable(self, tested_col):
+ return False if tested_col in self.protected_column else True
+
def addParent(self, parent, title, expanded=False, color=None, font=None):
item = QtWidgets.QTreeWidgetItem(parent, [title])
item.setChildIndicatorPolicy(QtWidgets.QTreeWidgetItem.ShowIndicator)
From 5b10e9faf0e0d0a7d7b9004cca88ccdfb3091d3f Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 1 Mar 2020 19:23:06 +0200
Subject: [PATCH 122/209] - updated the CutOut Tool such that while adding
manual gaps, the cutting geometry is updated on-the-fly if the gap size or
tool diameter parameters are adjusted
---
README.md | 4 ++++
flatcamTools/ToolCutOut.py | 11 +++++++----
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 3ebe0a9e..11b4b213 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+01.03.2020
+
+- updated the CutOut Tool such that while adding manual gaps, the cutting geometry is updated on-the-fly if the gap size or tool diameter parameters are adjusted
+
29.02.2020
- compacted the NCC Tool UI by replacing some Radio buttons with Combo boxes due of too many elements
diff --git a/flatcamTools/ToolCutOut.py b/flatcamTools/ToolCutOut.py
index 0033d149..38f4ae7c 100644
--- a/flatcamTools/ToolCutOut.py
+++ b/flatcamTools/ToolCutOut.py
@@ -532,8 +532,8 @@ class CutOut(FlatCAMTool):
object_geo = cutout_obj.solid_geometry.convex_hull
else:
object_geo = cutout_obj.solid_geometry
- except Exception as e:
- log.debug("CutOut.on_freeform_cutout().geo_init() --> %s" % str(e))
+ except Exception as err:
+ log.debug("CutOut.on_freeform_cutout().geo_init() --> %s" % str(err))
else:
object_geo = cutout_obj.solid_geometry
@@ -939,6 +939,9 @@ class CutOut(FlatCAMTool):
self.app.new_object('geometry', outname, geo_init)
def cutting_geo(self, pos):
+ self.cutting_dia = float(self.dia.get_value())
+ self.cutting_gapsize = float(self.gapsize.get_value())
+
offset = self.cutting_dia / 2 + self.cutting_gapsize / 2
# cutting area definition
@@ -1034,7 +1037,7 @@ class CutOut(FlatCAMTool):
except TypeError:
return
- if self.app.grid_status() == True:
+ if self.app.grid_status():
snap_x, snap_y = self.app.geo_editor.snap(x, y)
else:
snap_x, snap_y = x, y
@@ -1064,7 +1067,7 @@ class CutOut(FlatCAMTool):
else:
radian = math.atan(dx / dy)
angle = radian * 180 / math.pi
- except Exception as e:
+ except Exception:
angle = 0
return angle
From bac37865e934ba4139319238b192f5e63f648f92 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 1 Mar 2020 20:40:07 +0200
Subject: [PATCH 123/209] - updated the UI in Geometry Editor
---
README.md | 1 +
flatcamEditors/FlatCAMGeoEditor.py | 42 ++++++++++++++++--------------
flatcamGUI/GUIElements.py | 24 +++++++++++++++++
3 files changed, 48 insertions(+), 19 deletions(-)
diff --git a/README.md b/README.md
index 11b4b213..4b42bb5c 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
01.03.2020
- updated the CutOut Tool such that while adding manual gaps, the cutting geometry is updated on-the-fly if the gap size or tool diameter parameters are adjusted
+- updated the UI in Geometry Editor
29.02.2020
diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py
index a1a13b9b..6b5c3cc5 100644
--- a/flatcamEditors/FlatCAMGeoEditor.py
+++ b/flatcamEditors/FlatCAMGeoEditor.py
@@ -3252,15 +3252,17 @@ class FlatCAMGeoEditor(QtCore.QObject):
self.title_box.addWidget(self.title_label, stretch=1)
self.title_box.addWidget(QtWidgets.QLabel(''))
- self.tw = FCTree(extended_sel=True)
+ self.tw = FCTree(columns=3, header_hidden=False, protected_column=[0, 1], extended_sel=True)
+ self.tw.setHeaderLabels(["ID", _("Type"), _("Name")])
+ self.tw.setIndentation(0)
+ self.tw.header().setStretchLastSection(True)
+ self.tw.header().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
self.tools_box.addWidget(self.tw)
self.geo_font = QtGui.QFont()
self.geo_font.setBold(True)
- parent = self.tw.invisibleRootItem()
- self.geo_parent = self.tw.addParent(
- parent, _('Geometry Elements'), expanded=True, color=QtGui.QColor("#000000"), font=self.geo_font)
+ self.geo_parent = self.tw.invisibleRootItem()
# ## Toolbar events and properties
self.tools = {
@@ -3494,29 +3496,33 @@ class FlatCAMGeoEditor(QtCore.QObject):
for elem in self.storage.get_objects():
geo_type = type(elem.geo)
- title = None
+ el_type = None
if geo_type is LinearRing:
- title = _('ID Ring')
+ el_type = _('Ring')
elif geo_type is LineString:
- title = _('ID Line')
+ el_type = _('Line')
elif geo_type is Polygon:
- title = _('ID Polygon')
+ el_type = _('Polygon')
elif geo_type is MultiLineString:
- title = _('ID Multi-Line')
+ el_type = _('Multi-Line')
elif geo_type is MultiPolygon:
- title = _('ID Multi-Polygon')
+ el_type = _('Multi-Polygon')
- self.tw.addChild(
+ self.tw.addParentEditable(
self.geo_parent,
[
- '%s:' % title,
- str(id(elem))
+ str(id(elem)),
+ '%s' % el_type,
+ _("Geo Elem")
],
- True,
font=self.geo_font,
- font_items=1
+ font_items=2,
+ # color=QtGui.QColor("#FF0000"),
+ editable=True
)
+ self.tw.resize_sig.emit()
+
def on_geo_elem_selected(self):
pass
@@ -3526,7 +3532,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
for sel in selected_tree_items:
for obj_shape in self.storage.get_objects():
try:
- if id(obj_shape) == int(sel.text(1)):
+ if id(obj_shape) == int(sel.text(0)):
self.selected.append(obj_shape)
except ValueError:
pass
@@ -3686,9 +3692,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
# clear the Tree
self.tw.clear()
- parent = self.tw.invisibleRootItem()
- self.geo_parent = self.tw.addParent(
- parent, _('Geometry Elements'), expanded=True, color=QtGui.QColor("#000000"), font=self.geo_font)
+ self.geo_parent = self.tw.invisibleRootItem()
# hide the UI
self.geo_frame.hide()
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index da536279..18c46b55 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -153,6 +153,7 @@ class RadioSet(QtWidgets.QWidget):
class FCTree(QtWidgets.QTreeWidget):
+ resize_sig = QtCore.pyqtSignal()
def __init__(self, parent=None, columns=2, header_hidden=True, extended_sel=False, protected_column=None):
super(FCTree, self).__init__(parent)
@@ -167,6 +168,8 @@ class FCTree(QtWidgets.QTreeWidget):
self.protected_column = protected_column
self.itemDoubleClicked.connect(self.on_double_click)
+ self.header().sectionDoubleClicked.connect(self.on_header_double_click)
+ self.resize_sig.connect(self.on_resize)
def on_double_click(self, item, column):
# from here: https://stackoverflow.com/questions/2801959/making-only-one-column-of-a-qtreewidgetitem-editable
@@ -176,6 +179,13 @@ class FCTree(QtWidgets.QTreeWidget):
elif tmp_flags & QtCore.Qt.ItemIsEditable:
item.setFlags(tmp_flags ^ QtCore.Qt.ItemIsEditable)
+ def on_header_double_click(self, column):
+ header = self.header()
+ header.setSectionResizeMode(column, QtWidgets.QHeaderView.ResizeToContents)
+ width = header.sectionSize(column)
+ header.setSectionResizeMode(column, QtWidgets.QHeaderView.Interactive)
+ header.resizeSection(column, width)
+
def is_editable(self, tested_col):
return False if tested_col in self.protected_column else True
@@ -228,6 +238,20 @@ class FCTree(QtWidgets.QTreeWidget):
except TypeError:
item.setFont(font_items, font)
+ def resizeEvent(self, event):
+ """ Resize all sections to content and user interactive """
+
+ super(FCTree, self).resizeEvent(event)
+ self.on_resize()
+
+ def on_resize(self):
+ header = self.header()
+ for column in range(header.count()):
+ header.setSectionResizeMode(column, QtWidgets.QHeaderView.ResizeToContents)
+ width = header.sectionSize(column)
+ header.setSectionResizeMode(column, QtWidgets.QHeaderView.Interactive)
+ header.resizeSection(column, width)
+
class LengthEntry(QtWidgets.QLineEdit):
def __init__(self, output_units='IN', decimals=None, parent=None):
From 0477a9860ab747096521d0b38d9934065c03a58e Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 2 Mar 2020 06:17:18 +0200
Subject: [PATCH 124/209] - added property that allow the FCComboBox to update
the view with the last item loaded; updated the app to use this property
---
FlatCAMObj.py | 8 +++---
README.md | 5 +++-
flatcamGUI/GUIElements.py | 23 +++++++++++++++---
flatcamGUI/ObjectUI.py | 16 ++++++------
flatcamTools/ToolAlignObjects.py | 4 +--
flatcamTools/ToolCalibration.py | 4 +--
flatcamTools/ToolCopperThieving.py | 16 ++++++------
flatcamTools/ToolCutOut.py | 12 ++++-----
flatcamTools/ToolDblSided.py | 18 +++++++-------
flatcamTools/ToolExtractDrills.py | 6 ++---
flatcamTools/ToolFiducials.py | 10 ++++----
flatcamTools/ToolFilm.py | 39 ++++++++++++++++--------------
flatcamTools/ToolInvertGerber.py | 6 ++---
flatcamTools/ToolNCC.py | 5 ++--
flatcamTools/ToolOptimal.py | 6 ++---
flatcamTools/ToolPaint.py | 12 ++++-----
flatcamTools/ToolPanelize.py | 25 ++++++++++---------
flatcamTools/ToolPunchGerber.py | 10 ++++----
flatcamTools/ToolQRCode.py | 6 ++---
flatcamTools/ToolRulesCheck.py | 38 ++++++++++++++---------------
flatcamTools/ToolSolderPaste.py | 6 ++---
flatcamTools/ToolSub.py | 14 +++++------
22 files changed, 157 insertions(+), 132 deletions(-)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 2c4dcfdc..963e64a6 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -733,7 +733,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
# set the model for the Area Exception comboboxes
self.ui.obj_combo.setModel(self.app.collection)
self.ui.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.ui.obj_combo.setCurrentIndex(1)
+ self.ui.obj_combo.set_last = True
self.ui.type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
self.ui.tool_type_radio.activated_custom.connect(self.on_tool_type_change)
@@ -4101,21 +4101,21 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
dia_item.setFlags(QtCore.Qt.ItemIsEnabled)
- offset_item = QtWidgets.QComboBox()
+ offset_item = FCComboBox()
for item in self.offset_item_options:
offset_item.addItem(item)
# offset_item.setStyleSheet('background-color: rgb(255,255,255)')
idx = offset_item.findText(tooluid_value['offset'])
offset_item.setCurrentIndex(idx)
- type_item = QtWidgets.QComboBox()
+ type_item = FCComboBox()
for item in self.type_item_options:
type_item.addItem(item)
# type_item.setStyleSheet('background-color: rgb(255,255,255)')
idx = type_item.findText(tooluid_value['type'])
type_item.setCurrentIndex(idx)
- tool_type_item = QtWidgets.QComboBox()
+ tool_type_item = FCComboBox()
for item in self.tool_type_item_options:
tool_type_item.addItem(item)
# tool_type_item.setStyleSheet('background-color: rgb(255,255,255)')
diff --git a/README.md b/README.md
index 4b42bb5c..dd227f7c 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+02.03.2020
+
+- added property that allow the FCComboBox to update the view with the last item loaded; updated the app to use this property
+
01.03.2020
- updated the CutOut Tool such that while adding manual gaps, the cutting geometry is updated on-the-fly if the gap size or tool diameter parameters are adjusted
@@ -42,7 +46,6 @@ CAD program, and create G-Code for Isolation routing.
- fixed an issue in Gerber Editor where the multiprocessing pool was reported as closed and an ValueError exception was raised in a certain scneraio
- on Set Origin, Move to Origin and Move actions for Gerber and Excellon objects the source file will be also updated (the export functions will export an updated object)
- in FlatCAMObj.export_gerber() method took into account the possibility of polygons of type 'clear' (the ones found in the Gerber files under the LPC command)
-
17.02.2020
- updated the Excellon UI to hold data for each tool
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index 18c46b55..9e3094ec 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -302,7 +302,7 @@ class LengthEntry(QtWidgets.QLineEdit):
units = raw[-2:]
units = self.scales[self.output_units][units.upper()]
value = raw[:-2]
- return float(eval(value))* units
+ return float(eval(value)) * units
except IndexError:
value = raw
return float(eval(value))
@@ -334,7 +334,7 @@ class FloatEntry(QtWidgets.QLineEdit):
def mousePressEvent(self, e, Parent=None):
super(FloatEntry, self).mousePressEvent(e) # required to deselect on 2e click
- if self.readyToEdit == True:
+ if self.readyToEdit is True:
self.selectAll()
self.readyToEdit = False
@@ -1285,6 +1285,8 @@ class FCComboBox(QtWidgets.QComboBox):
self.view.viewport().installEventFilter(self)
self.view.setContextMenuPolicy(Qt.CustomContextMenu)
+ self._set_last = False
+
# the callback() will be called on customcontextmenu event and will be be passed 2 parameters:
# pos = mouse right click click position
# self = is the combobox object itself
@@ -1306,6 +1308,19 @@ class FCComboBox(QtWidgets.QComboBox):
def set_value(self, val):
self.setCurrentIndex(self.findText(str(val)))
+ @property
+ def set_last(self):
+ return self._set_last
+
+ @set_last.setter
+ def set_last(self, val):
+ self._set_last = val
+ if self._set_last is True:
+ self.model().rowsInserted.connect(self.on_model_changed)
+
+ def on_model_changed(self, first, last):
+ self.setCurrentIndex(last)
+
class FCInputDialog(QtWidgets.QInputDialog):
def __init__(self, parent=None, ok=False, val=None, title=None, text=None, min=None, max=None, decimals=None,
@@ -1436,7 +1451,7 @@ class FCDetachableTab(QtWidgets.QTabWidget):
self.protect_by_name = protect_by_name if isinstance(protect_by_name, list) else None
# Close all detached tabs if the application is closed explicitly
- QtWidgets.qApp.aboutToQuit.connect(self.closeDetachedTabs) # @UndefinedVariable
+ QtWidgets.qApp.aboutToQuit.connect(self.closeDetachedTabs) # @UndefinedVariable
# used by the property self.useOldIndex(param)
self.use_old_index = None
@@ -1916,7 +1931,7 @@ class FCDetachableTab(QtWidgets.QTabWidget):
self.dragInitiated = True
# If the current movement is a drag initiated by the left button
- if ((event.buttons() & QtCore.Qt.LeftButton)) and self.dragInitiated and self.can_be_dragged:
+ if (event.buttons() & QtCore.Qt.LeftButton) and self.dragInitiated and self.can_be_dragged:
# Stop the move event
finishMoveEvent = QtGui.QMouseEvent(
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index ca99e6c4..1b298f29 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -445,15 +445,17 @@ class GerberObjectUI(ObjectUI):
# ################################################
# ##### Type of object to be excepted ############
# ################################################
- self.type_obj_combo = QtWidgets.QComboBox()
- self.type_obj_combo.addItem("Gerber")
- self.type_obj_combo.addItem("Excellon")
- self.type_obj_combo.addItem("Geometry")
+ self.type_obj_combo = FCComboBox()
+ self.type_obj_combo.addItems(["Gerber", "Geometry"])
+
+ # self.type_obj_combo.addItem("Gerber")
+ # self.type_obj_combo.addItem("Excellon")
+ # self.type_obj_combo.addItem("Geometry")
# we get rid of item1 ("Excellon") as it is not suitable
- self.type_obj_combo.view().setRowHidden(1, True)
+ # self.type_obj_combo.view().setRowHidden(1, True)
self.type_obj_combo.setItemIcon(0, QtGui.QIcon(self.resource_loc + "/flatcam_icon16.png"))
- self.type_obj_combo.setItemIcon(2, QtGui.QIcon(self.resource_loc + "/geometry16.png"))
+ self.type_obj_combo.setItemIcon(1, QtGui.QIcon(self.resource_loc + "/geometry16.png"))
self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Obj Type"))
self.type_obj_combo_label.setToolTip(
@@ -468,7 +470,7 @@ class GerberObjectUI(ObjectUI):
# ################################################
# ##### The object to be excepted ################
# ################################################
- self.obj_combo = QtWidgets.QComboBox()
+ self.obj_combo = FCComboBox()
self.obj_label = QtWidgets.QLabel('%s:' % _("Object"))
self.obj_label.setToolTip(_("Object whose area will be removed from isolation geometry."))
diff --git a/flatcamTools/ToolAlignObjects.py b/flatcamTools/ToolAlignObjects.py
index 1ffbe1e5..f8f6d14f 100644
--- a/flatcamTools/ToolAlignObjects.py
+++ b/flatcamTools/ToolAlignObjects.py
@@ -80,7 +80,7 @@ class AlignObjects(FlatCAMTool):
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.setCurrentIndex(1)
+ self.object_combo.set_last = True
self.object_combo.setToolTip(
_("Object to be aligned.")
@@ -116,7 +116,7 @@ class AlignObjects(FlatCAMTool):
self.aligner_object_combo = FCComboBox()
self.aligner_object_combo.setModel(self.app.collection)
self.aligner_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.aligner_object_combo.setCurrentIndex(1)
+ self.aligner_object_combo.set_last = True
self.aligner_object_combo.setToolTip(
_("Object to be aligned to. Aligner.")
diff --git a/flatcamTools/ToolCalibration.py b/flatcamTools/ToolCalibration.py
index 6f9b015c..2a3956e3 100644
--- a/flatcamTools/ToolCalibration.py
+++ b/flatcamTools/ToolCalibration.py
@@ -206,7 +206,7 @@ class ToolCalibration(FlatCAMTool):
self.object_combo = FCComboBox()
self.object_combo.setModel(self.app.collection)
self.object_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
- self.object_combo.setCurrentIndex(1)
+ self.object_combo.set_last = True
self.object_label = QtWidgets.QLabel("%s:" % _("Source object selection"))
self.object_label.setToolTip(
@@ -628,7 +628,7 @@ class ToolCalibration(FlatCAMTool):
)
grid_lay.addWidget(step_5, 45, 0, 1, 3)
- self.adj_object_type_combo = QtWidgets.QComboBox()
+ self.adj_object_type_combo = FCComboBox()
self.adj_object_type_combo.addItems([_("Gerber"), _("Excellon"), _("Geometry")])
self.adj_object_type_combo.setCurrentIndex(0)
diff --git a/flatcamTools/ToolCopperThieving.py b/flatcamTools/ToolCopperThieving.py
index 295aed5a..3949cdda 100644
--- a/flatcamTools/ToolCopperThieving.py
+++ b/flatcamTools/ToolCopperThieving.py
@@ -9,7 +9,7 @@ from PyQt5 import QtWidgets, QtCore
import FlatCAMApp
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import FCDoubleSpinner, RadioSet, FCEntry
+from flatcamGUI.GUIElements import FCDoubleSpinner, RadioSet, FCEntry, FCComboBox
from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMExcellon
import shapely.geometry.base as base
@@ -66,10 +66,10 @@ class ToolCopperThieving(FlatCAMTool):
i_grid_lay.setColumnStretch(0, 0)
i_grid_lay.setColumnStretch(1, 1)
- self.grb_object_combo = QtWidgets.QComboBox()
+ self.grb_object_combo = FCComboBox()
self.grb_object_combo.setModel(self.app.collection)
self.grb_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.grb_object_combo.setCurrentIndex(1)
+ self.grb_object_combo.set_last = True
self.grbobj_label = QtWidgets.QLabel("%s:" % _("GERBER"))
self.grbobj_label.setToolTip(
@@ -140,7 +140,7 @@ class ToolCopperThieving(FlatCAMTool):
_("The type of FlatCAM object to be used as copper thieving reference.\n"
"It can be Gerber, Excellon or Geometry.")
)
- self.box_combo_type = QtWidgets.QComboBox()
+ self.box_combo_type = FCComboBox()
self.box_combo_type.addItem(_("Reference Gerber"))
self.box_combo_type.addItem(_("Reference Excellon"))
self.box_combo_type.addItem(_("Reference Geometry"))
@@ -152,10 +152,10 @@ class ToolCopperThieving(FlatCAMTool):
self.box_combo_label.setToolTip(
_("The FlatCAM object to be used as non copper clearing reference.")
)
- self.box_combo = QtWidgets.QComboBox()
+ self.box_combo = FCComboBox()
self.box_combo.setModel(self.app.collection)
self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.box_combo.setCurrentIndex(1)
+ self.box_combo.set_last = True
grid_lay.addWidget(self.box_combo_label, 5, 0)
grid_lay.addWidget(self.box_combo, 5, 1)
@@ -417,10 +417,10 @@ class ToolCopperThieving(FlatCAMTool):
"the pattern plating mask.")
)
- self.sm_object_combo = QtWidgets.QComboBox()
+ self.sm_object_combo = FCComboBox()
self.sm_object_combo.setModel(self.app.collection)
self.sm_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.sm_object_combo.setCurrentIndex(1)
+ self.sm_object_combo.set_last = True
grid_lay_1.addWidget(self.sm_obj_label, 7, 0, 1, 3)
grid_lay_1.addWidget(self.sm_object_combo, 8, 0, 1, 3)
diff --git a/flatcamTools/ToolCutOut.py b/flatcamTools/ToolCutOut.py
index 38f4ae7c..a94d7fa5 100644
--- a/flatcamTools/ToolCutOut.py
+++ b/flatcamTools/ToolCutOut.py
@@ -73,7 +73,7 @@ class CutOut(FlatCAMTool):
grid0.addWidget(self.object_label, 0, 0, 1, 2)
# Object kind
- self.kindlabel = QtWidgets.QLabel('%s:' % _('Object kind'))
+ self.kindlabel = QtWidgets.QLabel('%s:' % _('Kind'))
self.kindlabel.setToolTip(
_("Choice of what kind the object we want to cutout is.
"
"- Single: contain a single PCB Gerber outline object.
"
@@ -93,7 +93,7 @@ class CutOut(FlatCAMTool):
{"label": _("Geometry"), "value": "geo"},
])
- self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
+ self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Type"))
self.type_obj_combo_label.setToolTip(
_("Specify the type of object to be cutout.\n"
"It can be of type: Gerber or Geometry.\n"
@@ -105,10 +105,10 @@ class CutOut(FlatCAMTool):
grid0.addWidget(self.type_obj_radio, 2, 1)
# Object to be cutout
- self.obj_combo = QtWidgets.QComboBox()
+ self.obj_combo = FCComboBox()
self.obj_combo.setModel(self.app.collection)
self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.obj_combo.setCurrentIndex(1)
+ self.obj_combo.set_last = True
grid0.addWidget(self.obj_combo, 3, 0, 1, 2)
@@ -318,10 +318,10 @@ class CutOut(FlatCAMTool):
self.layout.addLayout(form_layout_3)
# Manual Geo Object
- self.man_object_combo = QtWidgets.QComboBox()
+ self.man_object_combo = FCComboBox()
self.man_object_combo.setModel(self.app.collection)
self.man_object_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
- self.man_object_combo.setCurrentIndex(1)
+ self.man_object_combo.set_last = True
self.man_object_label = QtWidgets.QLabel('%s:' % _("Geometry Object"))
self.man_object_label.setToolTip(
diff --git a/flatcamTools/ToolDblSided.py b/flatcamTools/ToolDblSided.py
index 56602125..8612932c 100644
--- a/flatcamTools/ToolDblSided.py
+++ b/flatcamTools/ToolDblSided.py
@@ -2,7 +2,7 @@
from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, EvalEntry, FCEntry, FCButton
+from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, EvalEntry, FCEntry, FCButton, FCComboBox
from FlatCAMObj import FlatCAMGerber, FlatCAMExcellon, FlatCAMGeometry
from numpy import Inf
@@ -56,10 +56,10 @@ class DblSidedTool(FlatCAMTool):
grid_lay.addWidget(self.m_objects_label, 0, 0, 1, 2)
# ## Gerber Object to mirror
- self.gerber_object_combo = QtWidgets.QComboBox()
+ self.gerber_object_combo = FCComboBox()
self.gerber_object_combo.setModel(self.app.collection)
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.gerber_object_combo.setCurrentIndex(1)
+ self.gerber_object_combo.set_last = True
self.botlay_label = QtWidgets.QLabel("%s:" % _("GERBER"))
self.botlay_label.setToolTip('%s.' % _("Gerber to be mirrored"))
@@ -83,10 +83,10 @@ class DblSidedTool(FlatCAMTool):
grid_lay.addWidget(self.mirror_gerber_button, 2, 1)
# ## Excellon Object to mirror
- self.exc_object_combo = QtWidgets.QComboBox()
+ self.exc_object_combo = FCComboBox()
self.exc_object_combo.setModel(self.app.collection)
self.exc_object_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
- self.exc_object_combo.setCurrentIndex(1)
+ self.exc_object_combo.set_last = True
self.excobj_label = QtWidgets.QLabel("%s:" % _("EXCELLON"))
self.excobj_label.setToolTip(_("Excellon Object to be mirrored."))
@@ -110,10 +110,10 @@ class DblSidedTool(FlatCAMTool):
grid_lay.addWidget(self.mirror_exc_button, 4, 1)
# ## Geometry Object to mirror
- self.geo_object_combo = QtWidgets.QComboBox()
+ self.geo_object_combo = FCComboBox()
self.geo_object_combo.setModel(self.app.collection)
self.geo_object_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
- self.geo_object_combo.setCurrentIndex(1)
+ self.geo_object_combo.set_last = True
self.geoobj_label = QtWidgets.QLabel("%s:" % _("GEOMETRY"))
self.geoobj_label.setToolTip(
@@ -229,10 +229,10 @@ class DblSidedTool(FlatCAMTool):
grid_lay2.addWidget(self.box_type_radio, 1, 0, 1, 2)
# Object used as BOX reference
- self.box_combo = QtWidgets.QComboBox()
+ self.box_combo = FCComboBox()
self.box_combo.setModel(self.app.collection)
self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.box_combo.setCurrentIndex(1)
+ self.box_combo.set_last = True
self.box_combo.hide()
diff --git a/flatcamTools/ToolExtractDrills.py b/flatcamTools/ToolExtractDrills.py
index 287a1571..39e287a4 100644
--- a/flatcamTools/ToolExtractDrills.py
+++ b/flatcamTools/ToolExtractDrills.py
@@ -8,7 +8,7 @@
from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox
+from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, FCComboBox
from shapely.geometry import Point
@@ -52,10 +52,10 @@ class ToolExtractDrills(FlatCAMTool):
grid_lay.setColumnStretch(1, 0)
# ## Gerber Object
- self.gerber_object_combo = QtWidgets.QComboBox()
+ self.gerber_object_combo = FCComboBox()
self.gerber_object_combo.setModel(self.app.collection)
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.gerber_object_combo.setCurrentIndex(1)
+ self.gerber_object_combo.set_last = True
self.grb_label = QtWidgets.QLabel("%s:" % _("GERBER"))
self.grb_label.setToolTip('%s.' % _("Gerber from which to extract drill holes"))
diff --git a/flatcamTools/ToolFiducials.py b/flatcamTools/ToolFiducials.py
index 342f1d5c..1586f010 100644
--- a/flatcamTools/ToolFiducials.py
+++ b/flatcamTools/ToolFiducials.py
@@ -8,7 +8,7 @@
from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import FCDoubleSpinner, RadioSet, EvalEntry, FCTable
+from flatcamGUI.GUIElements import FCDoubleSpinner, RadioSet, EvalEntry, FCTable, FCComboBox
from shapely.geometry import Point, Polygon, MultiPolygon, LineString
from shapely.geometry import box as box
@@ -250,10 +250,10 @@ class ToolFiducials(FlatCAMTool):
grid_lay.addWidget(separator_line_1, 8, 0, 1, 2)
# Copper Gerber object
- self.grb_object_combo = QtWidgets.QComboBox()
+ self.grb_object_combo = FCComboBox()
self.grb_object_combo.setModel(self.app.collection)
self.grb_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.grb_object_combo.setCurrentIndex(1)
+ self.grb_object_combo.set_last = True
self.grbobj_label = QtWidgets.QLabel("%s:" % _("Copper Gerber"))
self.grbobj_label.setToolTip(
@@ -286,10 +286,10 @@ class ToolFiducials(FlatCAMTool):
self.sm_object_label.setToolTip(
_("The Soldermask Gerber object.")
)
- self.sm_object_combo = QtWidgets.QComboBox()
+ self.sm_object_combo = FCComboBox()
self.sm_object_combo.setModel(self.app.collection)
self.sm_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.sm_object_combo.setCurrentIndex(1)
+ self.sm_object_combo.set_last = True
grid_lay.addWidget(self.sm_object_label, 13, 0, 1, 2)
grid_lay.addWidget(self.sm_object_combo, 14, 0, 1, 2)
diff --git a/flatcamTools/ToolFilm.py b/flatcamTools/ToolFilm.py
index bf3af64a..98a9f1d3 100644
--- a/flatcamTools/ToolFilm.py
+++ b/flatcamTools/ToolFilm.py
@@ -65,15 +65,16 @@ class Film(FlatCAMTool):
grid0.setColumnStretch(1, 1)
# Type of object for which to create the film
- self.tf_type_obj_combo = QtWidgets.QComboBox()
- self.tf_type_obj_combo.addItem("Gerber")
- self.tf_type_obj_combo.addItem("Excellon")
- self.tf_type_obj_combo.addItem("Geometry")
+ self.tf_type_obj_combo = FCComboBox()
+ self.tf_type_obj_combo.addItems(["Gerber", "Geometry"])
+ # self.tf_type_obj_combo.addItem("Gerber")
+ # self.tf_type_obj_combo.addItem("Excellon")
+ # self.tf_type_obj_combo.addItem("Geometry")
# we get rid of item1 ("Excellon") as it is not suitable for creating film
- self.tf_type_obj_combo.view().setRowHidden(1, True)
+ # self.tf_type_obj_combo.view().setRowHidden(1, True)
self.tf_type_obj_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
- self.tf_type_obj_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
+ self.tf_type_obj_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
self.tf_type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
self.tf_type_obj_combo_label.setToolTip(
@@ -86,10 +87,10 @@ class Film(FlatCAMTool):
grid0.addWidget(self.tf_type_obj_combo, 0, 1)
# List of objects for which we can create the film
- self.tf_object_combo = QtWidgets.QComboBox()
+ self.tf_object_combo = FCComboBox()
self.tf_object_combo.setModel(self.app.collection)
self.tf_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.tf_object_combo.setCurrentIndex(1)
+ self.tf_object_combo.set_last = True
self.tf_object_label = QtWidgets.QLabel('%s:' % _("Film Object"))
self.tf_object_label.setToolTip(
@@ -100,15 +101,17 @@ class Film(FlatCAMTool):
# Type of Box Object to be used as an envelope for film creation
# Within this we can create negative
- self.tf_type_box_combo = QtWidgets.QComboBox()
- self.tf_type_box_combo.addItem("Gerber")
- self.tf_type_box_combo.addItem("Excellon")
- self.tf_type_box_combo.addItem("Geometry")
+ self.tf_type_box_combo = FCComboBox()
+ self.tf_type_box_combo.addItems(["Gerber", "Geometry"])
+
+ # self.tf_type_box_combo.addItem("Gerber")
+ # self.tf_type_box_combo.addItem("Excellon")
+ # self.tf_type_box_combo.addItem("Geometry")
# we get rid of item1 ("Excellon") as it is not suitable for box when creating film
- self.tf_type_box_combo.view().setRowHidden(1, True)
+ # self.tf_type_box_combo.view().setRowHidden(1, True)
self.tf_type_box_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
- self.tf_type_box_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
+ self.tf_type_box_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
self.tf_type_box_combo_label = QtWidgets.QLabel(_("Box Type:"))
self.tf_type_box_combo_label.setToolTip(
@@ -121,10 +124,10 @@ class Film(FlatCAMTool):
grid0.addWidget(self.tf_type_box_combo, 2, 1)
# Box
- self.tf_box_combo = QtWidgets.QComboBox()
+ self.tf_box_combo = FCComboBox()
self.tf_box_combo.setModel(self.app.collection)
self.tf_box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.tf_box_combo.setCurrentIndex(1)
+ self.tf_box_combo.set_last = True
self.tf_box_combo_label = QtWidgets.QLabel('%s:' % _("Box Object"))
self.tf_box_combo_label.setToolTip(
@@ -366,10 +369,10 @@ class Film(FlatCAMTool):
self.exc_label.setToolTip(
_("Remove the geometry of Excellon from the Film to create the holes in pads.")
)
- self.exc_combo = QtWidgets.QComboBox()
+ self.exc_combo = FCComboBox()
self.exc_combo.setModel(self.app.collection)
self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
- self.exc_combo.setCurrentIndex(1)
+ self.exc_combo.set_last = True
punch_grid.addWidget(self.exc_label, 1, 0)
punch_grid.addWidget(self.exc_combo, 1, 1)
diff --git a/flatcamTools/ToolInvertGerber.py b/flatcamTools/ToolInvertGerber.py
index 4d8e62c8..46124730 100644
--- a/flatcamTools/ToolInvertGerber.py
+++ b/flatcamTools/ToolInvertGerber.py
@@ -8,7 +8,7 @@
from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import FCButton, FCDoubleSpinner, RadioSet
+from flatcamGUI.GUIElements import FCButton, FCDoubleSpinner, RadioSet, FCComboBox
from shapely.geometry import box
@@ -63,10 +63,10 @@ class ToolInvertGerber(FlatCAMTool):
grid0.addWidget(QtWidgets.QLabel(''), 0, 0, 1, 2)
# Target Gerber Object
- self.gerber_combo = QtWidgets.QComboBox()
+ self.gerber_combo = FCComboBox()
self.gerber_combo.setModel(self.app.collection)
self.gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.gerber_combo.setCurrentIndex(1)
+ self.gerber_combo.set_last = True
self.gerber_label = QtWidgets.QLabel('%s:' % _("GERBER"))
self.gerber_label.setToolTip(
diff --git a/flatcamTools/ToolNCC.py b/flatcamTools/ToolNCC.py
index 4b7c7253..1203a3c5 100644
--- a/flatcamTools/ToolNCC.py
+++ b/flatcamTools/ToolNCC.py
@@ -101,7 +101,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
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.setCurrentIndex(1)
+ # self.object_combo.setCurrentIndex(1)
+ self.object_combo.set_last = True
self.object_label = QtWidgets.QLabel('%s:' % _("Object"))
self.object_label.setToolTip(_("Object to be cleared of excess copper."))
@@ -563,7 +564,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.box_combo = FCComboBox()
self.box_combo.setModel(self.app.collection)
self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.box_combo.setCurrentIndex(1)
+ self.box_combo.set_last = True
form1.addRow(self.box_combo_label, self.box_combo)
self.box_combo.hide()
diff --git a/flatcamTools/ToolOptimal.py b/flatcamTools/ToolOptimal.py
index 16c00efa..0cbbf0f6 100644
--- a/flatcamTools/ToolOptimal.py
+++ b/flatcamTools/ToolOptimal.py
@@ -8,7 +8,7 @@
from PyQt5 import QtWidgets, QtCore, QtGui
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import OptionalHideInputSection, FCTextArea, FCEntry, FCSpinner, FCCheckBox
+from flatcamGUI.GUIElements import OptionalHideInputSection, FCTextArea, FCEntry, FCSpinner, FCCheckBox, FCComboBox
from FlatCAMObj import FlatCAMGerber
import FlatCAMApp
@@ -63,10 +63,10 @@ class ToolOptimal(FlatCAMTool):
form_lay.addRow(QtWidgets.QLabel(""))
# ## Gerber Object to mirror
- self.gerber_object_combo = QtWidgets.QComboBox()
+ self.gerber_object_combo = FCComboBox()
self.gerber_object_combo.setModel(self.app.collection)
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.gerber_object_combo.setCurrentIndex(1)
+ self.gerber_object_combo.set_last = True
self.gerber_object_label = QtWidgets.QLabel("%s:" % _("GERBER"))
self.gerber_object_label.setToolTip(
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 7f9a8c27..0c436f58 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -94,10 +94,10 @@ class ToolPaint(FlatCAMTool, Gerber):
# ################################################
# ##### The object to be painted #################
# ################################################
- self.obj_combo = QtWidgets.QComboBox()
+ self.obj_combo = FCComboBox()
self.obj_combo.setModel(self.app.collection)
self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.obj_combo.setCurrentIndex(1)
+ self.obj_combo.set_last = True
self.object_label = QtWidgets.QLabel('%s:' % _("Object"))
self.object_label.setToolTip(_("Object to be painted."))
@@ -496,7 +496,7 @@ class ToolPaint(FlatCAMTool, Gerber):
_("The type of FlatCAM object to be used as paint reference.\n"
"It can be Gerber, Excellon or Geometry.")
)
- self.box_combo_type = QtWidgets.QComboBox()
+ self.box_combo_type = FCComboBox()
self.box_combo_type.addItem(_("Reference Gerber"))
self.box_combo_type.addItem(_("Reference Excellon"))
self.box_combo_type.addItem(_("Reference Geometry"))
@@ -506,10 +506,10 @@ class ToolPaint(FlatCAMTool, Gerber):
self.box_combo_label.setToolTip(
_("The FlatCAM object to be used as non copper clearing reference.")
)
- self.box_combo = QtWidgets.QComboBox()
+ self.box_combo = FCComboBox()
self.box_combo.setModel(self.app.collection)
self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.box_combo.setCurrentIndex(1)
+ self.box_combo.set_last = True
form1.addRow(self.box_combo_label, self.box_combo)
self.box_combo.hide()
@@ -1058,7 +1058,7 @@ class ToolPaint(FlatCAMTool, Gerber):
dia.setFlags(QtCore.Qt.ItemIsEnabled)
- tool_type_item = QtWidgets.QComboBox()
+ tool_type_item = FCComboBox()
for item in self.tool_type_item_options:
tool_type_item.addItem(item)
# tool_type_item.setStyleSheet('background-color: rgb(255,255,255)')
diff --git a/flatcamTools/ToolPanelize.py b/flatcamTools/ToolPanelize.py
index 9494c2d0..0b7f5fec 100644
--- a/flatcamTools/ToolPanelize.py
+++ b/flatcamTools/ToolPanelize.py
@@ -8,7 +8,7 @@
from PyQt5 import QtWidgets, QtGui, QtCore
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import FCSpinner, FCDoubleSpinner, RadioSet, FCCheckBox, OptionalInputSection
+from flatcamGUI.GUIElements import FCSpinner, FCDoubleSpinner, RadioSet, FCCheckBox, OptionalInputSection, FCComboBox
from FlatCAMObj import FlatCAMGeometry, FlatCAMGerber, FlatCAMExcellon
import FlatCAMApp
from copy import deepcopy
@@ -66,7 +66,7 @@ class Panelize(FlatCAMTool):
self.layout.addLayout(form_layout_0)
# Type of object to be panelized
- self.type_obj_combo = QtWidgets.QComboBox()
+ self.type_obj_combo = FCComboBox()
self.type_obj_combo.addItem("Gerber")
self.type_obj_combo.addItem("Excellon")
self.type_obj_combo.addItem("Geometry")
@@ -80,10 +80,10 @@ class Panelize(FlatCAMTool):
form_layout_0.addRow(self.type_object_label, self.type_obj_combo)
# Object to be panelized
- self.object_combo = QtWidgets.QComboBox()
+ 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.setCurrentIndex(1)
+ self.object_combo.set_last = True
self.object_combo.setToolTip(
_("Object to be panelized. This means that it will\n"
@@ -114,15 +114,16 @@ class Panelize(FlatCAMTool):
form_layout.addRow(self.reference_radio)
# Type of Box Object to be used as an envelope for panelization
- self.type_box_combo = QtWidgets.QComboBox()
- self.type_box_combo.addItem("Gerber")
- self.type_box_combo.addItem("Excellon")
- self.type_box_combo.addItem("Geometry")
+ self.type_box_combo = FCComboBox()
+ self.type_box_combo.addItems(["Gerber", "Geometry"])
+ # self.type_box_combo.addItem("Gerber")
+ # self.type_box_combo.addItem("Excellon")
+ # self.type_box_combo.addItem("Geometry")
# we get rid of item1 ("Excellon") as it is not suitable for use as a "box" for panelizing
- self.type_box_combo.view().setRowHidden(1, True)
+ # self.type_box_combo.view().setRowHidden(1, True)
self.type_box_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
- self.type_box_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
+ self.type_box_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
self.type_box_combo_label = QtWidgets.QLabel('%s:' % _("Box Type"))
self.type_box_combo_label.setToolTip(
@@ -134,10 +135,10 @@ class Panelize(FlatCAMTool):
form_layout.addRow(self.type_box_combo_label, self.type_box_combo)
# Box
- self.box_combo = QtWidgets.QComboBox()
+ self.box_combo = FCComboBox()
self.box_combo.setModel(self.app.collection)
self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.box_combo.setCurrentIndex(1)
+ self.box_combo.set_last = True
self.box_combo.setToolTip(
_("The actual object that is used a container for the\n "
diff --git a/flatcamTools/ToolPunchGerber.py b/flatcamTools/ToolPunchGerber.py
index 660dae7f..c4c9ae61 100644
--- a/flatcamTools/ToolPunchGerber.py
+++ b/flatcamTools/ToolPunchGerber.py
@@ -8,7 +8,7 @@
from PyQt5 import QtCore, QtWidgets
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox
+from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, FCComboBox
from copy import deepcopy
import logging
@@ -55,10 +55,10 @@ class ToolPunchGerber(FlatCAMTool):
grid_lay.setColumnStretch(1, 0)
# ## Gerber Object
- self.gerber_object_combo = QtWidgets.QComboBox()
+ self.gerber_object_combo = FCComboBox()
self.gerber_object_combo.setModel(self.app.collection)
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.gerber_object_combo.setCurrentIndex(1)
+ self.gerber_object_combo.set_last = True
self.grb_label = QtWidgets.QLabel("%s:" % _("GERBER"))
self.grb_label.setToolTip('%s.' % _("Gerber into which to punch holes"))
@@ -165,10 +165,10 @@ class ToolPunchGerber(FlatCAMTool):
_("Remove the geometry of Excellon from the Gerber to create the holes in pads.")
)
- self.exc_combo = QtWidgets.QComboBox()
+ self.exc_combo = FCComboBox()
self.exc_combo.setModel(self.app.collection)
self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
- self.exc_combo.setCurrentIndex(1)
+ self.exc_combo.set_last = True
grid0.addWidget(self.exc_label, 3, 0, 1, 2)
grid0.addWidget(self.exc_combo, 4, 0, 1, 2)
diff --git a/flatcamTools/ToolQRCode.py b/flatcamTools/ToolQRCode.py
index 2486ba7f..67add5c9 100644
--- a/flatcamTools/ToolQRCode.py
+++ b/flatcamTools/ToolQRCode.py
@@ -9,7 +9,7 @@ from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtCore import Qt
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import RadioSet, FCTextArea, FCSpinner, FCEntry, FCCheckBox
+from flatcamGUI.GUIElements import RadioSet, FCTextArea, FCSpinner, FCEntry, FCCheckBox, FCComboBox
from flatcamParsers.ParseSVG import *
from shapely.geometry.base import *
@@ -69,10 +69,10 @@ class QRCode(FlatCAMTool):
i_grid_lay.setColumnStretch(0, 0)
i_grid_lay.setColumnStretch(1, 1)
- self.grb_object_combo = QtWidgets.QComboBox()
+ self.grb_object_combo = FCComboBox()
self.grb_object_combo.setModel(self.app.collection)
self.grb_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.grb_object_combo.setCurrentIndex(1)
+ self.grb_object_combo.set_last = True
self.grbobj_label = QtWidgets.QLabel("%s:" % _("GERBER"))
self.grbobj_label.setToolTip(
diff --git a/flatcamTools/ToolRulesCheck.py b/flatcamTools/ToolRulesCheck.py
index ffd5844d..9deb26be 100644
--- a/flatcamTools/ToolRulesCheck.py
+++ b/flatcamTools/ToolRulesCheck.py
@@ -8,7 +8,7 @@
from PyQt5 import QtWidgets
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, OptionalInputSection
+from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, OptionalInputSection, FCComboBox
from copy import deepcopy
from FlatCAMPool import *
@@ -69,10 +69,10 @@ class RulesCheck(FlatCAMTool):
self.grid_layout.addWidget(self.all_obj_cb, 0, 2)
# Copper Top object
- self.copper_t_object = QtWidgets.QComboBox()
+ 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.setCurrentIndex(1)
+ self.copper_t_object.set_last = True
self.copper_t_object_lbl = QtWidgets.QLabel('%s:' % _("Top"))
self.copper_t_object_lbl.setToolTip(
@@ -86,10 +86,10 @@ class RulesCheck(FlatCAMTool):
self.grid_layout.addWidget(self.copper_t_cb, 1, 2)
# Copper Bottom object
- self.copper_b_object = QtWidgets.QComboBox()
+ 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.setCurrentIndex(1)
+ self.copper_b_object.set_last = True
self.copper_b_object_lbl = QtWidgets.QLabel('%s:' % _("Bottom"))
self.copper_b_object_lbl.setToolTip(
@@ -103,10 +103,10 @@ class RulesCheck(FlatCAMTool):
self.grid_layout.addWidget(self.copper_b_cb, 2, 2)
# SolderMask Top object
- self.sm_t_object = QtWidgets.QComboBox()
+ 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.setCurrentIndex(1)
+ self.sm_t_object.set_last = True
self.sm_t_object_lbl = QtWidgets.QLabel('%s:' % _("SM Top"))
self.sm_t_object_lbl.setToolTip(
@@ -120,10 +120,10 @@ class RulesCheck(FlatCAMTool):
self.grid_layout.addWidget(self.sm_t_cb, 3, 2)
# SolderMask Bottom object
- self.sm_b_object = QtWidgets.QComboBox()
+ 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.setCurrentIndex(1)
+ self.sm_b_object.set_last = True
self.sm_b_object_lbl = QtWidgets.QLabel('%s:' % _("SM Bottom"))
self.sm_b_object_lbl.setToolTip(
@@ -137,10 +137,10 @@ class RulesCheck(FlatCAMTool):
self.grid_layout.addWidget(self.sm_b_cb, 4, 2)
# SilkScreen Top object
- self.ss_t_object = QtWidgets.QComboBox()
+ 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.setCurrentIndex(1)
+ self.ss_t_object.set_last = True
self.ss_t_object_lbl = QtWidgets.QLabel('%s:' % _("Silk Top"))
self.ss_t_object_lbl.setToolTip(
@@ -154,10 +154,10 @@ class RulesCheck(FlatCAMTool):
self.grid_layout.addWidget(self.ss_t_cb, 5, 2)
# SilkScreen Bottom object
- self.ss_b_object = QtWidgets.QComboBox()
+ 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.setCurrentIndex(1)
+ self.ss_b_object.set_last = True
self.ss_b_object_lbl = QtWidgets.QLabel('%s:' % _("Silk Bottom"))
self.ss_b_object_lbl.setToolTip(
@@ -171,10 +171,10 @@ class RulesCheck(FlatCAMTool):
self.grid_layout.addWidget(self.ss_b_cb, 6, 2)
# Outline object
- self.outline_object = QtWidgets.QComboBox()
+ 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.setCurrentIndex(1)
+ self.outline_object.set_last = True
self.outline_object_lbl = QtWidgets.QLabel('%s:' % _("Outline"))
self.outline_object_lbl.setToolTip(
@@ -197,10 +197,10 @@ class RulesCheck(FlatCAMTool):
self.grid_layout.addWidget(self.excellon_title_lbl, 9, 0, 1, 3)
# Excellon 1 object
- self.e1_object = QtWidgets.QComboBox()
+ 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.setCurrentIndex(1)
+ self.e1_object.set_last = True
self.e1_object_lbl = QtWidgets.QLabel('%s:' % _("Excellon 1"))
self.e1_object_lbl.setToolTip(
@@ -215,10 +215,10 @@ class RulesCheck(FlatCAMTool):
self.grid_layout.addWidget(self.e1_cb, 10, 2)
# Excellon 2 object
- self.e2_object = QtWidgets.QComboBox()
+ 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.setCurrentIndex(1)
+ self.e2_object.set_last = True
self.e2_object_lbl = QtWidgets.QLabel('%s:' % _("Excellon 2"))
self.e2_object_lbl.setToolTip(
diff --git a/flatcamTools/ToolSolderPaste.py b/flatcamTools/ToolSolderPaste.py
index 655ab3aa..568f164e 100644
--- a/flatcamTools/ToolSolderPaste.py
+++ b/flatcamTools/ToolSolderPaste.py
@@ -61,7 +61,7 @@ class SolderPaste(FlatCAMTool):
self.obj_combo = FCComboBox(callback=self.on_rmb_combo)
self.obj_combo.setModel(self.app.collection)
self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.obj_combo.setCurrentIndex(1)
+ self.obj_combo.set_last = True
self.object_label = QtWidgets.QLabel("Gerber: ")
self.object_label.setToolTip(
@@ -383,7 +383,7 @@ class SolderPaste(FlatCAMTool):
self.geo_obj_combo = FCComboBox(callback=self.on_rmb_combo)
self.geo_obj_combo.setModel(self.app.collection)
self.geo_obj_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
- self.geo_obj_combo.setCurrentIndex(1)
+ self.geo_obj_combo.set_last = True
self.geo_object_label = QtWidgets.QLabel('%s:' % _("Geo Result"))
self.geo_object_label.setToolTip(
@@ -416,7 +416,7 @@ class SolderPaste(FlatCAMTool):
self.cnc_obj_combo = FCComboBox(callback=self.on_rmb_combo)
self.cnc_obj_combo.setModel(self.app.collection)
self.cnc_obj_combo.setRootModelIndex(self.app.collection.index(3, 0, QtCore.QModelIndex()))
- self.cnc_obj_combo.setCurrentIndex(1)
+ self.cnc_obj_combo.set_last = True
self.cnc_object_label = QtWidgets.QLabel('%s:' % _("CNC Result"))
self.cnc_object_label.setToolTip(
diff --git a/flatcamTools/ToolSub.py b/flatcamTools/ToolSub.py
index 9d547ed5..c63ff5e2 100644
--- a/flatcamTools/ToolSub.py
+++ b/flatcamTools/ToolSub.py
@@ -8,7 +8,7 @@
from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import FCCheckBox, FCButton
+from flatcamGUI.GUIElements import FCCheckBox, FCButton, FCComboBox
from shapely.geometry import Polygon, MultiPolygon, MultiLineString, LineString
from shapely.ops import cascaded_union
@@ -66,7 +66,7 @@ class ToolSub(FlatCAMTool):
form_layout.addRow(self.gerber_title)
# Target Gerber Object
- self.target_gerber_combo = QtWidgets.QComboBox()
+ 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)
@@ -80,10 +80,10 @@ class ToolSub(FlatCAMTool):
form_layout.addRow(self.target_gerber_label, self.target_gerber_combo)
# Substractor Gerber Object
- self.sub_gerber_combo = QtWidgets.QComboBox()
+ 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.setCurrentIndex(1)
+ self.sub_gerber_combo.set_last = True
self.sub_gerber_label = QtWidgets.QLabel('%s:' % _("Subtractor"))
self.sub_gerber_label.setToolTip(
@@ -118,7 +118,7 @@ class ToolSub(FlatCAMTool):
form_geo_layout.addRow(self.geo_title)
# Target Geometry Object
- self.target_geo_combo = QtWidgets.QComboBox()
+ 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)
@@ -132,10 +132,10 @@ class ToolSub(FlatCAMTool):
form_geo_layout.addRow(self.target_geo_label, self.target_geo_combo)
# Substractor Geometry Object
- self.sub_geo_combo = QtWidgets.QComboBox()
+ 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.setCurrentIndex(1)
+ self.sub_geo_combo.set_last = True
self.sub_geo_label = QtWidgets.QLabel('%s:' % _("Subtractor"))
self.sub_geo_label.setToolTip(
From 15ee54d0571301b79e30ce6b549f749bb3a7123d Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 4 Mar 2020 00:27:51 +0200
Subject: [PATCH 125/209] - updated all the FlatCAM Tools and the Gerber UI
FCComboBoxes to update the box value with the latest object loaded in the App
- some fixes in the NCC Tool - modified some strings
---
FlatCAMObj.py | 13 +++-
README.md | 6 ++
flatcamGUI/GUIElements.py | 21 ++++--
flatcamGUI/ObjectUI.py | 6 +-
flatcamTools/ToolAlignObjects.py | 6 +-
flatcamTools/ToolCalibration.py | 31 ++++++---
flatcamTools/ToolCopperThieving.py | 78 +++++++++++----------
flatcamTools/ToolCutOut.py | 6 +-
flatcamTools/ToolDblSided.py | 23 ++++---
flatcamTools/ToolExtractDrills.py | 3 +-
flatcamTools/ToolFiducials.py | 6 +-
flatcamTools/ToolFilm.py | 29 +++++---
flatcamTools/ToolImage.py | 13 ++--
flatcamTools/ToolInvertGerber.py | 3 +-
flatcamTools/ToolNCC.py | 105 ++++++++++++++++-------------
flatcamTools/ToolOptimal.py | 3 +-
flatcamTools/ToolPaint.py | 76 +++++++++++----------
flatcamTools/ToolPanelize.py | 20 ++++--
flatcamTools/ToolPunchGerber.py | 6 +-
flatcamTools/ToolQRCode.py | 5 +-
flatcamTools/ToolRulesCheck.py | 27 +++++---
flatcamTools/ToolSolderPaste.py | 9 ++-
flatcamTools/ToolSub.py | 14 ++--
23 files changed, 309 insertions(+), 200 deletions(-)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 963e64a6..610df50d 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -733,7 +733,12 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
# set the model for the Area Exception comboboxes
self.ui.obj_combo.setModel(self.app.collection)
self.ui.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.ui.obj_combo.set_last = True
+ self.ui.obj_combo.is_last = True
+ self.ui.obj_combo.obj_type = {
+ _("Gerber"): "Gerber", _("Geometry"): "Geometry"
+ }[self.ui.type_obj_combo.get_value()]
+ self.on_type_obj_index_changed()
+
self.ui.type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
self.ui.tool_type_radio.activated_custom.connect(self.on_tool_type_change)
@@ -813,10 +818,12 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
tool_diameter = tdia + (2 * cutz * math.tan(math.radians(half_tip_angle)))
self.ui.iso_tool_dia_entry.set_value(tool_diameter)
- def on_type_obj_index_changed(self, index):
- obj_type = self.ui.type_obj_combo.currentIndex()
+ def on_type_obj_index_changed(self):
+ val = self.ui.type_obj_combo.get_value()
+ obj_type = {"Gerber": 0, "Geometry": 2}[val]
self.ui.obj_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.ui.obj_combo.setCurrentIndex(0)
+ self.ui.obj_combo.obj_type = {_("Gerber"): "Gerber", _("Geometry"): "Geometry"}[val]
def on_tool_type_change(self, state):
if state == 'circular':
diff --git a/README.md b/README.md
index dd227f7c..924856e7 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,12 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+4.03.2020
+
+- updated all the FlatCAM Tools and the Gerber UI FCComboBoxes to update the box value with the latest object loaded in the App
+- some fixes in the NCC Tool
+- modified some strings
+
02.03.2020
- added property that allow the FCComboBox to update the view with the last item loaded; updated the app to use this property
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index 9e3094ec..f9c7b814 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -1286,6 +1286,7 @@ class FCComboBox(QtWidgets.QComboBox):
self.view.setContextMenuPolicy(Qt.CustomContextMenu)
self._set_last = False
+ self._obj_type = None
# the callback() will be called on customcontextmenu event and will be be passed 2 parameters:
# pos = mouse right click click position
@@ -1309,17 +1310,27 @@ class FCComboBox(QtWidgets.QComboBox):
self.setCurrentIndex(self.findText(str(val)))
@property
- def set_last(self):
+ def is_last(self):
return self._set_last
- @set_last.setter
- def set_last(self, val):
+ @is_last.setter
+ def is_last(self, val):
self._set_last = val
if self._set_last is True:
self.model().rowsInserted.connect(self.on_model_changed)
+ self.setCurrentIndex(1)
- def on_model_changed(self, first, last):
- self.setCurrentIndex(last)
+ @property
+ def obj_type(self):
+ return self._obj_type
+
+ @obj_type.setter
+ def obj_type(self, val):
+ self._obj_type = val
+
+ def on_model_changed(self, parent, first, last):
+ if self.model().data(parent, QtCore.Qt.DisplayRole) == self.obj_type:
+ self.setCurrentIndex(first)
class FCInputDialog(QtWidgets.QInputDialog):
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index 1b298f29..39de3558 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -446,11 +446,7 @@ class GerberObjectUI(ObjectUI):
# ##### Type of object to be excepted ############
# ################################################
self.type_obj_combo = FCComboBox()
- self.type_obj_combo.addItems(["Gerber", "Geometry"])
-
- # self.type_obj_combo.addItem("Gerber")
- # self.type_obj_combo.addItem("Excellon")
- # self.type_obj_combo.addItem("Geometry")
+ self.type_obj_combo.addItems([_("Gerber"), _("Geometry")])
# we get rid of item1 ("Excellon") as it is not suitable
# self.type_obj_combo.view().setRowHidden(1, True)
diff --git a/flatcamTools/ToolAlignObjects.py b/flatcamTools/ToolAlignObjects.py
index f8f6d14f..863f27c3 100644
--- a/flatcamTools/ToolAlignObjects.py
+++ b/flatcamTools/ToolAlignObjects.py
@@ -80,7 +80,7 @@ class AlignObjects(FlatCAMTool):
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.set_last = True
+ self.object_combo.is_last = True
self.object_combo.setToolTip(
_("Object to be aligned.")
@@ -116,7 +116,7 @@ class AlignObjects(FlatCAMTool):
self.aligner_object_combo = FCComboBox()
self.aligner_object_combo.setModel(self.app.collection)
self.aligner_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.aligner_object_combo.set_last = True
+ self.aligner_object_combo.is_last = True
self.aligner_object_combo.setToolTip(
_("Object to be aligned to. Aligner.")
@@ -270,11 +270,13 @@ class AlignObjects(FlatCAMTool):
obj_type = {'grb': 0, 'exc': 1}[val]
self.object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.object_combo.setCurrentIndex(0)
+ self.object_combo.obj_type = {'grb': "Gerber", 'exc': "Excellon"}[val]
def on_type_aligner_changed(self, val):
obj_type = {'grb': 0, 'exc': 1}[val]
self.aligner_object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.aligner_object_combo.setCurrentIndex(0)
+ self.aligner_object_combo.obj_type = {'grb': "Gerber", 'exc': "Excellon"}[val]
def on_align(self):
self.app.delete_selection_shape()
diff --git a/flatcamTools/ToolCalibration.py b/flatcamTools/ToolCalibration.py
index 2a3956e3..b2a879fe 100644
--- a/flatcamTools/ToolCalibration.py
+++ b/flatcamTools/ToolCalibration.py
@@ -195,7 +195,6 @@ class ToolCalibration(FlatCAMTool):
self.obj_type_combo = FCComboBox()
self.obj_type_combo.addItem(_("Gerber"))
self.obj_type_combo.addItem(_("Excellon"))
- self.obj_type_combo.setCurrentIndex(1)
self.obj_type_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
self.obj_type_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/drill16.png"))
@@ -206,7 +205,7 @@ class ToolCalibration(FlatCAMTool):
self.object_combo = FCComboBox()
self.object_combo.setModel(self.app.collection)
self.object_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
- self.object_combo.set_last = True
+ self.object_combo.is_last = True
self.object_label = QtWidgets.QLabel("%s:" % _("Source object selection"))
self.object_label.setToolTip(
@@ -630,16 +629,13 @@ class ToolCalibration(FlatCAMTool):
self.adj_object_type_combo = FCComboBox()
self.adj_object_type_combo.addItems([_("Gerber"), _("Excellon"), _("Geometry")])
- self.adj_object_type_combo.setCurrentIndex(0)
self.adj_object_type_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
self.adj_object_type_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/drill16.png"))
self.adj_object_type_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
self.adj_object_type_label = QtWidgets.QLabel("%s:" % _("Adjusted object type"))
- self.adj_object_type_label.setToolTip(
- _("Type of the FlatCAM Object to be adjusted.")
- )
+ self.adj_object_type_label.setToolTip(_("Type of the FlatCAM Object to be adjusted."))
grid_lay.addWidget(self.adj_object_type_label, 46, 0, 1, 3)
grid_lay.addWidget(self.adj_object_type_combo, 47, 0, 1, 3)
@@ -647,7 +643,10 @@ class ToolCalibration(FlatCAMTool):
self.adj_object_combo = FCComboBox()
self.adj_object_combo.setModel(self.app.collection)
self.adj_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.adj_object_combo.setCurrentIndex(0)
+ self.adj_object_combo.is_last = True
+ self.adj_object_combo.obj_type = {
+ _("Gerber"): "Gerber", _("Excellon"): "Excellon", _("Geometry"): "Geometry"
+ }[self.adj_object_type_combo.get_value()]
self.adj_object_label = QtWidgets.QLabel("%s:" % _("Adjusted object selection"))
self.adj_object_label.setToolTip(
@@ -787,6 +786,14 @@ class ToolCalibration(FlatCAMTool):
self.skewx_entry.set_value(0.0)
self.skewy_entry.set_value(0.0)
+ # default object selection is Excellon = index_1
+ self.obj_type_combo.setCurrentIndex(1)
+ self.on_obj_type_combo()
+
+ self.adj_object_type_combo.setCurrentIndex(0)
+ self.on_adj_obj_type_combo()
+ # self.adj_object_combo.setCurrentIndex(0)
+
# calibrated object
self.cal_object = None
@@ -795,12 +802,18 @@ class ToolCalibration(FlatCAMTool):
def on_obj_type_combo(self):
obj_type = self.obj_type_combo.currentIndex()
self.object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
- self.object_combo.setCurrentIndex(0)
+ # self.object_combo.setCurrentIndex(0)
+ self.object_combo.obj_type = {
+ _("Gerber"): "Gerber", _("Excellon"): "Excellon"
+ }[self.obj_type_combo.get_value()]
def on_adj_obj_type_combo(self):
obj_type = self.adj_object_type_combo.currentIndex()
self.adj_object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
- self.adj_object_combo.setCurrentIndex(0)
+ # self.adj_object_combo.setCurrentIndex(0)
+ self.adj_object_combo.obj_type = {
+ _("Gerber"): "Gerber", _("Excellon"): "Excellon", _("Geometry"): "Geometry"
+ }[self.adj_object_type_combo.get_value()]
def on_cal_source_radio(self, val):
if val == 'object':
diff --git a/flatcamTools/ToolCopperThieving.py b/flatcamTools/ToolCopperThieving.py
index 3949cdda..7000ca0e 100644
--- a/flatcamTools/ToolCopperThieving.py
+++ b/flatcamTools/ToolCopperThieving.py
@@ -69,7 +69,8 @@ class ToolCopperThieving(FlatCAMTool):
self.grb_object_combo = FCComboBox()
self.grb_object_combo.setModel(self.app.collection)
self.grb_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.grb_object_combo.set_last = True
+ self.grb_object_combo.is_last = True
+ self.grb_object_combo.obj_type = 'Gerber'
self.grbobj_label = QtWidgets.QLabel("%s:" % _("GERBER"))
self.grbobj_label.setToolTip(
@@ -135,35 +136,36 @@ class ToolCopperThieving(FlatCAMTool):
grid_lay.addWidget(self.reference_label, 3, 0)
grid_lay.addWidget(self.reference_radio, 3, 1)
- self.box_combo_type_label = QtWidgets.QLabel('%s:' % _("Ref. Type"))
- self.box_combo_type_label.setToolTip(
+ self.ref_combo_type_label = QtWidgets.QLabel('%s:' % _("Ref. Type"))
+ self.ref_combo_type_label.setToolTip(
_("The type of FlatCAM object to be used as copper thieving reference.\n"
"It can be Gerber, Excellon or Geometry.")
)
- self.box_combo_type = FCComboBox()
- self.box_combo_type.addItem(_("Reference Gerber"))
- self.box_combo_type.addItem(_("Reference Excellon"))
- self.box_combo_type.addItem(_("Reference Geometry"))
+ self.ref_combo_type = FCComboBox()
+ self.ref_combo_type.addItems([_("Gerber"), _("Excellon"), _("Geometry")])
- grid_lay.addWidget(self.box_combo_type_label, 4, 0)
- grid_lay.addWidget(self.box_combo_type, 4, 1)
+ grid_lay.addWidget(self.ref_combo_type_label, 4, 0)
+ grid_lay.addWidget(self.ref_combo_type, 4, 1)
- self.box_combo_label = QtWidgets.QLabel('%s:' % _("Ref. Object"))
- self.box_combo_label.setToolTip(
+ self.ref_combo_label = QtWidgets.QLabel('%s:' % _("Ref. Object"))
+ self.ref_combo_label.setToolTip(
_("The FlatCAM object to be used as non copper clearing reference.")
)
- self.box_combo = FCComboBox()
- self.box_combo.setModel(self.app.collection)
- self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.box_combo.set_last = True
+ self.ref_combo = FCComboBox()
+ self.ref_combo.setModel(self.app.collection)
+ self.ref_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.ref_combo.is_last = True
+ self.ref_combo.obj_type = {
+ _("Gerber"): "Gerber", _("Excellon"): "Excellon", _("Geometry"): "Geometry"
+ }[self.ref_combo_type.get_value()]
- grid_lay.addWidget(self.box_combo_label, 5, 0)
- grid_lay.addWidget(self.box_combo, 5, 1)
+ grid_lay.addWidget(self.ref_combo_label, 5, 0)
+ grid_lay.addWidget(self.ref_combo, 5, 1)
- self.box_combo.hide()
- self.box_combo_label.hide()
- self.box_combo_type.hide()
- self.box_combo_type_label.hide()
+ self.ref_combo.hide()
+ self.ref_combo_label.hide()
+ self.ref_combo_type.hide()
+ self.ref_combo_type_label.hide()
# Bounding Box Type #
self.bbox_type_radio = RadioSet([
@@ -420,7 +422,8 @@ class ToolCopperThieving(FlatCAMTool):
self.sm_object_combo = FCComboBox()
self.sm_object_combo.setModel(self.app.collection)
self.sm_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.sm_object_combo.set_last = True
+ self.sm_object_combo.is_last = True
+ self.sm_object_combo.obj_type = 'Gerber'
grid_lay_1.addWidget(self.sm_obj_label, 7, 0, 1, 3)
grid_lay_1.addWidget(self.sm_object_combo, 8, 0, 1, 3)
@@ -526,7 +529,7 @@ class ToolCopperThieving(FlatCAMTool):
self.rb_thickness = None
# SIGNALS
- self.box_combo_type.currentIndexChanged.connect(self.on_combo_box_type)
+ self.ref_combo_type.currentIndexChanged.connect(self.on_ref_combo_type_change)
self.reference_radio.group_toggle_fn = self.on_toggle_reference
self.fill_type_radio.activated_custom.connect(self.on_thieving_type)
@@ -594,22 +597,25 @@ class ToolCopperThieving(FlatCAMTool):
self.robber_line = None
self.new_solid_geometry = None
- def on_combo_box_type(self):
- obj_type = self.box_combo_type.currentIndex()
- self.box_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
- self.box_combo.setCurrentIndex(0)
+ def on_ref_combo_type_change(self):
+ obj_type = self.ref_combo_type.currentIndex()
+ self.ref_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
+ self.ref_combo.setCurrentIndex(0)
+ self.ref_combo.obj_type = {
+ _("Gerber"): "Gerber", _("Excellon"): "Excellon", _("Geometry"): "Geometry"
+ }[self.ref_combo_type.get_value()]
def on_toggle_reference(self):
if self.reference_radio.get_value() == "itself" or self.reference_radio.get_value() == "area":
- self.box_combo.hide()
- self.box_combo_label.hide()
- self.box_combo_type.hide()
- self.box_combo_type_label.hide()
+ self.ref_combo.hide()
+ self.ref_combo_label.hide()
+ self.ref_combo_type.hide()
+ self.ref_combo_type_label.hide()
else:
- self.box_combo.show()
- self.box_combo_label.show()
- self.box_combo_type.show()
- self.box_combo_type_label.show()
+ self.ref_combo.show()
+ self.ref_combo_label.show()
+ self.ref_combo_type.show()
+ self.ref_combo_type_label.show()
if self.reference_radio.get_value() == "itself":
self.bbox_type_label.show()
@@ -778,7 +784,7 @@ class ToolCopperThieving(FlatCAMTool):
self.mm = self.app.plotcanvas.graph_event_connect('mouse_move', self.on_mouse_move)
elif reference_method == 'box':
- bound_obj_name = self.box_combo.currentText()
+ bound_obj_name = self.ref_combo.currentText()
# Get reference object.
try:
diff --git a/flatcamTools/ToolCutOut.py b/flatcamTools/ToolCutOut.py
index a94d7fa5..9b0ecb3d 100644
--- a/flatcamTools/ToolCutOut.py
+++ b/flatcamTools/ToolCutOut.py
@@ -108,7 +108,7 @@ class CutOut(FlatCAMTool):
self.obj_combo = FCComboBox()
self.obj_combo.setModel(self.app.collection)
self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.obj_combo.set_last = True
+ self.obj_combo.is_last = True
grid0.addWidget(self.obj_combo, 3, 0, 1, 2)
@@ -321,7 +321,8 @@ class CutOut(FlatCAMTool):
self.man_object_combo = FCComboBox()
self.man_object_combo.setModel(self.app.collection)
self.man_object_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
- self.man_object_combo.set_last = True
+ self.man_object_combo.is_last = True
+ self.man_object_combo.obj_type = "Geometry"
self.man_object_label = QtWidgets.QLabel('%s:' % _("Geometry Object"))
self.man_object_label.setToolTip(
@@ -416,6 +417,7 @@ class CutOut(FlatCAMTool):
obj_type = {'grb': 0, 'geo': 2}[val]
self.obj_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.obj_combo.setCurrentIndex(0)
+ self.obj_combo.obj_type = {"grb": "Gerber", "geo": "Geometry"}[val]
def run(self, toggle=True):
self.app.report_usage("ToolCutOut()")
diff --git a/flatcamTools/ToolDblSided.py b/flatcamTools/ToolDblSided.py
index 8612932c..75071e88 100644
--- a/flatcamTools/ToolDblSided.py
+++ b/flatcamTools/ToolDblSided.py
@@ -59,7 +59,8 @@ class DblSidedTool(FlatCAMTool):
self.gerber_object_combo = FCComboBox()
self.gerber_object_combo.setModel(self.app.collection)
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.gerber_object_combo.set_last = True
+ self.gerber_object_combo.is_last = True
+ self.gerber_object_combo.obj_type = "Gerber"
self.botlay_label = QtWidgets.QLabel("%s:" % _("GERBER"))
self.botlay_label.setToolTip('%s.' % _("Gerber to be mirrored"))
@@ -86,7 +87,8 @@ class DblSidedTool(FlatCAMTool):
self.exc_object_combo = FCComboBox()
self.exc_object_combo.setModel(self.app.collection)
self.exc_object_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
- self.exc_object_combo.set_last = True
+ self.exc_object_combo.is_last = True
+ self.exc_object_combo.obj_type = "Excellon"
self.excobj_label = QtWidgets.QLabel("%s:" % _("EXCELLON"))
self.excobj_label.setToolTip(_("Excellon Object to be mirrored."))
@@ -113,7 +115,8 @@ class DblSidedTool(FlatCAMTool):
self.geo_object_combo = FCComboBox()
self.geo_object_combo.setModel(self.app.collection)
self.geo_object_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
- self.geo_object_combo.set_last = True
+ self.geo_object_combo.is_last = True
+ self.geo_object_combo.obj_type = "Geometry"
self.geoobj_label = QtWidgets.QLabel("%s:" % _("GEOMETRY"))
self.geoobj_label.setToolTip(
@@ -232,7 +235,7 @@ class DblSidedTool(FlatCAMTool):
self.box_combo = FCComboBox()
self.box_combo.setModel(self.app.collection)
self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.box_combo.set_last = True
+ self.box_combo.is_last = True
self.box_combo.hide()
@@ -555,14 +558,16 @@ class DblSidedTool(FlatCAMTool):
self.align_ref_label_val.set_value('%.*f' % (self.decimals, 0.0))
+ # run once to make sure that the obj_type attribute is updated in the FCComboBox
+ self.box_type_radio.set_value('grb')
+ self.on_combo_box_type('grb')
+
def on_combo_box_type(self, val):
- obj_type = {
- 'grb': 0,
- 'exc': 1,
- 'geo': 2
- }[val]
+ obj_type = {'grb': 0, 'exc': 1, 'geo': 2}[val]
self.box_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.box_combo.setCurrentIndex(0)
+ self.box_combo.obj_type = {
+ "grb": "Gerber", "exc": "Excellon", "geo": "Geometry"}[val]
def on_create_alignment_holes(self):
axis = self.align_axis_radio.get_value()
diff --git a/flatcamTools/ToolExtractDrills.py b/flatcamTools/ToolExtractDrills.py
index 39e287a4..aa4a7adc 100644
--- a/flatcamTools/ToolExtractDrills.py
+++ b/flatcamTools/ToolExtractDrills.py
@@ -55,7 +55,8 @@ class ToolExtractDrills(FlatCAMTool):
self.gerber_object_combo = FCComboBox()
self.gerber_object_combo.setModel(self.app.collection)
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.gerber_object_combo.set_last = True
+ self.gerber_object_combo.is_last = True
+ self.gerber_object_combo.obj_type = "Gerber"
self.grb_label = QtWidgets.QLabel("%s:" % _("GERBER"))
self.grb_label.setToolTip('%s.' % _("Gerber from which to extract drill holes"))
diff --git a/flatcamTools/ToolFiducials.py b/flatcamTools/ToolFiducials.py
index 1586f010..4c9070e9 100644
--- a/flatcamTools/ToolFiducials.py
+++ b/flatcamTools/ToolFiducials.py
@@ -253,7 +253,8 @@ class ToolFiducials(FlatCAMTool):
self.grb_object_combo = FCComboBox()
self.grb_object_combo.setModel(self.app.collection)
self.grb_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.grb_object_combo.set_last = True
+ self.grb_object_combo.is_last = True
+ self.grb_object_combo.obj_type = "Gerber"
self.grbobj_label = QtWidgets.QLabel("%s:" % _("Copper Gerber"))
self.grbobj_label.setToolTip(
@@ -289,7 +290,8 @@ class ToolFiducials(FlatCAMTool):
self.sm_object_combo = FCComboBox()
self.sm_object_combo.setModel(self.app.collection)
self.sm_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.sm_object_combo.set_last = True
+ self.sm_object_combo.is_last = True
+ self.sm_object_combo.obj_type = "Gerber"
grid_lay.addWidget(self.sm_object_label, 13, 0, 1, 2)
grid_lay.addWidget(self.sm_object_combo, 14, 0, 1, 2)
diff --git a/flatcamTools/ToolFilm.py b/flatcamTools/ToolFilm.py
index 98a9f1d3..252cb0fb 100644
--- a/flatcamTools/ToolFilm.py
+++ b/flatcamTools/ToolFilm.py
@@ -66,10 +66,7 @@ class Film(FlatCAMTool):
# Type of object for which to create the film
self.tf_type_obj_combo = FCComboBox()
- self.tf_type_obj_combo.addItems(["Gerber", "Geometry"])
- # self.tf_type_obj_combo.addItem("Gerber")
- # self.tf_type_obj_combo.addItem("Excellon")
- # self.tf_type_obj_combo.addItem("Geometry")
+ self.tf_type_obj_combo.addItems([_("Gerber"), _("Geometry")])
# we get rid of item1 ("Excellon") as it is not suitable for creating film
# self.tf_type_obj_combo.view().setRowHidden(1, True)
@@ -90,7 +87,7 @@ class Film(FlatCAMTool):
self.tf_object_combo = FCComboBox()
self.tf_object_combo.setModel(self.app.collection)
self.tf_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.tf_object_combo.set_last = True
+ self.tf_object_combo.is_last = True
self.tf_object_label = QtWidgets.QLabel('%s:' % _("Film Object"))
self.tf_object_label.setToolTip(
@@ -102,7 +99,7 @@ class Film(FlatCAMTool):
# Type of Box Object to be used as an envelope for film creation
# Within this we can create negative
self.tf_type_box_combo = FCComboBox()
- self.tf_type_box_combo.addItems(["Gerber", "Geometry"])
+ self.tf_type_box_combo.addItems([_("Gerber"), _("Geometry")])
# self.tf_type_box_combo.addItem("Gerber")
# self.tf_type_box_combo.addItem("Excellon")
@@ -127,7 +124,7 @@ class Film(FlatCAMTool):
self.tf_box_combo = FCComboBox()
self.tf_box_combo.setModel(self.app.collection)
self.tf_box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.tf_box_combo.set_last = True
+ self.tf_box_combo.is_last = True
self.tf_box_combo_label = QtWidgets.QLabel('%s:' % _("Box Object"))
self.tf_box_combo_label.setToolTip(
@@ -372,7 +369,9 @@ class Film(FlatCAMTool):
self.exc_combo = FCComboBox()
self.exc_combo.setModel(self.app.collection)
self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
- self.exc_combo.set_last = True
+ self.exc_combo.is_last = True
+ self.exc_combo.obj_type = "Excellon"
+
punch_grid.addWidget(self.exc_label, 1, 0)
punch_grid.addWidget(self.exc_combo, 1, 1)
@@ -542,15 +541,21 @@ class Film(FlatCAMTool):
self.file_type_radio.activated_custom.connect(self.on_file_type)
self.reset_button.clicked.connect(self.set_tool_ui)
- def on_type_obj_index_changed(self, index):
+ def on_type_obj_index_changed(self):
obj_type = self.tf_type_obj_combo.currentIndex()
self.tf_object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.tf_object_combo.setCurrentIndex(0)
+ self.tf_object_combo.obj_type = {
+ _("Gerber"): "Gerber", _("Geometry"): "Geometry"
+ }[self.tf_type_obj_combo.get_value()]
- def on_type_box_index_changed(self, index):
+ def on_type_box_index_changed(self):
obj_type = self.tf_type_box_combo.currentIndex()
self.tf_box_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.tf_box_combo.setCurrentIndex(0)
+ self.tf_box_combo.obj_type = {
+ _("Gerber"): "Gerber", _("Geometry"): "Geometry"
+ }[self.tf_type_obj_combo.get_value()]
def run(self, toggle=True):
self.app.report_usage("ToolFilm()")
@@ -613,6 +618,10 @@ class Film(FlatCAMTool):
self.orientation_radio.set_value(self.app.defaults["tools_film_orientation"])
self.pagesize_combo.set_value(self.app.defaults["tools_film_pagesize"])
+ # run once to update the obj_type attribute in the FCCombobox so the last object is showed in cb
+ self.on_type_obj_index_changed()
+ self.on_type_box_index_changed()
+
def on_film_type(self, val):
type_of_film = val
diff --git a/flatcamTools/ToolImage.py b/flatcamTools/ToolImage.py
index 8ac9ed89..603fb9e1 100644
--- a/flatcamTools/ToolImage.py
+++ b/flatcamTools/ToolImage.py
@@ -46,8 +46,7 @@ class ToolImage(FlatCAMTool):
# Type of object to create for the image
self.tf_type_obj_combo = FCComboBox()
- self.tf_type_obj_combo.addItem("Gerber")
- self.tf_type_obj_combo.addItem("Geometry")
+ self.tf_type_obj_combo.addItems([_("Gerber"), _("Geometry")])
self.tf_type_obj_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
self.tf_type_obj_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
@@ -238,7 +237,7 @@ class ToolImage(FlatCAMTool):
filename, _f = QtWidgets.QFileDialog.getOpenFileName(caption=_("Import IMAGE"), filter=filter)
filename = str(filename)
- type_obj = self.tf_type_obj_combo.get_value().lower()
+ type_obj = self.tf_type_obj_combo.get_value()
dpi = self.dpi_entry.get_value()
mode = self.image_type.get_value()
mask = [self.mask_bw_entry.get_value(), self.mask_r_entry.get_value(), self.mask_g_entry.get_value(),
@@ -250,7 +249,7 @@ class ToolImage(FlatCAMTool):
self.app.worker_task.emit({'fcn': self.import_image,
'params': [filename, type_obj, dpi, mode, mask]})
- def import_image(self, filename, o_type='gerber', dpi=96, mode='black', mask=None, outname=None):
+ def import_image(self, filename, o_type=_("Gerber"), dpi=96, mode='black', mask=None, outname=None):
"""
Adds a new Geometry Object to the projects and populates
it with shapes extracted from the SVG file.
@@ -269,10 +268,10 @@ class ToolImage(FlatCAMTool):
if mask is None:
mask = [250, 250, 250, 250]
- if o_type is None or o_type == "geometry":
+ if o_type is None or o_type == _("Geometry"):
obj_type = "geometry"
- elif o_type == "gerber":
- obj_type = o_type
+ elif o_type == _("Gerber"):
+ obj_type = "gerber"
else:
self.app.inform.emit('[ERROR_NOTCL] %s' %
_("Not supported type is picked as parameter. "
diff --git a/flatcamTools/ToolInvertGerber.py b/flatcamTools/ToolInvertGerber.py
index 46124730..ffacf098 100644
--- a/flatcamTools/ToolInvertGerber.py
+++ b/flatcamTools/ToolInvertGerber.py
@@ -66,7 +66,8 @@ class ToolInvertGerber(FlatCAMTool):
self.gerber_combo = FCComboBox()
self.gerber_combo.setModel(self.app.collection)
self.gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.gerber_combo.set_last = True
+ self.gerber_combo.is_last = True
+ self.gerber_combo.obj_type = "Gerber"
self.gerber_label = QtWidgets.QLabel('%s:' % _("GERBER"))
self.gerber_label.setToolTip(
diff --git a/flatcamTools/ToolNCC.py b/flatcamTools/ToolNCC.py
index 1203a3c5..2873be89 100644
--- a/flatcamTools/ToolNCC.py
+++ b/flatcamTools/ToolNCC.py
@@ -71,15 +71,15 @@ class NonCopperClear(FlatCAMTool, Gerber):
# ################################################
# ##### Type of object to be copper cleaned ######
# ################################################
- # 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_radio = FCComboBox()
+ # self.type_obj_radio.addItem("Gerber")
+ # self.type_obj_radio.addItem("Excellon")
+ # self.type_obj_radio.addItem("Geometry")
#
# # we get rid of item1 ("Excellon") as it is not suitable
- # self.type_obj_combo.view().setRowHidden(1, True)
- # self.type_obj_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
- # self.type_obj_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
+ # self.type_obj_radio.view().setRowHidden(1, True)
+ # self.type_obj_radio.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
+ # self.type_obj_radio.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Obj Type"))
self.type_obj_combo_label.setToolTip(
@@ -90,10 +90,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
)
self.type_obj_combo_label.setMinimumWidth(60)
- self.type_obj_combo = RadioSet([{'label': "Geometry", 'value': 'geometry'},
- {'label': "Gerber", 'value': 'gerber'}])
+ self.type_obj_radio = RadioSet([{'label': _("Geometry"), 'value': 'geometry'},
+ {'label': _("Gerber"), 'value': 'gerber'}])
- form_layout.addRow(self.type_obj_combo_label, self.type_obj_combo)
+ form_layout.addRow(self.type_obj_combo_label, self.type_obj_radio)
# ################################################
# ##### The object to be copper cleaned ##########
@@ -102,7 +102,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.object_combo.setModel(self.app.collection)
self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
# self.object_combo.setCurrentIndex(1)
- self.object_combo.set_last = True
+ self.object_combo.is_last = True
self.object_label = QtWidgets.QLabel('%s:' % _("Object"))
self.object_label.setToolTip(_("Object to be cleared of excess copper."))
@@ -546,31 +546,30 @@ class NonCopperClear(FlatCAMTool, Gerber):
form1 = QtWidgets.QFormLayout()
self.grid3.addLayout(form1, 28, 0, 1, 2)
- self.box_combo_type_label = QtWidgets.QLabel('%s:' % _("Ref. Type"))
- self.box_combo_type_label.setToolTip(
+ self.reference_combo_type_label = QtWidgets.QLabel('%s:' % _("Ref. Type"))
+ self.reference_combo_type_label.setToolTip(
_("The type of FlatCAM object to be used as non copper clearing reference.\n"
"It can be Gerber, Excellon or Geometry.")
)
- self.box_combo_type = FCComboBox()
- self.box_combo_type.addItem(_("Reference Gerber"))
- self.box_combo_type.addItem(_("Reference Excellon"))
- self.box_combo_type.addItem(_("Reference Geometry"))
- form1.addRow(self.box_combo_type_label, self.box_combo_type)
+ self.reference_combo_type = FCComboBox()
+ self.reference_combo_type.addItems([_("Gerber"), _("Excellon"), _("Geometry")])
- self.box_combo_label = QtWidgets.QLabel('%s:' % _("Ref. Object"))
- self.box_combo_label.setToolTip(
+ form1.addRow(self.reference_combo_type_label, self.reference_combo_type)
+
+ self.reference_combo_label = QtWidgets.QLabel('%s:' % _("Ref. Object"))
+ self.reference_combo_label.setToolTip(
_("The FlatCAM object to be used as non copper clearing reference.")
)
- self.box_combo = FCComboBox()
- self.box_combo.setModel(self.app.collection)
- self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.box_combo.set_last = True
- form1.addRow(self.box_combo_label, self.box_combo)
+ self.reference_combo = FCComboBox()
+ self.reference_combo.setModel(self.app.collection)
+ self.reference_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.reference_combo.is_last = True
+ form1.addRow(self.reference_combo_label, self.reference_combo)
- self.box_combo.hide()
- self.box_combo_label.hide()
- self.box_combo_type.hide()
- self.box_combo_type_label.hide()
+ self.reference_combo.hide()
+ self.reference_combo_label.hide()
+ self.reference_combo_type.hide()
+ self.reference_combo_type_label.hide()
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
@@ -706,13 +705,13 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.op_radio.activated_custom.connect(self.on_operation_change)
- self.box_combo_type.currentIndexChanged.connect(self.on_combo_box_type)
- self.select_combo.group_toggle_fn = self.on_toggle_reference
+ self.reference_combo_type.currentIndexChanged.connect(self.on_reference_combo_changed)
+ self.select_combo.currentIndexChanged.connect(self.on_toggle_reference)
self.ncc_rest_cb.stateChanged.connect(self.on_rest_machining_check)
self.ncc_order_radio.activated_custom[str].connect(self.on_order_changed)
- self.type_obj_combo.activated_custom.connect(self.on_type_obj_index_changed)
+ self.type_obj_radio.activated_custom.connect(self.on_type_obj_index_changed)
self.apply_param_to_all.clicked.connect(self.on_apply_param_to_all_clicked)
@@ -722,6 +721,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
obj_type = 0 if val == 'gerber' else 2
self.object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.object_combo.setCurrentIndex(0)
+ self.object_combo.obj_type = {
+ "gerber": "Gerber", "geometry": "Geometry"
+ }[self.type_obj_radio.get_value()]
def on_operation_change(self, val):
if val == 'iso':
@@ -910,6 +912,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
def run(self, toggle=True):
self.app.report_usage("ToolNonCopperClear()")
+ log.debug("ToolNCC().run() was launched ...")
if toggle:
# if the splitter is hidden, display it, else hide it but only if the current widget is the same
@@ -948,7 +951,12 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.tools_frame.show()
- self.type_obj_combo.set_value('gerber')
+ self.type_obj_radio.set_value('gerber')
+
+ # run those once so the obj_type attribute is updated for the FCComboboxes
+ # so the last loaded object is displayed
+ self.on_type_obj_index_changed(val="gerber")
+ self.on_reference_combo_changed()
self.op_radio.set_value(self.app.defaults["tools_nccoperation"])
self.ncc_order_radio.set_value(self.app.defaults["tools_nccorder"])
@@ -1254,22 +1262,25 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.tool_type_radio.get_value() == 'C1':
self.old_tool_dia = self.addtool_entry.get_value()
- def on_combo_box_type(self):
- obj_type = self.box_combo_type.currentIndex()
- self.box_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
- self.box_combo.setCurrentIndex(0)
+ def on_reference_combo_changed(self):
+ obj_type = self.reference_combo_type.currentIndex()
+ self.reference_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
+ self.reference_combo.setCurrentIndex(0)
+ self.reference_combo.obj_type = {
+ _("Gerber"): "Gerber", _("Excellon"): "Excellon", _("Geometry"): "Geometry"
+ }[self.reference_combo_type.get_value()]
def on_toggle_reference(self):
if self.select_combo.get_value() == _("Itself") or self.select_combo.get_value() == _("Area Selection"):
- self.box_combo.hide()
- self.box_combo_label.hide()
- self.box_combo_type.hide()
- self.box_combo_type_label.hide()
+ self.reference_combo.hide()
+ self.reference_combo_label.hide()
+ self.reference_combo_type.hide()
+ self.reference_combo_type_label.hide()
else:
- self.box_combo.show()
- self.box_combo_label.show()
- self.box_combo_type.show()
- self.box_combo_type_label.show()
+ self.reference_combo.show()
+ self.reference_combo_label.show()
+ self.reference_combo_type.show()
+ self.reference_combo_type_label.show()
def on_order_changed(self, order):
if order != 'no':
@@ -1567,7 +1578,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
"use a number."))
continue
- if self.tools_table.cellWidget(x.row(), 4).currentText() == 'iso_op':
+ if self.op_radio.get_value() == _("Isolation"):
self.iso_dia_list.append(self.tooldia)
else:
self.ncc_dia_list.append(self.tooldia)
@@ -1606,7 +1617,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.mr = self.app.plotcanvas.graph_event_connect('mouse_release', self.on_mouse_release)
self.mm = self.app.plotcanvas.graph_event_connect('mouse_move', self.on_mouse_move)
elif self.select_method == 'box':
- self.bound_obj_name = self.box_combo.currentText()
+ self.bound_obj_name = self.reference_combo.currentText()
# Get source object.
try:
self.bound_obj = self.app.collection.get_by_name(self.bound_obj_name)
diff --git a/flatcamTools/ToolOptimal.py b/flatcamTools/ToolOptimal.py
index 0cbbf0f6..7dcbf121 100644
--- a/flatcamTools/ToolOptimal.py
+++ b/flatcamTools/ToolOptimal.py
@@ -66,7 +66,8 @@ class ToolOptimal(FlatCAMTool):
self.gerber_object_combo = FCComboBox()
self.gerber_object_combo.setModel(self.app.collection)
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.gerber_object_combo.set_last = True
+ self.gerber_object_combo.is_last = True
+ self.gerber_object_combo.obj_type = "Gerber"
self.gerber_object_label = QtWidgets.QLabel("%s:" % _("GERBER"))
self.gerber_object_label.setToolTip(
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 0c436f58..3951a5cc 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -97,7 +97,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.obj_combo = FCComboBox()
self.obj_combo.setModel(self.app.collection)
self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.obj_combo.set_last = True
+ self.obj_combo.is_last = True
self.object_label = QtWidgets.QLabel('%s:' % _("Object"))
self.object_label.setToolTip(_("Object to be painted."))
@@ -491,31 +491,30 @@ class ToolPaint(FlatCAMTool, Gerber):
form1 = QtWidgets.QFormLayout()
grid4.addLayout(form1, 20, 0, 1, 2)
- self.box_combo_type_label = QtWidgets.QLabel('%s:' % _("Ref. Type"))
- self.box_combo_type_label.setToolTip(
+ self.reference_type_label = QtWidgets.QLabel('%s:' % _("Ref. Type"))
+ self.reference_type_label.setToolTip(
_("The type of FlatCAM object to be used as paint reference.\n"
"It can be Gerber, Excellon or Geometry.")
)
- self.box_combo_type = FCComboBox()
- self.box_combo_type.addItem(_("Reference Gerber"))
- self.box_combo_type.addItem(_("Reference Excellon"))
- self.box_combo_type.addItem(_("Reference Geometry"))
- form1.addRow(self.box_combo_type_label, self.box_combo_type)
+ self.reference_type_combo = FCComboBox()
+ self.reference_type_combo.addItems([_("Gerber"), _("Excellon"), _("Geometry")])
- self.box_combo_label = QtWidgets.QLabel('%s:' % _("Ref. Object"))
- self.box_combo_label.setToolTip(
+ form1.addRow(self.reference_type_label, self.reference_type_combo)
+
+ self.reference_combo_label = QtWidgets.QLabel('%s:' % _("Ref. Object"))
+ self.reference_combo_label.setToolTip(
_("The FlatCAM object to be used as non copper clearing reference.")
)
- self.box_combo = FCComboBox()
- self.box_combo.setModel(self.app.collection)
- self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.box_combo.set_last = True
- form1.addRow(self.box_combo_label, self.box_combo)
+ self.reference_combo = FCComboBox()
+ self.reference_combo.setModel(self.app.collection)
+ self.reference_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+ self.reference_combo.is_last = True
+ form1.addRow(self.reference_combo_label, self.reference_combo)
- self.box_combo.hide()
- self.box_combo_label.hide()
- self.box_combo_type.hide()
- self.box_combo_type_label.hide()
+ self.reference_combo.hide()
+ self.reference_combo_label.hide()
+ self.reference_type_combo.hide()
+ self.reference_type_label.hide()
# GO Button
self.generate_paint_button = QtWidgets.QPushButton(_('Generate Geometry'))
@@ -633,7 +632,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.order_radio.activated_custom[str].connect(self.on_order_changed)
self.rest_cb.stateChanged.connect(self.on_rest_machining_check)
- self.box_combo_type.currentIndexChanged.connect(self.on_combo_box_type)
+ self.reference_type_combo.currentIndexChanged.connect(self.on_reference_combo_changed)
self.type_obj_combo.activated_custom.connect(self.on_type_obj_changed)
self.apply_param_to_all.clicked.connect(self.on_apply_param_to_all_clicked)
@@ -660,6 +659,7 @@ class ToolPaint(FlatCAMTool, Gerber):
obj_type = 0 if val == 'gerber' else 2
self.obj_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.obj_combo.setCurrentIndex(0)
+ self.obj_combo.obj_type = {"gerber": "Gerber", "geometry": "Geometry"}[val]
idx = self.paintmethod_combo.findText(_("Laser_lines"))
if self.type_obj_combo.get_value().lower() == 'gerber':
@@ -669,6 +669,14 @@ class ToolPaint(FlatCAMTool, Gerber):
if self.paintmethod_combo.get_value() == _("Laser_lines"):
self.paintmethod_combo.set_value(_("Lines"))
+ def on_reference_combo_changed(self):
+ obj_type = self.reference_type_combo.currentIndex()
+ self.reference_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
+ self.reference_combo.setCurrentIndex(0)
+ self.reference_combo.obj_type = {
+ _("Gerber"): "Gerber", _("Excellon"): "Excellon", _("Geometry"): "Geometry"
+ }[self.reference_type_combo.get_value()]
+
def install(self, icon=None, separator=None, **kwargs):
FlatCAMTool.install(self, icon, separator, shortcut='ALT+P', **kwargs)
@@ -888,15 +896,15 @@ class ToolPaint(FlatCAMTool, Gerber):
def on_selection(self):
if self.selectmethod_combo.get_value() == _("Reference Object"):
- self.box_combo.show()
- self.box_combo_label.show()
- self.box_combo_type.show()
- self.box_combo_type_label.show()
+ self.reference_combo.show()
+ self.reference_combo_label.show()
+ self.reference_type_combo.show()
+ self.reference_type_label.show()
else:
- self.box_combo.hide()
- self.box_combo_label.hide()
- self.box_combo_type.hide()
- self.box_combo_type_label.hide()
+ self.reference_combo.hide()
+ self.reference_combo_label.hide()
+ self.reference_type_combo.hide()
+ self.reference_type_label.hide()
if self.selectmethod_combo.get_value() == _("Polygon Selection"):
# disable rest-machining for single polygon painting
@@ -997,6 +1005,11 @@ class ToolPaint(FlatCAMTool, Gerber):
# make the default object type, "Geometry"
self.type_obj_combo.set_value("geometry")
+ # run those once so the obj_type attribute is updated in the FCComboBoxes
+ # to make sure that the last loaded object is displayed in the combobox
+ self.on_type_obj_changed(val="geometry")
+ self.on_reference_combo_changed()
+
try:
diameters = [float(self.app.defaults["tools_painttooldia"])]
except (ValueError, TypeError):
@@ -1103,11 +1116,6 @@ class ToolPaint(FlatCAMTool, Gerber):
self.ui_connect()
- def on_combo_box_type(self):
- obj_type = self.box_combo_type.currentIndex()
- self.box_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
- self.box_combo.setCurrentIndex(0)
-
def on_tool_add(self, dia=None, muted=None):
self.blockSignals(True)
@@ -1411,7 +1419,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.mr = self.app.plotcanvas.graph_event_connect('mouse_release', self.on_mouse_release)
self.mm = self.app.plotcanvas.graph_event_connect('mouse_move', self.on_mouse_move)
elif self.select_method == _("Reference Object"):
- self.bound_obj_name = self.box_combo.currentText()
+ self.bound_obj_name = self.reference_combo.currentText()
# Get source object.
try:
self.bound_obj = self.app.collection.get_by_name(self.bound_obj_name)
diff --git a/flatcamTools/ToolPanelize.py b/flatcamTools/ToolPanelize.py
index 0b7f5fec..fe381fc0 100644
--- a/flatcamTools/ToolPanelize.py
+++ b/flatcamTools/ToolPanelize.py
@@ -83,7 +83,7 @@ class Panelize(FlatCAMTool):
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.set_last = True
+ self.object_combo.is_last = True
self.object_combo.setToolTip(
_("Object to be panelized. This means that it will\n"
@@ -115,10 +115,7 @@ class Panelize(FlatCAMTool):
# Type of Box Object to be used as an envelope for panelization
self.type_box_combo = FCComboBox()
- self.type_box_combo.addItems(["Gerber", "Geometry"])
- # self.type_box_combo.addItem("Gerber")
- # self.type_box_combo.addItem("Excellon")
- # self.type_box_combo.addItem("Geometry")
+ self.type_box_combo.addItems([_("Gerber"), _("Geometry")])
# we get rid of item1 ("Excellon") as it is not suitable for use as a "box" for panelizing
# self.type_box_combo.view().setRowHidden(1, True)
@@ -138,7 +135,7 @@ class Panelize(FlatCAMTool):
self.box_combo = FCComboBox()
self.box_combo.setModel(self.app.collection)
self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.box_combo.set_last = True
+ self.box_combo.is_last = True
self.box_combo.setToolTip(
_("The actual object that is used a container for the\n "
@@ -364,10 +361,18 @@ class Panelize(FlatCAMTool):
self.app.defaults["tools_panelize_panel_type"] else 'gerber'
self.panel_type_radio.set_value(panel_type)
+ # run once the following so the obj_type attribute is updated in the FCComboBoxes
+ # such that the last loaded object is populated in the combo boxes
+ self.on_type_obj_index_changed()
+ self.on_type_box_index_changed()
+
def on_type_obj_index_changed(self):
obj_type = self.type_obj_combo.currentIndex()
self.object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.object_combo.setCurrentIndex(0)
+ self.object_combo.obj_type = {
+ _("Gerber"): "Gerber", _("Excellon"): "Excellon", _("Geometry"): "Geometry"
+ }[self.type_obj_combo.get_value()]
# hide the panel type for Excellons, the panel can be only of type Geometry
if self.type_obj_combo.currentText() != 'Excellon':
@@ -382,6 +387,9 @@ class Panelize(FlatCAMTool):
obj_type = self.type_box_combo.currentIndex()
self.box_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
self.box_combo.setCurrentIndex(0)
+ self.box_combo.obj_type = {
+ _("Gerber"): "Gerber", _("Geometry"): "Geometry"
+ }[self.type_box_combo.get_value()]
def on_reference_radio_changed(self, current_val):
if current_val == 'object':
diff --git a/flatcamTools/ToolPunchGerber.py b/flatcamTools/ToolPunchGerber.py
index c4c9ae61..8c094dbf 100644
--- a/flatcamTools/ToolPunchGerber.py
+++ b/flatcamTools/ToolPunchGerber.py
@@ -58,7 +58,8 @@ class ToolPunchGerber(FlatCAMTool):
self.gerber_object_combo = FCComboBox()
self.gerber_object_combo.setModel(self.app.collection)
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.gerber_object_combo.set_last = True
+ self.gerber_object_combo.is_last = True
+ self.gerber_object_combo.obj_type = "Gerber"
self.grb_label = QtWidgets.QLabel("%s:" % _("GERBER"))
self.grb_label.setToolTip('%s.' % _("Gerber into which to punch holes"))
@@ -168,7 +169,8 @@ class ToolPunchGerber(FlatCAMTool):
self.exc_combo = FCComboBox()
self.exc_combo.setModel(self.app.collection)
self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
- self.exc_combo.set_last = True
+ self.exc_combo.is_last = True
+ self.exc_combo.obj_type = "Excellon"
grid0.addWidget(self.exc_label, 3, 0, 1, 2)
grid0.addWidget(self.exc_combo, 4, 0, 1, 2)
diff --git a/flatcamTools/ToolQRCode.py b/flatcamTools/ToolQRCode.py
index 67add5c9..b71d477e 100644
--- a/flatcamTools/ToolQRCode.py
+++ b/flatcamTools/ToolQRCode.py
@@ -72,9 +72,10 @@ class QRCode(FlatCAMTool):
self.grb_object_combo = FCComboBox()
self.grb_object_combo.setModel(self.app.collection)
self.grb_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.grb_object_combo.set_last = True
+ self.grb_object_combo.is_last = True
+ self.grb_object_combo.obj_type = "Gerber"
- self.grbobj_label = QtWidgets.QLabel("%s:" % _("GERBER"))
+ self.grbobj_label = QtWidgets.QLabel("%s:" % _("Object"))
self.grbobj_label.setToolTip(
_("Gerber Object to which the QRCode will be added.")
)
diff --git a/flatcamTools/ToolRulesCheck.py b/flatcamTools/ToolRulesCheck.py
index 9deb26be..eb236381 100644
--- a/flatcamTools/ToolRulesCheck.py
+++ b/flatcamTools/ToolRulesCheck.py
@@ -72,7 +72,8 @@ class RulesCheck(FlatCAMTool):
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.set_last = True
+ 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(
@@ -89,7 +90,8 @@ class RulesCheck(FlatCAMTool):
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.set_last = True
+ 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(
@@ -106,7 +108,8 @@ class RulesCheck(FlatCAMTool):
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.set_last = True
+ 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(
@@ -123,7 +126,8 @@ class RulesCheck(FlatCAMTool):
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.set_last = True
+ 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(
@@ -140,7 +144,8 @@ class RulesCheck(FlatCAMTool):
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.set_last = True
+ 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(
@@ -157,7 +162,8 @@ class RulesCheck(FlatCAMTool):
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.set_last = True
+ 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(
@@ -174,7 +180,8 @@ class RulesCheck(FlatCAMTool):
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.set_last = True
+ 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(
@@ -200,7 +207,8 @@ class RulesCheck(FlatCAMTool):
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.set_last = True
+ 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(
@@ -218,7 +226,8 @@ class RulesCheck(FlatCAMTool):
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.set_last = True
+ 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(
diff --git a/flatcamTools/ToolSolderPaste.py b/flatcamTools/ToolSolderPaste.py
index 568f164e..2dfd5d97 100644
--- a/flatcamTools/ToolSolderPaste.py
+++ b/flatcamTools/ToolSolderPaste.py
@@ -61,7 +61,8 @@ class SolderPaste(FlatCAMTool):
self.obj_combo = FCComboBox(callback=self.on_rmb_combo)
self.obj_combo.setModel(self.app.collection)
self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
- self.obj_combo.set_last = True
+ self.obj_combo.is_last = True
+ self.obj_combo.obj_type = "Gerber"
self.object_label = QtWidgets.QLabel("Gerber: ")
self.object_label.setToolTip(
@@ -383,7 +384,8 @@ class SolderPaste(FlatCAMTool):
self.geo_obj_combo = FCComboBox(callback=self.on_rmb_combo)
self.geo_obj_combo.setModel(self.app.collection)
self.geo_obj_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
- self.geo_obj_combo.set_last = True
+ self.geo_obj_combo.is_last = True
+ self.geo_obj_combo.obj_type = "Geometry"
self.geo_object_label = QtWidgets.QLabel('%s:' % _("Geo Result"))
self.geo_object_label.setToolTip(
@@ -416,7 +418,8 @@ class SolderPaste(FlatCAMTool):
self.cnc_obj_combo = FCComboBox(callback=self.on_rmb_combo)
self.cnc_obj_combo.setModel(self.app.collection)
self.cnc_obj_combo.setRootModelIndex(self.app.collection.index(3, 0, QtCore.QModelIndex()))
- self.cnc_obj_combo.set_last = True
+ self.cnc_obj_combo.is_last = True
+ self.geo_obj_combo.obj_type = "CNCJob"
self.cnc_object_label = QtWidgets.QLabel('%s:' % _("CNC Result"))
self.cnc_object_label.setToolTip(
diff --git a/flatcamTools/ToolSub.py b/flatcamTools/ToolSub.py
index c63ff5e2..1471bd70 100644
--- a/flatcamTools/ToolSub.py
+++ b/flatcamTools/ToolSub.py
@@ -69,7 +69,9 @@ class ToolSub(FlatCAMTool):
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.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(
@@ -83,7 +85,8 @@ class ToolSub(FlatCAMTool):
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.set_last = True
+ 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(
@@ -121,7 +124,9 @@ class ToolSub(FlatCAMTool):
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.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(
@@ -135,7 +140,8 @@ class ToolSub(FlatCAMTool):
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.set_last = True
+ 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(
From 1a06ce6a2d3745090b44ac064253a05fd79b0761 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 12 Mar 2020 18:20:22 +0200
Subject: [PATCH 126/209] - working on the new database - fix a bug in the
TextInputTool in FlatCAM Geometry Editor that crashed the sw when some fonts
are not loaded correctly
---
FlatCAMCommon.py | 597 +++++++++++++++++++++--------
README.md | 6 +
flatcamEditors/FlatCAMGeoEditor.py | 18 +-
flatcamGUI/PreferencesUI.py | 2 +-
4 files changed, 453 insertions(+), 170 deletions(-)
diff --git a/FlatCAMCommon.py b/FlatCAMCommon.py
index f324fe4c..c8a3860b 100644
--- a/FlatCAMCommon.py
+++ b/FlatCAMCommon.py
@@ -13,7 +13,7 @@
from PyQt5 import QtGui, QtCore, QtWidgets
from flatcamGUI.GUIElements import FCTable, FCEntry, FCButton, FCDoubleSpinner, FCComboBox, FCCheckBox, FCSpinner, \
- FCTree
+ FCTree, RadioSet
from camlib import to_dict
import sys
@@ -1435,22 +1435,358 @@ class ToolsDB2(QtWidgets.QWidget):
self.tree_widget.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
tree_layout.addWidget(self.tree_widget)
- table_hlay = QtWidgets.QHBoxLayout()
- grid_layout.addLayout(table_hlay, 0, 1)
+ param_hlay = QtWidgets.QHBoxLayout()
+ grid_layout.addLayout(param_hlay, 0, 1)
- self.table_widget = FCTable(drag_drop=True)
- self.table_widget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
- table_hlay.addWidget(self.table_widget)
+ # ###########################################################################
+ # ############## The UI form ################################################
+ # ###########################################################################
+ self.basic_box = QtWidgets.QGroupBox()
+ self.basic_box.setStyleSheet("""
+ QGroupBox
+ {
+ font-size: 16px;
+ font-weight: bold;
+ }
+ """)
+ self.basic_vlay = QtWidgets.QVBoxLayout()
+ self.basic_box.setLayout(self.basic_vlay)
+ self.basic_box.setTitle(_("Basic Parameters"))
+ self.basic_box.setMinimumWidth(250)
- # set the number of columns and the headers tool tips
- self.configure_table()
+ self.advanced_box = QtWidgets.QGroupBox()
+ self.advanced_box.setStyleSheet("""
+ QGroupBox
+ {
+ font-size: 16px;
+ font-weight: bold;
+ }
+ """)
+ self.advanced_vlay = QtWidgets.QVBoxLayout()
+ self.advanced_box.setLayout(self.advanced_vlay)
+ self.advanced_box.setTitle(_("Advanced Parameters"))
+ self.advanced_box.setMinimumWidth(250)
+
+ param_hlay.addLayout(self.basic_vlay)
+ param_hlay.addLayout(self.advanced_vlay)
+
+ # ###########################################################################
+ # ############### BASIC UI form #############################################
+ # ###########################################################################
+
+ grid0 = QtWidgets.QGridLayout()
+ self.advanced_vlay.addLayout(grid0)
+ grid0.setColumnStretch(0, 0)
+ grid0.setColumnStretch(1, 1)
+
+ # Tool Name
+ self.name_label = QtWidgets.QLabel('%s:' % _('Tool Name'))
+ self.name_label.setToolTip(
+ _("Tool name.\n"
+ "This is not used in the app, it's function\n"
+ "is to serve as a note for the user."))
+
+ self.name_entry = FCEntry()
+ self.name_entry.setObjectName('gdb_name')
+
+ grid0.addWidget(self.name_label, 0, 0)
+ grid0.addWidget(self.name_entry, 0, 1)
+
+ # Tool Dia
+ self.dia_label = QtWidgets.QLabel('%s:' % _('Tool Dia'))
+ self.dia_label.setToolTip(
+ _("Tool Diameter."))
+
+ self.dia_entry = FCDoubleSpinner()
+ self.dia_entry.set_range(-9999.9999, 9999.9999)
+ self.dia_entry.set_precision(self.decimals)
+ self.dia_entry.setObjectName('gdb_dia')
+
+ grid0.addWidget(self.dia_label, 1, 0)
+ grid0.addWidget(self.dia_entry, 1, 1)
+
+ # Tool Shape
+ self.shape_label = QtWidgets.QLabel('%s:' % _('Tool Shape'))
+ self.shape_label.setToolTip(
+ _("Tool Shape. \n"
+ "Can be:\n"
+ "C1 ... C4 = circular tool with x flutes\n"
+ "B = ball tip milling tool\n"
+ "V = v-shape milling tool"))
+
+ self.shape_combo = FCComboBox()
+ self.shape_combo.addItems(["C1", "C2", "C3", "C4", "B", "V"])
+ self.shape_combo.setObjectName('gdb_shape')
+
+ grid0.addWidget(self.shape_label, 2, 0)
+ grid0.addWidget(self.shape_combo, 2, 1)
+
+ # Cut Z
+ self.cutz_label = QtWidgets.QLabel('%s:' % _("Cut Z"))
+ self.cutz_label.setToolTip(
+ _("Cutting Depth.\n"
+ "The depth at which to cut into material."))
+
+ self.cutz_entry = FCDoubleSpinner()
+ self.cutz_entry.set_range(-9999.9999, 9999.9999)
+ self.cutz_entry.set_precision(self.decimals)
+ self.cutz_entry.setObjectName('gdb_cutz')
+
+ grid0.addWidget(self.cutz_label, 4, 0)
+ grid0.addWidget(self.cutz_entry, 4, 1)
+
+ # Multi Depth
+ self.multidepth_label = QtWidgets.QLabel('%s:' % _("MultiDepth"))
+ self.multidepth_label.setToolTip(
+ _("Multi Depth.\n"
+ "Selecting this will allow cutting in multiple passes,\n"
+ "each pass adding a DPP parameter depth."))
+
+ self.multidepth_cb = FCCheckBox()
+ self.multidepth_cb.setObjectName('gdb_multidepth')
+
+ grid0.addWidget(self.multidepth_label, 5, 0)
+ grid0.addWidget(self.multidepth_cb, 5, 1)
+
+ # Depth Per Pass
+ self.dpp_label = QtWidgets.QLabel('%s:' % _("DPP"))
+ self.dpp_label.setToolTip(
+ _("DPP. Depth per Pass.\n"
+ "The value used to cut into material on each pass."))
+
+ self.multidepth_entry = FCDoubleSpinner()
+ self.multidepth_entry.set_range(-9999.9999, 9999.9999)
+ self.multidepth_entry.set_precision(self.decimals)
+ self.multidepth_entry.setObjectName('gdb_multidepth_entry')
+
+ grid0.addWidget(self.dpp_label, 7, 0)
+ grid0.addWidget(self.multidepth_entry, 7, 1)
+
+ # Travel Z
+ self.travelz_label = QtWidgets.QLabel('%s:' % _("Travel Z"))
+ self.travelz_label.setToolTip(
+ _("Clearance Height.\n"
+ "Height at which the milling bit will travel between cuts,\n"
+ "above the surface of the material, avoiding all fixtures."))
+
+ self.travelz_entry = FCDoubleSpinner()
+ self.travelz_entry.set_range(-9999.9999, 9999.9999)
+ self.travelz_entry.set_precision(self.decimals)
+ self.travelz_entry.setObjectName('gdb_travel')
+
+ grid0.addWidget(self.travelz_label, 9, 0)
+ grid0.addWidget(self.travelz_entry, 9, 1)
+
+ # Feedrate X-Y
+ self.frxy_label = QtWidgets.QLabel('%s:' % _("Feedrate X-Y"))
+ self.frxy_label.setToolTip(
+ _("Feedrate X-Y. Feedrate\n"
+ "The speed on XY plane used while cutting into material."))
+
+ self.frxy_entry = FCEntry()
+ self.frxy_entry.setObjectName('gdb_frxy')
+
+ grid0.addWidget(self.frxy_label, 12, 0)
+ grid0.addWidget(self.frxy_entry, 12, 1)
+
+ # Feedrate Z
+ self.frz_label = QtWidgets.QLabel('%s:' % _("Feedrate Z"))
+ self.frz_label.setToolTip(
+ _("Feedrate Z\n"
+ "The speed on Z plane."))
+
+ self.frz_entry = FCDoubleSpinner()
+ self.frz_entry.set_range(-9999.9999, 9999.9999)
+ self.frz_entry.set_precision(self.decimals)
+ self.frz_entry.setObjectName('gdb_frz')
+
+ grid0.addWidget(self.frz_label, 14, 0)
+ grid0.addWidget(self.frz_entry, 14, 1)
+
+ # Spindle Spped
+ self.spindle_label = QtWidgets.QLabel('%s:' % _("Spindle Speed"))
+ self.spindle_label.setToolTip(
+ _("Spindle Speed.\n"
+ "If it's left empty it will not be used.\n"
+ "The speed of the spindle in RPM."))
+
+ self.spindle_entry = FCDoubleSpinner()
+ self.spindle_entry.set_range(-9999.9999, 9999.9999)
+ self.spindle_entry.set_precision(self.decimals)
+ self.frz_entry.setObjectName('gdb_spindle')
+
+ grid0.addWidget(self.spindle_label, 15, 0)
+ grid0.addWidget(self.spindle_entry, 15, 1)
+
+ # Dwell
+ self.dwell_label = QtWidgets.QLabel('%s:' % _("Dwell"))
+ self.dwell_label.setToolTip(
+ _("Dwell.\n"
+ "Check this if a delay is needed to allow\n"
+ "the spindle motor to reach it's set speed."))
+
+ self.dwell_cb = FCCheckBox()
+ self.dwell_cb.setObjectName('gdb_dwell')
+
+ grid0.addWidget(self.dwell_label, 16, 0)
+ grid0.addWidget(self.dwell_cb, 16, 1)
+
+ # Dwell Time
+ self.dwelltime_label = QtWidgets.QLabel('%s:' % _("Dwelltime"))
+ self.dwelltime_label.setToolTip(
+ _("Dwell Time.\n"
+ "A delay used to allow the motor spindle reach it's set speed."))
+
+ self.dwelltime_entry = FCDoubleSpinner()
+ self.dwelltime_entry.set_range(0.0000, 9999.9999)
+ self.dwelltime_entry.set_precision(self.decimals)
+ self.dwelltime_entry.setObjectName('gdb_dwelltime')
+
+ grid0.addWidget(self.dwelltime_label, 17, 0)
+ grid0.addWidget(self.dwelltime_entry, 17, 1)
+
+ # ###########################################################################
+ # ############### ADVANCED UI form ##########################################
+ # ###########################################################################
+
+ grid1 = QtWidgets.QGridLayout()
+ self.advanced_vlay.addLayout(grid1)
+ grid1.setColumnStretch(0, 0)
+ grid1.setColumnStretch(1, 1)
+
+ # Tool Type
+ self.type_label = QtWidgets.QLabel('%s:' % _("Tool Type"))
+ self.type_label.setToolTip(
+ _("Tool Type.\n"
+ "Can be:\n"
+ "Iso = isolation cut\n"
+ "Rough = rough cut, low feedrate, multiple passes\n"
+ "Finish = finishing cut, high feedrate"))
+
+ self.type_combo = FCComboBox()
+ self.type_combo.addItems(["Iso", "Rough", "Finish"])
+ self.type_combo.setObjectName('gdb_type')
+
+ grid1.addWidget(self.type_label, 0, 0)
+ grid1.addWidget(self.type_combo, 0, 1)
+
+ # Tool Offset
+ self.tooloffset_label = QtWidgets.QLabel('%s:' % _('Tool Offset'))
+ self.tooloffset_label.setToolTip(
+ _("Tool Offset.\n"
+ "Can be of a few types:\n"
+ "Path = zero offset\n"
+ "In = offset inside by half of tool diameter\n"
+ "Out = offset outside by half of tool diameter\n"
+ "Custom = custom offset using the Custom Offset value"))
+
+ self.tooloffset_combo = FCComboBox()
+ self.tooloffset_combo.addItems(["Path", "In", "Out", "Custom"])
+ self.tooloffset_combo.setObjectName('gdb_tool_offset')
+
+ grid1.addWidget(self.tooloffset_label, 2, 0)
+ grid1.addWidget(self.tooloffset_combo, 2, 1)
+
+ # Custom Offset
+ self.custom_offset_label = QtWidgets.QLabel('%s:' % _("Custom Offset"))
+ self.custom_offset_label.setToolTip(
+ _("Custom Offset.\n"
+ "A value to be used as offset from the current path."))
+
+ self.custom_offset_entry = FCDoubleSpinner()
+ self.custom_offset_entry.set_range(-9999.9999, 9999.9999)
+ self.custom_offset_entry.set_precision(self.decimals)
+ self.custom_offset_entry.setObjectName('gdb_custom_offset')
+
+ grid1.addWidget(self.custom_offset_label, 5, 0)
+ grid1.addWidget(self.custom_offset_entry, 5, 1)
+
+ # V-Dia
+ self.vdia_label = QtWidgets.QLabel('%s:' % _("V-Dia"))
+ self.vdia_label.setToolTip(
+ _("V-Dia.\n"
+ "Diameter of the tip for V-Shape Tools."))
+
+ self.vdia_entry = FCDoubleSpinner()
+ self.vdia_entry.set_range(0.0000, 9999.9999)
+ self.vdia_entry.set_precision(self.decimals)
+ self.vdia_entry.setObjectName('gdb_vdia')
+
+ grid1.addWidget(self.vdia_label, 7, 0)
+ grid1.addWidget(self.vdia_entry, 7, 1)
+
+ # V-Angle
+ self.vangle_label = QtWidgets.QLabel('%s:' % _("V-Angle"))
+ self.vangle_label.setToolTip(
+ _("V-Agle.\n"
+ "Angle at the tip for the V-Shape Tools."))
+
+ self.vangle_entry = FCDoubleSpinner()
+ self.vangle_entry.set_range(-360.0, 360.0)
+ self.vangle_entry.set_precision(self.decimals)
+ self.vangle_entry.setObjectName('gdb_vangle')
+
+ grid1.addWidget(self.vangle_label, 8, 0)
+ grid1.addWidget(self.vangle_entry, 8, 1)
+
+ # Feedrate Rapids
+ self.frapids_label = QtWidgets.QLabel('%s:' % _("FR Rapids"))
+ self.frapids_label.setToolTip(
+ _("FR Rapids. Feedrate Rapids\n"
+ "Speed used while moving as fast as possible.\n"
+ "This is used only by some devices that can't use\n"
+ "the G0 g-code command. Mostly 3D printers."))
+
+ self.frapids_entry = FCDoubleSpinner()
+ self.frapids_entry.set_range(0.0000, 9999.9999)
+ self.frapids_entry.set_precision(self.decimals)
+ self.frapids_entry.setObjectName('gdb_frapids')
+
+ grid1.addWidget(self.frapids_label, 10, 0)
+ grid1.addWidget(self.frapids_entry, 10, 1)
+
+ # Extra Cut
+ self.ecut_label = QtWidgets.QLabel('%s:' % _("ExtraCut"))
+ self.ecut_label.setToolTip(
+ _("Extra Cut.\n"
+ "If checked, after a isolation is finished an extra cut\n"
+ "will be added where the start and end of isolation meet\n"
+ "such as that this point is covered by this extra cut to\n"
+ "ensure a complete isolation."))
+
+ self.ecut_cb = FCCheckBox()
+ self.ecut_cb.setObjectName('gdb_ecut')
+
+ grid1.addWidget(self.ecut_label, 12, 0)
+ grid1.addWidget(self.ecut_cb, 12, 1)
+
+ # Extra Cut Length
+ self.ecut_length_label = QtWidgets.QLabel('%s:' % _("E-Cut Length"))
+ self.ecut_length_label.setToolTip(
+ _("Extra Cut length.\n"
+ "If checked, after a isolation is finished an extra cut\n"
+ "will be added where the start and end of isolation meet\n"
+ "such as that this point is covered by this extra cut to\n"
+ "ensure a complete isolation. This is the length of\n"
+ "the extra cut."))
+
+ self.ecut_length_entry = FCDoubleSpinner()
+ self.ecut_length_entry.set_range(0.0000, 9999.9999)
+ self.ecut_length_entry.set_precision(self.decimals)
+ self.ecut_length_entry.setObjectName('gdb_ecut_length')
+
+ grid1.addWidget(self.ecut_length_label, 13, 0)
+ grid1.addWidget(self.ecut_length_entry, 13, 1)
+
+ # ####################################################################
+ # ####################################################################
+ # GUI for the lower part of the window
+ # ####################################################################
+ # ####################################################################
new_vlay = QtWidgets.QVBoxLayout()
grid_layout.addLayout(new_vlay, 1, 0, 1, 2)
- # new_tool_lbl = QtWidgets.QLabel('%s' % _("New Tool"))
- # new_vlay.addWidget(new_tool_lbl, alignment=QtCore.Qt.AlignBottom)
-
self.buttons_frame = QtWidgets.QFrame()
self.buttons_frame.setContentsMargins(0, 0, 0, 0)
new_vlay.addWidget(self.buttons_frame)
@@ -1459,7 +1795,7 @@ class ToolsDB2(QtWidgets.QWidget):
self.buttons_frame.setLayout(self.buttons_box)
self.buttons_frame.show()
- add_entry_btn = FCButton(_("Add Geometry Tool in DB"))
+ add_entry_btn = FCButton(_("Add Tool in DB"))
add_entry_btn.setToolTip(
_("Add a new tool in the Tools Database.\n"
"It will be used in the Geometry UI.\n"
@@ -1510,6 +1846,64 @@ class ToolsDB2(QtWidgets.QWidget):
hlay.addWidget(self.cancel_tool_from_db)
hlay.addStretch()
+ # ##############################################################################
+ # ##############################################################################
+ # ########## SETUP THE DICTIONARIES THAT HOLD THE WIDGETS #####################
+ # ##############################################################################
+ # ##############################################################################
+
+ self.form_fields = {
+ # Basic
+ "name": self.name_entry,
+ "tooldia": self.dia_entry,
+ "tool_type": self.shape_combo,
+ "cutz": self.cutz_entry,
+ "multidepth": self.multidepth_cb,
+ "depthperpass": self.multidepth_entry,
+ "travelz": self.travelz_entry,
+ "feedrate": self.frxy_entry,
+ "feedrate_z": self.frxy_entry,
+ "spindlespeed": self.spindle_entry,
+ "dwell": self.dwell_cb,
+ "dwelltime": self.dwelltime_entry,
+
+ # Advanced
+ "type": self.type_combo,
+ "offset": self.tooloffset_combo,
+ "offset_value": self.custom_offset_entry,
+ "vtipdia": self.vdia_entry,
+ "vtipangle": self.vangle_entry,
+ "feedrate_rapid": self.frapids_entry,
+ "extracut": self.ecut_cb,
+ "extracut_length": self.ecut_length_entry
+ }
+
+ self.name2option = {
+ # Basic
+ "gdb_name": "name",
+ "gdb_dia": "tooldia",
+ "gdb_shape": "tool_type",
+ "gdb_cutz": "cutz",
+ "gdb_multidepth": "multidepth",
+ "gdb_multidepth_entry": "depthperpass",
+ "gdb_travel": "travelz",
+ "gdb_frxy": "feedrate",
+ "gdb_frz": "feedrate_z",
+ "gdb_spindle": "spindlespeed",
+ "gdb_dwell": "dwell",
+ "gdb_dwelltime": "dwelltime",
+
+ # Advanced
+ "gdb_type": "type",
+ "gdb_tool_offset": "offset",
+ "gdb_custom_offset": "offset_value",
+ "gdb_vdia": "vtipdia",
+ "gdb_vangle": "vtipangle",
+ "gdb_frapids": "feedrate_rapid",
+ "gdb_ecut": "extracut",
+ "gdb_ecut_length": "extracut_length"
+ }
+
# ##############################################################################
# ######################## SIGNALS #############################################
# ##############################################################################
@@ -1541,149 +1935,34 @@ class ToolsDB2(QtWidgets.QWidget):
row = int(item.text(0)) - 1
self.table_widget.item(row, 1).setText(item.text(1))
- def configure_table(self):
- self.table_widget.setColumnCount(27)
- # self.table_widget.setColumnWidth(0, 20)
- self.table_widget.setHorizontalHeaderLabels(
- [
- '#',
- _("Tool Name"),
- _("Tool Dia"),
- _("Tool Offset"),
- _("Custom Offset"),
- _("Tool Type"),
- _("Tool Shape"),
- _("Cut Z"),
- _("MultiDepth"),
- _("DPP"),
- _("V-Dia"),
- _("V-Angle"),
- _("Travel Z"),
- _("FR"),
- _("FR Z"),
- _("FR Rapids"),
- _("Spindle Speed"),
- _("Dwell"),
- _("Dwelltime"),
- _("Preprocessor"),
- _("ExtraCut"),
- _("E-Cut Length"),
- _("Toolchange"),
- _("Toolchange XY"),
- _("Toolchange Z"),
- _("Start Z"),
- _("End Z"),
- ]
- )
- self.table_widget.horizontalHeaderItem(0).setToolTip(
- _("Tool Index."))
- self.table_widget.horizontalHeaderItem(1).setToolTip(
- _("Tool name.\n"
- "This is not used in the app, it's function\n"
- "is to serve as a note for the user."))
- self.table_widget.horizontalHeaderItem(2).setToolTip(
- _("Tool Diameter."))
- self.table_widget.horizontalHeaderItem(3).setToolTip(
- _("Tool Offset.\n"
- "Can be of a few types:\n"
- "Path = zero offset\n"
- "In = offset inside by half of tool diameter\n"
- "Out = offset outside by half of tool diameter\n"
- "Custom = custom offset using the Custom Offset value"))
- self.table_widget.horizontalHeaderItem(4).setToolTip(
- _("Custom Offset.\n"
- "A value to be used as offset from the current path."))
- self.table_widget.horizontalHeaderItem(5).setToolTip(
- _("Tool Type.\n"
- "Can be:\n"
- "Iso = isolation cut\n"
- "Rough = rough cut, low feedrate, multiple passes\n"
- "Finish = finishing cut, high feedrate"))
- self.table_widget.horizontalHeaderItem(6).setToolTip(
- _("Tool Shape. \n"
- "Can be:\n"
- "C1 ... C4 = circular tool with x flutes\n"
- "B = ball tip milling tool\n"
- "V = v-shape milling tool"))
- self.table_widget.horizontalHeaderItem(7).setToolTip(
- _("Cutting Depth.\n"
- "The depth at which to cut into material."))
- self.table_widget.horizontalHeaderItem(8).setToolTip(
- _("Multi Depth.\n"
- "Selecting this will allow cutting in multiple passes,\n"
- "each pass adding a DPP parameter depth."))
- self.table_widget.horizontalHeaderItem(9).setToolTip(
- _("DPP. Depth per Pass.\n"
- "The value used to cut into material on each pass."))
- self.table_widget.horizontalHeaderItem(10).setToolTip(
- _("V-Dia.\n"
- "Diameter of the tip for V-Shape Tools."))
- self.table_widget.horizontalHeaderItem(11).setToolTip(
- _("V-Agle.\n"
- "Angle at the tip for the V-Shape Tools."))
- self.table_widget.horizontalHeaderItem(12).setToolTip(
- _("Clearance Height.\n"
- "Height at which the milling bit will travel between cuts,\n"
- "above the surface of the material, avoiding all fixtures."))
- self.table_widget.horizontalHeaderItem(13).setToolTip(
- _("FR. Feedrate\n"
- "The speed on XY plane used while cutting into material."))
- self.table_widget.horizontalHeaderItem(14).setToolTip(
- _("FR Z. Feedrate Z\n"
- "The speed on Z plane."))
- self.table_widget.horizontalHeaderItem(15).setToolTip(
- _("FR Rapids. Feedrate Rapids\n"
- "Speed used while moving as fast as possible.\n"
- "This is used only by some devices that can't use\n"
- "the G0 g-code command. Mostly 3D printers."))
- self.table_widget.horizontalHeaderItem(16).setToolTip(
- _("Spindle Speed.\n"
- "If it's left empty it will not be used.\n"
- "The speed of the spindle in RPM."))
- self.table_widget.horizontalHeaderItem(17).setToolTip(
- _("Dwell.\n"
- "Check this if a delay is needed to allow\n"
- "the spindle motor to reach it's set speed."))
- self.table_widget.horizontalHeaderItem(18).setToolTip(
- _("Dwell Time.\n"
- "A delay used to allow the motor spindle reach it's set speed."))
- self.table_widget.horizontalHeaderItem(19).setToolTip(
- _("Preprocessor.\n"
- "A selection of files that will alter the generated G-code\n"
- "to fit for a number of use cases."))
- self.table_widget.horizontalHeaderItem(20).setToolTip(
- _("Extra Cut.\n"
- "If checked, after a isolation is finished an extra cut\n"
- "will be added where the start and end of isolation meet\n"
- "such as that this point is covered by this extra cut to\n"
- "ensure a complete isolation."))
- self.table_widget.horizontalHeaderItem(21).setToolTip(
- _("Extra Cut length.\n"
- "If checked, after a isolation is finished an extra cut\n"
- "will be added where the start and end of isolation meet\n"
- "such as that this point is covered by this extra cut to\n"
- "ensure a complete isolation. This is the length of\n"
- "the extra cut."))
- self.table_widget.horizontalHeaderItem(22).setToolTip(
- _("Toolchange.\n"
- "It will create a toolchange event.\n"
- "The kind of toolchange is determined by\n"
- "the preprocessor file."))
- self.table_widget.horizontalHeaderItem(23).setToolTip(
- _("Toolchange XY.\n"
- "A set of coordinates in the format (x, y).\n"
- "Will determine the cartesian position of the point\n"
- "where the tool change event take place."))
- self.table_widget.horizontalHeaderItem(24).setToolTip(
- _("Toolchange Z.\n"
- "The position on Z plane where the tool change event take place."))
- self.table_widget.horizontalHeaderItem(25).setToolTip(
- _("Start Z.\n"
- "If it's left empty it will not be used.\n"
- "A position on Z plane to move immediately after job start."))
- self.table_widget.horizontalHeaderItem(26).setToolTip(
- _("End Z.\n"
- "A position on Z plane to move immediately after job stop."))
+ def storage_to_form(self, dict_storage):
+ for form_key in self.form_fields:
+ for storage_key in dict_storage:
+ if form_key == storage_key:
+ try:
+ self.form_fields[form_key].set_value(dict_storage[form_key])
+ except Exception:
+ pass
+
+ def form_to_storage(self, tool):
+ self.blockSignals(True)
+
+ widget_changed = self.sender()
+ wdg_objname = widget_changed.objectName()
+ option_changed = self.name2option[wdg_objname]
+
+
+ tooluid_item = int(tool)
+
+ for tooluid_key, tooluid_val in self.db_tool_dict.items():
+ if int(tooluid_key) == tooluid_item:
+ new_option_value = self.form_fields[option_changed].get_value()
+ if option_changed in tooluid_val:
+ tooluid_val[option_changed] = new_option_value
+ if option_changed in tooluid_val['data']:
+ tooluid_val['data'][option_changed] = new_option_value
+
+ self.blockSignals(False)
def setup_db_ui(self):
filename = self.app.data_path + '/geo_tools_db.FlatDB'
@@ -1709,12 +1988,12 @@ class ToolsDB2(QtWidgets.QWidget):
self.build_db_ui()
- self.table_widget.setupContextMenu()
- self.table_widget.addContextMenu(
+ self.tree_widget.setupContextMenu()
+ self.tree_widget.addContextMenu(
_("Add to DB"), self.on_tool_add, icon=QtGui.QIcon(self.app.resource_location + "/plus16.png"))
- self.table_widget.addContextMenu(
+ self.tree_widget.addContextMenu(
_("Copy from DB"), self.on_tool_copy, icon=QtGui.QIcon(self.app.resource_location + "/copy16.png"))
- self.table_widget.addContextMenu(
+ self.tree_widget.addContextMenu(
_("Delete from DB"), self.on_tool_delete, icon=QtGui.QIcon(self.app.resource_location + "/delete32.png"))
def build_db_ui(self):
diff --git a/README.md b/README.md
index 924856e7..f46213c8 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+12.03.2020
+
+- working on the new database
+- fix a bug in the TextInputTool in FlatCAM Geometry Editor that crashed the sw when some fonts are not loaded correctly
+
4.03.2020
- updated all the FlatCAM Tools and the Gerber UI FCComboBoxes to update the box value with the latest object loaded in the App
@@ -52,6 +57,7 @@ CAD program, and create G-Code for Isolation routing.
- fixed an issue in Gerber Editor where the multiprocessing pool was reported as closed and an ValueError exception was raised in a certain scneraio
- on Set Origin, Move to Origin and Move actions for Gerber and Excellon objects the source file will be also updated (the export functions will export an updated object)
- in FlatCAMObj.export_gerber() method took into account the possibility of polygons of type 'clear' (the ones found in the Gerber files under the LPC command)
+
17.02.2020
- updated the Excellon UI to hold data for each tool
diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py
index 6b5c3cc5..23d47e06 100644
--- a/flatcamEditors/FlatCAMGeoEditor.py
+++ b/flatcamEditors/FlatCAMGeoEditor.py
@@ -202,7 +202,7 @@ class TextInputTool(FlatCAMTool):
self.text_path = []
self.decimals = self.app.decimals
- self.f_parse = ParseFont(self)
+ self.f_parse = ParseFont(self.app)
self.f_parse.get_fonts_by_types()
# this way I can hide/show the frame
@@ -364,12 +364,10 @@ class TextInputTool(FlatCAMTool):
string_to_geo = self.text_input_entry.get_value()
font_to_geo_size = self.font_size_cb.get_value()
- self.text_path = self.f_parse.font_to_geometry(
- char_string=string_to_geo,
- font_name=self.font_name,
- font_size=font_to_geo_size,
- font_type=font_to_geo_type,
- units=self.app.defaults['units'].upper())
+ self.text_path = self.f_parse.font_to_geometry(char_string=string_to_geo, font_name=self.font_name,
+ font_size=font_to_geo_size,
+ font_type=font_to_geo_type,
+ units=self.app.defaults['units'].upper())
def font_family(self, font):
self.text_input_entry.selectAll()
@@ -403,8 +401,8 @@ class TextInputTool(FlatCAMTool):
def hide_tool(self):
self.text_tool_frame.hide()
- self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
- self.app.ui.splitter.setSizes([0, 1])
+ self.app.ui.notebook.setCurrentWidget(self.app.ui.selected_tab)
+ # self.app.ui.splitter.setSizes([0, 1])
self.app.ui.notebook.setTabText(2, _("Tool"))
@@ -2848,7 +2846,7 @@ class FCText(FCShapeTool):
self.draw_app.app.inform.emit(_("Click on 1st point ..."))
self.origin = (0, 0)
- self.text_gui = TextInputTool(self.app)
+ self.text_gui = TextInputTool(app=self.app)
self.text_gui.run()
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index acca4dfc..1cd46b4d 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -1414,7 +1414,7 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
def __init__(self, decimals=4, parent=None):
super(GeneralAppPrefGroupUI, self).__init__(self)
- self.setTitle(str(_("App Preferences")))
+ self.setTitle(_("App Preferences"))
self.decimals = decimals
# Create a form layout for the Application general settings
From 98f4a82ad4be193b5bde16ba6cb14a68e359b25a Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 13 Mar 2020 13:29:59 +0200
Subject: [PATCH 127/209] - fixed a bug in CNCJob generation out of a Excellon
object; the plot failed in case some of the geometry of the CNCJob was
invalid
---
README.md | 4 ++++
camlib.py | 3 +++
2 files changed, 7 insertions(+)
diff --git a/README.md b/README.md
index f46213c8..b57d51ea 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+13.03.2020
+
+- fixed a bug in CNCJob generation out of a Excellon object; the plot failed in case some of the geometry of the CNCJob was invalid
+
12.03.2020
- working on the new database
diff --git a/camlib.py b/camlib.py
index 88a62488..7e322deb 100644
--- a/camlib.py
+++ b/camlib.py
@@ -4752,6 +4752,9 @@ class CNCjob(Geometry):
# if the geos are travel lines it will enter into Exception
poly = geo['geom'].buffer(distance=(tooldia / 1.99999999), resolution=self.steps_per_circle)
poly = poly.simplify(tool_tolerance)
+ except Exception:
+ # deal here with unexpected plot errors due of LineStrings not valid
+ continue
else:
# plot the geometry of any objects other than Excellon
poly = geo['geom'].buffer(distance=(tooldia / 1.99999999), resolution=self.steps_per_circle)
From e6917ba1abcf91421f138e5a06722c30c8538c20 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 13 Mar 2020 15:43:26 +0200
Subject: [PATCH 128/209] - fixed Properties Tool due of recent changes to the
FCTree widget
---
FlatCAMApp.py | 2 +-
README.md | 1 +
flatcamGUI/FlatCAMGUI.py | 2 +-
flatcamGUI/GUIElements.py | 6 +++++-
flatcamTools/ToolProperties.py | 4 ++++
5 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index e4c098c4..7245a1e0 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -12727,7 +12727,7 @@ class App(QtCore.QObject):
)
return
- if act_name == _("Transparency"):
+ if act_name == _("Opacity"):
alpha_level, ok_button = QtWidgets.QInputDialog.getInt(
self.ui, _("Set alpha level ..."), '%s:' % _("Value"), min=0, max=255, step=1, value=191)
diff --git a/README.md b/README.md
index b57d51ea..458acf99 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
13.03.2020
- fixed a bug in CNCJob generation out of a Excellon object; the plot failed in case some of the geometry of the CNCJob was invalid
+- fixed Properties Tool due of recent changes to the FCTree widget
12.03.2020
diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py
index 82d55bcf..35b9ae2a 100644
--- a/flatcamGUI/FlatCAMGUI.py
+++ b/flatcamGUI/FlatCAMGUI.py
@@ -703,7 +703,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.menuprojectcolor.addSeparator()
self.menuproject_custom = self.menuprojectcolor.addAction(
- QtGui.QIcon(self.app.resource_location + '/set_color32.png'), _('Transparency'))
+ QtGui.QIcon(self.app.resource_location + '/set_color32.png'), _('Opacity'))
self.menuproject_custom = self.menuprojectcolor.addAction(
QtGui.QIcon(self.app.resource_location + '/set_color32.png'), _('Default'))
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index f9c7b814..fbfd739e 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -187,7 +187,11 @@ class FCTree(QtWidgets.QTreeWidget):
header.resizeSection(column, width)
def is_editable(self, tested_col):
- return False if tested_col in self.protected_column else True
+ try:
+ ret_val = False if tested_col in self.protected_column else True
+ except TypeError:
+ ret_val = False
+ return ret_val
def addParent(self, parent, title, expanded=False, color=None, font=None):
item = QtWidgets.QTreeWidgetItem(parent, [title])
diff --git a/flatcamTools/ToolProperties.py b/flatcamTools/ToolProperties.py
index b09d6e19..da783097 100644
--- a/flatcamTools/ToolProperties.py
+++ b/flatcamTools/ToolProperties.py
@@ -129,6 +129,10 @@ class Properties(FlatCAMTool):
for obj in obj_list:
self.addItems(obj)
self.app.inform.emit('[success] %s' % _("Object Properties are displayed."))
+
+ # make sure that the FCTree widget columns are resized to content
+ self.treeWidget.resize_sig.emit()
+
self.app.ui.notebook.setTabText(2, _("Properties Tool"))
def addItems(self, obj):
From f4f87eb2a77be4dc4b1f2a8fbc28a9744886c927 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 20 Mar 2020 05:04:52 +0200
Subject: [PATCH 129/209] - updated the "re-cut" feature in Geometry object;
now if the re-cut parameter is non zero it will cut half of the entered
distance before the isolation end and half of it after the isolation end
---
README.md | 4 +++
camlib.py | 87 +++++++++++++++++++++++++++++++++++++++++++------------
2 files changed, 73 insertions(+), 18 deletions(-)
diff --git a/README.md b/README.md
index 458acf99..dd05995f 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+20.03.2020
+
+- updated the "re-cut" feature in Geometry object; now if the re-cut parameter is non zero it will cut half of the entered distance before the isolation end and half of it after the isolation end
+
13.03.2020
- fixed a bug in CNCJob generation out of a Excellon object; the plot failed in case some of the geometry of the CNCJob was invalid
diff --git a/camlib.py b/camlib.py
index 7e322deb..c2e04a22 100644
--- a/camlib.py
+++ b/camlib.py
@@ -26,7 +26,7 @@ from lxml import etree as ET
from shapely.geometry import Polygon, LineString, Point, LinearRing, MultiLineString, MultiPoint, MultiPolygon
from shapely.geometry import box as shply_box
-from shapely.ops import cascaded_union, unary_union, polygonize
+from shapely.ops import cascaded_union, unary_union, substring
import shapely.affinity as affinity
from shapely.wkt import loads as sloads
from shapely.wkt import dumps as sdumps
@@ -5166,8 +5166,8 @@ class CNCjob(Geometry):
next_y = pt[1]
gcode += self.doformat(p.linear_code, x=next_x, y=next_y, z=z_cut) # Linear motion to point
- prev_x = pt[0]
- prev_y = pt[1]
+ prev_x = next_x
+ prev_y = next_y
# this line is added to create an extra cut over the first point in patch
# to make sure that we remove the copper leftovers
@@ -5186,23 +5186,74 @@ class CNCjob(Geometry):
# between point 0 and point 1 is more than the distance we set for the extra cut then make an interpolation
# along the path and find the point at the distance extracut_length
+ # this is an extra line therefore lift the milling bit
+ gcode += self.doformat(p.lift_code, x=prev_x, y=prev_y, z_move=z_move) # lift
+
if extracut_length == 0.0:
- gcode += self.doformat(p.linear_code, x=path[1][0], y=path[1][1])
- last_pt = path[1]
- else:
- if abs(distance(path[1], path[0])) > extracut_length:
- i_point = LineString([path[0], path[1]]).interpolate(extracut_length)
- gcode += self.doformat(p.linear_code, x=i_point.x, y=i_point.y)
- last_pt = (i_point.x, i_point.y)
+ extra_path = [path[-1], path[0], path[1]]
+ new_x = path[-1][0]
+ new_y = path[-1][1]
+
+ # move fast to the new first point
+ gcode += self.doformat(p.rapid_code, x=new_x, y=new_y)
+
+ # lower the milling bit
+ # Different feedrate for vertical cut?
+ if self.z_feedrate is not None:
+ gcode += self.doformat(p.z_feedrate_code)
+ gcode += self.doformat(p.down_code, x=new_x, y=new_y, z_cut=z_cut)
+ gcode += self.doformat(p.feedrate_code, feedrate=feedrate)
else:
- last_pt = path[0]
- for pt in path[1:]:
- extracut_distance = abs(distance(pt, last_pt))
- if extracut_distance <= extracut_length:
- gcode += self.doformat(p.linear_code, x=pt[0], y=pt[1])
- last_pt = pt
- else:
- break
+ gcode += self.doformat(p.down_code, x=new_x, y=new_y, z_cut=z_cut) # Start cutting
+
+ # start cutting the extra line
+ last_pt = extra_path[0]
+ for pt in extra_path[1:]:
+ gcode += self.doformat(p.linear_code, x=pt[0], y=pt[1])
+ last_pt = pt
+ else:
+ # go to the point that is 5% in length before the end (therefore 95% length from start of the line),
+ # along the line to be cut
+ extra_line = substring(target_linear, (-extracut_length * 0.5), (extracut_length * 0.5))
+ extra_path = list(extra_line.coords)
+ new_x = extra_path[0][0]
+ new_y = extra_path[0][1]
+
+ # move fast to the new first point
+ gcode += self.doformat(p.rapid_code, x=new_x, y=new_y)
+
+ # lower the milling bit
+ # Different feedrate for vertical cut?
+ if self.z_feedrate is not None:
+ gcode += self.doformat(p.z_feedrate_code)
+ gcode += self.doformat(p.down_code, x=new_x, y=new_y, z_cut=z_cut)
+ gcode += self.doformat(p.feedrate_code, feedrate=feedrate)
+ else:
+ gcode += self.doformat(p.down_code, x=new_x, y=new_y, z_cut=z_cut) # Start cutting
+
+ # start cutting the extra line
+ last_pt = extra_path[0]
+ for pt in extra_path[1:]:
+ gcode += self.doformat(p.linear_code, x=pt[0], y=pt[1])
+ last_pt = pt
+
+ # if extracut_length == 0.0:
+ # gcode += self.doformat(p.linear_code, x=path[1][0], y=path[1][1])
+ # last_pt = path[1]
+ # else:
+ # if abs(distance(path[1], path[0])) > extracut_length:
+ # i_point = LineString([path[0], path[1]]).interpolate(extracut_length)
+ # gcode += self.doformat(p.linear_code, x=i_point.x, y=i_point.y)
+ # last_pt = (i_point.x, i_point.y)
+ # else:
+ # last_pt = path[0]
+ # for pt in path[1:]:
+ # extracut_distance = abs(distance(pt, last_pt))
+ # if extracut_distance <= extracut_length:
+ # gcode += self.doformat(p.linear_code, x=pt[0], y=pt[1])
+ # last_pt = pt
+ # else:
+ # break
# Up to travelling height.
if up:
From 22f74edfab7101b0fda2852907af8c4cfe8a1712 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 20 Mar 2020 13:25:14 +0200
Subject: [PATCH 130/209] - added to Paint and NCC Tool a feature that allow
polygon area selection when the reference is selected as Area Selection - in
Paint Tool and NCC Tool added ability to use Escape Tool to cancel Area
Selection and for Paint Tool to cancel Polygon Selection
---
FlatCAMApp.py | 4 +
FlatCAMTool.py | 94 +++++++++++++-
README.md | 2 +
flatcamGUI/PreferencesUI.py | 50 ++++++--
flatcamTools/ToolNCC.py | 221 ++++++++++++++++++++++++++++-----
flatcamTools/ToolPaint.py | 240 ++++++++++++++++++++++++++++++------
6 files changed, 527 insertions(+), 84 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 7245a1e0..0564f774 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -786,6 +786,7 @@ class App(QtCore.QObject):
"tools_ncc_offset_choice": False,
"tools_ncc_offset_value": 0.0000,
"tools_nccref": _('Itself'),
+ "tools_ncc_area_shape": "square",
"tools_ncc_plotting": 'normal',
"tools_nccmilling_type": 'cl',
"tools_ncctool_type": 'C1',
@@ -812,6 +813,7 @@ class App(QtCore.QObject):
"tools_paintmargin": 0.0,
"tools_paintmethod": _("Seed"),
"tools_selectmethod": _("All Polygons"),
+ "tools_paint_area_shape": "square",
"tools_pathconnect": True,
"tools_paintcontour": True,
"tools_paint_plotting": 'normal',
@@ -1468,6 +1470,7 @@ class App(QtCore.QObject):
"tools_ncc_offset_choice": self.ui.tools_defaults_form.tools_ncc_group.ncc_choice_offset_cb,
"tools_ncc_offset_value": self.ui.tools_defaults_form.tools_ncc_group.ncc_offset_spinner,
"tools_nccref": self.ui.tools_defaults_form.tools_ncc_group.select_combo,
+ "tools_ncc_area_shape": self.ui.tools_defaults_form.tools_ncc_group.area_shape_radio,
"tools_ncc_plotting": self.ui.tools_defaults_form.tools_ncc_group.ncc_plotting_radio,
"tools_nccmilling_type": self.ui.tools_defaults_form.tools_ncc_group.milling_type_radio,
"tools_ncctool_type": self.ui.tools_defaults_form.tools_ncc_group.tool_type_radio,
@@ -1494,6 +1497,7 @@ class App(QtCore.QObject):
"tools_paintmargin": self.ui.tools_defaults_form.tools_paint_group.paintmargin_entry,
"tools_paintmethod": self.ui.tools_defaults_form.tools_paint_group.paintmethod_combo,
"tools_selectmethod": self.ui.tools_defaults_form.tools_paint_group.selectmethod_combo,
+ "tools_paint_area_shape": self.ui.tools_defaults_form.tools_paint_group.area_shape_radio,
"tools_pathconnect": self.ui.tools_defaults_form.tools_paint_group.pathconnect_cb,
"tools_paintcontour": self.ui.tools_defaults_form.tools_paint_group.contour_cb,
"tools_paint_plotting": self.ui.tools_defaults_form.tools_paint_group.paint_plotting_radio,
diff --git a/FlatCAMTool.py b/FlatCAMTool.py
index 02bd08bd..3343c06c 100644
--- a/FlatCAMTool.py
+++ b/FlatCAMTool.py
@@ -9,7 +9,7 @@
from PyQt5 import QtGui, QtCore, QtWidgets, QtWidgets
from PyQt5.QtCore import Qt
-from shapely.geometry import Polygon
+from shapely.geometry import Polygon, LineString
import gettext
import FlatCAMTranslation as fcTranslate
@@ -106,6 +106,7 @@ class FlatCAMTool(QtWidgets.QWidget):
:param old_coords: old coordinates
:param coords: new coordinates
+ :param kwargs:
:return:
"""
@@ -143,10 +144,101 @@ class FlatCAMTool(QtWidgets.QWidget):
if self.app.is_legacy is True:
self.app.tool_shapes.redraw()
+ def draw_selection_shape_polygon(self, points, **kwargs):
+ """
+
+ :param points: a list of points from which to create a Polygon
+ :param kwargs:
+ :return:
+ """
+ if 'color' in kwargs:
+ color = kwargs['color']
+ else:
+ color = self.app.defaults['global_sel_line']
+
+ if 'face_color' in kwargs:
+ face_color = kwargs['face_color']
+ else:
+ face_color = self.app.defaults['global_sel_fill']
+
+ if 'face_alpha' in kwargs:
+ face_alpha = kwargs['face_alpha']
+ else:
+ face_alpha = 0.3
+ if len(points) < 3:
+ sel_rect = LineString(points)
+ else:
+ sel_rect = Polygon(points)
+
+ # color_t = Color(face_color)
+ # color_t.alpha = face_alpha
+
+ color_t = face_color[:-2] + str(hex(int(face_alpha * 255)))[2:]
+
+ self.app.tool_shapes.add(sel_rect, color=color, face_color=color_t, update=True,
+ layer=0, tolerance=None)
+ if self.app.is_legacy is True:
+ self.app.tool_shapes.redraw()
+
def delete_tool_selection_shape(self):
self.app.tool_shapes.clear()
self.app.tool_shapes.redraw()
+ def draw_moving_selection_shape_poly(self, points, data, **kwargs):
+ """
+
+ :param points:
+ :param data:
+ :param kwargs:
+ :return:
+ """
+ if 'color' in kwargs:
+ color = kwargs['color']
+ else:
+ color = self.app.defaults['global_sel_line']
+
+ if 'face_color' in kwargs:
+ face_color = kwargs['face_color']
+ else:
+ face_color = self.app.defaults['global_sel_fill']
+
+ if 'face_alpha' in kwargs:
+ face_alpha = kwargs['face_alpha']
+ else:
+ face_alpha = 0.3
+
+ temp_points = [x for x in points]
+ try:
+ if data != temp_points[-1]:
+ temp_points.append(data)
+ except IndexError:
+ return
+
+ l_points = len(temp_points)
+ if l_points == 2:
+ geo = LineString(temp_points)
+ elif l_points > 2:
+ geo = Polygon(temp_points)
+ else:
+ return
+
+ color_t = face_color[:-2] + str(hex(int(face_alpha * 255)))[2:]
+ color_t_error = "#00000000"
+
+ if geo.is_valid and not geo.is_empty:
+ self.app.move_tool.sel_shapes.add(geo, color=color, face_color=color_t, update=True,
+ layer=0, tolerance=None)
+ elif not geo.is_valid:
+ self.app.move_tool.sel_shapes.add(geo, color="red", face_color=color_t_error, update=True,
+ layer=0, tolerance=None)
+
+ if self.app.is_legacy is True:
+ self.app.move_tool.sel_shapes.redraw()
+
+ def delete_moving_selection_shape(self):
+ self.app.move_tool.sel_shapes.clear()
+ self.app.move_tool.sel_shapes.redraw()
+
def confirmation_message(self, accepted, minval, maxval):
if accepted is False:
self.app.inform.emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' %
diff --git a/README.md b/README.md
index dd05995f..012292c8 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,8 @@ CAD program, and create G-Code for Isolation routing.
20.03.2020
- updated the "re-cut" feature in Geometry object; now if the re-cut parameter is non zero it will cut half of the entered distance before the isolation end and half of it after the isolation end
+- added to Paint and NCC Tool a feature that allow polygon area selection when the reference is selected as Area Selection
+- in Paint Tool and NCC Tool added ability to use Escape Tool to cancel Area Selection and for Paint Tool to cancel Polygon Selection
13.03.2020
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index 1cd46b4d..239b6fbb 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -2521,7 +2521,7 @@ class GerberEditorPrefGroupUI(OptionsGroupUI):
self.adddim_label = QtWidgets.QLabel('%s:' % _('Aperture Dimensions'))
self.adddim_label.setToolTip(
- _("Diameters of the cutting tools, separated by comma.\n"
+ _("Diameters of the tools, separated by comma.\n"
"The value of the diameter has to use the dot decimals separator.\n"
"Valid values: 0.3, 1.0")
)
@@ -3970,9 +3970,9 @@ class GeometryGenPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.tools_label, 2, 0, 1, 2)
# Tooldia
- tdlabel = QtWidgets.QLabel('%s:' % _('Tool dia'))
+ tdlabel = QtWidgets.QLabel('%s:' % _('Tools Dia'))
tdlabel.setToolTip(
- _("Diameters of the cutting tools, separated by comma.\n"
+ _("Diameters of the tools, separated by comma.\n"
"The value of the diameter has to use the dot decimals separator.\n"
"Valid values: 0.3, 1.0")
)
@@ -5139,7 +5139,7 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
ncctdlabel = QtWidgets.QLabel('%s:' % _('Tools Dia'))
ncctdlabel.setToolTip(
- _("Diameters of the cutting tools, separated by comma.\n"
+ _("Diameters of the tools, separated by comma.\n"
"The value of the diameter has to use the dot decimals separator.\n"
"Valid values: 0.3, 1.0")
)
@@ -5418,10 +5418,21 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
grid0.addWidget(select_label, 18, 0)
grid0.addWidget(self.select_combo, 18, 1)
+ self.area_shape_label = QtWidgets.QLabel('%s:' % _("Shape"))
+ self.area_shape_label.setToolTip(
+ _("The kind of selection shape used for area selection.")
+ )
+
+ self.area_shape_radio = RadioSet([{'label': _("Square"), 'value': 'square'},
+ {'label': _("Polygon"), 'value': 'polygon'}])
+
+ grid0.addWidget(self.area_shape_label, 19, 0)
+ grid0.addWidget(self.area_shape_radio, 19, 1)
+
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid0.addWidget(separator_line, 19, 0, 1, 2)
+ grid0.addWidget(separator_line, 20, 0, 1, 2)
# ## Plotting type
self.ncc_plotting_radio = RadioSet([{'label': _('Normal'), 'value': 'normal'},
@@ -5431,8 +5442,8 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
_("- 'Normal' - normal plotting, done at the end of the NCC job\n"
"- 'Progressive' - after each shape is generated it will be plotted.")
)
- grid0.addWidget(plotting_label, 20, 0)
- grid0.addWidget(self.ncc_plotting_radio, 20, 1)
+ grid0.addWidget(plotting_label, 21, 0)
+ grid0.addWidget(self.ncc_plotting_radio, 21, 1)
self.layout.addStretch()
@@ -5695,7 +5706,7 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
# Tool dia
ptdlabel = QtWidgets.QLabel('%s:' % _('Tools Dia'))
ptdlabel.setToolTip(
- _("Diameters of the cutting tools, separated by comma.\n"
+ _("Diameters of the tools, separated by comma.\n"
"The value of the diameter has to use the dot decimals separator.\n"
"Valid values: 0.3, 1.0")
)
@@ -5931,10 +5942,21 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
grid0.addWidget(selectlabel, 15, 0)
grid0.addWidget(self.selectmethod_combo, 15, 1)
+ self.area_shape_label = QtWidgets.QLabel('%s:' % _("Shape"))
+ self.area_shape_label.setToolTip(
+ _("The kind of selection shape used for area selection.")
+ )
+
+ self.area_shape_radio = RadioSet([{'label': _("Square"), 'value': 'square'},
+ {'label': _("Polygon"), 'value': 'polygon'}])
+
+ grid0.addWidget(self.area_shape_label, 18, 0)
+ grid0.addWidget(self.area_shape_radio, 18, 1)
+
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid0.addWidget(separator_line, 16, 0, 1, 2)
+ grid0.addWidget(separator_line, 19, 0, 1, 2)
# ## Plotting type
self.paint_plotting_radio = RadioSet([{'label': _('Normal'), 'value': 'normal'},
@@ -5944,8 +5966,8 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
_("- 'Normal' - normal plotting, done at the end of the Paint job\n"
"- 'Progressive' - after each shape is generated it will be plotted.")
)
- grid0.addWidget(plotting_label, 17, 0)
- grid0.addWidget(self.paint_plotting_radio, 17, 1)
+ grid0.addWidget(plotting_label, 20, 0)
+ grid0.addWidget(self.paint_plotting_radio, 20, 1)
self.layout.addStretch()
@@ -6748,9 +6770,11 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
self.layout.addLayout(grid0)
# Nozzle Tool Diameters
- nozzletdlabel = QtWidgets.QLabel('%s:' % _('Tools dia'))
+ nozzletdlabel = QtWidgets.QLabel('%s:' % _('Tools Dia'))
nozzletdlabel.setToolTip(
- _("Diameters of nozzle tools, separated by ','")
+ _("Diameters of the tools, separated by comma.\n"
+ "The value of the diameter has to use the dot decimals separator.\n"
+ "Valid values: 0.3, 1.0")
)
self.nozzle_tool_dia_entry = FCEntry()
diff --git a/flatcamTools/ToolNCC.py b/flatcamTools/ToolNCC.py
index 2873be89..630e87b5 100644
--- a/flatcamTools/ToolNCC.py
+++ b/flatcamTools/ToolNCC.py
@@ -22,6 +22,8 @@ from shapely.geometry import base
from shapely.ops import cascaded_union
from shapely.geometry import MultiPolygon, Polygon, MultiLineString, LineString, LinearRing
+from matplotlib.backend_bases import KeyEvent as mpl_key_event
+
import logging
import traceback
import gettext
@@ -571,10 +573,25 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.reference_combo_type.hide()
self.reference_combo_type_label.hide()
+ # Area Selection shape
+ self.area_shape_label = QtWidgets.QLabel('%s:' % _("Shape"))
+ self.area_shape_label.setToolTip(
+ _("The kind of selection shape used for area selection.")
+ )
+
+ self.area_shape_radio = RadioSet([{'label': _("Square"), 'value': 'square'},
+ {'label': _("Polygon"), 'value': 'polygon'}])
+
+ self.grid3.addWidget(self.area_shape_label, 29, 0)
+ self.grid3.addWidget(self.area_shape_radio, 29, 1)
+
+ self.area_shape_label.hide()
+ self.area_shape_radio.hide()
+
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.grid3.addWidget(separator_line, 29, 0, 1, 2)
+ self.grid3.addWidget(separator_line, 30, 0, 1, 2)
self.generate_ncc_button = QtWidgets.QPushButton(_('Generate Geometry'))
self.generate_ncc_button.setToolTip(
@@ -652,9 +669,17 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.cursor_pos = None
self.mouse_is_dragging = False
+ # store here the points for the "Polygon" area selection shape
+ self.points = []
+ # set this as True when in middle of drawing a "Polygon" area selection shape
+ # it is made False by first click to signify that the shape is complete
+ self.poly_drawn = False
+
self.mm = None
self.mr = None
+ self.kp = None
+
# store here solid_geometry when there are tool with isolation job
self.solid_geometry = []
@@ -666,7 +691,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.tooldia = None
self.form_fields = {
- "nccoperation":self.op_radio,
+ "nccoperation": self.op_radio,
"nccoverlap": self.ncc_overlap_entry,
"nccmargin": self.ncc_margin_entry,
"nccmethod": self.ncc_method_combo,
@@ -970,6 +995,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.ncc_offset_spinner.set_value(self.app.defaults["tools_ncc_offset_value"])
self.select_combo.set_value(self.app.defaults["tools_nccref"])
+ self.area_shape_radio.set_value(self.app.defaults["tools_ncc_area_shape"])
+
self.milling_type_radio.set_value(self.app.defaults["tools_nccmilling_type"])
self.cutz_entry.set_value(self.app.defaults["tools_ncccutz"])
self.tool_type_radio.set_value(self.app.defaults["tools_ncctool_type"])
@@ -1271,16 +1298,39 @@ class NonCopperClear(FlatCAMTool, Gerber):
}[self.reference_combo_type.get_value()]
def on_toggle_reference(self):
- if self.select_combo.get_value() == _("Itself") or self.select_combo.get_value() == _("Area Selection"):
+ sel_combo = self.select_combo.get_value()
+
+ if sel_combo == _("Itself"):
self.reference_combo.hide()
self.reference_combo_label.hide()
self.reference_combo_type.hide()
self.reference_combo_type_label.hide()
+ self.area_shape_label.hide()
+ self.area_shape_radio.hide()
+
+ # disable rest-machining for area painting
+ self.ncc_rest_cb.setDisabled(False)
+ elif sel_combo == _("Area Selection"):
+ self.reference_combo.hide()
+ self.reference_combo_label.hide()
+ self.reference_combo_type.hide()
+ self.reference_combo_type_label.hide()
+ self.area_shape_label.show()
+ self.area_shape_radio.show()
+
+ # disable rest-machining for area painting
+ self.ncc_rest_cb.set_value(False)
+ self.ncc_rest_cb.setDisabled(True)
else:
self.reference_combo.show()
self.reference_combo_label.show()
self.reference_combo_type.show()
self.reference_combo_type_label.show()
+ self.area_shape_label.hide()
+ self.area_shape_radio.hide()
+
+ # disable rest-machining for area painting
+ self.ncc_rest_cb.setDisabled(False)
def on_order_changed(self, order):
if order != 'no':
@@ -1616,6 +1666,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.mr = self.app.plotcanvas.graph_event_connect('mouse_release', self.on_mouse_release)
self.mm = self.app.plotcanvas.graph_event_connect('mouse_move', self.on_mouse_move)
+ self.kp = self.app.plotcanvas.graph_event_connect('key_press', self.on_key_press)
+
elif self.select_method == 'box':
self.bound_obj_name = self.reference_combo.currentText()
# Get source object.
@@ -1643,52 +1695,94 @@ class NonCopperClear(FlatCAMTool, Gerber):
right_button = 3
event_pos = self.app.plotcanvas.translate_coords(event_pos)
+ if self.app.grid_status():
+ curr_pos = self.app.geo_editor.snap(event_pos[0], event_pos[1])
+ else:
+ curr_pos = (event_pos[0], event_pos[1])
+
+ x1, y1 = curr_pos[0], curr_pos[1]
+
+ shape_type = self.area_shape_radio.get_value()
# do clear area only for left mouse clicks
if event.button == 1:
- if self.first_click is False:
- self.first_click = True
- self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click the end point of the paint area."))
+ if shape_type == "square":
+ if self.first_click is False:
+ self.first_click = True
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click the end point of the paint area."))
- self.cursor_pos = self.app.plotcanvas.translate_coords(event_pos)
- if self.app.grid_status():
- self.cursor_pos = self.app.geo_editor.snap(event_pos[0], event_pos[1])
- else:
- self.app.inform.emit(_("Zone added. Click to start adding next zone or right click to finish."))
- self.app.delete_selection_shape()
-
- if self.app.grid_status():
- curr_pos = self.app.geo_editor.snap(event_pos[0], event_pos[1])
+ self.cursor_pos = self.app.plotcanvas.translate_coords(event_pos)
+ if self.app.grid_status():
+ self.cursor_pos = self.app.geo_editor.snap(event_pos[0], event_pos[1])
else:
- curr_pos = (event_pos[0], event_pos[1])
+ self.app.inform.emit(_("Zone added. Click to start adding next zone or right click to finish."))
+ self.app.delete_selection_shape()
- x0, y0 = self.cursor_pos[0], self.cursor_pos[1]
- x1, y1 = curr_pos[0], curr_pos[1]
- pt1 = (x0, y0)
- pt2 = (x1, y0)
- pt3 = (x1, y1)
- pt4 = (x0, y1)
+ x0, y0 = self.cursor_pos[0], self.cursor_pos[1]
- new_rectangle = Polygon([pt1, pt2, pt3, pt4])
- self.sel_rect.append(new_rectangle)
+ pt1 = (x0, y0)
+ pt2 = (x1, y0)
+ pt3 = (x1, y1)
+ pt4 = (x0, y1)
- # add a temporary shape on canvas
- self.draw_tool_selection_shape(old_coords=(x0, y0), coords=(x1, y1))
+ new_rectangle = Polygon([pt1, pt2, pt3, pt4])
+ self.sel_rect.append(new_rectangle)
- self.first_click = False
- return
+ # add a temporary shape on canvas
+ self.draw_tool_selection_shape(old_coords=(x0, y0), coords=(x1, y1))
+ self.first_click = False
+ return
+ else:
+ self.points.append((x1, y1))
+
+ if len(self.points) > 1:
+ self.poly_drawn = True
+ self.app.inform.emit(_("Click on next Point or click right mouse button to complete ..."))
+
+ return ""
elif event.button == right_button and self.mouse_is_dragging is False:
- self.first_click = False
+
+ shape_type = self.area_shape_radio.get_value()
+
+ if shape_type == "square":
+ self.first_click = False
+ else:
+ # if we finish to add a polygon
+ if self.poly_drawn is True:
+ try:
+ # try to add the point where we last clicked if it is not already in the self.points
+ last_pt = (x1, y1)
+ if last_pt != self.points[-1]:
+ self.points.append(last_pt)
+ except IndexError:
+ pass
+
+ # we need to add a Polygon and a Polygon can be made only from at least 3 points
+ if len(self.points) > 2:
+ self.delete_moving_selection_shape()
+ pol = Polygon(self.points)
+ # do not add invalid polygons even if they are drawn by utility geometry
+ if pol.is_valid:
+ self.sel_rect.append(pol)
+ self.draw_selection_shape_polygon(points=self.points)
+ self.app.inform.emit(
+ _("Zone added. Click to start adding next zone or right click to finish."))
+
+ self.points = []
+ self.poly_drawn = False
+ return
self.delete_tool_selection_shape()
if self.app.is_legacy is False:
self.app.plotcanvas.graph_event_disconnect('mouse_release', self.on_mouse_release)
self.app.plotcanvas.graph_event_disconnect('mouse_move', self.on_mouse_move)
+ self.app.plotcanvas.graph_event_disconnect('key_press', self.on_key_press)
else:
self.app.plotcanvas.graph_event_disconnect(self.mr)
self.app.plotcanvas.graph_event_disconnect(self.mm)
+ self.app.plotcanvas.graph_event_disconnect(self.kp)
self.app.mp = self.app.plotcanvas.graph_event_connect('mouse_press',
self.app.on_mouse_click_over_plot)
@@ -1710,6 +1804,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
# called on mouse move
def on_mouse_move(self, event):
+ shape_type = self.area_shape_radio.get_value()
+
if self.app.is_legacy is False:
event_pos = event.pos
event_is_dragging = event.is_dragging
@@ -1749,10 +1845,69 @@ class NonCopperClear(FlatCAMTool, Gerber):
"%.4f " % (dx, dy))
# draw the utility geometry
- if self.first_click:
- self.app.delete_selection_shape()
- self.app.draw_moving_selection_shape(old_coords=(self.cursor_pos[0], self.cursor_pos[1]),
- coords=(curr_pos[0], curr_pos[1]))
+ if shape_type == "square":
+ if self.first_click:
+ self.app.delete_selection_shape()
+ self.app.draw_moving_selection_shape(old_coords=(self.cursor_pos[0], self.cursor_pos[1]),
+ coords=(curr_pos[0], curr_pos[1]))
+ else:
+ self.delete_moving_selection_shape()
+ self.draw_moving_selection_shape_poly(points=self.points, data=(curr_pos[0], curr_pos[1]))
+
+ def on_key_press(self, event):
+ modifiers = QtWidgets.QApplication.keyboardModifiers()
+ matplotlib_key_flag = False
+
+ # events out of the self.app.collection view (it's about Project Tab) are of type int
+ if type(event) is int:
+ key = event
+ # events from the GUI are of type QKeyEvent
+ elif type(event) == QtGui.QKeyEvent:
+ key = event.key()
+ elif isinstance(event, mpl_key_event): # MatPlotLib key events are trickier to interpret than the rest
+ matplotlib_key_flag = True
+
+ key = event.key
+ key = QtGui.QKeySequence(key)
+
+ # check for modifiers
+ key_string = key.toString().lower()
+ if '+' in key_string:
+ mod, __, key_text = key_string.rpartition('+')
+ if mod.lower() == 'ctrl':
+ modifiers = QtCore.Qt.ControlModifier
+ elif mod.lower() == 'alt':
+ modifiers = QtCore.Qt.AltModifier
+ elif mod.lower() == 'shift':
+ modifiers = QtCore.Qt.ShiftModifier
+ else:
+ modifiers = QtCore.Qt.NoModifier
+ key = QtGui.QKeySequence(key_text)
+
+ # events from Vispy are of type KeyEvent
+ else:
+ key = event.key
+
+ if key == QtCore.Qt.Key_Escape or key == 'Escape':
+ if self.app.is_legacy is False:
+ self.app.plotcanvas.graph_event_disconnect('mouse_release', self.on_mouse_release)
+ self.app.plotcanvas.graph_event_disconnect('mouse_move', self.on_mouse_move)
+ self.app.plotcanvas.graph_event_disconnect('key_press', self.on_key_press)
+ else:
+ self.app.plotcanvas.graph_event_disconnect(self.mr)
+ self.app.plotcanvas.graph_event_disconnect(self.mm)
+ self.app.plotcanvas.graph_event_disconnect(self.kp)
+
+ self.app.mp = self.app.plotcanvas.graph_event_connect('mouse_press',
+ self.app.on_mouse_click_over_plot)
+ self.app.mm = self.app.plotcanvas.graph_event_connect('mouse_move',
+ self.app.on_mouse_move_over_plot)
+ self.app.mr = self.app.plotcanvas.graph_event_connect('mouse_release',
+ self.app.on_mouse_click_release_over_plot)
+ self.points = []
+ self.poly_drawn = False
+ self.delete_moving_selection_shape()
+ self.delete_tool_selection_shape()
def envelope_object(self, ncc_obj, ncc_select, box_obj=None):
"""
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 3951a5cc..8837651e 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -20,6 +20,8 @@ import FlatCAMApp
from shapely.geometry import base, Polygon, MultiPolygon, LinearRing, Point, MultiLineString
from shapely.ops import cascaded_union, unary_union, linemerge
+from matplotlib.backend_bases import KeyEvent as mpl_key_event
+
import numpy as np
import math
from numpy import Inf
@@ -516,6 +518,21 @@ class ToolPaint(FlatCAMTool, Gerber):
self.reference_type_combo.hide()
self.reference_type_label.hide()
+ # Area Selection shape
+ self.area_shape_label = QtWidgets.QLabel('%s:' % _("Shape"))
+ self.area_shape_label.setToolTip(
+ _("The kind of selection shape used for area selection.")
+ )
+
+ self.area_shape_radio = RadioSet([{'label': _("Square"), 'value': 'square'},
+ {'label': _("Polygon"), 'value': 'polygon'}])
+
+ grid4.addWidget(self.area_shape_label, 21, 0)
+ grid4.addWidget(self.area_shape_radio, 21, 1)
+
+ self.area_shape_label.hide()
+ self.area_shape_radio.hide()
+
# GO Button
self.generate_paint_button = QtWidgets.QPushButton(_('Generate Geometry'))
self.generate_paint_button.setToolTip(
@@ -573,6 +590,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.units = ''
self.paint_tools = {}
self.tooluid = 0
+
self.first_click = False
self.cursor_pos = None
self.mouse_is_dragging = False
@@ -580,6 +598,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.mm = None
self.mp = None
self.mr = None
+ self.kp = None
self.sel_rect = []
@@ -612,6 +631,12 @@ class ToolPaint(FlatCAMTool, Gerber):
self.old_tool_dia = None
+ # store here the points for the "Polygon" area selection shape
+ self.points = []
+ # set this as True when in middle of drawing a "Polygon" area selection shape
+ # it is made False by first click to signify that the shape is complete
+ self.poly_drawn = False
+
# #############################################################################
# ################################# Signals ###################################
# #############################################################################
@@ -895,7 +920,9 @@ class ToolPaint(FlatCAMTool, Gerber):
return float(self.addtool_entry.get_value())
def on_selection(self):
- if self.selectmethod_combo.get_value() == _("Reference Object"):
+ sel_combo = self.selectmethod_combo.get_value()
+
+ if sel_combo == _("Reference Object"):
self.reference_combo.show()
self.reference_combo_label.show()
self.reference_type_combo.show()
@@ -906,14 +933,17 @@ class ToolPaint(FlatCAMTool, Gerber):
self.reference_type_combo.hide()
self.reference_type_label.hide()
- if self.selectmethod_combo.get_value() == _("Polygon Selection"):
+ if sel_combo == _("Polygon Selection"):
# disable rest-machining for single polygon painting
self.rest_cb.set_value(False)
self.rest_cb.setDisabled(True)
- if self.selectmethod_combo.get_value() == _("Area Selection"):
- # disable rest-machining for single polygon painting
+ if sel_combo == _("Area Selection"):
+ # disable rest-machining for area painting
self.rest_cb.set_value(False)
self.rest_cb.setDisabled(True)
+
+ self.area_shape_label.show()
+ self.area_shape_radio.show()
else:
self.rest_cb.setDisabled(False)
self.addtool_entry.setDisabled(False)
@@ -921,6 +951,9 @@ class ToolPaint(FlatCAMTool, Gerber):
self.deltool_btn.setDisabled(False)
self.tools_table.setContextMenuPolicy(Qt.ActionsContextMenu)
+ self.area_shape_label.hide()
+ self.area_shape_radio.hide()
+
def on_order_changed(self, order):
if order != 'no':
self.build_ui()
@@ -989,6 +1022,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.paintmargin_entry.set_value(self.app.defaults["tools_paintmargin"])
self.paintmethod_combo.set_value(self.app.defaults["tools_paintmethod"])
self.selectmethod_combo.set_value(self.app.defaults["tools_selectmethod"])
+ self.area_shape_radio.set_value(self.app.defaults["tools_paint_area_shape"])
self.pathconnect_cb.set_value(self.app.defaults["tools_pathconnect"])
self.paintcontour_cb.set_value(self.app.defaults["tools_paintcontour"])
self.paintoverlap_entry.set_value(self.app.defaults["tools_paintoverlap"])
@@ -1396,6 +1430,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.grid_status_memory = False
self.mr = self.app.plotcanvas.graph_event_connect('mouse_release', self.on_single_poly_mouse_release)
+ self.kp = self.app.plotcanvas.graph_event_connect('key_press', self.on_key_press)
if self.app.is_legacy is False:
self.app.plotcanvas.graph_event_disconnect('mouse_release', self.app.on_mouse_click_release_over_plot)
@@ -1418,6 +1453,8 @@ class ToolPaint(FlatCAMTool, Gerber):
self.mr = self.app.plotcanvas.graph_event_connect('mouse_release', self.on_mouse_release)
self.mm = self.app.plotcanvas.graph_event_connect('mouse_move', self.on_mouse_move)
+ self.kp = self.app.plotcanvas.graph_event_connect('key_press', self.on_key_press)
+
elif self.select_method == _("Reference Object"):
self.bound_obj_name = self.reference_combo.currentText()
# Get source object.
@@ -1498,8 +1535,10 @@ class ToolPaint(FlatCAMTool, Gerber):
if self.app.is_legacy is False:
self.app.plotcanvas.graph_event_disconnect('mouse_release', self.on_single_poly_mouse_release)
+ self.app.plotcanvas.graph_event_disconnect('key_press', self.on_key_press)
else:
self.app.plotcanvas.graph_event_disconnect(self.mr)
+ self.app.plotcanvas.graph_event_disconnect(self.kp)
self.app.mp = self.app.plotcanvas.graph_event_connect('mouse_press',
self.app.on_mouse_click_over_plot)
@@ -1540,51 +1579,93 @@ class ToolPaint(FlatCAMTool, Gerber):
event_pos = (x, y)
+ shape_type = self.area_shape_radio.get_value()
+
+ curr_pos = self.app.plotcanvas.translate_coords(event_pos)
+ if self.app.grid_status():
+ curr_pos = self.app.geo_editor.snap(curr_pos[0], curr_pos[1])
+
+ x1, y1 = curr_pos[0], curr_pos[1]
+
# do paint single only for left mouse clicks
if event.button == 1:
- if not self.first_click:
- self.first_click = True
- self.app.inform.emit('[WARNING_NOTCL] %s' %
- _("Click the end point of the paint area."))
+ if shape_type == "square":
+ if not self.first_click:
+ self.first_click = True
+ self.app.inform.emit('[WARNING_NOTCL] %s' %
+ _("Click the end point of the paint area."))
- self.cursor_pos = self.app.plotcanvas.translate_coords(event_pos)
- if self.app.grid_status():
- self.cursor_pos = self.app.geo_editor.snap(self.cursor_pos[0], self.cursor_pos[1])
+ self.cursor_pos = self.app.plotcanvas.translate_coords(event_pos)
+ if self.app.grid_status():
+ self.cursor_pos = self.app.geo_editor.snap(self.cursor_pos[0], self.cursor_pos[1])
+ else:
+ self.app.inform.emit(_("Zone added. Click to start adding next zone or right click to finish."))
+ self.app.delete_selection_shape()
+
+ x0, y0 = self.cursor_pos[0], self.cursor_pos[1]
+ pt1 = (x0, y0)
+ pt2 = (x1, y0)
+ pt3 = (x1, y1)
+ pt4 = (x0, y1)
+
+ new_rectangle = Polygon([pt1, pt2, pt3, pt4])
+ self.sel_rect.append(new_rectangle)
+
+ # add a temporary shape on canvas
+ self.draw_tool_selection_shape(old_coords=(x0, y0), coords=(x1, y1))
+
+ self.first_click = False
+ return
else:
- self.app.inform.emit(_("Zone added. Click to start adding next zone or right click to finish."))
- self.app.delete_selection_shape()
+ self.points.append((x1, y1))
- curr_pos = self.app.plotcanvas.translate_coords(event_pos)
- if self.app.grid_status():
- curr_pos = self.app.geo_editor.snap(curr_pos[0], curr_pos[1])
-
- x0, y0 = self.cursor_pos[0], self.cursor_pos[1]
- x1, y1 = curr_pos[0], curr_pos[1]
- pt1 = (x0, y0)
- pt2 = (x1, y0)
- pt3 = (x1, y1)
- pt4 = (x0, y1)
-
- new_rectangle = Polygon([pt1, pt2, pt3, pt4])
- self.sel_rect.append(new_rectangle)
-
- # add a temporary shape on canvas
- self.draw_tool_selection_shape(old_coords=(x0, y0), coords=(x1, y1))
-
- self.first_click = False
- return
+ if len(self.points) > 1:
+ self.poly_drawn = True
+ self.app.inform.emit(_("Click on next Point or click right mouse button to complete ..."))
+ return ""
elif event.button == right_button and self.mouse_is_dragging is False:
- self.first_click = False
+
+ shape_type = self.area_shape_radio.get_value()
+
+ if shape_type == "square":
+ self.first_click = False
+ else:
+ # if we finish to add a polygon
+ if self.poly_drawn is True:
+ try:
+ # try to add the point where we last clicked if it is not already in the self.points
+ last_pt = (x1, y1)
+ if last_pt != self.points[-1]:
+ self.points.append(last_pt)
+ except IndexError:
+ pass
+
+ # we need to add a Polygon and a Polygon can be made only from at least 3 points
+ if len(self.points) > 2:
+ self.delete_moving_selection_shape()
+ pol = Polygon(self.points)
+ # do not add invalid polygons even if they are drawn by utility geometry
+ if pol.is_valid:
+ self.sel_rect.append(pol)
+ self.draw_selection_shape_polygon(points=self.points)
+ self.app.inform.emit(
+ _("Zone added. Click to start adding next zone or right click to finish."))
+
+ self.points = []
+ self.poly_drawn = False
+ return
self.delete_tool_selection_shape()
if self.app.is_legacy is False:
self.app.plotcanvas.graph_event_disconnect('mouse_release', self.on_mouse_release)
self.app.plotcanvas.graph_event_disconnect('mouse_move', self.on_mouse_move)
+ self.app.plotcanvas.graph_event_disconnect('key_press', self.on_key_press)
else:
self.app.plotcanvas.graph_event_disconnect(self.mr)
self.app.plotcanvas.graph_event_disconnect(self.mm)
+ self.app.plotcanvas.graph_event_disconnect(self.kp)
self.app.mp = self.app.plotcanvas.graph_event_connect('mouse_press',
self.app.on_mouse_click_over_plot)
@@ -1607,6 +1688,8 @@ class ToolPaint(FlatCAMTool, Gerber):
# called on mouse move
def on_mouse_move(self, event):
+ shape_type = self.area_shape_radio.get_value()
+
if self.app.is_legacy is False:
event_pos = event.pos
event_is_dragging = event.is_dragging
@@ -1652,10 +1735,93 @@ class ToolPaint(FlatCAMTool, Gerber):
"%.4f " % (dx, dy))
# draw the utility geometry
- if self.first_click:
- self.app.delete_selection_shape()
- self.app.draw_moving_selection_shape(old_coords=(self.cursor_pos[0], self.cursor_pos[1]),
- coords=(curr_pos[0], curr_pos[1]))
+ if shape_type == "square":
+ if self.first_click:
+ self.app.delete_selection_shape()
+ self.app.draw_moving_selection_shape(old_coords=(self.cursor_pos[0], self.cursor_pos[1]),
+ coords=(curr_pos[0], curr_pos[1]))
+ else:
+ self.delete_moving_selection_shape()
+ self.draw_moving_selection_shape_poly(points=self.points, data=(curr_pos[0], curr_pos[1]))
+
+ def on_key_press(self, event):
+ modifiers = QtWidgets.QApplication.keyboardModifiers()
+ matplotlib_key_flag = False
+
+ # events out of the self.app.collection view (it's about Project Tab) are of type int
+ if type(event) is int:
+ key = event
+ # events from the GUI are of type QKeyEvent
+ elif type(event) == QtGui.QKeyEvent:
+ key = event.key()
+ elif isinstance(event, mpl_key_event): # MatPlotLib key events are trickier to interpret than the rest
+ matplotlib_key_flag = True
+
+ key = event.key
+ key = QtGui.QKeySequence(key)
+
+ # check for modifiers
+ key_string = key.toString().lower()
+ if '+' in key_string:
+ mod, __, key_text = key_string.rpartition('+')
+ if mod.lower() == 'ctrl':
+ modifiers = QtCore.Qt.ControlModifier
+ elif mod.lower() == 'alt':
+ modifiers = QtCore.Qt.AltModifier
+ elif mod.lower() == 'shift':
+ modifiers = QtCore.Qt.ShiftModifier
+ else:
+ modifiers = QtCore.Qt.NoModifier
+ key = QtGui.QKeySequence(key_text)
+
+ # events from Vispy are of type KeyEvent
+ else:
+ key = event.key
+
+ print(key)
+ if key == QtCore.Qt.Key_Escape or key == 'Escape':
+ try:
+ if self.app.is_legacy is False:
+ self.app.plotcanvas.graph_event_disconnect('mouse_release', self.on_mouse_release)
+ self.app.plotcanvas.graph_event_disconnect('mouse_move', self.on_mouse_move)
+ self.app.plotcanvas.graph_event_disconnect('key_press', self.on_key_press)
+ else:
+ self.app.plotcanvas.graph_event_disconnect(self.mr)
+ self.app.plotcanvas.graph_event_disconnect(self.mm)
+ self.app.plotcanvas.graph_event_disconnect(self.kp)
+ except Exception as e:
+ log.debug("ToolPaint.on_key_press() _1 --> %s" % str(e))
+
+ try:
+ # restore the Grid snapping if it was active before
+ if self.grid_status_memory is True:
+ self.app.ui.grid_snap_btn.trigger()
+
+ if self.app.is_legacy is False:
+ self.app.plotcanvas.graph_event_disconnect('mouse_release', self.on_single_poly_mouse_release)
+ self.app.plotcanvas.graph_event_disconnect('key_press', self.on_key_press)
+ else:
+ self.app.plotcanvas.graph_event_disconnect(self.mr)
+ self.app.plotcanvas.graph_event_disconnect(self.kp)
+
+ self.app.tool_shapes.clear(update=True)
+ except Exception as e:
+ log.debug("ToolPaint.on_key_press() _2 --> %s" % str(e))
+
+ self.app.mp = self.app.plotcanvas.graph_event_connect('mouse_press',
+ self.app.on_mouse_click_over_plot)
+ self.app.mm = self.app.plotcanvas.graph_event_connect('mouse_move',
+ self.app.on_mouse_move_over_plot)
+ self.app.mr = self.app.plotcanvas.graph_event_connect('mouse_release',
+ self.app.on_mouse_click_release_over_plot)
+
+ self.points = []
+ self.poly_drawn = False
+
+ self.poly_dict.clear()
+
+ self.delete_moving_selection_shape()
+ self.delete_tool_selection_shape()
def paint_poly(self, obj, inside_pt=None, poly_list=None, tooldia=None, overlap=None, order=None,
margin=None, method=None, outname=None, connect=None, contour=None, tools_storage=None,
From ffaea546db3251486995b8ad2e55441d402b3132 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 20 Mar 2020 16:28:59 +0200
Subject: [PATCH 131/209] - fixed issue in "re-cut" feature when combined with
multi-depth feature
---
README.md | 1 +
camlib.py | 48 ++++++++++++++++++++++++++++++++++-----
flatcamTools/ToolPaint.py | 1 -
3 files changed, 43 insertions(+), 7 deletions(-)
diff --git a/README.md b/README.md
index 012292c8..6a72b728 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ CAD program, and create G-Code for Isolation routing.
- updated the "re-cut" feature in Geometry object; now if the re-cut parameter is non zero it will cut half of the entered distance before the isolation end and half of it after the isolation end
- added to Paint and NCC Tool a feature that allow polygon area selection when the reference is selected as Area Selection
- in Paint Tool and NCC Tool added ability to use Escape Tool to cancel Area Selection and for Paint Tool to cancel Polygon Selection
+- fixed issue in "re-cut" feature when combined with multi-depth feature
13.03.2020
diff --git a/camlib.py b/camlib.py
index c2e04a22..bcf3c68e 100644
--- a/camlib.py
+++ b/camlib.py
@@ -5186,13 +5186,13 @@ class CNCjob(Geometry):
# between point 0 and point 1 is more than the distance we set for the extra cut then make an interpolation
# along the path and find the point at the distance extracut_length
- # this is an extra line therefore lift the milling bit
- gcode += self.doformat(p.lift_code, x=prev_x, y=prev_y, z_move=z_move) # lift
-
if extracut_length == 0.0:
extra_path = [path[-1], path[0], path[1]]
- new_x = path[-1][0]
- new_y = path[-1][1]
+ new_x = extra_path[0][0]
+ new_y = extra_path[0][1]
+
+ # this is an extra line therefore lift the milling bit
+ gcode += self.doformat(p.lift_code, x=prev_x, y=prev_y, z_move=z_move) # lift
# move fast to the new first point
gcode += self.doformat(p.rapid_code, x=new_x, y=new_y)
@@ -5211,14 +5211,28 @@ class CNCjob(Geometry):
for pt in extra_path[1:]:
gcode += self.doformat(p.linear_code, x=pt[0], y=pt[1])
last_pt = pt
+
+ # go back to the original point
+ gcode += self.doformat(p.linear_code, x=path[0][0], y=path[0][1])
+ last_pt = path[0]
else:
# go to the point that is 5% in length before the end (therefore 95% length from start of the line),
# along the line to be cut
- extra_line = substring(target_linear, (-extracut_length * 0.5), (extracut_length * 0.5))
+ if extracut_length >= target_linear.length:
+ extracut_length = target_linear.length
+
+ # ---------------------------------------------
+ # first half
+ # ---------------------------------------------
+ start_length = target_linear.length - (extracut_length * 0.5)
+ extra_line = substring(target_linear, start_length, target_linear.length)
extra_path = list(extra_line.coords)
new_x = extra_path[0][0]
new_y = extra_path[0][1]
+ # this is an extra line therefore lift the milling bit
+ gcode += self.doformat(p.lift_code, x=prev_x, y=prev_y, z_move=z_move) # lift
+
# move fast to the new first point
gcode += self.doformat(p.rapid_code, x=new_x, y=new_y)
@@ -5231,6 +5245,28 @@ class CNCjob(Geometry):
else:
gcode += self.doformat(p.down_code, x=new_x, y=new_y, z_cut=z_cut) # Start cutting
+ # start cutting the extra line
+ for pt in extra_path[1:]:
+ gcode += self.doformat(p.linear_code, x=pt[0], y=pt[1])
+
+ # ---------------------------------------------
+ # second half
+ # ---------------------------------------------
+ extra_line = substring(target_linear, 0, (extracut_length * 0.5))
+ extra_path = list(extra_line.coords)
+
+ # start cutting the extra line
+ last_pt = extra_path[0]
+ for pt in extra_path[1:]:
+ gcode += self.doformat(p.linear_code, x=pt[0], y=pt[1])
+ last_pt = pt
+
+ # ---------------------------------------------
+ # back to original start point, cutting
+ # ---------------------------------------------
+ extra_line = substring(target_linear, 0, (extracut_length * 0.5))
+ extra_path = list(extra_line.coords)[::-1]
+
# start cutting the extra line
last_pt = extra_path[0]
for pt in extra_path[1:]:
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 8837651e..0881cbe2 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -1778,7 +1778,6 @@ class ToolPaint(FlatCAMTool, Gerber):
else:
key = event.key
- print(key)
if key == QtCore.Qt.Key_Escape or key == 'Escape':
try:
if self.app.is_legacy is False:
From 7415ebc8af5e73e0b658cf99c0174d37be115d69 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 20 Mar 2020 17:12:20 +0200
Subject: [PATCH 132/209] - fixed bugs in cncjob TclCommand
---
README.md | 1 +
camlib.py | 4 ++--
tclCommands/TclCommandCncjob.py | 7 ++++++-
3 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 6a72b728..75711dbf 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ CAD program, and create G-Code for Isolation routing.
- added to Paint and NCC Tool a feature that allow polygon area selection when the reference is selected as Area Selection
- in Paint Tool and NCC Tool added ability to use Escape Tool to cancel Area Selection and for Paint Tool to cancel Polygon Selection
- fixed issue in "re-cut" feature when combined with multi-depth feature
+- fixed bugs in cncjob TclCommand
13.03.2020
diff --git a/camlib.py b/camlib.py
index bcf3c68e..96587a0e 100644
--- a/camlib.py
+++ b/camlib.py
@@ -3905,7 +3905,7 @@ class CNCjob(Geometry):
self.feedrate_rapid = float(feedrate_rapid) if feedrate_rapid is not None else \
self.app.defaults["geometry_feedrate_rapid"]
- self.spindlespeed = int(spindlespeed) if spindlespeed != 0 else None
+ self.spindlespeed = int(spindlespeed) if spindlespeed != 0 and spindlespeed is not None else None
self.spindledir = spindledir
self.dwell = dwell
self.dwelltime = float(dwelltime) if dwelltime is not None else self.app.defaults["geometry_dwelltime"]
@@ -3919,7 +3919,7 @@ class CNCjob(Geometry):
"in the format (x, y) but now there is only one value, not two."))
return 'fail'
- self.z_depthpercut = float(depthpercut) if depthpercut is not None else 0.0
+ self.z_depthpercut = float(depthpercut) if depthpercut is not None and depthpercut != 0 else abs(self.z_cut)
self.multidepth = multidepth
self.z_toolchange = float(toolchangez) if toolchangez is not None else self.app.defaults["geometry_toolchangez"]
self.extracut_length = float(extracut_length) if extracut_length is not None else \
diff --git a/tclCommands/TclCommandCncjob.py b/tclCommands/TclCommandCncjob.py
index eeaa4321..ffb91ba7 100644
--- a/tclCommands/TclCommandCncjob.py
+++ b/tclCommands/TclCommandCncjob.py
@@ -213,7 +213,12 @@ class TclCommandCncjob(TclCommandSignaled):
local_tools_dict[tool_uid]['data']['feedrate_rapid'] = args["feedrate_rapid"]
local_tools_dict[tool_uid]['data']['multidepth'] = args["multidepth"]
local_tools_dict[tool_uid]['data']['extracut'] = args["extracut"]
- local_tools_dict[tool_uid]['data']['extracut_length'] = args["extracut_length"]
+
+ if args["extracut"] is True:
+ local_tools_dict[tool_uid]['data']['extracut_length'] = args["extracut_length"]
+ else:
+ local_tools_dict[tool_uid]['data']['extracut_length'] = None
+
local_tools_dict[tool_uid]['data']['depthperpass'] = args["depthperpass"]
local_tools_dict[tool_uid]['data']['toolchange'] = args["toolchange"]
local_tools_dict[tool_uid]['data']['toolchangez'] = args["toolchangez"]
From 91884a57e068755b9425021a045ae3651defdfae Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 21 Mar 2020 09:12:15 +0200
Subject: [PATCH 133/209] - fixed Cutout Tool to work with negative values for
Margin parameter
---
README.md | 4 +++
flatcamTools/ToolCutOut.py | 62 +++++++++++++++++++++++++++-----------
2 files changed, 48 insertions(+), 18 deletions(-)
diff --git a/README.md b/README.md
index 75711dbf..7ace08cb 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+21.03.2020
+
+- fixed Cutout Tool to work with negative values for Margin parameter
+
20.03.2020
- updated the "re-cut" feature in Geometry object; now if the re-cut parameter is non zero it will cut half of the entered distance before the isolation end and half of it after the isolation end
diff --git a/flatcamTools/ToolCutOut.py b/flatcamTools/ToolCutOut.py
index 9b0ecb3d..17663890 100644
--- a/flatcamTools/ToolCutOut.py
+++ b/flatcamTools/ToolCutOut.py
@@ -536,6 +536,7 @@ class CutOut(FlatCAMTool):
object_geo = cutout_obj.solid_geometry
except Exception as err:
log.debug("CutOut.on_freeform_cutout().geo_init() --> %s" % str(err))
+ object_geo = cutout_obj.solid_geometry
else:
object_geo = cutout_obj.solid_geometry
@@ -606,12 +607,14 @@ class CutOut(FlatCAMTool):
if isinstance(object_geo, MultiPolygon):
x0, y0, x1, y1 = object_geo.bounds
object_geo = box(x0, y0, x1, y1)
+ if margin >= 0:
+ geo_buf = object_geo.buffer(margin + abs(dia / 2))
+ else:
+ geo_buf = object_geo.buffer(margin - abs(dia / 2))
- geo_buf = object_geo.buffer(margin + abs(dia / 2))
geo = geo_buf.exterior
else:
geo = object_geo
-
solid_geo = cutout_handler(geom=geo)
else:
try:
@@ -621,7 +624,11 @@ class CutOut(FlatCAMTool):
for geom_struct in object_geo:
if isinstance(cutout_obj, FlatCAMGerber):
- geom_struct = (geom_struct.buffer(margin + abs(dia / 2))).exterior
+ if margin >= 0:
+ geom_struct = (geom_struct.buffer(margin + abs(dia / 2))).exterior
+ else:
+ geom_struct_buff = geom_struct.buffer(-margin + abs(dia / 2))
+ geom_struct = geom_struct_buff.interiors
solid_geo += cutout_handler(geom=geom_struct)
@@ -769,24 +776,43 @@ class CutOut(FlatCAMTool):
# if Gerber create a buffer at a distance
# if Geometry then cut through the geometry
if isinstance(cutout_obj, FlatCAMGerber):
- geo = geo.buffer(margin + abs(dia / 2))
+ if margin >= 0:
+ geo = geo.buffer(margin + abs(dia / 2))
+ else:
+ geo = geo.buffer(margin - abs(dia / 2))
solid_geo = cutout_rect_handler(geom=geo)
else:
- try:
- __ = iter(object_geo)
- except TypeError:
- object_geo = [object_geo]
+ if cutout_obj.kind == 'geometry':
+ try:
+ __ = iter(object_geo)
+ except TypeError:
+ object_geo = [object_geo]
- for geom_struct in object_geo:
- geom_struct = unary_union(geom_struct)
- xmin, ymin, xmax, ymax = geom_struct.bounds
- geom_struct = box(xmin, ymin, xmax, ymax)
+ for geom_struct in object_geo:
+ geom_struct = unary_union(geom_struct)
+ xmin, ymin, xmax, ymax = geom_struct.bounds
+ geom_struct = box(xmin, ymin, xmax, ymax)
+
+ solid_geo += cutout_rect_handler(geom=geom_struct)
+ elif cutout_obj.kind == 'gerber' and margin >= 0:
+ try:
+ __ = iter(object_geo)
+ except TypeError:
+ object_geo = [object_geo]
+
+ for geom_struct in object_geo:
+ geom_struct = unary_union(geom_struct)
+ xmin, ymin, xmax, ymax = geom_struct.bounds
+ geom_struct = box(xmin, ymin, xmax, ymax)
- if isinstance(cutout_obj, FlatCAMGerber):
geom_struct = geom_struct.buffer(margin + abs(dia / 2))
- solid_geo += cutout_rect_handler(geom=geom_struct)
+ solid_geo += cutout_rect_handler(geom=geom_struct)
+ elif cutout_obj.kind == 'gerber' and margin < 0:
+ self.app.inform.emit('[WARNING_NOTCL] %s' %
+ _("Rectangular cutout with negative margin is not possible."))
+ return "fail"
geo_obj.solid_geometry = deepcopy(solid_geo)
geo_obj.options['cnctooldia'] = str(dia)
@@ -795,11 +821,11 @@ class CutOut(FlatCAMTool):
geo_obj.options['depthperpass'] = self.maxdepth_entry.get_value()
outname = cutout_obj.options["name"] + "_cutout"
- self.app.new_object('geometry', outname, geo_init)
+ ret = self.app.new_object('geometry', outname, geo_init)
- # cutout_obj.plot()
- self.app.inform.emit('[success] %s' %
- _("Any form CutOut operation finished."))
+ if ret != 'fail':
+ # cutout_obj.plot()
+ self.app.inform.emit('[success] %s' % _("Any form CutOut operation finished."))
# self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
self.app.should_we_save = True
From 5554cf0afac606d57f3524f43f2f13b4eae47a40 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 28 Mar 2020 22:22:53 +0200
Subject: [PATCH 134/209] - finished the new database based on a QTreeWidget
---
FlatCAMCommon.py | 624 +++++++++++++++++------------------------------
README.md | 4 +
requirements.txt | 2 +-
3 files changed, 229 insertions(+), 401 deletions(-)
diff --git a/FlatCAMCommon.py b/FlatCAMCommon.py
index c8a3860b..644f7ca4 100644
--- a/FlatCAMCommon.py
+++ b/FlatCAMCommon.py
@@ -1425,6 +1425,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.tree_widget = FCTree(columns=2, header_hidden=False, protected_column=[0])
self.tree_widget.setHeaderLabels(["ID", "Tool Name"])
self.tree_widget.setIndentation(0)
+ self.tree_widget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
+ self.tree_widget.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
# set alternating colors
# self.tree_widget.setAlternatingRowColors(True)
@@ -1436,7 +1438,14 @@ class ToolsDB2(QtWidgets.QWidget):
tree_layout.addWidget(self.tree_widget)
param_hlay = QtWidgets.QHBoxLayout()
- grid_layout.addLayout(param_hlay, 0, 1)
+ param_area = QtWidgets.QScrollArea()
+ param_widget = QtWidgets.QWidget()
+ param_widget.setLayout(param_hlay)
+
+ param_area.setWidget(param_widget)
+ param_area.setWidgetResizable(True)
+
+ grid_layout.addWidget(param_area, 0, 1)
# ###########################################################################
# ############## The UI form ################################################
@@ -1450,7 +1459,6 @@ class ToolsDB2(QtWidgets.QWidget):
}
""")
self.basic_vlay = QtWidgets.QVBoxLayout()
- self.basic_box.setLayout(self.basic_vlay)
self.basic_box.setTitle(_("Basic Parameters"))
self.basic_box.setMinimumWidth(250)
@@ -1463,21 +1471,25 @@ class ToolsDB2(QtWidgets.QWidget):
}
""")
self.advanced_vlay = QtWidgets.QVBoxLayout()
- self.advanced_box.setLayout(self.advanced_vlay)
self.advanced_box.setTitle(_("Advanced Parameters"))
self.advanced_box.setMinimumWidth(250)
- param_hlay.addLayout(self.basic_vlay)
- param_hlay.addLayout(self.advanced_vlay)
+ self.basic_box.setLayout(self.basic_vlay)
+ self.advanced_box.setLayout(self.advanced_vlay)
+
+ param_hlay.addWidget(self.basic_box)
+ param_hlay.addWidget(self.advanced_box)
+ param_hlay.addStretch()
# ###########################################################################
# ############### BASIC UI form #############################################
# ###########################################################################
- grid0 = QtWidgets.QGridLayout()
- self.advanced_vlay.addLayout(grid0)
- grid0.setColumnStretch(0, 0)
- grid0.setColumnStretch(1, 1)
+ self.grid0 = QtWidgets.QGridLayout()
+ self.basic_vlay.addLayout(self.grid0)
+ self.grid0.setColumnStretch(0, 0)
+ self.grid0.setColumnStretch(1, 1)
+ self.basic_vlay.addStretch()
# Tool Name
self.name_label = QtWidgets.QLabel('%s:' % _('Tool Name'))
@@ -1489,8 +1501,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.name_entry = FCEntry()
self.name_entry.setObjectName('gdb_name')
- grid0.addWidget(self.name_label, 0, 0)
- grid0.addWidget(self.name_entry, 0, 1)
+ self.grid0.addWidget(self.name_label, 0, 0)
+ self.grid0.addWidget(self.name_entry, 0, 1)
# Tool Dia
self.dia_label = QtWidgets.QLabel('%s:' % _('Tool Dia'))
@@ -1502,8 +1514,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.dia_entry.set_precision(self.decimals)
self.dia_entry.setObjectName('gdb_dia')
- grid0.addWidget(self.dia_label, 1, 0)
- grid0.addWidget(self.dia_entry, 1, 1)
+ self.grid0.addWidget(self.dia_label, 1, 0)
+ self.grid0.addWidget(self.dia_entry, 1, 1)
# Tool Shape
self.shape_label = QtWidgets.QLabel('%s:' % _('Tool Shape'))
@@ -1518,8 +1530,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.shape_combo.addItems(["C1", "C2", "C3", "C4", "B", "V"])
self.shape_combo.setObjectName('gdb_shape')
- grid0.addWidget(self.shape_label, 2, 0)
- grid0.addWidget(self.shape_combo, 2, 1)
+ self.grid0.addWidget(self.shape_label, 2, 0)
+ self.grid0.addWidget(self.shape_combo, 2, 1)
# Cut Z
self.cutz_label = QtWidgets.QLabel('%s:' % _("Cut Z"))
@@ -1532,8 +1544,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.cutz_entry.set_precision(self.decimals)
self.cutz_entry.setObjectName('gdb_cutz')
- grid0.addWidget(self.cutz_label, 4, 0)
- grid0.addWidget(self.cutz_entry, 4, 1)
+ self.grid0.addWidget(self.cutz_label, 4, 0)
+ self.grid0.addWidget(self.cutz_entry, 4, 1)
# Multi Depth
self.multidepth_label = QtWidgets.QLabel('%s:' % _("MultiDepth"))
@@ -1545,8 +1557,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.multidepth_cb = FCCheckBox()
self.multidepth_cb.setObjectName('gdb_multidepth')
- grid0.addWidget(self.multidepth_label, 5, 0)
- grid0.addWidget(self.multidepth_cb, 5, 1)
+ self.grid0.addWidget(self.multidepth_label, 5, 0)
+ self.grid0.addWidget(self.multidepth_cb, 5, 1)
# Depth Per Pass
self.dpp_label = QtWidgets.QLabel('%s:' % _("DPP"))
@@ -1559,8 +1571,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.multidepth_entry.set_precision(self.decimals)
self.multidepth_entry.setObjectName('gdb_multidepth_entry')
- grid0.addWidget(self.dpp_label, 7, 0)
- grid0.addWidget(self.multidepth_entry, 7, 1)
+ self.grid0.addWidget(self.dpp_label, 7, 0)
+ self.grid0.addWidget(self.multidepth_entry, 7, 1)
# Travel Z
self.travelz_label = QtWidgets.QLabel('%s:' % _("Travel Z"))
@@ -1574,8 +1586,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.travelz_entry.set_precision(self.decimals)
self.travelz_entry.setObjectName('gdb_travel')
- grid0.addWidget(self.travelz_label, 9, 0)
- grid0.addWidget(self.travelz_entry, 9, 1)
+ self.grid0.addWidget(self.travelz_label, 9, 0)
+ self.grid0.addWidget(self.travelz_entry, 9, 1)
# Feedrate X-Y
self.frxy_label = QtWidgets.QLabel('%s:' % _("Feedrate X-Y"))
@@ -1583,11 +1595,13 @@ class ToolsDB2(QtWidgets.QWidget):
_("Feedrate X-Y. Feedrate\n"
"The speed on XY plane used while cutting into material."))
- self.frxy_entry = FCEntry()
+ self.frxy_entry = FCDoubleSpinner()
+ self.frxy_entry.set_range(-9999.9999, 9999.9999)
+ self.frxy_entry.set_precision(self.decimals)
self.frxy_entry.setObjectName('gdb_frxy')
- grid0.addWidget(self.frxy_label, 12, 0)
- grid0.addWidget(self.frxy_entry, 12, 1)
+ self.grid0.addWidget(self.frxy_label, 12, 0)
+ self.grid0.addWidget(self.frxy_entry, 12, 1)
# Feedrate Z
self.frz_label = QtWidgets.QLabel('%s:' % _("Feedrate Z"))
@@ -1600,8 +1614,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.frz_entry.set_precision(self.decimals)
self.frz_entry.setObjectName('gdb_frz')
- grid0.addWidget(self.frz_label, 14, 0)
- grid0.addWidget(self.frz_entry, 14, 1)
+ self.grid0.addWidget(self.frz_label, 14, 0)
+ self.grid0.addWidget(self.frz_entry, 14, 1)
# Spindle Spped
self.spindle_label = QtWidgets.QLabel('%s:' % _("Spindle Speed"))
@@ -1615,8 +1629,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.spindle_entry.set_precision(self.decimals)
self.frz_entry.setObjectName('gdb_spindle')
- grid0.addWidget(self.spindle_label, 15, 0)
- grid0.addWidget(self.spindle_entry, 15, 1)
+ self.grid0.addWidget(self.spindle_label, 15, 0)
+ self.grid0.addWidget(self.spindle_entry, 15, 1)
# Dwell
self.dwell_label = QtWidgets.QLabel('%s:' % _("Dwell"))
@@ -1628,8 +1642,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.dwell_cb = FCCheckBox()
self.dwell_cb.setObjectName('gdb_dwell')
- grid0.addWidget(self.dwell_label, 16, 0)
- grid0.addWidget(self.dwell_cb, 16, 1)
+ self.grid0.addWidget(self.dwell_label, 16, 0)
+ self.grid0.addWidget(self.dwell_cb, 16, 1)
# Dwell Time
self.dwelltime_label = QtWidgets.QLabel('%s:' % _("Dwelltime"))
@@ -1642,17 +1656,18 @@ class ToolsDB2(QtWidgets.QWidget):
self.dwelltime_entry.set_precision(self.decimals)
self.dwelltime_entry.setObjectName('gdb_dwelltime')
- grid0.addWidget(self.dwelltime_label, 17, 0)
- grid0.addWidget(self.dwelltime_entry, 17, 1)
+ self.grid0.addWidget(self.dwelltime_label, 17, 0)
+ self.grid0.addWidget(self.dwelltime_entry, 17, 1)
# ###########################################################################
# ############### ADVANCED UI form ##########################################
# ###########################################################################
- grid1 = QtWidgets.QGridLayout()
- self.advanced_vlay.addLayout(grid1)
- grid1.setColumnStretch(0, 0)
- grid1.setColumnStretch(1, 1)
+ self.grid1 = QtWidgets.QGridLayout()
+ self.advanced_vlay.addLayout(self.grid1)
+ self.grid1.setColumnStretch(0, 0)
+ self.grid1.setColumnStretch(1, 1)
+ self.advanced_vlay.addStretch()
# Tool Type
self.type_label = QtWidgets.QLabel('%s:' % _("Tool Type"))
@@ -1667,8 +1682,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.type_combo.addItems(["Iso", "Rough", "Finish"])
self.type_combo.setObjectName('gdb_type')
- grid1.addWidget(self.type_label, 0, 0)
- grid1.addWidget(self.type_combo, 0, 1)
+ self.grid1.addWidget(self.type_label, 0, 0)
+ self.grid1.addWidget(self.type_combo, 0, 1)
# Tool Offset
self.tooloffset_label = QtWidgets.QLabel('%s:' % _('Tool Offset'))
@@ -1684,8 +1699,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.tooloffset_combo.addItems(["Path", "In", "Out", "Custom"])
self.tooloffset_combo.setObjectName('gdb_tool_offset')
- grid1.addWidget(self.tooloffset_label, 2, 0)
- grid1.addWidget(self.tooloffset_combo, 2, 1)
+ self.grid1.addWidget(self.tooloffset_label, 2, 0)
+ self.grid1.addWidget(self.tooloffset_combo, 2, 1)
# Custom Offset
self.custom_offset_label = QtWidgets.QLabel('%s:' % _("Custom Offset"))
@@ -1698,8 +1713,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.custom_offset_entry.set_precision(self.decimals)
self.custom_offset_entry.setObjectName('gdb_custom_offset')
- grid1.addWidget(self.custom_offset_label, 5, 0)
- grid1.addWidget(self.custom_offset_entry, 5, 1)
+ self.grid1.addWidget(self.custom_offset_label, 5, 0)
+ self.grid1.addWidget(self.custom_offset_entry, 5, 1)
# V-Dia
self.vdia_label = QtWidgets.QLabel('%s:' % _("V-Dia"))
@@ -1712,8 +1727,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.vdia_entry.set_precision(self.decimals)
self.vdia_entry.setObjectName('gdb_vdia')
- grid1.addWidget(self.vdia_label, 7, 0)
- grid1.addWidget(self.vdia_entry, 7, 1)
+ self.grid1.addWidget(self.vdia_label, 7, 0)
+ self.grid1.addWidget(self.vdia_entry, 7, 1)
# V-Angle
self.vangle_label = QtWidgets.QLabel('%s:' % _("V-Angle"))
@@ -1726,8 +1741,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.vangle_entry.set_precision(self.decimals)
self.vangle_entry.setObjectName('gdb_vangle')
- grid1.addWidget(self.vangle_label, 8, 0)
- grid1.addWidget(self.vangle_entry, 8, 1)
+ self.grid1.addWidget(self.vangle_label, 8, 0)
+ self.grid1.addWidget(self.vangle_entry, 8, 1)
# Feedrate Rapids
self.frapids_label = QtWidgets.QLabel('%s:' % _("FR Rapids"))
@@ -1742,8 +1757,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.frapids_entry.set_precision(self.decimals)
self.frapids_entry.setObjectName('gdb_frapids')
- grid1.addWidget(self.frapids_label, 10, 0)
- grid1.addWidget(self.frapids_entry, 10, 1)
+ self.grid1.addWidget(self.frapids_label, 10, 0)
+ self.grid1.addWidget(self.frapids_entry, 10, 1)
# Extra Cut
self.ecut_label = QtWidgets.QLabel('%s:' % _("ExtraCut"))
@@ -1757,8 +1772,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.ecut_cb = FCCheckBox()
self.ecut_cb.setObjectName('gdb_ecut')
- grid1.addWidget(self.ecut_label, 12, 0)
- grid1.addWidget(self.ecut_cb, 12, 1)
+ self.grid1.addWidget(self.ecut_label, 12, 0)
+ self.grid1.addWidget(self.ecut_cb, 12, 1)
# Extra Cut Length
self.ecut_length_label = QtWidgets.QLabel('%s:' % _("E-Cut Length"))
@@ -1775,8 +1790,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.ecut_length_entry.set_precision(self.decimals)
self.ecut_length_entry.setObjectName('gdb_ecut_length')
- grid1.addWidget(self.ecut_length_label, 13, 0)
- grid1.addWidget(self.ecut_length_entry, 13, 1)
+ self.grid1.addWidget(self.ecut_length_label, 13, 0)
+ self.grid1.addWidget(self.ecut_length_entry, 13, 1)
# ####################################################################
# ####################################################################
@@ -1862,7 +1877,7 @@ class ToolsDB2(QtWidgets.QWidget):
"depthperpass": self.multidepth_entry,
"travelz": self.travelz_entry,
"feedrate": self.frxy_entry,
- "feedrate_z": self.frxy_entry,
+ "feedrate_z": self.frz_entry,
"spindlespeed": self.spindle_entry,
"dwell": self.dwell_cb,
"dwelltime": self.dwelltime_entry,
@@ -1904,6 +1919,8 @@ class ToolsDB2(QtWidgets.QWidget):
"gdb_ecut_length": "extracut_length"
}
+ self.current_toolid = None
+
# ##############################################################################
# ######################## SIGNALS #############################################
# ##############################################################################
@@ -1920,20 +1937,38 @@ class ToolsDB2(QtWidgets.QWidget):
# self.tree_widget.selectionModel().selectionChanged.connect(self.on_list_selection_change)
self.tree_widget.currentItemChanged.connect(self.on_list_selection_change)
self.tree_widget.itemChanged.connect(self.on_list_item_edited)
+ self.tree_widget.customContextMenuRequested.connect(self.on_menu_request)
self.setup_db_ui()
+ def on_menu_request(self, pos):
+
+ menu = QtWidgets.QMenu()
+ add_tool = menu.addAction(QtGui.QIcon(self.app.resource_location + '/plus16.png'), _("Add to DB"))
+ add_tool.triggered.connect(self.on_tool_add)
+
+ copy_tool = menu.addAction(QtGui.QIcon(self.app.resource_location + '/copy16.png'), _("Copy from DB"))
+ copy_tool.triggered.connect(self.on_tool_copy)
+
+ delete_tool = menu.addAction(QtGui.QIcon(self.app.resource_location + '/delete32.png'), _("Delete from DB"))
+ delete_tool.triggered.connect(self.on_tool_delete)
+
+ # tree_item = self.tree_widget.itemAt(pos)
+ menu.exec(self.tree_widget.viewport().mapToGlobal(pos))
+
def on_list_selection_change(self, current, previous):
# for idx in current.indexes():
# print(idx.data())
- print(current.text(0))
- self.table_widget.selectRow(int(current.text(0))-1)
+ # print(current.text(0))
+ self.current_toolid = int(current.text(0))
+
+ self.storage_to_form(self.db_tool_dict[current.text(0)])
def on_list_item_edited(self, item, column):
if column == 0:
return
- row = int(item.text(0)) - 1
- self.table_widget.item(row, 1).setText(item.text(1))
+
+ self.name_entry.set_value(item.text(1))
def storage_to_form(self, dict_storage):
for form_key in self.form_fields:
@@ -1941,8 +1976,15 @@ class ToolsDB2(QtWidgets.QWidget):
if form_key == storage_key:
try:
self.form_fields[form_key].set_value(dict_storage[form_key])
- except Exception:
- pass
+ except Exception as e:
+ print(str(e))
+ if storage_key == 'data':
+ for data_key in dict_storage[storage_key]:
+ if form_key == data_key:
+ try:
+ self.form_fields[form_key].set_value(dict_storage['data'][data_key])
+ except Exception as e:
+ print(str(e))
def form_to_storage(self, tool):
self.blockSignals(True)
@@ -1988,18 +2030,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.build_db_ui()
- self.tree_widget.setupContextMenu()
- self.tree_widget.addContextMenu(
- _("Add to DB"), self.on_tool_add, icon=QtGui.QIcon(self.app.resource_location + "/plus16.png"))
- self.tree_widget.addContextMenu(
- _("Copy from DB"), self.on_tool_copy, icon=QtGui.QIcon(self.app.resource_location + "/copy16.png"))
- self.tree_widget.addContextMenu(
- _("Delete from DB"), self.on_tool_delete, icon=QtGui.QIcon(self.app.resource_location + "/delete32.png"))
-
def build_db_ui(self):
self.ui_disconnect()
- self.table_widget.setRowCount(len(self.db_tool_dict))
-
nr_crt = 0
parent = self.tree_widget
@@ -2013,7 +2045,7 @@ class ToolsDB2(QtWidgets.QWidget):
t_name = dict_val['name']
try:
- self.add_tool_table_line(row, name=t_name, widget=self.table_widget, tooldict=dict_val)
+ # self.add_tool_table_line(row, name=t_name, tooldict=dict_val)
self.tree_widget.blockSignals(True)
try:
self.tree_widget.addParentEditable(parent=parent, title=[str(row+1), t_name], editable=True)
@@ -2022,211 +2054,18 @@ class ToolsDB2(QtWidgets.QWidget):
self.tree_widget.blockSignals(False)
except Exception as e:
self.app.log.debug("ToolDB.build_db_ui.add_tool_table_line() --> %s" % str(e))
- vertical_header = self.table_widget.verticalHeader()
- vertical_header.hide()
- horizontal_header = self.table_widget.horizontalHeader()
- horizontal_header.setMinimumSectionSize(10)
- horizontal_header.setDefaultSectionSize(70)
-
- self.table_widget.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
- for x in range(27):
- self.table_widget.resizeColumnToContents(x)
-
- horizontal_header.setSectionResizeMode(0, QtWidgets.QHeaderView.Fixed)
- # horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
- # horizontal_header.setSectionResizeMode(13, QtWidgets.QHeaderView.Fixed)
-
- horizontal_header.resizeSection(0, 20)
- # horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
- # horizontal_header.setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch)
+ if self.current_toolid is None or self.current_toolid < 1:
+ if self.db_tool_dict:
+ self.storage_to_form(self.db_tool_dict['1'])
+ else:
+ self.storage_to_form(self.db_tool_dict[str(self.current_toolid)])
self.ui_connect()
- def add_tool_table_line(self, row, name, widget, tooldict):
+ def add_tool_table_line(self, row, name, tooldict):
data = tooldict['data']
- nr_crt = row + 1
- id_item = QtWidgets.QTableWidgetItem('%d' % int(nr_crt))
- # id_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
- flags = id_item.flags() & ~QtCore.Qt.ItemIsEditable
- id_item.setFlags(flags)
- widget.setItem(row, 0, id_item) # Tool name/id
-
- tool_name_item = QtWidgets.QTableWidgetItem(name)
- widget.setItem(row, 1, tool_name_item)
-
- dia_item = FCDoubleSpinner()
- dia_item.set_precision(self.decimals)
- dia_item.setSingleStep(0.1)
- dia_item.set_range(0.0, 9999.9999)
- dia_item.set_value(float(tooldict['tooldia']))
- widget.setCellWidget(row, 2, dia_item)
-
- tool_offset_item = FCComboBox()
- for item in self.offset_item_options:
- tool_offset_item.addItem(item)
- tool_offset_item.set_value(tooldict['offset'])
- widget.setCellWidget(row, 3, tool_offset_item)
-
- c_offset_item = FCDoubleSpinner()
- c_offset_item.set_precision(self.decimals)
- c_offset_item.setSingleStep(0.1)
- c_offset_item.set_range(-9999.9999, 9999.9999)
- c_offset_item.set_value(float(tooldict['offset_value']))
- widget.setCellWidget(row, 4, c_offset_item)
-
- tt_item = FCComboBox()
- for item in self.type_item_options:
- tt_item.addItem(item)
- tt_item.set_value(tooldict['type'])
- widget.setCellWidget(row, 5, tt_item)
-
- tshape_item = FCComboBox()
- for item in self.tool_type_item_options:
- tshape_item.addItem(item)
- tshape_item.set_value(tooldict['tool_type'])
- widget.setCellWidget(row, 6, tshape_item)
-
- cutz_item = FCDoubleSpinner()
- cutz_item.set_precision(self.decimals)
- cutz_item.setSingleStep(0.1)
- if self.app.defaults['global_machinist_setting']:
- cutz_item.set_range(-9999.9999, 9999.9999)
- else:
- cutz_item.set_range(-9999.9999, -0.0000)
-
- cutz_item.set_value(float(data['cutz']))
- widget.setCellWidget(row, 7, cutz_item)
-
- multidepth_item = FCCheckBox()
- multidepth_item.set_value(data['multidepth'])
- widget.setCellWidget(row, 8, multidepth_item)
-
- # to make the checkbox centered but it can no longer have it's value accessed - needs a fix using findchild()
- # multidepth_item = QtWidgets.QWidget()
- # cb = FCCheckBox()
- # cb.set_value(data['multidepth'])
- # qhboxlayout = QtWidgets.QHBoxLayout(multidepth_item)
- # qhboxlayout.addWidget(cb)
- # qhboxlayout.setAlignment(QtCore.Qt.AlignCenter)
- # qhboxlayout.setContentsMargins(0, 0, 0, 0)
- # widget.setCellWidget(row, 8, multidepth_item)
-
- depth_per_pass_item = FCDoubleSpinner()
- depth_per_pass_item.set_precision(self.decimals)
- depth_per_pass_item.setSingleStep(0.1)
- depth_per_pass_item.set_range(0.0, 9999.9999)
- depth_per_pass_item.set_value(float(data['depthperpass']))
- widget.setCellWidget(row, 9, depth_per_pass_item)
-
- vtip_dia_item = FCDoubleSpinner()
- vtip_dia_item.set_precision(self.decimals)
- vtip_dia_item.setSingleStep(0.1)
- vtip_dia_item.set_range(0.0, 9999.9999)
- vtip_dia_item.set_value(float(data['vtipdia']))
- widget.setCellWidget(row, 10, vtip_dia_item)
-
- vtip_angle_item = FCDoubleSpinner()
- vtip_angle_item.set_precision(self.decimals)
- vtip_angle_item.setSingleStep(0.1)
- vtip_angle_item.set_range(-360.0, 360.0)
- vtip_angle_item.set_value(float(data['vtipangle']))
- widget.setCellWidget(row, 11, vtip_angle_item)
-
- travelz_item = FCDoubleSpinner()
- travelz_item.set_precision(self.decimals)
- travelz_item.setSingleStep(0.1)
- if self.app.defaults['global_machinist_setting']:
- travelz_item.set_range(-9999.9999, 9999.9999)
- else:
- travelz_item.set_range(0.0000, 9999.9999)
-
- travelz_item.set_value(float(data['travelz']))
- widget.setCellWidget(row, 12, travelz_item)
-
- fr_item = FCDoubleSpinner()
- fr_item.set_precision(self.decimals)
- fr_item.set_range(0.0, 9999.9999)
- fr_item.set_value(float(data['feedrate']))
- widget.setCellWidget(row, 13, fr_item)
-
- frz_item = FCDoubleSpinner()
- frz_item.set_precision(self.decimals)
- frz_item.set_range(0.0, 9999.9999)
- frz_item.set_value(float(data['feedrate_z']))
- widget.setCellWidget(row, 14, frz_item)
-
- frrapids_item = FCDoubleSpinner()
- frrapids_item.set_precision(self.decimals)
- frrapids_item.set_range(0.0, 9999.9999)
- frrapids_item.set_value(float(data['feedrate_rapid']))
- widget.setCellWidget(row, 15, frrapids_item)
-
- spindlespeed_item = FCSpinner()
- spindlespeed_item.set_range(0, 1000000)
- spindlespeed_item.set_value(int(data['spindlespeed']))
- spindlespeed_item.set_step(100)
- widget.setCellWidget(row, 16, spindlespeed_item)
-
- dwell_item = FCCheckBox()
- dwell_item.set_value(data['dwell'])
- widget.setCellWidget(row, 17, dwell_item)
-
- dwelltime_item = FCDoubleSpinner()
- dwelltime_item.set_precision(self.decimals)
- dwelltime_item.set_range(0.0000, 9999.9999)
- dwelltime_item.set_value(float(data['dwelltime']))
- widget.setCellWidget(row, 18, dwelltime_item)
-
- pp_item = FCComboBox()
- for item in self.app.preprocessors:
- pp_item.addItem(item)
- pp_item.set_value(data['ppname_g'])
- widget.setCellWidget(row, 19, pp_item)
-
- ecut_item = FCCheckBox()
- ecut_item.set_value(data['extracut'])
- widget.setCellWidget(row, 20, ecut_item)
-
- ecut_length_item = FCDoubleSpinner()
- ecut_length_item.set_precision(self.decimals)
- ecut_length_item.set_range(0.0000, 9999.9999)
- ecut_length_item.set_value(data['extracut_length'])
- widget.setCellWidget(row, 21, ecut_length_item)
-
- toolchange_item = FCCheckBox()
- toolchange_item.set_value(data['toolchange'])
- widget.setCellWidget(row, 22, toolchange_item)
-
- toolchangexy_item = QtWidgets.QTableWidgetItem(str(data['toolchangexy']) if data['toolchangexy'] else '')
- widget.setItem(row, 23, toolchangexy_item)
-
- toolchangez_item = FCDoubleSpinner()
- toolchangez_item.set_precision(self.decimals)
- toolchangez_item.setSingleStep(0.1)
- if self.app.defaults['global_machinist_setting']:
- toolchangez_item.set_range(-9999.9999, 9999.9999)
- else:
- toolchangez_item.set_range(0.0000, 9999.9999)
-
- toolchangez_item.set_value(float(data['toolchangez']))
- widget.setCellWidget(row, 24, toolchangez_item)
-
- startz_item = QtWidgets.QTableWidgetItem(str(data['startz']) if data['startz'] else '')
- widget.setItem(row, 25, startz_item)
-
- endz_item = FCDoubleSpinner()
- endz_item.set_precision(self.decimals)
- endz_item.setSingleStep(0.1)
- if self.app.defaults['global_machinist_setting']:
- endz_item.set_range(-9999.9999, 9999.9999)
- else:
- endz_item.set_range(0.0000, 9999.9999)
-
- endz_item.set_value(float(data['endz']))
- widget.setCellWidget(row, 26, endz_item)
-
def on_tool_add(self):
"""
Add a tool in the DB Tool Table
@@ -2277,11 +2116,11 @@ class ToolsDB2(QtWidgets.QWidget):
dict_elem['data'] = default_data
new_toolid = len(self.db_tool_dict) + 1
- self.db_tool_dict[new_toolid] = deepcopy(dict_elem)
+ self.db_tool_dict[str(new_toolid)] = deepcopy(dict_elem)
# add the new entry to the Tools DB table
+ self.update_storage()
self.build_db_ui()
- self.callback_on_edited()
self.app.inform.emit('[success] %s' % _("Tool added to DB."))
def on_tool_copy(self):
@@ -2289,20 +2128,23 @@ class ToolsDB2(QtWidgets.QWidget):
Copy a selection of Tools in the Tools DB table
:return:
"""
- new_tool_id = self.table_widget.rowCount() + 1
- for model_index in self.table_widget.selectionModel().selectedRows():
- # index = QtCore.QPersistentModelIndex(model_index)
- old_tool_id = self.table_widget.item(model_index.row(), 0).text()
- new_tool_id += 1
+ new_tool_id = len(self.db_tool_dict)
+ for item in self.tree_widget.selectedItems():
+ old_tool_id = item.data(0, QtCore.Qt.DisplayRole)
for toolid, dict_val in list(self.db_tool_dict.items()):
if int(old_tool_id) == int(toolid):
+ new_tool_id += 1
+ new_key = str(new_tool_id)
+
self.db_tool_dict.update({
- new_tool_id: deepcopy(dict_val)
+ new_key: deepcopy(dict_val)
})
+ self.current_toolid = new_tool_id
+
+ self.update_storage()
self.build_db_ui()
- self.callback_on_edited()
self.app.inform.emit('[success] %s' % _("Tool copied from Tools DB."))
def on_tool_delete(self):
@@ -2310,17 +2152,18 @@ class ToolsDB2(QtWidgets.QWidget):
Delete a selection of Tools in the Tools DB table
:return:
"""
- for model_index in self.table_widget.selectionModel().selectedRows():
- # index = QtCore.QPersistentModelIndex(model_index)
- toolname_to_remove = self.table_widget.item(model_index.row(), 0).text()
+ for item in self.tree_widget.selectedItems():
+ toolname_to_remove = item.data(0, QtCore.Qt.DisplayRole)
for toolid, dict_val in list(self.db_tool_dict.items()):
if int(toolname_to_remove) == int(toolid):
# remove from the storage
self.db_tool_dict.pop(toolid, None)
+ self.current_toolid -= 1
+
+ self.update_storage()
self.build_db_ui()
- self.callback_on_edited()
self.app.inform.emit('[success] %s' % _("Tool removed from Tools DB."))
def on_export_tools_db_file(self):
@@ -2408,7 +2251,7 @@ class ToolsDB2(QtWidgets.QWidget):
self.app.inform.emit('[success] %s: %s' % (_("Loaded FlatCAM Tools DB from"), filename))
self.build_db_ui()
- self.callback_on_edited()
+ self.update_storage()
def on_save_tools_db(self, silent=False):
self.app.log.debug("ToolsDB.on_save_button() --> Saving Tools Database to file.")
@@ -2434,145 +2277,126 @@ class ToolsDB2(QtWidgets.QWidget):
self.app.inform.emit('[success] %s' % _("Saved Tools DB."))
def ui_connect(self):
- try:
- try:
- self.table_widget.itemChanged.disconnect(self.callback_on_edited)
- except (TypeError, AttributeError):
- pass
- self.table_widget.itemChanged.connect(self.callback_on_edited)
- except AttributeError:
- pass
+ # make sure that we don't make multiple connections to the widgets
+ self.ui_disconnect()
- for row in range(self.table_widget.rowCount()):
- for col in range(self.table_widget.columnCount()):
- # ComboBox
- try:
- try:
- self.table_widget.cellWidget(row, col).currentIndexChanged.disconnect(self.callback_on_edited)
- except (TypeError, AttributeError):
- pass
- self.table_widget.cellWidget(row, col).currentIndexChanged.connect(self.callback_on_edited)
- except AttributeError:
- pass
+ self.name_entry.editingFinished.connect(self.update_tree_name)
- # CheckBox
- try:
- try:
- self.table_widget.cellWidget(row, col).toggled.disconnect(self.callback_on_edited)
- except (TypeError, AttributeError):
- pass
- self.table_widget.cellWidget(row, col).toggled.connect(self.callback_on_edited)
- except AttributeError:
- pass
+ for key in self.form_fields:
+ wdg = self.form_fields[key]
- # SpinBox, DoubleSpinBox
- try:
- try:
- self.table_widget.cellWidget(row, col).valueChanged.disconnect(self.callback_on_edited)
- except (TypeError, AttributeError):
- pass
- self.table_widget.cellWidget(row, col).valueChanged.connect(self.callback_on_edited)
- except AttributeError:
- pass
+ # FCEntry
+ if isinstance(wdg, FCEntry):
+ wdg.textChanged.connect(self.update_storage)
+
+ # ComboBox
+ if isinstance(wdg, FCComboBox):
+ wdg.currentIndexChanged.connect(self.update_storage)
+
+ # CheckBox
+ if isinstance(wdg, FCCheckBox):
+ wdg.toggled.connect(self.update_storage)
+
+ # SpinBox, DoubleSpinBox
+ if isinstance(wdg, FCSpinner) or isinstance(wdg, FCDoubleSpinner):
+ wdg.valueChanged.connect(self.update_storage)
def ui_disconnect(self):
try:
- self.table_widget.itemChanged.disconnect(self.callback_on_edited)
+ self.name_entry.editingFinished.disconnect(self.update_tree_name)
except (TypeError, AttributeError):
pass
- for row in range(self.table_widget.rowCount()):
- for col in range(self.table_widget.columnCount()):
- # ComboBox
+ for key in self.form_fields:
+ wdg = self.form_fields[key]
+
+ # FCEntry
+ if isinstance(wdg, FCEntry):
try:
- self.table_widget.cellWidget(row, col).currentIndexChanged.disconnect(self.callback_on_edited)
+ wdg.textChanged.disconnect(self.update_storage)
except (TypeError, AttributeError):
pass
- # CheckBox
+ # ComboBox
+ if isinstance(wdg, FCComboBox):
try:
- self.table_widget.cellWidget(row, col).toggled.disconnect(self.callback_on_edited)
+ wdg.currentIndexChanged.disconnect(self.update_storage)
except (TypeError, AttributeError):
pass
- # SpinBox, DoubleSpinBox
+ # CheckBox
+ if isinstance(wdg, FCCheckBox):
try:
- self.table_widget.cellWidget(row, col).valueChanged.disconnect(self.callback_on_edited)
+ wdg.toggled.disconnect(self.update_storage)
except (TypeError, AttributeError):
pass
- def callback_on_edited(self):
+ # SpinBox, DoubleSpinBox
+ if isinstance(wdg, FCSpinner) or isinstance(wdg, FCDoubleSpinner):
+ try:
+ wdg.valueChanged.disconnect(self.update_storage)
+ except (TypeError, AttributeError):
+ pass
- # update the dictionary storage self.db_tool_dict
- self.db_tool_dict.clear()
- dict_elem = {}
- default_data = {}
+ def update_tree_name(self):
+ val = self.name_entry.get_value()
- for row in range(self.table_widget.rowCount()):
- new_toolid = row + 1
- for col in range(self.table_widget.columnCount()):
- column_header_text = self.table_widget.horizontalHeaderItem(col).text()
- if column_header_text == _('Tool Name'):
- dict_elem['name'] = self.table_widget.item(row, col).text()
- elif column_header_text == _('Tool Dia'):
- dict_elem['tooldia'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('Tool Offset'):
- dict_elem['offset'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('Custom Offset'):
- dict_elem['offset_value'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('Tool Type'):
- dict_elem['type'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('Tool Shape'):
- dict_elem['tool_type'] = self.table_widget.cellWidget(row, col).get_value()
- else:
- if column_header_text == _('Cut Z'):
- default_data['cutz'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('MultiDepth'):
- default_data['multidepth'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('DPP'):
- default_data['depthperpass'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('V-Dia'):
- default_data['vtipdia'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('V-Angle'):
- default_data['vtipangle'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('Travel Z'):
- default_data['travelz'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('FR'):
- default_data['feedrate'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('FR Z'):
- default_data['feedrate_z'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('FR Rapids'):
- default_data['feedrate_rapid'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('Spindle Speed'):
- default_data['spindlespeed'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('Dwell'):
- default_data['dwell'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('Dwelltime'):
- default_data['dwelltime'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('Preprocessor'):
- default_data['ppname_g'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('ExtraCut'):
- default_data['extracut'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _("E-Cut Length"):
- default_data['extracut_length'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('Toolchange'):
- default_data['toolchange'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('Toolchange XY'):
- default_data['toolchangexy'] = self.table_widget.item(row, col).text()
- elif column_header_text == _('Toolchange Z'):
- default_data['toolchangez'] = self.table_widget.cellWidget(row, col).get_value()
- elif column_header_text == _('Start Z'):
- default_data['startz'] = float(self.table_widget.item(row, col).text()) \
- if self.table_widget.item(row, col).text() is not '' else None
- elif column_header_text == _('End Z'):
- default_data['endz'] = self.table_widget.cellWidget(row, col).get_value()
+ item = self.tree_widget.currentItem()
+ # I'm setting the value for the second column (designated by 1) because first column holds the ID
+ # and second column holds the Name (this behavior is set in the build_ui method)
+ item.setData(1, QtCore.Qt.DisplayRole, val)
- dict_elem['data'] = default_data
- self.db_tool_dict.update(
- {
- new_toolid: deepcopy(dict_elem)
- }
- )
+ def update_storage(self):
+
+ tool_id = str(self.current_toolid)
+ wdg = self.sender()
+ if wdg is None:
+ return
+ wdg_name = wdg.objectName()
+
+ if wdg_name == "gdb_name":
+ self.db_tool_dict[tool_id]['name'] = wdg.get_value()
+ elif wdg_name == "gdb_dia":
+ self.db_tool_dict[tool_id]['tooldia'] = wdg.get_value()
+ elif wdg_name == "gdb_tool_offset":
+ self.db_tool_dict[tool_id]['offset'] = wdg.get_value()
+ elif wdg_name == "gdb_custom_offset":
+ self.db_tool_dict[tool_id]['offset_value'] = wdg.get_value()
+ elif wdg_name == "gdb_type":
+ self.db_tool_dict[tool_id]['type'] = wdg.get_value()
+ elif wdg_name == "gdb_shape":
+ self.db_tool_dict[tool_id]['tool_type'] = wdg.get_value()
+ else:
+ if wdg_name == "gdb_cutz":
+ self.db_tool_dict[tool_id]['data']['cutz'] = wdg.get_value()
+ elif wdg_name == "gdb_multidepth":
+ self.db_tool_dict[tool_id]['data']['multidepth'] = wdg.get_value()
+ elif wdg_name == "gdb_multidepth_entry":
+ self.db_tool_dict[tool_id]['data']['depthperpass'] = wdg.get_value()
+
+ elif wdg_name == "gdb_travel":
+ self.db_tool_dict[tool_id]['data']['travelz'] = wdg.get_value()
+ elif wdg_name == "gdb_frxy":
+ self.db_tool_dict[tool_id]['data']['feedrate'] = wdg.get_value()
+ elif wdg_name == "gdb_frz":
+ self.db_tool_dict[tool_id]['data']['feedrate_z'] = wdg.get_value()
+ elif wdg_name == "gdb_spindle":
+ self.db_tool_dict[tool_id]['data']['spindlespeed'] = wdg.get_value()
+ elif wdg_name == "gdb_dwell":
+ self.db_tool_dict[tool_id]['data']['dwell'] = wdg.get_value()
+ elif wdg_name == "gdb_dwelltime":
+ self.db_tool_dict[tool_id]['data']['dwelltime'] = wdg.get_value()
+
+ elif wdg_name == "gdb_vdia":
+ self.db_tool_dict[tool_id]['data']['vtipdia'] = wdg.get_value()
+ elif wdg_name == "gdb_vangle":
+ self.db_tool_dict[tool_id]['data']['vtipangle'] = wdg.get_value()
+ elif wdg_name == "gdb_frapids":
+ self.db_tool_dict[tool_id]['data']['feedrate_rapid'] = wdg.get_value()
+ elif wdg_name == "gdb_ecut":
+ self.db_tool_dict[tool_id]['data']['extracut'] = wdg.get_value()
+ elif wdg_name == "gdb_ecut_length":
+ self.db_tool_dict[tool_id]['data']['extracut_length'] = wdg.get_value()
self.callback_app()
diff --git a/README.md b/README.md
index 7ace08cb..0137a92f 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+28.03.2020
+
+- finished the new database based on a QTreeWidget
+
21.03.2020
- fixed Cutout Tool to work with negative values for Margin parameter
diff --git a/requirements.txt b/requirements.txt
index 6e58e3f7..ee962276 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,7 @@
# This file contains python only requirements to be installed with pip
# Python packages that cannot be installed with pip (e.g. PyQt5, GDAL) are not included.
# Usage: pip3 install -r requirements.txt
-pyqt5==5.12
+pyqt5==5.12.1
numpy>=1.16
matplotlib>=3.1
cycler>=0.10
From 1ca650e883fc31956a2b76301a5d20f23647acc3 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 29 Mar 2020 14:22:11 +0300
Subject: [PATCH 135/209] - modified the new database to accept data from NCC
and Paint Tools
---
FlatCAMApp.py | 18 +-
FlatCAMCommon.py | 411 ++++++++++++++++++++++++++++++++++----
README.md | 4 +
flatcamGUI/GUIElements.py | 13 ++
4 files changed, 402 insertions(+), 44 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 0564f774..0306632b 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -140,7 +140,7 @@ class App(QtCore.QObject):
# ################## Version and VERSION DATE ##############################
# ##########################################################################
version = 8.992
- version_date = "2020/02/22"
+ version_date = "2020/03/27"
beta = True
engine = '3D'
@@ -353,14 +353,14 @@ class App(QtCore.QObject):
f.close()
# create fctool_tools_db.FlatDB file if there is none
- try:
- f = open(self.data_path + '/fctool_tools_db.FlatDB')
- f.close()
- except IOError:
- App.log.debug('Creating empty fctool_tool_db.FlatDB')
- f = open(self.data_path + '/fctool_tools_db.FlatDB', 'w')
- json.dump({}, f)
- f.close()
+ # try:
+ # f = open(self.data_path + '/fctool_tools_db.FlatDB')
+ # f.close()
+ # except IOError:
+ # App.log.debug('Creating empty fctool_tool_db.FlatDB')
+ # f = open(self.data_path + '/fctool_tools_db.FlatDB', 'w')
+ # json.dump({}, f)
+ # f.close()
# create current_defaults.FlatConfig file if there is none
try:
diff --git a/FlatCAMCommon.py b/FlatCAMCommon.py
index 644f7ca4..f80106e3 100644
--- a/FlatCAMCommon.py
+++ b/FlatCAMCommon.py
@@ -1459,8 +1459,8 @@ class ToolsDB2(QtWidgets.QWidget):
}
""")
self.basic_vlay = QtWidgets.QVBoxLayout()
- self.basic_box.setTitle(_("Basic Parameters"))
- self.basic_box.setMinimumWidth(250)
+ self.basic_box.setTitle(_("Basic Geo Parameters"))
+ self.basic_box.setFixedWidth(250)
self.advanced_box = QtWidgets.QGroupBox()
self.advanced_box.setStyleSheet("""
@@ -1471,14 +1471,50 @@ class ToolsDB2(QtWidgets.QWidget):
}
""")
self.advanced_vlay = QtWidgets.QVBoxLayout()
- self.advanced_box.setTitle(_("Advanced Parameters"))
- self.advanced_box.setMinimumWidth(250)
+ self.advanced_box.setTitle(_("Advanced Geo Parameters"))
+ self.advanced_box.setFixedWidth(250)
+
+ self.ncc_box = QtWidgets.QGroupBox()
+ self.ncc_box.setStyleSheet("""
+ QGroupBox
+ {
+ font-size: 16px;
+ font-weight: bold;
+ }
+ """)
+ self.ncc_vlay = QtWidgets.QVBoxLayout()
+ self.ncc_box.setTitle(_("NCC Parameters"))
+ self.ncc_box.setFixedWidth(250)
+
+ self.paint_box = QtWidgets.QGroupBox()
+ self.paint_box.setStyleSheet("""
+ QGroupBox
+ {
+ font-size: 16px;
+ font-weight: bold;
+ }
+ """)
+ self.paint_vlay = QtWidgets.QVBoxLayout()
+ self.paint_box.setTitle(_("Paint Parameters"))
+ self.paint_box.setFixedWidth(250)
self.basic_box.setLayout(self.basic_vlay)
self.advanced_box.setLayout(self.advanced_vlay)
+ self.ncc_box.setLayout(self.ncc_vlay)
+ self.paint_box.setLayout(self.paint_vlay)
- param_hlay.addWidget(self.basic_box)
- param_hlay.addWidget(self.advanced_box)
+ geo_vlay = QtWidgets.QVBoxLayout()
+ geo_vlay.addWidget(self.basic_box)
+ geo_vlay.addWidget(self.advanced_box)
+ geo_vlay.addStretch()
+
+ tools_vlay = QtWidgets.QVBoxLayout()
+ tools_vlay.addWidget(self.ncc_box)
+ tools_vlay.addWidget(self.paint_box)
+ tools_vlay.addStretch()
+
+ param_hlay.addLayout(geo_vlay)
+ param_hlay.addLayout(tools_vlay)
param_hlay.addStretch()
# ###########################################################################
@@ -1492,7 +1528,7 @@ class ToolsDB2(QtWidgets.QWidget):
self.basic_vlay.addStretch()
# Tool Name
- self.name_label = QtWidgets.QLabel('%s:' % _('Tool Name'))
+ self.name_label = QtWidgets.QLabel('%s:' % _('Tool Name'))
self.name_label.setToolTip(
_("Tool name.\n"
"This is not used in the app, it's function\n"
@@ -1731,7 +1767,7 @@ class ToolsDB2(QtWidgets.QWidget):
self.grid1.addWidget(self.vdia_entry, 7, 1)
# V-Angle
- self.vangle_label = QtWidgets.QLabel('%s:' % _("V-Angle"))
+ self.vangle_label = QtWidgets.QLabel('%s:' % _("V-Angle"))
self.vangle_label.setToolTip(
_("V-Agle.\n"
"Angle at the tip for the V-Shape Tools."))
@@ -1745,7 +1781,7 @@ class ToolsDB2(QtWidgets.QWidget):
self.grid1.addWidget(self.vangle_entry, 8, 1)
# Feedrate Rapids
- self.frapids_label = QtWidgets.QLabel('%s:' % _("FR Rapids"))
+ self.frapids_label = QtWidgets.QLabel('%s:' % _("FR Rapids"))
self.frapids_label.setToolTip(
_("FR Rapids. Feedrate Rapids\n"
"Speed used while moving as fast as possible.\n"
@@ -1793,6 +1829,245 @@ class ToolsDB2(QtWidgets.QWidget):
self.grid1.addWidget(self.ecut_length_label, 13, 0)
self.grid1.addWidget(self.ecut_length_entry, 13, 1)
+ # ###########################################################################
+ # ############### NCC UI form ###############################################
+ # ###########################################################################
+
+ self.grid2 = QtWidgets.QGridLayout()
+ self.ncc_vlay.addLayout(self.grid2)
+ self.grid2.setColumnStretch(0, 0)
+ self.grid2.setColumnStretch(1, 1)
+ self.ncc_vlay.addStretch()
+
+ # Operation
+ op_label = QtWidgets.QLabel('%s:' % _('Operation'))
+ op_label.setToolTip(
+ _("The 'Operation' can be:\n"
+ "- Isolation -> will ensure that the non-copper clearing is always complete.\n"
+ "If it's not successful then the non-copper clearing will fail, too.\n"
+ "- Clear -> the regular non-copper clearing.")
+ )
+
+ self.op_radio = RadioSet([
+ {"label": _("Clear"), "value": "clear"},
+ {"label": _("Isolation"), "value": "iso"}
+ ], orientation='horizontal', stretch=False)
+ self.op_radio.setObjectName("gdb_n_operation")
+
+ self.grid2.addWidget(op_label, 13, 0)
+ self.grid2.addWidget(self.op_radio, 13, 1)
+
+ # Milling Type Radio Button
+ self.milling_type_label = QtWidgets.QLabel('%s:' % _('Milling Type'))
+ self.milling_type_label.setToolTip(
+ _("Milling type when the selected tool is of type: 'iso_op':\n"
+ "- climb / best for precision milling and to reduce tool usage\n"
+ "- conventional / useful when there is no backlash compensation")
+ )
+
+ self.milling_type_radio = RadioSet([{'label': _('Climb'), 'value': 'cl'},
+ {'label': _('Conventional'), 'value': 'cv'}])
+ self.milling_type_radio.setToolTip(
+ _("Milling type when the selected tool is of type: 'iso_op':\n"
+ "- climb / best for precision milling and to reduce tool usage\n"
+ "- conventional / useful when there is no backlash compensation")
+ )
+ self.milling_type_radio.setObjectName("gdb_n_milling_type")
+
+ self.milling_type_label.setEnabled(False)
+ self.milling_type_radio.setEnabled(False)
+
+ self.grid2.addWidget(self.milling_type_label, 14, 0)
+ self.grid2.addWidget(self.milling_type_radio, 14, 1)
+
+ # Overlap Entry
+ nccoverlabel = QtWidgets.QLabel('%s:' % _('Overlap'))
+ nccoverlabel.setToolTip(
+ _("How much (percentage) of the tool width to overlap each tool pass.\n"
+ "Adjust the value starting with lower values\n"
+ "and increasing it if areas that should be cleared are still \n"
+ "not cleared.\n"
+ "Lower values = faster processing, faster execution on CNC.\n"
+ "Higher values = slow processing and slow execution on CNC\n"
+ "due of too many paths.")
+ )
+ self.ncc_overlap_entry = FCDoubleSpinner(suffix='%')
+ self.ncc_overlap_entry.set_precision(self.decimals)
+ self.ncc_overlap_entry.setWrapping(True)
+ self.ncc_overlap_entry.setRange(0.000, 99.9999)
+ self.ncc_overlap_entry.setSingleStep(0.1)
+ self.ncc_overlap_entry.setObjectName("gdb_n_overlap")
+
+ self.grid2.addWidget(nccoverlabel, 15, 0)
+ self.grid2.addWidget(self.ncc_overlap_entry, 15, 1)
+
+ # Margin
+ nccmarginlabel = QtWidgets.QLabel('%s:' % _('Margin'))
+ nccmarginlabel.setToolTip(
+ _("Bounding box margin.")
+ )
+ self.ncc_margin_entry = FCDoubleSpinner()
+ self.ncc_margin_entry.set_precision(self.decimals)
+ self.ncc_margin_entry.set_range(-9999.9999, 9999.9999)
+ self.ncc_margin_entry.setObjectName("gdb_n_margin")
+
+ self.grid2.addWidget(nccmarginlabel, 16, 0)
+ self.grid2.addWidget(self.ncc_margin_entry, 16, 1)
+
+ # Method
+ methodlabel = QtWidgets.QLabel('%s:' % _('Method'))
+ methodlabel.setToolTip(
+ _("Algorithm for copper clearing:\n"
+ "- Standard: Fixed step inwards.\n"
+ "- Seed-based: Outwards from seed.\n"
+ "- Line-based: Parallel lines.")
+ )
+
+ self.ncc_method_combo = FCComboBox()
+ self.ncc_method_combo.addItems(
+ [_("Standard"), _("Seed"), _("Lines")]
+ )
+ self.ncc_method_combo.setObjectName("gdb_n_method")
+
+ self.grid2.addWidget(methodlabel, 17, 0)
+ self.grid2.addWidget(self.ncc_method_combo, 17, 1)
+
+ # Connect lines
+ self.ncc_connect_cb = FCCheckBox('%s' % _("Connect"))
+ self.ncc_connect_cb.setObjectName("gdb_n_connect")
+
+ self.ncc_connect_cb.setToolTip(
+ _("Draw lines between resulting\n"
+ "segments to minimize tool lifts.")
+ )
+ self.grid2.addWidget(self.ncc_connect_cb, 18, 0)
+
+ # Contour
+ self.ncc_contour_cb = FCCheckBox('%s' % _("Contour"))
+ self.ncc_contour_cb.setObjectName("gdb_n_contour")
+
+ self.ncc_contour_cb.setToolTip(
+ _("Cut around the perimeter of the polygon\n"
+ "to trim rough edges.")
+ )
+ self.grid2.addWidget(self.ncc_contour_cb, 18, 1)
+
+ # ## NCC Offset choice
+ self.ncc_choice_offset_cb = FCCheckBox('%s' % _("Offset"))
+ self.ncc_choice_offset_cb.setObjectName("gdb_n_offset")
+
+ self.ncc_choice_offset_cb.setToolTip(
+ _("If used, it will add an offset to the copper features.\n"
+ "The copper clearing will finish to a distance\n"
+ "from the copper features.\n"
+ "The value can be between 0 and 10 FlatCAM units.")
+ )
+ self.grid2.addWidget(self.ncc_choice_offset_cb, 19, 0)
+
+ # ## NCC Offset Entry
+ self.ncc_offset_spinner = FCDoubleSpinner()
+ self.ncc_offset_spinner.set_range(0.00, 10.00)
+ self.ncc_offset_spinner.set_precision(4)
+ self.ncc_offset_spinner.setWrapping(True)
+ self.ncc_offset_spinner.setObjectName("gdb_n_offset_value")
+
+ units = self.app.defaults['units'].upper()
+ if units == 'MM':
+ self.ncc_offset_spinner.setSingleStep(0.1)
+ else:
+ self.ncc_offset_spinner.setSingleStep(0.01)
+
+ self.grid2.addWidget(self.ncc_offset_spinner, 19, 1)
+
+ # ###########################################################################
+ # ############### Paint UI form #############################################
+ # ###########################################################################
+
+ self.grid3 = QtWidgets.QGridLayout()
+ self.paint_vlay.addLayout(self.grid3)
+ self.grid3.setColumnStretch(0, 0)
+ self.grid3.setColumnStretch(1, 1)
+ self.paint_vlay.addStretch()
+
+ # Overlap
+ ovlabel = QtWidgets.QLabel('%s:' % _('Overlap'))
+ ovlabel.setToolTip(
+ _("How much (percentage) of the tool width to overlap each tool pass.\n"
+ "Adjust the value starting with lower values\n"
+ "and increasing it if areas that should be painted are still \n"
+ "not painted.\n"
+ "Lower values = faster processing, faster execution on CNC.\n"
+ "Higher values = slow processing and slow execution on CNC\n"
+ "due of too many paths.")
+ )
+ self.paintoverlap_entry = FCDoubleSpinner(suffix='%')
+ self.paintoverlap_entry.set_precision(3)
+ self.paintoverlap_entry.setWrapping(True)
+ self.paintoverlap_entry.setRange(0.0000, 99.9999)
+ self.paintoverlap_entry.setSingleStep(0.1)
+ self.paintoverlap_entry.setObjectName('gdb_p_overlap')
+
+ self.grid3.addWidget(ovlabel, 1, 0)
+ self.grid3.addWidget(self.paintoverlap_entry, 1, 1)
+
+ # Margin
+ marginlabel = QtWidgets.QLabel('%s:' % _('Margin'))
+ marginlabel.setToolTip(
+ _("Distance by which to avoid\n"
+ "the edges of the polygon to\n"
+ "be painted.")
+ )
+ self.paintmargin_entry = FCDoubleSpinner()
+ self.paintmargin_entry.set_precision(self.decimals)
+ self.paintmargin_entry.set_range(-9999.9999, 9999.9999)
+ self.paintmargin_entry.setObjectName('gdb_p_margin')
+
+ self.grid3.addWidget(marginlabel, 2, 0)
+ self.grid3.addWidget(self.paintmargin_entry, 2, 1)
+
+ # Method
+ methodlabel = QtWidgets.QLabel('%s:' % _('Method'))
+ methodlabel.setToolTip(
+ _("Algorithm for painting:\n"
+ "- Standard: Fixed step inwards.\n"
+ "- Seed-based: Outwards from seed.\n"
+ "- Line-based: Parallel lines.\n"
+ "- Laser-lines: Active only for Gerber objects.\n"
+ "Will create lines that follow the traces.\n"
+ "- Combo: In case of failure a new method will be picked from the above\n"
+ "in the order specified.")
+ )
+
+ self.paintmethod_combo = FCComboBox()
+ self.paintmethod_combo.addItems(
+ [_("Standard"), _("Seed"), _("Lines"), _("Laser_lines"), _("Combo")]
+ )
+ idx = self.paintmethod_combo.findText(_("Laser_lines"))
+ self.paintmethod_combo.model().item(idx).setEnabled(False)
+
+ self.paintmethod_combo.setObjectName('gdb_p_method')
+
+ self.grid3.addWidget(methodlabel, 7, 0)
+ self.grid3.addWidget(self.paintmethod_combo, 7, 1)
+
+ # Connect lines
+ self.pathconnect_cb = FCCheckBox('%s' % _("Connect"))
+ self.pathconnect_cb.setObjectName('gdb_p_connect')
+ self.pathconnect_cb.setToolTip(
+ _("Draw lines between resulting\n"
+ "segments to minimize tool lifts.")
+ )
+
+ self.paintcontour_cb = FCCheckBox('%s' % _("Contour"))
+ self.paintcontour_cb.setObjectName('gdb_p_contour')
+ self.paintcontour_cb.setToolTip(
+ _("Cut around the perimeter of the polygon\n"
+ "to trim rough edges.")
+ )
+
+ self.grid3.addWidget(self.pathconnect_cb, 10, 0)
+ self.grid3.addWidget(self.paintcontour_cb, 10, 1)
+
# ####################################################################
# ####################################################################
# GUI for the lower part of the window
@@ -1890,7 +2165,25 @@ class ToolsDB2(QtWidgets.QWidget):
"vtipangle": self.vangle_entry,
"feedrate_rapid": self.frapids_entry,
"extracut": self.ecut_cb,
- "extracut_length": self.ecut_length_entry
+ "extracut_length": self.ecut_length_entry,
+
+ # NCC
+ "tools_nccoperation": self.op_radio,
+ "tools_nccmilling_type": self.milling_type_radio,
+ "tools_nccoverlap": self.ncc_overlap_entry,
+ "tools_nccmargin": self.ncc_margin_entry,
+ "tools_nccmethod": self.ncc_method_combo,
+ "tools_nccconnect": self.ncc_connect_cb,
+ "tools_ncccontour": self.ncc_contour_cb,
+ "tools_ncc_offset_choice": self.ncc_choice_offset_cb,
+ "tools_ncc_offset_value": self.ncc_offset_spinner,
+
+ # Paint
+ "paintoverlap": self.paintoverlap_entry,
+ "paintmargin": self.paintmargin_entry,
+ "paintmethod": self.paintmethod_combo,
+ "pathconnect": self.pathconnect_cb,
+ "paintcontour": self.paintcontour_cb,
}
self.name2option = {
@@ -1916,7 +2209,25 @@ class ToolsDB2(QtWidgets.QWidget):
"gdb_vangle": "vtipangle",
"gdb_frapids": "feedrate_rapid",
"gdb_ecut": "extracut",
- "gdb_ecut_length": "extracut_length"
+ "gdb_ecut_length": "extracut_length",
+
+ # NCC
+ "gdb_n_operation": "nccoperation",
+ "gdb_n_overlap": "nccoverlap",
+ "gdb_n_margin": "nccmargin",
+ "gdb_n_method": "nccmethod",
+ "gdb_n_connect": "nccconnect",
+ "gdb_n_contour": "ncccontour",
+ "gdb_n_offset": "nccoffset",
+ "gdb_n_offset_value": "nccoffset_value",
+ "gdb_n_milling_type": "milling_type",
+
+ # Paint
+ 'gdb_p_overlap': "paintoverlap",
+ 'gdb_p_margin': "paintmargin",
+ 'gdb_p_method': "paintmethod",
+ 'gdb_p_connect': "pathconnect",
+ 'gdb_p_contour': "paintcontour",
}
self.current_toolid = None
@@ -1993,7 +2304,6 @@ class ToolsDB2(QtWidgets.QWidget):
wdg_objname = widget_changed.objectName()
option_changed = self.name2option[wdg_objname]
-
tooluid_item = int(tool)
for tooluid_key, tooluid_val in self.db_tool_dict.items():
@@ -2058,14 +2368,27 @@ class ToolsDB2(QtWidgets.QWidget):
if self.current_toolid is None or self.current_toolid < 1:
if self.db_tool_dict:
self.storage_to_form(self.db_tool_dict['1'])
+
+ # Enable GUI
+ self.basic_box.setEnabled(True)
+ self.advanced_box.setEnabled(True)
+ self.ncc_box.setEnabled(True)
+ self.paint_box.setEnabled(True)
+
+ self.tree_widget.setCurrentItem(self.tree_widget.topLevelItem(0))
+ self.tree_widget.setFocus()
+
+ else:
+ # Disable GUI
+ self.basic_box.setEnabled(False)
+ self.advanced_box.setEnabled(False)
+ self.ncc_box.setEnabled(False)
+ self.paint_box.setEnabled(False)
else:
self.storage_to_form(self.db_tool_dict[str(self.current_toolid)])
self.ui_connect()
- def add_tool_table_line(self, row, name, tooldict):
- data = tooldict['data']
-
def on_tool_add(self):
"""
Add a tool in the DB Tool Table
@@ -2074,26 +2397,44 @@ class ToolsDB2(QtWidgets.QWidget):
default_data = {}
default_data.update({
- "cutz": float(self.app.defaults["geometry_cutz"]),
- "multidepth": self.app.defaults["geometry_multidepth"],
- "depthperpass": float(self.app.defaults["geometry_depthperpass"]),
- "vtipdia": float(self.app.defaults["geometry_vtipdia"]),
- "vtipangle": float(self.app.defaults["geometry_vtipangle"]),
- "travelz": float(self.app.defaults["geometry_travelz"]),
- "feedrate": float(self.app.defaults["geometry_feedrate"]),
- "feedrate_z": float(self.app.defaults["geometry_feedrate_z"]),
- "feedrate_rapid": float(self.app.defaults["geometry_feedrate_rapid"]),
- "spindlespeed": self.app.defaults["geometry_spindlespeed"],
- "dwell": self.app.defaults["geometry_dwell"],
- "dwelltime": float(self.app.defaults["geometry_dwelltime"]),
- "ppname_g": self.app.defaults["geometry_ppname_g"],
- "extracut": self.app.defaults["geometry_extracut"],
- "extracut_length": float(self.app.defaults["geometry_extracut_length"]),
- "toolchange": self.app.defaults["geometry_toolchange"],
- "toolchangexy": self.app.defaults["geometry_toolchangexy"],
- "toolchangez": float(self.app.defaults["geometry_toolchangez"]),
- "startz": self.app.defaults["geometry_startz"],
- "endz": float(self.app.defaults["geometry_endz"])
+ "cutz": float(self.app.defaults["geometry_cutz"]),
+ "multidepth": self.app.defaults["geometry_multidepth"],
+ "depthperpass": float(self.app.defaults["geometry_depthperpass"]),
+ "vtipdia": float(self.app.defaults["geometry_vtipdia"]),
+ "vtipangle": float(self.app.defaults["geometry_vtipangle"]),
+ "travelz": float(self.app.defaults["geometry_travelz"]),
+ "feedrate": float(self.app.defaults["geometry_feedrate"]),
+ "feedrate_z": float(self.app.defaults["geometry_feedrate_z"]),
+ "feedrate_rapid": float(self.app.defaults["geometry_feedrate_rapid"]),
+ "spindlespeed": self.app.defaults["geometry_spindlespeed"],
+ "dwell": self.app.defaults["geometry_dwell"],
+ "dwelltime": float(self.app.defaults["geometry_dwelltime"]),
+ "ppname_g": self.app.defaults["geometry_ppname_g"],
+ "extracut": self.app.defaults["geometry_extracut"],
+ "extracut_length": float(self.app.defaults["geometry_extracut_length"]),
+ "toolchange": self.app.defaults["geometry_toolchange"],
+ "toolchangexy": self.app.defaults["geometry_toolchangexy"],
+ "toolchangez": float(self.app.defaults["geometry_toolchangez"]),
+ "startz": self.app.defaults["geometry_startz"],
+ "endz": float(self.app.defaults["geometry_endz"]),
+
+ # NCC
+ "tools_nccoperation": self.app.defaults["tools_nccoperation"],
+ "tools_nccmilling_type": self.app.defaults["tools_nccmilling_type"],
+ "tools_nccoverlap": float(self.app.defaults["tools_nccoverlap"]),
+ "tools_nccmargin": float(self.app.defaults["tools_nccmargin"]),
+ "tools_nccmethod": self.app.defaults["tools_nccmethod"],
+ "tools_nccconnect": self.app.defaults["tools_nccconnect"],
+ "tools_ncccontour": self.app.defaults["tools_ncccontour"],
+ "tools_ncc_offset_choice": self.app.defaults["tools_ncc_offset_choice"],
+ "tools_ncc_offset_value": float(self.app.defaults["tools_ncc_offset_value"]),
+
+ # Paint
+ "paintoverlap": float(self.app.defaults["tools_paintoverlap"]),
+ "paintmargin": float(self.app.defaults["tools_paintmargin"]),
+ "paintmethod": self.app.defaults["tools_paintmethod"],
+ "pathconnect": self.app.defaults["tools_pathconnect"],
+ "paintcontour": self.app.defaults["tools_paintcontour"],
})
dict_elem = {}
diff --git a/README.md b/README.md
index 0137a92f..bc228160 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+29.03.2020
+
+- modified the new database to accept data from NCC and Paint Tools
+
28.03.2020
- finished the new database based on a QTreeWidget
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index fbfd739e..c9fdc607 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -163,9 +163,20 @@ class FCTree(QtWidgets.QTreeWidget):
self.header().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
self.setSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Expanding)
+ palette = QtGui.QPalette()
+ palette.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.Highlight,
+ palette.color(QtGui.QPalette.Active, QtGui.QPalette.Highlight))
+
+ # make inactive rows text some color as active; may be useful in the future
+ # palette.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.HighlightedText,
+ # palette.color(QtGui.QPalette.Active, QtGui.QPalette.HighlightedText))
+ self.setPalette(palette)
+
if extended_sel:
self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
+ self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
+
self.protected_column = protected_column
self.itemDoubleClicked.connect(self.on_double_click)
self.header().sectionDoubleClicked.connect(self.on_header_double_click)
@@ -210,6 +221,8 @@ class FCTree(QtWidgets.QTreeWidget):
if editable:
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
+ item.setFlags(item.flags() | QtCore.Qt.ItemIsSelectable)
+
for t in range(len(title)):
item.setText(t, title[t])
From e8adcb0c10e00557f88da6eb1ae2064a364b151c Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 29 Mar 2020 15:07:18 +0300
Subject: [PATCH 136/209] - fixed issues in the new database when adding the
tool in a Geometry object
---
FlatCAMCommon.py | 165 ++++++++++++++++++++++++++++++-----------------
README.md | 1 +
2 files changed, 108 insertions(+), 58 deletions(-)
diff --git a/FlatCAMCommon.py b/FlatCAMCommon.py
index f80106e3..c0cb24db 100644
--- a/FlatCAMCommon.py
+++ b/FlatCAMCommon.py
@@ -1632,7 +1632,7 @@ class ToolsDB2(QtWidgets.QWidget):
"The speed on XY plane used while cutting into material."))
self.frxy_entry = FCDoubleSpinner()
- self.frxy_entry.set_range(-9999.9999, 9999.9999)
+ self.frxy_entry.set_range(-999999.9999, 999999.9999)
self.frxy_entry.set_precision(self.decimals)
self.frxy_entry.setObjectName('gdb_frxy')
@@ -1646,7 +1646,7 @@ class ToolsDB2(QtWidgets.QWidget):
"The speed on Z plane."))
self.frz_entry = FCDoubleSpinner()
- self.frz_entry.set_range(-9999.9999, 9999.9999)
+ self.frz_entry.set_range(-999999.9999, 999999.9999)
self.frz_entry.set_precision(self.decimals)
self.frz_entry.setObjectName('gdb_frz')
@@ -1661,9 +1661,9 @@ class ToolsDB2(QtWidgets.QWidget):
"The speed of the spindle in RPM."))
self.spindle_entry = FCDoubleSpinner()
- self.spindle_entry.set_range(-9999.9999, 9999.9999)
+ self.spindle_entry.set_range(-999999.9999, 999999.9999)
self.spindle_entry.set_precision(self.decimals)
- self.frz_entry.setObjectName('gdb_spindle')
+ self.spindle_entry.setObjectName('gdb_spindle')
self.grid0.addWidget(self.spindle_label, 15, 0)
self.grid0.addWidget(self.spindle_entry, 15, 1)
@@ -1874,9 +1874,6 @@ class ToolsDB2(QtWidgets.QWidget):
)
self.milling_type_radio.setObjectName("gdb_n_milling_type")
- self.milling_type_label.setEnabled(False)
- self.milling_type_radio.setEnabled(False)
-
self.grid2.addWidget(self.milling_type_label, 14, 0)
self.grid2.addWidget(self.milling_type_radio, 14, 1)
@@ -2179,11 +2176,11 @@ class ToolsDB2(QtWidgets.QWidget):
"tools_ncc_offset_value": self.ncc_offset_spinner,
# Paint
- "paintoverlap": self.paintoverlap_entry,
- "paintmargin": self.paintmargin_entry,
- "paintmethod": self.paintmethod_combo,
- "pathconnect": self.pathconnect_cb,
- "paintcontour": self.paintcontour_cb,
+ "tools_paintoverlap": self.paintoverlap_entry,
+ "tools_paintmargin": self.paintmargin_entry,
+ "tools_paintmethod": self.paintmethod_combo,
+ "tools_pathconnect": self.pathconnect_cb,
+ "tools_paintcontour": self.paintcontour_cb,
}
self.name2option = {
@@ -2212,22 +2209,22 @@ class ToolsDB2(QtWidgets.QWidget):
"gdb_ecut_length": "extracut_length",
# NCC
- "gdb_n_operation": "nccoperation",
- "gdb_n_overlap": "nccoverlap",
- "gdb_n_margin": "nccmargin",
- "gdb_n_method": "nccmethod",
- "gdb_n_connect": "nccconnect",
- "gdb_n_contour": "ncccontour",
- "gdb_n_offset": "nccoffset",
- "gdb_n_offset_value": "nccoffset_value",
- "gdb_n_milling_type": "milling_type",
+ "gdb_n_operation": "tools_nccoperation",
+ "gdb_n_overlap": "tools_nccoverlap",
+ "gdb_n_margin": "tools_nccmargin",
+ "gdb_n_method": "tools_nccmethod",
+ "gdb_n_connect": "tools_nccconnect",
+ "gdb_n_contour": "tools_ncccontour",
+ "gdb_n_offset": "tools_ncc_offset_choice",
+ "gdb_n_offset_value": "tools_ncc_offset_value",
+ "gdb_n_milling_type": "tools_nccmilling_type",
# Paint
- 'gdb_p_overlap': "paintoverlap",
- 'gdb_p_margin': "paintmargin",
- 'gdb_p_method': "paintmethod",
- 'gdb_p_connect': "pathconnect",
- 'gdb_p_contour': "paintcontour",
+ 'gdb_p_overlap': "tools_paintoverlap",
+ 'gdb_p_margin': "tools_paintmargin",
+ 'gdb_p_method': "tools_paintmethod",
+ 'gdb_p_connect': "tools_pathconnect",
+ 'gdb_p_contour': "tools_paintcontour",
}
self.current_toolid = None
@@ -2376,7 +2373,7 @@ class ToolsDB2(QtWidgets.QWidget):
self.paint_box.setEnabled(True)
self.tree_widget.setCurrentItem(self.tree_widget.topLevelItem(0))
- self.tree_widget.setFocus()
+ # self.tree_widget.setFocus()
else:
# Disable GUI
@@ -2430,11 +2427,11 @@ class ToolsDB2(QtWidgets.QWidget):
"tools_ncc_offset_value": float(self.app.defaults["tools_ncc_offset_value"]),
# Paint
- "paintoverlap": float(self.app.defaults["tools_paintoverlap"]),
- "paintmargin": float(self.app.defaults["tools_paintmargin"]),
- "paintmethod": self.app.defaults["tools_paintmethod"],
- "pathconnect": self.app.defaults["tools_pathconnect"],
- "paintcontour": self.app.defaults["tools_paintcontour"],
+ "tools_paintoverlap": float(self.app.defaults["tools_paintoverlap"]),
+ "tools_paintmargin": float(self.app.defaults["tools_paintmargin"]),
+ "tools_paintmethod": self.app.defaults["tools_paintmethod"],
+ "tools_pathconnect": self.app.defaults["tools_pathconnect"],
+ "tools_paintcontour": self.app.defaults["tools_paintcontour"],
})
dict_elem = {}
@@ -2638,6 +2635,10 @@ class ToolsDB2(QtWidgets.QWidget):
if isinstance(wdg, FCCheckBox):
wdg.toggled.connect(self.update_storage)
+ # FCRadio
+ if isinstance(wdg, RadioSet):
+ wdg.activated_custom.connect(self.update_storage)
+
# SpinBox, DoubleSpinBox
if isinstance(wdg, FCSpinner) or isinstance(wdg, FCDoubleSpinner):
wdg.valueChanged.connect(self.update_storage)
@@ -2672,6 +2673,13 @@ class ToolsDB2(QtWidgets.QWidget):
except (TypeError, AttributeError):
pass
+ # FCRadio
+ if isinstance(wdg, RadioSet):
+ try:
+ wdg.activated_custom.disconnect(self.update_storage)
+ except (TypeError, AttributeError):
+ pass
+
# SpinBox, DoubleSpinBox
if isinstance(wdg, FCSpinner) or isinstance(wdg, FCDoubleSpinner):
try:
@@ -2688,68 +2696,109 @@ class ToolsDB2(QtWidgets.QWidget):
item.setData(1, QtCore.Qt.DisplayRole, val)
def update_storage(self):
-
+ """
+ Update the dictionary that is the storage of the tools 'database'
+ :return:
+ """
tool_id = str(self.current_toolid)
+
wdg = self.sender()
if wdg is None:
return
+
wdg_name = wdg.objectName()
+ try:
+ val = wdg.get_value()
+ except AttributeError:
+ return
+
if wdg_name == "gdb_name":
- self.db_tool_dict[tool_id]['name'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['name'] = val
elif wdg_name == "gdb_dia":
- self.db_tool_dict[tool_id]['tooldia'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['tooldia'] = val
elif wdg_name == "gdb_tool_offset":
- self.db_tool_dict[tool_id]['offset'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['offset'] = val
elif wdg_name == "gdb_custom_offset":
- self.db_tool_dict[tool_id]['offset_value'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['offset_value'] = val
elif wdg_name == "gdb_type":
- self.db_tool_dict[tool_id]['type'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['type'] = val
elif wdg_name == "gdb_shape":
- self.db_tool_dict[tool_id]['tool_type'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['tool_type'] = val
else:
if wdg_name == "gdb_cutz":
- self.db_tool_dict[tool_id]['data']['cutz'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['data']['cutz'] = val
elif wdg_name == "gdb_multidepth":
- self.db_tool_dict[tool_id]['data']['multidepth'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['data']['multidepth'] = val
elif wdg_name == "gdb_multidepth_entry":
- self.db_tool_dict[tool_id]['data']['depthperpass'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['data']['depthperpass'] = val
elif wdg_name == "gdb_travel":
- self.db_tool_dict[tool_id]['data']['travelz'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['data']['travelz'] = val
elif wdg_name == "gdb_frxy":
- self.db_tool_dict[tool_id]['data']['feedrate'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['data']['feedrate'] = val
elif wdg_name == "gdb_frz":
- self.db_tool_dict[tool_id]['data']['feedrate_z'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['data']['feedrate_z'] = val
elif wdg_name == "gdb_spindle":
- self.db_tool_dict[tool_id]['data']['spindlespeed'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['data']['spindlespeed'] = val
elif wdg_name == "gdb_dwell":
- self.db_tool_dict[tool_id]['data']['dwell'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['data']['dwell'] = val
elif wdg_name == "gdb_dwelltime":
- self.db_tool_dict[tool_id]['data']['dwelltime'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['data']['dwelltime'] = val
elif wdg_name == "gdb_vdia":
- self.db_tool_dict[tool_id]['data']['vtipdia'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['data']['vtipdia'] = val
elif wdg_name == "gdb_vangle":
- self.db_tool_dict[tool_id]['data']['vtipangle'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['data']['vtipangle'] = val
elif wdg_name == "gdb_frapids":
- self.db_tool_dict[tool_id]['data']['feedrate_rapid'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['data']['feedrate_rapid'] = val
elif wdg_name == "gdb_ecut":
- self.db_tool_dict[tool_id]['data']['extracut'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['data']['extracut'] = val
elif wdg_name == "gdb_ecut_length":
- self.db_tool_dict[tool_id]['data']['extracut_length'] = wdg.get_value()
+ self.db_tool_dict[tool_id]['data']['extracut_length'] = val
+
+ # NCC Tool
+ elif wdg_name == "gdb_n_operation":
+ self.db_tool_dict[tool_id]['data']['tools_nccoperation'] = val
+ elif wdg_name == "gdb_n_overlap":
+ self.db_tool_dict[tool_id]['data']['tools_nccoverlap'] = val
+ elif wdg_name == "gdb_n_margin":
+ self.db_tool_dict[tool_id]['data']['tools_nccmargin'] = val
+ elif wdg_name == "gdb_n_method":
+ self.db_tool_dict[tool_id]['data']['tools_nccmethod'] = val
+ elif wdg_name == "gdb_n_connect":
+ self.db_tool_dict[tool_id]['data']['tools_nccconnect'] = val
+ elif wdg_name == "gdb_n_contour":
+ self.db_tool_dict[tool_id]['data']['tools_ncccontour'] = val
+ elif wdg_name == "gdb_n_offset":
+ self.db_tool_dict[tool_id]['data']['tools_ncc_offset_choice'] = val
+ elif wdg_name == "gdb_n_offset_value":
+ self.db_tool_dict[tool_id]['data']['tools_ncc_offset_value'] = val
+ elif wdg_name == "gdb_n_milling_type":
+ self.db_tool_dict[tool_id]['data']['tools_nccmilling_type'] = val
+
+ # Paint Tool
+ elif wdg_name == "gdb_p_overlap":
+ self.db_tool_dict[tool_id]['data']['tools_paintoverlap'] = val
+ elif wdg_name == "gdb_p_margin":
+ self.db_tool_dict[tool_id]['data']['tools_paintmargin'] = val
+ elif wdg_name == "gdb_p_method":
+ self.db_tool_dict[tool_id]['data']['tools_paintmethod'] = val
+ elif wdg_name == "gdb_p_connect":
+ self.db_tool_dict[tool_id]['data']['tools_pathconnect'] = val
+ elif wdg_name == "gdb_p_contour":
+ self.db_tool_dict[tool_id]['data']['tools_paintcontour'] = val
self.callback_app()
def on_tool_requested_from_app(self):
- if not self.table_widget.selectionModel().selectedRows():
+ if not self.tree_widget.selectedItems():
self.app.inform.emit('[WARNING_NOTCL] %s...' % _("No Tool/row selected in the Tools Database table"))
return
- model_index_list = self.table_widget.selectionModel().selectedRows()
- for model_index in model_index_list:
- selected_row = model_index.row()
- tool_uid = selected_row + 1
+ for item in self.tree_widget.selectedItems():
+ tool_uid = item.data(0, QtCore.Qt.DisplayRole)
+
for key in self.db_tool_dict.keys():
if str(key) == str(tool_uid):
selected_tool = self.db_tool_dict[key]
diff --git a/README.md b/README.md
index bc228160..f02c95aa 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
29.03.2020
- modified the new database to accept data from NCC and Paint Tools
+- fixed issues in the new database when adding the tool in a Geometry object
28.03.2020
From d6adb99ec8eebd59f14eeb0488568ca9ede3fd07 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 29 Mar 2020 15:09:30 +0300
Subject: [PATCH 137/209] - fixed a bug in Geometry object that generated a
change of dictionary while iterating over it
---
FlatCAMObj.py | 4 ++--
README.md | 1 +
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 610df50d..a28e2c73 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -4658,9 +4658,9 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
try:
# set the form with data from the newly selected tool
- for tooluid_key, tooluid_value in self.tools.items():
+ for tooluid_key, tooluid_value in list(self.tools.items()):
if int(tooluid_key) == tooluid:
- for key, value in tooluid_value.items():
+ for key, value in list(tooluid_value.items()):
if key == 'data':
form_value_storage = tooluid_value['data']
self.update_form(form_value_storage)
diff --git a/README.md b/README.md
index f02c95aa..65d35d41 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- modified the new database to accept data from NCC and Paint Tools
- fixed issues in the new database when adding the tool in a Geometry object
+- fixed a bug in Geometry object that generated a change of dictionary while iterating over it
28.03.2020
From 4aeadde3dae9191254fec28ab6e020a14b0e693c Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 29 Mar 2020 17:48:46 +0300
Subject: [PATCH 138/209] - started to add the new database links in the NCC
and Paint Tools
---
FlatCAMApp.py | 29 +++++++++---
FlatCAMCommon.py | 1 +
README.md | 1 +
flatcamTools/ToolNCC.py | 99 ++++++++++++++++++++++++++++++++++++++-
flatcamTools/ToolPaint.py | 96 +++++++++++++++++++++++++++++++++++++
5 files changed, 217 insertions(+), 9 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 0306632b..aec238e4 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -8066,7 +8066,7 @@ class App(QtCore.QObject):
self.preferences_changed_flag = True
- def on_tools_database(self):
+ def on_tools_database(self, source='app'):
"""
Adds the Tools Database in a Tab in Plot Area
:return:
@@ -8076,12 +8076,27 @@ class App(QtCore.QObject):
# there can be only one instance of Tools Database at one time
return
- self.tools_db_tab = ToolsDB2(
- app=self,
- parent=self.ui,
- callback_on_edited=self.on_tools_db_edited,
- callback_on_tool_request=self.on_geometry_tool_add_from_db_executed
- )
+ if source == 'app':
+ self.tools_db_tab = ToolsDB2(
+ app=self,
+ parent=self.ui,
+ callback_on_edited=self.on_tools_db_edited,
+ callback_on_tool_request=self.on_geometry_tool_add_from_db_executed
+ )
+ elif source == 'ncc':
+ self.tools_db_tab = ToolsDB2(
+ app=self,
+ parent=self.ui,
+ callback_on_edited=self.on_tools_db_edited,
+ callback_on_tool_request=self.ncclear_tool.on_ncc_tool_add_from_db_executed
+ )
+ elif source == 'paint':
+ self.tools_db_tab = ToolsDB2(
+ app=self,
+ parent=self.ui,
+ callback_on_edited=self.on_tools_db_edited,
+ callback_on_tool_request=self.paint_tool.on_paint_tool_add_from_db_executed
+ )
# add the tab if it was closed
self.ui.plot_tab_area.addTab(self.tools_db_tab, _("Tools Database"))
diff --git a/FlatCAMCommon.py b/FlatCAMCommon.py
index c0cb24db..9d02b94e 100644
--- a/FlatCAMCommon.py
+++ b/FlatCAMCommon.py
@@ -2394,6 +2394,7 @@ class ToolsDB2(QtWidgets.QWidget):
default_data = {}
default_data.update({
+ "plot": True,
"cutz": float(self.app.defaults["geometry_cutz"]),
"multidepth": self.app.defaults["geometry_multidepth"],
"depthperpass": float(self.app.defaults["geometry_depthperpass"]),
diff --git a/README.md b/README.md
index 65d35d41..88c30ba0 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ CAD program, and create G-Code for Isolation routing.
- modified the new database to accept data from NCC and Paint Tools
- fixed issues in the new database when adding the tool in a Geometry object
- fixed a bug in Geometry object that generated a change of dictionary while iterating over it
+- started to add the new database links in the NCC and Paint Tools
28.03.2020
diff --git a/flatcamTools/ToolNCC.py b/flatcamTools/ToolNCC.py
index 630e87b5..af81fb95 100644
--- a/flatcamTools/ToolNCC.py
+++ b/flatcamTools/ToolNCC.py
@@ -737,8 +737,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.ncc_order_radio.activated_custom[str].connect(self.on_order_changed)
self.type_obj_radio.activated_custom.connect(self.on_type_obj_index_changed)
-
self.apply_param_to_all.clicked.connect(self.on_apply_param_to_all_clicked)
+ self.addtool_from_db_btn.clicked.connect(self.on_ncc_tool_add_from_db_clicked)
self.reset_button.clicked.connect(self.set_tool_ui)
@@ -1127,7 +1127,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
tool_type_item = FCComboBox()
tool_type_item.addItems(self.tool_type_item_options)
- # tool_type_item.setStyleSheet('background-color: rgb(255,255,255)')
+ # tool_type_item.setStyleSheet('background-color: rgb(255,255,255)')
idx = tool_type_item.findText(tooluid_value['tool_type'])
tool_type_item.setCurrentIndex(idx)
@@ -3965,3 +3965,98 @@ class NonCopperClear(FlatCAMTool, Gerber):
log.debug("NonCopperClear.generate_envelope() Error --> %s" % str(e))
return 'fail'
return geom
+
+ def on_ncc_tool_add_from_db_executed(self, tool):
+ """
+ Here add the tool from DB in the selected geometry object
+ :return:
+ """
+ tool_from_db = deepcopy(tool)
+
+ res = self.on_ncc_tool_from_db_inserted(tool=tool_from_db)
+
+ for idx in range(self.app.ui.plot_tab_area.count()):
+ if self.app.ui.plot_tab_area.tabText(idx) == _("Tools Database"):
+ wdg = self.app.ui.plot_tab_area.widget(idx)
+ wdg.deleteLater()
+ self.app.ui.plot_tab_area.removeTab(idx)
+
+ if res == 'fail':
+ return
+ self.app.inform.emit('[success] %s' % _("Tool from DB added in Tool Table."))
+
+ def on_ncc_tool_from_db_inserted(self, tool):
+ """
+ Called from the Tools DB object through a App method when adding a tool from Tools Database
+ :param tool: a dict with the tool data
+ :return: None
+ """
+
+ self.ui_disconnect()
+ self.units = self.app.defaults['units'].upper()
+
+ tooldia = float(tool['tooldia'])
+
+ # construct a list of all 'tooluid' in the self.tools
+ tool_uid_list = []
+ for tooluid_key in self.ncc_tools:
+ tool_uid_item = int(tooluid_key)
+ tool_uid_list.append(tool_uid_item)
+
+ # find maximum from the temp_uid, add 1 and this is the new 'tooluid'
+ if not tool_uid_list:
+ max_uid = 0
+ else:
+ max_uid = max(tool_uid_list)
+ tooluid = max_uid + 1
+
+ tooldia = float('%.*f' % (self.decimals, tooldia))
+
+ tool_dias = []
+ for k, v in self.ncc_tools.items():
+ for tool_v in v.keys():
+ if tool_v == 'tooldia':
+ tool_dias.append(float('%.*f' % (self.decimals, (v[tool_v]))))
+
+ if float('%.*f' % (self.decimals, tooldia)) in tool_dias:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Adding tool cancelled. Tool already in Tool Table."))
+ self.ui_connect()
+ return 'fail'
+
+ self.ncc_tools.update({
+ tooluid: {
+ 'tooldia': float('%.*f' % (self.decimals, tooldia)),
+ 'offset': 'Path',
+ 'offset_value': 0.0,
+ 'type': 'Iso',
+ 'tool_type': tool['tool_type'],
+ 'data': deepcopy(tool['data']),
+ 'solid_geometry': []
+ }
+ })
+ self.ncc_tools[tooluid]['data']['name'] = '_ncc'
+
+ self.app.inform.emit('[success] %s' % _("New tool added to Tool Table."))
+
+ self.ui_connect()
+ self.build_ui()
+
+ # if self.tools_table.rowCount() != 0:
+ # self.param_frame.setDisabled(False)
+
+ def on_ncc_tool_add_from_db_clicked(self):
+ """
+ Called when the user wants to add a new tool from Tools Database. It will create the Tools Database object
+ and display the Tools Database tab in the form needed for the Tool adding
+ :return: None
+ """
+
+ # if the Tools Database is already opened focus on it
+ for idx in range(self.app.ui.plot_tab_area.count()):
+ if self.app.ui.plot_tab_area.tabText(idx) == _("Tools Database"):
+ self.app.ui.plot_tab_area.setCurrentWidget(self.app.tools_db_tab)
+ break
+ self.app.on_tools_database(source='ncc')
+ self.app.tools_db_tab.buttons_frame.hide()
+ self.app.tools_db_tab.add_tool_from_db.show()
+ self.app.tools_db_tab.cancel_tool_from_db.show()
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 0881cbe2..0b930c4c 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -661,6 +661,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.type_obj_combo.activated_custom.connect(self.on_type_obj_changed)
self.apply_param_to_all.clicked.connect(self.on_apply_param_to_all_clicked)
+ self.addtool_from_db_btn.clicked.connect(self.on_paint_tool_add_from_db_clicked)
self.reset_button.clicked.connect(self.set_tool_ui)
@@ -4331,5 +4332,100 @@ class ToolPaint(FlatCAMTool, Gerber):
return bounds_rec(geometry)
+ def on_paint_tool_add_from_db_executed(self, tool):
+ """
+ Here add the tool from DB in the selected geometry object
+ :return:
+ """
+ tool_from_db = deepcopy(tool)
+
+ res = self.on_paint_tool_from_db_inserted(tool=tool_from_db)
+
+ for idx in range(self.app.ui.plot_tab_area.count()):
+ if self.app.ui.plot_tab_area.tabText(idx) == _("Tools Database"):
+ wdg = self.app.ui.plot_tab_area.widget(idx)
+ wdg.deleteLater()
+ self.app.ui.plot_tab_area.removeTab(idx)
+
+ if res == 'fail':
+ return
+ self.app.inform.emit('[success] %s' % _("Tool from DB added in Tool Table."))
+
+ def on_paint_tool_from_db_inserted(self, tool):
+ """
+ Called from the Tools DB object through a App method when adding a tool from Tools Database
+ :param tool: a dict with the tool data
+ :return: None
+ """
+
+ self.ui_disconnect()
+ self.units = self.app.defaults['units'].upper()
+
+ tooldia = float(tool['tooldia'])
+
+ # construct a list of all 'tooluid' in the self.tools
+ tool_uid_list = []
+ for tooluid_key in self.paint_tools:
+ tool_uid_item = int(tooluid_key)
+ tool_uid_list.append(tool_uid_item)
+
+ # find maximum from the temp_uid, add 1 and this is the new 'tooluid'
+ if not tool_uid_list:
+ max_uid = 0
+ else:
+ max_uid = max(tool_uid_list)
+ tooluid = max_uid + 1
+
+ tooldia = float('%.*f' % (self.decimals, tooldia))
+
+ tool_dias = []
+ for k, v in self.paint_tools.items():
+ for tool_v in v.keys():
+ if tool_v == 'tooldia':
+ tool_dias.append(float('%.*f' % (self.decimals, (v[tool_v]))))
+
+ if float('%.*f' % (self.decimals, tooldia)) in tool_dias:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Adding tool cancelled. Tool already in Tool Table."))
+ self.ui_connect()
+ return 'fail'
+
+ self.paint_tools.update({
+ tooluid: {
+ 'tooldia': float('%.*f' % (self.decimals, tooldia)),
+ 'offset': 'Path',
+ 'offset_value': 0.0,
+ 'type': 'Iso',
+ 'tool_type': tool['tool_type'],
+ 'data': deepcopy(tool['data']),
+ 'solid_geometry': []
+ }
+ })
+ self.paint_tools[tooluid]['data']['name'] = '_paint'
+
+ self.app.inform.emit('[success] %s' % _("New tool added to Tool Table."))
+
+ self.ui_connect()
+ self.build_ui()
+
+ # if self.tools_table.rowCount() != 0:
+ # self.param_frame.setDisabled(False)
+
+ def on_paint_tool_add_from_db_clicked(self):
+ """
+ Called when the user wants to add a new tool from Tools Database. It will create the Tools Database object
+ and display the Tools Database tab in the form needed for the Tool adding
+ :return: None
+ """
+
+ # if the Tools Database is already opened focus on it
+ for idx in range(self.app.ui.plot_tab_area.count()):
+ if self.app.ui.plot_tab_area.tabText(idx) == _("Tools Database"):
+ self.app.ui.plot_tab_area.setCurrentWidget(self.app.tools_db_tab)
+ break
+ self.app.on_tools_database(source='paint')
+ self.app.tools_db_tab.buttons_frame.hide()
+ self.app.tools_db_tab.add_tool_from_db.show()
+ self.app.tools_db_tab.cancel_tool_from_db.show()
+
def reset_fields(self):
self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
From a872a958cacb7e6e0c6dc21e747b5bec1e5a7952 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 29 Mar 2020 21:10:30 +0300
Subject: [PATCH 139/209] - in the new Tools DB added ability to double click
on the ID in the tree widget to execute adding a tool from DB
---
FlatCAMCommon.py | 10 ++++++++++
FlatCAMObj.py | 1 +
README.md | 1 +
flatcamTools/ToolNCC.py | 29 +++++++++++++++--------------
flatcamTools/ToolPaint.py | 1 +
5 files changed, 28 insertions(+), 14 deletions(-)
diff --git a/FlatCAMCommon.py b/FlatCAMCommon.py
index 9d02b94e..08142a9e 100644
--- a/FlatCAMCommon.py
+++ b/FlatCAMCommon.py
@@ -2229,6 +2229,9 @@ class ToolsDB2(QtWidgets.QWidget):
self.current_toolid = None
+ # variable to show if double clicking and item will trigger adding a tool from DB
+ self.ok_to_add = False
+
# ##############################################################################
# ######################## SIGNALS #############################################
# ##############################################################################
@@ -2247,6 +2250,8 @@ class ToolsDB2(QtWidgets.QWidget):
self.tree_widget.itemChanged.connect(self.on_list_item_edited)
self.tree_widget.customContextMenuRequested.connect(self.on_menu_request)
+ self.tree_widget.itemDoubleClicked.connect(self.on_item_double_clicked)
+
self.setup_db_ui()
def on_menu_request(self, pos):
@@ -2264,6 +2269,11 @@ class ToolsDB2(QtWidgets.QWidget):
# tree_item = self.tree_widget.itemAt(pos)
menu.exec(self.tree_widget.viewport().mapToGlobal(pos))
+ def on_item_double_clicked(self, item, column):
+ if column == 0 and self.ok_to_add is True:
+ self.ok_to_add = False
+ self.on_tool_requested_from_app()
+
def on_list_selection_change(self, current, previous):
# for idx in current.indexes():
# print(idx.data())
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index a28e2c73..a267856f 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -4774,6 +4774,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.app.ui.plot_tab_area.setCurrentWidget(self.app.tools_db_tab)
break
self.app.on_tools_database()
+ self.app.tools_db_tab.ok_to_add = True
self.app.tools_db_tab.buttons_frame.hide()
self.app.tools_db_tab.add_tool_from_db.show()
self.app.tools_db_tab.cancel_tool_from_db.show()
diff --git a/README.md b/README.md
index 88c30ba0..ec435ee2 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ CAD program, and create G-Code for Isolation routing.
- fixed issues in the new database when adding the tool in a Geometry object
- fixed a bug in Geometry object that generated a change of dictionary while iterating over it
- started to add the new database links in the NCC and Paint Tools
+- in the new Tools DB added ability to double click on the ID in the tree widget to execute adding a tool from DB
28.03.2020
diff --git a/flatcamTools/ToolNCC.py b/flatcamTools/ToolNCC.py
index af81fb95..11be5cbe 100644
--- a/flatcamTools/ToolNCC.py
+++ b/flatcamTools/ToolNCC.py
@@ -3911,20 +3911,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
return ret_val
- def reset_fields(self):
- self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
-
- def reset_usage(self):
- self.obj_name = ""
- self.ncc_obj = None
- self.bound_obj = None
-
- self.first_click = False
- self.cursor_pos = None
- self.mouse_is_dragging = False
-
- self.sel_rect = []
-
@staticmethod
def poly2rings(poly):
return [poly.exterior] + [interior for interior in poly.interiors]
@@ -4057,6 +4043,21 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.app.ui.plot_tab_area.setCurrentWidget(self.app.tools_db_tab)
break
self.app.on_tools_database(source='ncc')
+ self.app.tools_db_tab.ok_to_add = True
self.app.tools_db_tab.buttons_frame.hide()
self.app.tools_db_tab.add_tool_from_db.show()
self.app.tools_db_tab.cancel_tool_from_db.show()
+
+ def reset_fields(self):
+ self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
+
+ def reset_usage(self):
+ self.obj_name = ""
+ self.ncc_obj = None
+ self.bound_obj = None
+
+ self.first_click = False
+ self.cursor_pos = None
+ self.mouse_is_dragging = False
+
+ self.sel_rect = []
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 0b930c4c..3f7c1e48 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -4423,6 +4423,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.app.ui.plot_tab_area.setCurrentWidget(self.app.tools_db_tab)
break
self.app.on_tools_database(source='paint')
+ self.app.tools_db_tab.ok_to_add = True
self.app.tools_db_tab.buttons_frame.hide()
self.app.tools_db_tab.add_tool_from_db.show()
self.app.tools_db_tab.cancel_tool_from_db.show()
From 70dd9aecaea4627a6d7fabf1bd5f428e69ac56e4 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 29 Mar 2020 21:39:20 +0300
Subject: [PATCH 140/209] - working in updating NCC Tool
---
README.md | 1 +
flatcamTools/ToolNCC.py | 86 ++++++++++++++++++++---------------------
2 files changed, 44 insertions(+), 43 deletions(-)
diff --git a/README.md b/README.md
index ec435ee2..c7a7f84f 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,7 @@ CAD program, and create G-Code for Isolation routing.
- fixed a bug in Geometry object that generated a change of dictionary while iterating over it
- started to add the new database links in the NCC and Paint Tools
- in the new Tools DB added ability to double click on the ID in the tree widget to execute adding a tool from DB
+- working in updating NCC Tool
28.03.2020
diff --git a/flatcamTools/ToolNCC.py b/flatcamTools/ToolNCC.py
index 11be5cbe..6ace005f 100644
--- a/flatcamTools/ToolNCC.py
+++ b/flatcamTools/ToolNCC.py
@@ -691,27 +691,27 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.tooldia = None
self.form_fields = {
- "nccoperation": self.op_radio,
- "nccoverlap": self.ncc_overlap_entry,
- "nccmargin": self.ncc_margin_entry,
- "nccmethod": self.ncc_method_combo,
- "nccconnect": self.ncc_connect_cb,
- "ncccontour": self.ncc_contour_cb,
- "nccoffset": self.ncc_choice_offset_cb,
- "nccoffset_value": self.ncc_offset_spinner,
- "milling_type": self.milling_type_radio
+ "tools_nccoperation": self.op_radio,
+ "tools_nccoverlap": self.ncc_overlap_entry,
+ "tools_nccmargin": self.ncc_margin_entry,
+ "tools_nccmethod": self.ncc_method_combo,
+ "tools_nccconnect": self.ncc_connect_cb,
+ "tools_ncccontour": self.ncc_contour_cb,
+ "tools_ncc_offset_choice": self.ncc_choice_offset_cb,
+ "tools_ncc_offset_value": self.ncc_offset_spinner,
+ "tools_nccmilling_type": self.milling_type_radio
}
self.name2option = {
- "n_operation": "nccoperation",
- "n_overlap": "nccoverlap",
- "n_margin": "nccmargin",
- "n_method": "nccmethod",
- "n_connect": "nccconnect",
- "n_contour": "ncccontour",
- "n_offset": "nccoffset",
- "n_offset_value": "nccoffset_value",
- "n_milling_type": "milling_type",
+ "n_operation": "tools_nccoperation",
+ "n_overlap": "tools_nccoverlap",
+ "n_margin": "tools_nccmargin",
+ "n_method": "tools_nccmethod",
+ "n_connect": "tools_nccconnect",
+ "n_contour": "tools_ncccontour",
+ "n_offset": "tools_ncc_offset_choice",
+ "n_offset_value": "tools_ncc_offset_value",
+ "n_milling_type": "tools_nccmilling_type",
}
self.old_tool_dia = None
@@ -761,7 +761,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
current_row = self.tools_table.currentRow()
try:
current_uid = int(self.tools_table.item(current_row, 3).text())
- self.ncc_tools[current_uid]['data']['nccoperation'] = val
+ self.ncc_tools[current_uid]['data']['tools_nccoperation'] = val
except AttributeError:
return
@@ -1036,17 +1036,17 @@ class NonCopperClear(FlatCAMTool, Gerber):
"toolchangexy": self.app.defaults["geometry_toolchangexy"],
"startz": self.app.defaults["geometry_startz"],
- "nccoperation": self.app.defaults["tools_nccoperation"],
- "nccmargin": self.app.defaults["tools_nccmargin"],
- "nccmethod": self.app.defaults["tools_nccmethod"],
- "nccconnect": self.app.defaults["tools_nccconnect"],
- "ncccontour": self.app.defaults["tools_ncccontour"],
- "nccoverlap": self.app.defaults["tools_nccoverlap"],
+ "tools_nccoperation": self.app.defaults["tools_nccoperation"],
+ "tools_nccmargin": self.app.defaults["tools_nccmargin"],
+ "tools_nccmethod": self.app.defaults["tools_nccmethod"],
+ "tools_nccconnect": self.app.defaults["tools_nccconnect"],
+ "tools_ncccontour": self.app.defaults["tools_ncccontour"],
+ "tools_nccoverlap": self.app.defaults["tools_nccoverlap"],
"nccrest": self.app.defaults["tools_nccrest"],
"nccref": self.app.defaults["tools_nccref"],
- "nccoffset": self.app.defaults["tools_ncc_offset_choice"],
- "nccoffset_value": self.app.defaults["tools_ncc_offset_value"],
-
+ "tools_ncc_offset_choice": self.app.defaults["tools_ncc_offset_choice"],
+ "tools_ncc_offset_value": self.app.defaults["tools_ncc_offset_value"],
+ "tools_nccmilling_type": self.app.defaults["tools_nccmilling_type"],
}
try:
@@ -2256,7 +2256,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
# if self.tools_table.cellWidget(row, 1).currentText() == 'clear_op':
# sorted_tools.append(float(self.tools_table.item(row, 1).text()))
for tooluid in self.ncc_tools:
- if self.ncc_tools[tooluid]['data']['nccoperation'] == 'clear':
+ if self.ncc_tools[tooluid]['data']['tools_nccoperation'] == 'clear':
sorted_tools.append(self.ncc_tools[tooluid]['tooldia'])
# ########################################################################################################
@@ -2335,13 +2335,13 @@ class NonCopperClear(FlatCAMTool, Gerber):
tooluid = int(k)
break
- ncc_overlap = float(self.ncc_tools[tooluid]["data"]["nccoverlap"]) / 100.0
- ncc_margin = float(self.ncc_tools[tooluid]["data"]["nccmargin"])
- ncc_method = self.ncc_tools[tooluid]["data"]["nccmethod"]
- ncc_connect = self.ncc_tools[tooluid]["data"]["nccconnect"]
- ncc_contour = self.ncc_tools[tooluid]["data"]["ncccontour"]
- has_offset = self.ncc_tools[tooluid]["data"]["nccoffset"]
- ncc_offset = float(self.ncc_tools[tooluid]["data"]["nccoffset_value"])
+ ncc_overlap = float(self.ncc_tools[tooluid]["data"]["tools_nccoverlap"]) / 100.0
+ ncc_margin = float(self.ncc_tools[tooluid]["data"]["tools_nccmargin"])
+ ncc_method = self.ncc_tools[tooluid]["data"]["tools_nccmethod"]
+ ncc_connect = self.ncc_tools[tooluid]["data"]["tools_nccconnect"]
+ ncc_contour = self.ncc_tools[tooluid]["data"]["tools_ncccontour"]
+ has_offset = self.ncc_tools[tooluid]["data"]["tools_ncc_offset_choice"]
+ ncc_offset = float(self.ncc_tools[tooluid]["data"]["tools_ncc_offset_value"])
cleared_geo[:] = []
@@ -2620,13 +2620,13 @@ class NonCopperClear(FlatCAMTool, Gerber):
tooluid = int(k)
break
- ncc_overlap = float(self.ncc_tools[tooluid]["data"]["nccoverlap"]) / 100.0
- ncc_margin = float(self.ncc_tools[tooluid]["data"]["nccmargin"])
- ncc_method = self.ncc_tools[tooluid]["data"]["nccmethod"]
- ncc_connect = self.ncc_tools[tooluid]["data"]["nccconnect"]
- ncc_contour = self.ncc_tools[tooluid]["data"]["ncccontour"]
- has_offset = self.ncc_tools[tooluid]["data"]["nccoffset"]
- ncc_offset = float(self.ncc_tools[tooluid]["data"]["nccoffset_value"])
+ ncc_overlap = float(self.ncc_tools[tooluid]["data"]["tools_nccoverlap"]) / 100.0
+ ncc_margin = float(self.ncc_tools[tooluid]["data"]["tools_nccmargin"])
+ ncc_method = self.ncc_tools[tooluid]["data"]["tools_nccmethod"]
+ ncc_connect = self.ncc_tools[tooluid]["data"]["tools_nccconnect"]
+ ncc_contour = self.ncc_tools[tooluid]["data"]["tools_ncccontour"]
+ has_offset = self.ncc_tools[tooluid]["data"]["tools_ncc_offset_choice"]
+ ncc_offset = float(self.ncc_tools[tooluid]["data"]["tools_ncc_offset_value"])
tool_used = tool - 1e-12
cleared_geo[:] = []
From 8a2f5fed0568b865d3abbe1670d15ad7f9e17734 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 30 Mar 2020 23:12:27 +0300
Subject: [PATCH 141/209] - working to update the Paint Tool
---
README.md | 4 +
camlib.py | 18 +-
flatcamTools/ToolNCC.py | 14 +-
flatcamTools/ToolPaint.py | 1649 +++++++++++++++----------------------
4 files changed, 700 insertions(+), 985 deletions(-)
diff --git a/README.md b/README.md
index c7a7f84f..01845106 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+30.03.2020
+
+- working to update the Paint Tool
+
29.03.2020
- modified the new database to accept data from NCC and Paint Tools
diff --git a/camlib.py b/camlib.py
index 96587a0e..2770021c 100644
--- a/camlib.py
+++ b/camlib.py
@@ -1470,8 +1470,13 @@ class Geometry(object):
line = LineString([(left, y), (right, y)])
line = line.intersection(margin_poly)
- for ll in line:
- lines_trimmed.append(ll)
+ try:
+ for ll in line:
+ lines_trimmed.append(ll)
+ if prog_plot:
+ self.plot_temp_shapes(ll)
+ except TypeError:
+ lines_trimmed.append(line)
if prog_plot:
self.plot_temp_shapes(line)
except Exception as e:
@@ -1502,8 +1507,13 @@ class Geometry(object):
line = LineString([(x, top), (x, bot)])
line = line.intersection(margin_poly)
- for ll in line:
- lines_trimmed.append(ll)
+ try:
+ for ll in line:
+ lines_trimmed.append(ll)
+ if prog_plot:
+ self.plot_temp_shapes(ll)
+ except TypeError:
+ lines_trimmed.append(line)
if prog_plot:
self.plot_temp_shapes(line)
except Exception as e:
diff --git a/flatcamTools/ToolNCC.py b/flatcamTools/ToolNCC.py
index 6ace005f..e2e5adfd 100644
--- a/flatcamTools/ToolNCC.py
+++ b/flatcamTools/ToolNCC.py
@@ -128,6 +128,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.tools_box.addWidget(self.tools_table)
self.tools_table.setColumnCount(4)
+ # 3rd column is reserved (and hidden) for the tool ID
self.tools_table.setHorizontalHeaderLabels(['#', _('Diameter'), _('TT'), ''])
self.tools_table.setColumnHidden(3, True)
self.tools_table.setSortingEnabled(False)
@@ -3971,6 +3972,13 @@ class NonCopperClear(FlatCAMTool, Gerber):
return
self.app.inform.emit('[success] %s' % _("Tool from DB added in Tool Table."))
+ # select last tool added
+ toolid = res
+ for row in range(self.tools_table.rowCount()):
+ if int(self.tools_table.item(row, 3).text()) == toolid:
+ self.tools_table.selectRow(row)
+ self.on_row_selection_change()
+
def on_ncc_tool_from_db_inserted(self, tool):
"""
Called from the Tools DB object through a App method when adding a tool from Tools Database
@@ -4012,9 +4020,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.ncc_tools.update({
tooluid: {
'tooldia': float('%.*f' % (self.decimals, tooldia)),
- 'offset': 'Path',
- 'offset_value': 0.0,
- 'type': 'Iso',
+ 'offset': tool['offset'],
+ 'offset_value': tool['offset_value'],
+ 'type': tool['type'],
'tool_type': tool['tool_type'],
'data': deepcopy(tool['data']),
'solid_geometry': []
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 3f7c1e48..51e6c9e3 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -120,6 +120,7 @@ class ToolPaint(FlatCAMTool, Gerber):
)
self.tools_table = FCTable()
+ # self.tools_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
grid0.addWidget(self.tools_table_label, 6, 0, 1, 2)
grid0.addWidget(self.tools_table, 7, 0, 1, 2)
@@ -614,19 +615,19 @@ class ToolPaint(FlatCAMTool, Gerber):
self.tool_type_item_options = ["C1", "C2", "C3", "C4", "B", "V"]
self.form_fields = {
- "paintoverlap": self.paintoverlap_entry,
- "paintmargin": self.paintmargin_entry,
- "paintmethod": self.paintmethod_combo,
- "pathconnect": self.pathconnect_cb,
- "paintcontour": self.paintcontour_cb,
+ "tools_paintoverlap": self.paintoverlap_entry,
+ "tools_paintmargin": self.paintmargin_entry,
+ "tools_paintmethod": self.paintmethod_combo,
+ "tools_pathconnect": self.pathconnect_cb,
+ "tools_paintcontour": self.paintcontour_cb,
}
self.name2option = {
- 'p_overlap': "paintoverlap",
- 'p_margin': "paintmargin",
- 'p_method': "paintmethod",
- 'p_connect': "pathconnect",
- 'p_contour': "paintcontour",
+ 'p_overlap': "tools_paintoverlap",
+ 'p_margin': "tools_paintmargin",
+ 'p_method': "tools_paintmethod",
+ 'p_connect': "tools_pathconnect",
+ 'p_contour': "tools_paintcontour",
}
self.old_tool_dia = None
@@ -737,10 +738,13 @@ class ToolPaint(FlatCAMTool, Gerber):
def on_row_selection_change(self):
self.blockSignals(True)
- sel_rows = [it.row() for it in self.tools_table.selectedItems()]
- # sel_rows = sorted(set(index.row() for index in self.tools_table.selectedIndexes()))
-
- if not sel_rows:
+ sel_rows = set()
+ table_items = self.tools_table.selectedItems()
+ if table_items:
+ for it in table_items:
+ sel_rows.add(it.row())
+ # sel_rows = sorted(set(index.row() for index in self.tools_table.selectedIndexes()))
+ else:
sel_rows = [0]
for current_row in sel_rows:
@@ -765,10 +769,7 @@ class ToolPaint(FlatCAMTool, Gerber):
# set the form with data from the newly selected tool
for tooluid_key, tooluid_value in list(self.paint_tools.items()):
if int(tooluid_key) == tooluid:
- for key, value in tooluid_value.items():
- if key == 'data':
- form_value_storage = tooluid_value[key]
- self.storage_to_form(form_value_storage)
+ self.storage_to_form(tooluid_value['data'])
except Exception as e:
log.debug("ToolPaint ---> update_ui() " + str(e))
else:
@@ -779,13 +780,11 @@ class ToolPaint(FlatCAMTool, Gerber):
self.blockSignals(False)
def storage_to_form(self, dict_storage):
- for form_key in self.form_fields:
- for storage_key in dict_storage:
- if form_key == storage_key:
- try:
- self.form_fields[form_key].set_value(dict_storage[form_key])
- except Exception:
- pass
+ for k in self.form_fields:
+ try:
+ self.form_fields[k].set_value(dict_storage[k])
+ except Exception as err:
+ log.debug("ToolPaint.storage.form() --> %s" % str(err))
def form_to_storage(self):
if self.tools_table.rowCount() == 0:
@@ -1009,13 +1008,13 @@ class ToolPaint(FlatCAMTool, Gerber):
"startz": self.app.defaults["geometry_startz"],
"tooldia": self.app.defaults["tools_painttooldia"],
- "paintmargin": self.app.defaults["tools_paintmargin"],
- "paintmethod": self.app.defaults["tools_paintmethod"],
- "selectmethod": self.app.defaults["tools_selectmethod"],
- "pathconnect": self.app.defaults["tools_pathconnect"],
- "paintcontour": self.app.defaults["tools_paintcontour"],
- "paintoverlap": self.app.defaults["tools_paintoverlap"],
- "paintrest": self.app.defaults["tools_paintrest"],
+ "tools_paintmargin": self.app.defaults["tools_paintmargin"],
+ "tools_paintmethod": self.app.defaults["tools_paintmethod"],
+ "tools_selectmethod": self.app.defaults["tools_selectmethod"],
+ "tools_pathconnect": self.app.defaults["tools_pathconnect"],
+ "tools_paintcontour": self.app.defaults["tools_paintcontour"],
+ "tools_paintoverlap": self.app.defaults["tools_paintoverlap"],
+ "tools_paintrest": self.app.defaults["tools_paintrest"],
})
# ## Init the GUI interface
@@ -1054,7 +1053,7 @@ class ToolPaint(FlatCAMTool, Gerber):
log.error("At least one tool diameter needed. Verify in Edit -> Preferences -> TOOLS -> NCC Tools.")
self.build_ui()
# if the Paint Method is "Single" disable the tool table context menu
- if self.default_data["selectmethod"] == "single":
+ if self.default_data["tools_selectmethod"] == "single":
self.tools_table.setContextMenuPolicy(Qt.NoContextMenu)
return
@@ -1064,7 +1063,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.on_tool_add(dia, muted=True)
# if the Paint Method is "Single" disable the tool table context menu
- if self.default_data["selectmethod"] == "single":
+ if self.default_data["tools_selectmethod"] == "single":
self.tools_table.setContextMenuPolicy(Qt.NoContextMenu)
def build_ui(self):
@@ -1151,6 +1150,16 @@ class ToolPaint(FlatCAMTool, Gerber):
self.ui_connect()
+ # set the text on tool_data_label after loading the object
+ sel_rows = set()
+ sel_items = self.tools_table.selectedItems()
+ for it in sel_items:
+ sel_rows.add(it.row())
+ if len(sel_rows) > 1:
+ self.tool_data_label.setText(
+ "%s: %s" % (_('Parameters for'), _("Multiple Tools"))
+ )
+
def on_tool_add(self, dia=None, muted=None):
self.blockSignals(True)
@@ -1362,15 +1371,6 @@ class ToolPaint(FlatCAMTool, Gerber):
self.app.report_usage("on_paint_button_click")
# self.app.call_source = 'paint'
- # #####################################################
- # ######### Reading Parameters ########################
- # #####################################################
- self.app.inform.emit(_("Paint Tool. Reading parameters."))
-
- self.overlap = float(self.paintoverlap_entry.get_value()) / 100.0
-
- self.connect = self.pathconnect_cb.get_value()
- self.contour = self.paintcontour_cb.get_value()
self.select_method = self.selectmethod_combo.get_value()
self.obj_name = self.obj_combo.currentText()
@@ -1396,8 +1396,9 @@ class ToolPaint(FlatCAMTool, Gerber):
# use the selected tools in the tool table; get diameters
self.tooldia_list = []
- if self.tools_table.selectedItems():
- for x in self.tools_table.selectedItems():
+ table_items = self.tools_table.selectedItems()
+ if table_items:
+ for x in table_items:
try:
self.tooldia = float(self.tools_table.item(x.row(), 1).text())
except ValueError:
@@ -1415,10 +1416,7 @@ class ToolPaint(FlatCAMTool, Gerber):
if self.select_method == _("All Polygons"):
self.paint_poly_all(self.paint_obj,
tooldia=self.tooldia_list,
- outname=self.o_name,
- overlap=self.overlap,
- connect=self.connect,
- contour=self.contour)
+ outname=self.o_name)
elif self.select_method == _("Polygon Selection"):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click on a polygon to paint it."))
@@ -1468,10 +1466,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.paint_poly_ref(obj=self.paint_obj,
sel_obj=self.bound_obj,
tooldia=self.tooldia_list,
- overlap=self.overlap,
- outname=self.o_name,
- connect=self.connect,
- contour=self.contour)
+ outname=self.o_name)
# To be called after clicking on the plot.
def on_single_poly_mouse_release(self, event):
@@ -1553,10 +1548,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.paint_poly(self.paint_obj,
inside_pt=(curr_pos[0], curr_pos[1]),
poly_list=poly_list,
- tooldia=self.tooldia_list,
- overlap=self.overlap,
- connect=self.connect,
- contour=self.contour)
+ tooldia=self.tooldia_list)
self.poly_dict.clear()
else:
self.app.inform.emit('[ERROR_NOTCL] %s' % _("List of single polygons is empty. Aborting."))
@@ -1682,10 +1674,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.paint_poly_area(obj=self.paint_obj,
tooldia=self.tooldia_list,
sel_obj=self.sel_rect,
- outname=self.o_name,
- overlap=self.overlap,
- connect=self.connect,
- contour=self.contour)
+ outname=self.o_name)
# called on mouse move
def on_mouse_move(self, event):
@@ -1823,8 +1812,249 @@ class ToolPaint(FlatCAMTool, Gerber):
self.delete_moving_selection_shape()
self.delete_tool_selection_shape()
- def paint_poly(self, obj, inside_pt=None, poly_list=None, tooldia=None, overlap=None, order=None,
- margin=None, method=None, outname=None, connect=None, contour=None, tools_storage=None,
+ def paint_polygon_worker(self, polyg, tooldiameter, paint_method, over, conn, cont, prog_plot, obj):
+
+ cpoly = None
+
+ if paint_method == _("Standard"):
+ try:
+ # Type(cp) == FlatCAMRTreeStorage | None
+ cpoly = self.clear_polygon(polyg,
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults["geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+ except FlatCAMApp.GracefulException:
+ return "fail"
+ except Exception as ee:
+ log.debug("ToolPaint.paint_polygon_worker() Standard --> %s" % str(ee))
+ elif paint_method == _("Seed"):
+ try:
+ # Type(cp) == FlatCAMRTreeStorage | None
+ cpoly = self.clear_polygon2(polyg,
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults["geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+ except FlatCAMApp.GracefulException:
+ return "fail"
+ except Exception as ee:
+ log.debug("ToolPaint.paint_polygon_worker() Seed --> %s" % str(ee))
+ elif paint_method == _("Lines"):
+ try:
+ # Type(cp) == FlatCAMRTreeStorage | None
+ cpoly = self.clear_polygon3(polyg,
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults["geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+ except FlatCAMApp.GracefulException:
+ return "fail"
+ except Exception as ee:
+ log.debug("ToolPaint.paint_polygon_worker() Lines --> %s" % str(ee))
+ elif paint_method == _("Laser_lines"):
+ try:
+ # line = None
+ # aperture_size = None
+
+ # the key is the aperture type and the val is a list of geo elements
+ flash_el_dict = {}
+ # the key is the aperture size, the val is a list of geo elements
+ traces_el_dict = {}
+
+ # find the flashes and the lines that are in the selected polygon and store them separately
+ for apid, apval in obj.apertures.items():
+ for geo_el in apval['geometry']:
+ if apval["size"] == 0.0:
+ if apval["size"] in traces_el_dict:
+ traces_el_dict[apval["size"]].append(geo_el)
+ else:
+ traces_el_dict[apval["size"]] = [geo_el]
+
+ if 'follow' in geo_el and geo_el['follow'].within(polyg):
+ if isinstance(geo_el['follow'], Point):
+ if apval["type"] == 'C':
+ if 'C' in flash_el_dict:
+ flash_el_dict['C'].append(geo_el)
+ else:
+ flash_el_dict['C'] = [geo_el]
+ elif apval["type"] == 'O':
+ if 'O' in flash_el_dict:
+ flash_el_dict['O'].append(geo_el)
+ else:
+ flash_el_dict['O'] = [geo_el]
+ elif apval["type"] == 'R':
+ if 'R' in flash_el_dict:
+ flash_el_dict['R'].append(geo_el)
+ else:
+ flash_el_dict['R'] = [geo_el]
+ else:
+ aperture_size = apval['size']
+
+ if aperture_size in traces_el_dict:
+ traces_el_dict[aperture_size].append(geo_el)
+ else:
+ traces_el_dict[aperture_size] = [geo_el]
+
+ cpoly = FlatCAMRTreeStorage()
+ pads_lines_list = []
+
+ # process the flashes found in the selected polygon with the 'lines' method for rectangular
+ # flashes and with _("Seed") for oblong and circular flashes
+ # and pads (flahes) need the contour therefore I override the GUI settings with always True
+ for ap_type in flash_el_dict:
+ for elem in flash_el_dict[ap_type]:
+ if 'solid' in elem:
+ if ap_type == 'C':
+ f_o = self.clear_polygon2(elem['solid'],
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ elif ap_type == 'O':
+ f_o = self.clear_polygon2(elem['solid'],
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ elif ap_type == 'R':
+ f_o = self.clear_polygon3(elem['solid'],
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=True,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ pads_lines_list += [p for p in f_o.get_objects() if p]
+
+ # add the lines from pads to the storage
+ try:
+ for lin in pads_lines_list:
+ if lin:
+ cpoly.insert(lin)
+ except TypeError:
+ cpoly.insert(pads_lines_list)
+
+ copper_lines_list = []
+ # process the traces found in the selected polygon using the 'laser_lines' method,
+ # method which will follow the 'follow' line therefore use the longer path possible for the
+ # laser, therefore the acceleration will play a smaller factor
+ for aperture_size in traces_el_dict:
+ for elem in traces_el_dict[aperture_size]:
+ line = elem['follow']
+ if line:
+ t_o = self.fill_with_lines(line, aperture_size,
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults[
+ "geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ copper_lines_list += [p for p in t_o.get_objects() if p]
+
+ # add the lines from copper features to storage but first try to make as few lines as possible
+ # by trying to fuse them
+ lines_union = linemerge(unary_union(copper_lines_list))
+ try:
+ for lin in lines_union:
+ if lin:
+ cpoly.insert(lin)
+ except TypeError:
+ cpoly.insert(lines_union)
+ # # determine the Gerber follow line
+ # for apid, apval in obj.apertures.items():
+ # for geo_el in apval['geometry']:
+ # if 'solid' in geo_el:
+ # if Point(inside_pt).within(geo_el['solid']):
+ # if not isinstance(geo_el['follow'], Point):
+ # line = geo_el['follow']
+ #
+ # if apval['type'] == 'C':
+ # aperture_size = apval['size']
+ # else:
+ # if apval['width'] > apval['height']:
+ # aperture_size = apval['height']
+ # else:
+ # aperture_size = apval['width']
+ #
+ # if line:
+ # cpoly = self.fill_with_lines(line, aperture_size,
+ # tooldia=tooldiameter,
+ # steps_per_circle=self.app.defaults["geometry_circle_steps"],
+ # overlap=over,
+ # contour=cont,
+ # connect=conn,
+ # prog_plot=prog_plot)
+ except FlatCAMApp.GracefulException:
+ return "fail"
+ except Exception as ee:
+ log.debug("ToolPaint.paint_polygon_worker() Laser Lines --> %s" % str(ee))
+ elif paint_method == _("Combo"):
+ try:
+ self.app.inform.emit(_("Painting polygon with method: lines."))
+ cpoly = self.clear_polygon3(polyg,
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults["geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+
+ if cpoly and cpoly.objects:
+ pass
+ else:
+ self.app.inform.emit(_("Failed. Painting polygon with method: seed."))
+ cpoly = self.clear_polygon2(polyg,
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults["geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+ if cpoly and cpoly.objects:
+ pass
+ else:
+ self.app.inform.emit(_("Failed. Painting polygon with method: standard."))
+ cpoly = self.clear_polygon(polyg,
+ tooldia=tooldiameter,
+ steps_per_circle=self.app.defaults["geometry_circle_steps"],
+ overlap=over,
+ contour=cont,
+ connect=conn,
+ prog_plot=prog_plot)
+ except FlatCAMApp.GracefulException:
+ return "fail"
+ except Exception as ee:
+ log.debug("ToolPaint.paint_polygon_worker() Combo --> %s" % str(ee))
+
+ if cpoly and cpoly.objects:
+ return cpoly
+ else:
+ self.app.inform.emit('[ERROR_NOTCL] %s' % _('Geometry could not be painted completely'))
+ return None
+
+ def paint_poly(self, obj, inside_pt=None, poly_list=None, tooldia=None, order=None,
+ method=None, outname=None, tools_storage=None,
plot=True, run_threaded=True):
"""
Paints a polygon selected by clicking on its interior or by having a point coordinates given
@@ -1837,12 +2067,8 @@ class ToolPaint(FlatCAMTool, Gerber):
:param obj: painted object
:param inside_pt: [x, y]
:param tooldia: Diameter of the painting tool
- :param overlap: Overlap of the tool between passes.
:param order: if the tools are ordered and how
- :param margin: a border around painting area
:param outname: Name of the resulting Geometry Object.
- :param connect: Connect lines to avoid tool lifts.
- :param contour: Paint around the edges.
:param method: choice out of _("Seed"), 'normal', 'lines'
:param tools_storage: whether to use the current tools_storage self.paints_tools or a different one.
Usage of the different one is related to when this function is called from a TcL command.
@@ -1850,27 +2076,29 @@ class ToolPaint(FlatCAMTool, Gerber):
"""
if isinstance(obj, FlatCAMGerber):
+ # I don't do anything here, like buffering when the Gerber is loaded without buffering????!!!!
if self.app.defaults["gerber_buffering"] == 'no':
self.app.inform.emit('%s %s %s' %
(_("Paint Tool."), _("Normal painting polygon task started."),
_("Buffering geometry...")))
else:
self.app.inform.emit('%s %s' % (_("Paint Tool."), _("Normal painting polygon task started.")))
- else:
- self.app.inform.emit('%s %s' % (_("Paint Tool."), _("Normal painting polygon task started.")))
- if isinstance(obj, FlatCAMGerber):
if self.app.defaults["tools_paint_plotting"] == 'progressive':
if isinstance(obj.solid_geometry, list):
obj.solid_geometry = MultiPolygon(obj.solid_geometry).buffer(0)
else:
obj.solid_geometry = obj.solid_geometry.buffer(0)
+ else:
+ self.app.inform.emit('%s %s' % (_("Paint Tool."), _("Normal painting polygon task started.")))
polygon_list = None
if inside_pt and poly_list is None:
polygon_list = [self.find_polygon(point=inside_pt, geoset=obj.solid_geometry)]
elif (inside_pt is None and poly_list) or (inside_pt and poly_list):
polygon_list = poly_list
+ else:
+ return
# No polygon?
if polygon_list is None:
@@ -1879,14 +2107,10 @@ class ToolPaint(FlatCAMTool, Gerber):
return
paint_method = method if method is not None else self.paintmethod_combo.get_value()
- paint_margin = float(self.paintmargin_entry.get_value()) if margin is None else margin
# determine if to use the progressive plotting
prog_plot = True if self.app.defaults["tools_paint_plotting"] == 'progressive' else False
name = outname if outname is not None else self.obj_name + "_paint"
- over = overlap if overlap is not None else float(self.app.defaults["tools_paintoverlap"]) / 100.0
- conn = connect if connect is not None else self.app.defaults["tools_pathconnect"]
- cont = contour if contour is not None else self.app.defaults["tools_paintcontour"]
order = order if order is not None else self.order_radio.get_value()
tools_storage = self.paint_tools if tools_storage is None else tools_storage
@@ -1911,287 +2135,104 @@ class ToolPaint(FlatCAMTool, Gerber):
proc = self.app.proc_container.new(_("Painting polygon..."))
- # Initializes the new geometry object
- def gen_paintarea(geo_obj, app_obj):
- geo_obj.solid_geometry = []
+ tool_dia = None
+ current_uid = None
+ final_solid_geometry = []
- def paint_p(polyg, tooldiameter):
- cpoly = None
- try:
- if paint_method == _("Standard"):
- # Type(cp) == FlatCAMRTreeStorage | None
- cpoly = self.clear_polygon(polyg,
- tooldia=tooldiameter,
- steps_per_circle=self.app.defaults["geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
+ for tool_dia in sorted_tools:
+ log.debug("Starting geometry processing for tool: %s" % str(tool_dia))
+ self.app.inform.emit(
+ '[success] %s %s%s %s' % (_('Painting with tool diameter = '), str(tool_dia), self.units.lower(),
+ _('started'))
+ )
+ self.app.proc_container.update_view_text(' %d%%' % 0)
- elif paint_method == _("Seed"):
- # Type(cp) == FlatCAMRTreeStorage | None
- cpoly = self.clear_polygon2(polyg,
- tooldia=tooldiameter,
- steps_per_circle=self.app.defaults["geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
+ # find the tooluid associated with the current tool_dia so we know what tool to use
+ for k, v in tools_storage.items():
+ if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals, tool_dia)):
+ current_uid = int(k)
- elif paint_method == _("Lines"):
- # Type(cp) == FlatCAMRTreeStorage | None
- cpoly = self.clear_polygon3(polyg,
- tooldia=tooldiameter,
- steps_per_circle=self.app.defaults["geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
+ if not current_uid:
+ return "fail"
- elif paint_method == _("Laser_lines"):
- # line = None
- # aperture_size = None
+ # determine the tool parameters to use
+ over = float(tools_storage[current_uid]['data']['tools_paintoverlap']) / 100.0
+ conn = tools_storage[current_uid]['data']['tools_pathconnect']
+ cont = tools_storage[current_uid]['data']['tools_paintcontour']
- # the key is the aperture type and the val is a list of geo elements
- flash_el_dict = {}
- # the key is the aperture size, the val is a list of geo elements
- traces_el_dict = {}
+ paint_margin = float(tools_storage[current_uid]['data']['tools_paintmargin'])
+ poly_buf = []
+ for pol in polygon_list:
+ buffered_pol = pol.buffer(-paint_margin)
+ if buffered_pol and not buffered_pol.is_empty:
+ poly_buf.append(buffered_pol)
- # find the flashes and the lines that are in the selected polygon and store them separately
- for apid, apval in obj.apertures.items():
- for geo_el in apval['geometry']:
- if apval["size"] == 0.0:
- if apval["size"] in traces_el_dict:
- traces_el_dict[apval["size"]].append(geo_el)
- else:
- traces_el_dict[apval["size"]] = [geo_el]
+ if not poly_buf:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Margin parameter too big. Tool is not used"))
+ continue
- if 'follow' in geo_el and geo_el['follow'].within(polyg):
- if isinstance(geo_el['follow'], Point):
- if apval["type"] == 'C':
- if 'C' in flash_el_dict:
- flash_el_dict['C'].append(geo_el)
- else:
- flash_el_dict['C'] = [geo_el]
- elif apval["type"] == 'O':
- if 'O' in flash_el_dict:
- flash_el_dict['O'].append(geo_el)
- else:
- flash_el_dict['O'] = [geo_el]
- elif apval["type"] == 'R':
- if 'R' in flash_el_dict:
- flash_el_dict['R'].append(geo_el)
- else:
- flash_el_dict['R'] = [geo_el]
- else:
- aperture_size = apval['size']
+ # variables to display the percentage of work done
+ geo_len = len(poly_buf)
- if aperture_size in traces_el_dict:
- traces_el_dict[aperture_size].append(geo_el)
- else:
- traces_el_dict[aperture_size] = [geo_el]
+ log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
- cpoly = FlatCAMRTreeStorage()
- pads_lines_list = []
-
- # process the flashes found in the selected polygon with the 'lines' method for rectangular
- # flashes and with _("Seed") for oblong and circular flashes
- # and pads (flahes) need the contour therefore I override the GUI settings with always True
- for ap_type in flash_el_dict:
- for elem in flash_el_dict[ap_type]:
- if 'solid' in elem:
- if ap_type == 'C':
- f_o = self.clear_polygon2(elem['solid'],
- tooldia=tooldiameter,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=True,
- connect=conn,
- prog_plot=prog_plot)
- pads_lines_list += [p for p in f_o.get_objects() if p]
-
- elif ap_type == 'O':
- f_o = self.clear_polygon2(elem['solid'],
- tooldia=tooldiameter,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=True,
- connect=conn,
- prog_plot=prog_plot)
- pads_lines_list += [p for p in f_o.get_objects() if p]
-
- elif ap_type == 'R':
- f_o = self.clear_polygon3(elem['solid'],
- tooldia=tooldiameter,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=True,
- connect=conn,
- prog_plot=prog_plot)
-
- pads_lines_list += [p for p in f_o.get_objects() if p]
-
- # add the lines from pads to the storage
- try:
- for lin in pads_lines_list:
- if lin:
- cpoly.insert(lin)
- except TypeError:
- cpoly.insert(pads_lines_list)
-
- copper_lines_list = []
- # process the traces found in the selected polygon using the 'laser_lines' method,
- # method which will follow the 'follow' line therefore use the longer path possible for the
- # laser, therefore the acceleration will play a smaller factor
- for aperture_size in traces_el_dict:
- for elem in traces_el_dict[aperture_size]:
- line = elem['follow']
- if line:
- t_o = self.fill_with_lines(line, aperture_size,
- tooldia=tooldiameter,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
-
- copper_lines_list += [p for p in t_o.get_objects() if p]
-
- # add the lines from copper features to storage but first try to make as few lines as possible
- # by trying to fuse them
- lines_union = linemerge(unary_union(copper_lines_list))
- try:
- for lin in lines_union:
- if lin:
- cpoly.insert(lin)
- except TypeError:
- cpoly.insert(lines_union)
- # # determine the Gerber follow line
- # for apid, apval in obj.apertures.items():
- # for geo_el in apval['geometry']:
- # if 'solid' in geo_el:
- # if Point(inside_pt).within(geo_el['solid']):
- # if not isinstance(geo_el['follow'], Point):
- # line = geo_el['follow']
- #
- # if apval['type'] == 'C':
- # aperture_size = apval['size']
- # else:
- # if apval['width'] > apval['height']:
- # aperture_size = apval['height']
- # else:
- # aperture_size = apval['width']
- #
- # if line:
- # cpoly = self.fill_with_lines(line, aperture_size,
- # tooldia=tooldiameter,
- # steps_per_circle=self.app.defaults["geometry_circle_steps"],
- # overlap=over,
- # contour=cont,
- # connect=conn,
- # prog_plot=prog_plot)
-
- elif paint_method == _("Combo"):
- self.app.inform.emit(_("Painting polygon with method: lines."))
- cpoly = self.clear_polygon3(polyg,
- tooldia=tooldiameter,
- steps_per_circle=self.app.defaults["geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
-
- if cpoly and cpoly.objects:
- pass
- else:
- self.app.inform.emit(_("Failed. Painting polygon with method: seed."))
- cpoly = self.clear_polygon2(polyg,
- tooldia=tooldiameter,
- steps_per_circle=self.app.defaults["geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
- if cpoly and cpoly.objects:
- pass
- else:
- self.app.inform.emit(_("Failed. Painting polygon with method: standard."))
- cpoly = self.clear_polygon(polyg,
- tooldia=tooldiameter,
- steps_per_circle=self.app.defaults["geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
- except FlatCAMApp.GracefulException:
- return "fail"
- except Exception as ee:
- log.debug("ToolPaint.paint_poly().gen_paintarea().paint_p() --> %s" % str(ee))
-
- if cpoly and cpoly.objects:
- geo_obj.solid_geometry += list(cpoly.get_objects())
- return cpoly
- else:
- app_obj.inform.emit('[ERROR_NOTCL] %s' % _('Geometry could not be painted completely'))
- return None
-
- current_uid = int(1)
- tool_dia = None
- for tool_dia in sorted_tools:
- # find the tooluid associated with the current tool_dia so we know where to add the tool solid_geometry
- for k, v in tools_storage.items():
- if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals, tool_dia)):
- current_uid = int(k)
- break
+ pol_nr = 0
+ # -----------------------------
+ # effective polygon clearing job
+ # -----------------------------
try:
- poly_buf = [pol.buffer(-paint_margin) for pol in polygon_list]
cp = []
try:
for pp in poly_buf:
- cp.append(paint_p(pp, tooldiameter=tool_dia))
+ geo_res = self.paint_polygon_worker(pp, tooldiameter=tool_dia, over=over, conn=conn,
+ cont=cont, paint_method=paint_method, obj=obj,
+ prog_plot=prog_plot)
+ if geo_res:
+ cp.append(geo_res)
except TypeError:
- cp = paint_p(poly_buf, tooldiameter=tool_dia)
+ geo_res = self.paint_polygon_worker(poly_buf, tooldiameter=tool_dia, over=over, conn=conn,
+ cont=cont, paint_method=paint_method, obj=obj,
+ prog_plot=prog_plot)
+ if geo_res:
+ cp.append(geo_res)
total_geometry = []
if cp:
- try:
- for x in cp:
- total_geometry += list(x.get_objects())
- except TypeError:
- total_geometry = list(cp.get_objects())
+ for x in cp:
+ total_geometry += list(x.get_objects())
+ final_solid_geometry += total_geometry
except FlatCAMApp.GracefulException:
return "fail"
except Exception as e:
log.debug("Could not Paint the polygons. %s" % str(e))
- app_obj.inform.emit('[ERROR] %s\n%s' %
- (_("Could not do Paint. Try a different combination of parameters. "
- "Or a different strategy of paint"),
- str(e)
- )
- )
- return "fail"
+ self.app.inform.emit(
+ '[ERROR] %s\n%s' %
+ (_("Could not do Paint. Try a different combination of parameters. "
+ "Or a different strategy of paint"), str(e)
+ )
+ )
+ continue
# add the solid_geometry to the current too in self.paint_tools (tools_storage)
# dictionary and then reset the temporary list that stored that solid_geometry
tools_storage[current_uid]['solid_geometry'] = deepcopy(total_geometry)
-
tools_storage[current_uid]['data']['name'] = name
- # clean the progressive plotted shapes if it was used
- if self.app.defaults["tools_paint_plotting"] == 'progressive':
- self.temp_shapes.clear(update=True)
+ # clean the progressive plotted shapes if it was used
+ if self.app.defaults["tools_paint_plotting"] == 'progressive':
+ self.temp_shapes.clear(update=True)
- # delete tools with empty geometry
- # look for keys in the tools_storage dict that have 'solid_geometry' values empty
- for uid in list(tools_storage.keys()):
- # if the solid_geometry (type=list) is empty
- if not tools_storage[uid]['solid_geometry']:
- tools_storage.pop(uid, None)
+ # delete tools with empty geometry
+ # look for keys in the tools_storage dict that have 'solid_geometry' values empty
+ for uid in list(tools_storage.keys()):
+ # if the solid_geometry (type=list) is empty
+ if not tools_storage[uid]['solid_geometry']:
+ tools_storage.pop(uid, None)
+
+ def job_init(geo_obj, app_obj):
+ if not tools_storage:
+ return 'fail'
geo_obj.options["cnctooldia"] = str(tool_dia)
@@ -2201,7 +2242,7 @@ class ToolPaint(FlatCAMTool, Gerber):
geo_obj.tools.clear()
geo_obj.tools = dict(tools_storage)
- geo_obj.solid_geometry = cascaded_union(tools_storage[current_uid]['solid_geometry'])
+ geo_obj.solid_geometry = cascaded_union(final_solid_geometry)
try:
if isinstance(geo_obj.solid_geometry, list):
@@ -2213,8 +2254,8 @@ class ToolPaint(FlatCAMTool, Gerber):
geo_obj.options['ymin'] = b
geo_obj.options['xmax'] = c
geo_obj.options['ymax'] = d
- except Exception as e:
- log.debug("ToolPaint.paint_poly.gen_paintarea() bounds error --> %s" % str(e))
+ except Exception as ee:
+ log.debug("ToolPaint.paint_poly.gen_paintarea() bounds error --> %s" % str(ee))
return
# test if at least one tool has solid_geometry. If no tool has solid_geometry we raise an Exception
@@ -2228,10 +2269,7 @@ class ToolPaint(FlatCAMTool, Gerber):
_("There is no Painting Geometry in the file.\n"
"Usually it means that the tool diameter is too big for the painted geometry.\n"
"Change the painting parameters and try again."))
- return
-
- total_geometry[:] = []
- self.app.inform.emit('[success] %s' % _("Paint Single Done."))
+ return "fail"
# Experimental...
# print("Indexing...", end=' ')
@@ -2249,19 +2287,24 @@ class ToolPaint(FlatCAMTool, Gerber):
def job_thread(app_obj):
try:
- app_obj.new_object("geometry", name, gen_paintarea, plot=plot)
+ ret = app_obj.new_object("geometry", name, job_init, plot=plot)
except FlatCAMApp.GracefulException:
proc.done()
return
- except Exception as e:
+ except Exception as er:
proc.done()
- self.app.inform.emit('[ERROR_NOTCL] %s --> %s' %
- ('PaintTool.paint_poly()',
- str(e)))
+ app_obj.inform.emit('[ERROR_NOTCL] %s --> %s' % ('PaintTool.paint_poly()', str(er)))
return
proc.done()
+
+ if ret == 'fail':
+ self.app.inform.emit('[ERROR] %s' % _("Paint Single failed."))
+ return
+
# focus on Selected Tab
- self.app.ui.notebook.setCurrentWidget(self.app.ui.selected_tab)
+ # self.app.ui.notebook.setCurrentWidget(self.app.ui.selected_tab)
+
+ self.app.inform.emit('[success] %s' % _("Paint Single Done."))
self.app.inform.emit(_("Polygon Paint started ..."))
@@ -2274,8 +2317,8 @@ class ToolPaint(FlatCAMTool, Gerber):
else:
job_thread(app_obj=self.app)
- def paint_poly_all(self, obj, tooldia=None, overlap=None, order=None, margin=None, method=None, outname=None,
- connect=None, contour=None, tools_storage=None, plot=True, run_threaded=True):
+ def paint_poly_all(self, obj, tooldia=None, order=None, method=None, outname=None,
+ tools_storage=None, plot=True, run_threaded=True):
"""
Paints all polygons in this object.
@@ -2296,11 +2339,6 @@ class ToolPaint(FlatCAMTool, Gerber):
"""
paint_method = method if method is not None else self.paintmethod_combo.get_value()
- if margin is not None:
- paint_margin = margin
- else:
- paint_margin = float(self.paintmargin_entry.get_value())
-
# determine if to use the progressive plotting
if self.app.defaults["tools_paint_plotting"] == 'progressive':
prog_plot = True
@@ -2309,11 +2347,8 @@ class ToolPaint(FlatCAMTool, Gerber):
proc = self.app.proc_container.new(_("Painting polygons..."))
name = outname if outname is not None else self.obj_name + "_paint"
-
- over = overlap if overlap is not None else float(self.app.defaults["tools_paintoverlap"]) / 100.0
- conn = connect if connect is not None else self.app.defaults["tools_pathconnect"]
- cont = contour if contour is not None else self.app.defaults["tools_paintcontour"]
order = order if order is not None else self.order_radio.get_value()
+ tools_storage = self.paint_tools if tools_storage is None else tools_storage
sorted_tools = []
if tooldia is not None:
@@ -2328,10 +2363,6 @@ class ToolPaint(FlatCAMTool, Gerber):
for row in range(self.tools_table.rowCount()):
sorted_tools.append(float(self.tools_table.item(row, 1).text()))
- if tools_storage is not None:
- tools_storage = tools_storage
- else:
- tools_storage = self.paint_tools
# This is a recursive generator of individual Polygons.
# Note: Double check correct implementation. Might exit
# early if it finds something that is not a Polygon?
@@ -2423,8 +2454,13 @@ class ToolPaint(FlatCAMTool, Gerber):
total_geometry = []
current_uid = int(1)
+ old_disp_number = 0
geo_obj.solid_geometry = []
+ final_solid_geometry = []
+
+ painted_area = recurse(obj.solid_geometry)
+
for tool_dia in sorted_tools:
log.debug("Starting geometry processing for tool: %s" % str(tool_dia))
app_obj.inform.emit(
@@ -2440,523 +2476,116 @@ class ToolPaint(FlatCAMTool, Gerber):
if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals, tool_dia)):
current_uid = int(k)
break
+ if not current_uid:
+ return "fail"
+
+ # determine the tool parameters to use
+ over = float(tools_storage[current_uid]['data']['tools_paintoverlap']) / 100.0
+ conn = tools_storage[current_uid]['data']['tools_pathconnect']
+ cont = tools_storage[current_uid]['data']['tools_paintcontour']
+
+ paint_margin = float(tools_storage[current_uid]['data']['tools_paintmargin'])
+ poly_buf = []
+ for pol in painted_area:
+ buffered_pol = pol.buffer(-paint_margin)
+ if buffered_pol and not buffered_pol.is_empty:
+ poly_buf.append(buffered_pol)
+
+ if not poly_buf:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Margin parameter too big. Tool is not used"))
+ continue
- painted_area = recurse(obj.solid_geometry)
# variables to display the percentage of work done
- geo_len = len(painted_area)
+ geo_len = len(poly_buf)
- old_disp_number = 0
log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
pol_nr = 0
- for geo in painted_area:
- # provide the app with a way to process the GUI events when in a blocking loop
- QtWidgets.QApplication.processEvents()
+ # -----------------------------
+ # effective polygon clearing job
+ # -----------------------------
+ poly_processed = []
- if self.app.abort_flag:
- # graceful abort requested by the user
- raise FlatCAMApp.GracefulException
+ try:
+ cp = []
+ geo_res = None
+ try:
+ for pp in poly_buf:
- # try to clean the Polygon but it may result into a MultiPolygon
- geo = geo.buffer(0)
- poly_buf = geo.buffer(-paint_margin)
+ # provide the app with a way to process the GUI events when in a blocking loop
+ QtWidgets.QApplication.processEvents()
+ if self.app.abort_flag:
+ # graceful abort requested by the user
+ raise FlatCAMApp.GracefulException
- if geo is not None and geo.is_valid:
- poly_processed = []
- try:
- for pol in poly_buf:
- if pol is not None and isinstance(pol, Polygon):
- cp = None
- if paint_method == _("Standard"):
- cp = self.clear_polygon(pol,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
+ geo_res = self.paint_polygon_worker(pp, tooldiameter=tool_dia, over=over, conn=conn,
+ cont=cont, paint_method=paint_method, obj=obj,
prog_plot=prog_plot)
- elif paint_method == _("Seed"):
- cp = self.clear_polygon2(pol,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
- elif paint_method == _("Lines"):
- cp = self.clear_polygon3(pol,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
- elif paint_method == _("Laser_lines"):
- # line = None
- # aperture_size = None
-
- # the key is the aperture type and the val is a list of geo elements
- flash_el_dict = {}
- # the key is the aperture size, the val is a list of geo elements
- traces_el_dict = {}
-
- # find the flashes and the lines that are in the selected polygon and store
- # them separately
- for apid, apval in obj.apertures.items():
- for geo_el in apval['geometry']:
- if apval["size"] == 0.0:
- if apval["size"] in traces_el_dict:
- traces_el_dict[apval["size"]].append(geo_el)
- else:
- traces_el_dict[apval["size"]] = [geo_el]
-
- if 'follow' in geo_el and geo_el['follow'].within(pol):
- if isinstance(geo_el['follow'], Point):
- if apval["type"] == 'C':
- if 'C' in flash_el_dict:
- flash_el_dict['C'].append(geo_el)
- else:
- flash_el_dict['C'] = [geo_el]
- elif apval["type"] == 'O':
- if 'O' in flash_el_dict:
- flash_el_dict['O'].append(geo_el)
- else:
- flash_el_dict['O'] = [geo_el]
- elif apval["type"] == 'R':
- if 'R' in flash_el_dict:
- flash_el_dict['R'].append(geo_el)
- else:
- flash_el_dict['R'] = [geo_el]
- else:
- aperture_size = apval['size']
-
- if aperture_size in traces_el_dict:
- traces_el_dict[aperture_size].append(geo_el)
- else:
- traces_el_dict[aperture_size] = [geo_el]
-
- cp = FlatCAMRTreeStorage()
- pads_lines_list = []
-
- # process the flashes found in the selected polygon with the 'lines' method
- # for rectangular flashes and with _("Seed") for oblong and circular flashes
- # and pads (flahes) need the contour therefore I override the GUI settings
- # with always True
- for ap_type in flash_el_dict:
- for elem in flash_el_dict[ap_type]:
- if 'solid' in elem:
- if ap_type == 'C':
- f_o = self.clear_polygon2(elem['solid'],
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=True,
- connect=conn,
- prog_plot=prog_plot)
- pads_lines_list += [p for p in f_o.get_objects() if p]
-
- elif ap_type == 'O':
- f_o = self.clear_polygon2(elem['solid'],
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=True,
- connect=conn,
- prog_plot=prog_plot)
- pads_lines_list += [p for p in f_o.get_objects() if p]
-
- elif ap_type == 'R':
- f_o = self.clear_polygon3(elem['solid'],
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=True,
- connect=conn,
- prog_plot=prog_plot)
-
- pads_lines_list += [p for p in f_o.get_objects() if p]
-
- # add the lines from pads to the storage
- try:
- for lin in pads_lines_list:
- if lin:
- cp.insert(lin)
- except TypeError:
- cp.insert(pads_lines_list)
-
- copper_lines_list = []
- # process the traces found in the selected polygon using the 'laser_lines'
- # method, method which will follow the 'follow' line therefore use the longer
- # path possible for the laser, therefore the acceleration will play
- # a smaller factor
- for aperture_size in traces_el_dict:
- for elem in traces_el_dict[aperture_size]:
- line = elem['follow']
- if line:
- t_o = self.fill_with_lines(line, aperture_size,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
-
- copper_lines_list += [p for p in t_o.get_objects() if p]
-
- # add the lines from copper features to storage but first try to make as few
- # lines as possible
- # by trying to fuse them
- lines_union = linemerge(unary_union(copper_lines_list))
- try:
- for lin in lines_union:
- if lin:
- cp.insert(lin)
- except TypeError:
- cp.insert(lines_union)
- elif paint_method == _("Combo"):
- self.app.inform.emit(_("Painting polygons with method: lines."))
- cp = self.clear_polygon3(pol,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
-
- if cp and cp.objects:
- pass
- else:
- self.app.inform.emit(_("Failed. Painting polygons with method: seed."))
- cp = self.clear_polygon2(pol,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
- if cp and cp.objects:
- pass
- else:
- self.app.inform.emit(
- _("Failed. Painting polygons with method: standard."))
-
- cp = self.clear_polygon(pol,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
- if cp and cp.objects:
- total_geometry += list(cp.get_objects())
- poly_processed.append(True)
- else:
- poly_processed.append(False)
- log.warning("Polygon in MultiPolygon can not be cleared.")
- else:
- log.warning("Geo in Iterable can not be cleared because it is not Polygon. "
- "It is: %s" % str(type(pol)))
- except TypeError:
- if isinstance(poly_buf, Polygon):
- cp = None
- if paint_method == _("Standard"):
- cp = self.clear_polygon(poly_buf,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
- elif paint_method == _("Seed"):
- cp = self.clear_polygon2(poly_buf,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
- elif paint_method == _("Lines"):
- cp = self.clear_polygon3(poly_buf,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
- elif paint_method == _("Laser_lines"):
- # line = None
- # aperture_size = None
-
- # the key is the aperture type and the val is a list of geo elements
- flash_el_dict = {}
- # the key is the aperture size, the val is a list of geo elements
- traces_el_dict = {}
-
- # find the flashes and the lines that are in the selected polygon and store
- # them separately
- for apid, apval in obj.apertures.items():
- for geo_el in apval['geometry']:
- if apval["size"] == 0.0:
- if apval["size"] in traces_el_dict:
- traces_el_dict[apval["size"]].append(geo_el)
- else:
- traces_el_dict[apval["size"]] = [geo_el]
-
- if 'follow' in geo_el and geo_el['follow'].within(poly_buf):
- if isinstance(geo_el['follow'], Point):
- if apval["type"] == 'C':
- if 'C' in flash_el_dict:
- flash_el_dict['C'].append(geo_el)
- else:
- flash_el_dict['C'] = [geo_el]
- elif apval["type"] == 'O':
- if 'O' in flash_el_dict:
- flash_el_dict['O'].append(geo_el)
- else:
- flash_el_dict['O'] = [geo_el]
- elif apval["type"] == 'R':
- if 'R' in flash_el_dict:
- flash_el_dict['R'].append(geo_el)
- else:
- flash_el_dict['R'] = [geo_el]
- else:
- aperture_size = apval['size']
-
- if aperture_size in traces_el_dict:
- traces_el_dict[aperture_size].append(geo_el)
- else:
- traces_el_dict[aperture_size] = [geo_el]
-
- cp = FlatCAMRTreeStorage()
- pads_lines_list = []
-
- # process the flashes found in the selected polygon with the 'lines' method
- # for rectangular flashes and with _("Seed") for oblong and circular flashes
- # and pads (flahes) need the contour therefore I override the GUI settings
- # with always True
- for ap_type in flash_el_dict:
- for elem in flash_el_dict[ap_type]:
- if 'solid' in elem:
- if ap_type == 'C':
- f_o = self.clear_polygon2(elem['solid'],
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=True,
- connect=conn,
- prog_plot=prog_plot)
- pads_lines_list += [p for p in f_o.get_objects() if p]
-
- elif ap_type == 'O':
- f_o = self.clear_polygon2(elem['solid'],
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=True,
- connect=conn,
- prog_plot=prog_plot)
- pads_lines_list += [p for p in f_o.get_objects() if p]
-
- elif ap_type == 'R':
- f_o = self.clear_polygon3(elem['solid'],
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=True,
- connect=conn,
- prog_plot=prog_plot)
-
- pads_lines_list += [p for p in f_o.get_objects() if p]
-
- # add the lines from pads to the storage
- try:
- for lin in pads_lines_list:
- if lin:
- cp.insert(lin)
- except TypeError:
- cp.insert(pads_lines_list)
-
- copper_lines_list = []
- # process the traces found in the selected polygon using the 'laser_lines'
- # method, method which will follow the 'follow' line therefore use the longer
- # path possible for the laser, therefore the acceleration will play
- # a smaller factor
- for aperture_size in traces_el_dict:
- for elem in traces_el_dict[aperture_size]:
- line = elem['follow']
- if line:
- t_o = self.fill_with_lines(line, aperture_size,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
-
- copper_lines_list += [p for p in t_o.get_objects() if p]
-
- # add the lines from copper features to storage but first try to make as few
- # lines as possible
- # by trying to fuse them
- lines_union = linemerge(unary_union(copper_lines_list))
- try:
- for lin in lines_union:
- if lin:
- cp.insert(lin)
- except TypeError:
- cp.insert(lines_union)
- elif paint_method == _("Combo"):
- self.app.inform.emit(_("Painting polygons with method: lines."))
- cp = self.clear_polygon3(poly_buf,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
-
- if cp and cp.objects:
- pass
- else:
- self.app.inform.emit(_("Failed. Painting polygons with method: seed."))
- cp = self.clear_polygon2(poly_buf,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
- if cp and cp.objects:
- pass
- else:
- self.app.inform.emit(_("Failed. Painting polygons with method: standard."))
- cp = self.clear_polygon(poly_buf,
- tooldia=tool_dia,
- steps_per_circle=self.app.defaults[
- "geometry_circle_steps"],
- overlap=over,
- contour=cont,
- connect=conn,
- prog_plot=prog_plot)
- if cp:
- total_geometry += list(cp.get_objects())
- poly_processed.append(True)
- else:
- poly_processed.append(False)
- log.warning("Polygon can not be cleared.")
+ if geo_res:
+ cp.append(geo_res)
+ poly_processed.append(True)
else:
- log.warning("Geo can not be cleared because it is: %s" % str(type(poly_buf)))
+ poly_processed.append(False)
+ except TypeError:
+ # provide the app with a way to process the GUI events when in a blocking loop
+ QtWidgets.QApplication.processEvents()
+ if self.app.abort_flag:
+ # graceful abort requested by the user
+ raise FlatCAMApp.GracefulException
- p_cleared = poly_processed.count(True)
- p_not_cleared = poly_processed.count(False)
+ geo_res = self.paint_polygon_worker(poly_buf, tooldiameter=tool_dia, over=over, conn=conn,
+ cont=cont, paint_method=paint_method, obj=obj,
+ prog_plot=prog_plot)
+ if geo_res:
+ cp.append(geo_res)
+ poly_processed.append(True)
+ else:
+ poly_processed.append(False)
- if p_not_cleared:
- app_obj.poly_not_cleared = True
+ total_geometry = []
+ if cp:
+ for x in cp:
+ total_geometry += list(x.get_objects())
+ final_solid_geometry += total_geometry
- if p_cleared == 0:
- continue
+ pol_nr += 1
+ disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
+ # log.debug("Polygons cleared: %d" % pol_nr)
- # try:
- # # Polygons are the only really paintable geometries,
- # # lines in theory have no area to be painted
- # if not isinstance(geo, Polygon):
- # continue
- # poly_buf = geo.buffer(-paint_margin)
- #
- # if paint_method == _("Seed"):
- # # Type(cp) == FlatCAMRTreeStorage | None
- # cp = self.clear_polygon2(poly_buf,
- # tooldia=tool_dia,
- # steps_per_circle=self.app.defaults["geometry_circle_steps"],
- # overlap=over,
- # contour=cont,
- # connect=conn,
- # prog_plot=prog_plot)
- #
- # elif paint_method == _("Lines"):
- # # Type(cp) == FlatCAMRTreeStorage | None
- # cp = self.clear_polygon3(poly_buf,
- # tooldia=tool_dia,
- # steps_per_circle=self.app.defaults["geometry_circle_steps"],
- # overlap=over,
- # contour=cont,
- # connect=conn,
- # prog_plot=prog_plot)
- #
- # else:
- # # Type(cp) == FlatCAMRTreeStorage | None
- # cp = self.clear_polygon(poly_buf,
- # tooldia=tool_dia,
- # steps_per_circle=self.app.defaults["geometry_circle_steps"],
- # overlap=over,
- # contour=cont,
- # connect=conn,
- # prog_plot=prog_plot)
- #
- # if cp is not None:
- # total_geometry += list(cp.get_objects())
- # except FlatCAMApp.GracefulException:
- # return "fail"
- # except Exception as e:
- # log.debug("Could not Paint the polygons. %s" % str(e))
- # self.app.inform.emit('[ERROR] %s\n%s' %
- # (_("Could not do Paint All. Try a different combination of parameters. "
- # "Or a different Method of paint"),
- # str(e)))
- # return "fail"
+ if old_disp_number < disp_number <= 100:
+ app_obj.proc_container.update_view_text(' %d%%' % disp_number)
+ old_disp_number = disp_number
+ # log.debug("Polygons cleared: %d. Percentage done: %d%%" % (pol_nr, disp_number))
- pol_nr += 1
- disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
- # log.debug("Polygons cleared: %d" % pol_nr)
+ except Exception as err:
+ log.debug("Could not Paint the polygons. %s" % str(err))
+ self.app.inform.emit(
+ '[ERROR] %s\n%s' %
+ (_("Could not do Paint. Try a different combination of parameters. "
+ "Or a different strategy of paint"), str(err)
+ )
+ )
+ continue
- if old_disp_number < disp_number <= 100:
- app_obj.proc_container.update_view_text(' %d%%' % disp_number)
- old_disp_number = disp_number
- # log.debug("Polygons cleared: %d. Percentage done: %d%%" % (pol_nr, disp_number))
+ p_cleared = poly_processed.count(True)
+ p_not_cleared = poly_processed.count(False)
+
+ if p_not_cleared:
+ app_obj.poly_not_cleared = True
+
+ if p_cleared == 0:
+ continue
# add the solid_geometry to the current too in self.paint_tools (tools_storage)
# dictionary and then reset the temporary list that stored that solid_geometry
tools_storage[current_uid]['solid_geometry'] = deepcopy(total_geometry)
-
tools_storage[current_uid]['data']['name'] = name
- total_geometry[:] = []
# clean the progressive plotted shapes if it was used
if self.app.defaults["tools_paint_plotting"] == 'progressive':
self.temp_shapes.clear(update=True)
- # # delete tools with empty geometry
- # keys_to_delete = []
- # # look for keys in the tools_storage dict that have 'solid_geometry' values empty
- # for uid in tools_storage:
- # # if the solid_geometry (type=list) is empty
- # if not tools_storage[uid]['solid_geometry']:
- # keys_to_delete.append(uid)
- #
- # # actual delete of keys from the tools_storage dict
- # for k in keys_to_delete:
- # tools_storage.pop(k, None)
-
# delete tools with empty geometry
# look for keys in the tools_storage dict that have 'solid_geometry' values empty
for uid in list(tools_storage.keys()):
@@ -2964,6 +2593,9 @@ class ToolPaint(FlatCAMTool, Gerber):
if not tools_storage[uid]['solid_geometry']:
tools_storage.pop(uid, None)
+ if not tools_storage:
+ return 'fail'
+
geo_obj.options["cnctooldia"] = str(tool_dia)
# this turn on the FlatCAMCNCJob plot for multiple tools
geo_obj.multigeo = True
@@ -2971,6 +2603,8 @@ class ToolPaint(FlatCAMTool, Gerber):
geo_obj.tools.clear()
geo_obj.tools = dict(tools_storage)
+ geo_obj.solid_geometry = cascaded_union(final_solid_geometry)
+
# test if at least one tool has solid_geometry. If no tool has solid_geometry we raise an Exception
has_solid_geo = 0
for tooluid in geo_obj.tools:
@@ -2981,7 +2615,7 @@ class ToolPaint(FlatCAMTool, Gerber):
_("There is no Painting Geometry in the file.\n"
"Usually it means that the tool diameter is too big for the painted geometry.\n"
"Change the painting parameters and try again."))
- return
+ return "fail"
# Experimental...
# print("Indexing...", end=' ')
@@ -2991,8 +2625,8 @@ class ToolPaint(FlatCAMTool, Gerber):
# Initializes the new geometry object
def gen_paintarea_rest_machining(geo_obj, app_obj):
- assert isinstance(geo_obj, FlatCAMGeometry), \
- "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
+ # assert isinstance(geo_obj, FlatCAMGeometry), \
+ # "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
log.debug("Paint Tool. Rest machining painting all task started.")
if isinstance(obj, FlatCAMGerber):
@@ -3010,10 +2644,6 @@ class ToolPaint(FlatCAMTool, Gerber):
tool_dia = None
sorted_tools.sort(reverse=True)
- cleared_geo = []
- current_uid = int(1)
- geo_obj.solid_geometry = []
-
if isinstance(obj, FlatCAMGerber):
if self.app.defaults["tools_paint_plotting"] == 'progressive':
if isinstance(obj.solid_geometry, list):
@@ -3031,6 +2661,14 @@ class ToolPaint(FlatCAMTool, Gerber):
log.debug("ToolPaint.paint_poly.gen_paintarea() bounds error --> %s" % str(e))
return
+ cleared_geo = []
+ current_uid = int(1)
+ geo_obj.solid_geometry = []
+ final_solid_geometry = []
+ old_disp_number = 0
+
+ painted_area = recurse(obj.solid_geometry)
+
for tool_dia in sorted_tools:
log.debug("Starting geometry processing for tool: %s" % str(tool_dia))
app_obj.inform.emit(
@@ -3041,37 +2679,57 @@ class ToolPaint(FlatCAMTool, Gerber):
)
app_obj.proc_container.update_view_text(' %d%%' % 0)
- painted_area = recurse(obj.solid_geometry)
- # variables to display the percentage of work done
- geo_len = int(len(painted_area) / 100)
+ # find the tooluid associated with the current tool_dia so we know where to add the tool solid_geometry
+ for k, v in tools_storage.items():
+ if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals, tool_dia)):
+ current_uid = int(k)
+ break
+ if not current_uid:
+ return "fail"
+
+ # determine the tool parameters to use
+ over = float(tools_storage[current_uid]['data']['tools_paintoverlap']) / 100.0
+ conn = tools_storage[current_uid]['data']['tools_pathconnect']
+ cont = tools_storage[current_uid]['data']['tools_paintcontour']
+
+ paint_margin = float(tools_storage[current_uid]['data']['tools_paintmargin'])
+ poly_buf = []
+ for pol in painted_area:
+ pol = Polygon(pol) if not isinstance(pol, Polygon) else pol
+ buffered_pol = pol.buffer(-paint_margin)
+ if buffered_pol and not buffered_pol.is_empty:
+ poly_buf.append(buffered_pol)
+
+ if not poly_buf:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Margin parameter too big. Tool is not used"))
+ continue
+
+ # variables to display the percentage of work done
+ geo_len = len(poly_buf)
- old_disp_number = 0
log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
pol_nr = 0
- for geo in painted_area:
+
+ for geo in poly_buf:
try:
- geo = Polygon(geo) if not isinstance(geo, Polygon) else geo
- poly_buf = geo.buffer(-paint_margin)
cp = None
if paint_method == _("Standard"):
# Type(cp) == FlatCAMRTreeStorage | None
- cp = self.clear_polygon(poly_buf, tooldia=tool_dia,
+ cp = self.clear_polygon(geo, tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over, contour=cont, connect=conn,
prog_plot=prog_plot)
-
elif paint_method == _("Seed"):
# Type(cp) == FlatCAMRTreeStorage | None
- cp = self.clear_polygon2(poly_buf, tooldia=tool_dia,
+ cp = self.clear_polygon2(geo, tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over, contour=cont, connect=conn,
prog_plot=prog_plot)
-
elif paint_method == _("Lines"):
# Type(cp) == FlatCAMRTreeStorage | None
- cp = self.clear_polygon3(poly_buf, tooldia=tool_dia,
+ cp = self.clear_polygon3(geo, tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over, contour=cont, connect=conn,
prog_plot=prog_plot)
@@ -3094,7 +2752,7 @@ class ToolPaint(FlatCAMTool, Gerber):
else:
traces_el_dict[apval["size"]] = [geo_el]
- if 'follow' in geo_el and geo_el['follow'].within(poly_buf):
+ if 'follow' in geo_el and geo_el['follow'].within(geo):
if isinstance(geo_el['follow'], Point):
if apval["type"] == 'C':
if 'C' in flash_el_dict:
@@ -3203,7 +2861,7 @@ class ToolPaint(FlatCAMTool, Gerber):
cp.insert(lines_union)
elif paint_method == _("Combo"):
self.app.inform.emit(_("Painting polygons with method: lines."))
- cp = self.clear_polygon3(poly_buf,
+ cp = self.clear_polygon3(geo,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
@@ -3216,7 +2874,7 @@ class ToolPaint(FlatCAMTool, Gerber):
pass
else:
self.app.inform.emit(_("Failed. Painting polygons with method: seed."))
- cp = self.clear_polygon2(poly_buf,
+ cp = self.clear_polygon2(geo,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
@@ -3228,7 +2886,7 @@ class ToolPaint(FlatCAMTool, Gerber):
pass
else:
self.app.inform.emit(_("Failed. Painting polygons with method: standard."))
- cp = self.clear_polygon(poly_buf,
+ cp = self.clear_polygon(geo,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
@@ -3258,19 +2916,27 @@ class ToolPaint(FlatCAMTool, Gerber):
old_disp_number = disp_number
# log.debug("Polygons cleared: %d. Percentage done: %d%%" % (pol_nr, disp_number))
- # find the tooluid associated with the current tool_dia so we know where to add the tool solid_geometry
- for k, v in tools_storage.items():
- if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals, tool_dia)):
- current_uid = int(k)
- break
-
+ final_solid_geometry += cleared_geo
# add the solid_geometry to the current too in self.paint_tools (or tools_storage) dictionary and
# then reset the temporary list that stored that solid_geometry
tools_storage[current_uid]['solid_geometry'] = deepcopy(cleared_geo)
-
tools_storage[current_uid]['data']['name'] = name
cleared_geo[:] = []
+ # clean the progressive plotted shapes if it was used
+ if self.app.defaults["tools_paint_plotting"] == 'progressive':
+ self.temp_shapes.clear(update=True)
+
+ # delete tools with empty geometry
+ # look for keys in the tools_storage dict that have 'solid_geometry' values empty
+ for uid in list(tools_storage.keys()):
+ # if the solid_geometry (type=list) is empty
+ if not tools_storage[uid]['solid_geometry']:
+ tools_storage.pop(uid, None)
+
+ if not tools_storage:
+ return 'fail'
+
geo_obj.options["cnctooldia"] = str(tool_dia)
# this turn on the FlatCAMCNCJob plot for multiple tools
geo_obj.multigeo = True
@@ -3278,9 +2944,7 @@ class ToolPaint(FlatCAMTool, Gerber):
geo_obj.tools.clear()
geo_obj.tools = dict(tools_storage)
- # clean the progressive plotted shapes if it was used
- if self.app.defaults["tools_paint_plotting"] == 'progressive':
- self.temp_shapes.clear(update=True)
+ geo_obj.solid_geometry = cascaded_union(final_solid_geometry)
# test if at least one tool has solid_geometry. If no tool has solid_geometry we raise an Exception
has_solid_geo = 0
@@ -3328,18 +2992,8 @@ class ToolPaint(FlatCAMTool, Gerber):
else:
job_thread(app_obj=self.app)
- def paint_poly_area(self, obj, sel_obj,
- tooldia=None,
- overlap=None,
- order=None,
- margin=None,
- method=None,
- outname=None,
- connect=None,
- contour=None,
- tools_storage=None,
- plot=True,
- run_threaded=True):
+ def paint_poly_area(self, obj, sel_obj, tooldia=None, order=None, method=None,
+ outname=None, tools_storage=None, plot=True, run_threaded=True):
"""
Paints all polygons in this object that are within the sel_obj object
@@ -3361,20 +3015,6 @@ class ToolPaint(FlatCAMTool, Gerber):
"""
paint_method = method if method is not None else self.paintmethod_combo.get_value()
- if margin is not None:
- paint_margin = margin
- else:
- try:
- paint_margin = float(self.paintmargin_entry.get_value())
- except ValueError:
- # try to convert comma to decimal point. if it's still not working error message and return
- try:
- paint_margin = float(self.paintmargin_entry.get_value().replace(',', '.'))
- except ValueError:
- self.app.inform.emit('[ERROR_NOTCL] %s' %
- _("Wrong value format entered, use a number."))
- return
-
# determine if to use the progressive plotting
if self.app.defaults["tools_paint_plotting"] == 'progressive':
prog_plot = True
@@ -3383,11 +3023,8 @@ class ToolPaint(FlatCAMTool, Gerber):
proc = self.app.proc_container.new(_("Painting polygons..."))
name = outname if outname is not None else self.obj_name + "_paint"
-
- over = overlap if overlap is not None else float(self.app.defaults["tools_paintoverlap"]) / 100.0
- conn = connect if connect is not None else self.app.defaults["tools_pathconnect"]
- cont = contour if contour is not None else self.app.defaults["tools_paintcontour"]
order = order if order is not None else self.order_radio.get_value()
+ tools_storage = self.paint_tools if tools_storage is None else tools_storage
sorted_tools = []
if tooldia is not None:
@@ -3402,11 +3039,6 @@ class ToolPaint(FlatCAMTool, Gerber):
for row in range(self.tools_table.rowCount()):
sorted_tools.append(float(self.tools_table.item(row, 1).text()))
- if tools_storage is not None:
- tools_storage = tools_storage
- else:
- tools_storage = self.paint_tools
-
def recurse(geometry, reset=True):
"""
Creates a list of non-iterable linear geometry objects.
@@ -3449,16 +3081,13 @@ class ToolPaint(FlatCAMTool, Gerber):
log.debug("Paint Tool. Normal painting area task started.")
if isinstance(obj, FlatCAMGerber):
if app_obj.defaults["gerber_buffering"] == 'no':
- app_obj.inform.emit('%s %s %s' %
- (_("Paint Tool."),
- _("Normal painting area task started."),
+ app_obj.inform.emit('%s %s' %
+ (_("Paint Tool. Normal painting area task started."),
_("Buffering geometry...")))
else:
- app_obj.inform.emit('%s %s' %
- (_("Paint Tool."), _("Normal painting area task started.")))
+ app_obj.inform.emit(_("Paint Tool. Normal painting area task started."))
else:
- app_obj.inform.emit('%s %s' %
- (_("Paint Tool."), _("Normal painting area task started.")))
+ app_obj.inform.emit(_("Paint Tool. Normal painting area task started."))
tool_dia = None
if order == 'fwd':
@@ -3478,8 +3107,8 @@ class ToolPaint(FlatCAMTool, Gerber):
else:
target_geo = target_geo.buffer(0)
- geo_to_paint = target_geo.intersection(sel_obj)
+ geo_to_paint = target_geo.intersection(sel_obj)
painted_area = recurse(geo_to_paint)
try:
@@ -3496,6 +3125,9 @@ class ToolPaint(FlatCAMTool, Gerber):
current_uid = int(1)
geo_obj.solid_geometry = []
+ final_solid_geometry = []
+ old_disp_number = 0
+
for tool_dia in sorted_tools:
log.debug("Starting geometry processing for tool: %s" % str(tool_dia))
app_obj.inform.emit(
@@ -3512,23 +3144,42 @@ class ToolPaint(FlatCAMTool, Gerber):
current_uid = int(k)
break
+ if not current_uid:
+ return "fail"
+
+ # determine the tool parameters to use
+ over = float(tools_storage[current_uid]['data']['tools_paintoverlap']) / 100.0
+ conn = tools_storage[current_uid]['data']['tools_pathconnect']
+ cont = tools_storage[current_uid]['data']['tools_paintcontour']
+
+ paint_margin = float(tools_storage[current_uid]['data']['tools_paintmargin'])
+ poly_buf = []
+ for pol in painted_area:
+ buffered_pol = pol.buffer(-paint_margin)
+ if buffered_pol and not buffered_pol.is_empty:
+ poly_buf.append(buffered_pol)
+
+ if not poly_buf:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Margin parameter too big. Tool is not used"))
+ continue
+
# variables to display the percentage of work done
- geo_len = len(painted_area)
- old_disp_number = 0
+ geo_len = len(poly_buf)
+
log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
pol_nr = 0
- for geo in painted_area:
+
+ for geo in poly_buf:
try:
# Polygons are the only really paintable geometries, lines in theory have no area to be painted
if not isinstance(geo, Polygon):
continue
- poly_buf = geo.buffer(-paint_margin)
cp = None
if paint_method == _("Seed"):
# Type(cp) == FlatCAMRTreeStorage | None
- cp = self.clear_polygon2(poly_buf,
+ cp = self.clear_polygon2(geo,
tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over,
@@ -3538,7 +3189,7 @@ class ToolPaint(FlatCAMTool, Gerber):
elif paint_method == _("Lines"):
# Type(cp) == FlatCAMRTreeStorage | None
- cp = self.clear_polygon3(poly_buf,
+ cp = self.clear_polygon3(geo,
tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over,
@@ -3548,7 +3199,7 @@ class ToolPaint(FlatCAMTool, Gerber):
elif paint_method == _("Standard"):
# Type(cp) == FlatCAMRTreeStorage | None
- cp = self.clear_polygon(poly_buf,
+ cp = self.clear_polygon(geo,
tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over,
@@ -3574,7 +3225,7 @@ class ToolPaint(FlatCAMTool, Gerber):
else:
traces_el_dict[apval["size"]] = [geo_el]
- if 'follow' in geo_el and geo_el['follow'].within(poly_buf):
+ if 'follow' in geo_el and geo_el['follow'].within(geo):
if isinstance(geo_el['follow'], Point):
if apval["type"] == 'C':
if 'C' in flash_el_dict:
@@ -3683,7 +3334,7 @@ class ToolPaint(FlatCAMTool, Gerber):
cp.insert(lines_union)
elif paint_method == _("Combo"):
self.app.inform.emit(_("Painting polygons with method: lines."))
- cp = self.clear_polygon3(poly_buf,
+ cp = self.clear_polygon3(geo,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
@@ -3696,7 +3347,7 @@ class ToolPaint(FlatCAMTool, Gerber):
pass
else:
self.app.inform.emit(_("Failed. Painting polygons with method: seed."))
- cp = self.clear_polygon2(poly_buf,
+ cp = self.clear_polygon2(geo,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
@@ -3708,7 +3359,7 @@ class ToolPaint(FlatCAMTool, Gerber):
pass
else:
self.app.inform.emit(_("Failed. Painting polygons with method: standard."))
- cp = self.clear_polygon(poly_buf,
+ cp = self.clear_polygon(geo,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
@@ -3718,14 +3369,18 @@ class ToolPaint(FlatCAMTool, Gerber):
prog_plot=prog_plot)
if cp and cp.objects:
total_geometry += list(cp.get_objects())
+ final_solid_geometry += total_geometry
except FlatCAMApp.GracefulException:
return "fail"
- except Exception as e:
- log.debug("Could not Paint the polygons. %s" % str(e))
- self.app.inform.emit('[ERROR] %s\n%s' %
- (_("Could not do Paint All. Try a different combination of parameters. "
- "Or a different Method of paint"), str(e)))
- return
+ except Exception as err:
+ log.debug("Could not Paint the polygons. %s" % str(err))
+ self.app.inform.emit(
+ '[ERROR] %s\n%s' %
+ (_("Could not do Paint. Try a different combination of parameters. "
+ "Or a different strategy of paint"), str(err)
+ )
+ )
+ continue
pol_nr += 1
disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
@@ -3739,7 +3394,6 @@ class ToolPaint(FlatCAMTool, Gerber):
# add the solid_geometry to the current too in self.paint_tools (tools_storage)
# dictionary and then reset the temporary list that stored that solid_geometry
tools_storage[current_uid]['solid_geometry'] = deepcopy(total_geometry)
-
tools_storage[current_uid]['data']['name'] = name
total_geometry[:] = []
@@ -3748,16 +3402,14 @@ class ToolPaint(FlatCAMTool, Gerber):
self.temp_shapes.clear(update=True)
# delete tools with empty geometry
- keys_to_delete = []
# look for keys in the tools_storage dict that have 'solid_geometry' values empty
- for uid in tools_storage:
+ for uid in list(tools_storage.keys()):
# if the solid_geometry (type=list) is empty
if not tools_storage[uid]['solid_geometry']:
- keys_to_delete.append(uid)
+ tools_storage.pop(uid, None)
- # actual delete of keys from the tools_storage dict
- for k in keys_to_delete:
- tools_storage.pop(k, None)
+ if not tools_storage:
+ return 'fail'
geo_obj.options["cnctooldia"] = str(tool_dia)
# this turn on the FlatCAMCNCJob plot for multiple tools
@@ -3766,6 +3418,8 @@ class ToolPaint(FlatCAMTool, Gerber):
geo_obj.tools.clear()
geo_obj.tools = dict(tools_storage)
+ geo_obj.solid_geometry = cascaded_union(final_solid_geometry)
+
# test if at least one tool has solid_geometry. If no tool has solid_geometry we raise an Exception
has_solid_geo = 0
for tooluid in geo_obj.tools:
@@ -3786,18 +3440,18 @@ class ToolPaint(FlatCAMTool, Gerber):
# Initializes the new geometry object
def gen_paintarea_rest_machining(geo_obj, app_obj):
- assert isinstance(geo_obj, FlatCAMGeometry), \
- "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
+ # assert isinstance(geo_obj, FlatCAMGeometry), \
+ # "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
log.debug("Paint Tool. Rest machining painting area task started.")
if isinstance(obj, FlatCAMGerber):
if app_obj.defaults["gerber_buffering"] == 'no':
app_obj.inform.emit('%s %s %s' %
- (_("Paint Tool."),
- _("Rest machining painting area task started."),
+ (_("Paint Tool."), _("Rest machining painting area task started."),
_("Buffering geometry...")))
else:
- app_obj.inform.emit(_("Paint Tool. Rest machining painting area task started."))
+ app_obj.inform.emit('%s %s' %
+ (_("Paint Tool."), _("Rest machining painting area task started.")))
else:
app_obj.inform.emit('%s %s' %
(_("Paint Tool."), _("Rest machining painting area task started.")))
@@ -3808,6 +3462,8 @@ class ToolPaint(FlatCAMTool, Gerber):
cleared_geo = []
current_uid = int(1)
geo_obj.solid_geometry = []
+ final_solid_geometry = []
+ old_disp_number = 0
# this is were heavy lifting is done and creating the geometry to be painted
target_geo = obj.solid_geometry
@@ -3820,7 +3476,6 @@ class ToolPaint(FlatCAMTool, Gerber):
target_geo = target_geo.buffer(0)
geo_to_paint = target_geo.intersection(sel_obj)
-
painted_area = recurse(geo_to_paint)
try:
@@ -3843,35 +3498,61 @@ class ToolPaint(FlatCAMTool, Gerber):
)
app_obj.proc_container.update_view_text(' %d%%' % 0)
+ # find the tooluid associated with the current tool_dia so we know where to add the tool solid_geometry
+ for k, v in tools_storage.items():
+ if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals, tool_dia)):
+ current_uid = int(k)
+ break
+
+ if not current_uid:
+ return "fail"
+
+ painted_area = recurse(obj.solid_geometry)
+
+ # determine the tool parameters to use
+ over = float(tools_storage[current_uid]['data']['tools_paintoverlap']) / 100.0
+ conn = tools_storage[current_uid]['data']['tools_pathconnect']
+ cont = tools_storage[current_uid]['data']['tools_paintcontour']
+
+ paint_margin = float(tools_storage[current_uid]['data']['tools_paintmargin'])
+ poly_buf = []
+ for pol in painted_area:
+ pol = Polygon(pol) if not isinstance(pol, Polygon) else pol
+ buffered_pol = pol.buffer(-paint_margin)
+ if buffered_pol and not buffered_pol.is_empty:
+ poly_buf.append(buffered_pol)
+
+ if not poly_buf:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Margin parameter too big. Tool is not used"))
+ continue
+
# variables to display the percentage of work done
- geo_len = len(painted_area)
- old_disp_number = 0
+ geo_len = len(poly_buf)
+
log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
pol_nr = 0
- for geo in painted_area:
+
+
+ for geo in poly_buf:
try:
- geo = Polygon(geo) if not isinstance(geo, Polygon) else geo
- poly_buf = geo.buffer(-paint_margin)
cp = None
if paint_method == _("Standard"):
# Type(cp) == FlatCAMRTreeStorage | None
- cp = self.clear_polygon(poly_buf, tooldia=tool_dia,
+ cp = self.clear_polygon(geo, tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over, contour=cont, connect=conn,
prog_plot=prog_plot)
-
elif paint_method == _("Seed"):
# Type(cp) == FlatCAMRTreeStorage | None
- cp = self.clear_polygon2(poly_buf, tooldia=tool_dia,
+ cp = self.clear_polygon2(geo, tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over, contour=cont, connect=conn,
prog_plot=prog_plot)
-
elif paint_method == _("Lines"):
# Type(cp) == FlatCAMRTreeStorage | None
- cp = self.clear_polygon3(poly_buf, tooldia=tool_dia,
+ cp = self.clear_polygon3(geo, tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over, contour=cont, connect=conn,
prog_plot=prog_plot)
@@ -3894,7 +3575,7 @@ class ToolPaint(FlatCAMTool, Gerber):
else:
copper_el_dict[apval["size"]] = [geo_el]
- if 'follow' in geo_el and geo_el['follow'].within(poly_buf):
+ if 'follow' in geo_el and geo_el['follow'].within(geo):
if isinstance(geo_el['follow'], Point):
if apval["type"] == 'C':
if 'C' in flash_el_dict:
@@ -4003,7 +3684,7 @@ class ToolPaint(FlatCAMTool, Gerber):
cp.insert(lines_union)
elif paint_method == _("Combo"):
self.app.inform.emit(_("Painting polygons with method: lines."))
- cp = self.clear_polygon3(poly_buf,
+ cp = self.clear_polygon3(geo,
tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over,
@@ -4015,7 +3696,7 @@ class ToolPaint(FlatCAMTool, Gerber):
pass
else:
self.app.inform.emit(_("Failed. Painting polygons with method: seed."))
- cp = self.clear_polygon2(poly_buf,
+ cp = self.clear_polygon2(geo,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
@@ -4027,7 +3708,7 @@ class ToolPaint(FlatCAMTool, Gerber):
pass
else:
self.app.inform.emit(_("Failed. Painting polygons with method: standard."))
- cp = self.clear_polygon(poly_buf,
+ cp = self.clear_polygon(geo,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
@@ -4055,29 +3736,33 @@ class ToolPaint(FlatCAMTool, Gerber):
old_disp_number = disp_number
# log.debug("Polygons cleared: %d. Percentage done: %d%%" % (pol_nr, disp_number))
- # find the tooluid associated with the current tool_dia so we know where to add the tool solid_geometry
- for k, v in tools_storage.items():
- if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals, tool_dia)):
- current_uid = int(k)
- break
-
+ final_solid_geometry += cleared_geo
# add the solid_geometry to the current too in self.paint_tools (or tools_storage) dictionary and
# then reset the temporary list that stored that solid_geometry
tools_storage[current_uid]['solid_geometry'] = deepcopy(cleared_geo)
-
tools_storage[current_uid]['data']['name'] = name
cleared_geo[:] = []
+ # clean the progressive plotted shapes if it was used
+ if self.app.defaults["tools_paint_plotting"] == 'progressive':
+ self.temp_shapes.clear(update=True)
+
+ # delete tools with empty geometry
+ # look for keys in the tools_storage dict that have 'solid_geometry' values empty
+ for uid in list(tools_storage.keys()):
+ # if the solid_geometry (type=list) is empty
+ if not tools_storage[uid]['solid_geometry']:
+ tools_storage.pop(uid, None)
+
+ if not tools_storage:
+ return 'fail'
+
geo_obj.options["cnctooldia"] = str(tool_dia)
# this turn on the FlatCAMCNCJob plot for multiple tools
geo_obj.multigeo = True
geo_obj.multitool = True
geo_obj.tools.clear()
- geo_obj.tools = dict(self.paint_tools)
-
- # clean the progressive plotted shapes if it was used
- if self.app.defaults["tools_paint_plotting"] == 'progressive':
- self.temp_shapes.clear(update=True)
+ geo_obj.tools = dict(tools_storage)
# test if at least one tool has solid_geometry. If no tool has solid_geometry we raise an Exception
has_solid_geo = 0
@@ -4351,6 +4036,13 @@ class ToolPaint(FlatCAMTool, Gerber):
return
self.app.inform.emit('[success] %s' % _("Tool from DB added in Tool Table."))
+ # select last tool added
+ toolid = res
+ for row in range(self.tools_table.rowCount()):
+ if int(self.tools_table.item(row, 3).text()) == toolid:
+ self.tools_table.selectRow(row)
+ self.on_row_selection_change()
+
def on_paint_tool_from_db_inserted(self, tool):
"""
Called from the Tools DB object through a App method when adding a tool from Tools Database
@@ -4392,9 +4084,9 @@ class ToolPaint(FlatCAMTool, Gerber):
self.paint_tools.update({
tooluid: {
'tooldia': float('%.*f' % (self.decimals, tooldia)),
- 'offset': 'Path',
- 'offset_value': 0.0,
- 'type': 'Iso',
+ 'offset': tool['offset'],
+ 'offset_value': tool['offset_value'],
+ 'type': tool['type'],
'tool_type': tool['tool_type'],
'data': deepcopy(tool['data']),
'solid_geometry': []
@@ -4407,6 +4099,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.ui_connect()
self.build_ui()
+ return tooluid
# if self.tools_table.rowCount() != 0:
# self.param_frame.setDisabled(False)
From 9a741394979a4b82389826afd264d68e77d12dc5 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 30 Mar 2020 23:56:38 +0300
Subject: [PATCH 142/209] - fixed some issues in Paint Tool
---
README.md | 1 +
flatcamTools/ToolPaint.py | 6 +++---
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 01845106..e75e8fd6 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
30.03.2020
- working to update the Paint Tool
+- fixed some issues in Paint Tool
29.03.2020
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 51e6c9e3..9cf45655 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -984,9 +984,9 @@ class ToolPaint(FlatCAMTool, Gerber):
self.default_data.update({
"name": '_paint',
"plot": self.app.defaults["geometry_plot"],
- "cutz": float(self.cutz_entry.get_value()),
- "vtipdia": float(self.tipdia_entry.get_value()),
- "vtipangle": float(self.tipangle_entry.get_value()),
+ "cutz": float(self.app.defaults["tools_paintcutz"],),
+ "vtipdia": float(self.app.defaults["tools_painttipdia"],),
+ "vtipangle": float(self.app.defaults["tools_painttipangle"],),
"travelz": float(self.app.defaults["geometry_travelz"]),
"feedrate": float(self.app.defaults["geometry_feedrate"]),
"feedrate_z": float(self.app.defaults["geometry_feedrate_z"]),
From 1d13b997f2a1751d96da846b6f4f893b62ecbe0c Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 1 Apr 2020 00:09:50 +0300
Subject: [PATCH 143/209] - updated the SVG parser to take into consideration
the 'Close' svg element and paths that are made from a single line (we may
need to switch to svgpathtools module)
---
FlatCAMApp.py | 4 ++--
README.md | 4 ++++
flatcamParsers/ParseSVG.py | 35 +++++++++++++++++++++++++++++++----
3 files changed, 37 insertions(+), 6 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index aec238e4..157d9f6b 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -5323,8 +5323,8 @@ class App(QtCore.QObject):
# try to quit the Socket opened by ArgsThread class
try:
self.new_launch.listener.close()
- except Exception:
- pass
+ except Exception as err:
+ log.debug("App.quit_application() --> %s" % str(err))
# quit app by signalling for self.kill_app() method
self.close_app_signal.emit()
diff --git a/README.md b/README.md
index e75e8fd6..97b4b23d 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+1.04.2020
+
+- updated the SVG parser to take into consideration the 'Close' svg element and paths that are made from a single line (we may need to switch to svgpathtools module)
+
30.03.2020
- working to update the Paint Tool
diff --git a/flatcamParsers/ParseSVG.py b/flatcamParsers/ParseSVG.py
index edff621f..d5634944 100644
--- a/flatcamParsers/ParseSVG.py
+++ b/flatcamParsers/ParseSVG.py
@@ -21,7 +21,7 @@
# import xml.etree.ElementTree as ET
from svg.path import Line, Arc, CubicBezier, QuadraticBezier, parse_path
-from svg.path.path import Move
+from svg.path.path import Move, Close
from shapely.geometry import LineString, LinearRing, MultiLineString
from shapely.affinity import skew, affine_transform, rotate
import numpy as np
@@ -69,6 +69,7 @@ def path2shapely(path, object_type, res=1.0):
geometry = []
geo_element = None
rings = []
+ closed = False
for component in path:
# Line
@@ -88,7 +89,8 @@ def path2shapely(path, object_type, res=1.0):
# How many points to use in the discrete representation.
length = component.length(res / 10.0)
- steps = int(length / res + 0.5)
+ # steps = int(length / res + 0.5)
+ steps = int(length) * 2
# solve error when step is below 1,
# it may cause other problems, but LineString needs at least two points
@@ -109,11 +111,29 @@ def path2shapely(path, object_type, res=1.0):
# Move
if isinstance(component, Move):
+ if not points:
+ continue
+ else:
+ rings.append(points)
+ if closed is False:
+ points = []
+ else:
+ closed = False
+ start = component.start
+ x, y = start.real, start.imag
+ points = [(x, y)]
+ continue
+
+ closed = False
+
+ # Close
+ if isinstance(component, Close):
if not points:
continue
else:
rings.append(points)
points = []
+ closed = True
continue
log.warning("I don't know what this is: %s" % str(component))
continue
@@ -122,8 +142,12 @@ def path2shapely(path, object_type, res=1.0):
if points:
rings.append(points)
+ try:
+ rings = MultiLineString(rings)
+ except Exception as e:
+ log.debug("ParseSVG.path2shapely() MString --> %s" % str(e))
+ return None
- rings = MultiLineString(rings)
if len(rings) > 0:
if len(rings) == 1 and not isinstance(rings, MultiLineString):
# Polygons are closed and require more than 2 points
@@ -139,7 +163,10 @@ def path2shapely(path, object_type, res=1.0):
for line in rings:
coords.append(line.coords[0])
coords.append(line.coords[1])
- geo_element = Polygon(coords)
+ try:
+ geo_element = Polygon(coords)
+ except Exception:
+ geo_element = LineString(coords)
geometry.append(geo_element)
return geometry
From 3d39916b5feee6155df329f5359947fc272662f1 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 1 Apr 2020 18:45:20 +0300
Subject: [PATCH 144/209] - minor changes to increase compatibility with Python
3.8
---
FlatCAMApp.py | 14 +++++---
FlatCAMCommon.py | 4 +--
FlatCAMObj.py | 6 ++--
ObjectCollection.py | 2 +-
README.md | 1 +
flatcamEditors/FlatCAMExcEditor.py | 2 +-
flatcamEditors/FlatCAMGeoEditor.py | 12 +++----
flatcamEditors/FlatCAMGrbEditor.py | 14 ++++----
flatcamGUI/GUIElements.py | 8 ++---
flatcamParsers/ParseExcellon.py | 2 +-
flatcamParsers/ParseGerber.py | 2 +-
flatcamTools/ToolDblSided.py | 2 +-
flatcamTools/ToolPanelize.py | 2 +-
flatcamTools/ToolProperties.py | 2 +-
flatcamTools/ToolRulesCheck.py | 52 +++++++++++++++---------------
flatcamTools/ToolTransform.py | 12 +++----
tclCommands/TclCommandPanelize.py | 2 +-
17 files changed, 72 insertions(+), 67 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 157d9f6b..e95e6085 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -5317,8 +5317,8 @@ class App(QtCore.QObject):
# try to quit the QThread that run ArgsThread class
try:
self.th.quit()
- except Exception:
- pass
+ except Exception as e:
+ log.debug("App.final_save() --> %s" % str(e))
# try to quit the Socket opened by ArgsThread class
try:
@@ -5327,7 +5327,11 @@ class App(QtCore.QObject):
log.debug("App.quit_application() --> %s" % str(err))
# quit app by signalling for self.kill_app() method
- self.close_app_signal.emit()
+ # self.close_app_signal.emit()
+ QtWidgets.qApp.quit()
+ # When the main event loop is not started yet in which case the qApp.quit() will do nothing
+ # we use the following command
+ sys.exit(0)
def kill_app(self):
QtWidgets.qApp.quit()
@@ -10178,7 +10182,7 @@ class App(QtCore.QObject):
filenames, _f = QtWidgets.QFileDialog.getOpenFileNames(caption=_("Import SVG"),
filter=_filter_)
- if type_of_obj is not "geometry" and type_of_obj is not "gerber":
+ if type_of_obj != "geometry" and type_of_obj != "gerber":
type_of_obj = "geometry"
filenames = [str(filename) for filename in filenames]
@@ -10211,7 +10215,7 @@ class App(QtCore.QObject):
filenames, _f = QtWidgets.QFileDialog.getOpenFileNames(caption=_("Import DXF"),
filter=_filter_)
- if type_of_obj is not "geometry" and type_of_obj is not "gerber":
+ if type_of_obj != "geometry" and type_of_obj != "gerber":
type_of_obj = "geometry"
filenames = [str(filename) for filename in filenames]
diff --git a/FlatCAMCommon.py b/FlatCAMCommon.py
index 08142a9e..8940542f 100644
--- a/FlatCAMCommon.py
+++ b/FlatCAMCommon.py
@@ -261,7 +261,7 @@ class BookmarkManager(QtWidgets.QWidget):
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Title entry is empty."))
return 'fail'
- if 'link' is kwargs:
+ if 'link' in kwargs:
link = kwargs['link']
else:
link = self.link_entry.get_value()
@@ -1325,7 +1325,7 @@ class ToolsDB(QtWidgets.QWidget):
default_data['toolchangez'] = self.table_widget.cellWidget(row, col).get_value()
elif column_header_text == _('Start Z'):
default_data['startz'] = float(self.table_widget.item(row, col).text()) \
- if self.table_widget.item(row, col).text() is not '' else None
+ if self.table_widget.item(row, col).text() != '' else None
elif column_header_text == _('End Z'):
default_data['endz'] = self.table_widget.cellWidget(row, col).get_value()
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index a267856f..ed31bb98 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -567,7 +567,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
FlatCAMGerber.merge(grb, grb_final)
else: # If not list, just append
for option in grb.options:
- if option is not 'name':
+ if option != 'name':
try:
grb_final.options[option] = grb.options[option]
except KeyError:
@@ -2507,7 +2507,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
for exc in flattened_list:
# copy options of the current excellon obj to the final excellon obj
for option in exc.options:
- if option is not 'name':
+ if option != 'name':
try:
exc_final.options[option] = exc.options[option]
except Exception:
@@ -6440,7 +6440,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
for geo_obj in geo_list:
for option in geo_obj.options:
- if option is not 'name':
+ if option != 'name':
try:
new_options[option] = deepcopy(geo_obj.options[option])
except Exception as e:
diff --git a/ObjectCollection.py b/ObjectCollection.py
index e0f0bd4c..f015b031 100644
--- a/ObjectCollection.py
+++ b/ObjectCollection.py
@@ -518,7 +518,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
self.endInsertRows()
# Expand group
- if group.child_count() is 1:
+ if group.child_count() == 1:
self.view.setExpanded(group_index, True)
self.app.should_we_save = True
diff --git a/README.md b/README.md
index 97b4b23d..840a9b4a 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
1.04.2020
- updated the SVG parser to take into consideration the 'Close' svg element and paths that are made from a single line (we may need to switch to svgpathtools module)
+- minor changes to increase compatibility with Python 3.8
30.03.2020
diff --git a/flatcamEditors/FlatCAMExcEditor.py b/flatcamEditors/FlatCAMExcEditor.py
index b53c0006..60ce3d6a 100644
--- a/flatcamEditors/FlatCAMExcEditor.py
+++ b/flatcamEditors/FlatCAMExcEditor.py
@@ -3393,7 +3393,7 @@ class FlatCAMExcEditor(QtCore.QObject):
self.app.log.debug("on_tool_select('%s')" % tool)
- if self.last_tool_selected is None and current_tool is not 'drill_select':
+ if self.last_tool_selected is None and current_tool != 'drill_select':
# self.draw_app.select_tool('drill_select')
self.complete = True
current_tool = 'drill_select'
diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py
index 23d47e06..cac6918a 100644
--- a/flatcamEditors/FlatCAMGeoEditor.py
+++ b/flatcamEditors/FlatCAMGeoEditor.py
@@ -1327,11 +1327,11 @@ class TransformEditorTool(FlatCAMTool):
# execute mirroring
for sha in shape_list:
- if axis is 'X':
+ if axis == 'X':
sha.mirror('X', (px, py))
self.app.inform.emit('[success] %s...' %
_('Flip on the Y axis done'))
- elif axis is 'Y':
+ elif axis == 'Y':
sha.mirror('Y', (px, py))
self.app.inform.emit('[success] %s' %
_('Flip on the X axis done'))
@@ -1368,9 +1368,9 @@ class TransformEditorTool(FlatCAMTool):
yminimal = min(yminlist)
for sha in shape_list:
- if axis is 'X':
+ if axis == 'X':
sha.skew(num, 0, point=(xminimal, yminimal))
- elif axis is 'Y':
+ elif axis == 'Y':
sha.skew(0, num, point=(xminimal, yminimal))
self.draw_app.replot()
@@ -1449,9 +1449,9 @@ class TransformEditorTool(FlatCAMTool):
with self.app.proc_container.new(_("Applying Offset")):
try:
for sha in shape_list:
- if axis is 'X':
+ if axis == 'X':
sha.offset((num, 0))
- elif axis is 'Y':
+ elif axis == 'Y':
sha.offset((0, num))
self.draw_app.replot()
diff --git a/flatcamEditors/FlatCAMGrbEditor.py b/flatcamEditors/FlatCAMGrbEditor.py
index 73fc0afa..d1cbb789 100644
--- a/flatcamEditors/FlatCAMGrbEditor.py
+++ b/flatcamEditors/FlatCAMGrbEditor.py
@@ -4254,7 +4254,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.app.log.debug("on_tool_select('%s')" % tool)
- if self.last_aperture_selected is None and current_tool is not 'select':
+ if self.last_aperture_selected is None and current_tool != 'select':
# self.draw_app.select_tool('select')
self.complete = True
current_tool = 'select'
@@ -5867,7 +5867,7 @@ class TransformEditorTool(FlatCAMTool):
# execute mirroring
for sel_el_shape in elem_list:
sel_el = sel_el_shape.geo
- if axis is 'X':
+ if axis == 'X':
if 'solid' in sel_el:
sel_el['solid'] = affinity.scale(sel_el['solid'], xfact=1, yfact=-1, origin=(px, py))
if 'follow' in sel_el:
@@ -5876,7 +5876,7 @@ class TransformEditorTool(FlatCAMTool):
sel_el['clear'] = affinity.scale(sel_el['clear'], xfact=1, yfact=-1, origin=(px, py))
self.app.inform.emit('[success] %s...' %
_('Flip on the Y axis done'))
- elif axis is 'Y':
+ elif axis == 'Y':
if 'solid' in sel_el:
sel_el['solid'] = affinity.scale(sel_el['solid'], xfact=-1, yfact=1, origin=(px, py))
if 'follow' in sel_el:
@@ -5924,14 +5924,14 @@ class TransformEditorTool(FlatCAMTool):
for sel_el_shape in elem_list:
sel_el = sel_el_shape.geo
- if axis is 'X':
+ if axis == 'X':
if 'solid' in sel_el:
sel_el['solid'] = affinity.skew(sel_el['solid'], num, 0, origin=(xminimal, yminimal))
if 'follow' in sel_el:
sel_el['follow'] = affinity.skew(sel_el['follow'], num, 0, origin=(xminimal, yminimal))
if 'clear' in sel_el:
sel_el['clear'] = affinity.skew(sel_el['clear'], num, 0, origin=(xminimal, yminimal))
- elif axis is 'Y':
+ elif axis == 'Y':
if 'solid' in sel_el:
sel_el['solid'] = affinity.skew(sel_el['solid'], 0, num, origin=(xminimal, yminimal))
if 'follow' in sel_el:
@@ -6031,14 +6031,14 @@ class TransformEditorTool(FlatCAMTool):
try:
for sel_el_shape in elem_list:
sel_el = sel_el_shape.geo
- if axis is 'X':
+ if axis == 'X':
if 'solid' in sel_el:
sel_el['solid'] = affinity.translate(sel_el['solid'], num, 0)
if 'follow' in sel_el:
sel_el['follow'] = affinity.translate(sel_el['follow'], num, 0)
if 'clear' in sel_el:
sel_el['clear'] = affinity.translate(sel_el['clear'], num, 0)
- elif axis is 'Y':
+ elif axis == 'Y':
if 'solid' in sel_el:
sel_el['solid'] = affinity.translate(sel_el['solid'], 0, num)
if 'follow' in sel_el:
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index c9fdc607..1b34118a 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -376,7 +376,7 @@ class FloatEntry(QtWidgets.QLineEdit):
evaled = eval(raw)
return float(evaled)
except Exception as e:
- if raw is not '':
+ if raw != '':
log.error("Could not evaluate val: %s, error: %s" % (str(raw), str(e)))
return None
@@ -422,7 +422,7 @@ class FloatEntry2(QtWidgets.QLineEdit):
evaled = eval(raw)
return float(evaled)
except Exception as e:
- if raw is not '':
+ if raw != '':
log.error("Could not evaluate val: %s, error: %s" % (str(raw), str(e)))
return None
@@ -602,7 +602,7 @@ class EvalEntry(QtWidgets.QLineEdit):
try:
evaled = eval(raw)
except Exception as e:
- if raw is not '':
+ if raw != '':
log.error("Could not evaluate val: %s, error: %s" % (str(raw), str(e)))
return None
return evaled
@@ -642,7 +642,7 @@ class EvalEntry2(QtWidgets.QLineEdit):
try:
evaled = eval(raw)
except Exception as e:
- if raw is not '':
+ if raw != '':
log.error("Could not evaluate val: %s, error: %s" % (str(raw), str(e)))
return None
return evaled
diff --git a/flatcamParsers/ParseExcellon.py b/flatcamParsers/ParseExcellon.py
index 7dc9ee35..1e7f2565 100644
--- a/flatcamParsers/ParseExcellon.py
+++ b/flatcamParsers/ParseExcellon.py
@@ -967,7 +967,7 @@ class Excellon(Geometry):
for drill in self.drills:
# poly = drill['point'].buffer(self.tools[drill['tool']]["C"]/2.0)
- if drill['tool'] is '':
+ if drill['tool'] == '':
self.app.inform.emit('[WARNING] %s' %
_("Excellon.create_geometry() -> a drill location was skipped "
"due of not having a tool associated.\n"
diff --git a/flatcamParsers/ParseGerber.py b/flatcamParsers/ParseGerber.py
index 54091259..deba943e 100644
--- a/flatcamParsers/ParseGerber.py
+++ b/flatcamParsers/ParseGerber.py
@@ -718,7 +718,7 @@ class Gerber(Geometry):
# so it can be processed by FlatCAM.
# But first test to see if the aperture type is "aperture macro". In that case
# we should not test for "size" key as it does not exist in this case.
- if self.apertures[current_aperture]["type"] is not "AM":
+ if self.apertures[current_aperture]["type"] != "AM":
if self.apertures[current_aperture]["size"] == 0:
self.apertures[current_aperture]["size"] = 1e-12
# log.debug(self.apertures[current_aperture])
diff --git a/flatcamTools/ToolDblSided.py b/flatcamTools/ToolDblSided.py
index 75071e88..89014940 100644
--- a/flatcamTools/ToolDblSided.py
+++ b/flatcamTools/ToolDblSided.py
@@ -606,7 +606,7 @@ class DblSidedTool(FlatCAMTool):
xscale, yscale = {"X": (1.0, -1.0), "Y": (-1.0, 1.0)}[axis]
dia = float(self.drill_dia.get_value())
- if dia is '':
+ if dia == '':
self.app.inform.emit('[WARNING_NOTCL] %s' %
_("No value or wrong format in Drill Dia entry. Add it and retry."))
return
diff --git a/flatcamTools/ToolPanelize.py b/flatcamTools/ToolPanelize.py
index fe381fc0..2cab2448 100644
--- a/flatcamTools/ToolPanelize.py
+++ b/flatcamTools/ToolPanelize.py
@@ -504,7 +504,7 @@ class Panelize(FlatCAMTool):
obj_fin.solid_geometry = []
for option in panel_obj.options:
- if option is not 'name':
+ if option != 'name':
try:
obj_fin.options[option] = panel_obj.options[option]
except KeyError:
diff --git a/flatcamTools/ToolProperties.py b/flatcamTools/ToolProperties.py
index da783097..97ba0e04 100644
--- a/flatcamTools/ToolProperties.py
+++ b/flatcamTools/ToolProperties.py
@@ -349,7 +349,7 @@ class Properties(FlatCAMTool):
# Options items
for option in obj.options:
- if option is 'name':
+ if option == 'name':
continue
self.treeWidget.addChild(options, [str(option), str(obj.options[option])], True)
diff --git a/flatcamTools/ToolRulesCheck.py b/flatcamTools/ToolRulesCheck.py
index eb236381..9ee387fc 100644
--- a/flatcamTools/ToolRulesCheck.py
+++ b/flatcamTools/ToolRulesCheck.py
@@ -1130,14 +1130,14 @@ class RulesCheck(FlatCAMTool):
if self.trace_size_cb.get_value():
copper_list = []
copper_name_1 = self.copper_t_object.currentText()
- if copper_name_1 is not '' and self.copper_t_cb.get_value():
+ if copper_name_1 != '' and self.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 is not '' and self.copper_b_cb.get_value():
+ if copper_name_2 !='' and self.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)
@@ -1162,7 +1162,7 @@ class RulesCheck(FlatCAMTool):
copper_t_obj = self.copper_t_object.currentText()
copper_t_dict = {}
- if copper_t_obj is not '':
+ if copper_t_obj != '':
copper_t_dict['name'] = deepcopy(copper_t_obj)
copper_t_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_t_obj).apertures)
@@ -1173,7 +1173,7 @@ class RulesCheck(FlatCAMTool):
if self.copper_b_cb.get_value():
copper_b_obj = self.copper_b_object.currentText()
copper_b_dict = {}
- if copper_b_obj is not '':
+ if copper_b_obj != '':
copper_b_dict['name'] = deepcopy(copper_b_obj)
copper_b_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_b_obj).apertures)
@@ -1195,17 +1195,17 @@ class RulesCheck(FlatCAMTool):
outline_dict = {}
copper_top = self.copper_t_object.currentText()
- if copper_top is not '' and self.copper_t_cb.get_value():
+ if copper_top != '' and self.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 is not '' and self.copper_b_cb.get_value():
+ if copper_bottom != '' and self.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 is not '' and self.out_cb.get_value():
+ if copper_outline != '' and self.out_cb.get_value():
outline_dict['name'] = deepcopy(copper_outline)
outline_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_outline).apertures)
@@ -1257,7 +1257,7 @@ class RulesCheck(FlatCAMTool):
if self.ss_t_cb.get_value():
silk_obj = self.ss_t_object.currentText()
- if silk_obj is not '':
+ if silk_obj != '':
silk_dict['name'] = deepcopy(silk_obj)
silk_dict['apertures'] = deepcopy(self.app.collection.get_by_name(silk_obj).apertures)
@@ -1267,7 +1267,7 @@ class RulesCheck(FlatCAMTool):
_("TOP -> Silk to Silk clearance"))))
if self.ss_b_cb.get_value():
silk_obj = self.ss_b_object.currentText()
- if silk_obj is not '':
+ if silk_obj != '':
silk_dict['name'] = deepcopy(silk_obj)
silk_dict['apertures'] = deepcopy(self.app.collection.get_by_name(silk_obj).apertures)
@@ -1295,25 +1295,25 @@ class RulesCheck(FlatCAMTool):
bottom_sm = False
silk_top = self.ss_t_object.currentText()
- if silk_top is not '' and self.ss_t_cb.get_value():
+ if silk_top != '' and self.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 is not '' and self.ss_b_cb.get_value():
+ if silk_bottom != '' and self.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 is not '' and self.sm_t_cb.get_value():
+ if sm_top != '' and self.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 is not '' and self.sm_b_cb.get_value():
+ if sm_bottom != '' and self.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
@@ -1358,17 +1358,17 @@ class RulesCheck(FlatCAMTool):
outline_dict = {}
silk_top = self.ss_t_object.currentText()
- if silk_top is not '' and self.ss_t_cb.get_value():
+ if silk_top != '' and self.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 is not '' and self.ss_b_cb.get_value():
+ if silk_bottom != '' and self.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 is not '' and self.out_cb.get_value():
+ if copper_outline != '' and self.out_cb.get_value():
outline_dict['name'] = deepcopy(copper_outline)
outline_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_outline).apertures)
@@ -1421,7 +1421,7 @@ class RulesCheck(FlatCAMTool):
if self.sm_t_cb.get_value():
solder_obj = self.sm_t_object.currentText()
- if solder_obj is not '':
+ if solder_obj != '':
sm_dict['name'] = deepcopy(solder_obj)
sm_dict['apertures'] = deepcopy(self.app.collection.get_by_name(solder_obj).apertures)
@@ -1431,7 +1431,7 @@ class RulesCheck(FlatCAMTool):
_("TOP -> Minimum Solder Mask Sliver"))))
if self.sm_b_cb.get_value():
solder_obj = self.sm_b_object.currentText()
- if solder_obj is not '':
+ if solder_obj != '':
sm_dict['name'] = deepcopy(solder_obj)
sm_dict['apertures'] = deepcopy(self.app.collection.get_by_name(solder_obj).apertures)
@@ -1454,23 +1454,23 @@ class RulesCheck(FlatCAMTool):
exc_2_dict = {}
copper_top = self.copper_t_object.currentText()
- if copper_top is not '' and self.copper_t_cb.get_value():
+ if copper_top != '' and self.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 is not '' and self.copper_b_cb.get_value():
+ if copper_bottom != '' and self.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 is not '' and self.e1_cb.get_value():
+ if excellon_1 != '' and self.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 is not '' and self.e2_cb.get_value():
+ if excellon_2 != '' and self.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)
@@ -1515,14 +1515,14 @@ class RulesCheck(FlatCAMTool):
if self.clearance_d2d_cb.get_value():
exc_list = []
exc_name_1 = self.e1_object.currentText()
- if exc_name_1 is not '' and self.e1_cb.get_value():
+ if exc_name_1 != '' and self.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 is not '' and self.e2_cb.get_value():
+ if exc_name_2 != '' and self.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)
@@ -1535,14 +1535,14 @@ class RulesCheck(FlatCAMTool):
if self.drill_size_cb.get_value():
exc_list = []
exc_name_1 = self.e1_object.currentText()
- if exc_name_1 is not '' and self.e1_cb.get_value():
+ if exc_name_1 != '' and self.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 is not '' and self.e2_cb.get_value():
+ if exc_name_2 != '' and self.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)
diff --git a/flatcamTools/ToolTransform.py b/flatcamTools/ToolTransform.py
index 8ce0eff5..72955eee 100644
--- a/flatcamTools/ToolTransform.py
+++ b/flatcamTools/ToolTransform.py
@@ -760,7 +760,7 @@ class ToolTransform(FlatCAMTool):
if isinstance(sel_obj, FlatCAMCNCjob):
self.app.inform.emit(_("CNCJob objects can't be mirrored/flipped."))
else:
- if axis is 'X':
+ if axis == 'X':
sel_obj.mirror('X', (px, py))
# add information to the object that it was changed and how much
# the axis is reversed because of the reference
@@ -770,7 +770,7 @@ class ToolTransform(FlatCAMTool):
sel_obj.options['mirror_y'] = True
self.app.inform.emit('[success] %s...' %
_('Flip on the Y axis done'))
- elif axis is 'Y':
+ elif axis == 'Y':
sel_obj.mirror('Y', (px, py))
# add information to the object that it was changed and how much
# the axis is reversed because of the reference
@@ -820,11 +820,11 @@ class ToolTransform(FlatCAMTool):
if isinstance(sel_obj, FlatCAMCNCjob):
self.app.inform.emit(_("CNCJob objects can't be skewed."))
else:
- if axis is 'X':
+ if axis == 'X':
sel_obj.skew(num, 0, point=(xminimal, yminimal))
# add information to the object that it was changed and how much
sel_obj.options['skew_x'] = num
- elif axis is 'Y':
+ elif axis == 'Y':
sel_obj.skew(0, num, point=(xminimal, yminimal))
# add information to the object that it was changed and how much
sel_obj.options['skew_y'] = num
@@ -906,11 +906,11 @@ class ToolTransform(FlatCAMTool):
if isinstance(sel_obj, FlatCAMCNCjob):
self.app.inform.emit(_("CNCJob objects can't be offset."))
else:
- if axis is 'X':
+ if axis == 'X':
sel_obj.offset((num, 0))
# add information to the object that it was changed and how much
sel_obj.options['offset_x'] = num
- elif axis is 'Y':
+ elif axis == 'Y':
sel_obj.offset((0, num))
# add information to the object that it was changed and how much
sel_obj.options['offset_y'] = num
diff --git a/tclCommands/TclCommandPanelize.py b/tclCommands/TclCommandPanelize.py
index 140c5e55..b40cc434 100644
--- a/tclCommands/TclCommandPanelize.py
+++ b/tclCommands/TclCommandPanelize.py
@@ -185,7 +185,7 @@ class TclCommandPanelize(TclCommand):
obj_fin.solid_geometry = []
for option in obj.options:
- if option is not 'name':
+ if option != 'name':
try:
obj_fin.options[option] = obj.options[option]
except Exception as e:
From 280eb1dc3a2cf086cdb9a88187daaeb0894c00a4 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Wed, 1 Apr 2020 18:59:53 +0300
Subject: [PATCH 145/209] - PEP8 changes
---
README.md | 1 +
flatcamEditors/FlatCAMExcEditor.py | 67 +++++++++++++-----------------
flatcamEditors/FlatCAMGeoEditor.py | 46 ++++++++------------
flatcamEditors/FlatCAMGrbEditor.py | 48 +++++++++++----------
4 files changed, 72 insertions(+), 90 deletions(-)
diff --git a/README.md b/README.md
index 840a9b4a..094cef18 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- updated the SVG parser to take into consideration the 'Close' svg element and paths that are made from a single line (we may need to switch to svgpathtools module)
- minor changes to increase compatibility with Python 3.8
+- PEP8 changes
30.03.2020
diff --git a/flatcamEditors/FlatCAMExcEditor.py b/flatcamEditors/FlatCAMExcEditor.py
index 60ce3d6a..65f9e497 100644
--- a/flatcamEditors/FlatCAMExcEditor.py
+++ b/flatcamEditors/FlatCAMExcEditor.py
@@ -398,7 +398,7 @@ class FCSlot(FCShapeTool):
try:
QtGui.QGuiApplication.restoreOverrideCursor()
- except Exception as e:
+ except Exception:
pass
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.draw_app.app.resource_location + '/aero_slot.png'))
QtGui.QGuiApplication.setOverrideCursor(self.cursor)
@@ -538,7 +538,7 @@ class FCSlot(FCShapeTool):
try:
QtGui.QGuiApplication.restoreOverrideCursor()
- except Exception as e:
+ except Exception:
pass
try:
@@ -600,7 +600,7 @@ class FCSlotArray(FCShapeTool):
try:
QtGui.QGuiApplication.restoreOverrideCursor()
- except Exception as e:
+ except Exception:
pass
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.draw_app.app.resource_location + '/aero_array.png'))
QtGui.QGuiApplication.setOverrideCursor(self.cursor)
@@ -677,9 +677,8 @@ class FCSlotArray(FCShapeTool):
self.draw_app.app.inform.emit('[ERROR_NOTCL] %s' %
_("The value is not Float. Check for comma instead of dot separator."))
return
- except Exception as e:
- self.draw_app.app.inform.emit('[ERROR_NOTCL] %s' %
- _("The value is mistyped. Check the value."))
+ except Exception:
+ self.draw_app.app.inform.emit('[ERROR_NOTCL] %s' % _("The value is mistyped. Check the value."))
return
if self.slot_array == 'Linear':
@@ -829,7 +828,7 @@ class FCSlotArray(FCShapeTool):
try:
QtGui.QGuiApplication.restoreOverrideCursor()
- except Exception as e:
+ except Exception:
pass
# add the point to slots if the diameter is a key in the dict, if not, create it add the drill location
@@ -1340,7 +1339,7 @@ class FCDrillSelect(DrawTool):
try:
QtGui.QGuiApplication.restoreOverrideCursor()
- except Exception as e:
+ except Exception:
pass
self.exc_editor_app = draw_app
@@ -1739,7 +1738,7 @@ class FlatCAMExcEditor(QtCore.QObject):
self.linear_box.addLayout(self.linear_form)
# Linear Drill Array direction
- self.drill_axis_label = QtWidgets.QLabel('%s:'% _('Direction'))
+ self.drill_axis_label = QtWidgets.QLabel('%s:' % _('Direction'))
self.drill_axis_label.setToolTip(
_("Direction on which the linear array is oriented:\n"
"- 'X' - horizontal axis \n"
@@ -2037,22 +2036,14 @@ class FlatCAMExcEditor(QtCore.QObject):
# ## Toolbar events and properties
self.tools_exc = {
- "drill_select": {"button": self.app.ui.select_drill_btn,
- "constructor": FCDrillSelect},
- "drill_add": {"button": self.app.ui.add_drill_btn,
- "constructor": FCDrillAdd},
- "drill_array": {"button": self.app.ui.add_drill_array_btn,
- "constructor": FCDrillArray},
- "slot_add": {"button": self.app.ui.add_slot_btn,
- "constructor": FCSlot},
- "slot_array": {"button": self.app.ui.add_slot_array_btn,
- "constructor": FCSlotArray},
- "drill_resize": {"button": self.app.ui.resize_drill_btn,
- "constructor": FCDrillResize},
- "drill_copy": {"button": self.app.ui.copy_drill_btn,
- "constructor": FCDrillCopy},
- "drill_move": {"button": self.app.ui.move_drill_btn,
- "constructor": FCDrillMove},
+ "drill_select": {"button": self.app.ui.select_drill_btn, "constructor": FCDrillSelect},
+ "drill_add": {"button": self.app.ui.add_drill_btn, "constructor": FCDrillAdd},
+ "drill_array": {"button": self.app.ui.add_drill_array_btn, "constructor": FCDrillArray},
+ "slot_add": {"button": self.app.ui.add_slot_btn, "constructor": FCSlot},
+ "slot_array": {"button": self.app.ui.add_slot_array_btn, "constructor": FCSlotArray},
+ "drill_resize": {"button": self.app.ui.resize_drill_btn, "constructor": FCDrillResize},
+ "drill_copy": {"button": self.app.ui.copy_drill_btn, "constructor": FCDrillCopy},
+ "drill_move": {"button": self.app.ui.move_drill_btn, "constructor": FCDrillMove},
}
# ## Data
@@ -2192,7 +2183,7 @@ class FlatCAMExcEditor(QtCore.QObject):
"operation": self.app.defaults["excellon_operation"],
"milling_type": self.app.defaults["excellon_milling_type"],
- "milling_dia":self.app.defaults["excellon_milling_dia"],
+ "milling_dia": self.app.defaults["excellon_milling_dia"],
"cutz": self.app.defaults["excellon_cutz"],
"multidepth": self.app.defaults["excellon_multidepth"],
@@ -2579,9 +2570,8 @@ class FlatCAMExcEditor(QtCore.QObject):
# each time a tool diameter is edited or added
self.olddia_newdia[tool_dia] = tool_dia
else:
- self.app.inform.emit('[WARNING_NOTCL] %s' %
- _("Tool already in the original or actual tool list.\n"
- "Save and reedit Excellon if you need to add this tool. "))
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Tool already in the original or actual tool list.\n"
+ "Save and reedit Excellon if you need to add this tool. "))
return
# since we add a new tool, we update also the initial state of the tool_table through it's dictionary
@@ -2621,9 +2611,8 @@ class FlatCAMExcEditor(QtCore.QObject):
deleted_tool_dia_list.append(float('%.*f' % (self.decimals, dd)))
else:
deleted_tool_dia_list.append(float('%.*f' % (self.decimals, dia)))
- except Exception as e:
- self.app.inform.emit('[WARNING_NOTCL] %s' %
- _("Select a tool in Tool Table"))
+ except Exception:
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("Select a tool in Tool Table"))
return
for deleted_tool_dia in deleted_tool_dia_list:
@@ -2871,7 +2860,7 @@ class FlatCAMExcEditor(QtCore.QObject):
def deactivate(self):
try:
QtGui.QGuiApplication.restoreOverrideCursor()
- except Exception as e:
+ except Exception:
pass
# adjust the status of the menu entries related to the editor
@@ -3468,7 +3457,7 @@ class FlatCAMExcEditor(QtCore.QObject):
self.pos = self.canvas.translate_coords(event_pos)
- if self.app.grid_status() == True:
+ if self.app.grid_status():
self.pos = self.app.geo_editor.snap(self.pos[0], self.pos[1])
else:
self.pos = (self.pos[0], self.pos[1])
@@ -3613,7 +3602,7 @@ class FlatCAMExcEditor(QtCore.QObject):
pos_canvas = self.canvas.translate_coords(event_pos)
- if self.app.grid_status() == True:
+ if self.app.grid_status():
pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1])
else:
pos = (pos_canvas[0], pos_canvas[1])
@@ -3625,7 +3614,7 @@ class FlatCAMExcEditor(QtCore.QObject):
if self.app.ui.popMenu.mouse_is_panning is False:
try:
QtGui.QGuiApplication.restoreOverrideCursor()
- except Exception as e:
+ except Exception:
pass
if self.active_tool.complete is False and not isinstance(self.active_tool, FCDrillSelect):
self.active_tool.complete = True
@@ -3704,7 +3693,7 @@ class FlatCAMExcEditor(QtCore.QObject):
for storage in self.storage_dict:
for obj in self.storage_dict[storage].get_objects():
if (sel_type is True and poly_selection.contains(obj.geo)) or \
- (sel_type is False and poly_selection.intersects(obj.geo)):
+ (sel_type is False and poly_selection.intersects(obj.geo)):
if obj in self.selected:
# remove the shape object from the selected shapes storage
@@ -3724,7 +3713,7 @@ class FlatCAMExcEditor(QtCore.QObject):
try:
self.tools_table_exc.cellPressed.disconnect()
- except Exception as e:
+ except Exception:
pass
# first deselect all rows (tools) in the Tools Table
@@ -3801,7 +3790,7 @@ class FlatCAMExcEditor(QtCore.QObject):
return
# ## Snap coordinates
- if self.app.grid_status() == True:
+ if self.app.grid_status():
x, y = self.app.geo_editor.snap(x, y)
# Update cursor
diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py
index cac6918a..9d6be36b 100644
--- a/flatcamEditors/FlatCAMGeoEditor.py
+++ b/flatcamEditors/FlatCAMGeoEditor.py
@@ -1805,7 +1805,7 @@ class DrawToolShape(object):
geoms.append(scale_recursion(local_geom))
return geoms
else:
- return affinity.scale(geom, xfactor, yfactor, origin=(px, py))
+ return affinity.scale(geom, xfactor, yfactor, origin=(px, py))
try:
self.geo = scale_recursion(self.geo)
@@ -3264,34 +3264,20 @@ class FlatCAMGeoEditor(QtCore.QObject):
# ## Toolbar events and properties
self.tools = {
- "select": {"button": self.app.ui.geo_select_btn,
- "constructor": FCSelect},
- "arc": {"button": self.app.ui.geo_add_arc_btn,
- "constructor": FCArc},
- "circle": {"button": self.app.ui.geo_add_circle_btn,
- "constructor": FCCircle},
- "path": {"button": self.app.ui.geo_add_path_btn,
- "constructor": FCPath},
- "rectangle": {"button": self.app.ui.geo_add_rectangle_btn,
- "constructor": FCRectangle},
- "polygon": {"button": self.app.ui.geo_add_polygon_btn,
- "constructor": FCPolygon},
- "text": {"button": self.app.ui.geo_add_text_btn,
- "constructor": FCText},
- "buffer": {"button": self.app.ui.geo_add_buffer_btn,
- "constructor": FCBuffer},
- "paint": {"button": self.app.ui.geo_add_paint_btn,
- "constructor": FCPaint},
- "eraser": {"button": self.app.ui.geo_eraser_btn,
- "constructor": FCEraser},
- "move": {"button": self.app.ui.geo_move_btn,
- "constructor": FCMove},
- "transform": {"button": self.app.ui.geo_transform_btn,
- "constructor": FCTransform},
- "copy": {"button": self.app.ui.geo_copy_btn,
- "constructor": FCCopy},
- "explode": {"button": self.app.ui.geo_explode_btn,
- "constructor": FCExplode}
+ "select": {"button": self.app.ui.geo_select_btn, "constructor": FCSelect},
+ "arc": {"button": self.app.ui.geo_add_arc_btn, "constructor": FCArc},
+ "circle": {"button": self.app.ui.geo_add_circle_btn, "constructor": FCCircle},
+ "path": {"button": self.app.ui.geo_add_path_btn, "constructor": FCPath},
+ "rectangle": {"button": self.app.ui.geo_add_rectangle_btn, "constructor": FCRectangle},
+ "polygon": {"button": self.app.ui.geo_add_polygon_btn, "constructor": FCPolygon},
+ "text": {"button": self.app.ui.geo_add_text_btn, "constructor": FCText},
+ "buffer": {"button": self.app.ui.geo_add_buffer_btn, "constructor": FCBuffer},
+ "paint": {"button": self.app.ui.geo_add_paint_btn, "constructor": FCPaint},
+ "eraser": {"button": self.app.ui.geo_eraser_btn, "constructor": FCEraser},
+ "move": {"button": self.app.ui.geo_move_btn, "constructor": FCMove},
+ "transform": {"button": self.app.ui.geo_transform_btn, "constructor": FCTransform},
+ "copy": {"button": self.app.ui.geo_copy_btn, "constructor": FCCopy},
+ "explode": {"button": self.app.ui.geo_explode_btn, "constructor": FCExplode}
}
# # ## Data
@@ -3343,6 +3329,8 @@ class FlatCAMGeoEditor(QtCore.QObject):
# signal that there is an action active like polygon or path
self.in_action = False
+ self.units = None
+
# this will flag if the Editor "tools" are launched from key shortcuts (True) or from menu toolbar (False)
self.launched_from_shortcuts = False
diff --git a/flatcamEditors/FlatCAMGrbEditor.py b/flatcamEditors/FlatCAMGrbEditor.py
index d1cbb789..b655656b 100644
--- a/flatcamEditors/FlatCAMGrbEditor.py
+++ b/flatcamEditors/FlatCAMGrbEditor.py
@@ -423,7 +423,7 @@ class FCPadArray(FCShapeTool):
try:
QtGui.QGuiApplication.restoreOverrideCursor()
- except Exception as e:
+ except Exception:
pass
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.draw_app.app.resource_location + '/aero_array.png'))
QtGui.QGuiApplication.setOverrideCursor(self.cursor)
@@ -515,9 +515,8 @@ class FCPadArray(FCShapeTool):
self.draw_app.app.inform.emit('[ERROR_NOTCL] %s' %
_("The value is not Float. Check for comma instead of dot separator."))
return
- except Exception as e:
- self.draw_app.app.inform.emit('[ERROR_NOTCL] %s' %
- _("The value is mistyped. Check the value."))
+ except Exception:
+ self.draw_app.app.inform.emit('[ERROR_NOTCL] %s' % _("The value is mistyped. Check the value."))
return
if self.pad_array == 'Linear':
@@ -3103,6 +3102,10 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.conversion_factor = 1
+ self.apertures_row = 0
+
+ self.complete = True
+
self.set_ui()
log.debug("Initialization of the FlatCAM Gerber Editor is finished ...")
@@ -3332,8 +3335,8 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.storage_dict[ap_id]['geometry'] = []
- # self.olddia_newdia dict keeps the evidence on current aperture codes as keys and gets updated on values
- # each time a aperture code is edited or added
+ # self.olddia_newdia dict keeps the evidence on current aperture codes as keys and
+ # gets updated on values each time a aperture code is edited or added
self.olddia_newdia[ap_id] = ap_id
else:
if ap_id not in self.olddia_newdia:
@@ -3945,9 +3948,9 @@ class FlatCAMGrbEditor(QtCore.QObject):
@staticmethod
def worker_job(app_obj):
with app_obj.app.proc_container.new('%s ...' % _("Loading Gerber into Editor")):
- # ############################################################# ##
+ # ###############################################################
# APPLY CLEAR_GEOMETRY on the SOLID_GEOMETRY
- # ############################################################# ##
+ # ###############################################################
# list of clear geos that are to be applied to the entire file
global_clear_geo = []
@@ -3968,9 +3971,9 @@ class FlatCAMGrbEditor(QtCore.QObject):
# we subtract the big "negative" (clear) geometry from each solid polygon but only the part of
# clear geometry that fits inside the solid. otherwise we may loose the solid
- for apid in app_obj.gerber_obj.apertures:
+ for ap_id in app_obj.gerber_obj.apertures:
temp_solid_geometry = []
- if 'geometry' in app_obj.gerber_obj.apertures[apid]:
+ if 'geometry' in app_obj.gerber_obj.apertures[ap_id]:
# for elem in self.gerber_obj.apertures[apid]['geometry']:
# if 'solid' in elem:
# solid_geo = elem['solid']
@@ -3998,7 +4001,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
# if 'follow' in elem:
# new_elem['follow'] = solid_geo
# temp_elem.append(deepcopy(new_elem))
- for elem in app_obj.gerber_obj.apertures[apid]['geometry']:
+ for elem in app_obj.gerber_obj.apertures[ap_id]['geometry']:
new_elem = {}
if 'solid' in elem:
solid_geo = elem['solid']
@@ -4019,7 +4022,8 @@ class FlatCAMGrbEditor(QtCore.QObject):
new_elem['follow'] = elem['follow']
temp_solid_geometry.append(deepcopy(new_elem))
- app_obj.gerber_obj.apertures[apid]['geometry'] = deepcopy(temp_solid_geometry)
+ app_obj.gerber_obj.apertures[ap_id]['geometry'] = deepcopy(temp_solid_geometry)
+
log.warning("Polygon difference done for %d apertures." % len(app_obj.gerber_obj.apertures))
try:
@@ -4028,9 +4032,9 @@ class FlatCAMGrbEditor(QtCore.QObject):
app_obj.results.append(
app_obj.pool.apply_async(app_obj.add_apertures, args=(ap_id, ap_dict))
)
- except Exception as e:
+ except Exception as ee:
log.debug(
- "FlatCAMGrbEditor.edit_fcgerber.worker_job() Adding processes to pool --> %s" % str(e))
+ "FlatCAMGrbEditor.edit_fcgerber.worker_job() Adding processes to pool --> %s" % str(ee))
traceback.print_exc()
output = []
@@ -4222,7 +4226,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
except KeyError:
self.app.inform.emit('[ERROR_NOTCL] %s' %
_("There are no Aperture definitions in the file. Aborting Gerber creation."))
- except Exception as e:
+ except Exception:
msg = '[ERROR] %s' % \
_("An internal error has occurred. See shell.\n")
msg += traceback.format_exc()
@@ -4240,7 +4244,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.results = []
return
- self.app.inform.emit('[success] %s' % _("Done. Gerber editing finished."))
+ self.app.inform.emit('[success] %s' % _("Done. Gerber editing finished."))
# make sure to clean the previous results
self.results = []
@@ -4395,7 +4399,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.pos = self.canvas.translate_coords(event_pos)
- if self.app.grid_status() == True:
+ if self.app.grid_status():
self.pos = self.app.geo_editor.snap(self.pos[0], self.pos[1])
else:
self.pos = (self.pos[0], self.pos[1])
@@ -4462,7 +4466,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
right_button = 3
pos_canvas = self.canvas.translate_coords(event_pos)
- if self.app.grid_status() == True:
+ if self.app.grid_status():
pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1])
else:
pos = (pos_canvas[0], pos_canvas[1])
@@ -4625,7 +4629,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
return
# # ## Snap coordinates
- if self.app.grid_status() == True:
+ if self.app.grid_status():
x, y = self.app.geo_editor.snap(x, y)
# Update cursor
@@ -4755,7 +4759,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
try:
self.shapes.add(shape=geometry.geo, color=color, face_color=color, layer=0, tolerance=self.tolerance)
- except AttributeError as e:
+ except AttributeError:
if type(geometry) == Point:
return
if len(color) == 9:
@@ -5069,12 +5073,12 @@ class FlatCAMGrbEditor(QtCore.QObject):
area = geo_el.geo['solid'].area
try:
upper_threshold_val = self.ma_upper_threshold_entry.get_value()
- except Exception as e:
+ except Exception:
return
try:
lower_threshold_val = self.ma_lower_threshold_entry.get_value()
- except Exception as e:
+ except Exception:
lower_threshold_val = 0.0
if float(upper_threshold_val) > area > float(lower_threshold_val):
From 376c8058d96b8bbfeafd4d188d8be743bad5b3b7 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 4 Apr 2020 18:02:40 +0300
Subject: [PATCH 146/209] - fixed the Repeated code parsing in Excellon Parse
---
README.md | 4 +
flatcamParsers/ParseExcellon.py | 126 +++++++++++++++++---------------
2 files changed, 72 insertions(+), 58 deletions(-)
diff --git a/README.md b/README.md
index 094cef18..d8ff21c6 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+4.04.2020
+
+- fixed the Repeated code parsing in Excellon Parse
+
1.04.2020
- updated the SVG parser to take into consideration the 'Close' svg element and paths that are made from a single line (we may need to switch to svgpathtools module)
diff --git a/flatcamParsers/ParseExcellon.py b/flatcamParsers/ParseExcellon.py
index 1e7f2565..406bbb16 100644
--- a/flatcamParsers/ParseExcellon.py
+++ b/flatcamParsers/ParseExcellon.py
@@ -618,82 +618,92 @@ class Excellon(Geometry):
match = self.coordsnoperiod_re.search(eline)
if match:
matchr = self.repeat_re.search(eline)
- if matchr:
+ if matchr: # if we have a repeat command
repeat = int(matchr.group(1))
- try:
- x = self.parse_number(match.group(1))
- repeating_x = current_x
- current_x = x
- except TypeError:
- x = current_x
- repeating_x = 0
- except Exception:
- return
+ if match.group(1):
+ repeating_x = self.parse_number(match.group(1))
+ else:
+ repeating_x = 0
- try:
- y = self.parse_number(match.group(2))
- repeating_y = current_y
- current_y = y
- except TypeError:
- y = current_y
- repeating_y = 0
- except Exception:
- return
+ if match.group(2):
+ repeating_y = self.parse_number(match.group(2))
+ else:
+ repeating_y = 0
- if x is None or y is None:
- log.error("Missing coordinates")
+ coordx = current_x
+ coordy = current_y
+
+ while repeat > 0:
+ if repeating_x:
+ coordx += repeating_x
+ if repeating_y:
+ coordy += repeating_y
+ self.drills.append({'point': Point((coordx, coordy)), 'tool': current_tool})
+
+ repeat -= 1
+ current_x = coordx
+ current_y = coordy
continue
- # ## Excellon Routing parse
- if len(re.findall("G00", eline)) > 0:
- self.match_routing_start = 'G00'
+ else: # those are normal coordinates
+ try:
+ x = self.parse_number(match.group(1))
+ current_x = x
+ except TypeError:
+ x = current_x
+ except Exception:
+ return
- # signal that there are milling slots operations
- self.defaults['excellon_drills'] = False
+ try:
+ y = self.parse_number(match.group(2))
+ current_y = y
+ except TypeError:
+ y = current_y
+ except Exception:
+ return
- self.routing_flag = 0
- slot_start_x = x
- slot_start_y = y
- continue
+ if x is None or y is None:
+ log.error("Missing coordinates")
+ continue
- if self.routing_flag == 0:
- if len(re.findall("G01", eline)) > 0:
- self.match_routing_stop = 'G01'
+ # ## Excellon Routing parse
+ if len(re.findall("G00", eline)) > 0:
+ self.match_routing_start = 'G00'
# signal that there are milling slots operations
self.defaults['excellon_drills'] = False
- self.routing_flag = 1
- slot_stop_x = x
- slot_stop_y = y
- self.slots.append(
- {
- 'start': Point(slot_start_x, slot_start_y),
- 'stop': Point(slot_stop_x, slot_stop_y),
- 'tool': current_tool
- }
- )
+ self.routing_flag = 0
+ slot_start_x = x
+ slot_start_y = y
continue
- if self.match_routing_start is None and self.match_routing_stop is None:
- if repeat == 0:
+ if self.routing_flag == 0:
+ if len(re.findall("G01", eline)) > 0:
+ self.match_routing_stop = 'G01'
+
+ # signal that there are milling slots operations
+ self.defaults['excellon_drills'] = False
+
+ self.routing_flag = 1
+ slot_stop_x = x
+ slot_stop_y = y
+ self.slots.append(
+ {
+ 'start': Point(slot_start_x, slot_start_y),
+ 'stop': Point(slot_stop_x, slot_stop_y),
+ 'tool': current_tool
+ }
+ )
+ continue
+
+ if self.match_routing_start is None and self.match_routing_stop is None:
# signal that there are drill operations
self.defaults['excellon_drills'] = True
self.drills.append({'point': Point((x, y)), 'tool': current_tool})
- else:
- coordx = x
- coordy = y
- while repeat > 0:
- if repeating_x:
- coordx = (repeat * x) + repeating_x
- if repeating_y:
- coordy = (repeat * y) + repeating_y
- self.drills.append({'point': Point((coordx, coordy)), 'tool': current_tool})
- repeat -= 1
- repeating_x = repeating_y = 0
- # log.debug("{:15} {:8} {:8}".format(eline, x, y))
- continue
+ # log.debug("{:15} {:8} {:8}".format(eline, x, y))
+ continue
# ## Coordinates with period: Use literally. # ##
match = self.coordsperiod_re.search(eline)
From bee2a9dddca45afe2946cdbc7e0ae0786d629004 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 5 Apr 2020 13:48:47 +0300
Subject: [PATCH 147/209] - made sure that the HDPI scaling attribute is set
before the QApplication is started - made sure that when saving a project,
the app will try to update the active object from UI form only if there is an
active object
---
FlatCAM.py | 10 +++++-----
FlatCAMApp.py | 4 +++-
README.md | 5 +++++
3 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/FlatCAM.py b/FlatCAM.py
index 02c56c9d..eb7410b2 100644
--- a/FlatCAM.py
+++ b/FlatCAM.py
@@ -55,6 +55,11 @@ if __name__ == '__main__':
# else:
# QGuiApplication.setAttribute(Qt.AA_EnableHighDpiScaling, False)
+ if hdpi_support == 2:
+ QtWidgets.QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
+ else:
+ QtWidgets.QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, False)
+
app = QtWidgets.QApplication(sys.argv)
# apply style
@@ -63,11 +68,6 @@ if __name__ == '__main__':
style = settings.value('style', type=str)
app.setStyle(style)
- if hdpi_support == 2:
- app.setAttribute(Qt.AA_EnableHighDpiScaling, True)
- else:
- app.setAttribute(Qt.AA_EnableHighDpiScaling, False)
-
fc = App()
sys.exit(app.exec_())
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index e95e6085..f23c700a 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -12809,7 +12809,9 @@ class App(QtCore.QObject):
# Capture the latest changes
# Current object
try:
- self.collection.get_active().read_form()
+ current_object = self.collection.get_active()
+ if current_object:
+ current_object.read_form()
except Exception as e:
self.log.debug("save_project() --> There was no active object. Skipping read_form. %s" % str(e))
pass
diff --git a/README.md b/README.md
index d8ff21c6..f540a075 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+5.04.2020
+
+- made sure that the HDPI scaling attribute is set before the QApplication is started
+- made sure that when saving a project, the app will try to update the active object from UI form only if there is an active object
+
4.04.2020
- fixed the Repeated code parsing in Excellon Parse
From b53c1c403a32a807278c14579cd035f545988c65 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 5 Apr 2020 16:32:16 +0300
Subject: [PATCH 148/209] - fix for contextual menus on canvas when using PyQt
versions > 5.12.1 - decision on which mouse button to use for panning is done
now once when setting the plotcanvas
---
FlatCAM.py | 4 ++--
FlatCAMApp.py | 28 +++++++++++++++++++++-------
README.md | 2 ++
flatcamGUI/GUIElements.py | 4 +++-
4 files changed, 28 insertions(+), 10 deletions(-)
diff --git a/FlatCAM.py b/FlatCAM.py
index eb7410b2..546877a3 100644
--- a/FlatCAM.py
+++ b/FlatCAM.py
@@ -69,5 +69,5 @@ if __name__ == '__main__':
app.setStyle(style)
fc = App()
-
- sys.exit(app.exec_())
+ # sys.exit(app.exec_())
+ app.exec_()
\ No newline at end of file
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index f23c700a..d7e17179 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -5328,12 +5328,14 @@ class App(QtCore.QObject):
# quit app by signalling for self.kill_app() method
# self.close_app_signal.emit()
+
QtWidgets.qApp.quit()
# When the main event loop is not started yet in which case the qApp.quit() will do nothing
# we use the following command
sys.exit(0)
def kill_app(self):
+ # QtCore.QCoreApplication.quit()
QtWidgets.qApp.quit()
# When the main event loop is not started yet in which case the qApp.quit() will do nothing
# we use the following command
@@ -8667,8 +8669,8 @@ class App(QtCore.QObject):
def populate_cmenu_grids(self):
units = self.defaults['units'].lower()
- for act in self.ui.cmenu_gridmenu.actions():
- act.triggered.disconnect()
+ # for act in self.ui.cmenu_gridmenu.actions():
+ # act.triggered.disconnect()
self.ui.cmenu_gridmenu.clear()
sorted_list = sorted(self.defaults["global_grid_context_menu"][str(units)])
@@ -8807,13 +8809,13 @@ class App(QtCore.QObject):
if self.is_legacy is False:
event_pos = event.pos
- pan_button = 2 if self.defaults["global_pan_button"] == '2'else 3
- # Set the mouse button for panning
- self.plotcanvas.view.camera.pan_button_setting = pan_button
+ # pan_button = 2 if self.defaults["global_pan_button"] == '2'else 3
+ # # Set the mouse button for panning
+ # self.plotcanvas.view.camera.pan_button_setting = pan_button
else:
event_pos = (event.xdata, event.ydata)
# Matplotlib has the middle and right buttons mapped in reverse compared with VisPy
- pan_button = 3 if self.defaults["global_pan_button"] == '2' else 2
+ # pan_button = 3 if self.defaults["global_pan_button"] == '2' else 2
# So it can receive key presses
self.plotcanvas.native.setFocus()
@@ -8873,9 +8875,14 @@ class App(QtCore.QObject):
self.ui.popMenu.mouse_is_panning = False
- if not origin_click:
+ if origin_click is None:
# if the RMB is clicked and mouse is moving over plot then 'panning_action' is True
if event.button == pan_button and self.event_is_dragging == 1:
+
+ # if a popup menu is active don't change mouse_is_panning variable because is not True
+ if self.ui.popMenu.popup_active:
+ self.ui.popMenu.popup_active = False
+ return
self.ui.popMenu.mouse_is_panning = True
return
@@ -8977,6 +8984,8 @@ class App(QtCore.QObject):
# if the released mouse button was RMB then test if it was a panning motion or not, if not it was a context
# canvas menu
if event.button == right_button and self.ui.popMenu.mouse_is_panning is False: # right click
+ self.ui.popMenu.mouse_is_panning = False
+
self.cursor = QtGui.QCursor()
self.populate_cmenu_grids()
self.ui.popMenu.popup(self.cursor.pos())
@@ -12465,6 +12474,11 @@ class App(QtCore.QObject):
# So it can receive key presses
self.plotcanvas.native.setFocus()
+ if self.is_legacy is False:
+ pan_button = 2 if self.defaults["global_pan_button"] == '2'else 3
+ # Set the mouse button for panning
+ self.plotcanvas.view.camera.pan_button_setting = pan_button
+
self.mm = self.plotcanvas.graph_event_connect('mouse_move', self.on_mouse_move_over_plot)
self.mp = self.plotcanvas.graph_event_connect('mouse_press', self.on_mouse_click_over_plot)
self.mr = self.plotcanvas.graph_event_connect('mouse_release', self.on_mouse_click_release_over_plot)
diff --git a/README.md b/README.md
index f540a075..9ff2dce0 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,8 @@ CAD program, and create G-Code for Isolation routing.
- made sure that the HDPI scaling attribute is set before the QApplication is started
- made sure that when saving a project, the app will try to update the active object from UI form only if there is an active object
+- fix for contextual menus on canvas when using PyQt versions > 5.12.1
+- decision on which mouse button to use for panning is done now once when setting the plotcanvas
4.04.2020
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index 1b34118a..f851d16e 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -1419,10 +1419,12 @@ class FCMenu(QtWidgets.QMenu):
def __init__(self):
super().__init__()
self.mouse_is_panning = False
+ self.popup_active = False
def popup(self, pos, action=None):
- self.mouse_is_panning = False
super().popup(pos)
+ self.mouse_is_panning = False
+ self.popup_active = True
class FCTab(QtWidgets.QTabWidget):
From 836122ca2481adcb36688c7432198d9d397ea7ac Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 5 Apr 2020 16:53:10 +0300
Subject: [PATCH 149/209] - fix to work with Python 3.8 (closing the
application)
---
FlatCAMApp.py | 9 +++++----
README.md | 1 +
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index d7e17179..e3d570d2 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -5280,7 +5280,7 @@ class App(QtCore.QObject):
:return: None
"""
self.save_defaults(silent=True)
- log.debug("App.final_save() --> App Defaults saved.")
+ log.debug("App.quit_application() --> App Defaults saved.")
if self.cmd_line_headless != 1:
# save app state to file
@@ -5312,13 +5312,13 @@ class App(QtCore.QObject):
# This will write the setting to the platform specific storage.
del stgs
- log.debug("App.final_save() --> App UI state saved.")
+ log.debug("App.quit_application() --> App UI state saved.")
# try to quit the QThread that run ArgsThread class
try:
self.th.quit()
except Exception as e:
- log.debug("App.final_save() --> %s" % str(e))
+ log.debug("App.quit_application() --> %s" % str(e))
# try to quit the Socket opened by ArgsThread class
try:
@@ -5332,7 +5332,8 @@ class App(QtCore.QObject):
QtWidgets.qApp.quit()
# When the main event loop is not started yet in which case the qApp.quit() will do nothing
# we use the following command
- sys.exit(0)
+ # sys.exit(0)
+ os._exit(0) # fix to work with Python 3.8
def kill_app(self):
# QtCore.QCoreApplication.quit()
diff --git a/README.md b/README.md
index 9ff2dce0..e38cf11e 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ CAD program, and create G-Code for Isolation routing.
- made sure that when saving a project, the app will try to update the active object from UI form only if there is an active object
- fix for contextual menus on canvas when using PyQt versions > 5.12.1
- decision on which mouse button to use for panning is done now once when setting the plotcanvas
+- fix to work with Python 3.8 (closing the application)
4.04.2020
From fdd5344581cfdb0c696d8cf8fe5a8eb764ce5544 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 5 Apr 2020 21:11:48 +0300
Subject: [PATCH 150/209] - fixed bug in Gerber parser that allowed loading as
Gerber of a file that is not a Gerber - fixed a bug in extension detection
for Gerber files that allowed in the filtered list files that extension *.gb*
- added a processEvents method in the Gerber parser parse_lines() method
---
FlatCAM.py | 2 +-
FlatCAMApp.py | 5 ++---
README.md | 3 +++
flatcamParsers/ParseGerber.py | 6 ++++--
4 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/FlatCAM.py b/FlatCAM.py
index 546877a3..33b2b7c7 100644
--- a/FlatCAM.py
+++ b/FlatCAM.py
@@ -1,7 +1,7 @@
import sys
import os
-from PyQt5 import QtWidgets, QtGui
+from PyQt5 import QtWidgets
from PyQt5.QtCore import QSettings, Qt
from FlatCAMApp import App
from flatcamGUI import VisPyPatches
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index e3d570d2..cc33ca1b 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -9543,7 +9543,7 @@ class App(QtCore.QObject):
_filter_ = "Gerber Files (*.gbr *.ger *.gtl *.gbl *.gts *.gbs *.gtp *.gbp *.gto *.gbo *.gm1 *.gml *.gm3 *" \
".gko *.cmp *.sol *.stc *.sts *.plc *.pls *.crc *.crs *.tsm *.bsm *.ly2 *.ly15 *.dim *.mil *.grb" \
- "*.top *.bot *.smt *.smb *.sst *.ssb *.spt *.spb *.pho *.gdo *.art *.gbd *.gb*);;" \
+ "*.top *.bot *.smt *.smb *.sst *.ssb *.spt *.spb *.pho *.gdo *.art *.gbd);;" \
"Protel Files (*.gtl *.gbl *.gts *.gbs *.gto *.gbo *.gtp *.gbp *.gml *.gm1 *.gm3 *.gko);;" \
"Eagle Files (*.cmp *.sol *.stc *.sts *.plc *.pls *.crc *.crs *.tsm *.bsm *.ly2 *.ly15 *.dim " \
"*.mil);;" \
@@ -9570,8 +9570,7 @@ class App(QtCore.QObject):
color=QtGui.QColor("gray"))
if len(filenames) == 0:
- self.inform.emit('[WARNING_NOTCL] %s' %
- _("Open Gerber cancelled."))
+ self.inform.emit('[WARNING_NOTCL] %s' % _("Open Gerber cancelled."))
else:
for filename in filenames:
if filename != '':
diff --git a/README.md b/README.md
index e38cf11e..8fe6e57d 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,9 @@ CAD program, and create G-Code for Isolation routing.
- fix for contextual menus on canvas when using PyQt versions > 5.12.1
- decision on which mouse button to use for panning is done now once when setting the plotcanvas
- fix to work with Python 3.8 (closing the application)
+- fixed bug in Gerber parser that allowed loading as Gerber of a file that is not a Gerber
+- fixed a bug in extension detection for Gerber files that allowed in the filtered list files that extension *.gb*
+- added a processEvents method in the Gerber parser parse_lines() method
4.04.2020
diff --git a/flatcamParsers/ParseGerber.py b/flatcamParsers/ParseGerber.py
index deba943e..bad7b97d 100644
--- a/flatcamParsers/ParseGerber.py
+++ b/flatcamParsers/ParseGerber.py
@@ -1,4 +1,4 @@
-
+from PyQt5 import QtWidgets
from camlib import Geometry, arc, arc_angle, ApertureMacro
import FlatCAMApp
@@ -1416,6 +1416,8 @@ class Gerber(Geometry):
# ######### Line did not match any pattern. Warn user. ##########
# ################################################################
log.warning("Line ignored (%d): %s" % (line_num, gline))
+ # provide the app with a way to process the GUI events when in a blocking loop
+ QtWidgets.QApplication.processEvents()
try:
path_length = len(path)
@@ -1475,7 +1477,7 @@ class Gerber(Geometry):
sol_geo_length = 1
try:
- if buff_length == 0 and sol_geo_length == 0:
+ if buff_length == 0 and sol_geo_length in [0, 1]:
log.error("Object is not Gerber file or empty. Aborting Object creation.")
return 'fail'
except TypeError as e:
From 139baaff6468a0d85fd062c6b7d058c74ea860b4 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sun, 5 Apr 2020 21:50:32 +0300
Subject: [PATCH 151/209] - fixed issue #386 - multiple Cut operation on a
edited object created a crash due of the bounds() method
---
FlatCAMApp.py | 2 +-
README.md | 2 ++
camlib.py | 16 ++++++++++++++--
3 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index cc33ca1b..3d225531 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -3520,7 +3520,7 @@ class App(QtCore.QObject):
# update the geo object options so it is including the bounding box values
try:
- xmin, ymin, xmax, ymax = edited_obj.bounds()
+ xmin, ymin, xmax, ymax = edited_obj.bounds(flatten=True)
edited_obj.options['xmin'] = xmin
edited_obj.options['ymin'] = ymin
edited_obj.options['xmax'] = xmax
diff --git a/README.md b/README.md
index 8fe6e57d..aa96371a 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,8 @@ CAD program, and create G-Code for Isolation routing.
- fixed bug in Gerber parser that allowed loading as Gerber of a file that is not a Gerber
- fixed a bug in extension detection for Gerber files that allowed in the filtered list files that extension *.gb*
- added a processEvents method in the Gerber parser parse_lines() method
+- fixed issue #386 - multiple Cut operation on a edited object created a crash due of the bounds() method
+
4.04.2020
diff --git a/camlib.py b/camlib.py
index 2770021c..bb192a4b 100644
--- a/camlib.py
+++ b/camlib.py
@@ -614,10 +614,12 @@ class Geometry(object):
log.warning("Not implemented.")
self.solid_geometry = cascaded_union(diffs)
- def bounds(self):
+ def bounds(self, flatten=False):
"""
Returns coordinates of rectangular bounds
of geometry: (xmin, ymin, xmax, ymax).
+ :param flatten: will flatten the solid_geometry if True
+ :return:
"""
# fixed issue of getting bounds only for one level lists of objects
# now it can get bounds for nested lists of objects
@@ -661,7 +663,13 @@ class Geometry(object):
maxy_list = []
for tool in self.tools:
- minx, miny, maxx, maxy = bounds_rec(self.tools[tool]['solid_geometry'])
+ working_geo = self.tools[tool]['solid_geometry']
+
+ if flatten:
+ self.flatten(geometry=working_geo, reset=True)
+ working_geo = self.flat_geometry
+
+ minx, miny, maxx, maxy = bounds_rec(working_geo)
minx_list.append(minx)
miny_list.append(miny)
maxx_list.append(maxx)
@@ -669,6 +677,10 @@ class Geometry(object):
return(min(minx_list), min(miny_list), max(maxx_list), max(maxy_list))
else:
+ if flatten:
+ self.flatten(reset=True)
+ self.solid_geometry = self.flat_geometry
+
bounds_coords = bounds_rec(self.solid_geometry)
return bounds_coords
From 8a2ed1c72604cdff9a251cffe802b5dc6011d52a Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 6 Apr 2020 01:56:38 +0300
Subject: [PATCH 152/209] - some changes in the Geometry UI
---
FlatCAMObj.py | 41 ++++++--
README.md | 2 +-
flatcamGUI/FlatCAMGUI.py | 4 +
flatcamGUI/GUIElements.py | 6 +-
flatcamGUI/ObjectUI.py | 200 ++++++++++++++++++++------------------
5 files changed, 149 insertions(+), 104 deletions(-)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index ed31bb98..68edd0a2 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -233,7 +233,10 @@ class FlatCAMObj(QtCore.QObject):
# self.ui.scale_entry.returnPressed.connect(self.on_scale_button_click)
except Exception as e:
self.app.log.debug("FlatCAMObj.build_ui() --> Nothing to remove: %s" % str(e))
+
self.app.ui.selected_scroll_area.setWidget(self.ui)
+ # self.ui.setMinimumWidth(100)
+ # self.ui.setMaximumWidth(self.app.ui.selected_tab.sizeHint().width())
self.muted_ui = False
@@ -4076,6 +4079,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.outline_color = self.app.defaults['geometry_plot_line']
self.alpha_level = 'FF'
+ self.param_fields = {}
+
# Attributes to be included in serialization
# Always append to it because it carries contents
# from predecessors.
@@ -4244,6 +4249,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
assert isinstance(self.ui, GeometryObjectUI), \
"Expected a GeometryObjectUI, got %s" % type(self.ui)
+
self.units = self.app.defaults['units'].upper()
self.units_found = self.app.defaults['units']
@@ -4277,6 +4283,24 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
"cnctooldia": self.ui.addtool_entry
})
+ self.param_fields.update({
+ "vtipdia": self.ui.tipdia_entry,
+ "vtipangle": self.ui.tipangle_entry,
+ "cutz": self.ui.cutz_entry,
+ "depthperpass": self.ui.maxdepth_entry,
+ "multidepth": self.ui.mpass_cb,
+ "travelz": self.ui.travelz_entry,
+ "feedrate": self.ui.cncfeedrate_entry,
+ "feedrate_z": self.ui.feedrate_z_entry,
+ "feedrate_rapid": self.ui.feedrate_rapid_entry,
+ "extracut": self.ui.extracut_cb,
+ "extracut_length": self.ui.e_cut_entry,
+ "spindlespeed": self.ui.cncspindlespeed_entry,
+ "dwelltime": self.ui.dwelltime_entry,
+ "dwell": self.ui.dwell_cb,
+ "pdepth": self.ui.pdepth_entry,
+ "pfeedrate": self.ui.feedrate_probe_entry,
+ })
# Fill form fields only on object create
self.to_form()
@@ -4486,8 +4510,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
def ui_connect(self):
# on any change to the widgets that matter it will be called self.gui_form_to_storage which will save the
# changes in geometry UI
- for i in range(self.ui.grid3.count()):
- current_widget = self.ui.grid3.itemAt(i).widget()
+ for i in self.param_fields:
+ current_widget = self.param_fields[i]
if isinstance(current_widget, FCCheckBox):
current_widget.stateChanged.connect(self.gui_form_to_storage)
elif isinstance(current_widget, FCComboBox):
@@ -4527,27 +4551,28 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# on any change to the widgets that matter it will be called self.gui_form_to_storage which will save the
# changes in geometry UI
- for i in range(self.ui.grid3.count()):
- current_widget = self.ui.grid3.itemAt(i).widget()
+ for i in self.param_fields:
+ # current_widget = self.ui.grid3.itemAt(i).widget()
+ current_widget = self.param_fields[i]
if isinstance(current_widget, FCCheckBox):
try:
- self.ui.grid3.itemAt(i).widget().stateChanged.disconnect(self.gui_form_to_storage)
+ current_widget.stateChanged.disconnect(self.gui_form_to_storage)
except (TypeError, AttributeError):
pass
elif isinstance(current_widget, FCComboBox):
try:
- self.ui.grid3.itemAt(i).widget().currentIndexChanged.disconnect(self.gui_form_to_storage)
+ current_widget.currentIndexChanged.disconnect(self.gui_form_to_storage)
except (TypeError, AttributeError):
pass
elif isinstance(current_widget, LengthEntry) or isinstance(current_widget, IntEntry) or \
isinstance(current_widget, FCEntry) or isinstance(current_widget, FloatEntry):
try:
- self.ui.grid3.itemAt(i).widget().editingFinished.disconnect(self.gui_form_to_storage)
+ current_widget.editingFinished.disconnect(self.gui_form_to_storage)
except (TypeError, AttributeError):
pass
elif isinstance(current_widget, FCSpinner) or isinstance(current_widget, FCDoubleSpinner):
try:
- self.ui.grid3.itemAt(i).widget().returnPressed.disconnect(self.gui_form_to_storage)
+ current_widget.returnPressed.disconnect(self.gui_form_to_storage)
except TypeError:
pass
diff --git a/README.md b/README.md
index aa96371a..95a692dc 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@ CAD program, and create G-Code for Isolation routing.
- fixed a bug in extension detection for Gerber files that allowed in the filtered list files that extension *.gb*
- added a processEvents method in the Gerber parser parse_lines() method
- fixed issue #386 - multiple Cut operation on a edited object created a crash due of the bounds() method
-
+- some changes in the Geometry UI
4.04.2020
diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py
index 35b9ae2a..9fdd90fd 100644
--- a/flatcamGUI/FlatCAMGUI.py
+++ b/flatcamGUI/FlatCAMGUI.py
@@ -1112,10 +1112,13 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# ########################## SELECTED Tab # ##############################
# ########################################################################
self.selected_tab = QtWidgets.QWidget()
+ # self.selected_tab.setMinimumWidth(270)
self.selected_tab.setObjectName("selected_tab")
self.selected_tab_layout = QtWidgets.QVBoxLayout(self.selected_tab)
self.selected_tab_layout.setContentsMargins(2, 2, 2, 2)
+
self.selected_scroll_area = VerticalScrollArea()
+ # self.selected_scroll_area.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
self.selected_tab_layout.addWidget(self.selected_scroll_area)
self.notebook.addTab(self.selected_tab, _("Selected"))
@@ -1128,6 +1131,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.tool_tab_layout.setContentsMargins(2, 2, 2, 2)
self.notebook.addTab(self.tool_tab, _("Tool"))
self.tool_scroll_area = VerticalScrollArea()
+ # self.tool_scroll_area.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
self.tool_tab_layout.addWidget(self.tool_scroll_area)
# ########################################################################
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index f851d16e..4965b954 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -898,6 +898,10 @@ class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
self.setRange(min_val, max_val)
+ # def sizeHint(self):
+ # default_hint_size = super(FCDoubleSpinner, self).sizeHint()
+ # return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())
+
class FCCheckBox(QtWidgets.QCheckBox):
def __init__(self, label='', parent=None):
@@ -2076,7 +2080,7 @@ class FCDetachableTab2(FCDetachableTab):
class VerticalScrollArea(QtWidgets.QScrollArea):
"""
This widget extends QtGui.QScrollArea to make a vertical-only
- scroll area that also expands horizontally to accomodate
+ scroll area that also expands horizontally to accommodate
its contents.
"""
def __init__(self, parent=None):
diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py
index 39de3558..3b91514c 100644
--- a/flatcamGUI/ObjectUI.py
+++ b/flatcamGUI/ObjectUI.py
@@ -37,7 +37,7 @@ class ObjectUI(QtWidgets.QWidget):
def __init__(self, app, icon_file='share/flatcam_icon32.png', title=_('FlatCAM Object'), parent=None, common=True):
QtWidgets.QWidget.__init__(self, parent=parent)
-
+
self.app = app
self.decimals = app.decimals
@@ -1427,6 +1427,7 @@ class GeometryObjectUI(ObjectUI):
# ## Object name
self.name_hlay = QtWidgets.QHBoxLayout()
self.custom_box.addLayout(self.name_hlay)
+
name_label = QtWidgets.QLabel("%s:" % _("Name"))
self.name_entry = FCEntry()
self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus)
@@ -1438,12 +1439,25 @@ class GeometryObjectUI(ObjectUI):
self.geo_tools_frame = QtWidgets.QFrame()
self.geo_tools_frame.setContentsMargins(0, 0, 0, 0)
self.custom_box.addWidget(self.geo_tools_frame)
+
self.geo_tools_box = QtWidgets.QVBoxLayout()
self.geo_tools_box.setContentsMargins(0, 0, 0, 0)
self.geo_tools_frame.setLayout(self.geo_tools_box)
- hlay_plot = QtWidgets.QHBoxLayout()
- self.geo_tools_box.addLayout(hlay_plot)
+ # ************************************************************************
+ # ************** TABLE BOX FRAME *****************************************
+ # ************************************************************************
+ self.geo_table_frame = QtWidgets.QFrame()
+ self.geo_table_frame.setContentsMargins(0, 0, 0, 0)
+ self.geo_tools_box.addWidget(self.geo_table_frame)
+ self.geo_table_box = QtWidgets.QVBoxLayout()
+ self.geo_table_box.setContentsMargins(0, 0, 0, 0)
+ self.geo_table_frame.setLayout(self.geo_table_box)
+
+ grid0 = QtWidgets.QGridLayout()
+ self.geo_table_box.addLayout(grid0)
+ grid0.setColumnStretch(0, 0)
+ grid0.setColumnStretch(1, 1)
# ### Tools ####
self.tools_table_label = QtWidgets.QLabel('%s:' % _('Tools Table'))
@@ -1461,7 +1475,7 @@ class GeometryObjectUI(ObjectUI):
"grayed out and Cut Z is automatically calculated from the newly \n"
"showed UI form entries named V-Tip Dia and V-Tip Angle.")
)
- hlay_plot.addWidget(self.tools_table_label)
+ grid0.addWidget(self.tools_table_label, 0, 0)
# Plot CB
# self.plot_cb = QtWidgets.QCheckBox('Plot')
@@ -1470,11 +1484,10 @@ class GeometryObjectUI(ObjectUI):
_("Plot (show) this object.")
)
self.plot_cb.setLayoutDirection(QtCore.Qt.RightToLeft)
- hlay_plot.addStretch()
- hlay_plot.addWidget(self.plot_cb)
+ grid0.addWidget(self.plot_cb, 0, 1)
self.geo_tools_table = FCTable()
- self.geo_tools_box.addWidget(self.geo_tools_table)
+ grid0.addWidget(self.geo_tools_table, 1, 0, 1, 2)
self.geo_tools_table.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
self.geo_tools_table.setColumnCount(7)
@@ -1535,10 +1548,10 @@ class GeometryObjectUI(ObjectUI):
# self.geo_tools_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
# Tool Offset
- self.grid1 = QtWidgets.QGridLayout()
- self.geo_tools_box.addLayout(self.grid1)
- self.grid1.setColumnStretch(0, 0)
- self.grid1.setColumnStretch(1, 1)
+ grid1 = QtWidgets.QGridLayout()
+ self.geo_table_box.addLayout(grid1)
+ grid1.setColumnStretch(0, 0)
+ grid1.setColumnStretch(1, 1)
self.tool_offset_lbl = QtWidgets.QLabel('%s:' % _('Tool Offset'))
self.tool_offset_lbl.setToolTip(
@@ -1554,16 +1567,16 @@ class GeometryObjectUI(ObjectUI):
self.tool_offset_entry.set_range(-9999.9999, 9999.9999)
self.tool_offset_entry.setSingleStep(0.1)
- self.grid1.addWidget(self.tool_offset_lbl, 0, 0)
- self.grid1.addWidget(self.tool_offset_entry, 0, 1, 1, 2)
+ grid1.addWidget(self.tool_offset_lbl, 0, 0)
+ grid1.addWidget(self.tool_offset_entry, 0, 1)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.grid1.addWidget(separator_line, 1, 0, 1, 3)
+ grid1.addWidget(separator_line, 1, 0, 1, 2)
self.tool_sel_label = QtWidgets.QLabel('%s' % _("New Tool"))
- self.grid1.addWidget(self.tool_sel_label, 2, 0, 1, 3)
+ grid1.addWidget(self.tool_sel_label, 2, 0, 1, 2)
self.addtool_entry_lbl = QtWidgets.QLabel('%s:' % _('Tool Dia'))
self.addtool_entry_lbl.setToolTip(
@@ -1574,30 +1587,30 @@ class GeometryObjectUI(ObjectUI):
self.addtool_entry.set_range(0.00001, 9999.9999)
self.addtool_entry.setSingleStep(0.1)
+ grid1.addWidget(self.addtool_entry_lbl, 3, 0)
+ grid1.addWidget(self.addtool_entry, 3, 1)
+
self.addtool_btn = QtWidgets.QPushButton(_('Add'))
self.addtool_btn.setToolTip(
_("Add a new tool to the Tool Table\n"
"with the specified diameter.")
)
-
- self.grid1.addWidget(self.addtool_entry_lbl, 3, 0)
- self.grid1.addWidget(self.addtool_entry, 3, 1)
- self.grid1.addWidget(self.addtool_btn, 3, 2)
+ grid1.addWidget(self.addtool_btn, 4, 0, 1, 2)
self.addtool_from_db_btn = QtWidgets.QPushButton(_('Add from DB'))
self.addtool_from_db_btn.setToolTip(
_("Add a new tool to the Tool Table\n"
"from the Tool DataBase.")
)
- self.grid1.addWidget(self.addtool_from_db_btn, 4, 0, 1, 3)
+ grid1.addWidget(self.addtool_from_db_btn, 7, 0, 1, 2)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.grid1.addWidget(separator_line, 5, 0, 1, 3)
+ grid1.addWidget(separator_line, 9, 0, 1, 2)
grid2 = QtWidgets.QGridLayout()
- self.geo_tools_box.addLayout(grid2)
+ self.geo_table_box.addLayout(grid2)
self.copytool_btn = QtWidgets.QPushButton(_('Copy'))
self.copytool_btn.setToolTip(
@@ -1614,17 +1627,33 @@ class GeometryObjectUI(ObjectUI):
grid2.addWidget(self.copytool_btn, 0, 0)
grid2.addWidget(self.deltool_btn, 0, 1)
- self.empty_label = QtWidgets.QLabel('')
- self.geo_tools_box.addWidget(self.empty_label)
+ self.geo_table_box.addWidget(QtWidgets.QLabel(''))
# ###########################################################
# ############# Create CNC Job ##############################
# ###########################################################
+ self.geo_param_frame = QtWidgets.QFrame()
+ self.geo_param_frame.setContentsMargins(0, 0, 0, 0)
+ self.geo_tools_box.addWidget(self.geo_param_frame)
+
+ self.geo_param_box = QtWidgets.QVBoxLayout()
+ self.geo_param_box.setContentsMargins(0, 0, 0, 0)
+ self.geo_param_frame.setLayout(self.geo_param_box)
+
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.geo_tools_box.addWidget(separator_line)
+ self.geo_param_box.addWidget(separator_line)
+
+ # #################################################################
+ # ################# GRID LAYOUT 3 ###############################
+ # #################################################################
+
+ grid3 = QtWidgets.QGridLayout()
+ grid3.setColumnStretch(0, 0)
+ grid3.setColumnStretch(1, 1)
+ self.geo_param_box.addLayout(grid3)
# ### Tools Data ## ##
self.tool_data_label = QtWidgets.QLabel(
@@ -1635,24 +1664,7 @@ class GeometryObjectUI(ObjectUI):
"Each tool store it's own set of such data."
)
)
- self.geo_tools_box.addWidget(self.tool_data_label)
-
- self.geo_param_frame = QtWidgets.QFrame()
- self.geo_param_frame.setContentsMargins(0, 0, 0, 0)
- self.geo_tools_box.addWidget(self.geo_param_frame)
-
- self.geo_param_box = QtWidgets.QVBoxLayout()
- self.geo_param_box.setContentsMargins(0, 0, 0, 0)
- self.geo_param_frame.setLayout(self.geo_param_box)
-
- # #################################################################
- # ################# GRID LAYOUT 3 ###############################
- # #################################################################
-
- self.grid3 = QtWidgets.QGridLayout()
- self.grid3.setColumnStretch(0, 0)
- self.grid3.setColumnStretch(1, 1)
- self.geo_param_box.addLayout(self.grid3)
+ grid3.addWidget(self.tool_data_label, 0, 0, 1, 2)
# Tip Dia
self.tipdialabel = QtWidgets.QLabel('%s:' % _('V-Tip Dia'))
@@ -1666,8 +1678,8 @@ class GeometryObjectUI(ObjectUI):
self.tipdia_entry.set_range(0.00001, 9999.9999)
self.tipdia_entry.setSingleStep(0.1)
- self.grid3.addWidget(self.tipdialabel, 1, 0)
- self.grid3.addWidget(self.tipdia_entry, 1, 1)
+ grid3.addWidget(self.tipdialabel, 1, 0)
+ grid3.addWidget(self.tipdia_entry, 1, 1)
# Tip Angle
self.tipanglelabel = QtWidgets.QLabel('%s:' % _('V-Tip Angle'))
@@ -1682,8 +1694,8 @@ class GeometryObjectUI(ObjectUI):
self.tipangle_entry.set_range(1.0, 180.0)
self.tipangle_entry.setSingleStep(1)
- self.grid3.addWidget(self.tipanglelabel, 2, 0)
- self.grid3.addWidget(self.tipangle_entry, 2, 1)
+ grid3.addWidget(self.tipanglelabel, 2, 0)
+ grid3.addWidget(self.tipangle_entry, 2, 1)
# Cut Z
self.cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
@@ -1703,8 +1715,8 @@ class GeometryObjectUI(ObjectUI):
self.cutz_entry.setSingleStep(0.1)
- self.grid3.addWidget(self.cutzlabel, 3, 0)
- self.grid3.addWidget(self.cutz_entry, 3, 1)
+ grid3.addWidget(self.cutzlabel, 3, 0)
+ grid3.addWidget(self.cutz_entry, 3, 1)
# Multi-pass
self.mpass_cb = FCCheckBox('%s:' % _("Multi-Depth"))
@@ -1729,8 +1741,8 @@ class GeometryObjectUI(ObjectUI):
)
self.ois_mpass_geo = OptionalInputSection(self.mpass_cb, [self.maxdepth_entry])
- self.grid3.addWidget(self.mpass_cb, 4, 0)
- self.grid3.addWidget(self.maxdepth_entry, 4, 1)
+ grid3.addWidget(self.mpass_cb, 4, 0)
+ grid3.addWidget(self.maxdepth_entry, 4, 1)
# Travel Z
self.travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z'))
@@ -1748,8 +1760,8 @@ class GeometryObjectUI(ObjectUI):
self.travelz_entry.setSingleStep(0.1)
- self.grid3.addWidget(self.travelzlabel, 5, 0)
- self.grid3.addWidget(self.travelz_entry, 5, 1)
+ grid3.addWidget(self.travelzlabel, 5, 0)
+ grid3.addWidget(self.travelz_entry, 5, 1)
# Feedrate X-Y
self.frlabel = QtWidgets.QLabel('%s:' % _('Feedrate X-Y'))
@@ -1762,8 +1774,8 @@ class GeometryObjectUI(ObjectUI):
self.cncfeedrate_entry.set_range(0, 99999.9999)
self.cncfeedrate_entry.setSingleStep(0.1)
- self.grid3.addWidget(self.frlabel, 10, 0)
- self.grid3.addWidget(self.cncfeedrate_entry, 10, 1)
+ grid3.addWidget(self.frlabel, 10, 0)
+ grid3.addWidget(self.cncfeedrate_entry, 10, 1)
# Feedrate Z (Plunge)
self.frzlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z'))
@@ -1777,8 +1789,8 @@ class GeometryObjectUI(ObjectUI):
self.feedrate_z_entry.set_range(0, 99999.9999)
self.feedrate_z_entry.setSingleStep(0.1)
- self.grid3.addWidget(self.frzlabel, 11, 0)
- self.grid3.addWidget(self.feedrate_z_entry, 11, 1)
+ grid3.addWidget(self.frzlabel, 11, 0)
+ grid3.addWidget(self.feedrate_z_entry, 11, 1)
# Feedrate rapids
self.fr_rapidlabel = QtWidgets.QLabel('%s:' % _('Feedrate Rapids'))
@@ -1794,8 +1806,8 @@ class GeometryObjectUI(ObjectUI):
self.feedrate_rapid_entry.set_range(0, 99999.9999)
self.feedrate_rapid_entry.setSingleStep(0.1)
- self.grid3.addWidget(self.fr_rapidlabel, 12, 0)
- self.grid3.addWidget(self.feedrate_rapid_entry, 12, 1)
+ grid3.addWidget(self.fr_rapidlabel, 12, 0)
+ grid3.addWidget(self.feedrate_rapid_entry, 12, 1)
# default values is to hide
self.fr_rapidlabel.hide()
self.feedrate_rapid_entry.hide()
@@ -1820,8 +1832,8 @@ class GeometryObjectUI(ObjectUI):
"meet with last cut, we generate an\n"
"extended cut over the first cut section.")
)
- self.grid3.addWidget(self.extracut_cb, 13, 0)
- self.grid3.addWidget(self.e_cut_entry, 13, 1)
+ grid3.addWidget(self.extracut_cb, 13, 0)
+ grid3.addWidget(self.e_cut_entry, 13, 1)
# Spindlespeed
self.spindle_label = QtWidgets.QLabel('%s:' % _('Spindle speed'))
@@ -1836,8 +1848,8 @@ class GeometryObjectUI(ObjectUI):
self.cncspindlespeed_entry.set_range(0, 1000000)
self.cncspindlespeed_entry.set_step(100)
- self.grid3.addWidget(self.spindle_label, 14, 0)
- self.grid3.addWidget(self.cncspindlespeed_entry, 14, 1)
+ grid3.addWidget(self.spindle_label, 14, 0)
+ grid3.addWidget(self.cncspindlespeed_entry, 14, 1)
# Dwell
self.dwell_cb = FCCheckBox('%s:' % _('Dwell'))
@@ -1857,8 +1869,8 @@ class GeometryObjectUI(ObjectUI):
)
self.ois_dwell_geo = OptionalInputSection(self.dwell_cb, [self.dwelltime_entry])
- self.grid3.addWidget(self.dwell_cb, 15, 0)
- self.grid3.addWidget(self.dwelltime_entry, 15, 1)
+ grid3.addWidget(self.dwell_cb, 15, 0)
+ grid3.addWidget(self.dwelltime_entry, 15, 1)
# Probe depth
self.pdepth_label = QtWidgets.QLabel('%s:' % _("Probe Z depth"))
@@ -1871,8 +1883,8 @@ class GeometryObjectUI(ObjectUI):
self.pdepth_entry.set_range(-9999.9999, 9999.9999)
self.pdepth_entry.setSingleStep(0.1)
- self.grid3.addWidget(self.pdepth_label, 17, 0)
- self.grid3.addWidget(self.pdepth_entry, 17, 1)
+ grid3.addWidget(self.pdepth_label, 17, 0)
+ grid3.addWidget(self.pdepth_entry, 17, 1)
self.pdepth_label.hide()
self.pdepth_entry.setVisible(False)
@@ -1887,8 +1899,8 @@ class GeometryObjectUI(ObjectUI):
self.feedrate_probe_entry.set_range(0.0, 9999.9999)
self.feedrate_probe_entry.setSingleStep(0.1)
- self.grid3.addWidget(self.feedrate_probe_label, 18, 0)
- self.grid3.addWidget(self.feedrate_probe_entry, 18, 1)
+ grid3.addWidget(self.feedrate_probe_label, 18, 0)
+ grid3.addWidget(self.feedrate_probe_entry, 18, 1)
self.feedrate_probe_label.hide()
self.feedrate_probe_entry.setVisible(False)
@@ -1897,34 +1909,34 @@ class GeometryObjectUI(ObjectUI):
# ################# GRID LAYOUT 4 ###############################
# #################################################################
- self.grid4 = QtWidgets.QGridLayout()
- self.grid4.setColumnStretch(0, 0)
- self.grid4.setColumnStretch(1, 1)
- self.geo_param_box.addLayout(self.grid4)
+ grid4 = QtWidgets.QGridLayout()
+ grid4.setColumnStretch(0, 0)
+ grid4.setColumnStretch(1, 1)
+ self.geo_param_box.addLayout(grid4)
separator_line2 = QtWidgets.QFrame()
separator_line2.setFrameShape(QtWidgets.QFrame.HLine)
separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.grid4.addWidget(separator_line2, 0, 0, 1, 2)
+ grid4.addWidget(separator_line2, 0, 0, 1, 2)
self.apply_param_to_all = FCButton(_("Apply parameters to all tools"))
self.apply_param_to_all.setToolTip(
_("The parameters in the current form will be applied\n"
"on all the tools from the Tool Table.")
)
- self.grid4.addWidget(self.apply_param_to_all, 1, 0, 1, 2)
+ grid4.addWidget(self.apply_param_to_all, 1, 0, 1, 2)
separator_line2 = QtWidgets.QFrame()
separator_line2.setFrameShape(QtWidgets.QFrame.HLine)
separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.grid4.addWidget(separator_line2, 2, 0, 1, 2)
+ grid4.addWidget(separator_line2, 2, 0, 1, 2)
# General Parameters
self.gen_param_label = QtWidgets.QLabel('%s' % _("Common Parameters"))
self.gen_param_label.setToolTip(
_("Parameters that are common for all tools.")
)
- self.grid4.addWidget(self.gen_param_label, 3, 0, 1, 2)
+ grid4.addWidget(self.gen_param_label, 3, 0, 1, 2)
# Tool change Z
self.toolchangeg_cb = FCCheckBox('%s:' % _("Tool change Z"))
@@ -1951,8 +1963,8 @@ class GeometryObjectUI(ObjectUI):
self.toolchangez_entry.setSingleStep(0.1)
self.ois_tcz_geo = OptionalInputSection(self.toolchangeg_cb, [self.toolchangez_entry])
- self.grid4.addWidget(self.toolchangeg_cb, 6, 0)
- self.grid4.addWidget(self.toolchangez_entry, 6, 1)
+ grid4.addWidget(self.toolchangeg_cb, 6, 0)
+ grid4.addWidget(self.toolchangez_entry, 6, 1)
# The Z value for the start move
# startzlabel = QtWidgets.QLabel('Start move Z:')
@@ -1961,9 +1973,9 @@ class GeometryObjectUI(ObjectUI):
# "Delete the value if you don't need this feature."
#
# )
- # self.grid3.addWidget(startzlabel, 8, 0)
+ # grid3.addWidget(startzlabel, 8, 0)
# self.gstartz_entry = FloatEntry()
- # self.grid3.addWidget(self.gstartz_entry, 8, 1)
+ # grid3.addWidget(self.gstartz_entry, 8, 1)
# The Z value for the end move
self.endz_label = QtWidgets.QLabel('%s:' % _('End move Z'))
@@ -1981,8 +1993,8 @@ class GeometryObjectUI(ObjectUI):
self.endz_entry.setSingleStep(0.1)
- self.grid4.addWidget(self.endz_label, 9, 0)
- self.grid4.addWidget(self.endz_entry, 9, 1)
+ grid4.addWidget(self.endz_label, 9, 0)
+ grid4.addWidget(self.endz_entry, 9, 1)
# End Move X,Y
endmove_xy_label = QtWidgets.QLabel('%s:' % _('End move X,Y'))
@@ -1993,8 +2005,8 @@ class GeometryObjectUI(ObjectUI):
)
self.endxy_entry = FCEntry()
- self.grid4.addWidget(endmove_xy_label, 10, 0)
- self.grid4.addWidget(self.endxy_entry, 10, 1)
+ grid4.addWidget(endmove_xy_label, 10, 0)
+ grid4.addWidget(self.endxy_entry, 10, 1)
# preprocessor selection
pp_label = QtWidgets.QLabel('%s:' % _("Preprocessor"))
@@ -2005,17 +2017,17 @@ class GeometryObjectUI(ObjectUI):
self.pp_geometry_name_cb = FCComboBox()
self.pp_geometry_name_cb.setFocusPolicy(QtCore.Qt.StrongFocus)
- self.grid4.addWidget(pp_label, 11, 0)
- self.grid4.addWidget(self.pp_geometry_name_cb, 11, 1)
+ grid4.addWidget(pp_label, 11, 0)
+ grid4.addWidget(self.pp_geometry_name_cb, 11, 1)
- self.grid4.addWidget(QtWidgets.QLabel(''), 12, 0, 1, 2)
+ grid4.addWidget(QtWidgets.QLabel(''), 12, 0, 1, 2)
warning_lbl = QtWidgets.QLabel(
_(
"Add / Select at least one tool in the tool-table.\n"
"Click the # header to select all, or Ctrl + LMB\n"
"for custom selection of tools."
))
- self.grid4.addWidget(warning_lbl, 13, 0, 1, 2)
+ grid4.addWidget(warning_lbl, 13, 0, 1, 2)
# Button
self.generate_cnc_button = QtWidgets.QPushButton(_('Generate CNCJob object'))
@@ -2028,9 +2040,9 @@ class GeometryObjectUI(ObjectUI):
font-weight: bold;
}
""")
- self.grid4.addWidget(self.generate_cnc_button, 14, 0, 1, 2)
+ grid4.addWidget(self.generate_cnc_button, 14, 0, 1, 2)
- self.grid4.addWidget(QtWidgets.QLabel(''), 15, 0, 1, 2)
+ grid4.addWidget(QtWidgets.QLabel(''), 15, 0, 1, 2)
# ##############
# Paint area ##
@@ -2039,7 +2051,7 @@ class GeometryObjectUI(ObjectUI):
self.tools_label.setToolTip(
_("Launch Paint Tool in Tools Tab.")
)
- self.grid4.addWidget(self.tools_label, 16, 0, 1, 2)
+ grid4.addWidget(self.tools_label, 16, 0, 1, 2)
# Paint Button
self.paint_tool_button = QtWidgets.QPushButton(_('Paint Tool'))
@@ -2057,7 +2069,7 @@ class GeometryObjectUI(ObjectUI):
font-weight: bold;
}
""")
- self.grid4.addWidget(self.paint_tool_button, 17, 0, 1, 2)
+ grid4.addWidget(self.paint_tool_button, 17, 0, 1, 2)
# NCC Tool
self.generate_ncc_button = QtWidgets.QPushButton(_('NCC Tool'))
@@ -2071,7 +2083,7 @@ class GeometryObjectUI(ObjectUI):
font-weight: bold;
}
""")
- self.grid4.addWidget(self.generate_ncc_button, 18, 0, 1, 2)
+ grid4.addWidget(self.generate_ncc_button, 18, 0, 1, 2)
class CNCObjectUI(ObjectUI):
From 69b39e293750b2cdcd9c61c9c4964c0fce3464ce Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 6 Apr 2020 06:28:55 +0300
Subject: [PATCH 153/209] - added key shortcuts (arrow up/down) that will
select the objects in the Project tab if the focus is in that tab
---
README.md | 4 ++++
flatcamGUI/FlatCAMGUI.py | 22 ++++++++++++++++++++++
2 files changed, 26 insertions(+)
diff --git a/README.md b/README.md
index 95a692dc..2ba2b6c0 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+6.04.2020
+
+- added key shortcuts (arrow up/down) that will select the objects in the Project tab if the focus is in that tab
+
5.04.2020
- made sure that the HDPI scaling attribute is set before the QApplication is started
diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py
index 9fdd90fd..064d3d76 100644
--- a/flatcamGUI/FlatCAMGUI.py
+++ b/flatcamGUI/FlatCAMGUI.py
@@ -2778,6 +2778,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
modifiers = QtWidgets.QApplication.keyboardModifiers()
active = self.app.collection.get_active()
selected = self.app.collection.get_selected()
+ names_list = self.app.collection.get_names()
matplotlib_key_flag = False
@@ -3131,6 +3132,27 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.app.collection.update_view()
self.app.delete_selection_shape()
+ # Select the object in the Tree above the current one
+ if key == QtCore.Qt.Key_Up:
+ self.app.collection.set_all_inactive()
+ active_name = active.options['name']
+ active_index = names_list.index(active_name)
+ if active_index == 0:
+ self.app.collection.set_active(names_list[-1])
+ else:
+ self.app.collection.set_active(names_list[active_index-1])
+
+ # Select the object in the Tree bellow the current one
+ if key == QtCore.Qt.Key_Down:
+ self.app.collection.set_all_inactive()
+ active_name = active.options['name']
+ active_index = names_list.index(active_name)
+ if active_index == len(names_list) - 1:
+ self.app.collection.set_active(names_list[0])
+ else:
+ self.app.collection.set_active(names_list[active_index+1])
+
+
# New Geometry
if key == QtCore.Qt.Key_B:
self.app.new_gerber_object()
From b11ac0ca4d188ef46da5e0603ab238c05129b6f6 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 6 Apr 2020 19:04:32 +0300
Subject: [PATCH 154/209] - added a minor change to the ListSys Tcl command
---
README.md | 1 +
tclCommands/TclCommandListSys.py | 4 +++-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 2ba2b6c0..9cda4dcb 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
6.04.2020
- added key shortcuts (arrow up/down) that will select the objects in the Project tab if the focus is in that tab
+- added a minor change to the ListSys Tcl command
5.04.2020
diff --git a/tclCommands/TclCommandListSys.py b/tclCommands/TclCommandListSys.py
index 39fc6e22..58d8c8e3 100644
--- a/tclCommands/TclCommandListSys.py
+++ b/tclCommands/TclCommandListSys.py
@@ -60,4 +60,6 @@ class TclCommandListSys(TclCommand):
argument = args['selection']
return str([k for k in self.app.defaults.keys() if str(k).startswith(str(argument))])
else:
- return str([*self.app.defaults])
\ No newline at end of file
+ ret_val = list(self.app.defaults.keys())
+ return str(ret_val)
+ # return str([*self.app.defaults])
From ee6ac2593fe94af88d81c9d32d68ae52b89fa85e Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 6 Apr 2020 20:31:42 +0300
Subject: [PATCH 155/209] - fixed an crash generated when running the Tool
Database from the Menu -> Options menu entry
---
FlatCAMApp.py | 10 +++++++---
README.md | 1 +
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 3d225531..4bdbc575 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -2065,7 +2065,7 @@ class App(QtCore.QObject):
self.ui.menuoptions_transform_flipx.triggered.connect(self.on_flipx)
self.ui.menuoptions_transform_flipy.triggered.connect(self.on_flipy)
self.ui.menuoptions_view_source.triggered.connect(self.on_view_source)
- self.ui.menuoptions_tools_db.triggered.connect(self.on_tools_database)
+ self.ui.menuoptions_tools_db.triggered.connect(lambda: self.on_tools_database(source='app'))
self.ui.menuviewdisableall.triggered.connect(self.disable_all_plots)
self.ui.menuviewdisableother.triggered.connect(self.disable_other_plots)
@@ -8106,8 +8106,12 @@ class App(QtCore.QObject):
)
# add the tab if it was closed
- self.ui.plot_tab_area.addTab(self.tools_db_tab, _("Tools Database"))
- self.tools_db_tab.setObjectName("database_tab")
+ try:
+ self.ui.plot_tab_area.addTab(self.tools_db_tab, _("Tools Database"))
+ self.tools_db_tab.setObjectName("database_tab")
+ except Exception as e:
+ log.debug("App.on_tools_database() --> %s" % str(e))
+ return
# delete the absolute and relative position and messages in the infobar
self.ui.position_label.setText("")
diff --git a/README.md b/README.md
index 9cda4dcb..5104b726 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- added key shortcuts (arrow up/down) that will select the objects in the Project tab if the focus is in that tab
- added a minor change to the ListSys Tcl command
+- fixed an crash generated when running the Tool Database from the Menu -> Options menu entry
5.04.2020
From d14e5d9445560f31e5b02ef180e5439347ab2351 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 6 Apr 2020 20:52:00 +0300
Subject: [PATCH 156/209] - fixed a bug in handling the UP/DOWN key shortcuts
that caused a crash when no object was selected in the Project Tab; also made
sure that the said keys are handled only for the Project Tab
---
README.md | 1 +
flatcamGUI/FlatCAMGUI.py | 41 ++++++++++++++++++++++++----------------
2 files changed, 26 insertions(+), 16 deletions(-)
diff --git a/README.md b/README.md
index 5104b726..5e9d55b8 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ CAD program, and create G-Code for Isolation routing.
- added key shortcuts (arrow up/down) that will select the objects in the Project tab if the focus is in that tab
- added a minor change to the ListSys Tcl command
- fixed an crash generated when running the Tool Database from the Menu -> Options menu entry
+- fixed a bug in handling the UP/DOWN key shortcuts that caused a crash when no object was selected in the Project Tab; also made sure that the said keys are handled only for the Project Tab
5.04.2020
diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py
index 064d3d76..27c80913 100644
--- a/flatcamGUI/FlatCAMGUI.py
+++ b/flatcamGUI/FlatCAMGUI.py
@@ -16,8 +16,7 @@ from flatcamEditors.FlatCAMGeoEditor import FCShapeTool
from matplotlib.backend_bases import KeyEvent as mpl_key_event
import webbrowser
-from copy import deepcopy
-from datetime import datetime
+from ObjectCollection import KeySensitiveListView
import subprocess
import os
@@ -3134,23 +3133,33 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# Select the object in the Tree above the current one
if key == QtCore.Qt.Key_Up:
- self.app.collection.set_all_inactive()
- active_name = active.options['name']
- active_index = names_list.index(active_name)
- if active_index == 0:
- self.app.collection.set_active(names_list[-1])
- else:
- self.app.collection.set_active(names_list[active_index-1])
+ # make sure it works only for the Project Tab who is an instance of KeySensitiveListView
+ focused_wdg = QtWidgets.QApplication.focusWidget()
+ if isinstance(focused_wdg, KeySensitiveListView):
+ self.app.collection.set_all_inactive()
+ if active is None:
+ return
+ active_name = active.options['name']
+ active_index = names_list.index(active_name)
+ if active_index == 0:
+ self.app.collection.set_active(names_list[-1])
+ else:
+ self.app.collection.set_active(names_list[active_index-1])
# Select the object in the Tree bellow the current one
if key == QtCore.Qt.Key_Down:
- self.app.collection.set_all_inactive()
- active_name = active.options['name']
- active_index = names_list.index(active_name)
- if active_index == len(names_list) - 1:
- self.app.collection.set_active(names_list[0])
- else:
- self.app.collection.set_active(names_list[active_index+1])
+ # make sure it works only for the Project Tab who is an instance of KeySensitiveListView
+ focused_wdg = QtWidgets.QApplication.focusWidget()
+ if isinstance(focused_wdg, KeySensitiveListView):
+ self.app.collection.set_all_inactive()
+ if active is None:
+ return
+ active_name = active.options['name']
+ active_index = names_list.index(active_name)
+ if active_index == len(names_list) - 1:
+ self.app.collection.set_active(names_list[0])
+ else:
+ self.app.collection.set_active(names_list[active_index+1])
# New Geometry
From 573070f154d4fd11e9981b124313b5f77c6561d3 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 6 Apr 2020 21:10:02 +0300
Subject: [PATCH 157/209] - some PEP8 changes and other minor changes
---
FlatCAMObj.py | 138 ++++++++++++++++++++++++++++----------------------
README.md | 1 +
2 files changed, 78 insertions(+), 61 deletions(-)
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 68edd0a2..d803cea1 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -16,7 +16,7 @@ from shapely.ops import cascaded_union
import shapely.affinity as affinity
from copy import deepcopy
-from copy import copy
+# from copy import copy
from io import StringIO
import traceback
@@ -32,7 +32,7 @@ from flatcamParsers.ParseGerber import Gerber
from camlib import Geometry, CNCjob
import FlatCAMApp
-from flatcamGUI.VisPyVisuals import ShapeCollection
+# from flatcamGUI.VisPyVisuals import ShapeCollection
import tkinter as tk
import os
@@ -63,6 +63,7 @@ class ValidationError(Exception):
self.errors = errors
+
# #######################################
# # FlatCAMObj ##
# #######################################
@@ -496,7 +497,7 @@ class FlatCAMObj(QtCore.QObject):
# Not all object types has annotations
try:
self.annotation.visible = value
- except Exception as e:
+ except Exception:
pass
if threaded is False:
@@ -1069,12 +1070,12 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
if self.ui.iso_type_radio.get_value() == 'int':
self.iso_type = 1
- def worker_task(obj, app_obj):
+ def worker_task(iso_obj, app_obj):
with self.app.proc_container.new(_("Isolating...")):
if self.ui.follow_cb.get_value() is True:
- obj.follow_geo()
+ iso_obj.follow_geo()
# in the end toggle the visibility of the origin object so we can see the generated Geometry
- obj.ui.plot_cb.toggle()
+ iso_obj.ui.plot_cb.toggle()
else:
app_obj.report_usage("gerber_on_iso_button")
self.read_form()
@@ -1999,7 +2000,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
self.ui.mark_all_cb.setChecked(True)
self.ui_connect()
- def on_mark_all_click(self, signal):
+ def on_mark_all_click(self):
self.ui_disconnect()
mark_all = self.ui.mark_all_cb.isChecked()
for row in range(self.ui.apertures_table.rowCount()):
@@ -2409,7 +2410,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
"toolchangez": 1.0,
"toolchangexy": "0.0, 0.0",
"extracut": self.app.defaults["geometry_extracut"],
- "extracut_length":self.app.defaults["geometry_extracut_length"],
+ "extracut_length": self.app.defaults["geometry_extracut_length"],
"endz": 2.0,
"endxy": '',
@@ -2914,20 +2915,20 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
"e_operation": "operation",
"e_milling_type": "milling_type",
"e_milling_dia": "milling_dia",
- "e_cutz" : "cutz",
- "e_multidepth" : "multidepth",
- "e_depthperpass" : "depthperpass",
+ "e_cutz": "cutz",
+ "e_multidepth": "multidepth",
+ "e_depthperpass": "depthperpass",
- "e_travelz" : "travelz",
- "e_feedratexy" : "feedrate",
- "e_feedratez" : "feedrate_z",
- "e_fr_rapid" : "feedrate_rapid",
- "e_extracut" : "extracut",
- "e_extracut_length" : "extracut_length",
- "e_spindlespeed" : "spindlespeed",
- "e_dwell" : "dwell",
- "e_dwelltime" : "dwelltime",
- "e_offset" : "offset",
+ "e_travelz": "travelz",
+ "e_feedratexy": "feedrate",
+ "e_feedratez": "feedrate_z",
+ "e_fr_rapid": "feedrate_rapid",
+ "e_extracut": "extracut",
+ "e_extracut_length": "extracut_length",
+ "e_spindlespeed": "spindlespeed",
+ "e_dwell": "dwell",
+ "e_dwelltime": "dwelltime",
+ "e_offset": "offset",
}
# populate Excellon preprocessor combobox list
@@ -4249,7 +4250,6 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
assert isinstance(self.ui, GeometryObjectUI), \
"Expected a GeometryObjectUI, got %s" % type(self.ui)
-
self.units = self.app.defaults['units'].upper()
self.units_found = self.app.defaults['units']
@@ -4413,7 +4413,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
_("Copy"), self.on_tool_copy,
icon=QtGui.QIcon(self.app.resource_location + "/copy16.png"))
self.ui.geo_tools_table.addContextMenu(
- _("Delete"), lambda: self.on_tool_delete(all=None),
+ _("Delete"), lambda: self.on_tool_delete(all_tools=None),
icon=QtGui.QIcon(self.app.resource_location + "/delete32.png"))
# Show/Hide Advanced Options
@@ -4862,7 +4862,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
if self.ui.geo_tools_table.rowCount() != 0:
self.ui.geo_param_frame.setDisabled(False)
- def on_tool_copy(self, all=None):
+ def on_tool_copy(self, all_tools=None):
self.ui_disconnect()
# find the tool_uid maximum value in the self.tools
@@ -4874,7 +4874,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
except ValueError:
max_uid = 0
- if all is None:
+ if all_tools is None:
if self.ui.geo_tools_table.selectedItems():
for current_row in self.ui.geo_tools_table.selectedItems():
# sometime the header get selected and it has row number -1
@@ -4956,10 +4956,10 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui_connect()
self.build_ui()
- def on_tool_delete(self, all=None):
+ def on_tool_delete(self, all_tools=None):
self.ui_disconnect()
- if all is None:
+ if all_tools is None:
if self.ui.geo_tools_table.selectedItems():
for current_row in self.ui.geo_tools_table.selectedItems():
# sometime the header get selected and it has row number -1
@@ -5307,29 +5307,28 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.geo_tools_table.setCurrentItem(self.ui.geo_tools_table.item(row, 0))
def export_dxf(self):
- units = self.app.defaults['units'].upper()
dwg = None
try:
dwg = ezdxf.new('R2010')
msp = dwg.modelspace()
- def g2dxf(dxf_space, geo):
- if isinstance(geo, MultiPolygon):
- for poly in geo:
+ def g2dxf(dxf_space, geo_obj):
+ if isinstance(geo_obj, MultiPolygon):
+ for poly in geo_obj:
ext_points = list(poly.exterior.coords)
dxf_space.add_lwpolyline(ext_points)
for interior in poly.interiors:
dxf_space.add_lwpolyline(list(interior.coords))
- if isinstance(geo, Polygon):
- ext_points = list(geo.exterior.coords)
+ if isinstance(geo_obj, Polygon):
+ ext_points = list(geo_obj.exterior.coords)
dxf_space.add_lwpolyline(ext_points)
- for interior in geo.interiors:
+ for interior in geo_obj.interiors:
dxf_space.add_lwpolyline(list(interior.coords))
- if isinstance(geo, MultiLineString):
- for line in geo:
+ if isinstance(geo_obj, MultiLineString):
+ for line in geo_obj:
dxf_space.add_lwpolyline(list(line.coords))
- if isinstance(geo, LineString) or isinstance(geo, LinearRing):
- dxf_space.add_lwpolyline(list(geo.coords))
+ if isinstance(geo_obj, LineString) or isinstance(geo_obj, LinearRing):
+ dxf_space.add_lwpolyline(list(geo_obj.coords))
multigeo_solid_geometry = []
if self.multigeo:
@@ -5577,11 +5576,14 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
:param tools_in_use: the tools that are used, needed by some preprocessors
:type list of lists, each list in the list is made out of row elements of tools table from GUI
- :param segx: number of segments on the X axis, for auto-levelling
- :param segy: number of segments on the Y axis, for auto-levelling
- :param plot: if True the generated object will be plotted; if False will not be plotted
- :param use_thread: if True use threading
- :return: None
+ :param outname:
+ :param tools_dict:
+ :param tools_in_use:
+ :param segx: number of segments on the X axis, for auto-levelling
+ :param segy: number of segments on the Y axis, for auto-levelling
+ :param plot: if True the generated object will be plotted; if False will not be plotted
+ :param use_thread: if True use threading
+ :return: None
"""
# use the name of the first tool selected in self.geo_tools_table which has the diameter passed as tool_dia
@@ -5890,8 +5892,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
try:
dia_cnc_dict['solid_geometry'] = deepcopy(tool_solid_geometry)
self.app.inform.emit('[success] %s' % _("Finished G-Code processing..."))
- except Exception as e:
- self.app.inform.emit('[ERROR] %s: %s' % (_("G-Code processing failed with error"), str(e)))
+ except Exception as ee:
+ self.app.inform.emit('[ERROR] %s: %s' % (_("G-Code processing failed with error"), str(ee)))
# tell gcode_parse from which point to start drawing the lines depending on what kind of
# object is the source of gcode
@@ -5943,15 +5945,31 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
work is done by the target camlib.CNCjob
`generate_from_geometry_2()` method.
- :param z_cut: Cut depth (negative)
- :param z_move: Hight of the tool when travelling (not cutting)
- :param feedrate: Feed rate while cutting on X - Y plane
- :param feedrate_z: Feed rate while cutting on Z plane
- :param feedrate_rapid: Feed rate while moving with rapids
- :param dia: Tool diameter
- :param outname: Name of the new object
- :param spindlespeed: Spindle speed (RPM)
- :param pp Name of the preprocessor
+ :param outname: Name of the new object
+ :param dia: Tool diameter
+ :param offset:
+ :param z_cut: Cut depth (negative value)
+ :param z_move: Height of the tool when travelling (not cutting)
+ :param feedrate: Feed rate while cutting on X - Y plane
+ :param feedrate_z: Feed rate while cutting on Z plane
+ :param feedrate_rapid: Feed rate while moving with rapids
+ :param spindlespeed: Spindle speed (RPM)
+ :param dwell:
+ :param dwelltime:
+ :param multidepth:
+ :param depthperpass:
+ :param toolchange:
+ :param toolchangez:
+ :param toolchangexy:
+ :param extracut:
+ :param extracut_length:
+ :param startz:
+ :param endz:
+ :param pp: Name of the preprocessor
+ :param segx:
+ :param segy:
+ :param use_thread:
+ :param plot:
:return: None
"""
@@ -6050,7 +6068,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
else:
self.app.new_object("cncjob", outname, job_init, plot=plot)
- # def on_plot_cb_click(self, *args): # TODO: args not needed
+ # def on_plot_cb_click(self, *args):
# if self.muted_ui:
# return
# self.read_form_item('plot')
@@ -6119,8 +6137,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# variables to display the percentage of work done
self.geo_len = 0
try:
- for g in self.tools[tool]['solid_geometry']:
- self.geo_len += 1
+ self.geo_len = len(self.tools[tool]['solid_geometry'])
except TypeError:
self.geo_len = 1
self.old_disp_number = 0
@@ -6196,8 +6213,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# variables to display the percentage of work done
self.geo_len = 0
try:
- for g in self.tools[tool]['solid_geometry']:
- self.geo_len += 1
+ self.geo_len = len(self.tools[tool]['solid_geometry'])
except TypeError:
self.geo_len = 1
self.old_disp_number = 0
@@ -6208,10 +6224,10 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# variables to display the percentage of work done
self.geo_len = 0
try:
- for g in self.solid_geometry:
- self.geo_len += 1
+ self.geo_len = len(self.solid_geometry)
except TypeError:
self.geo_len = 1
+
self.old_disp_number = 0
self.el_count = 0
diff --git a/README.md b/README.md
index 5e9d55b8..dd6c3e21 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ CAD program, and create G-Code for Isolation routing.
- added a minor change to the ListSys Tcl command
- fixed an crash generated when running the Tool Database from the Menu -> Options menu entry
- fixed a bug in handling the UP/DOWN key shortcuts that caused a crash when no object was selected in the Project Tab; also made sure that the said keys are handled only for the Project Tab
+- some PEP8 changes and other minor changes
5.04.2020
From e1269cdb341e412d43a3a24945c86770101a8c5f Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 6 Apr 2020 21:39:23 +0300
Subject: [PATCH 158/209] - updated the requirements file
---
README.md | 1 +
requirements.txt | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index dd6c3e21..5ee4f317 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,7 @@ CAD program, and create G-Code for Isolation routing.
- fixed an crash generated when running the Tool Database from the Menu -> Options menu entry
- fixed a bug in handling the UP/DOWN key shortcuts that caused a crash when no object was selected in the Project Tab; also made sure that the said keys are handled only for the Project Tab
- some PEP8 changes and other minor changes
+- updated the requirements file
5.04.2020
diff --git a/requirements.txt b/requirements.txt
index ee962276..0f1f6d04 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,7 @@
# This file contains python only requirements to be installed with pip
# Python packages that cannot be installed with pip (e.g. PyQt5, GDAL) are not included.
# Usage: pip3 install -r requirements.txt
-pyqt5==5.12.1
+pyqt5>=5.12.1
numpy>=1.16
matplotlib>=3.1
cycler>=0.10
From ecba1a9232ac321ba7b047c7b926f14fdb27d534 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 6 Apr 2020 22:28:18 +0300
Subject: [PATCH 159/209] - updated the 2Sided Tool by not allowing the Gerber
file to be mirrored without a valid reference and added some placeholder
texts
---
README.md | 1 +
flatcamTools/ToolDblSided.py | 8 +++++---
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 5ee4f317..e115e7a8 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,7 @@ CAD program, and create G-Code for Isolation routing.
- fixed a bug in handling the UP/DOWN key shortcuts that caused a crash when no object was selected in the Project Tab; also made sure that the said keys are handled only for the Project Tab
- some PEP8 changes and other minor changes
- updated the requirements file
+- updated the 2Sided Tool by not allowing the Gerber file to be mirrored without a valid reference and added some placeholder texts
5.04.2020
diff --git a/flatcamTools/ToolDblSided.py b/flatcamTools/ToolDblSided.py
index 89014940..29261cc5 100644
--- a/flatcamTools/ToolDblSided.py
+++ b/flatcamTools/ToolDblSided.py
@@ -187,6 +187,7 @@ class DblSidedTool(FlatCAMTool):
# ## Point/Box
self.point_entry = EvalEntry()
+ self.point_entry.setPlaceholderText(_("Point coordinates"))
# Add a reference
self.add_point_button = QtWidgets.QPushButton(_("Add"))
@@ -416,6 +417,7 @@ class DblSidedTool(FlatCAMTool):
)
self.alignment_holes = EvalEntry()
+ self.alignment_holes.setPlaceholderText(_("Drill coordinates"))
grid_lay4.addWidget(self.ah_label, 0, 0, 1, 2)
grid_lay4.addWidget(self.alignment_holes, 1, 0, 1, 2)
@@ -667,9 +669,9 @@ class DblSidedTool(FlatCAMTool):
try:
px, py = self.point_entry.get_value()
except TypeError:
- self.app.inform.emit('[WARNING_NOTCL] %s' % _("'Point' coordinates missing. "
- "Using Origin (0, 0) as mirroring reference."))
- px, py = (0, 0)
+ self.app.inform.emit('[WARNING_NOTCL] %s' % _("There are no Point coordinates in the Point field. "
+ "Add coords and try again ..."))
+ return
else:
selection_index_box = self.box_combo.currentIndex()
From 42949021b1fcd101b662a591f075724e6dfc3b91 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 9 Apr 2020 04:13:04 +0300
Subject: [PATCH 160/209] - fixed the Tcl Command Delete to have an argument -f
that will force deletion evading the popup (if the popup is enabled). The sme
command without a name now will delete all objects - fixed the Tcl Command
JoinExcellons - fixed the Tcl Command JoinGeometry - fixed the Tcl Command
Mirror - updated the Tcl Command Mirror to use a (X,Y) origin parameter.
Works if the -box parameter is not used. - updated the Tcl Command Offset.
Now it can use only -x or -y parameter no longer is mandatory to have both.
The one that is not present will be assumed 0.0 - updated the Tcl Command
Panelize. The -rows and -columns parameters are no longer both required. If
one is not present then it is assumed to be zero. - updated the Tcl Command
Scale. THe -origin parameter can now be a tuple of (x,y) coordinates. -
updated the Tcl Command Skew. Now it can use only -x or -y parameter no
longer is mandatory to have both. The one that is not present will be assumed
0.0 - updated the help for all the Tcl Commands
---
FlatCAMApp.py | 23 +++++++---
README.md | 13 ++++++
tclCommands/TclCommandAddCircle.py | 2 +-
tclCommands/TclCommandAddRectangle.py | 2 +-
tclCommands/TclCommandAlignDrill.py | 2 +-
tclCommands/TclCommandAlignDrillGrid.py | 2 +-
tclCommands/TclCommandBbox.py | 2 +-
tclCommands/TclCommandBounds.py | 1 +
tclCommands/TclCommandClearShell.py | 2 +-
tclCommands/TclCommandCutout.py | 2 +-
tclCommands/TclCommandDelete.py | 52 ++++++++++++++++------
tclCommands/TclCommandExportGcode.py | 4 +-
tclCommands/TclCommandExportGerber.py | 2 +-
tclCommands/TclCommandExportSVG.py | 2 +-
tclCommands/TclCommandExteriors.py | 4 +-
tclCommands/TclCommandFollow.py | 4 +-
tclCommands/TclCommandGeoCutout.py | 4 +-
tclCommands/TclCommandGeoUnion.py | 6 +--
tclCommands/TclCommandGetNames.py | 4 +-
tclCommands/TclCommandGetSys.py | 4 +-
tclCommands/TclCommandImportSvg.py | 4 +-
tclCommands/TclCommandInteriors.py | 6 +--
tclCommands/TclCommandIsolate.py | 12 +++--
tclCommands/TclCommandJoinExcellon.py | 21 ++++-----
tclCommands/TclCommandJoinGeometry.py | 18 ++++----
tclCommands/TclCommandListSys.py | 2 +-
tclCommands/TclCommandMillDrills.py | 16 ++++---
tclCommands/TclCommandMillSlots.py | 14 +++---
tclCommands/TclCommandMirror.py | 43 +++++++++++-------
tclCommands/TclCommandNew.py | 2 +-
tclCommands/TclCommandNewExcellon.py | 2 +-
tclCommands/TclCommandNewGeometry.py | 5 ++-
tclCommands/TclCommandNewGerber.py | 2 +-
tclCommands/TclCommandNregions.py | 4 +-
tclCommands/TclCommandOffset.py | 23 ++++++----
tclCommands/TclCommandOpenExcellon.py | 10 ++++-
tclCommands/TclCommandOpenGCode.py | 10 +++--
tclCommands/TclCommandOpenGerber.py | 11 +++--
tclCommands/TclCommandOpenProject.py | 10 +++--
tclCommands/TclCommandOptions.py | 6 +--
tclCommands/TclCommandPanelize.py | 28 +++++++++---
tclCommands/TclCommandPlotAll.py | 2 +-
tclCommands/TclCommandPlotObjects.py | 8 ++--
tclCommands/TclCommandSaveProject.py | 7 ++-
tclCommands/TclCommandSaveSys.py | 4 +-
tclCommands/TclCommandScale.py | 29 ++++++++----
tclCommands/TclCommandSetActive.py | 4 +-
tclCommands/TclCommandSetOrigin.py | 8 ++--
tclCommands/TclCommandSetSys.py | 4 +-
tclCommands/TclCommandSkew.py | 31 ++++++++-----
tclCommands/TclCommandSubtractPoly.py | 8 ++--
tclCommands/TclCommandSubtractRectangle.py | 5 ++-
tclCommands/TclCommandWriteGCode.py | 4 +-
53 files changed, 322 insertions(+), 178 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 4bdbc575..6f6d0919 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -1033,7 +1033,7 @@ class App(QtCore.QObject):
'Toolchange_manual, Users, all, angle_x, angle_y, axis, auto, axisoffset, '
'box, center_x, center_y, columns, combine, connect, contour, default, '
'depthperpass, dia, diatol, dist, drilled_dias, drillz, dwelltime, '
- 'extracut_length, '
+ 'extracut_length, f, '
'feedrate_z, grbl_11, GRBL_laser, gridoffsety, gridx, gridy, has_offset, '
'holes, hpgl, iso_type, line_xyz, margin, marlin, method, milled_dias, '
'minoffset, name, offset, opt_type, order, outname, overlap, '
@@ -2305,7 +2305,8 @@ class App(QtCore.QObject):
# #####################################################################################
self.tcl_commands_list = ['add_circle', 'add_poly', 'add_polygon', 'add_polyline', 'add_rectangle',
'aligndrill', 'aligndrillgrid', 'bbox', 'bounding_box', 'clear', 'cncjob', 'cutout',
- 'delete', 'drillcncjob', 'export_dxf', 'edxf', 'export_excellon', 'ee', 'export_exc',
+ 'del', 'delete', 'drillcncjob', 'export_dxf', 'edxf', 'export_excellon', 'ee',
+ 'export_exc',
'export_gcode', 'export_gerber', 'egr', 'export_svg', 'ext', 'exteriors', 'follow',
'geo_union', 'geocutout', 'get_names', 'get_sys', 'getsys', 'help', 'import_svg',
'interiors', 'isolate', 'join_excellon', 'join_excellons', 'join_geometries',
@@ -2326,7 +2327,7 @@ class App(QtCore.QObject):
'axisoffset',
'box', 'center_x', 'center_y', 'columns', 'combine', 'connect', 'contour', 'default',
'depthperpass', 'dia', 'diatol', 'dist', 'drilled_dias', 'drillz',
- 'dwelltime', 'extracut_length',
+ 'dwelltime', 'extracut_length', 'f',
'feedrate_z', 'grbl_11', 'GRBL_laser', 'gridoffsety', 'gridx', 'gridy',
'has_offset', 'holes', 'hpgl', 'iso_type', 'line_xyz', 'margin', 'marlin', 'method',
'milled_dias', 'minoffset', 'name', 'offset', 'opt_type', 'order',
@@ -7201,10 +7202,11 @@ class App(QtCore.QObject):
# Hovering over Selected tab, if the selected tab is a Geometry it will delete tools in tool table. But even if
# there is a Selected tab in focus with a Geometry inside, if you hover over canvas it will delete an object.
# Complicated, I know :)
- def on_delete(self):
+ def on_delete(self, force_deletion=False):
"""
Delete the currently selected FlatCAMObjs.
+ :param force_deletion: used by Tcl command
:return: None
"""
self.report_usage("on_delete()")
@@ -7216,7 +7218,7 @@ class App(QtCore.QObject):
# a geometry object before we update it.
if self.geo_editor.editor_active is False and self.exc_editor.editor_active is False \
and self.grb_editor.editor_active is False:
- if self.defaults["global_delete_confirmation"] is True:
+ if self.defaults["global_delete_confirmation"] is True and force_deletion is False:
msgbox = QtWidgets.QMessageBox()
msgbox.setWindowTitle(_("Delete objects"))
msgbox.setWindowIcon(QtGui.QIcon(self.resource_location + '/deleteshape32.png'))
@@ -7230,7 +7232,10 @@ class App(QtCore.QObject):
msgbox.exec_()
response = msgbox.clickedButton()
- if response == bt_ok or self.defaults["global_delete_confirmation"] is False:
+ if self.defaults["global_delete_confirmation"] is False or force_deletion is True:
+ response = bt_ok
+
+ if response == bt_ok:
if self.collection.get_active():
self.log.debug("App.on_delete()")
@@ -9539,6 +9544,7 @@ class App(QtCore.QObject):
File menu callback for opening a Gerber.
:param signal: required because clicking the entry will generate a checked signal which needs a container
+ :param name:
:return: None
"""
@@ -9585,6 +9591,7 @@ class App(QtCore.QObject):
File menu callback for opening an Excellon file.
:param signal: required because clicking the entry will generate a checked signal which needs a container
+ :param name:
:return: None
"""
@@ -9619,10 +9626,12 @@ class App(QtCore.QObject):
def on_fileopengcode(self, signal: bool = None, name=None):
"""
+
File menu call back for opening gcode.
:param signal: required because clicking the entry will generate a checked signal which needs a container
- :return: None
+ :param name:
+ :return:
"""
self.report_usage("on_fileopengcode")
diff --git a/README.md b/README.md
index e115e7a8..678a9953 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,19 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+9.4.2020
+
+- fixed the Tcl Command Delete to have an argument -f that will force deletion evading the popup (if the popup is enabled). The sme command without a name now will delete all objects
+- fixed the Tcl Command JoinExcellons
+- fixed the Tcl Command JoinGeometry
+- fixed the Tcl Command Mirror
+- updated the Tcl Command Mirror to use a (X,Y) origin parameter. Works if the -box parameter is not used.
+- updated the Tcl Command Offset. Now it can use only -x or -y parameter no longer is mandatory to have both. The one that is not present will be assumed 0.0
+- updated the Tcl Command Panelize. The -rows and -columns parameters are no longer both required. If one is not present then it is assumed to be zero.
+- updated the Tcl Command Scale. THe -origin parameter can now be a tuple of (x,y) coordinates.
+- updated the Tcl Command Skew. Now it can use only -x or -y parameter no longer is mandatory to have both. The one that is not present will be assumed 0.0
+- updated the help for all the Tcl Commands
+
6.04.2020
- added key shortcuts (arrow up/down) that will select the objects in the Project tab if the focus is in that tab
diff --git a/tclCommands/TclCommandAddCircle.py b/tclCommands/TclCommandAddCircle.py
index 181484d6..f48ece80 100644
--- a/tclCommands/TclCommandAddCircle.py
+++ b/tclCommands/TclCommandAddCircle.py
@@ -38,7 +38,7 @@ class TclCommandAddCircle(TclCommand):
('center_y', 'Y coordinates of the center of the circle.'),
('radius', 'Radius of the circle.')
]),
- 'examples': []
+ 'examples': ['add_circle geo_name 1.0 2.0 3']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandAddRectangle.py b/tclCommands/TclCommandAddRectangle.py
index fa26ae02..0fa7096e 100644
--- a/tclCommands/TclCommandAddRectangle.py
+++ b/tclCommands/TclCommandAddRectangle.py
@@ -37,7 +37,7 @@ class TclCommandAddRectangle(TclCommandSignaled):
('x0 y0', 'Bottom left corner coordinates.'),
('x1 y1', 'Top right corner coordinates.')
]),
- 'examples': []
+ 'examples': ["add_rectangle geo_name 0 0 10 10"]
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandAlignDrill.py b/tclCommands/TclCommandAlignDrill.py
index e34c8afd..1659b2a4 100644
--- a/tclCommands/TclCommandAlignDrill.py
+++ b/tclCommands/TclCommandAlignDrill.py
@@ -41,7 +41,7 @@ class TclCommandAlignDrill(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Create excellon with drills for aligment.",
+ 'main': "Create an Excellon object with drills for alignment.",
'args': collections.OrderedDict([
('name', 'Name of the object (Gerber or Excellon) to mirror.'),
('dia', 'Tool diameter'),
diff --git a/tclCommands/TclCommandAlignDrillGrid.py b/tclCommands/TclCommandAlignDrillGrid.py
index e15bd840..ac86f198 100644
--- a/tclCommands/TclCommandAlignDrillGrid.py
+++ b/tclCommands/TclCommandAlignDrillGrid.py
@@ -39,7 +39,7 @@ class TclCommandAlignDrillGrid(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Create excellon with drills for aligment grid.",
+ 'main': "Create an Excellon object with drills for alignment arranged in a grid.",
'args': collections.OrderedDict([
('outname', 'Name of the object to create.'),
('dia', 'Tool diameter.'),
diff --git a/tclCommands/TclCommandBbox.py b/tclCommands/TclCommandBbox.py
index 06cef7d8..a3df3d16 100644
--- a/tclCommands/TclCommandBbox.py
+++ b/tclCommands/TclCommandBbox.py
@@ -38,7 +38,7 @@ class TclCommandBbox(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Creates a Geometry object that surrounds the object.",
+ 'main': "Creates a rectangular Geometry object that surrounds the object.",
'args': collections.OrderedDict([
('name', 'Object name for which to create bounding box. String'),
('outname', 'Name of the resulting Geometry object. String.'),
diff --git a/tclCommands/TclCommandBounds.py b/tclCommands/TclCommandBounds.py
index e4d53c7b..a03a97c0 100644
--- a/tclCommands/TclCommandBounds.py
+++ b/tclCommands/TclCommandBounds.py
@@ -12,6 +12,7 @@ if '_' not in builtins.__dict__:
log = logging.getLogger('base')
+
class TclCommandBounds(TclCommand):
"""
Tcl shell command to return the bounds values for a supplied list of objects (identified by their names).
diff --git a/tclCommands/TclCommandClearShell.py b/tclCommands/TclCommandClearShell.py
index d765367a..4672ecae 100644
--- a/tclCommands/TclCommandClearShell.py
+++ b/tclCommands/TclCommandClearShell.py
@@ -38,7 +38,7 @@ class TclCommandClearShell(TclCommand):
'main': "Clear the text in the Tcl Shell browser.",
'args': collections.OrderedDict([
]),
- 'examples': []
+ 'examples': ['clear']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandCutout.py b/tclCommands/TclCommandCutout.py
index 3df71efb..c074fa8e 100644
--- a/tclCommands/TclCommandCutout.py
+++ b/tclCommands/TclCommandCutout.py
@@ -48,7 +48,7 @@ class TclCommandCutout(TclCommand):
('gapsize', 'Size of gap. Default = 0.1'),
('gaps', "Type of gaps. Can be: 'tb' = top-bottom, 'lr' = left-right and '4' = one each side. Default = 4"),
]),
- 'examples': []
+ 'examples': ['cutout new_geo -dia 1.2 -margin 0.1 -gapsize 1 -gaps "tb" ']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandDelete.py b/tclCommands/TclCommandDelete.py
index c5deb08d..43a69693 100644
--- a/tclCommands/TclCommandDelete.py
+++ b/tclCommands/TclCommandDelete.py
@@ -12,7 +12,7 @@ class TclCommandDelete(TclCommand):
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
- aliases = ['delete']
+ aliases = ['delete', 'del']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
@@ -21,19 +21,23 @@ class TclCommandDelete(TclCommand):
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
-
+ ('f', bool)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
- required = ['name']
+ required = []
# structured help for current command, args needs to be ordered
help = {
- 'main': 'Deletes the given object.',
+ 'main': 'Deletes the given object. If no name is given will delete all objects.',
'args': collections.OrderedDict([
('name', 'Name of the Object.'),
+ ('f', 'Use this parameter to force deletion.')
]),
- 'examples': []
+ 'examples': ['del new_geo -f True\n'
+ 'delete new_geo -f 1\n'
+ 'del new_geo -f\n'
+ 'del new_geo']
}
def execute(self, args, unnamed_args):
@@ -43,13 +47,35 @@ class TclCommandDelete(TclCommand):
:param unnamed_args:
:return:
"""
-
- obj_name = args['name']
+ obj_name = None
try:
- # deselect all to avoid delete selected object when run delete from shell
- self.app.collection.set_all_inactive()
- self.app.collection.set_active(str(obj_name))
- self.app.on_delete() # Todo: This is an event handler for the GUI... bad?
- except Exception as e:
- return "Command failed: %s" % str(e)
+ obj_name = args['name']
+ delete_all = False
+ except KeyError:
+ delete_all = True
+
+ is_forced = False
+ if 'f' in args:
+ try:
+ if args['f'] is None:
+ is_forced = True
+ else:
+ is_forced = True if eval(str(args['f'])) else False
+ except KeyError:
+ is_forced = True
+
+ if delete_all is False:
+ try:
+ # deselect all to avoid delete selected object when run delete from shell
+ self.app.collection.set_all_inactive()
+ self.app.collection.set_active(str(obj_name))
+ self.app.on_delete(force_deletion=is_forced)
+ except Exception as e:
+ return "Command failed: %s" % str(e)
+ else:
+ try:
+ self.app.collection.set_all_active()
+ self.app.on_delete(force_deletion=is_forced)
+ except Exception as e:
+ return "Command failed: %s" % str(e)
diff --git a/tclCommands/TclCommandExportGcode.py b/tclCommands/TclCommandExportGcode.py
index 23842c91..2981e272 100644
--- a/tclCommands/TclCommandExportGcode.py
+++ b/tclCommands/TclCommandExportGcode.py
@@ -48,11 +48,11 @@ class TclCommandExportGcode(TclCommandSignaled):
help = {
'main': "Export gcode into console output.",
'args': collections.OrderedDict([
- ('name', 'Name of the source Geometry object.'),
+ ('name', 'Name of the source Geometry object. Required.'),
('preamble', 'Prepend GCODE.'),
('postamble', 'Append GCODE.')
]),
- 'examples': []
+ 'examples': ['export_gcode geo_name -preamble "G01 X10 Y10" -postamble "G00 X20 Y20\nM04"']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandExportGerber.py b/tclCommands/TclCommandExportGerber.py
index a4d27152..0fc7b0aa 100644
--- a/tclCommands/TclCommandExportGerber.py
+++ b/tclCommands/TclCommandExportGerber.py
@@ -31,7 +31,7 @@ class TclCommandExportGerber(TclCommand):
help = {
'main': "Export a Gerber Object as a Gerber File.",
'args': collections.OrderedDict([
- ('obj_name', 'Name of the object to export.'),
+ ('obj_name', 'Name of the object to export. Required.'),
('filename', 'Path to the file to export.')
]),
'examples': ['export_gerber my_gerber path/my_file.gbr']
diff --git a/tclCommands/TclCommandExportSVG.py b/tclCommands/TclCommandExportSVG.py
index ebe95bc6..bc6efce9 100644
--- a/tclCommands/TclCommandExportSVG.py
+++ b/tclCommands/TclCommandExportSVG.py
@@ -33,7 +33,7 @@ class TclCommandExportSVG(TclCommand):
help = {
'main': "Export a Geometry Object as a SVG File.",
'args': collections.OrderedDict([
- ('name', 'Name of the object export.'),
+ ('name', 'Name of the object export. Required.'),
('filename', 'Path to the file to export.'),
('scale_factor', 'Multiplication factor used for scaling line widths during export.')
]),
diff --git a/tclCommands/TclCommandExteriors.py b/tclCommands/TclCommandExteriors.py
index e6a65503..cb3f041a 100644
--- a/tclCommands/TclCommandExteriors.py
+++ b/tclCommands/TclCommandExteriors.py
@@ -29,10 +29,10 @@ class TclCommandExteriors(TclCommandSignaled):
help = {
'main': "Get exteriors of polygons.",
'args': collections.OrderedDict([
- ('name', 'Name of the source Geometry object.'),
+ ('name', 'Name of the source Geometry object. Required.'),
('outname', 'Name of the resulting Geometry object.')
]),
- 'examples': []
+ 'examples': ['ext geo_source_name -outname "final_geo"']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandFollow.py b/tclCommands/TclCommandFollow.py
index 59ad53ee..0ca8ab5e 100644
--- a/tclCommands/TclCommandFollow.py
+++ b/tclCommands/TclCommandFollow.py
@@ -29,10 +29,10 @@ class TclCommandFollow(TclCommandSignaled):
help = {
'main': "Creates a geometry object following gerber paths.",
'args': collections.OrderedDict([
- ('name', 'Object name to follow.'),
+ ('name', 'Object name to follow. Required.'),
('outname', 'Name of the resulting Geometry object.')
]),
- 'examples': ['follow name -outname name_follow']
+ 'examples': ['follow name -outname "name_follow"']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandGeoCutout.py b/tclCommands/TclCommandGeoCutout.py
index f7df8108..c138d4ad 100644
--- a/tclCommands/TclCommandGeoCutout.py
+++ b/tclCommands/TclCommandGeoCutout.py
@@ -45,14 +45,14 @@ class TclCommandGeoCutout(TclCommandSignaled):
help = {
'main': 'Creates board cutout from an object (Gerber or Geometry) of any shape',
'args': collections.OrderedDict([
- ('name', 'Name of the object.'),
+ ('name', 'Name of the object to be cutout. Required'),
('dia', 'Tool diameter.'),
('margin', 'Margin over bounds.'),
('gapsize', 'size of gap.'),
('gaps', "type of gaps. Can be: 'tb' = top-bottom, 'lr' = left-right, '2tb' = 2top-2bottom, "
"'2lr' = 2left-2right, '4' = 4 cuts, '8' = 8 cuts")
]),
- 'examples': [" #isolate margin for example from fritzing arduino shield or any svg etc\n" +
+ 'examples': [" #isolate margin for example from Fritzing arduino shield or any svg etc\n" +
" isolate BCu_margin -dia 3 -overlap 1\n" +
"\n" +
" #create exteriors from isolated object\n" +
diff --git a/tclCommands/TclCommandGeoUnion.py b/tclCommands/TclCommandGeoUnion.py
index b0be4734..ac4fa4ea 100644
--- a/tclCommands/TclCommandGeoUnion.py
+++ b/tclCommands/TclCommandGeoUnion.py
@@ -32,12 +32,12 @@ class TclCommandGeoUnion(TclCommand):
help = {
'main': ('Runs a union operation (addition) on the components '
'of the geometry object. For example, if it contains '
- '2 intersecting polygons, this opperation adds them into'
+ '2 intersecting polygons, this operation adds them into'
'a single larger polygon.'),
'args': collections.OrderedDict([
- ('name', 'Name of the Geometry Object.'),
+ ('name', 'Name of the Geometry Object that contain the components to be joined. Required.'),
]),
- 'examples': []
+ 'examples': ['geo_union target_geo']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandGetNames.py b/tclCommands/TclCommandGetNames.py
index 6b597f6f..7cca9a46 100644
--- a/tclCommands/TclCommandGetNames.py
+++ b/tclCommands/TclCommandGetNames.py
@@ -29,11 +29,11 @@ class TclCommandGetNames(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': 'Lists the names of objects in the project.',
+ 'main': 'Lists the names of objects in the project. It returns a string with names separated by \n',
'args': collections.OrderedDict([
]),
- 'examples': []
+ 'examples': ['get_names']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandGetSys.py b/tclCommands/TclCommandGetSys.py
index 915ac18e..f98c3315 100644
--- a/tclCommands/TclCommandGetSys.py
+++ b/tclCommands/TclCommandGetSys.py
@@ -36,9 +36,9 @@ class TclCommandGetSys(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Returns the value of the system variable.",
+ 'main': "Returns the value of the targeted system variable.",
'args': collections.OrderedDict([
- ('name', 'Name of the system variable.'),
+ ('name', 'Name of the system variable. Required.'),
]),
'examples': ['get_sys excellon_zeros']
}
diff --git a/tclCommands/TclCommandImportSvg.py b/tclCommands/TclCommandImportSvg.py
index 6489db15..0617090e 100644
--- a/tclCommands/TclCommandImportSvg.py
+++ b/tclCommands/TclCommandImportSvg.py
@@ -30,11 +30,11 @@ class TclCommandImportSvg(TclCommandSignaled):
help = {
'main': "Import an SVG file as a Geometry Object..",
'args': collections.OrderedDict([
- ('filename', 'Path to file to open.'),
+ ('filename', 'Absolute path to file to open. Required.'),
('type', 'Import as gerber or geometry(default).'),
('outname', 'Name of the resulting Geometry object.')
]),
- 'examples': []
+ 'examples': ['import_svg D:\\my_beautiful_svg_file.SVG']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandInteriors.py b/tclCommands/TclCommandInteriors.py
index d4a1adb3..f22ef1db 100644
--- a/tclCommands/TclCommandInteriors.py
+++ b/tclCommands/TclCommandInteriors.py
@@ -27,12 +27,12 @@ class TclCommandInteriors(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Get interiors of polygons.",
+ 'main': "Return the interiors of polygons as a list of Shapely geometry elements.",
'args': collections.OrderedDict([
- ('name', 'Name of the source Geometry object.'),
+ ('name', 'Name of the source Geometry object. Required.'),
('outname', 'Name of the resulting Geometry object.')
]),
- 'examples': []
+ 'examples': ['interiors my_geo_name -outname "outputed_geo"']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandIsolate.py b/tclCommands/TclCommandIsolate.py
index f2864303..542dd3c3 100644
--- a/tclCommands/TclCommandIsolate.py
+++ b/tclCommands/TclCommandIsolate.py
@@ -29,7 +29,7 @@ class TclCommandIsolate(TclCommandSignaled):
('dia', float),
('passes', int),
('overlap', float),
- ('combine', int),
+ ('combine', bool),
('outname', str),
('follow', str),
('iso_type', int)
@@ -43,18 +43,18 @@ class TclCommandIsolate(TclCommandSignaled):
help = {
'main': "Creates isolation routing geometry for the given Gerber.",
'args': collections.OrderedDict([
- ('name', 'Name of the source object.'),
+ ('name', 'Name of the source object. Required.'),
('dia', 'Tool diameter.'),
('passes', 'Passes of tool width.'),
('overlap', 'Percentage of tool diameter to overlap current pass over previous pass. Float [0, 99.9999]\n'
'E.g: for a 25% from tool diameter overlap use -overlap 25'),
- ('combine', 'Combine all passes into one geometry.'),
+ ('combine', 'Combine all passes into one geometry. Can be True or False, 1 or 0'),
('outname', 'Name of the resulting Geometry object.'),
('follow', 'Create a Geometry that follows the Gerber path.'),
('iso_type', 'A value of 0 will isolate exteriors, a value of 1 will isolate interiors '
'and a value of 2 will do full isolation.')
]),
- 'examples': []
+ 'examples': ['isolate my_geo -dia 0.1 -passes 2 -overlap 10 -combine True -iso_type 2 -outname out_geo']
}
def execute(self, args, unnamed_args):
@@ -80,6 +80,10 @@ class TclCommandIsolate(TclCommandSignaled):
if 'follow' not in args:
args['follow'] = None
+ # evaluate this parameter so True, False, 0 and 1 works
+ if "combine" in args:
+ args['combine'] = eval(args['combine'])
+
obj = self.app.collection.get_by_name(name)
if obj is None:
self.raise_tcl_error("Object not found: %s" % name)
diff --git a/tclCommands/TclCommandJoinExcellon.py b/tclCommands/TclCommandJoinExcellon.py
index efe6290e..c385b55c 100644
--- a/tclCommands/TclCommandJoinExcellon.py
+++ b/tclCommands/TclCommandJoinExcellon.py
@@ -22,7 +22,6 @@ class TclCommandJoinExcellon(TclCommand):
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
-
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
@@ -30,14 +29,14 @@ class TclCommandJoinExcellon(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Runs a merge operation (join) on the Excellon objects.",
+ 'main': "Runs a merge operation (join) on the Excellon objects.\n"
+ "The names of the Excellon objects to be merged will be entered after the outname,\n"
+ "separated by spaces. See the example bellow.\n"
+ "WARNING: if the name of an Excellon objects has spaces, enclose the name with quotes.",
'args': collections.OrderedDict([
- ('name', 'Name of the new Excellon Object.'),
- ('obj_name_0', 'Name of the first object'),
- ('obj_name_1', 'Name of the second object.'),
- ('obj_name_2...', 'Additional object names')
+ ('outname', 'Name of the new Excellon Object made by joining of other Excellon objects. Required'),
]),
- 'examples': []
+ 'examples': ['join_excellons merged_new_excellon exc_name_1 "exc name_2"']
}
def execute(self, args, unnamed_args):
@@ -48,7 +47,7 @@ class TclCommandJoinExcellon(TclCommand):
:return:
"""
- outname = args['name']
+ outname = args['outname']
obj_names = unnamed_args
objs = []
@@ -60,7 +59,9 @@ class TclCommandJoinExcellon(TclCommand):
objs.append(obj)
def initialize(obj_, app):
- FlatCAMExcellon.merge(objs, obj_)
+ FlatCAMExcellon.merge(self, objs, obj_)
- if objs is not None:
+ if objs:
self.app.new_object("excellon", outname, initialize, plot=False)
+ else:
+ return "No Excellon objects to be joined."
diff --git a/tclCommands/TclCommandJoinGeometry.py b/tclCommands/TclCommandJoinGeometry.py
index 74036d80..d3208877 100644
--- a/tclCommands/TclCommandJoinGeometry.py
+++ b/tclCommands/TclCommandJoinGeometry.py
@@ -30,14 +30,14 @@ class TclCommandJoinGeometry(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Runs a merge operation (join) on the Excellon objects.",
+ 'main': "Runs a merge operation (join) on the Geometry objects.\n"
+ "The names of the Geometry objects to be merged will be entered after the outname,\n"
+ "separated by spaces. See the example bellow.\n"
+ "WARNING: if the name of an Geometry objects has spaces, enclose the name with quotes.",
'args': collections.OrderedDict([
- ('outname', 'Name of the new Geometry Object.'),
- ('obj_name_0', 'Name of the first object'),
- ('obj_name_1', 'Name of the second object.'),
- ('obj_name_2...', 'Additional object names')
+ ('outname', 'Name of the new Geometry Object made by joining of other Geometry objects. Required'),
]),
- 'examples': []
+ 'examples': ['join_geometry merged_new_geo geo_name_1 "geo name_2"']
}
def execute(self, args, unnamed_args):
@@ -60,7 +60,9 @@ class TclCommandJoinGeometry(TclCommand):
objs.append(obj)
def initialize(obj_, app):
- FlatCAMGeometry.merge(objs, obj_)
+ FlatCAMGeometry.merge(self, objs, obj_)
- if objs is not None:
+ if objs:
self.app.new_object("geometry", outname, initialize, plot=False)
+ else:
+ return "No Geometry objects to be joined."
diff --git a/tclCommands/TclCommandListSys.py b/tclCommands/TclCommandListSys.py
index 58d8c8e3..cff9ca06 100644
--- a/tclCommands/TclCommandListSys.py
+++ b/tclCommands/TclCommandListSys.py
@@ -40,7 +40,7 @@ class TclCommandListSys(TclCommand):
"of the system variable.\n"
"In that case it will list only the system variables that starts with that string.\n"
"Main categories start with: gerber or excellon or geometry or cncjob or global.\n"
- "Note: Use get_sys TclCommand to get the value and set_sys TclCommand to set it.\n",
+ "Note: Use 'get_sys system variable' to get the value and 'set_sys system variable value' to set it.\n",
'args': collections.OrderedDict([
]),
'examples': ['list_sys',
diff --git a/tclCommands/TclCommandMillDrills.py b/tclCommands/TclCommandMillDrills.py
index a7d607c2..1e8684d0 100644
--- a/tclCommands/TclCommandMillDrills.py
+++ b/tclCommands/TclCommandMillDrills.py
@@ -34,7 +34,7 @@ class TclCommandMillDrills(TclCommandSignaled):
('milled_dias', str),
('outname', str),
('tooldia', float),
- ('use_threads', bool),
+ ('use_thread', bool),
('diatol', float)
])
@@ -45,10 +45,13 @@ class TclCommandMillDrills(TclCommandSignaled):
help = {
'main': "Create Geometry Object for milling drill holes from Excellon.",
'args': collections.OrderedDict([
- ('name', 'Name of the Excellon Object.'),
- ('milled_dias', 'Comma separated tool diameters of the drills to be milled (example: 0.6, 1.0 or 3.125).'),
+ ('name', 'Name of the Excellon Object. Required.'),
+ ('milled_dias', 'Comma separated tool diameters of the drills to be milled (example: 0.6, 1.0 or 3.125).\n'
+ 'Exception: if you enter "all" then the drills for all tools will be milled.\n'
+ 'WARNING: no spaces are allowed in the list of tools.\n'
+ 'As a precaution you can enclose them with quotes.'),
('tooldia', 'Diameter of the milling tool (example: 0.1).'),
- ('outname', 'Name of object to create.'),
+ ('outname', 'Name of object to be created holding the milled geometries.'),
('use_thread', 'If to use multithreading: True or False.'),
('diatol', 'Tolerance. Percentange (0.0 ... 100.0) within which dias in milled_dias will be judged to be '
'the same as the ones in the tools from the Excellon object. E.g: if in milled_dias we have a '
@@ -56,7 +59,8 @@ class TclCommandMillDrills(TclCommandSignaled):
'diatol = 5.0 then the drills with the dia = (0.95 ... 1.05) '
'in Excellon will be processed. Float number.')
]),
- 'examples': ['milldrills mydrills', 'milld my_excellon.drl']
+ 'examples': ['milldrills mydrills -milled_dias "0.6,0.8" -tooldia 0.1 -diatol 10 -outname milled_holes',
+ 'milld my_excellon.drl']
}
def execute(self, args, unnamed_args):
@@ -85,8 +89,6 @@ class TclCommandMillDrills(TclCommandSignaled):
if not obj.drills:
self.raise_tcl_error("The Excellon object has no drills: %s" % name)
- units = self.app.defaults['units'].upper()
-
try:
if 'milled_dias' in args and args['milled_dias'] != 'all':
diameters = [x.strip() for x in args['milled_dias'].split(",") if x != '']
diff --git a/tclCommands/TclCommandMillSlots.py b/tclCommands/TclCommandMillSlots.py
index 9665c91d..af6070be 100644
--- a/tclCommands/TclCommandMillSlots.py
+++ b/tclCommands/TclCommandMillSlots.py
@@ -34,7 +34,7 @@ class TclCommandMillSlots(TclCommandSignaled):
('milled_dias', str),
('outname', str),
('tooldia', float),
- ('use_threads', bool),
+ ('use_thread', bool),
('diatol', float)
])
@@ -45,10 +45,13 @@ class TclCommandMillSlots(TclCommandSignaled):
help = {
'main': "Create Geometry Object for milling slot holes from Excellon.",
'args': collections.OrderedDict([
- ('name', 'Name of the Excellon Object.'),
- ('milled_dias', 'Comma separated tool diameters of the slots to be milled (example: 0.6, 1.0 or 3.125).'),
+ ('name', 'Name of the Excellon Object. Required.'),
+ ('milled_dias', 'Comma separated tool diameters of the slots to be milled (example: 0.6, 1.0 or 3.125).\n'
+ 'Exception: if you enter "all" then the slots for all tools will be milled.\n'
+ 'WARNING: no spaces are allowed in the list of tools.\n'
+ 'As a precaution you can enclose them with quotes.'),
('tooldia', 'Diameter of the milling tool (example: 0.1).'),
- ('outname', 'Name of object to create.'),
+ ('outname', 'Name of object to be created holding the milled geometries.'),
('use_thread', 'If to use multithreading: True or False.'),
('diatol', 'Tolerance. Percentange (0.0 ... 100.0) within which dias in milled_dias will be judged to be '
'the same as the ones in the tools from the Excellon object. E.g: if in milled_dias we have a '
@@ -56,7 +59,8 @@ class TclCommandMillSlots(TclCommandSignaled):
'diatol = 5.0 then the slots with the dia = (0.95 ... 1.05) '
'in Excellon will be processed. Float number.')
]),
- 'examples': ['millslots mydrills', 'mills my_excellon.drl']
+ 'examples': ['millslots myslots -milled_dias "0.6,0.8" -tooldia 0.1 -diatol 10 -outname milled_slots',
+ 'mills my_excellon.drl']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandMirror.py b/tclCommands/TclCommandMirror.py
index 819f26ef..cc29852f 100644
--- a/tclCommands/TclCommandMirror.py
+++ b/tclCommands/TclCommandMirror.py
@@ -24,22 +24,25 @@ class TclCommandMirror(TclCommandSignaled):
option_types = collections.OrderedDict([
('axis', str),
('box', str),
- ('dist', float)
+ ('origin', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
- required = ['name', 'axis']
+ required = ['name']
# structured help for current command, args needs to be ordered
help = {
- 'main': "Opens an Excellon file.",
+ 'main': "Will mirror an named object.",
'args': collections.OrderedDict([
- ('name', 'Name of the object (Gerber or Excellon) to mirror.'),
- ('box', 'Name of object which act as box (cutout for example.)'),
+ ('name', 'Name of the object (Gerber, Geometry or Excellon) to be mirrored. Required.'),
('axis', 'Mirror axis parallel to the X or Y axis.'),
- ('dist', 'Distance of the mirror axis to the X or Y axis.')
+ ('box', 'Name of object which act as box (cutout for example.)'),
+ ('origin', 'Reference point . It is used only if the box is not used. Format (x,y).\n'
+ 'Comma will separate the X and Y coordinates.\n'
+ 'WARNING: no spaces are allowed. If uncertain enclose the two values inside parenthesis.\n'
+ 'See the example.')
]),
- 'examples': []
+ 'examples': ['mirror obj_name -box box_geo -axis X -origin 3.2,4.7']
}
def execute(self, args, unnamed_args):
@@ -69,10 +72,13 @@ class TclCommandMirror(TclCommandSignaled):
return "ERROR: Only Gerber, Excellon and Geometry objects can be mirrored."
# Axis
- try:
- axis = args['axis'].upper()
- except KeyError:
- return "ERROR: Specify -axis X or -axis Y"
+ if 'axis' in args:
+ try:
+ axis = args['axis'].upper()
+ except KeyError:
+ axis = 'Y'
+ else:
+ axis = 'Y'
# Box
if 'box' in args:
@@ -91,19 +97,22 @@ class TclCommandMirror(TclCommandSignaled):
obj.mirror(axis, [px, py])
obj.plot()
-
+ return
except Exception as e:
return "Operation failed: %s" % str(e)
- else:
+ # Origin
+ if 'origin' in args:
try:
- dist = float(args['dist'])
+ origin_val = eval(args['origin'])
+ x = float(origin_val[0])
+ y = float(origin_val[1])
except KeyError:
- dist = 0.0
+ x, y = (0, 0)
except ValueError:
- return "Invalid distance: %s" % args['dist']
+ return "Invalid distance: %s" % str(args['origin'])
try:
- obj.mirror(axis, [dist, dist])
+ obj.mirror(axis, [x, y])
except Exception as e:
return "Operation failed: %s" % str(e)
diff --git a/tclCommands/TclCommandNew.py b/tclCommands/TclCommandNew.py
index 757412d3..66ff83b9 100644
--- a/tclCommands/TclCommandNew.py
+++ b/tclCommands/TclCommandNew.py
@@ -24,7 +24,7 @@ class TclCommandNew(TclCommand):
help = {
'main': "Starts a new project. Clears objects from memory.",
'args': collections.OrderedDict(),
- 'examples': []
+ 'examples': ['new']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandNewExcellon.py b/tclCommands/TclCommandNewExcellon.py
index 2c540fe1..c1322133 100644
--- a/tclCommands/TclCommandNewExcellon.py
+++ b/tclCommands/TclCommandNewExcellon.py
@@ -39,7 +39,7 @@ class TclCommandNewExcellon(TclCommandSignaled):
'args': collections.OrderedDict([
('name', 'New object name.'),
]),
- 'examples': []
+ 'examples': ['new_excellon my_excellon', 'new_excellon']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandNewGeometry.py b/tclCommands/TclCommandNewGeometry.py
index 089b2c50..4af616c6 100644
--- a/tclCommands/TclCommandNewGeometry.py
+++ b/tclCommands/TclCommandNewGeometry.py
@@ -28,11 +28,12 @@ class TclCommandNewGeometry(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Creates a new empty geometry object.",
+ 'main': "Creates a new empty Geometry object.",
'args': collections.OrderedDict([
('name', 'New object name.'),
]),
- 'examples': []
+ 'examples': ['new_geometry\n'
+ 'new_geometry my_new_geo']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandNewGerber.py b/tclCommands/TclCommandNewGerber.py
index bccbd923..7a667813 100644
--- a/tclCommands/TclCommandNewGerber.py
+++ b/tclCommands/TclCommandNewGerber.py
@@ -39,7 +39,7 @@ class TclCommandNewGerber(TclCommandSignaled):
'args': collections.OrderedDict([
('name', 'New object name.'),
]),
- 'examples': []
+ 'examples': ['new_gerber', 'new_gerber my_new_gerber_name']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandNregions.py b/tclCommands/TclCommandNregions.py
index 6dbb22d5..a4146792 100644
--- a/tclCommands/TclCommandNregions.py
+++ b/tclCommands/TclCommandNregions.py
@@ -41,13 +41,13 @@ class TclCommandNregions(TclCommand):
help = {
'main': "Creates a geometry object with the non-copper regions.",
'args': collections.OrderedDict([
- ('name', 'Object name for which to create non-copper regions. String'),
+ ('name', 'Object name for which to create non-copper regions. String. Required.'),
('outname', 'Name of the resulting Geometry object. String.'),
('margin', "Specify the edge of the PCB by drawing a box around all objects with this minimum distance. "
"Float number."),
('rounded', "Resulting geometry will have rounded corners. True or False.")
]),
- 'examples': ['ncr name -outname name_ncr']
+ 'examples': ['ncr name -margin 0.1 -rounded True -outname name_ncr']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandOffset.py b/tclCommands/TclCommandOffset.py
index a7306db9..6f5fd1c7 100644
--- a/tclCommands/TclCommandOffset.py
+++ b/tclCommands/TclCommandOffset.py
@@ -23,21 +23,22 @@ class TclCommandOffset(TclCommand):
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
-
+ ('x', float),
+ ('y', float)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
- required = ['name', 'x', 'y']
+ required = ['name']
# structured help for current command, args needs to be ordered
help = {
- 'main': "Changes the position of the object.",
+ 'main': "Changes the position of the object on X and/or Y axis.",
'args': collections.OrderedDict([
- ('name', 'Name of the object to offset.'),
- ('x', 'Offset distance in the X axis.'),
- ('y', 'Offset distance in the Y axis')
+ ('name', 'Name of the object to offset. Required.'),
+ ('x', 'Offset distance in the X axis. If it is not used it will be assumed to be 0.0'),
+ ('y', 'Offset distance in the Y axis. If it is not used it will be assumed to be 0.0')
]),
- 'examples': ['offset my_geometry 1.2 -0.3']
+ 'examples': ['offset my_geometry -x 1.2 -y -0.3', 'offset my_geometry -x 1.0']
}
def execute(self, args, unnamed_args):
@@ -49,6 +50,12 @@ class TclCommandOffset(TclCommand):
"""
name = args['name']
- x, y = float(args['x']), float(args['y'])
+ off_x = args['x'] if 'x' in args else 0.0
+ off_y = args['y'] if 'y' in args else 0.0
+
+ x, y = float(off_x), float(off_y)
+
+ if (x, y) == (0.0, 0.0):
+ return
self.app.collection.get_by_name(name).offset((x, y))
diff --git a/tclCommands/TclCommandOpenExcellon.py b/tclCommands/TclCommandOpenExcellon.py
index c9f32409..167db227 100644
--- a/tclCommands/TclCommandOpenExcellon.py
+++ b/tclCommands/TclCommandOpenExcellon.py
@@ -30,10 +30,13 @@ class TclCommandOpenExcellon(TclCommandSignaled):
help = {
'main': "Opens an Excellon file.",
'args': collections.OrderedDict([
- ('filename', 'Path to file to open.'),
+ ('filename', 'Absolute path to file to open. Required.\n'
+ 'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
('outname', 'Name of the resulting Excellon object.')
]),
- 'examples': []
+ 'examples': ['open_excellon D:\\my_excellon_file.DRL',
+ 'open_excellon "D:\\my_excellon_file with spaces in the name.DRL"',
+ 'open_excellon path_to_file']
}
def execute(self, args, unnamed_args):
@@ -48,6 +51,9 @@ class TclCommandOpenExcellon(TclCommandSignaled):
filename = args.pop('filename')
# filename = filename.replace(' ', '')
+ if ' ' in filename:
+ return "The absolute path to the project file contain spaces which is not allowed.\n" \
+ "Please enclose the path within quotes."
args['plot'] = False
self.app.open_excellon(filename, **args)
diff --git a/tclCommands/TclCommandOpenGCode.py b/tclCommands/TclCommandOpenGCode.py
index d4da1423..5eaa83c9 100644
--- a/tclCommands/TclCommandOpenGCode.py
+++ b/tclCommands/TclCommandOpenGCode.py
@@ -31,10 +31,12 @@ class TclCommandOpenGCode(TclCommandSignaled):
help = {
'main': "Opens a G-Code file.",
'args': collections.OrderedDict([
- ('filename', 'Path to file to open.'),
+ ('filename', 'Absolute path to file to open. Required.\n'
+ 'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
('outname', 'Name of the resulting CNCJob object.')
]),
- 'examples': []
+ 'examples': ['open_gcode D:\\my_gcode_file.NC',
+ 'open_gcode "D:\\my_gcode_file with spaces in the name.TXT"']
}
def execute(self, args, unnamed_args):
@@ -48,6 +50,8 @@ class TclCommandOpenGCode(TclCommandSignaled):
"""
args['plot'] = False
filename = args["filename"]
- # filename = filename.replace(' ', '')
+ if ' ' in filename:
+ return "The absolute path to the project file contain spaces which is not allowed.\n" \
+ "Please enclose the path within quotes."
self.app.open_gcode(filename, **args)
diff --git a/tclCommands/TclCommandOpenGerber.py b/tclCommands/TclCommandOpenGerber.py
index 0b67f83c..037882a1 100644
--- a/tclCommands/TclCommandOpenGerber.py
+++ b/tclCommands/TclCommandOpenGerber.py
@@ -30,10 +30,12 @@ class TclCommandOpenGerber(TclCommandSignaled):
help = {
'main': "Opens a Gerber file.",
'args': collections.OrderedDict([
- ('filename', 'Path to file to open.'),
+ ('filename', 'Absolute path to file to open. Required.\n'
+ 'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
('outname', 'Name of the resulting Gerber object.')
]),
- 'examples': ["open_gerber gerber_object_path -outname bla"]
+ 'examples': ["open_gerber gerber_object_path -outname bla",
+ 'open_gerber "D:\\my_gerber_file with spaces in the name.GRB"']
}
def execute(self, args, unnamed_args):
@@ -65,7 +67,10 @@ class TclCommandOpenGerber(TclCommandSignaled):
return
filename = args['filename']
- # filename = filename.replace(' ', '')
+
+ if ' ' in filename:
+ return "The absolute path to the project file contain spaces which is not allowed.\n" \
+ "Please enclose the path within quotes."
if 'outname' in args:
outname = args['outname']
diff --git a/tclCommands/TclCommandOpenProject.py b/tclCommands/TclCommandOpenProject.py
index ef0775af..3dddad61 100644
--- a/tclCommands/TclCommandOpenProject.py
+++ b/tclCommands/TclCommandOpenProject.py
@@ -30,9 +30,11 @@ class TclCommandOpenProject(TclCommandSignaled):
help = {
'main': "Opens a FlatCAM project.",
'args': collections.OrderedDict([
- ('filename', 'Path to file to open.'),
+ ('filename', 'Absolute path to file to open. Required.\n'
+ 'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
]),
- 'examples': []
+ 'examples': ['open_project D:\\my_project_file.FlatPrj',
+ 'open_project "D:\\my_project_file with spaces in the name.FlatPrj"']
}
def execute(self, args, unnamed_args):
@@ -45,6 +47,8 @@ class TclCommandOpenProject(TclCommandSignaled):
:return: None or exception
"""
filename = args['filename']
- filename = filename.replace(' ', '')
+ if ' ' in filename:
+ return "The absolute path to the project file contain spaces which is not allowed.\n" \
+ "Please enclose the path within quotes."
self.app.open_project(filename, cli=True, plot=False)
diff --git a/tclCommands/TclCommandOptions.py b/tclCommands/TclCommandOptions.py
index 4bc90b84..ab22599e 100644
--- a/tclCommands/TclCommandOptions.py
+++ b/tclCommands/TclCommandOptions.py
@@ -28,11 +28,11 @@ class TclCommandOptions(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Shows the settings for an object.",
+ 'main': "Will return the options (settings) for an object as a string with values separated by \\n.",
'args': collections.OrderedDict([
- ('name', 'Object name.'),
+ ('name', 'Object name for which to return the options. Required.'),
]),
- 'examples': []
+ 'examples': ['options obj_name']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandPanelize.py b/tclCommands/TclCommandPanelize.py
index b40cc434..71d50199 100644
--- a/tclCommands/TclCommandPanelize.py
+++ b/tclCommands/TclCommandPanelize.py
@@ -38,7 +38,7 @@ class TclCommandPanelize(TclCommand):
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
- required = ['name', 'rows', 'columns']
+ required = ['name']
# structured help for current command, args needs to be ordered
help = {
@@ -54,7 +54,14 @@ class TclCommandPanelize(TclCommand):
('outname', 'Name of the new geometry object.'),
('run_threaded', 'False = non-threaded || True = threaded')
]),
- 'examples': []
+ 'examples': [
+ 'panelize obj_name',
+
+ 'panel obj_name -rows 2 -columns 2 -spacing_columns 0.4 -spacing_rows 1.3 -box box_obj_name '
+ '-outname panelized_name',
+
+ 'panel obj_name -columns 2 -box box_obj_name -outname panelized_name',
+ ]
}
def execute(self, args, unnamed_args):
@@ -85,8 +92,18 @@ class TclCommandPanelize(TclCommand):
else:
box = obj
- if 'columns' not in args or 'rows' not in args:
- return "ERROR: Specify -columns and -rows"
+ if 'columns' in args:
+ columns = int(args['columns'])
+ else:
+ columns = int(0)
+
+ if 'rows' in args:
+ rows = int(args['rows'])
+ else:
+ rows = int(0)
+
+ if 'columns' not in args and 'rows' not in args:
+ return "ERROR: Specify either -columns or -rows. The one not specified it will assumed to be 0"
if 'outname' in args:
outname = args['outname']
@@ -108,9 +125,6 @@ class TclCommandPanelize(TclCommand):
else:
spacing_rows = 5
- rows = int(args['rows'])
- columns = int(args['columns'])
-
xmin, ymin, xmax, ymax = box.bounds()
lenghtx = xmax - xmin + spacing_columns
lenghty = ymax - ymin + spacing_rows
diff --git a/tclCommands/TclCommandPlotAll.py b/tclCommands/TclCommandPlotAll.py
index 2e8ead22..d3833dd0 100644
--- a/tclCommands/TclCommandPlotAll.py
+++ b/tclCommands/TclCommandPlotAll.py
@@ -33,7 +33,7 @@ class TclCommandPlotAll(TclCommand):
'args': collections.OrderedDict([
]),
- 'examples': []
+ 'examples': ['plot_all']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandPlotObjects.py b/tclCommands/TclCommandPlotObjects.py
index bc3978a3..1df57886 100644
--- a/tclCommands/TclCommandPlotObjects.py
+++ b/tclCommands/TclCommandPlotObjects.py
@@ -32,15 +32,15 @@ class TclCommandPlotObjects(TclCommand):
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
- required = []
+ required = ['names']
# structured help for current command, args needs to be ordered
help = {
'main': "Plot a list of objects.",
'args': collections.OrderedDict([
- ('names', "UA list of object names to be plotted.")
+ ('names', "A list of object names to be plotted separated by comma. Required.")
]),
- 'examples': ["plot_objects"]
+ 'examples': ["plot_objects gerber_obj.GRB, excellon_obj.DRL"]
}
def execute(self, args, unnamed_args):
@@ -51,7 +51,7 @@ class TclCommandPlotObjects(TclCommand):
:return:
"""
if self.app.cmd_line_headless != 1:
- names = [x.strip() for x in args['names'].split(",")]
+ names = [x.strip() for x in args['names'].split(",") if x != '']
objs = []
for name in names:
objs.append(self.app.collection.get_by_name(name))
diff --git a/tclCommands/TclCommandSaveProject.py b/tclCommands/TclCommandSaveProject.py
index 9eaa1bbe..899247a2 100644
--- a/tclCommands/TclCommandSaveProject.py
+++ b/tclCommands/TclCommandSaveProject.py
@@ -30,9 +30,12 @@ class TclCommandSaveProject(TclCommandSignaled):
help = {
'main': "Saves the FlatCAM project to file.",
'args': collections.OrderedDict([
- ('filename', 'Path to file.'),
+ ('filename', 'Absolute path to file to open. Required.\n'
+ 'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
]),
- 'examples': []
+ 'examples': ['save_project D:\\my_project_file.FlatPrj',
+ 'save_project "D:\\my_project_file with spaces in the name.FlatPrj"',
+ 'save_project path_to_where_the_file_is_stored']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandSaveSys.py b/tclCommands/TclCommandSaveSys.py
index 9b18ba80..5712515b 100644
--- a/tclCommands/TclCommandSaveSys.py
+++ b/tclCommands/TclCommandSaveSys.py
@@ -33,9 +33,9 @@ class TclCommandSaveSys(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Saves the FlatCAM system paramaters to defaults file.",
+ 'main': "Saves the FlatCAM system parameters to defaults file.",
'args': collections.OrderedDict([]),
- 'examples': []
+ 'examples': ['save_sys']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandScale.py b/tclCommands/TclCommandScale.py
index 8f68ee92..aa5ebc3e 100644
--- a/tclCommands/TclCommandScale.py
+++ b/tclCommands/TclCommandScale.py
@@ -45,18 +45,22 @@ class TclCommandScale(TclCommand):
help = {
'main': "Resizes the object by a factor on X axis and a factor on Y axis, having as scale origin the point ",
'args': collections.OrderedDict([
- ('name', 'Name of the object to resize.'),
- ('factor', 'Fraction by which to scale on both axis. '),
+ ('name', 'Name of the object (Gerber, Geometry or Excellon) to be resized. Required.'),
+ ('factor', 'Fraction by which to scale on both axis.'),
('x', 'Fraction by which to scale on X axis. If "factor" is used then this parameter is ignored'),
('y', 'Fraction by which to scale on Y axis. If "factor" is used then this parameter is ignored'),
- ('origin', 'Reference used for scale. It can be: "origin" which means point (0, 0) or "min_bounds" which '
- 'means the lower left point of the bounding box or it can be "center" which means the center '
- 'of the bounding box.')
+ ('origin', 'Reference used for scale.\n'
+ 'The reference point can be:\n'
+ '- "origin" which means point (0, 0)\n'
+ '- "min_bounds" which means the lower left point of the bounding box\n'
+ '- "center" which means the center point of the bounding box of the object.\n'
+ '- a tuple in format (x,y) with the X and Y coordinates separated by a comma. NO SPACES ALLOWED')
]),
'examples': ['scale my_geometry 4.2',
'scale my_geo -x 3.1 -y 2.8',
- 'scale my_geo 1.2 -origin min_bounds']
+ 'scale my_geo 1.2 -origin min_bounds',
+ 'scale my_geometry -x 2 -origin 3.0,2.1']
}
def execute(self, args, unnamed_args):
@@ -92,8 +96,17 @@ class TclCommandScale(TclCommand):
c_y = ymin + (ymax - ymin) / 2
point = (c_x, c_y)
else:
- self.raise_tcl_error('%s' % _("Expected -origin or -origin or -origin ."))
- return 'fail'
+ try:
+ point = eval(args['origin'])
+ if not isinstance(point, tuple):
+ raise Exception
+ except Exception as e:
+ self.raise_tcl_error('%s\n%s' % (_("Expected -origin or "
+ "-origin or "
+ "-origin or "
+ "- origin 3.0,4.2."), str(e))
+ )
+ return 'fail'
if 'factor' in args:
factor = float(args['factor'])
diff --git a/tclCommands/TclCommandSetActive.py b/tclCommands/TclCommandSetActive.py
index 2c51b72c..5144289a 100644
--- a/tclCommands/TclCommandSetActive.py
+++ b/tclCommands/TclCommandSetActive.py
@@ -31,9 +31,9 @@ class TclCommandSetActive(TclCommand):
help = {
'main': 'Sets an object as active.',
'args': collections.OrderedDict([
- ('name', 'Name of the Object.'),
+ ('name', 'Name of the FlatCAM object to be set as active (selected). Required.'),
]),
- 'examples': []
+ 'examples': ['set_active object_name']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandSetOrigin.py b/tclCommands/TclCommandSetOrigin.py
index 52974dd2..895338e4 100644
--- a/tclCommands/TclCommandSetOrigin.py
+++ b/tclCommands/TclCommandSetOrigin.py
@@ -49,13 +49,15 @@ class TclCommandSetOrigin(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Will set the origin at the specified x,y location.",
+ 'main': "Will set the origin at the specified x,y location.\n"
+ "If it is called without arguments it will set origin at (0, 0)",
'args': collections.OrderedDict([
- ('loc', 'Location to offset all the selected objects. No spaces between x and y pair. Use like this: 2,3'),
+ ('loc', 'Location to offset all the selected objects. NO SPACES ALLOWED in X and Y pair.\n'
+ 'Use like this: 2,3'),
('auto', 'If set to True it will set the origin to the minimum x, y of the object selection bounding box.'
'-auto=True is not correct but -auto 1 or -auto True is correct.')
]),
- 'examples': ['set_origin 3,2', 'set_origin -auto 1']
+ 'examples': ['set_origin 3,2', 'set_origin -auto 1', 'origin']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandSetSys.py b/tclCommands/TclCommandSetSys.py
index 9d477e27..a8133317 100644
--- a/tclCommands/TclCommandSetSys.py
+++ b/tclCommands/TclCommandSetSys.py
@@ -32,10 +32,10 @@ class TclCommandSetSys(TclCommand):
help = {
'main': "Sets the value of the system variable.",
'args': collections.OrderedDict([
- ('name', 'Name of the system variable.'),
+ ('name', 'Name of the system variable. Required.'),
('value', 'Value to set.')
]),
- 'examples': []
+ 'examples': ['set_sys global_gridx 1.0']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandSkew.py b/tclCommands/TclCommandSkew.py
index 60902b10..28da6e1c 100644
--- a/tclCommands/TclCommandSkew.py
+++ b/tclCommands/TclCommandSkew.py
@@ -17,28 +17,27 @@ class TclCommandSkew(TclCommand):
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
- ('angle_x', float),
- ('angle_y', float)
])
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
-
+ ('x', float),
+ ('y', float)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
- required = ['name', 'angle_x', 'angle_y']
+ required = ['name']
# structured help for current command, args needs to be ordered
help = {
'main': "Shear/Skew an object by angles along x and y dimensions. The reference point is the left corner of "
"the bounding box of the object.",
'args': collections.OrderedDict([
- ('name', 'Name of the object to skew.'),
- ('angle_x', 'Angle in degrees by which to skew on the X axis.'),
- ('angle_y', 'Angle in degrees by which to skew on the Y axis.')
+ ('name', 'Name of the object (Gerber, Geometry or Excellon) to be deformed (skewed). Required.'),
+ ('x', 'Angle in degrees by which to skew on the X axis. If it is not used it will be assumed to be 0.0'),
+ ('y', 'Angle in degrees by which to skew on the Y axis. If it is not used it will be assumed to be 0.0')
]),
- 'examples': ['skew my_geometry 10.2 3.5']
+ 'examples': ['skew my_geometry -x 10.2 -y 3.5', 'skew my_geo -x 3.0']
}
def execute(self, args, unnamed_args):
@@ -50,8 +49,20 @@ class TclCommandSkew(TclCommand):
"""
name = args['name']
- angle_x = float(args['angle_x'])
- angle_y = float(args['angle_y'])
+
+ if 'x' in args:
+ angle_x = float(args['x'])
+ else:
+ angle_x = 0.0
+
+ if 'y' in args:
+ angle_y = float(args['y'])
+ else:
+ angle_y = 0.0
+
+ if angle_x == 0.0 and angle_y == 0.0:
+ # nothing to be done
+ return
obj_to_skew = self.app.collection.get_by_name(name)
xmin, ymin, xmax, ymax = obj_to_skew.bounds()
diff --git a/tclCommands/TclCommandSubtractPoly.py b/tclCommands/TclCommandSubtractPoly.py
index f5b08fd1..98c43c66 100644
--- a/tclCommands/TclCommandSubtractPoly.py
+++ b/tclCommands/TclCommandSubtractPoly.py
@@ -28,12 +28,14 @@ class TclCommandSubtractPoly(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Subtract polygon from the given Geometry object.",
+ 'main': "Subtract polygon from the given Geometry object. The coordinates are provided in X Y pairs.\n"
+ "If the number of coordinates is not even then the 'Incomplete coordinate' error is raised.\n"
+ "If last coordinates are not the same as the first ones, the polygon will be completed automatically.",
'args': collections.OrderedDict([
- ('name', 'Name of the Geometry object from which to subtract.'),
+ ('name', 'Name of the Geometry object from which to subtract. Required.'),
('x0 y0 x1 y1 x2 y2 ...', 'Points defining the polygon.')
]),
- 'examples': []
+ 'examples': ['subtract_poly my_geo 0 0 2 1 3 3 4 4 0 0']
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandSubtractRectangle.py b/tclCommands/TclCommandSubtractRectangle.py
index 53f99bf6..2453c584 100644
--- a/tclCommands/TclCommandSubtractRectangle.py
+++ b/tclCommands/TclCommandSubtractRectangle.py
@@ -36,9 +36,10 @@ class TclCommandSubtractRectangle(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Subtract rectange from the given Geometry object.",
+ 'main': "Subtract a rectangle from the given Geometry object. The coordinates are provided in X Y pairs.\n"
+ "If the number of coordinates is not even then the 'Incomplete coordinates' error is raised.",
'args': collections.OrderedDict([
- ('name', 'Name of the Geometry object from which to subtract.'),
+ ('name', 'Name of the Geometry object from which to subtract. Required.'),
('x0 y0', 'Bottom left corner coordinates.'),
('x1 y1', 'Top right corner coordinates.')
]),
diff --git a/tclCommands/TclCommandWriteGCode.py b/tclCommands/TclCommandWriteGCode.py
index 7125706e..655f00cb 100644
--- a/tclCommands/TclCommandWriteGCode.py
+++ b/tclCommands/TclCommandWriteGCode.py
@@ -34,8 +34,8 @@ class TclCommandWriteGCode(TclCommandSignaled):
help = {
'main': "Saves G-code of a CNC Job object to file.",
'args': collections.OrderedDict([
- ('name', 'Source CNC Job object.'),
- ('filename', 'Output filename.'),
+ ('name', 'Source CNC Job object. Required.'),
+ ('filename', 'Output filename. Required.'),
('preamble', 'Text to append at the beginning.'),
('postamble', 'Text to append at the end.'),
('muted', 'It will not put errors in the Shell or status bar.')
From c13721184c977eb70a5319f90fe224e82e2c445c Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 9 Apr 2020 04:36:41 +0300
Subject: [PATCH 161/209] - if FlatCAM is not run with Python version >= 3.5 it
will exit.
---
FlatCAM.py | 13 +++++++++++++
README.md | 4 ++++
2 files changed, 17 insertions(+)
diff --git a/FlatCAM.py b/FlatCAM.py
index 33b2b7c7..cd961119 100644
--- a/FlatCAM.py
+++ b/FlatCAM.py
@@ -32,6 +32,19 @@ if __name__ == '__main__':
# NOTE: Never talk to the GUI from threads! This is why I commented the above.
freeze_support()
+ # Supported Python version is >= 3.5
+ if sys.version_info.major >= 3:
+ if sys.version_info.minor >= 5:
+ pass
+ else:
+ print("FlatCAM BETA uses PYTHON 3. The version minimum is 3.5\n"
+ "Your Python version is: %s" % str(sys.version_info))
+ os._exit(0)
+ else:
+ print("FlatCAM BETA uses PYTHON 3. The version minimum is 3.5\n"
+ "Your Python version is: %s" % str(sys.version_info))
+ os._exit(0)
+
debug_trace()
VisPyPatches.apply_patches()
diff --git a/README.md b/README.md
index 678a9953..b896f620 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+10.04.2020
+
+- if FlatCAM is not run with Python version >= 3.5 it will exit.
+
9.4.2020
- fixed the Tcl Command Delete to have an argument -f that will force deletion evading the popup (if the popup is enabled). The sme command without a name now will delete all objects
From d80de538e3a69f5e8ef1dbe105a1aa0b75ebee12 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 9 Apr 2020 05:16:48 +0300
Subject: [PATCH 162/209] - modified all CTRL+ with Ctrl+ and all ALT+ with
Alt+ and all SHIFT+ with Shift+. Fixed issue #387.
---
README.md | 59 ++--
flatcamEditors/FlatCAMGeoEditor.py | 2 +-
flatcamEditors/FlatCAMGrbEditor.py | 2 +-
flatcamGUI/FlatCAMGUI.py | 188 ++++++-------
flatcamTools/ToolAlignObjects.py | 2 +-
flatcamTools/ToolCalculators.py | 2 +-
flatcamTools/ToolCalibration.py | 2 +-
flatcamTools/ToolCopperThieving.py | 2 +-
flatcamTools/ToolCutOut.py | 2 +-
flatcamTools/ToolDblSided.py | 4 +-
flatcamTools/ToolDistance.py | 2 +-
flatcamTools/ToolDistanceMin.py | 2 +-
flatcamTools/ToolExtractDrills.py | 2 +-
flatcamTools/ToolFiducials.py | 2 +-
flatcamTools/ToolFilm.py | 2 +-
flatcamTools/ToolNCC.py | 2 +-
flatcamTools/ToolOptimal.py | 2 +-
flatcamTools/ToolPDF.py | 2 +-
flatcamTools/ToolPaint.py | 2 +-
flatcamTools/ToolPanelize.py | 2 +-
flatcamTools/ToolPunchGerber.py | 2 +-
flatcamTools/ToolQRCode.py | 2 +-
flatcamTools/ToolRulesCheck.py | 2 +-
flatcamTools/ToolSolderPaste.py | 2 +-
flatcamTools/ToolSub.py | 2 +-
flatcamTools/ToolTransform.py | 2 +-
locale/de/LC_MESSAGES/strings.po | 286 ++++++++++----------
locale/en/LC_MESSAGES/strings.po | 404 ++++++++++++++--------------
locale/es/LC_MESSAGES/strings.po | 114 ++++----
locale/fr/LC_MESSAGES/strings.po | 110 ++++----
locale/it/LC_MESSAGES/strings.po | 64 ++---
locale/pt_BR/LC_MESSAGES/strings.po | 300 ++++++++++-----------
locale/ro/LC_MESSAGES/strings.po | 338 +++++++++++------------
locale/ru/LC_MESSAGES/strings.po | 300 ++++++++++-----------
locale_template/strings.pot | 56 ++--
35 files changed, 1135 insertions(+), 1134 deletions(-)
diff --git a/README.md b/README.md
index b896f620..1aeb53f8 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
10.04.2020
- if FlatCAM is not run with Python version >= 3.5 it will exit.
+- modified all CTRL+ with Ctrl+ and all ALT+ with Alt+ and all SHIFT+ with Shift+. Fixed issue #387.
9.4.2020
@@ -306,8 +307,8 @@ CAD program, and create G-Code for Isolation routing.
15.01.2020
-- added key shortcuts and toolbar icons for the new tools: Align Object Tool (ALT+A) and Extract Drills (ALT+I)
-- added new functionality (key shortcut SHIFT+J) to locate the corners of the bounding box (and center) in a selected object
+- added key shortcuts and toolbar icons for the new tools: Align Object Tool (Alt+A) and Extract Drills (Alt+I)
+- added new functionality (key shortcut Shift+J) to locate the corners of the bounding box (and center) in a selected object
- modified the NCC Tool GUI to prepare for accepting a tool from a tool database
- started to modify the Paint Tool to be similar to NCC Tool and to accept a tool from a database
- work in Paint Tool GUI functionality
@@ -403,7 +404,7 @@ CAD program, and create G-Code for Isolation routing.
- the Apply button text in Preferences is now made red when changes were made and require to be applied
- the Gerber UI is built only once now so the process is lighter on CPU
- the Gerber apertures marking shapes storage is now built only once because the more are built the more sluggish is the interface
-- added a new function called by shortcut key combo CTRL+G when the current widget in Plot Area is an Code Editor. It will jump to the specified line in the text.
+- added a new function called by shortcut key combo Ctrl+G when the current widget in Plot Area is an Code Editor. It will jump to the specified line in the text.
- fixed a small bug where the app tried to hide a label that I've removed previously
- in Paint Tool Preferences is allowed to add a list of initial tools separated by comma
- in Geometry Paint Tool fixed the Overlap rate to work between 0 and 99.9999%
@@ -505,7 +506,7 @@ CAD program, and create G-Code for Isolation routing.
- added Preferences values for PDF margins when saving text in Code Editor as PDF
- when clicking Cancel in Preferences now the values are reverted to what they used to be before opening Preferences tab and start changing values
- starting to work to a general Print function; for now it will generate PDF files; currently it works only for one object not for a selection
-- added shortcut key CTRL+P for printing to PDF method
+- added shortcut key Ctrl+P for printing to PDF method
18.12.2019
@@ -681,7 +682,7 @@ CAD program, and create G-Code for Isolation routing.
3.12.2019
-- in Preferences added an Apply button which apply the modified preferences but does not save to a file, minimizing the file IO operations; CTRL+S key combo does the Apply now.
+- in Preferences added an Apply button which apply the modified preferences but does not save to a file, minimizing the file IO operations; Ctrl+S key combo does the Apply now.
- updated some of the default values to metric, values that were missed previously
- remade the Gerber Editor way to import an Gerber object into the editor in such a way to use the multiprocessing
- various small fixes
@@ -809,7 +810,7 @@ CAD program, and create G-Code for Isolation routing.
11.11.2019
-- in Tools Database added a contextual menu to add/copy/delete tool; CTRL+C, DEL keys work too; key T for adding a tool is now only partially working
+- in Tools Database added a contextual menu to add/copy/delete tool; Ctrl+C, DEL keys work too; key T for adding a tool is now only partially working
- in Tools Database made the status bar messages show when adding/copying/deleting tools in DB
- changed all Except statements that were single to except Exception as recommended in some PEP
- renamed the Copper Fill Tool to Copper Thieving Tool as this is a more appropriate name; started to add ability for more types of copper thieving besides solid
@@ -900,7 +901,7 @@ CAD program, and create G-Code for Isolation routing.
- QRCode Tool: added ability to save the generated QRCode as SVG file or PNG file
- QRCode Tool: added the feature to save the PNG file with transparent background
- QRCode Tool: added GUI category in Preferences window
-- QRCode Tool: shortcut key for this tool is now ALT+Q while PDF import Tool was relegated to CTRL+Q combo key shortcut
+- QRCode Tool: shortcut key for this tool is now Alt+Q while PDF import Tool was relegated to Ctrl+Q combo key shortcut
- added a new FlatCAM Tool: Copper Fill Tool. It will pour copper into a Gerber filling all empty space with copper, at a clearance distance of the Gerber features
- Copper Fill Tool: added possibility to select between a bounding box rectangular or convex hull when the reference is the geometry of the source Gerber object
- Copper Fill Tool: cleanup on not regular tool exit
@@ -998,7 +999,7 @@ CAD program, and create G-Code for Isolation routing.
- fixed a bug in the Merge functions
- fixed the Export PNG function when using the 2D legacy graphic engine
-- added a new capability to toggle the grid lines for both graphic engines: menu link in View and key shortcut combo ALT+G
+- added a new capability to toggle the grid lines for both graphic engines: menu link in View and key shortcut combo Alt+G
- changed the grid colors for 3D graphic engine when in Dark mode
- enhanced the Tool Film adding the Film adjustments and added the GUI in Preferences
- set the GUI layout in Preferences for a new category named Tools 2
@@ -1843,7 +1844,7 @@ CAD program, and create G-Code for Isolation routing.
- fixed a possible issue in Gerber Object class
- added a new tool in Gerber Editor: Mark Area Tool. It will mark the polygons in a edited Gerber object with areas within a defined range, allowing to delete some of the not necessary copper features
- added new menu links in the Gerber Editor menu for Eraser Tool and Mark Area Tool
-- added key shortcuts for Eraser Tool (CTRL+E) and Mark Area Tool (ALT+A) and updated the shortcuts list
+- added key shortcuts for Eraser Tool (Ctrl+E) and Mark Area Tool (Alt+A) and updated the shortcuts list
9.07.2019
@@ -2223,7 +2224,7 @@ CAD program, and create G-Code for Isolation routing.
- fixed the PDF import tool to work with files generated by the Microsoft PDF printer (chained subpaths)
- in PDF import tool added support for paths filled and at the same time stroked ('B' and 'B*'commands)
-- added a shortcut key for PDF Import Tool (ALT+Q) and updated the Shortcut list (also with the 'T' and 'R' keys for Gerber Editor where they control the bend in Track and Region tool and the 'M' and 'D' keys for Add Arc tool in Geometry Editor)
+- added a shortcut key for PDF Import Tool (Alt+Q) and updated the Shortcut list (also with the 'T' and 'R' keys for Gerber Editor where they control the bend in Track and Region tool and the 'M' and 'D' keys for Add Arc tool in Geometry Editor)
20.04.2019
@@ -2268,7 +2269,7 @@ CAD program, and create G-Code for Isolation routing.
- Excellon Editor: update so always there is a tool selected even after the Excellon object was just edited; before it always required a click inside of the tool table, not you do it only if needed.
- fixed the menu File -> Edit -> Edit/Close Editor entry to reflect the status of the app (Editor active or not)
- added support in Excellon parser for autodetection of Excellon file format for the Excellon files generated by the following ECAD sw: DipTrace, Eagle, Altium, Sprint Layout
-- Gerber Editor: finished a new tool: Poligonize Tool (ALT+N in Editor). It will fuse a selection of tracks into a polygon. It will fill a selection of polygons if they are apart and it will make a single polygon if the selection is overlapped. All the newly created filled polygons will be stored in aperture '0' (if it does not exist it will be automatically created)
+- Gerber Editor: finished a new tool: Poligonize Tool (Alt+N in Editor). It will fuse a selection of tracks into a polygon. It will fill a selection of polygons if they are apart and it will make a single polygon if the selection is overlapped. All the newly created filled polygons will be stored in aperture '0' (if it does not exist it will be automatically created)
- fixed a bug in Move command in context menu who crashed the app when triggered
- Gerber Editor: when adding a new aperture it will be store as the last selected and it will be used for any tools that are triggered until a new aperture is selected.
@@ -2460,7 +2461,7 @@ CAD program, and create G-Code for Isolation routing.
- added ability to create new scripts and open scripts in FlatCAM Script Editor
- the Code Editor tab name is changed according to the task; 'save' and 'open' buttons will have filters installed for the QOpenDialog fit to the task
- added ability to run a FlatCAM Tcl script by double-clicking on the file
-- in Code Editor added shortcut combo key CTRL+SHIFT+V to function as a Special Paste that will replace the '\' char with '/' so the Windows paths will be pasted correctly for TCL Shell. Also doing SHIFT + LMB on the Paste in contextual menu is doing the same.
+- in Code Editor added shortcut combo key Ctrl+Shift+V to function as a Special Paste that will replace the '\' char with '/' so the Windows paths will be pasted correctly for TCL Shell. Also doing SHIFT + LMB on the Paste in contextual menu is doing the same.
17.03.2019
@@ -2692,7 +2693,7 @@ CAD program, and create G-Code for Isolation routing.
- added support for FlatCAM usage with High DPI monitors (4k). It is applied on the next app startup after change in Preferences -> General -> Gui Settings -> HDPI Support Checkbox
- made the app not remember the window size if the app is maximized and remember in QSettings if it was maximized. This way we can restore the maximized state but restore the windows size unmaximized
- added a button to clear the GUI preferences in Preferences -> General -> Gui Settings -> Clear GUI Settings
-- added key shortcuts for the shape transformations within Geometry Editor: X, Y keys for Flip(mirror), SHIFT+X, SHIFT+Y combo keys for Skew and ALT+X, ALT+Y combo keys for Offset
+- added key shortcuts for the shape transformations within Geometry Editor: X, Y keys for Flip(mirror), Shift+X, Shift+Y combo keys for Skew and Alt+X, Alt+Y combo keys for Offset
- adjusted the plotcanvas.zomm_fit() function so the objects are better fit into view (with a border around)
- modified the GUI in Objects Selected Tab to accommodate 2 different modes: basic and Advanced. In Basic mode, some of the functionality's are hidden from the user.
- added Tool Transform preferences in Edit -> Preferences and used them through out the app
@@ -2811,7 +2812,7 @@ CAD program, and create G-Code for Isolation routing.
- in Excellon Editor added a protection for Tool_dia field in case numbers using comma as decimal separator are used. Also added a QDoubleValidator forcing a number with max 4 decimals and from 0.0000 to 9.9999
- in Excellon Editor added a shortcut key 'T' that popup a window allowing to enter a new Tool with the set diameter
- in App added a shortcut key 'T' that popup a windows allowing to enter a new Tool with set diameter only when the Selected tab is on focus and only if a Geometry object is selected
-- changed the shortcut key for Transform Tool from 'T' to 'ALT+T'
+- changed the shortcut key for Transform Tool from 'T' to 'Alt+T'
- fixed bug in Geometry Selected tab that generated error when used tool offset was less than half of either total length or half of total width. Now the app signal the issue with a status bar message
- added Double Validator for the Offset value so only float numbers can be entered.
- in App added a shortcut key 'T' that popup a windows allowing to enter a new Tool with set diameter only when the Tool tab is on focus and only if a NCC Tool or Paint Area Tool object is installed in the Tool Tab
@@ -2918,7 +2919,7 @@ CAD program, and create G-Code for Isolation routing.
- updated the camlib.CNCJob.scale() function so now the GCode is scaled also (quite a HACK :( it will need to be replaced at some point)). Units change work now on the GCODE also.
- added the bounds coordinates to the GCODE header
- FlatCAM saves now to a file in self.data_path the toolbar positions and the position of TCL Shell
-- Plot Area Tab view can now be toggled, added entry in View Menu and shortcut key CTRL+F10
+- Plot Area Tab view can now be toggled, added entry in View Menu and shortcut key Ctrl+F10
- All the tabs in the GUI right side are (Plot Are, Preferences etc) are now detachable to a separate windows which when closed it returns in the previous location in the toolbar. Those detached tabs can be also reattached by drag and drop.
30.01.2019
@@ -2965,7 +2966,7 @@ CAD program, and create G-Code for Isolation routing.
- redesigned the messagebox that is showed when quiting ot creating a New Project: now it has an option ('Cancel') to abort the process returning to the app
- added options for trace segmentation that can be useful for auto-levelling (code snippet from Lei Zheng from a rejected pull request on FlatCAM https://bitbucket.org/realthunder/ )
- added shortcut key 'L' for creating 'New Excellon'
-- added shortcut key combo 'SHIFT+S' for Running a Script.
+- added shortcut key combo 'Shift+S' for Running a Script.
- modified GRBL_laser preprocessor file so it includes a Sxxxx command on the line with M03 (laser active) whenever a value is enter in the Spindlespeed entry field
- remade the EDIT -> PREFERENCES window, the Excellon and Gerber sections. Created a new section named TOOLS
@@ -3830,7 +3831,7 @@ also the Project tab). Replaced it with the Preferences Tab launched with
Menu -> Edit -> Preferences
- when FlatCAM is used under MacOS, multiple selection of shapes in Editor
mode is done using SHIFT key instead of CTRL key due of MacOS interpreting
-CTRL+LMB_click as a RMB click
+Ctrl+LMB_click as a RMB click
- when in Editor, clicking not on a shape, reset the index of selected shapes
to zero
- added a new Tab in the Plot Area named Gcode Editor. It allow the user to
@@ -3889,7 +3890,7 @@ because the value has to be positive. This may have solved for some use
cases the user complaints that on clearing the areas of copper there is
still copper leftovers.
-- added shortcut "SHIFT+G" to toggle the axis presence. Useful when one
+- added shortcut "Shift+G" to toggle the axis presence. Useful when one
wants to save a PNG file.
- changed color of the grid from 'gray' to 'dimgray'
@@ -3918,7 +3919,7 @@ in a intermediary state on canvas.
- added selection shape drawing in Geometry Editor preserving the
current behavior: click to select, click on canvas clear selection,
-CTRL+click add to selection new shape but remove from selection
+Ctrl+click add to selection new shape but remove from selection
if already selected. Drag LMB from left to right select enclosed
shapes, drag LMB from right to left select touching shapes. Now the
selection is made based on
@@ -4019,7 +4020,7 @@ crash
- remade the bounds() function to work with nested lists of objects as
per advice from JP which made the operation less performance taxing.
- added shortcut Shift+R that is complement to 'R'
-- shorcuts 'R' and 'SHIFT+R' are working now in steps of 90 degrees
+- shorcuts 'R' and 'Shift+R' are working now in steps of 90 degrees
instead of previous 45 degrees.
- added filters in the open ... FlatCAM projects are saved automatically
as *.flat, the Gerber files have few categories. So the Excellons and
@@ -4184,13 +4185,13 @@ Y Flip on Y_axis
~ Show Shortcut List
Space: En(Dis)able Obj Plot
-CTRL+A Select All
-CTRL+C Copy Obj
-CTRL+E Open Excellon File
-CTRL+G Open Gerber File
-CTRL+M Measurement Tool
-CTRL+O Open Project
-CTRL+S Save Project As
+Ctrl+A Select All
+Ctrl+C Copy Obj
+Ctrl+E Open Excellon File
+Ctrl+G Open Gerber File
+Ctrl+M Measurement Tool
+Ctrl+O Open Project
+Ctrl+S Save Project As
Delete Delete Obj'''
@@ -4255,8 +4256,8 @@ promises and raise an Tcl error if there are any.
Actually I reversed them to reflect reality.
- for the rotate command a positive angle now rotates CW. It was reversed.
- added shortcuts (for outside CANVAS; the CANVAS has it's own set of shortcuts)
-CTRL+C will copy to clipboard the name of the selected object
-CTRL+A will Select All objects
+Ctrl+C will copy to clipboard the name of the selected object
+Ctrl+A will Select All objects
"X" key will flip the selected objects on X axis
diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py
index 9d6be36b..74dd0892 100644
--- a/flatcamEditors/FlatCAMGeoEditor.py
+++ b/flatcamEditors/FlatCAMGeoEditor.py
@@ -992,7 +992,7 @@ class TransformEditorTool(FlatCAMTool):
self.app.ui.notebook.setTabText(2, _("Transform Tool"))
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+T', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+T', **kwargs)
def set_tool_ui(self):
# Initialize form
diff --git a/flatcamEditors/FlatCAMGrbEditor.py b/flatcamEditors/FlatCAMGrbEditor.py
index b655656b..f72f7c39 100644
--- a/flatcamEditors/FlatCAMGrbEditor.py
+++ b/flatcamEditors/FlatCAMGrbEditor.py
@@ -5538,7 +5538,7 @@ class TransformEditorTool(FlatCAMTool):
self.app.ui.notebook.setTabText(2, _("Transform Tool"))
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+T', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+T', **kwargs)
def set_tool_ui(self):
# Initialize form
diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py
index 27c80913..09bdb939 100644
--- a/flatcamGUI/FlatCAMGUI.py
+++ b/flatcamGUI/FlatCAMGUI.py
@@ -68,7 +68,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# New Project
self.menufilenewproject = QtWidgets.QAction(QtGui.QIcon(self.app.resource_location + '/file16.png'),
- _('&New Project ...\tCTRL+N'), self)
+ _('&New Project ...\tCtrl+N'), self)
self.menufilenewproject.setToolTip(
_("Will create a new, blank project")
)
@@ -113,12 +113,12 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# Open Gerber ...
self.menufileopengerber = QtWidgets.QAction(QtGui.QIcon(self.app.resource_location + '/flatcam_icon24.png'),
- _('Open &Gerber ...\tCTRL+G'), self)
+ _('Open &Gerber ...\tCtrl+G'), self)
self.menufile_open.addAction(self.menufileopengerber)
# Open Excellon ...
self.menufileopenexcellon = QtWidgets.QAction(QtGui.QIcon(self.app.resource_location + '/open_excellon32.png'),
- _('Open &Excellon ...\tCTRL+E'), self)
+ _('Open &Excellon ...\tCtrl+E'), self)
self.menufile_open.addAction(self.menufileopenexcellon)
# Open G-Code ...
@@ -152,7 +152,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.menufileopenscript = QtWidgets.QAction(
QtGui.QIcon(self.app.resource_location + '/open_script32.png'), _('Open Script ...'), self)
self.menufilerunscript = QtWidgets.QAction(
- QtGui.QIcon(self.app.resource_location + '/script16.png'), '%s\tSHIFT+S' % _('Run Script ...'), self)
+ QtGui.QIcon(self.app.resource_location + '/script16.png'), '%s\tShift+S' % _('Run Script ...'), self)
self.menufilerunscript.setToolTip(
_("Will run the opened Tcl Script thus\n"
"enabling the automation of certain\n"
@@ -262,7 +262,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# Separator
self.menufile.addSeparator()
self.menufile_print = QtWidgets.QAction(
- QtGui.QIcon(self.app.resource_location + '/printer32.png'), '%s\tCTRL+P' % _('Print (PDF)'))
+ QtGui.QIcon(self.app.resource_location + '/printer32.png'), '%s\tCtrl+P' % _('Print (PDF)'))
self.menufile.addAction(self.menufile_print)
self.menufile_save = self.menufile.addMenu(QtGui.QIcon(self.app.resource_location + '/save_as.png'), _('Save'))
@@ -274,7 +274,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# Save Project As ...
self.menufilesaveprojectas = QtWidgets.QAction(
- QtGui.QIcon(self.app.resource_location + '/save_as.png'), _('Save Project &As ...\tCTRL+S'), self)
+ QtGui.QIcon(self.app.resource_location + '/save_as.png'), _('Save Project &As ...\tCtrl+S'), self)
self.menufile_save.addAction(self.menufilesaveprojectas)
# Save Project Copy ...
@@ -303,7 +303,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.menueditedit = self.menuedit.addAction(
QtGui.QIcon(self.app.resource_location + '/edit16.png'), _('Edit Object\tE'))
self.menueditok = self.menuedit.addAction(
- QtGui.QIcon(self.app.resource_location + '/edit_ok16.png'), _('Close Editor\tCTRL+S'))
+ QtGui.QIcon(self.app.resource_location + '/edit_ok16.png'), _('Close Editor\tCtrl+S'))
# adjust the initial state of the menu entries related to the editor
self.menueditedit.setDisabled(False)
@@ -359,7 +359,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# Separator
self.menuedit.addSeparator()
self.menueditcopyobject = self.menuedit.addAction(
- QtGui.QIcon(self.app.resource_location + '/copy.png'), _('&Copy\tCTRL+C'))
+ QtGui.QIcon(self.app.resource_location + '/copy.png'), _('&Copy\tCtrl+C'))
# Separator
self.menuedit.addSeparator()
@@ -371,24 +371,24 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.menueditorigin = self.menuedit.addAction(
QtGui.QIcon(self.app.resource_location + '/origin16.png'), _('Se&t Origin\tO'))
self.menuedit_move2origin = self.menuedit.addAction(
- QtGui.QIcon(self.app.resource_location + '/origin2_16.png'), _('Move to Origin\tSHIFT+O'))
+ QtGui.QIcon(self.app.resource_location + '/origin2_16.png'), _('Move to Origin\tShift+O'))
self.menueditjump = self.menuedit.addAction(
QtGui.QIcon(self.app.resource_location + '/jump_to16.png'), _('Jump to Location\tJ'))
self.menueditlocate = self.menuedit.addAction(
- QtGui.QIcon(self.app.resource_location + '/locate16.png'), _('Locate in Object\tSHIFT+J'))
+ QtGui.QIcon(self.app.resource_location + '/locate16.png'), _('Locate in Object\tShift+J'))
# Separator
self.menuedit.addSeparator()
self.menuedittoggleunits = self.menuedit.addAction(
QtGui.QIcon(self.app.resource_location + '/toggle_units16.png'), _('Toggle Units\tQ'))
self.menueditselectall = self.menuedit.addAction(
- QtGui.QIcon(self.app.resource_location + '/select_all.png'), _('&Select All\tCTRL+A'))
+ QtGui.QIcon(self.app.resource_location + '/select_all.png'), _('&Select All\tCtrl+A'))
# Separator
self.menuedit.addSeparator()
self.menueditpreferences = self.menuedit.addAction(
- QtGui.QIcon(self.app.resource_location + '/pref.png'), _('&Preferences\tSHIFT+P'))
+ QtGui.QIcon(self.app.resource_location + '/pref.png'), _('&Preferences\tShift+P'))
# ########################################################################
# ########################## OPTIONS # ###################################
@@ -396,14 +396,14 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.menuoptions = self.menu.addMenu(_('Options'))
self.menuoptions_transform_rotate = self.menuoptions.addAction(
- QtGui.QIcon(self.app.resource_location + '/rotate.png'), _("&Rotate Selection\tSHIFT+(R)"))
+ QtGui.QIcon(self.app.resource_location + '/rotate.png'), _("&Rotate Selection\tShift+(R)"))
# Separator
self.menuoptions.addSeparator()
self.menuoptions_transform_skewx = self.menuoptions.addAction(
- QtGui.QIcon(self.app.resource_location + '/skewX.png'), _("&Skew on X axis\tSHIFT+X"))
+ QtGui.QIcon(self.app.resource_location + '/skewX.png'), _("&Skew on X axis\tShift+X"))
self.menuoptions_transform_skewy = self.menuoptions.addAction(
- QtGui.QIcon(self.app.resource_location + '/skewY.png'), _("S&kew on Y axis\tSHIFT+Y"))
+ QtGui.QIcon(self.app.resource_location + '/skewY.png'), _("S&kew on Y axis\tShift+Y"))
# Separator
self.menuoptions.addSeparator()
@@ -415,9 +415,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.menuoptions.addSeparator()
self.menuoptions_view_source = self.menuoptions.addAction(
- QtGui.QIcon(self.app.resource_location + '/source32.png'), _("View source\tALT+S"))
+ QtGui.QIcon(self.app.resource_location + '/source32.png'), _("View source\tAlt+S"))
self.menuoptions_tools_db = self.menuoptions.addAction(
- QtGui.QIcon(self.app.resource_location + '/database32.png'), _("Tools DataBase\tCTRL+D"))
+ QtGui.QIcon(self.app.resource_location + '/database32.png'), _("Tools DataBase\tCtrl+D"))
# Separator
self.menuoptions.addSeparator()
@@ -426,11 +426,11 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# ########################################################################
self.menuview = self.menu.addMenu(_('View'))
self.menuviewenable = self.menuview.addAction(
- QtGui.QIcon(self.app.resource_location + '/replot16.png'), _('Enable all plots\tALT+1'))
+ QtGui.QIcon(self.app.resource_location + '/replot16.png'), _('Enable all plots\tAlt+1'))
self.menuviewdisableall = self.menuview.addAction(
- QtGui.QIcon(self.app.resource_location + '/clear_plot16.png'), _('Disable all plots\tALT+2'))
+ QtGui.QIcon(self.app.resource_location + '/clear_plot16.png'), _('Disable all plots\tAlt+2'))
self.menuviewdisableother = self.menuview.addAction(
- QtGui.QIcon(self.app.resource_location + '/clear_plot16.png'), _('Disable non-selected\tALT+3'))
+ QtGui.QIcon(self.app.resource_location + '/clear_plot16.png'), _('Disable non-selected\tAlt+3'))
# Separator
self.menuview.addSeparator()
self.menuview_zoom_fit = self.menuview.addAction(
@@ -447,12 +447,12 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.menuview.addSeparator()
self.menuview_toggle_code_editor = self.menuview.addAction(
- QtGui.QIcon(self.app.resource_location + '/code_editor32.png'), _('Toggle Code Editor\tSHIFT+E'))
+ QtGui.QIcon(self.app.resource_location + '/code_editor32.png'), _('Toggle Code Editor\tShift+E'))
self.menuview.addSeparator()
self.menuview_toggle_fscreen = self.menuview.addAction(
- QtGui.QIcon(self.app.resource_location + '/fscreen32.png'), _("&Toggle FullScreen\tALT+F10"))
+ QtGui.QIcon(self.app.resource_location + '/fscreen32.png'), _("&Toggle FullScreen\tAlt+F10"))
self.menuview_toggle_parea = self.menuview.addAction(
- QtGui.QIcon(self.app.resource_location + '/plot32.png'), _("&Toggle Plot Area\tCTRL+F10"))
+ QtGui.QIcon(self.app.resource_location + '/plot32.png'), _("&Toggle Plot Area\tCtrl+F10"))
self.menuview_toggle_notebook = self.menuview.addAction(
QtGui.QIcon(self.app.resource_location + '/notebook32.png'), _("&Toggle Project/Sel/Tool\t`"))
@@ -460,11 +460,11 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.menuview_toggle_grid = self.menuview.addAction(
QtGui.QIcon(self.app.resource_location + '/grid32.png'), _("&Toggle Grid Snap\tG"))
self.menuview_toggle_grid_lines = self.menuview.addAction(
- QtGui.QIcon(self.app.resource_location + '/grid32.png'), _("&Toggle Grid Lines\tALT+G"))
+ QtGui.QIcon(self.app.resource_location + '/grid32.png'), _("&Toggle Grid Lines\tAlt+G"))
self.menuview_toggle_axis = self.menuview.addAction(
- QtGui.QIcon(self.app.resource_location + '/axis32.png'), _("&Toggle Axis\tSHIFT+G"))
+ QtGui.QIcon(self.app.resource_location + '/axis32.png'), _("&Toggle Axis\tShift+G"))
self.menuview_toggle_workspace = self.menuview.addAction(
- QtGui.QIcon(self.app.resource_location + '/workspace24.png'), _("Toggle Workspace\tSHIFT+W"))
+ QtGui.QIcon(self.app.resource_location + '/workspace24.png'), _("Toggle Workspace\tShift+W"))
# ########################################################################
# ########################## Objects # ###################################
@@ -566,7 +566,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
QtGui.QIcon(self.app.resource_location + '/paint16.png'), _("Paint Tool\tI")
)
self.geo_transform_menuitem = self.geo_editor_menu.addAction(
- QtGui.QIcon(self.app.resource_location + '/transform.png'), _("Transform Tool\tALT+R")
+ QtGui.QIcon(self.app.resource_location + '/transform.png'), _("Transform Tool\tAlt+R")
)
self.geo_editor_menu.addSeparator()
self.geo_cornersnap_menuitem = self.geo_editor_menu.addAction(
@@ -621,7 +621,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.grb_editor_menu.addSeparator()
self.grb_convert_poly_menuitem = self.grb_editor_menu.addAction(
- QtGui.QIcon(self.app.resource_location + '/poligonize32.png'), _("Poligonize\tALT+N"))
+ QtGui.QIcon(self.app.resource_location + '/poligonize32.png'), _("Poligonize\tAlt+N"))
self.grb_add_semidisc_menuitem = self.grb_editor_menu.addAction(
QtGui.QIcon(self.app.resource_location + '/semidisc32.png'), _("Add SemiDisc\tE"))
self.grb_add_disc_menuitem = self.grb_editor_menu.addAction(
@@ -631,11 +631,11 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.grb_add_scale_menuitem = self.grb_editor_menu.addAction(
QtGui.QIcon(self.app.resource_location + '/scale32.png'), _('Scale\tS'))
self.grb_add_markarea_menuitem = self.grb_editor_menu.addAction(
- QtGui.QIcon(self.app.resource_location + '/markarea32.png'), _('Mark Area\tALT+A'))
+ QtGui.QIcon(self.app.resource_location + '/markarea32.png'), _('Mark Area\tAlt+A'))
self.grb_add_eraser_menuitem = self.grb_editor_menu.addAction(
- QtGui.QIcon(self.app.resource_location + '/eraser26.png'), _('Eraser\tCTRL+E'))
+ QtGui.QIcon(self.app.resource_location + '/eraser26.png'), _('Eraser\tCtrl+E'))
self.grb_transform_menuitem = self.grb_editor_menu.addAction(
- QtGui.QIcon(self.app.resource_location + '/transform.png'), _("Transform\tALT+R"))
+ QtGui.QIcon(self.app.resource_location + '/transform.png'), _("Transform\tAlt+R"))
self.grb_editor_menu.addSeparator()
self.grb_copy_menuitem = self.grb_editor_menu.addAction(
@@ -1449,51 +1449,51 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
- | CTRL+A |
+ Ctrl+A |
%s |
- | CTRL+C |
+ Ctrl+C |
%s |
- | CTRL+D |
+ Ctrl+D |
%s |
- | CTRL+E |
+ Ctrl+E |
%s |
- | CTRL+G |
+ Ctrl+G |
%s |
- | CTRL+M |
+ Ctrl+M |
%s |
- | CTRL+N |
+ Ctrl+N |
%s |
- | CTRL+O |
+ Ctrl+O |
%s |
- | CTRL+P |
+ Ctrl+P |
%s |
- | CTRL+Q |
+ Ctrl+Q |
%s |
- | CTRL+S |
+ Ctrl+S |
%s |
- | CTRL+F10 |
+ Ctrl+F10 |
%s |
@@ -1501,47 +1501,47 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
| |
- | SHIFT+C |
+ Shift+C |
%s |
- | SHIFT+E |
+ Shift+E |
%s |
- | SHIFT+G |
+ Shift+G |
%s |
- | SHIFT+J |
+ Shift+J |
%s |
- | SHIFT+M |
+ Shift+M |
%s |
- | SHIFT+P |
+ Shift+P |
%s |
- | SHIFT+R |
+ Shift+R |
%s |
- | SHIFT+S |
+ Shift+S |
%s |
- | SHIFT+W |
+ Shift+W |
%s |
- | SHIFT+X |
+ Shift+X |
%s |
- | SHIFT+Y |
+ Shift+Y |
%s |
@@ -1549,83 +1549,83 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
| |
- | ALT+A |
+ Alt+A |
%s |
- | ALT+C |
+ Alt+C |
%s |
- | ALT+D |
+ Alt+D |
%s |
- | ALT+E |
+ Alt+E |
%s |
- | ALT+H |
+ Alt+H |
%s |
- | ALT+I |
+ Alt+I |
%s |
- | ALT+J |
+ Alt+J |
%s |
- | ALT+K |
+ Alt+K |
%s |
- | ALT+L |
+ Alt+L |
%s |
- | ALT+N |
+ Alt+N |
%s |
- | ALT+O |
+ Alt+O |
%s |
- | ALT+P |
+ Alt+P |
%s |
- | ALT+Q |
+ Alt+Q |
%s |
- | ALT+R |
+ Alt+R |
%s |
- | ALT+S |
+ Alt+S |
%s |
- | ALT+U |
+ Alt+U |
%s |
- | ALT+1 |
+ Alt+1 |
%s |
- | ALT+2 |
+ Alt+2 |
%s |
- | ALT+3 |
+ Alt+3 |
%s |
- | ALT+F10 |
+ Alt+F10 |
%s |
@@ -1633,7 +1633,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
| |
- | CTRL+ALT+X |
+ Ctrl+Alt+X |
%s |
@@ -1813,15 +1813,15 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
| |
- | SHIFT+M |
+ Shift+M |
%s |
- | SHIFT+X |
+ Shift+X |
%s |
- | SHIFT+Y |
+ Shift+Y |
%s |
@@ -1829,15 +1829,15 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
| |
- | ALT+R |
+ Alt+R |
%s |
- | ALT+X |
+ Alt+X |
%s |
- | ALT+Y |
+ Alt+Y |
%s |
@@ -1845,15 +1845,15 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
| |
- | CTRL+M |
+ Ctrl+M |
%s |
- | CTRL+S |
+ Ctrl+S |
%s |
- | CTRL+X |
+ Ctrl+X |
%s |
@@ -1939,7 +1939,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
| |
- | SHIFT+M |
+ Shift+M |
%s |
@@ -1963,7 +1963,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
| %s |
- | CTRL+S |
+ Ctrl+S |
%s |
@@ -2055,7 +2055,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
- | SHIFT+M |
+ Shift+M |
%s |
@@ -2063,11 +2063,11 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
| |
- | CTRL+E |
+ Ctrl+E |
%s |
- | CTRL+S |
+ Ctrl+S |
%s |
@@ -2075,15 +2075,15 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
| |
- | ALT+A |
+ Alt+A |
%s |
- | ALT+N |
+ Alt+N |
%s |
- | ALT+R |
+ Alt+R |
%s |
@@ -4308,12 +4308,12 @@ class FlatCAMSystemTray(QtWidgets.QSystemTrayIcon):
# Open Gerber ...
menu_opengerber = QtWidgets.QAction(QtGui.QIcon(self.app.resource_location + '/flatcam_icon24.png'),
- _('Open &Gerber ...\tCTRL+G'), self)
+ _('Open &Gerber ...\tCtrl+G'), self)
self.menu_open.addAction(menu_opengerber)
# Open Excellon ...
menu_openexcellon = QtWidgets.QAction(QtGui.QIcon(self.app.resource_location + '/open_excellon32.png'),
- _('Open &Excellon ...\tCTRL+E'), self)
+ _('Open &Excellon ...\tCtrl+E'), self)
self.menu_open.addAction(menu_openexcellon)
# Open G-Code ...
diff --git a/flatcamTools/ToolAlignObjects.py b/flatcamTools/ToolAlignObjects.py
index 863f27c3..efb7e1b3 100644
--- a/flatcamTools/ToolAlignObjects.py
+++ b/flatcamTools/ToolAlignObjects.py
@@ -244,7 +244,7 @@ class AlignObjects(FlatCAMTool):
self.app.ui.notebook.setTabText(2, _("Align Tool"))
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+A', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+A', **kwargs)
def set_tool_ui(self):
self.reset_fields()
diff --git a/flatcamTools/ToolCalculators.py b/flatcamTools/ToolCalculators.py
index 086ab83e..5b57be84 100644
--- a/flatcamTools/ToolCalculators.py
+++ b/flatcamTools/ToolCalculators.py
@@ -299,7 +299,7 @@ class ToolCalculator(FlatCAMTool):
self.app.ui.notebook.setTabText(2, _("Calc. Tool"))
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+C', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+C', **kwargs)
def set_tool_ui(self):
self.units = self.app.defaults['units'].upper()
diff --git a/flatcamTools/ToolCalibration.py b/flatcamTools/ToolCalibration.py
index b2a879fe..e1e884aa 100644
--- a/flatcamTools/ToolCalibration.py
+++ b/flatcamTools/ToolCalibration.py
@@ -759,7 +759,7 @@ class ToolCalibration(FlatCAMTool):
self.app.ui.notebook.setTabText(2, _("Calibration Tool"))
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+E', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+E', **kwargs)
def set_tool_ui(self):
self.units = self.app.defaults['units'].upper()
diff --git a/flatcamTools/ToolCopperThieving.py b/flatcamTools/ToolCopperThieving.py
index 7000ca0e..9b1bc968 100644
--- a/flatcamTools/ToolCopperThieving.py
+++ b/flatcamTools/ToolCopperThieving.py
@@ -569,7 +569,7 @@ class ToolCopperThieving(FlatCAMTool):
self.app.ui.notebook.setTabText(2, _("Copper Thieving Tool"))
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+F', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+F', **kwargs)
def set_tool_ui(self):
self.units = self.app.defaults['units']
diff --git a/flatcamTools/ToolCutOut.py b/flatcamTools/ToolCutOut.py
index 17663890..da366c0b 100644
--- a/flatcamTools/ToolCutOut.py
+++ b/flatcamTools/ToolCutOut.py
@@ -447,7 +447,7 @@ class CutOut(FlatCAMTool):
self.app.ui.notebook.setTabText(2, _("Cutout Tool"))
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+X', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+X', **kwargs)
def set_tool_ui(self):
self.reset_fields()
diff --git a/flatcamTools/ToolDblSided.py b/flatcamTools/ToolDblSided.py
index 29261cc5..50ca4632 100644
--- a/flatcamTools/ToolDblSided.py
+++ b/flatcamTools/ToolDblSided.py
@@ -428,7 +428,7 @@ class DblSidedTool(FlatCAMTool):
"on one side of the alignment axis.\n\n"
"The coordinates set can be obtained:\n"
"- press SHIFT key and left mouse clicking on canvas. Then click Add.\n"
- "- press SHIFT key and left mouse clicking on canvas. Then CTRL+V in the field.\n"
+ "- press SHIFT key and left mouse clicking on canvas. Then Ctrl+V in the field.\n"
"- press SHIFT key and left mouse clicking on canvas. Then RMB click in the field and click Paste.\n"
"- by entering the coords manually in the format: (x1, y1), (x2, y2), ...")
)
@@ -512,7 +512,7 @@ class DblSidedTool(FlatCAMTool):
self.drill_values = ""
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+D', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+D', **kwargs)
def run(self, toggle=True):
self.app.report_usage("Tool2Sided()")
diff --git a/flatcamTools/ToolDistance.py b/flatcamTools/ToolDistance.py
index 59f6f9d4..43bae37c 100644
--- a/flatcamTools/ToolDistance.py
+++ b/flatcamTools/ToolDistance.py
@@ -207,7 +207,7 @@ class Distance(FlatCAMTool):
self.deactivate_measure_tool()
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='CTRL+M', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Ctrl+M', **kwargs)
def set_tool_ui(self):
# Remove anything else in the GUI
diff --git a/flatcamTools/ToolDistanceMin.py b/flatcamTools/ToolDistanceMin.py
index 485fca3b..1769f8aa 100644
--- a/flatcamTools/ToolDistanceMin.py
+++ b/flatcamTools/ToolDistanceMin.py
@@ -155,7 +155,7 @@ class DistanceMin(FlatCAMTool):
_("Select two objects and no more, to measure the distance between them ..."))
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='SHIFT+M', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Shift+M', **kwargs)
def set_tool_ui(self):
# Remove anything else in the GUI
diff --git a/flatcamTools/ToolExtractDrills.py b/flatcamTools/ToolExtractDrills.py
index aa4a7adc..e3354978 100644
--- a/flatcamTools/ToolExtractDrills.py
+++ b/flatcamTools/ToolExtractDrills.py
@@ -363,7 +363,7 @@ class ToolExtractDrills(FlatCAMTool):
)
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+I', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+I', **kwargs)
def run(self, toggle=True):
self.app.report_usage("Extract Drills()")
diff --git a/flatcamTools/ToolFiducials.py b/flatcamTools/ToolFiducials.py
index 4c9070e9..cfd3b71f 100644
--- a/flatcamTools/ToolFiducials.py
+++ b/flatcamTools/ToolFiducials.py
@@ -395,7 +395,7 @@ class ToolFiducials(FlatCAMTool):
self.app.ui.notebook.setTabText(2, _("Fiducials Tool"))
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+J', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+J', **kwargs)
def set_tool_ui(self):
self.units = self.app.defaults['units']
diff --git a/flatcamTools/ToolFilm.py b/flatcamTools/ToolFilm.py
index 252cb0fb..4baae1a6 100644
--- a/flatcamTools/ToolFilm.py
+++ b/flatcamTools/ToolFilm.py
@@ -586,7 +586,7 @@ class Film(FlatCAMTool):
self.app.ui.notebook.setTabText(2, _("Film Tool"))
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+L', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+L', **kwargs)
def set_tool_ui(self):
self.reset_fields()
diff --git a/flatcamTools/ToolNCC.py b/flatcamTools/ToolNCC.py
index e2e5adfd..8fcaedf2 100644
--- a/flatcamTools/ToolNCC.py
+++ b/flatcamTools/ToolNCC.py
@@ -934,7 +934,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.app.inform.emit('[WARNING_NOTCL] %s...' % _("Adding Tool cancelled"))
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+N', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+N', **kwargs)
def run(self, toggle=True):
self.app.report_usage("ToolNonCopperClear()")
diff --git a/flatcamTools/ToolOptimal.py b/flatcamTools/ToolOptimal.py
index 7dcbf121..f67d9941 100644
--- a/flatcamTools/ToolOptimal.py
+++ b/flatcamTools/ToolOptimal.py
@@ -278,7 +278,7 @@ class ToolOptimal(FlatCAMTool):
self.reset_button.clicked.connect(self.set_tool_ui)
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+O', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+O', **kwargs)
def run(self, toggle=True):
self.app.report_usage("ToolOptimal()")
diff --git a/flatcamTools/ToolPDF.py b/flatcamTools/ToolPDF.py
index e5db0001..9f91260f 100644
--- a/flatcamTools/ToolPDF.py
+++ b/flatcamTools/ToolPDF.py
@@ -135,7 +135,7 @@ class ToolPDF(FlatCAMTool):
self.on_open_pdf_click()
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='CTRL+Q', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Ctrl+Q', **kwargs)
def set_tool_ui(self):
pass
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 9cf45655..842b6c56 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -705,7 +705,7 @@ class ToolPaint(FlatCAMTool, Gerber):
}[self.reference_type_combo.get_value()]
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+P', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+P', **kwargs)
def run(self, toggle=True):
self.app.report_usage("ToolPaint()")
diff --git a/flatcamTools/ToolPanelize.py b/flatcamTools/ToolPanelize.py
index 2cab2448..bbe57c18 100644
--- a/flatcamTools/ToolPanelize.py
+++ b/flatcamTools/ToolPanelize.py
@@ -322,7 +322,7 @@ class Panelize(FlatCAMTool):
self.app.ui.notebook.setTabText(2, _("Panel. Tool"))
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+Z', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+Z', **kwargs)
def set_tool_ui(self):
self.reset_fields()
diff --git a/flatcamTools/ToolPunchGerber.py b/flatcamTools/ToolPunchGerber.py
index 8c094dbf..2f984f5f 100644
--- a/flatcamTools/ToolPunchGerber.py
+++ b/flatcamTools/ToolPunchGerber.py
@@ -425,7 +425,7 @@ class ToolPunchGerber(FlatCAMTool):
self.app.ui.notebook.setTabText(2, _("Punch Tool"))
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+H', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+H', **kwargs)
def set_tool_ui(self):
self.reset_fields()
diff --git a/flatcamTools/ToolQRCode.py b/flatcamTools/ToolQRCode.py
index b71d477e..438349d3 100644
--- a/flatcamTools/ToolQRCode.py
+++ b/flatcamTools/ToolQRCode.py
@@ -382,7 +382,7 @@ class QRCode(FlatCAMTool):
self.app.ui.notebook.setTabText(2, _("QRCode Tool"))
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+Q', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+Q', **kwargs)
def set_tool_ui(self):
self.units = self.app.defaults['units']
diff --git a/flatcamTools/ToolRulesCheck.py b/flatcamTools/ToolRulesCheck.py
index 9ee387fc..53f634c2 100644
--- a/flatcamTools/ToolRulesCheck.py
+++ b/flatcamTools/ToolRulesCheck.py
@@ -616,7 +616,7 @@ class RulesCheck(FlatCAMTool):
self.app.ui.notebook.setTabText(2, _("Rules Tool"))
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+R', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+R', **kwargs)
def set_tool_ui(self):
diff --git a/flatcamTools/ToolSolderPaste.py b/flatcamTools/ToolSolderPaste.py
index 2dfd5d97..d42b39d6 100644
--- a/flatcamTools/ToolSolderPaste.py
+++ b/flatcamTools/ToolSolderPaste.py
@@ -552,7 +552,7 @@ class SolderPaste(FlatCAMTool):
self.app.ui.notebook.setTabText(2, _("SolderPaste Tool"))
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+K', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+K', **kwargs)
def on_add_tool_by_key(self):
tool_add_popup = FCInputDialog(title='%s...' % _("New Tool"),
diff --git a/flatcamTools/ToolSub.py b/flatcamTools/ToolSub.py
index 1471bd70..adf44dd7 100644
--- a/flatcamTools/ToolSub.py
+++ b/flatcamTools/ToolSub.py
@@ -233,7 +233,7 @@ class ToolSub(FlatCAMTool):
self.reset_button.clicked.connect(self.set_tool_ui)
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+W', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+W', **kwargs)
def run(self, toggle=True):
self.app.report_usage("ToolSub()")
diff --git a/flatcamTools/ToolTransform.py b/flatcamTools/ToolTransform.py
index 72955eee..69a1189b 100644
--- a/flatcamTools/ToolTransform.py
+++ b/flatcamTools/ToolTransform.py
@@ -463,7 +463,7 @@ class ToolTransform(FlatCAMTool):
self.app.ui.notebook.setTabText(2, _("Transform Tool"))
def install(self, icon=None, separator=None, **kwargs):
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+T', **kwargs)
+ FlatCAMTool.install(self, icon, separator, shortcut='Alt+T', **kwargs)
def set_tool_ui(self):
self.rotate_button.set_value(_("Rotate"))
diff --git a/locale/de/LC_MESSAGES/strings.po b/locale/de/LC_MESSAGES/strings.po
index 48cf9797..7341ac7f 100644
--- a/locale/de/LC_MESSAGES/strings.po
+++ b/locale/de/LC_MESSAGES/strings.po
@@ -5318,7 +5318,7 @@ msgid "File"
msgstr "Datei"
#: flatcamGUI/FlatCAMGUI.py:69
-msgid "&New Project ...\tCTRL+N"
+msgid "&New Project ...\tCtrl+N"
msgstr "&Neues Projekt ...\\STRG+N"
#: flatcamGUI/FlatCAMGUI.py:71
@@ -5371,11 +5371,11 @@ msgid "Open &Project ..."
msgstr "&Projekt öffnen..."
#: flatcamGUI/FlatCAMGUI.py:109 flatcamGUI/FlatCAMGUI.py:4121
-msgid "Open &Gerber ...\tCTRL+G"
+msgid "Open &Gerber ...\tCtrl+G"
msgstr "&Gerber öffnen...\\STRG+G"
#: flatcamGUI/FlatCAMGUI.py:114 flatcamGUI/FlatCAMGUI.py:4126
-msgid "Open &Excellon ...\tCTRL+E"
+msgid "Open &Excellon ...\tCtrl+E"
msgstr "&Excellon öffnen...\\STRG+E"
#: flatcamGUI/FlatCAMGUI.py:118 flatcamGUI/FlatCAMGUI.py:4131
@@ -5527,7 +5527,7 @@ msgid "&Save Project ..."
msgstr "Projekt speichern ..."
#: flatcamGUI/FlatCAMGUI.py:256
-msgid "Save Project &As ...\tCTRL+S"
+msgid "Save Project &As ...\tCtrl+S"
msgstr "Projekt speichern als ...\\STRG+S"
#: flatcamGUI/FlatCAMGUI.py:261
@@ -5548,7 +5548,7 @@ msgid "Edit Object\tE"
msgstr "Objekt bearbeiten\tE"
#: flatcamGUI/FlatCAMGUI.py:285
-msgid "Close Editor\tCTRL+S"
+msgid "Close Editor\tCtrl+S"
msgstr "Schließen Sie Editor\tSTRG+S"
#: flatcamGUI/FlatCAMGUI.py:294
@@ -5626,7 +5626,7 @@ msgid "Convert Any to Gerber"
msgstr "Konvertieren Sie Any zu Gerber"
#: flatcamGUI/FlatCAMGUI.py:341
-msgid "&Copy\tCTRL+C"
+msgid "&Copy\tCtrl+C"
msgstr "Kopieren\tSTRG+C"
#: flatcamGUI/FlatCAMGUI.py:346
@@ -5646,28 +5646,28 @@ msgid "Toggle Units\tQ"
msgstr "Einheiten umschalten\tQ"
#: flatcamGUI/FlatCAMGUI.py:360
-msgid "&Select All\tCTRL+A"
+msgid "&Select All\tCtrl+A"
msgstr "Alles auswählen\tSTRG+A"
#: flatcamGUI/FlatCAMGUI.py:365
-msgid "&Preferences\tSHIFT+P"
-msgstr "Einstellungen\tSHIFT+P"
+msgid "&Preferences\tShift+P"
+msgstr "Einstellungen\tShift+P"
#: flatcamGUI/FlatCAMGUI.py:371 flatcamTools/ToolProperties.py:153
msgid "Options"
msgstr "Optionen"
#: flatcamGUI/FlatCAMGUI.py:373
-msgid "&Rotate Selection\tSHIFT+(R)"
-msgstr "Auswahl drehen\tSHIFT+(R)"
+msgid "&Rotate Selection\tShift+(R)"
+msgstr "Auswahl drehen\tShift+(R)"
#: flatcamGUI/FlatCAMGUI.py:378
-msgid "&Skew on X axis\tSHIFT+X"
-msgstr "Neigung auf der X-Achse\tSHIFT+X"
+msgid "&Skew on X axis\tShift+X"
+msgstr "Neigung auf der X-Achse\tShift+X"
#: flatcamGUI/FlatCAMGUI.py:380
-msgid "S&kew on Y axis\tSHIFT+Y"
-msgstr "Neigung auf der Y-Achse\tSHIFT+Y"
+msgid "S&kew on Y axis\tShift+Y"
+msgstr "Neigung auf der Y-Achse\tShift+Y"
#: flatcamGUI/FlatCAMGUI.py:385
msgid "Flip on &X axis\tX"
@@ -5678,11 +5678,11 @@ msgid "Flip on &Y axis\tY"
msgstr "Y-Achse kippen\tY"
#: flatcamGUI/FlatCAMGUI.py:392
-msgid "View source\tALT+S"
-msgstr "Quelltext anzeigen\tALT+S"
+msgid "View source\tAlt+S"
+msgstr "Quelltext anzeigen\tAlt+S"
#: flatcamGUI/FlatCAMGUI.py:394
-msgid "Tools DataBase\tCTRL+D"
+msgid "Tools DataBase\tCtrl+D"
msgstr "Werkzeugdatenbank\tSTRG+D"
#: flatcamGUI/FlatCAMGUI.py:401 flatcamGUI/FlatCAMGUI.py:2060
@@ -5690,16 +5690,16 @@ msgid "View"
msgstr "Aussicht"
#: flatcamGUI/FlatCAMGUI.py:403
-msgid "Enable all plots\tALT+1"
-msgstr "Alle Diagramme aktivieren\tALT+1"
+msgid "Enable all plots\tAlt+1"
+msgstr "Alle Diagramme aktivieren\tAlt+1"
#: flatcamGUI/FlatCAMGUI.py:405
-msgid "Disable all plots\tALT+2"
-msgstr "Alle Diagramme deaktivieren\tALT+2"
+msgid "Disable all plots\tAlt+2"
+msgstr "Alle Diagramme deaktivieren\tAlt+2"
#: flatcamGUI/FlatCAMGUI.py:407
-msgid "Disable non-selected\tALT+3"
-msgstr "Nicht ausgewählte Diagramme deaktivieren\tALT+3"
+msgid "Disable non-selected\tAlt+3"
+msgstr "Nicht ausgewählte Diagramme deaktivieren\tAlt+3"
#: flatcamGUI/FlatCAMGUI.py:411
msgid "&Zoom Fit\tV"
@@ -5718,15 +5718,15 @@ msgid "Redraw All\tF5"
msgstr "Alles neu zeichnen\tF5"
#: flatcamGUI/FlatCAMGUI.py:424
-msgid "Toggle Code Editor\tSHIFT+E"
-msgstr "Code-Editor umschalten\tSHIFT+E"
+msgid "Toggle Code Editor\tShift+E"
+msgstr "Code-Editor umschalten\tShift+E"
#: flatcamGUI/FlatCAMGUI.py:427
-msgid "&Toggle FullScreen\tALT+F10"
-msgstr "FullScreen umschalten\tALT+F10"
+msgid "&Toggle FullScreen\tAlt+F10"
+msgstr "FullScreen umschalten\tAlt+F10"
#: flatcamGUI/FlatCAMGUI.py:429
-msgid "&Toggle Plot Area\tCTRL+F10"
+msgid "&Toggle Plot Area\tCtrl+F10"
msgstr "Plotbereich umschalten\tSTRG+F10"
#: flatcamGUI/FlatCAMGUI.py:431
@@ -5738,16 +5738,16 @@ msgid "&Toggle Grid Snap\tG"
msgstr "Schaltet den Rasterfang ein\tG"
#: flatcamGUI/FlatCAMGUI.py:437
-msgid "&Toggle Grid Lines\tALT+G"
-msgstr "Gitterlinien umschalten\tALT+G"
+msgid "&Toggle Grid Lines\tAlt+G"
+msgstr "Gitterlinien umschalten\tAlt+G"
#: flatcamGUI/FlatCAMGUI.py:439
-msgid "&Toggle Axis\tSHIFT+G"
-msgstr "Achse umschalten\tSHIFT+G"
+msgid "&Toggle Axis\tShift+G"
+msgstr "Achse umschalten\tShift+G"
#: flatcamGUI/FlatCAMGUI.py:441
-msgid "Toggle Workspace\tSHIFT+W"
-msgstr "Arbeitsbereich umschalten\tSHIFT+W"
+msgid "Toggle Workspace\tShift+W"
+msgstr "Arbeitsbereich umschalten\tShift+W"
#: flatcamGUI/FlatCAMGUI.py:446
msgid "Objects"
@@ -5846,8 +5846,8 @@ msgid "Paint Tool\tI"
msgstr "Malenwerkzeug\tI"
#: flatcamGUI/FlatCAMGUI.py:543
-msgid "Transform Tool\tALT+R"
-msgstr "Transformationswerkzeug\tALT+R"
+msgid "Transform Tool\tAlt+R"
+msgstr "Transformationswerkzeug\tAlt+R"
#: flatcamGUI/FlatCAMGUI.py:547
msgid "Toggle Corner Snap\tK"
@@ -5910,8 +5910,8 @@ msgid "Add Region\tN"
msgstr "Region hinzufügen\tN"
#: flatcamGUI/FlatCAMGUI.py:598
-msgid "Poligonize\tALT+N"
-msgstr "Polygonisieren\tALT+N"
+msgid "Poligonize\tAlt+N"
+msgstr "Polygonisieren\tAlt+N"
#: flatcamGUI/FlatCAMGUI.py:600
msgid "Add SemiDisc\tE"
@@ -5930,15 +5930,15 @@ msgid "Scale\tS"
msgstr "Skalieren\tS"
#: flatcamGUI/FlatCAMGUI.py:608
-msgid "Mark Area\tALT+A"
-msgstr "Bereich markieren\tALT+A"
+msgid "Mark Area\tAlt+A"
+msgstr "Bereich markieren\tAlt+A"
#: flatcamGUI/FlatCAMGUI.py:610
-msgid "Eraser\tCTRL+E"
+msgid "Eraser\tCtrl+E"
msgstr "Radiergummi\tSTRG+E"
#: flatcamGUI/FlatCAMGUI.py:612
-msgid "Transform\tALT+R"
+msgid "Transform\tAlt+R"
msgstr "Transformationswerkzeug\tSTRG+R"
#: flatcamGUI/FlatCAMGUI.py:639
@@ -14096,7 +14096,7 @@ msgid ""
"\n"
"The coordinates set can be obtained:\n"
"- press SHIFT key and left mouse clicking on canvas. Then click Add.\n"
-"- press SHIFT key and left mouse clicking on canvas. Then CTRL+V in the "
+"- press SHIFT key and left mouse clicking on canvas. Then Ctrl+V in the "
"field.\n"
"- press SHIFT key and left mouse clicking on canvas. Then RMB click in the "
"field and click Paste.\n"
@@ -17831,8 +17831,8 @@ msgstr ""
#~ "> Verknüpfungsliste oder über eine eigene Tastenkombination: "
#~ "F3.
\n"
-#~ msgid "Run Script ...\tSHIFT+S"
-#~ msgstr "Skript ausführen ...\tSHIFT+S"
+#~ msgid "Run Script ...\tShift+S"
+#~ msgstr "Skript ausführen ...\tShift+S"
#~ msgid ""
#~ "FlatCAM
Version {version} {beta} ({date}) - "
@@ -18001,39 +18001,39 @@ msgstr ""
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | CTRL+A | \n"
+#~ " Ctrl+A | \n"
#~ " Select All | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+C | \n"
+#~ " Ctrl+C | \n"
#~ " Copy Obj | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+E | \n"
+#~ " Ctrl+E | \n"
#~ " Open Excellon File | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+G | \n"
+#~ " Ctrl+G | \n"
#~ " Open Gerber File | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+N | \n"
+#~ " Ctrl+N | \n"
#~ " New Project | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Measurement Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+O | \n"
+#~ " Ctrl+O | \n"
#~ " Open Project | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Project As | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+F10 | \n"
+#~ " Ctrl+F10 | \n"
#~ " Toggle Plot Area | \n"
#~ "
\n"
#~ " \n"
@@ -18041,39 +18041,39 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+C | \n"
+#~ " Shift+C | \n"
#~ " Copy Obj_Name | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+E | \n"
+#~ " Shift+E | \n"
#~ " Toggle Code Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+G | \n"
+#~ " Shift+G | \n"
#~ " Toggle the axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+P | \n"
+#~ " Shift+P | \n"
#~ " Open Preferences Window | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+R | \n"
+#~ " Shift+R | \n"
#~ " Rotate by 90 degree CCW | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+S | \n"
+#~ " Shift+S | \n"
#~ " Run a Script | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+W | \n"
+#~ " Shift+W | \n"
#~ " Toggle the workspace | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Skew on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Skew on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -18081,59 +18081,59 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+C | \n"
+#~ " Alt+C | \n"
#~ " Calculators Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+D | \n"
+#~ " Alt+D | \n"
#~ " 2-Sided PCB Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+K | \n"
+#~ " Alt+K | \n"
#~ " Solder Paste Dispensing Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+L | \n"
+#~ " Alt+L | \n"
#~ " Film PCB Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Non-Copper Clearing Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+P | \n"
+#~ " Alt+P | \n"
#~ " Paint Area Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Q | \n"
+#~ " Alt+Q | \n"
#~ " PDF Import Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Transformations Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+S | \n"
+#~ " Alt+S | \n"
#~ " View File Source | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+U | \n"
+#~ " Alt+U | \n"
#~ " Cutout PCB Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+1 | \n"
+#~ " Alt+1 | \n"
#~ " Enable all Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+2 | \n"
+#~ " Alt+2 | \n"
#~ " Disable all Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+3 | \n"
+#~ " Alt+3 | \n"
#~ " Disable Non-selected Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+F10 | \n"
+#~ " Alt+F10 | \n"
#~ " Toggle Full Screen | \n"
#~ "
\n"
#~ " \n"
@@ -18141,7 +18141,7 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+ALT+X"
+#~ " | Ctrl+Alt+X"
#~ "td>\n"
#~ " | Abort current task (gracefully) | \n"
#~ "
\n"
@@ -18339,40 +18339,40 @@ msgstr ""
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | SHIFT+C | \n"
+#~ " Shift+C | \n"
#~ " Objektnamen kopieren | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+E | \n"
+#~ " Shift+E | \n"
#~ " Code-Editor umschalten | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+G | \n"
+#~ " Shift+G | \n"
#~ " Toggle the axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+P | \n"
+#~ " Shift+P | \n"
#~ " Öffnen Sie das Einstellungsfenster"
#~ "td>\n"
#~ " |
\n"
#~ " \n"
-#~ " | SHIFT+R | \n"
+#~ " Shift+R | \n"
#~ " Um 90 Grad nach links drehen | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+S | \n"
+#~ " Shift+S | \n"
#~ " Führen Sie ein Skript aus | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+W | \n"
+#~ " Shift+W | \n"
#~ " Arbeitsbereich umschalten | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Neigung auf der X-Achse | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Neigung auf der Y-Achse | \n"
#~ "
\n"
#~ " \n"
@@ -18380,60 +18380,60 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+C | \n"
+#~ " Alt+C | \n"
#~ " Rechnerwerzeug | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+D | \n"
+#~ " Alt+D | \n"
#~ " 2-seitiges PCBwerkzeug | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+K | \n"
+#~ " Alt+K | \n"
#~ " Lötpastenwerkzeug | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+L | \n"
+#~ " Alt+L | \n"
#~ " Film PCB Werkzeug | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Nicht-Kupfer löschen Werkzeug | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+P | \n"
+#~ " Alt+P | \n"
#~ " Paint Werkzeug | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Q | \n"
+#~ " Alt+Q | \n"
#~ " PDF-Importwerkzeug | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Transformationen\" Werkzeug | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+S | \n"
+#~ " Alt+S | \n"
#~ " Dateiquelle anzeigen | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+U | \n"
+#~ " Alt+U | \n"
#~ " PCB-Werkzeug ausschneiden | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+1 | \n"
+#~ " Alt+1 | \n"
#~ " Alle Plots aktivieren | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+2 | \n"
+#~ " Alt+2 | \n"
#~ " Deaktivieren Sie alle Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+3 | \n"
+#~ " Alt+3 | \n"
#~ " Deaktivieren Sie nicht ausgewählte "
#~ "Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+F10 | \n"
+#~ " Alt+F10 | \n"
#~ " Vollbild umschalten | \n"
#~ "
\n"
#~ " \n"
@@ -18441,7 +18441,7 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | STRG+ALT+X"
+#~ " | STRG+Alt+X"
#~ "td>\n"
#~ " | Aktuelle Aufgabe abbrechen "
#~ "(ordnungsgemäß) | \n"
@@ -18579,11 +18579,11 @@ msgstr ""
#~ " | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Skew shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Skew shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -18591,15 +18591,15 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Editor Transformation Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+X | \n"
+#~ " Alt+X | \n"
#~ " Offset shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Y | \n"
+#~ " Alt+Y | \n"
#~ " Offset shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -18607,15 +18607,15 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Measurement Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+X | \n"
+#~ " Ctrl+X | \n"
#~ " Polygon Cut Tool | \n"
#~ "
\n"
#~ " \n"
@@ -18707,7 +18707,7 @@ msgstr ""
#~ " | Abort and return to Select | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
@@ -18795,11 +18795,11 @@ msgstr ""
#~ " Abort and return to Select | \n"
#~ " \n"
#~ " \n"
-#~ " | CTRL+E | \n"
+#~ " Ctrl+E | \n"
#~ " Eraser Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
@@ -18807,15 +18807,15 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+A | \n"
+#~ " Alt+A | \n"
#~ " Mark Area Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Poligonize Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Transformation Tool | \n"
#~ "
\n"
#~ " \n"
@@ -18914,11 +18914,11 @@ msgstr ""
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Neigung auf der X-Achse | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Neigung auf der Y-Achse | \n"
#~ "
\n"
#~ " \n"
@@ -18926,15 +18926,15 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Editor-Umwandlungstool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+X | \n"
+#~ " Alt+X | \n"
#~ " Versatzform auf der X-Achse | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Y | \n"
+#~ " Alt+Y | \n"
#~ " Versatzform auf der Y-Achse | \n"
#~ "
\n"
#~ " \n"
@@ -19151,15 +19151,15 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+A | \n"
+#~ " Alt+A | \n"
#~ " Bereichswerkzeug markieren | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Werkzeug \"Polygonisieren\" | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Transformations Werkzeug | \n"
#~ "
\n"
#~ " \n"
@@ -20271,11 +20271,11 @@ msgstr ""
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Skew shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Skew shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -20283,15 +20283,15 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Editor Transformation Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+X | \n"
+#~ " Alt+X | \n"
#~ " Offset shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Y | \n"
+#~ " Alt+Y | \n"
#~ " Offset shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -20299,15 +20299,15 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Measurement Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+X | \n"
+#~ " Ctrl+X | \n"
#~ " Polygon Cut Tool | \n"
#~ "
\n"
#~ " \n"
@@ -20389,7 +20389,7 @@ msgstr ""
#~ " | Abort and return to Select | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
@@ -20478,11 +20478,11 @@ msgstr ""
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Skew shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Skew shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -20490,15 +20490,15 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Editor Transformation Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+X | \n"
+#~ " Alt+X | \n"
#~ " Offset shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Y | \n"
+#~ " Alt+Y | \n"
#~ " Offset shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -20506,15 +20506,15 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Measurement Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+X | \n"
+#~ " Ctrl+X | \n"
#~ " Polygon Cut Tool | \n"
#~ "
\n"
#~ " \n"
@@ -20596,7 +20596,7 @@ msgstr ""
#~ " | Abort and return to Select | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
diff --git a/locale/en/LC_MESSAGES/strings.po b/locale/en/LC_MESSAGES/strings.po
index f4300b66..ee2bf8a9 100644
--- a/locale/en/LC_MESSAGES/strings.po
+++ b/locale/en/LC_MESSAGES/strings.po
@@ -5159,8 +5159,8 @@ msgid "File"
msgstr "File"
#: flatcamGUI/FlatCAMGUI.py:69
-msgid "&New Project ...\tCTRL+N"
-msgstr "&New Project ...\tCTRL+N"
+msgid "&New Project ...\tCtrl+N"
+msgstr "&New Project ...\tCtrl+N"
#: flatcamGUI/FlatCAMGUI.py:71
msgid "Will create a new, blank project"
@@ -5212,12 +5212,12 @@ msgid "Open &Project ..."
msgstr "Open &Project ..."
#: flatcamGUI/FlatCAMGUI.py:109 flatcamGUI/FlatCAMGUI.py:4121
-msgid "Open &Gerber ...\tCTRL+G"
-msgstr "Open &Gerber ...\tCTRL+G"
+msgid "Open &Gerber ...\tCtrl+G"
+msgstr "Open &Gerber ...\tCtrl+G"
#: flatcamGUI/FlatCAMGUI.py:114 flatcamGUI/FlatCAMGUI.py:4126
-msgid "Open &Excellon ...\tCTRL+E"
-msgstr "Open &Excellon ...\tCTRL+E"
+msgid "Open &Excellon ...\tCtrl+E"
+msgstr "Open &Excellon ...\tCtrl+E"
#: flatcamGUI/FlatCAMGUI.py:118 flatcamGUI/FlatCAMGUI.py:4131
msgid "Open G-&Code ..."
@@ -5368,8 +5368,8 @@ msgid "&Save Project ..."
msgstr "&Save Project ..."
#: flatcamGUI/FlatCAMGUI.py:256
-msgid "Save Project &As ...\tCTRL+S"
-msgstr "Save Project &As ...\tCTRL+S"
+msgid "Save Project &As ...\tCtrl+S"
+msgstr "Save Project &As ...\tCtrl+S"
#: flatcamGUI/FlatCAMGUI.py:261
msgid "Save Project C&opy ..."
@@ -5389,8 +5389,8 @@ msgid "Edit Object\tE"
msgstr "Edit Object\tE"
#: flatcamGUI/FlatCAMGUI.py:285
-msgid "Close Editor\tCTRL+S"
-msgstr "Close Editor\tCTRL+S"
+msgid "Close Editor\tCtrl+S"
+msgstr "Close Editor\tCtrl+S"
#: flatcamGUI/FlatCAMGUI.py:294
msgid "Conversion"
@@ -5464,8 +5464,8 @@ msgid "Convert Any to Gerber"
msgstr "Convert Any to Gerber"
#: flatcamGUI/FlatCAMGUI.py:341
-msgid "&Copy\tCTRL+C"
-msgstr "&Copy\tCTRL+C"
+msgid "&Copy\tCtrl+C"
+msgstr "&Copy\tCtrl+C"
#: flatcamGUI/FlatCAMGUI.py:346
msgid "&Delete\tDEL"
@@ -5484,28 +5484,28 @@ msgid "Toggle Units\tQ"
msgstr "Toggle Units\tQ"
#: flatcamGUI/FlatCAMGUI.py:360
-msgid "&Select All\tCTRL+A"
-msgstr "&Select All\tCTRL+A"
+msgid "&Select All\tCtrl+A"
+msgstr "&Select All\tCtrl+A"
#: flatcamGUI/FlatCAMGUI.py:365
-msgid "&Preferences\tSHIFT+P"
-msgstr "&Preferences\tSHIFT+P"
+msgid "&Preferences\tShift+P"
+msgstr "&Preferences\tShift+P"
#: flatcamGUI/FlatCAMGUI.py:371 flatcamTools/ToolProperties.py:153
msgid "Options"
msgstr "Options"
#: flatcamGUI/FlatCAMGUI.py:373
-msgid "&Rotate Selection\tSHIFT+(R)"
-msgstr "&Rotate Selection\tSHIFT+(R)"
+msgid "&Rotate Selection\tShift+(R)"
+msgstr "&Rotate Selection\tShift+(R)"
#: flatcamGUI/FlatCAMGUI.py:378
-msgid "&Skew on X axis\tSHIFT+X"
-msgstr "&Skew on X axis\tSHIFT+X"
+msgid "&Skew on X axis\tShift+X"
+msgstr "&Skew on X axis\tShift+X"
#: flatcamGUI/FlatCAMGUI.py:380
-msgid "S&kew on Y axis\tSHIFT+Y"
-msgstr "S&kew on Y axis\tSHIFT+Y"
+msgid "S&kew on Y axis\tShift+Y"
+msgstr "S&kew on Y axis\tShift+Y"
#: flatcamGUI/FlatCAMGUI.py:385
msgid "Flip on &X axis\tX"
@@ -5516,28 +5516,28 @@ msgid "Flip on &Y axis\tY"
msgstr "Flip on &Y axis\tY"
#: flatcamGUI/FlatCAMGUI.py:392
-msgid "View source\tALT+S"
-msgstr "View source\tALT+S"
+msgid "View source\tAlt+S"
+msgstr "View source\tAlt+S"
#: flatcamGUI/FlatCAMGUI.py:394
-msgid "Tools DataBase\tCTRL+D"
-msgstr "Tools DataBase\tCTRL+D"
+msgid "Tools DataBase\tCtrl+D"
+msgstr "Tools DataBase\tCtrl+D"
#: flatcamGUI/FlatCAMGUI.py:401 flatcamGUI/FlatCAMGUI.py:2060
msgid "View"
msgstr "View"
#: flatcamGUI/FlatCAMGUI.py:403
-msgid "Enable all plots\tALT+1"
-msgstr "Enable all plots\tALT+1"
+msgid "Enable all plots\tAlt+1"
+msgstr "Enable all plots\tAlt+1"
#: flatcamGUI/FlatCAMGUI.py:405
-msgid "Disable all plots\tALT+2"
-msgstr "Disable all plots\tALT+2"
+msgid "Disable all plots\tAlt+2"
+msgstr "Disable all plots\tAlt+2"
#: flatcamGUI/FlatCAMGUI.py:407
-msgid "Disable non-selected\tALT+3"
-msgstr "Disable non-selected\tALT+3"
+msgid "Disable non-selected\tAlt+3"
+msgstr "Disable non-selected\tAlt+3"
#: flatcamGUI/FlatCAMGUI.py:411
msgid "&Zoom Fit\tV"
@@ -5556,16 +5556,16 @@ msgid "Redraw All\tF5"
msgstr "Redraw All\tF5"
#: flatcamGUI/FlatCAMGUI.py:424
-msgid "Toggle Code Editor\tSHIFT+E"
-msgstr "Toggle Code Editor\tSHIFT+E"
+msgid "Toggle Code Editor\tShift+E"
+msgstr "Toggle Code Editor\tShift+E"
#: flatcamGUI/FlatCAMGUI.py:427
-msgid "&Toggle FullScreen\tALT+F10"
-msgstr "&Toggle FullScreen\tALT+F10"
+msgid "&Toggle FullScreen\tAlt+F10"
+msgstr "&Toggle FullScreen\tAlt+F10"
#: flatcamGUI/FlatCAMGUI.py:429
-msgid "&Toggle Plot Area\tCTRL+F10"
-msgstr "&Toggle Plot Area\tCTRL+F10"
+msgid "&Toggle Plot Area\tCtrl+F10"
+msgstr "&Toggle Plot Area\tCtrl+F10"
#: flatcamGUI/FlatCAMGUI.py:431
msgid "&Toggle Project/Sel/Tool\t`"
@@ -5576,16 +5576,16 @@ msgid "&Toggle Grid Snap\tG"
msgstr "&Toggle Grid Snap\tG"
#: flatcamGUI/FlatCAMGUI.py:437
-msgid "&Toggle Grid Lines\tALT+G"
-msgstr "&Toggle Grid Lines\tALT+G"
+msgid "&Toggle Grid Lines\tAlt+G"
+msgstr "&Toggle Grid Lines\tAlt+G"
#: flatcamGUI/FlatCAMGUI.py:439
-msgid "&Toggle Axis\tSHIFT+G"
-msgstr "&Toggle Axis\tSHIFT+G"
+msgid "&Toggle Axis\tShift+G"
+msgstr "&Toggle Axis\tShift+G"
#: flatcamGUI/FlatCAMGUI.py:441
-msgid "Toggle Workspace\tSHIFT+W"
-msgstr "Toggle Workspace\tSHIFT+W"
+msgid "Toggle Workspace\tShift+W"
+msgstr "Toggle Workspace\tShift+W"
#: flatcamGUI/FlatCAMGUI.py:446
msgid "Objects"
@@ -5684,8 +5684,8 @@ msgid "Paint Tool\tI"
msgstr "Paint Tool\tI"
#: flatcamGUI/FlatCAMGUI.py:543
-msgid "Transform Tool\tALT+R"
-msgstr "Transform Tool\tALT+R"
+msgid "Transform Tool\tAlt+R"
+msgstr "Transform Tool\tAlt+R"
#: flatcamGUI/FlatCAMGUI.py:547
msgid "Toggle Corner Snap\tK"
@@ -5748,8 +5748,8 @@ msgid "Add Region\tN"
msgstr "Add Region\tN"
#: flatcamGUI/FlatCAMGUI.py:598
-msgid "Poligonize\tALT+N"
-msgstr "Poligonize\tALT+N"
+msgid "Poligonize\tAlt+N"
+msgstr "Poligonize\tAlt+N"
#: flatcamGUI/FlatCAMGUI.py:600
msgid "Add SemiDisc\tE"
@@ -5768,16 +5768,16 @@ msgid "Scale\tS"
msgstr "Scale\tS"
#: flatcamGUI/FlatCAMGUI.py:608
-msgid "Mark Area\tALT+A"
-msgstr "Mark Area\tALT+A"
+msgid "Mark Area\tAlt+A"
+msgstr "Mark Area\tAlt+A"
#: flatcamGUI/FlatCAMGUI.py:610
-msgid "Eraser\tCTRL+E"
-msgstr "Eraser\tCTRL+E"
+msgid "Eraser\tCtrl+E"
+msgstr "Eraser\tCtrl+E"
#: flatcamGUI/FlatCAMGUI.py:612
-msgid "Transform\tALT+R"
-msgstr "Transform\tALT+R"
+msgid "Transform\tAlt+R"
+msgstr "Transform\tAlt+R"
#: flatcamGUI/FlatCAMGUI.py:639
msgid "Enable Plot"
@@ -13800,7 +13800,7 @@ msgid ""
"\n"
"The coordinates set can be obtained:\n"
"- press SHIFT key and left mouse clicking on canvas. Then click Add.\n"
-"- press SHIFT key and left mouse clicking on canvas. Then CTRL+V in the "
+"- press SHIFT key and left mouse clicking on canvas. Then Ctrl+V in the "
"field.\n"
"- press SHIFT key and left mouse clicking on canvas. Then RMB click in the "
"field and click Paste.\n"
@@ -13811,7 +13811,7 @@ msgstr ""
"\n"
"The coordinates set can be obtained:\n"
"- press SHIFT key and left mouse clicking on canvas. Then click Add.\n"
-"- press SHIFT key and left mouse clicking on canvas. Then CTRL+V in the "
+"- press SHIFT key and left mouse clicking on canvas. Then Ctrl+V in the "
"field.\n"
"- press SHIFT key and left mouse clicking on canvas. Then RMB click in the "
"field and click Paste.\n"
@@ -17529,8 +17529,8 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ "\n"
#~ " "
-#~ msgid "Run Script ...\tSHIFT+S"
-#~ msgstr "Run Script ...\tSHIFT+S"
+#~ msgid "Run Script ...\tShift+S"
+#~ msgstr "Run Script ...\tShift+S"
#~| msgid ""
#~| "FlatCAM
Version {version} {beta} ({date}) "
@@ -17714,39 +17714,39 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~| " | \n"
#~| " \n"
#~| " \n"
-#~| " | CTRL+A | \n"
+#~| " Ctrl+A | \n"
#~| " Select All | \n"
#~| "
\n"
#~| " \n"
-#~| " | CTRL+C | \n"
+#~| " Ctrl+C | \n"
#~| " Copy Obj | \n"
#~| "
\n"
#~| " \n"
-#~| " | CTRL+E | \n"
+#~| " Ctrl+E | \n"
#~| " Open Excellon File | \n"
#~| "
\n"
#~| " \n"
-#~| " | CTRL+G | \n"
+#~| " Ctrl+G | \n"
#~| " Open Gerber File | \n"
#~| "
\n"
#~| " \n"
-#~| " | CTRL+N | \n"
+#~| " Ctrl+N | \n"
#~| " New Project | \n"
#~| "
\n"
#~| " \n"
-#~| " | CTRL+M | \n"
+#~| " Ctrl+M | \n"
#~| " Measurement Tool | \n"
#~| "
\n"
#~| " \n"
-#~| " | CTRL+O | \n"
+#~| " Ctrl+O | \n"
#~| " Open Project | \n"
#~| "
\n"
#~| " \n"
-#~| " | CTRL+S | \n"
+#~| " Ctrl+S | \n"
#~| " Save Project As | \n"
#~| "
\n"
#~| " \n"
-#~| " | CTRL+F10"
+#~| " | Ctrl+F10"
#~| "td>\n"
#~| " | Toggle Plot Area | \n"
#~| "
\n"
@@ -17755,39 +17755,39 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~| " | \n"
#~| " \n"
#~| " \n"
-#~| " | SHIFT+C | \n"
+#~| " Shift+C | \n"
#~| " Copy Obj_Name | \n"
#~| "
\n"
#~| " \n"
-#~| " | SHIFT+E | \n"
+#~| " Shift+E | \n"
#~| " Toggle Code Editor | \n"
#~| "
\n"
#~| " \n"
-#~| " | SHIFT+G | \n"
+#~| " Shift+G | \n"
#~| " Toggle the axis | \n"
#~| "
\n"
#~| " \n"
-#~| " | SHIFT+P | \n"
+#~| " Shift+P | \n"
#~| " Open Preferences Window | \n"
#~| "
\n"
#~| " \n"
-#~| " | SHIFT+R | \n"
+#~| " Shift+R | \n"
#~| " Rotate by 90 degree CCW | \n"
#~| "
\n"
#~| " \n"
-#~| " | SHIFT+S | \n"
+#~| " Shift+S | \n"
#~| " Run a Script | \n"
#~| "
\n"
#~| " \n"
-#~| " | SHIFT+W | \n"
+#~| " Shift+W | \n"
#~| " Toggle the workspace | \n"
#~| "
\n"
#~| " \n"
-#~| " | SHIFT+X | \n"
+#~| " Shift+X | \n"
#~| " Skew on X axis | \n"
#~| "
\n"
#~| " \n"
-#~| " | SHIFT+Y | \n"
+#~| " Shift+Y | \n"
#~| " Skew on Y axis | \n"
#~| "
\n"
#~| " \n"
@@ -17795,59 +17795,59 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~| " | | \n"
#~| "
\n"
#~| " \n"
-#~| " | ALT+C | \n"
+#~| " Alt+C | \n"
#~| " Calculators Tool | \n"
#~| "
\n"
#~| " \n"
-#~| " | ALT+D | \n"
+#~| " Alt+D | \n"
#~| " 2-Sided PCB Tool | \n"
#~| "
\n"
#~| " \n"
-#~| " | ALT+K | \n"
+#~| " Alt+K | \n"
#~| " Solder Paste Dispensing Tool | \n"
#~| "
\n"
#~| " \n"
-#~| " | ALT+L | \n"
+#~| " Alt+L | \n"
#~| " Film PCB Tool | \n"
#~| "
\n"
#~| " \n"
-#~| " | ALT+N | \n"
+#~| " Alt+N | \n"
#~| " Non-Copper Clearing Tool | \n"
#~| "
\n"
#~| " \n"
-#~| " | ALT+P | \n"
+#~| " Alt+P | \n"
#~| " Paint Area Tool | \n"
#~| "
\n"
#~| " \n"
-#~| " | ALT+Q | \n"
+#~| " Alt+Q | \n"
#~| " PDF Import Tool | \n"
#~| "
\n"
#~| " \n"
-#~| " | ALT+R | \n"
+#~| " Alt+R | \n"
#~| " Transformations Tool | \n"
#~| "
\n"
#~| " \n"
-#~| " | ALT+S | \n"
+#~| " Alt+S | \n"
#~| " View File Source | \n"
#~| "
\n"
#~| " \n"
-#~| " | ALT+U | \n"
+#~| " Alt+U | \n"
#~| " Cutout PCB Tool | \n"
#~| "
\n"
#~| " \n"
-#~| " | ALT+1 | \n"
+#~| " Alt+1 | \n"
#~| " Enable all Plots | \n"
#~| "
\n"
#~| " \n"
-#~| " | ALT+2 | \n"
+#~| " Alt+2 | \n"
#~| " Disable all Plots | \n"
#~| "
\n"
#~| " \n"
-#~| " | ALT+3 | \n"
+#~| " Alt+3 | \n"
#~| " Disable Non-selected Plots | \n"
#~| "
\n"
#~| " \n"
-#~| " | ALT+F10 | \n"
+#~| " Alt+F10 | \n"
#~| " Toggle Full Screen | \n"
#~| "
\n"
#~| " \n"
@@ -17998,39 +17998,39 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+A | \n"
+#~ " Ctrl+A | \n"
#~ " Select All | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+C | \n"
+#~ " Ctrl+C | \n"
#~ " Copy Obj | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+E | \n"
+#~ " Ctrl+E | \n"
#~ " Open Excellon File | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+G | \n"
+#~ " Ctrl+G | \n"
#~ " Open Gerber File | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+N | \n"
+#~ " Ctrl+N | \n"
#~ " New Project | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Measurement Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+O | \n"
+#~ " Ctrl+O | \n"
#~ " Open Project | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Project As | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+F10 | \n"
+#~ " Ctrl+F10 | \n"
#~ " Toggle Plot Area | \n"
#~ "
\n"
#~ " \n"
@@ -18038,39 +18038,39 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+C | \n"
+#~ " Shift+C | \n"
#~ " Copy Obj_Name | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+E | \n"
+#~ " Shift+E | \n"
#~ " Toggle Code Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+G | \n"
+#~ " Shift+G | \n"
#~ " Toggle the axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+P | \n"
+#~ " Shift+P | \n"
#~ " Open Preferences Window | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+R | \n"
+#~ " Shift+R | \n"
#~ " Rotate by 90 degree CCW | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+S | \n"
+#~ " Shift+S | \n"
#~ " Run a Script | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+W | \n"
+#~ " Shift+W | \n"
#~ " Toggle the workspace | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Skew on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Skew on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -18078,59 +18078,59 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+C | \n"
+#~ " Alt+C | \n"
#~ " Calculators Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+D | \n"
+#~ " Alt+D | \n"
#~ " 2-Sided PCB Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+K | \n"
+#~ " Alt+K | \n"
#~ " Solder Paste Dispensing Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+L | \n"
+#~ " Alt+L | \n"
#~ " Film PCB Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Non-Copper Clearing Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+P | \n"
+#~ " Alt+P | \n"
#~ " Paint Area Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Q | \n"
+#~ " Alt+Q | \n"
#~ " PDF Import Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Transformations Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+S | \n"
+#~ " Alt+S | \n"
#~ " View File Source | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+U | \n"
+#~ " Alt+U | \n"
#~ " Cutout PCB Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+1 | \n"
+#~ " Alt+1 | \n"
#~ " Enable all Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+2 | \n"
+#~ " Alt+2 | \n"
#~ " Disable all Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+3 | \n"
+#~ " Alt+3 | \n"
#~ " Disable Non-selected Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+F10 | \n"
+#~ " Alt+F10 | \n"
#~ " Toggle Full Screen | \n"
#~ "
\n"
#~ " \n"
@@ -18138,7 +18138,7 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+ALT+X"
+#~ " | Ctrl+Alt+X"
#~ "td>\n"
#~ " | Abort current task (gracefully) | \n"
#~ "
\n"
@@ -18290,39 +18290,39 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | CTRL+A | \n"
+#~ " Ctrl+A | \n"
#~ " Select All | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+C | \n"
+#~ " Ctrl+C | \n"
#~ " Copy Obj | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+E | \n"
+#~ " Ctrl+E | \n"
#~ " Open Excellon File | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+G | \n"
+#~ " Ctrl+G | \n"
#~ " Open Gerber File | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+N | \n"
+#~ " Ctrl+N | \n"
#~ " New Project | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Measurement Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+O | \n"
+#~ " Ctrl+O | \n"
#~ " Open Project | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Project As | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+F10 | \n"
+#~ " Ctrl+F10 | \n"
#~ " Toggle Plot Area | \n"
#~ "
\n"
#~ " \n"
@@ -18330,39 +18330,39 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+C | \n"
+#~ " Shift+C | \n"
#~ " Copy Obj_Name | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+E | \n"
+#~ " Shift+E | \n"
#~ " Toggle Code Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+G | \n"
+#~ " Shift+G | \n"
#~ " Toggle the axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+P | \n"
+#~ " Shift+P | \n"
#~ " Open Preferences Window | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+R | \n"
+#~ " Shift+R | \n"
#~ " Rotate by 90 degree CCW | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+S | \n"
+#~ " Shift+S | \n"
#~ " Run a Script | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+W | \n"
+#~ " Shift+W | \n"
#~ " Toggle the workspace | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Skew on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Skew on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -18370,59 +18370,59 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+C | \n"
+#~ " Alt+C | \n"
#~ " Calculators Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+D | \n"
+#~ " Alt+D | \n"
#~ " 2-Sided PCB Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+K | \n"
+#~ " Alt+K | \n"
#~ " Solder Paste Dispensing Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+L | \n"
+#~ " Alt+L | \n"
#~ " Film PCB Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Non-Copper Clearing Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+P | \n"
+#~ " Alt+P | \n"
#~ " Paint Area Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Q | \n"
+#~ " Alt+Q | \n"
#~ " PDF Import Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Transformations Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+S | \n"
+#~ " Alt+S | \n"
#~ " View File Source | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+U | \n"
+#~ " Alt+U | \n"
#~ " Cutout PCB Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+1 | \n"
+#~ " Alt+1 | \n"
#~ " Enable all Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+2 | \n"
+#~ " Alt+2 | \n"
#~ " Disable all Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+3 | \n"
+#~ " Alt+3 | \n"
#~ " Disable Non-selected Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+F10 | \n"
+#~ " Alt+F10 | \n"
#~ " Toggle Full Screen | \n"
#~ "
\n"
#~ " \n"
@@ -18430,7 +18430,7 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+ALT+X"
+#~ " | Ctrl+Alt+X"
#~ "td>\n"
#~ " | Abort current task (gracefully) | \n"
#~ "
\n"
@@ -18565,11 +18565,11 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Skew shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Skew shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -18577,15 +18577,15 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Editor Transformation Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+X | \n"
+#~ " Alt+X | \n"
#~ " Offset shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Y | \n"
+#~ " Alt+Y | \n"
#~ " Offset shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -18593,15 +18593,15 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Measurement Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+X | \n"
+#~ " Ctrl+X | \n"
#~ " Polygon Cut Tool | \n"
#~ "
\n"
#~ " \n"
@@ -18693,7 +18693,7 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | Abort and return to Select | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
@@ -18781,11 +18781,11 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " Abort and return to Select | \n"
#~ " \n"
#~ " \n"
-#~ " | CTRL+E | \n"
+#~ " Ctrl+E | \n"
#~ " Eraser Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
@@ -18793,15 +18793,15 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+A | \n"
+#~ " Alt+A | \n"
#~ " Mark Area Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Poligonize Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Transformation Tool | \n"
#~ "
\n"
#~ " \n"
@@ -18900,11 +18900,11 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Skew shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Skew shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -18912,15 +18912,15 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Editor Transformation Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+X | \n"
+#~ " Alt+X | \n"
#~ " Offset shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Y | \n"
+#~ " Alt+Y | \n"
#~ " Offset shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -18928,15 +18928,15 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Measurement Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+X | \n"
+#~ " Ctrl+X | \n"
#~ " Polygon Cut Tool | \n"
#~ "
\n"
#~ " \n"
@@ -19028,7 +19028,7 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | Abort and return to Select | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
@@ -19116,11 +19116,11 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " Abort and return to Select | \n"
#~ " \n"
#~ " \n"
-#~ " | CTRL+E | \n"
+#~ " Ctrl+E | \n"
#~ " Eraser Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
@@ -19128,15 +19128,15 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+A | \n"
+#~ " Alt+A | \n"
#~ " Mark Area Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Poligonize Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Transformation Tool | \n"
#~ "
\n"
#~ " \n"
@@ -20035,11 +20035,11 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Skew shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Skew shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -20047,15 +20047,15 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Editor Transformation Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+X | \n"
+#~ " Alt+X | \n"
#~ " Offset shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Y | \n"
+#~ " Alt+Y | \n"
#~ " Offset shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -20063,15 +20063,15 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Measurement Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+X | \n"
+#~ " Ctrl+X | \n"
#~ " Polygon Cut Tool | \n"
#~ "
\n"
#~ " \n"
@@ -20153,7 +20153,7 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | Abort and return to Select | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
@@ -20242,11 +20242,11 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Skew shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Skew shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -20254,15 +20254,15 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Editor Transformation Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+X | \n"
+#~ " Alt+X | \n"
#~ " Offset shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Y | \n"
+#~ " Alt+Y | \n"
#~ " Offset shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -20270,15 +20270,15 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Measurement Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+X | \n"
+#~ " Ctrl+X | \n"
#~ " Polygon Cut Tool | \n"
#~ "
\n"
#~ " \n"
@@ -20360,7 +20360,7 @@ msgstr "No Geometry name in args. Provide a name and try again."
#~ " | Abort and return to Select | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
diff --git a/locale/es/LC_MESSAGES/strings.po b/locale/es/LC_MESSAGES/strings.po
index 40d3783a..64592b0a 100644
--- a/locale/es/LC_MESSAGES/strings.po
+++ b/locale/es/LC_MESSAGES/strings.po
@@ -5267,8 +5267,8 @@ msgid "File"
msgstr "Archivo"
#: flatcamGUI/FlatCAMGUI.py:69
-msgid "&New Project ...\tCTRL+N"
-msgstr "&Nuevo proyecto ...\tCTRL+N"
+msgid "&New Project ...\tCtrl+N"
+msgstr "&Nuevo proyecto ...\tCtrl+N"
#: flatcamGUI/FlatCAMGUI.py:71
msgid "Will create a new, blank project"
@@ -5320,12 +5320,12 @@ msgid "Open &Project ..."
msgstr "Abierto &Project ..."
#: flatcamGUI/FlatCAMGUI.py:109 flatcamGUI/FlatCAMGUI.py:4121
-msgid "Open &Gerber ...\tCTRL+G"
-msgstr "Abierto &Gerber ...\tCTRL+G"
+msgid "Open &Gerber ...\tCtrl+G"
+msgstr "Abierto &Gerber ...\tCtrl+G"
#: flatcamGUI/FlatCAMGUI.py:114 flatcamGUI/FlatCAMGUI.py:4126
-msgid "Open &Excellon ...\tCTRL+E"
-msgstr "Abierto &Excellon ...\tCTRL+E"
+msgid "Open &Excellon ...\tCtrl+E"
+msgstr "Abierto &Excellon ...\tCtrl+E"
#: flatcamGUI/FlatCAMGUI.py:118 flatcamGUI/FlatCAMGUI.py:4131
msgid "Open G-&Code ..."
@@ -5476,8 +5476,8 @@ msgid "&Save Project ..."
msgstr "Salvar proyecto ..."
#: flatcamGUI/FlatCAMGUI.py:256
-msgid "Save Project &As ...\tCTRL+S"
-msgstr "Guardar proyecto como...\tCTRL+S"
+msgid "Save Project &As ...\tCtrl+S"
+msgstr "Guardar proyecto como...\tCtrl+S"
#: flatcamGUI/FlatCAMGUI.py:261
msgid "Save Project C&opy ..."
@@ -5497,8 +5497,8 @@ msgid "Edit Object\tE"
msgstr "Editar objeto\tE"
#: flatcamGUI/FlatCAMGUI.py:285
-msgid "Close Editor\tCTRL+S"
-msgstr "Cerrar Editor\tCTRL+S"
+msgid "Close Editor\tCtrl+S"
+msgstr "Cerrar Editor\tCtrl+S"
#: flatcamGUI/FlatCAMGUI.py:294
msgid "Conversion"
@@ -5574,8 +5574,8 @@ msgid "Convert Any to Gerber"
msgstr "Convertir cualquiera a Gerber"
#: flatcamGUI/FlatCAMGUI.py:341
-msgid "&Copy\tCTRL+C"
-msgstr "Dupdo\tCTRL+C"
+msgid "&Copy\tCtrl+C"
+msgstr "Dupdo\tCtrl+C"
#: flatcamGUI/FlatCAMGUI.py:346
msgid "&Delete\tDEL"
@@ -5594,28 +5594,28 @@ msgid "Toggle Units\tQ"
msgstr "Unidades de palanca\tQ"
#: flatcamGUI/FlatCAMGUI.py:360
-msgid "&Select All\tCTRL+A"
-msgstr "Seleccionar todo\tCTRL+A"
+msgid "&Select All\tCtrl+A"
+msgstr "Seleccionar todo\tCtrl+A"
#: flatcamGUI/FlatCAMGUI.py:365
-msgid "&Preferences\tSHIFT+P"
-msgstr "Preferencias\tSHIFT+P"
+msgid "&Preferences\tShift+P"
+msgstr "Preferencias\tShift+P"
#: flatcamGUI/FlatCAMGUI.py:371 flatcamTools/ToolProperties.py:153
msgid "Options"
msgstr "Opciones"
#: flatcamGUI/FlatCAMGUI.py:373
-msgid "&Rotate Selection\tSHIFT+(R)"
-msgstr "Rotar selección\tSHIFT+(R)"
+msgid "&Rotate Selection\tShift+(R)"
+msgstr "Rotar selección\tShift+(R)"
#: flatcamGUI/FlatCAMGUI.py:378
-msgid "&Skew on X axis\tSHIFT+X"
-msgstr "Sesgo en el eje X\tSHIFT+X"
+msgid "&Skew on X axis\tShift+X"
+msgstr "Sesgo en el eje X\tShift+X"
#: flatcamGUI/FlatCAMGUI.py:380
-msgid "S&kew on Y axis\tSHIFT+Y"
-msgstr "Sesgo en el eje Y\tSHIFT+Y"
+msgid "S&kew on Y axis\tShift+Y"
+msgstr "Sesgo en el eje Y\tShift+Y"
#: flatcamGUI/FlatCAMGUI.py:385
msgid "Flip on &X axis\tX"
@@ -5626,28 +5626,28 @@ msgid "Flip on &Y axis\tY"
msgstr "Voltear en el ejeY\tY"
#: flatcamGUI/FlatCAMGUI.py:392
-msgid "View source\tALT+S"
-msgstr "Ver fuente\tALT+S"
+msgid "View source\tAlt+S"
+msgstr "Ver fuente\tAlt+S"
#: flatcamGUI/FlatCAMGUI.py:394
-msgid "Tools DataBase\tCTRL+D"
-msgstr "DB de Herramientas\tCTRL+D"
+msgid "Tools DataBase\tCtrl+D"
+msgstr "DB de Herramientas\tCtrl+D"
#: flatcamGUI/FlatCAMGUI.py:401 flatcamGUI/FlatCAMGUI.py:2060
msgid "View"
msgstr "Ver"
#: flatcamGUI/FlatCAMGUI.py:403
-msgid "Enable all plots\tALT+1"
-msgstr "Habilitar todas las parcelas\tALT+1"
+msgid "Enable all plots\tAlt+1"
+msgstr "Habilitar todas las parcelas\tAlt+1"
#: flatcamGUI/FlatCAMGUI.py:405
-msgid "Disable all plots\tALT+2"
-msgstr "Deshabilitar todas las parcelas\tALT+2"
+msgid "Disable all plots\tAlt+2"
+msgstr "Deshabilitar todas las parcelas\tAlt+2"
#: flatcamGUI/FlatCAMGUI.py:407
-msgid "Disable non-selected\tALT+3"
-msgstr "Deshabilitar no seleccionado\tALT+3"
+msgid "Disable non-selected\tAlt+3"
+msgstr "Deshabilitar no seleccionado\tAlt+3"
#: flatcamGUI/FlatCAMGUI.py:411
msgid "&Zoom Fit\tV"
@@ -5666,16 +5666,16 @@ msgid "Redraw All\tF5"
msgstr "Redibujar todo\tF5"
#: flatcamGUI/FlatCAMGUI.py:424
-msgid "Toggle Code Editor\tSHIFT+E"
-msgstr "Alternar Editor de Código\tSHIFT+E"
+msgid "Toggle Code Editor\tShift+E"
+msgstr "Alternar Editor de Código\tShift+E"
#: flatcamGUI/FlatCAMGUI.py:427
-msgid "&Toggle FullScreen\tALT+F10"
-msgstr "Alternar pantalla completa\tALT+F10"
+msgid "&Toggle FullScreen\tAlt+F10"
+msgstr "Alternar pantalla completa\tAlt+F10"
#: flatcamGUI/FlatCAMGUI.py:429
-msgid "&Toggle Plot Area\tCTRL+F10"
-msgstr "Alternar área de la parcela\tCTRL+F10"
+msgid "&Toggle Plot Area\tCtrl+F10"
+msgstr "Alternar área de la parcela\tCtrl+F10"
#: flatcamGUI/FlatCAMGUI.py:431
msgid "&Toggle Project/Sel/Tool\t`"
@@ -5686,16 +5686,16 @@ msgid "&Toggle Grid Snap\tG"
msgstr "Activar cuadrícula\tG"
#: flatcamGUI/FlatCAMGUI.py:437
-msgid "&Toggle Grid Lines\tALT+G"
-msgstr "Alternar Líneas de Cuadrícula\tALT+G"
+msgid "&Toggle Grid Lines\tAlt+G"
+msgstr "Alternar Líneas de Cuadrícula\tAlt+G"
#: flatcamGUI/FlatCAMGUI.py:439
-msgid "&Toggle Axis\tSHIFT+G"
-msgstr "Eje de palanca\tSHIFT+G"
+msgid "&Toggle Axis\tShift+G"
+msgstr "Eje de palanca\tShift+G"
#: flatcamGUI/FlatCAMGUI.py:441
-msgid "Toggle Workspace\tSHIFT+W"
-msgstr "Alternar espacio de trabajo\tSHIFT+W"
+msgid "Toggle Workspace\tShift+W"
+msgstr "Alternar espacio de trabajo\tShift+W"
#: flatcamGUI/FlatCAMGUI.py:446
msgid "Objects"
@@ -5794,8 +5794,8 @@ msgid "Paint Tool\tI"
msgstr "Herramienta de pintura\tI"
#: flatcamGUI/FlatCAMGUI.py:543
-msgid "Transform Tool\tALT+R"
-msgstr "Herramienta de transformación\tALT+R"
+msgid "Transform Tool\tAlt+R"
+msgstr "Herramienta de transformación\tAlt+R"
#: flatcamGUI/FlatCAMGUI.py:547
msgid "Toggle Corner Snap\tK"
@@ -5858,8 +5858,8 @@ msgid "Add Region\tN"
msgstr "Añadir región\tN"
#: flatcamGUI/FlatCAMGUI.py:598
-msgid "Poligonize\tALT+N"
-msgstr "Poligonize\tALT+N"
+msgid "Poligonize\tAlt+N"
+msgstr "Poligonize\tAlt+N"
#: flatcamGUI/FlatCAMGUI.py:600
msgid "Add SemiDisc\tE"
@@ -5878,16 +5878,16 @@ msgid "Scale\tS"
msgstr "Escalar\tS"
#: flatcamGUI/FlatCAMGUI.py:608
-msgid "Mark Area\tALT+A"
-msgstr "Marcar area\tALT+A"
+msgid "Mark Area\tAlt+A"
+msgstr "Marcar area\tAlt+A"
#: flatcamGUI/FlatCAMGUI.py:610
-msgid "Eraser\tCTRL+E"
-msgstr "Borrador\tCTRL+E"
+msgid "Eraser\tCtrl+E"
+msgstr "Borrador\tCtrl+E"
#: flatcamGUI/FlatCAMGUI.py:612
-msgid "Transform\tALT+R"
-msgstr "Transformar\tALT+R"
+msgid "Transform\tAlt+R"
+msgstr "Transformar\tAlt+R"
#: flatcamGUI/FlatCAMGUI.py:639
msgid "Enable Plot"
@@ -14007,7 +14007,7 @@ msgid ""
"\n"
"The coordinates set can be obtained:\n"
"- press SHIFT key and left mouse clicking on canvas. Then click Add.\n"
-"- press SHIFT key and left mouse clicking on canvas. Then CTRL+V in the "
+"- press SHIFT key and left mouse clicking on canvas. Then Ctrl+V in the "
"field.\n"
"- press SHIFT key and left mouse clicking on canvas. Then RMB click in the "
"field and click Paste.\n"
@@ -17788,8 +17788,8 @@ msgstr ""
#~ "\n"
#~ " "
-#~ msgid "Run Script ...\tSHIFT+S"
-#~ msgstr "Ejecutar Script ...\tSHIFT+S"
+#~ msgid "Run Script ...\tShift+S"
+#~ msgstr "Ejecutar Script ...\tShift+S"
#~ msgid ""
#~ "FlatCAM
Version {version} {beta} ({date}) - "
diff --git a/locale/fr/LC_MESSAGES/strings.po b/locale/fr/LC_MESSAGES/strings.po
index a58e7f3c..ad897b9b 100644
--- a/locale/fr/LC_MESSAGES/strings.po
+++ b/locale/fr/LC_MESSAGES/strings.po
@@ -5282,8 +5282,8 @@ msgid "File"
msgstr "Fichier"
#: flatcamGUI/FlatCAMGUI.py:69
-msgid "&New Project ...\tCTRL+N"
-msgstr "Nouveau projet ...\tCTRL+N"
+msgid "&New Project ...\tCtrl+N"
+msgstr "Nouveau projet ...\tCtrl+N"
#: flatcamGUI/FlatCAMGUI.py:71
msgid "Will create a new, blank project"
@@ -5335,12 +5335,12 @@ msgid "Open &Project ..."
msgstr "Projet ouvert ..."
#: flatcamGUI/FlatCAMGUI.py:109 flatcamGUI/FlatCAMGUI.py:4121
-msgid "Open &Gerber ...\tCTRL+G"
-msgstr "Gerber ouvert...\tCTRL+G"
+msgid "Open &Gerber ...\tCtrl+G"
+msgstr "Gerber ouvert...\tCtrl+G"
#: flatcamGUI/FlatCAMGUI.py:114 flatcamGUI/FlatCAMGUI.py:4126
-msgid "Open &Excellon ...\tCTRL+E"
-msgstr "Excellon ouvert ...\tCTRL+E"
+msgid "Open &Excellon ...\tCtrl+E"
+msgstr "Excellon ouvert ...\tCtrl+E"
#: flatcamGUI/FlatCAMGUI.py:118 flatcamGUI/FlatCAMGUI.py:4131
msgid "Open G-&Code ..."
@@ -5491,8 +5491,8 @@ msgid "&Save Project ..."
msgstr "Sauvegarder le projet ..."
#: flatcamGUI/FlatCAMGUI.py:256
-msgid "Save Project &As ...\tCTRL+S"
-msgstr "Enregistrer le projet sous...\tCTRL+S"
+msgid "Save Project &As ...\tCtrl+S"
+msgstr "Enregistrer le projet sous...\tCtrl+S"
#: flatcamGUI/FlatCAMGUI.py:261
msgid "Save Project C&opy ..."
@@ -5512,8 +5512,8 @@ msgid "Edit Object\tE"
msgstr "Editer un objet\tE"
#: flatcamGUI/FlatCAMGUI.py:285
-msgid "Close Editor\tCTRL+S"
-msgstr "Fermer l'éditeur\tCTRL+S"
+msgid "Close Editor\tCtrl+S"
+msgstr "Fermer l'éditeur\tCtrl+S"
#: flatcamGUI/FlatCAMGUI.py:294
msgid "Conversion"
@@ -5589,8 +5589,8 @@ msgid "Convert Any to Gerber"
msgstr "Convertir n'importe lequel en gerber"
#: flatcamGUI/FlatCAMGUI.py:341
-msgid "&Copy\tCTRL+C"
-msgstr "Copie\tCTRL+C"
+msgid "&Copy\tCtrl+C"
+msgstr "Copie\tCtrl+C"
#: flatcamGUI/FlatCAMGUI.py:346
msgid "&Delete\tDEL"
@@ -5609,28 +5609,28 @@ msgid "Toggle Units\tQ"
msgstr "Basculer les Unités\tQ"
#: flatcamGUI/FlatCAMGUI.py:360
-msgid "&Select All\tCTRL+A"
-msgstr "Tout sélectionner\tCTRL+A"
+msgid "&Select All\tCtrl+A"
+msgstr "Tout sélectionner\tCtrl+A"
#: flatcamGUI/FlatCAMGUI.py:365
-msgid "&Preferences\tSHIFT+P"
-msgstr "Préférences\tSHIFT+P"
+msgid "&Preferences\tShift+P"
+msgstr "Préférences\tShift+P"
#: flatcamGUI/FlatCAMGUI.py:371 flatcamTools/ToolProperties.py:153
msgid "Options"
msgstr "Les options"
#: flatcamGUI/FlatCAMGUI.py:373
-msgid "&Rotate Selection\tSHIFT+(R)"
-msgstr "Faire pivoter la sélection\tSHIFT+(R)"
+msgid "&Rotate Selection\tShift+(R)"
+msgstr "Faire pivoter la sélection\tShift+(R)"
#: flatcamGUI/FlatCAMGUI.py:378
-msgid "&Skew on X axis\tSHIFT+X"
-msgstr "Fausser sur l'axe X\tSHIFT+X"
+msgid "&Skew on X axis\tShift+X"
+msgstr "Fausser sur l'axe X\tShift+X"
#: flatcamGUI/FlatCAMGUI.py:380
-msgid "S&kew on Y axis\tSHIFT+Y"
-msgstr "Fausser sur l'axe Y\tSHIFT+Y"
+msgid "S&kew on Y axis\tShift+Y"
+msgstr "Fausser sur l'axe Y\tShift+Y"
#: flatcamGUI/FlatCAMGUI.py:385
msgid "Flip on &X axis\tX"
@@ -5641,28 +5641,28 @@ msgid "Flip on &Y axis\tY"
msgstr "Miroir sur l'axe Y\tY"
#: flatcamGUI/FlatCAMGUI.py:392
-msgid "View source\tALT+S"
-msgstr "Voir la source\tALT+S"
+msgid "View source\tAlt+S"
+msgstr "Voir la source\tAlt+S"
#: flatcamGUI/FlatCAMGUI.py:394
-msgid "Tools DataBase\tCTRL+D"
-msgstr "Base de Données d'outils\tCTRL+D"
+msgid "Tools DataBase\tCtrl+D"
+msgstr "Base de Données d'outils\tCtrl+D"
#: flatcamGUI/FlatCAMGUI.py:401 flatcamGUI/FlatCAMGUI.py:2060
msgid "View"
msgstr "Vue"
#: flatcamGUI/FlatCAMGUI.py:403
-msgid "Enable all plots\tALT+1"
-msgstr "Activer tous les dessins\tALT+1"
+msgid "Enable all plots\tAlt+1"
+msgstr "Activer tous les dessins\tAlt+1"
#: flatcamGUI/FlatCAMGUI.py:405
-msgid "Disable all plots\tALT+2"
-msgstr "Désactiver tous les dessins\tALT+2"
+msgid "Disable all plots\tAlt+2"
+msgstr "Désactiver tous les dessins\tAlt+2"
#: flatcamGUI/FlatCAMGUI.py:407
-msgid "Disable non-selected\tALT+3"
-msgstr "Désactiver les non sélectionnés\tALT+3"
+msgid "Disable non-selected\tAlt+3"
+msgstr "Désactiver les non sélectionnés\tAlt+3"
#: flatcamGUI/FlatCAMGUI.py:411
msgid "&Zoom Fit\tV"
@@ -5681,16 +5681,16 @@ msgid "Redraw All\tF5"
msgstr "Tout redessiner\tF5"
#: flatcamGUI/FlatCAMGUI.py:424
-msgid "Toggle Code Editor\tSHIFT+E"
-msgstr "Basculer l'éditeur de code\tSHIFT+E"
+msgid "Toggle Code Editor\tShift+E"
+msgstr "Basculer l'éditeur de code\tShift+E"
#: flatcamGUI/FlatCAMGUI.py:427
-msgid "&Toggle FullScreen\tALT+F10"
-msgstr "Passer en plein écran\tALT+F10"
+msgid "&Toggle FullScreen\tAlt+F10"
+msgstr "Passer en plein écran\tAlt+F10"
#: flatcamGUI/FlatCAMGUI.py:429
-msgid "&Toggle Plot Area\tCTRL+F10"
-msgstr "Basculer la zone de tracé\tCTRL+F10"
+msgid "&Toggle Plot Area\tCtrl+F10"
+msgstr "Basculer la zone de tracé\tCtrl+F10"
#: flatcamGUI/FlatCAMGUI.py:431
msgid "&Toggle Project/Sel/Tool\t`"
@@ -5701,16 +5701,16 @@ msgid "&Toggle Grid Snap\tG"
msgstr "Basculer la grille\tG"
#: flatcamGUI/FlatCAMGUI.py:437
-msgid "&Toggle Grid Lines\tALT+G"
-msgstr "Basculer les lignes de la grille\tALT+G"
+msgid "&Toggle Grid Lines\tAlt+G"
+msgstr "Basculer les lignes de la grille\tAlt+G"
#: flatcamGUI/FlatCAMGUI.py:439
-msgid "&Toggle Axis\tSHIFT+G"
-msgstr "Basculer l'axe\tSHIFT+G"
+msgid "&Toggle Axis\tShift+G"
+msgstr "Basculer l'axe\tShift+G"
#: flatcamGUI/FlatCAMGUI.py:441
-msgid "Toggle Workspace\tSHIFT+W"
-msgstr "Basculer l'espace de travail\tSHIFT+W"
+msgid "Toggle Workspace\tShift+W"
+msgstr "Basculer l'espace de travail\tShift+W"
#: flatcamGUI/FlatCAMGUI.py:446
msgid "Objects"
@@ -5809,8 +5809,8 @@ msgid "Paint Tool\tI"
msgstr "Outil de Peinture\tI"
#: flatcamGUI/FlatCAMGUI.py:543
-msgid "Transform Tool\tALT+R"
-msgstr "Outil de Transformation\tALT+R"
+msgid "Transform Tool\tAlt+R"
+msgstr "Outil de Transformation\tAlt+R"
#: flatcamGUI/FlatCAMGUI.py:547
msgid "Toggle Corner Snap\tK"
@@ -5873,8 +5873,8 @@ msgid "Add Region\tN"
msgstr "Ajouter une Région\tN"
#: flatcamGUI/FlatCAMGUI.py:598
-msgid "Poligonize\tALT+N"
-msgstr "Polygoniser\tALT+N"
+msgid "Poligonize\tAlt+N"
+msgstr "Polygoniser\tAlt+N"
#: flatcamGUI/FlatCAMGUI.py:600
msgid "Add SemiDisc\tE"
@@ -5893,16 +5893,16 @@ msgid "Scale\tS"
msgstr "Échelle\tS"
#: flatcamGUI/FlatCAMGUI.py:608
-msgid "Mark Area\tALT+A"
-msgstr "Zone de Marque\tALT+A"
+msgid "Mark Area\tAlt+A"
+msgstr "Zone de Marque\tAlt+A"
#: flatcamGUI/FlatCAMGUI.py:610
-msgid "Eraser\tCTRL+E"
-msgstr "La Gomme\tCTRL+E"
+msgid "Eraser\tCtrl+E"
+msgstr "La Gomme\tCtrl+E"
#: flatcamGUI/FlatCAMGUI.py:612
-msgid "Transform\tALT+R"
-msgstr "Transformation\tALT+R"
+msgid "Transform\tAlt+R"
+msgstr "Transformation\tAlt+R"
#: flatcamGUI/FlatCAMGUI.py:639
msgid "Enable Plot"
@@ -14014,7 +14014,7 @@ msgid ""
"\n"
"The coordinates set can be obtained:\n"
"- press SHIFT key and left mouse clicking on canvas. Then click Add.\n"
-"- press SHIFT key and left mouse clicking on canvas. Then CTRL+V in the "
+"- press SHIFT key and left mouse clicking on canvas. Then Ctrl+V in the "
"field.\n"
"- press SHIFT key and left mouse clicking on canvas. Then RMB click in the "
"field and click Paste.\n"
diff --git a/locale/it/LC_MESSAGES/strings.po b/locale/it/LC_MESSAGES/strings.po
index 118af3b2..5a2bdbdf 100644
--- a/locale/it/LC_MESSAGES/strings.po
+++ b/locale/it/LC_MESSAGES/strings.po
@@ -4787,8 +4787,8 @@ msgid "File"
msgstr "File"
#: flatcamGUI/FlatCAMGUI.py:69
-msgid "&New Project ...\tCTRL+N"
-msgstr "&Nuovo progetto ...\tCTRL+N"
+msgid "&New Project ...\tCtrl+N"
+msgstr "&Nuovo progetto ...\tCtrl+N"
#: flatcamGUI/FlatCAMGUI.py:71
msgid "Will create a new, blank project"
@@ -4840,12 +4840,12 @@ msgid "Open &Project ..."
msgstr "Progetto aperto ..."
#: flatcamGUI/FlatCAMGUI.py:109 flatcamGUI/FlatCAMGUI.py:4121
-msgid "Open &Gerber ...\tCTRL+G"
-msgstr "Apri Gerber...\tCTRL+G"
+msgid "Open &Gerber ...\tCtrl+G"
+msgstr "Apri Gerber...\tCtrl+G"
#: flatcamGUI/FlatCAMGUI.py:114 flatcamGUI/FlatCAMGUI.py:4126
-msgid "Open &Excellon ...\tCTRL+E"
-msgstr "Apri Excellon ...\tCTRL+E"
+msgid "Open &Excellon ...\tCtrl+E"
+msgstr "Apri Excellon ...\tCtrl+E"
#: flatcamGUI/FlatCAMGUI.py:118 flatcamGUI/FlatCAMGUI.py:4131
msgid "Open G-&Code ..."
@@ -4984,8 +4984,8 @@ msgid "&Save Project ..."
msgstr "Salva il progetto ..."
#: flatcamGUI/FlatCAMGUI.py:256
-msgid "Save Project &As ...\tCTRL+S"
-msgstr "Salva progetto con nome ...\tCTRL+S"
+msgid "Save Project &As ...\tCtrl+S"
+msgstr "Salva progetto con nome ...\tCtrl+S"
#: flatcamGUI/FlatCAMGUI.py:261
msgid "Save Project C&opy ..."
@@ -5005,7 +5005,7 @@ msgid "Edit Object\tE"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:285
-msgid "Close Editor\tCTRL+S"
+msgid "Close Editor\tCtrl+S"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:294
@@ -5070,7 +5070,7 @@ msgid "Convert Any to Gerber"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:341
-msgid "&Copy\tCTRL+C"
+msgid "&Copy\tCtrl+C"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:346
@@ -5090,11 +5090,11 @@ msgid "Toggle Units\tQ"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:360
-msgid "&Select All\tCTRL+A"
+msgid "&Select All\tCtrl+A"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:365
-msgid "&Preferences\tSHIFT+P"
+msgid "&Preferences\tShift+P"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:371 flatcamTools/ToolProperties.py:153
@@ -5102,15 +5102,15 @@ msgid "Options"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:373
-msgid "&Rotate Selection\tSHIFT+(R)"
+msgid "&Rotate Selection\tShift+(R)"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:378
-msgid "&Skew on X axis\tSHIFT+X"
+msgid "&Skew on X axis\tShift+X"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:380
-msgid "S&kew on Y axis\tSHIFT+Y"
+msgid "S&kew on Y axis\tShift+Y"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:385
@@ -5122,11 +5122,11 @@ msgid "Flip on &Y axis\tY"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:392
-msgid "View source\tALT+S"
+msgid "View source\tAlt+S"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:394
-msgid "Tools DataBase\tCTRL+D"
+msgid "Tools DataBase\tCtrl+D"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:401 flatcamGUI/FlatCAMGUI.py:2060
@@ -5134,15 +5134,15 @@ msgid "View"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:403
-msgid "Enable all plots\tALT+1"
+msgid "Enable all plots\tAlt+1"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:405
-msgid "Disable all plots\tALT+2"
+msgid "Disable all plots\tAlt+2"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:407
-msgid "Disable non-selected\tALT+3"
+msgid "Disable non-selected\tAlt+3"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:411
@@ -5162,15 +5162,15 @@ msgid "Redraw All\tF5"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:424
-msgid "Toggle Code Editor\tSHIFT+E"
+msgid "Toggle Code Editor\tShift+E"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:427
-msgid "&Toggle FullScreen\tALT+F10"
+msgid "&Toggle FullScreen\tAlt+F10"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:429
-msgid "&Toggle Plot Area\tCTRL+F10"
+msgid "&Toggle Plot Area\tCtrl+F10"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:431
@@ -5182,15 +5182,15 @@ msgid "&Toggle Grid Snap\tG"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:437
-msgid "&Toggle Grid Lines\tALT+G"
+msgid "&Toggle Grid Lines\tAlt+G"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:439
-msgid "&Toggle Axis\tSHIFT+G"
+msgid "&Toggle Axis\tShift+G"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:441
-msgid "Toggle Workspace\tSHIFT+W"
+msgid "Toggle Workspace\tShift+W"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:446
@@ -5290,7 +5290,7 @@ msgid "Paint Tool\tI"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:543
-msgid "Transform Tool\tALT+R"
+msgid "Transform Tool\tAlt+R"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:547
@@ -5354,7 +5354,7 @@ msgid "Add Region\tN"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:598
-msgid "Poligonize\tALT+N"
+msgid "Poligonize\tAlt+N"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:600
@@ -5374,15 +5374,15 @@ msgid "Scale\tS"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:608
-msgid "Mark Area\tALT+A"
+msgid "Mark Area\tAlt+A"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:610
-msgid "Eraser\tCTRL+E"
+msgid "Eraser\tCtrl+E"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:612
-msgid "Transform\tALT+R"
+msgid "Transform\tAlt+R"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:639
@@ -12253,7 +12253,7 @@ msgid ""
"\n"
"The coordinates set can be obtained:\n"
"- press SHIFT key and left mouse clicking on canvas. Then click Add.\n"
-"- press SHIFT key and left mouse clicking on canvas. Then CTRL+V in the "
+"- press SHIFT key and left mouse clicking on canvas. Then Ctrl+V in the "
"field.\n"
"- press SHIFT key and left mouse clicking on canvas. Then RMB click in the "
"field and click Paste.\n"
diff --git a/locale/pt_BR/LC_MESSAGES/strings.po b/locale/pt_BR/LC_MESSAGES/strings.po
index 9e753cf7..15a1b23f 100644
--- a/locale/pt_BR/LC_MESSAGES/strings.po
+++ b/locale/pt_BR/LC_MESSAGES/strings.po
@@ -5241,8 +5241,8 @@ msgid "File"
msgstr "Arquivo"
#: flatcamGUI/FlatCAMGUI.py:69
-msgid "&New Project ...\tCTRL+N"
-msgstr "&Novo Projeto ...\tCTRL+N"
+msgid "&New Project ...\tCtrl+N"
+msgstr "&Novo Projeto ...\tCtrl+N"
#: flatcamGUI/FlatCAMGUI.py:71
msgid "Will create a new, blank project"
@@ -5294,12 +5294,12 @@ msgid "Open &Project ..."
msgstr "Abrir &Projeto ..."
#: flatcamGUI/FlatCAMGUI.py:109 flatcamGUI/FlatCAMGUI.py:4121
-msgid "Open &Gerber ...\tCTRL+G"
-msgstr "Abrir &Gerber ...\tCTRL+G"
+msgid "Open &Gerber ...\tCtrl+G"
+msgstr "Abrir &Gerber ...\tCtrl+G"
#: flatcamGUI/FlatCAMGUI.py:114 flatcamGUI/FlatCAMGUI.py:4126
-msgid "Open &Excellon ...\tCTRL+E"
-msgstr "Abrir &Excellon ...\tCTRL+E"
+msgid "Open &Excellon ...\tCtrl+E"
+msgstr "Abrir &Excellon ...\tCtrl+E"
#: flatcamGUI/FlatCAMGUI.py:118 flatcamGUI/FlatCAMGUI.py:4131
msgid "Open G-&Code ..."
@@ -5450,8 +5450,8 @@ msgid "&Save Project ..."
msgstr "&Salvar Projeto ..."
#: flatcamGUI/FlatCAMGUI.py:256
-msgid "Save Project &As ...\tCTRL+S"
-msgstr "S&alvar Projeto Como ...\tCTRL+S"
+msgid "Save Project &As ...\tCtrl+S"
+msgstr "S&alvar Projeto Como ...\tCtrl+S"
#: flatcamGUI/FlatCAMGUI.py:261
msgid "Save Project C&opy ..."
@@ -5471,8 +5471,8 @@ msgid "Edit Object\tE"
msgstr "Editar Objeto\tE"
#: flatcamGUI/FlatCAMGUI.py:285
-msgid "Close Editor\tCTRL+S"
-msgstr "Fechar Editor\tCTRL+S"
+msgid "Close Editor\tCtrl+S"
+msgstr "Fechar Editor\tCtrl+S"
#: flatcamGUI/FlatCAMGUI.py:294
msgid "Conversion"
@@ -5545,8 +5545,8 @@ msgid "Convert Any to Gerber"
msgstr "Converter Qualquer para Gerber"
#: flatcamGUI/FlatCAMGUI.py:341
-msgid "&Copy\tCTRL+C"
-msgstr "&Copiar\tCTRL+C"
+msgid "&Copy\tCtrl+C"
+msgstr "&Copiar\tCtrl+C"
#: flatcamGUI/FlatCAMGUI.py:346
msgid "&Delete\tDEL"
@@ -5565,28 +5565,28 @@ msgid "Toggle Units\tQ"
msgstr "Alternar Unidades\tQ"
#: flatcamGUI/FlatCAMGUI.py:360
-msgid "&Select All\tCTRL+A"
-msgstr "&Selecionar Tudo\tCTRL+A"
+msgid "&Select All\tCtrl+A"
+msgstr "&Selecionar Tudo\tCtrl+A"
#: flatcamGUI/FlatCAMGUI.py:365
-msgid "&Preferences\tSHIFT+P"
-msgstr "&Preferências\tSHIFT+P"
+msgid "&Preferences\tShift+P"
+msgstr "&Preferências\tShift+P"
#: flatcamGUI/FlatCAMGUI.py:371 flatcamTools/ToolProperties.py:153
msgid "Options"
msgstr "Opções"
#: flatcamGUI/FlatCAMGUI.py:373
-msgid "&Rotate Selection\tSHIFT+(R)"
-msgstr "Gi&rar Seleção\tSHIFT+(R)"
+msgid "&Rotate Selection\tShift+(R)"
+msgstr "Gi&rar Seleção\tShift+(R)"
#: flatcamGUI/FlatCAMGUI.py:378
-msgid "&Skew on X axis\tSHIFT+X"
-msgstr "Inclinar no eixo X\tSHIFT+X"
+msgid "&Skew on X axis\tShift+X"
+msgstr "Inclinar no eixo X\tShift+X"
#: flatcamGUI/FlatCAMGUI.py:380
-msgid "S&kew on Y axis\tSHIFT+Y"
-msgstr "Inclinar no eixo Y\tSHIFT+Y"
+msgid "S&kew on Y axis\tShift+Y"
+msgstr "Inclinar no eixo Y\tShift+Y"
#: flatcamGUI/FlatCAMGUI.py:385
msgid "Flip on &X axis\tX"
@@ -5597,28 +5597,28 @@ msgid "Flip on &Y axis\tY"
msgstr "Espelhar no eixo &Y\tY"
#: flatcamGUI/FlatCAMGUI.py:392
-msgid "View source\tALT+S"
-msgstr "Ver fonte\tALT+S"
+msgid "View source\tAlt+S"
+msgstr "Ver fonte\tAlt+S"
#: flatcamGUI/FlatCAMGUI.py:394
-msgid "Tools DataBase\tCTRL+D"
-msgstr "Banco de Dados de Ferramentas\tCTRL+D"
+msgid "Tools DataBase\tCtrl+D"
+msgstr "Banco de Dados de Ferramentas\tCtrl+D"
#: flatcamGUI/FlatCAMGUI.py:401 flatcamGUI/FlatCAMGUI.py:2060
msgid "View"
msgstr "Ver"
#: flatcamGUI/FlatCAMGUI.py:403
-msgid "Enable all plots\tALT+1"
-msgstr "Habilitar todos os gráficos\tALT+1"
+msgid "Enable all plots\tAlt+1"
+msgstr "Habilitar todos os gráficos\tAlt+1"
#: flatcamGUI/FlatCAMGUI.py:405
-msgid "Disable all plots\tALT+2"
-msgstr "Desabilitar todos os gráficos\tALT+2"
+msgid "Disable all plots\tAlt+2"
+msgstr "Desabilitar todos os gráficos\tAlt+2"
#: flatcamGUI/FlatCAMGUI.py:407
-msgid "Disable non-selected\tALT+3"
-msgstr "Desabilitar os não selecionados\tALT+3"
+msgid "Disable non-selected\tAlt+3"
+msgstr "Desabilitar os não selecionados\tAlt+3"
#: flatcamGUI/FlatCAMGUI.py:411
msgid "&Zoom Fit\tV"
@@ -5637,16 +5637,16 @@ msgid "Redraw All\tF5"
msgstr "Redesenha Todos\tF5"
#: flatcamGUI/FlatCAMGUI.py:424
-msgid "Toggle Code Editor\tSHIFT+E"
-msgstr "Alternar o Editor de Códigos\tSHIFT+E"
+msgid "Toggle Code Editor\tShift+E"
+msgstr "Alternar o Editor de Códigos\tShift+E"
#: flatcamGUI/FlatCAMGUI.py:427
-msgid "&Toggle FullScreen\tALT+F10"
-msgstr "Alternar &Tela Cheia\tALT+F10"
+msgid "&Toggle FullScreen\tAlt+F10"
+msgstr "Alternar &Tela Cheia\tAlt+F10"
#: flatcamGUI/FlatCAMGUI.py:429
-msgid "&Toggle Plot Area\tCTRL+F10"
-msgstr "Al&ternar Área de Gráficos\tCTRL+F10"
+msgid "&Toggle Plot Area\tCtrl+F10"
+msgstr "Al&ternar Área de Gráficos\tCtrl+F10"
#: flatcamGUI/FlatCAMGUI.py:431
msgid "&Toggle Project/Sel/Tool\t`"
@@ -5657,16 +5657,16 @@ msgid "&Toggle Grid Snap\tG"
msgstr "Al&ternar Encaixe na Grade\tG"
#: flatcamGUI/FlatCAMGUI.py:437
-msgid "&Toggle Grid Lines\tALT+G"
-msgstr "Al&ternar Encaixe na Grade\tALT+G"
+msgid "&Toggle Grid Lines\tAlt+G"
+msgstr "Al&ternar Encaixe na Grade\tAlt+G"
#: flatcamGUI/FlatCAMGUI.py:439
-msgid "&Toggle Axis\tSHIFT+G"
-msgstr "Al&ternar Eixo\tSHIFT+G"
+msgid "&Toggle Axis\tShift+G"
+msgstr "Al&ternar Eixo\tShift+G"
#: flatcamGUI/FlatCAMGUI.py:441
-msgid "Toggle Workspace\tSHIFT+W"
-msgstr "Alternar Área de Trabalho\tSHIFT+W"
+msgid "Toggle Workspace\tShift+W"
+msgstr "Alternar Área de Trabalho\tShift+W"
#: flatcamGUI/FlatCAMGUI.py:446
msgid "Objects"
@@ -5765,8 +5765,8 @@ msgid "Paint Tool\tI"
msgstr "Ferramenta de Pintura\tI"
#: flatcamGUI/FlatCAMGUI.py:543
-msgid "Transform Tool\tALT+R"
-msgstr "Ferramenta de Transformação\tALT+R"
+msgid "Transform Tool\tAlt+R"
+msgstr "Ferramenta de Transformação\tAlt+R"
#: flatcamGUI/FlatCAMGUI.py:547
msgid "Toggle Corner Snap\tK"
@@ -5829,8 +5829,8 @@ msgid "Add Region\tN"
msgstr "Adicionar Região\tN"
#: flatcamGUI/FlatCAMGUI.py:598
-msgid "Poligonize\tALT+N"
-msgstr "Poligonizar\tALT+N"
+msgid "Poligonize\tAlt+N"
+msgstr "Poligonizar\tAlt+N"
#: flatcamGUI/FlatCAMGUI.py:600
msgid "Add SemiDisc\tE"
@@ -5849,16 +5849,16 @@ msgid "Scale\tS"
msgstr "Escala\tS"
#: flatcamGUI/FlatCAMGUI.py:608
-msgid "Mark Area\tALT+A"
-msgstr "Marcar Área\tALT+A"
+msgid "Mark Area\tAlt+A"
+msgstr "Marcar Área\tAlt+A"
#: flatcamGUI/FlatCAMGUI.py:610
-msgid "Eraser\tCTRL+E"
-msgstr "Borracha\tCTRL+E"
+msgid "Eraser\tCtrl+E"
+msgstr "Borracha\tCtrl+E"
#: flatcamGUI/FlatCAMGUI.py:612
-msgid "Transform\tALT+R"
-msgstr "Transformar\tALT+R"
+msgid "Transform\tAlt+R"
+msgstr "Transformar\tAlt+R"
#: flatcamGUI/FlatCAMGUI.py:639
msgid "Enable Plot"
@@ -13846,7 +13846,7 @@ msgid ""
"\n"
"The coordinates set can be obtained:\n"
"- press SHIFT key and left mouse clicking on canvas. Then click Add.\n"
-"- press SHIFT key and left mouse clicking on canvas. Then CTRL+V in the "
+"- press SHIFT key and left mouse clicking on canvas. Then Ctrl+V in the "
"field.\n"
"- press SHIFT key and left mouse clicking on canvas. Then RMB click in the "
"field and click Paste.\n"
@@ -17554,8 +17554,8 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ "\n"
#~ " "
-#~ msgid "Run Script ...\tSHIFT+S"
-#~ msgstr "Executar Script ...\tSHIFT+S"
+#~ msgid "Run Script ...\tShift+S"
+#~ msgstr "Executar Script ...\tShift+S"
#~ msgid ""
#~ "FlatCAM
Version {version} {beta} ({date}) - "
@@ -17724,39 +17724,39 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | CTRL+A | \n"
+#~ " Ctrl+A | \n"
#~ " Select All | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+C | \n"
+#~ " Ctrl+C | \n"
#~ " Copy Obj | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+E | \n"
+#~ " Ctrl+E | \n"
#~ " Open Excellon File | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+G | \n"
+#~ " Ctrl+G | \n"
#~ " Open Gerber File | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+N | \n"
+#~ " Ctrl+N | \n"
#~ " New Project | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Measurement Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+O | \n"
+#~ " Ctrl+O | \n"
#~ " Open Project | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Project As | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+F10 | \n"
+#~ " Ctrl+F10 | \n"
#~ " Toggle Plot Area | \n"
#~ "
\n"
#~ " \n"
@@ -17764,39 +17764,39 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+C | \n"
+#~ " Shift+C | \n"
#~ " Copy Obj_Name | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+E | \n"
+#~ " Shift+E | \n"
#~ " Toggle Code Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+G | \n"
+#~ " Shift+G | \n"
#~ " Toggle the axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+P | \n"
+#~ " Shift+P | \n"
#~ " Open Preferences Window | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+R | \n"
+#~ " Shift+R | \n"
#~ " Rotate by 90 degree CCW | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+S | \n"
+#~ " Shift+S | \n"
#~ " Run a Script | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+W | \n"
+#~ " Shift+W | \n"
#~ " Toggle the workspace | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Skew on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Skew on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -17804,59 +17804,59 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+C | \n"
+#~ " Alt+C | \n"
#~ " Calculators Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+D | \n"
+#~ " Alt+D | \n"
#~ " 2-Sided PCB Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+K | \n"
+#~ " Alt+K | \n"
#~ " Solder Paste Dispensing Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+L | \n"
+#~ " Alt+L | \n"
#~ " Film PCB Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Non-Copper Clearing Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+P | \n"
+#~ " Alt+P | \n"
#~ " Paint Area Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Q | \n"
+#~ " Alt+Q | \n"
#~ " PDF Import Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Transformations Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+S | \n"
+#~ " Alt+S | \n"
#~ " View File Source | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+U | \n"
+#~ " Alt+U | \n"
#~ " Cutout PCB Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+1 | \n"
+#~ " Alt+1 | \n"
#~ " Enable all Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+2 | \n"
+#~ " Alt+2 | \n"
#~ " Disable all Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+3 | \n"
+#~ " Alt+3 | \n"
#~ " Disable Non-selected Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+F10 | \n"
+#~ " Alt+F10 | \n"
#~ " Toggle Full Screen | \n"
#~ "
\n"
#~ " \n"
@@ -17864,7 +17864,7 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+ALT+X"
+#~ " | Ctrl+Alt+X"
#~ "td>\n"
#~ " | Abort current task (gracefully) | \n"
#~ "
\n"
@@ -18016,39 +18016,39 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | CTRL+A | \n"
+#~ " Ctrl+A | \n"
#~ " Seleciona Todos | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+C | \n"
+#~ " Ctrl+C | \n"
#~ " Copiar Objeto | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+E | \n"
+#~ " Ctrl+E | \n"
#~ " Abrir Arquivo Excellon | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+G | \n"
+#~ " Ctrl+G | \n"
#~ " Abrir Arquivo Gerber | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+N | \n"
+#~ " Ctrl+N | \n"
#~ " Novo Projeto | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Ferramenta de Medição | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+O | \n"
+#~ " Ctrl+O | \n"
#~ " Abrir Projeto | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Salvar Projeto Como | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+F10 | \n"
+#~ " Ctrl+F10 | \n"
#~ " Alternar Área de Gráfico | \n"
#~ "
\n"
#~ " \n"
@@ -18056,39 +18056,39 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+C | \n"
+#~ " Shift+C | \n"
#~ " Copiar Obj_Name | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+E | \n"
+#~ " Shift+E | \n"
#~ " Alterna Editor de Código | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+G | \n"
+#~ " Shift+G | \n"
#~ " Alterna o Eixo | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+P | \n"
+#~ " Shift+P | \n"
#~ " Abre Janela de Preferências | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+R | \n"
+#~ " Shift+R | \n"
#~ " Gira 90 graus antihorário | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+S | \n"
+#~ " Shift+S | \n"
#~ " Executa um Script | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+W | \n"
+#~ " Shift+W | \n"
#~ " Alterna o Local de Trabalho | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Inclina no Eixo X | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Inclina no Eixo Y | \n"
#~ "
\n"
#~ " \n"
@@ -18096,60 +18096,60 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+C | \n"
+#~ " Alt+C | \n"
#~ " Calculadoras | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+D | \n"
+#~ " Alt+D | \n"
#~ " Ferramenta PCB 2-Faces | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+K | \n"
+#~ " Alt+K | \n"
#~ " Ferramenta Pasta de Solda | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+L | \n"
+#~ " Alt+L | \n"
#~ " Ferramenta Filme PCB | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Ferramenta Retirar Cobre (NCC) | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+P | \n"
+#~ " Alt+P | \n"
#~ " Ferramenta Pintura de Área | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Q | \n"
+#~ " Alt+Q | \n"
#~ " Ferramenta Importar PDF | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Ferramenta Transformações | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+S | \n"
+#~ " Alt+S | \n"
#~ " Ver Arquivo Fonte | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+U | \n"
+#~ " Alt+U | \n"
#~ " Ferramenta Recorte PCB | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+1 | \n"
+#~ " Alt+1 | \n"
#~ " Habilita todos os Gráficos | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+2 | \n"
+#~ " Alt+2 | \n"
#~ " Desabilita todos os Gráficos | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+3 | \n"
+#~ " Alt+3 | \n"
#~ " Desabilita todos os Gráficos não "
#~ "selecionados | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+F10 | \n"
+#~ " Alt+F10 | \n"
#~ " Alterna Tela Cheia | \n"
#~ "
\n"
#~ " \n"
@@ -18283,11 +18283,11 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Skew shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Skew shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -18295,15 +18295,15 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Editor Transformation Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+X | \n"
+#~ " Alt+X | \n"
#~ " Offset shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Y | \n"
+#~ " Alt+Y | \n"
#~ " Offset shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -18311,15 +18311,15 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Measurement Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+X | \n"
+#~ " Ctrl+X | \n"
#~ " Polygon Cut Tool | \n"
#~ "
\n"
#~ " \n"
@@ -18411,7 +18411,7 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " | Abort and return to Select | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
@@ -18499,11 +18499,11 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " Abort and return to Select | \n"
#~ " \n"
#~ " \n"
-#~ " | CTRL+E | \n"
+#~ " Ctrl+E | \n"
#~ " Eraser Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
@@ -18511,15 +18511,15 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+A | \n"
+#~ " Alt+A | \n"
#~ " Mark Area Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Poligonize Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Transformation Tool | \n"
#~ "
\n"
#~ " \n"
@@ -18620,11 +18620,11 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Inclina a forma no eixo X | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Inclina a forma no eixo Y | \n"
#~ "
\n"
#~ " \n"
@@ -18632,16 +18632,16 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Ferramenta Editor de Transformação"
#~ "td>\n"
#~ " |
\n"
#~ " \n"
-#~ " | ALT+X | \n"
+#~ " Alt+X | \n"
#~ " Desloca a forma no eixo X | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Y | \n"
+#~ " Alt+Y | \n"
#~ " Desloca a forma no eixo Y | \n"
#~ "
\n"
#~ " \n"
@@ -18649,15 +18649,15 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Ferramenta de Medição | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Salvar Objeto e Sair do Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+X | \n"
+#~ " Ctrl+X | \n"
#~ " Ferramenta de Corte de Polígono | \n"
#~ "
\n"
#~ " \n"
@@ -18754,7 +18754,7 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " | Abortar e retornar para a Seleção | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Salvar Objeto e Sair do Editor | \n"
#~ "
\n"
#~ " \n"
@@ -18843,11 +18843,11 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " Abortar e retornar para a Seleção | \n"
#~ " \n"
#~ " \n"
-#~ " | CTRL+E | \n"
+#~ " Ctrl+E | \n"
#~ " Ferramenta Apagador | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Salvar Objeto e Sair do Editor | \n"
#~ "
\n"
#~ " \n"
@@ -18855,15 +18855,15 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+A | \n"
+#~ " Alt+A | \n"
#~ " Ferramenta Marcar Área | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Ferramenta Poligonizar | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Ferramenta Transformação | \n"
#~ "
\n"
#~ " \n"
diff --git a/locale/ro/LC_MESSAGES/strings.po b/locale/ro/LC_MESSAGES/strings.po
index 214423d2..c357e24a 100644
--- a/locale/ro/LC_MESSAGES/strings.po
+++ b/locale/ro/LC_MESSAGES/strings.po
@@ -5275,8 +5275,8 @@ msgid "File"
msgstr "Fişiere"
#: flatcamGUI/FlatCAMGUI.py:69
-msgid "&New Project ...\tCTRL+N"
-msgstr "&Proiect Nou...\tCTRL+N"
+msgid "&New Project ...\tCtrl+N"
+msgstr "&Proiect Nou...\tCtrl+N"
#: flatcamGUI/FlatCAMGUI.py:71
msgid "Will create a new, blank project"
@@ -5328,12 +5328,12 @@ msgid "Open &Project ..."
msgstr "Încarcă &Project ..."
#: flatcamGUI/FlatCAMGUI.py:109 flatcamGUI/FlatCAMGUI.py:4121
-msgid "Open &Gerber ...\tCTRL+G"
-msgstr "Încarcă &Gerber ...\tCTRL+G"
+msgid "Open &Gerber ...\tCtrl+G"
+msgstr "Încarcă &Gerber ...\tCtrl+G"
#: flatcamGUI/FlatCAMGUI.py:114 flatcamGUI/FlatCAMGUI.py:4126
-msgid "Open &Excellon ...\tCTRL+E"
-msgstr "Încarcă &Excellon ...\tCTRL+E"
+msgid "Open &Excellon ...\tCtrl+E"
+msgstr "Încarcă &Excellon ...\tCtrl+E"
#: flatcamGUI/FlatCAMGUI.py:118 flatcamGUI/FlatCAMGUI.py:4131
msgid "Open G-&Code ..."
@@ -5484,8 +5484,8 @@ msgid "&Save Project ..."
msgstr "&Salvează Proiect ..."
#: flatcamGUI/FlatCAMGUI.py:256
-msgid "Save Project &As ...\tCTRL+S"
-msgstr "Salvează Proiect &ca ...\tCTRL+S"
+msgid "Save Project &As ...\tCtrl+S"
+msgstr "Salvează Proiect &ca ...\tCtrl+S"
#: flatcamGUI/FlatCAMGUI.py:261
msgid "Save Project C&opy ..."
@@ -5505,8 +5505,8 @@ msgid "Edit Object\tE"
msgstr "Editare Obiect\tE"
#: flatcamGUI/FlatCAMGUI.py:285
-msgid "Close Editor\tCTRL+S"
-msgstr "Salvează Editor\tCTRL+S"
+msgid "Close Editor\tCtrl+S"
+msgstr "Salvează Editor\tCtrl+S"
#: flatcamGUI/FlatCAMGUI.py:294
msgid "Conversion"
@@ -5582,8 +5582,8 @@ msgid "Convert Any to Gerber"
msgstr "Converteste Oricare in Gerber"
#: flatcamGUI/FlatCAMGUI.py:341
-msgid "&Copy\tCTRL+C"
-msgstr "&Copiază\tCTRL+C"
+msgid "&Copy\tCtrl+C"
+msgstr "&Copiază\tCtrl+C"
#: flatcamGUI/FlatCAMGUI.py:346
msgid "&Delete\tDEL"
@@ -5602,28 +5602,28 @@ msgid "Toggle Units\tQ"
msgstr "Comută Unitati\tQ"
#: flatcamGUI/FlatCAMGUI.py:360
-msgid "&Select All\tCTRL+A"
-msgstr "&Selectează Tot\tCTRL+A"
+msgid "&Select All\tCtrl+A"
+msgstr "&Selectează Tot\tCtrl+A"
#: flatcamGUI/FlatCAMGUI.py:365
-msgid "&Preferences\tSHIFT+P"
-msgstr "&Preferințe\tSHIFT+P"
+msgid "&Preferences\tShift+P"
+msgstr "&Preferințe\tShift+P"
#: flatcamGUI/FlatCAMGUI.py:371 flatcamTools/ToolProperties.py:153
msgid "Options"
msgstr "Opțiuni"
#: flatcamGUI/FlatCAMGUI.py:373
-msgid "&Rotate Selection\tSHIFT+(R)"
-msgstr "&Roteste Selectia\tSHIFT+(R)"
+msgid "&Rotate Selection\tShift+(R)"
+msgstr "&Roteste Selectia\tShift+(R)"
#: flatcamGUI/FlatCAMGUI.py:378
-msgid "&Skew on X axis\tSHIFT+X"
-msgstr "&Deformează pe axa X\tSHIFT+X"
+msgid "&Skew on X axis\tShift+X"
+msgstr "&Deformează pe axa X\tShift+X"
#: flatcamGUI/FlatCAMGUI.py:380
-msgid "S&kew on Y axis\tSHIFT+Y"
-msgstr "Deformează pe axa Y\tSHIFT+Y"
+msgid "S&kew on Y axis\tShift+Y"
+msgstr "Deformează pe axa Y\tShift+Y"
#: flatcamGUI/FlatCAMGUI.py:385
msgid "Flip on &X axis\tX"
@@ -5634,28 +5634,28 @@ msgid "Flip on &Y axis\tY"
msgstr "Oglindește pe axa &Y\tY"
#: flatcamGUI/FlatCAMGUI.py:392
-msgid "View source\tALT+S"
-msgstr "Vezi sursa\tALT+S"
+msgid "View source\tAlt+S"
+msgstr "Vezi sursa\tAlt+S"
#: flatcamGUI/FlatCAMGUI.py:394
-msgid "Tools DataBase\tCTRL+D"
-msgstr "Baza de data Unelte\tCTRL+D"
+msgid "Tools DataBase\tCtrl+D"
+msgstr "Baza de data Unelte\tCtrl+D"
#: flatcamGUI/FlatCAMGUI.py:401 flatcamGUI/FlatCAMGUI.py:2060
msgid "View"
msgstr "Vizualizare"
#: flatcamGUI/FlatCAMGUI.py:403
-msgid "Enable all plots\tALT+1"
-msgstr "Activează toate afişările\tALT+1"
+msgid "Enable all plots\tAlt+1"
+msgstr "Activează toate afişările\tAlt+1"
#: flatcamGUI/FlatCAMGUI.py:405
-msgid "Disable all plots\tALT+2"
-msgstr "Dezactivează toate afişările\tALT+2"
+msgid "Disable all plots\tAlt+2"
+msgstr "Dezactivează toate afişările\tAlt+2"
#: flatcamGUI/FlatCAMGUI.py:407
-msgid "Disable non-selected\tALT+3"
-msgstr "Dezactivează non-selectate\tALT+3"
+msgid "Disable non-selected\tAlt+3"
+msgstr "Dezactivează non-selectate\tAlt+3"
#: flatcamGUI/FlatCAMGUI.py:411
msgid "&Zoom Fit\tV"
@@ -5674,16 +5674,16 @@ msgid "Redraw All\tF5"
msgstr "Reafisare Toate\tF5"
#: flatcamGUI/FlatCAMGUI.py:424
-msgid "Toggle Code Editor\tSHIFT+E"
-msgstr "Comută Editorul de cod\tSHIFT+E"
+msgid "Toggle Code Editor\tShift+E"
+msgstr "Comută Editorul de cod\tShift+E"
#: flatcamGUI/FlatCAMGUI.py:427
-msgid "&Toggle FullScreen\tALT+F10"
-msgstr "Comută FullScreen\tALT+F10"
+msgid "&Toggle FullScreen\tAlt+F10"
+msgstr "Comută FullScreen\tAlt+F10"
#: flatcamGUI/FlatCAMGUI.py:429
-msgid "&Toggle Plot Area\tCTRL+F10"
-msgstr "Comută Aria de Afișare\tCTRL+F10"
+msgid "&Toggle Plot Area\tCtrl+F10"
+msgstr "Comută Aria de Afișare\tCtrl+F10"
#: flatcamGUI/FlatCAMGUI.py:431
msgid "&Toggle Project/Sel/Tool\t`"
@@ -5694,16 +5694,16 @@ msgid "&Toggle Grid Snap\tG"
msgstr "Comută Grid\tG"
#: flatcamGUI/FlatCAMGUI.py:437
-msgid "&Toggle Grid Lines\tALT+G"
-msgstr "Comută Linii Grid\tALT+G"
+msgid "&Toggle Grid Lines\tAlt+G"
+msgstr "Comută Linii Grid\tAlt+G"
#: flatcamGUI/FlatCAMGUI.py:439
-msgid "&Toggle Axis\tSHIFT+G"
-msgstr "Comută Axe\tSHIFT+G"
+msgid "&Toggle Axis\tShift+G"
+msgstr "Comută Axe\tShift+G"
#: flatcamGUI/FlatCAMGUI.py:441
-msgid "Toggle Workspace\tSHIFT+W"
-msgstr "Comută Suprafata de lucru\tSHIFT+W"
+msgid "Toggle Workspace\tShift+W"
+msgstr "Comută Suprafata de lucru\tShift+W"
#: flatcamGUI/FlatCAMGUI.py:446
msgid "Objects"
@@ -5802,8 +5802,8 @@ msgid "Paint Tool\tI"
msgstr "Unealta Paint\tI"
#: flatcamGUI/FlatCAMGUI.py:543
-msgid "Transform Tool\tALT+R"
-msgstr "Unealta Transformare\tALT+R"
+msgid "Transform Tool\tAlt+R"
+msgstr "Unealta Transformare\tAlt+R"
#: flatcamGUI/FlatCAMGUI.py:547
msgid "Toggle Corner Snap\tK"
@@ -5866,8 +5866,8 @@ msgid "Add Region\tN"
msgstr "Adaugă Regiune\tN"
#: flatcamGUI/FlatCAMGUI.py:598
-msgid "Poligonize\tALT+N"
-msgstr "Poligonizare\tALT+N"
+msgid "Poligonize\tAlt+N"
+msgstr "Poligonizare\tAlt+N"
#: flatcamGUI/FlatCAMGUI.py:600
msgid "Add SemiDisc\tE"
@@ -5886,16 +5886,16 @@ msgid "Scale\tS"
msgstr "Scalare\tS"
#: flatcamGUI/FlatCAMGUI.py:608
-msgid "Mark Area\tALT+A"
-msgstr "Marchează aria\tALT+A"
+msgid "Mark Area\tAlt+A"
+msgstr "Marchează aria\tAlt+A"
#: flatcamGUI/FlatCAMGUI.py:610
-msgid "Eraser\tCTRL+E"
-msgstr "Radieră\tCTRL+E"
+msgid "Eraser\tCtrl+E"
+msgstr "Radieră\tCtrl+E"
#: flatcamGUI/FlatCAMGUI.py:612
-msgid "Transform\tALT+R"
-msgstr "Unealta Transformare\tALT+R"
+msgid "Transform\tAlt+R"
+msgstr "Unealta Transformare\tAlt+R"
#: flatcamGUI/FlatCAMGUI.py:639
msgid "Enable Plot"
@@ -14024,7 +14024,7 @@ msgid ""
"\n"
"The coordinates set can be obtained:\n"
"- press SHIFT key and left mouse clicking on canvas. Then click Add.\n"
-"- press SHIFT key and left mouse clicking on canvas. Then CTRL+V in the "
+"- press SHIFT key and left mouse clicking on canvas. Then Ctrl+V in the "
"field.\n"
"- press SHIFT key and left mouse clicking on canvas. Then RMB click in the "
"field and click Paste.\n"
@@ -17836,8 +17836,8 @@ msgstr ""
#~ "\n"
#~ " "
-#~ msgid "Run Script ...\tSHIFT+S"
-#~ msgstr "Rulează Script ...\tSHIFT+S"
+#~ msgid "Run Script ...\tShift+S"
+#~ msgstr "Rulează Script ...\tShift+S"
#~ msgid ""
#~ "FlatCAM
Version {version} {beta} ({date}) - "
@@ -18010,39 +18010,39 @@ msgstr ""
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | CTRL+A | \n"
+#~ " Ctrl+A | \n"
#~ " Select All | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+C | \n"
+#~ " Ctrl+C | \n"
#~ " Copy Obj | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+E | \n"
+#~ " Ctrl+E | \n"
#~ " Open Excellon File | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+G | \n"
+#~ " Ctrl+G | \n"
#~ " Open Gerber File | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+N | \n"
+#~ " Ctrl+N | \n"
#~ " New Project | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Measurement Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+O | \n"
+#~ " Ctrl+O | \n"
#~ " Open Project | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Project As | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+F10 | \n"
+#~ " Ctrl+F10 | \n"
#~ " Toggle Plot Area | \n"
#~ "
\n"
#~ " \n"
@@ -18050,39 +18050,39 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+C | \n"
+#~ " Shift+C | \n"
#~ " Copy Obj_Name | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+E | \n"
+#~ " Shift+E | \n"
#~ " Toggle Code Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+G | \n"
+#~ " Shift+G | \n"
#~ " Toggle the axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+P | \n"
+#~ " Shift+P | \n"
#~ " Open Preferences Window | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+R | \n"
+#~ " Shift+R | \n"
#~ " Rotate by 90 degree CCW | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+S | \n"
+#~ " Shift+S | \n"
#~ " Run a Script | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+W | \n"
+#~ " Shift+W | \n"
#~ " Toggle the workspace | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Skew on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Skew on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -18090,59 +18090,59 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+C | \n"
+#~ " Alt+C | \n"
#~ " Calculators Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+D | \n"
+#~ " Alt+D | \n"
#~ " 2-Sided PCB Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+K | \n"
+#~ " Alt+K | \n"
#~ " Solder Paste Dispensing Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+L | \n"
+#~ " Alt+L | \n"
#~ " Film PCB Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Non-Copper Clearing Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+P | \n"
+#~ " Alt+P | \n"
#~ " Paint Area Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Q | \n"
+#~ " Alt+Q | \n"
#~ " PDF Import Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Transformations Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+S | \n"
+#~ " Alt+S | \n"
#~ " View File Source | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+U | \n"
+#~ " Alt+U | \n"
#~ " Cutout PCB Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+1 | \n"
+#~ " Alt+1 | \n"
#~ " Enable all Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+2 | \n"
+#~ " Alt+2 | \n"
#~ " Disable all Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+3 | \n"
+#~ " Alt+3 | \n"
#~ " Disable Non-selected Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+F10 | \n"
+#~ " Alt+F10 | \n"
#~ " Toggle Full Screen | \n"
#~ "
\n"
#~ " \n"
@@ -18150,7 +18150,7 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+ALT+X"
+#~ " | Ctrl+Alt+X"
#~ "td>\n"
#~ " | Abort current task (gracefully) | \n"
#~ "
\n"
@@ -18304,39 +18304,39 @@ msgstr ""
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | CTRL+A | \n"
+#~ " Ctrl+A | \n"
#~ " Selectează Tot | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+C | \n"
+#~ " Ctrl+C | \n"
#~ " Copiază Obiect | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+E | \n"
+#~ " Ctrl+E | \n"
#~ " Deschide fişier Excellon | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+G | \n"
+#~ " Ctrl+G | \n"
#~ " Deschide fişier Gerber | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+N | \n"
+#~ " Ctrl+N | \n"
#~ " Proiect Nou | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Unealta de Masurare | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+O | \n"
+#~ " Ctrl+O | \n"
#~ " Deschide Proiect | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Salvează Proiect ca | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+F10 | \n"
+#~ " Ctrl+F10 | \n"
#~ " Comută Aria de Afișare | \n"
#~ "
\n"
#~ " \n"
@@ -18344,39 +18344,39 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+C | \n"
+#~ " Shift+C | \n"
#~ " Copiază Nume Obiect | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+E | \n"
+#~ " Shift+E | \n"
#~ " Comută Editor Cod | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+G | \n"
+#~ " Shift+G | \n"
#~ " Comută Axele | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+P | \n"
+#~ " Shift+P | \n"
#~ " Deschide Preferințe | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+R | \n"
+#~ " Shift+R | \n"
#~ " Rotește cu 90 grade CCW | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+S | \n"
+#~ " Shift+S | \n"
#~ " Rulează un Script | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+W | \n"
+#~ " Shift+W | \n"
#~ " Comută Spatiul de Lucru | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Deformează pe axa X | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Deformează pe axa Y | \n"
#~ "
\n"
#~ " \n"
@@ -18384,60 +18384,60 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+C | \n"
+#~ " Alt+C | \n"
#~ " Unealta Calculatoare | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+D | \n"
+#~ " Alt+D | \n"
#~ " Unealta 2-Layer | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+K | \n"
+#~ " Alt+K | \n"
#~ " Unealta Dispensare Pasta Fludor | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+L | \n"
+#~ " Alt+L | \n"
#~ " Unealta Film PCB | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Unealta de curățare zone cupru | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+P | \n"
+#~ " Alt+P | \n"
#~ " Unealta Paint | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Q | \n"
+#~ " Alt+Q | \n"
#~ " Unealta de import PDF | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Unealta Transformări | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+S | \n"
+#~ " Alt+S | \n"
#~ " Vizualiz. Codul Sursa | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+U | \n"
+#~ " Alt+U | \n"
#~ " Unealta de Decupare | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+1 | \n"
+#~ " Alt+1 | \n"
#~ " Activează toate Afișările | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+2 | \n"
+#~ " Alt+2 | \n"
#~ " Dezactivează toate afişările/td>\n"
#~ " |
\n"
#~ " \n"
-#~ " | ALT+3 | \n"
+#~ " Alt+3 | \n"
#~ " Dezactivează toate afişările "
#~ "neselectate | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+F10 | \n"
+#~ " Alt+F10 | \n"
#~ " Comută Full Screen | \n"
#~ "
\n"
#~ " \n"
@@ -18445,7 +18445,7 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+ALT+X"
+#~ " | Ctrl+Alt+X"
#~ "td>\n"
#~ " | Anuleaza taskul curent | \n"
#~ "
\n"
@@ -18580,11 +18580,11 @@ msgstr ""
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Skew shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Skew shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -18592,15 +18592,15 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Editor Transformation Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+X | \n"
+#~ " Alt+X | \n"
#~ " Offset shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Y | \n"
+#~ " Alt+Y | \n"
#~ " Offset shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -18608,15 +18608,15 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Measurement Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+X | \n"
+#~ " Ctrl+X | \n"
#~ " Polygon Cut Tool | \n"
#~ "
\n"
#~ " \n"
@@ -18708,7 +18708,7 @@ msgstr ""
#~ " | Abort and return to Select | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
@@ -18796,11 +18796,11 @@ msgstr ""
#~ " Abort and return to Select | \n"
#~ " \n"
#~ " \n"
-#~ " | CTRL+E | \n"
+#~ " Ctrl+E | \n"
#~ " Eraser Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
@@ -18808,15 +18808,15 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+A | \n"
+#~ " Alt+A | \n"
#~ " Mark Area Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Poligonize Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Transformation Tool | \n"
#~ "
\n"
#~ " \n"
@@ -18915,11 +18915,11 @@ msgstr ""
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Deformeaza pe axa X | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Deformeaza pe axa Y | \n"
#~ "
\n"
#~ " \n"
@@ -18927,15 +18927,15 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Unealta Transformare din Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+X | \n"
+#~ " Alt+X | \n"
#~ " Deplaseaza pe axa X | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Y | \n"
+#~ " Alt+Y | \n"
#~ " Deplaseaza pe axa Y | \n"
#~ "
\n"
#~ " \n"
@@ -18943,15 +18943,15 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Unealta de masurare | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Inchide Editorul | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+X | \n"
+#~ " Ctrl+X | \n"
#~ " Unealta de Decupare Poligoane | \n"
#~ "
\n"
#~ " \n"
@@ -19048,7 +19048,7 @@ msgstr ""
#~ "Selectie\n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Inchide Editorul | \n"
#~ "
\n"
#~ " \n"
@@ -19134,11 +19134,11 @@ msgstr ""
#~ "td>\n"
#~ " \n"
#~ " \n"
-#~ " | CTRL+E | \n"
+#~ " Ctrl+E | \n"
#~ " Unealta Radieră | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Inchide Editorul | \n"
#~ "
\n"
#~ " \n"
@@ -19146,15 +19146,15 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+A | \n"
+#~ " Alt+A | \n"
#~ " Unealta Marcare Arii | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Unealta Poligonizare | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Unealta Transformare | \n"
#~ "
\n"
#~ " \n"
@@ -20087,11 +20087,11 @@ msgstr ""
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Skew shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Skew shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -20099,15 +20099,15 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Editor Transformation Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+X | \n"
+#~ " Alt+X | \n"
#~ " Offset shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Y | \n"
+#~ " Alt+Y | \n"
#~ " Offset shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -20115,15 +20115,15 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Measurement Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+X | \n"
+#~ " Ctrl+X | \n"
#~ " Polygon Cut Tool | \n"
#~ "
\n"
#~ " \n"
@@ -20205,7 +20205,7 @@ msgstr ""
#~ " | Abort and return to Select | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
@@ -20294,11 +20294,11 @@ msgstr ""
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Deformează forma geo pe axa X/td>\n"
#~ " |
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Deformează forma geo pe axa Y | \n"
#~ "
\n"
#~ " \n"
@@ -20306,15 +20306,15 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Unealta de Trasformări din Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+X | \n"
+#~ " Alt+X | \n"
#~ " Deplasează forma geo pe axa X | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Y | \n"
+#~ " Alt+Y | \n"
#~ " Deplasează forma geo pe axa Y | \n"
#~ "
\n"
#~ " \n"
@@ -20322,16 +20322,16 @@ msgstr ""
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Unealta de Masurare | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Salvează obiectul și ieși din Editor"
#~ "td>\n"
#~ " |
\n"
#~ " \n"
-#~ " | CTRL+X | \n"
+#~ " Ctrl+X | \n"
#~ " Unealta de tăiere Poligoane | \n"
#~ "
\n"
#~ " \n"
@@ -20415,7 +20415,7 @@ msgstr ""
#~ " | Renunta și intoarce-te la Select | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Salvează obiectul și ieși din Editor"
#~ "td>\n"
#~ " |
\n"
diff --git a/locale/ru/LC_MESSAGES/strings.po b/locale/ru/LC_MESSAGES/strings.po
index 77055d4e..e56f7930 100644
--- a/locale/ru/LC_MESSAGES/strings.po
+++ b/locale/ru/LC_MESSAGES/strings.po
@@ -5208,8 +5208,8 @@ msgid "File"
msgstr "Файл"
#: flatcamGUI/FlatCAMGUI.py:69
-msgid "&New Project ...\tCTRL+N"
-msgstr "&Новый проект ...\tCTRL+N"
+msgid "&New Project ...\tCtrl+N"
+msgstr "&Новый проект ...\tCtrl+N"
#: flatcamGUI/FlatCAMGUI.py:71
msgid "Will create a new, blank project"
@@ -5261,12 +5261,12 @@ msgid "Open &Project ..."
msgstr "Открыть &проект..."
#: flatcamGUI/FlatCAMGUI.py:109 flatcamGUI/FlatCAMGUI.py:4121
-msgid "Open &Gerber ...\tCTRL+G"
-msgstr "Открыть &Gerber...\tCTRL+G"
+msgid "Open &Gerber ...\tCtrl+G"
+msgstr "Открыть &Gerber...\tCtrl+G"
#: flatcamGUI/FlatCAMGUI.py:114 flatcamGUI/FlatCAMGUI.py:4126
-msgid "Open &Excellon ...\tCTRL+E"
-msgstr "Открыть &Excellon ...\tCTRL+E"
+msgid "Open &Excellon ...\tCtrl+E"
+msgstr "Открыть &Excellon ...\tCtrl+E"
#: flatcamGUI/FlatCAMGUI.py:118 flatcamGUI/FlatCAMGUI.py:4131
msgid "Open G-&Code ..."
@@ -5417,8 +5417,8 @@ msgid "&Save Project ..."
msgstr "&Сохранить проект ..."
#: flatcamGUI/FlatCAMGUI.py:256
-msgid "Save Project &As ...\tCTRL+S"
-msgstr "Сохранить проект &как ...\tCTRL+S"
+msgid "Save Project &As ...\tCtrl+S"
+msgstr "Сохранить проект &как ...\tCtrl+S"
#: flatcamGUI/FlatCAMGUI.py:261
msgid "Save Project C&opy ..."
@@ -5438,8 +5438,8 @@ msgid "Edit Object\tE"
msgstr "Редактировать объект\tE"
#: flatcamGUI/FlatCAMGUI.py:285
-msgid "Close Editor\tCTRL+S"
-msgstr "Закрыть редактор\tCTRL+S"
+msgid "Close Editor\tCtrl+S"
+msgstr "Закрыть редактор\tCtrl+S"
#: flatcamGUI/FlatCAMGUI.py:294
msgid "Conversion"
@@ -5515,8 +5515,8 @@ msgid "Convert Any to Gerber"
msgstr "Конвертировать любой объект в Gerber"
#: flatcamGUI/FlatCAMGUI.py:341
-msgid "&Copy\tCTRL+C"
-msgstr "&Копировать\tCTRL+C"
+msgid "&Copy\tCtrl+C"
+msgstr "&Копировать\tCtrl+C"
#: flatcamGUI/FlatCAMGUI.py:346
msgid "&Delete\tDEL"
@@ -5535,28 +5535,28 @@ msgid "Toggle Units\tQ"
msgstr "Единицы измерения\tQ"
#: flatcamGUI/FlatCAMGUI.py:360
-msgid "&Select All\tCTRL+A"
-msgstr "&Выбрать все\tCTRL+A"
+msgid "&Select All\tCtrl+A"
+msgstr "&Выбрать все\tCtrl+A"
#: flatcamGUI/FlatCAMGUI.py:365
-msgid "&Preferences\tSHIFT+P"
-msgstr "&Настройки\tSHIFT+P"
+msgid "&Preferences\tShift+P"
+msgstr "&Настройки\tShift+P"
#: flatcamGUI/FlatCAMGUI.py:371 flatcamTools/ToolProperties.py:153
msgid "Options"
msgstr "Опции"
#: flatcamGUI/FlatCAMGUI.py:373
-msgid "&Rotate Selection\tSHIFT+(R)"
-msgstr "&Вращение\tSHIFT+(R)"
+msgid "&Rotate Selection\tShift+(R)"
+msgstr "&Вращение\tShift+(R)"
#: flatcamGUI/FlatCAMGUI.py:378
-msgid "&Skew on X axis\tSHIFT+X"
-msgstr "&Наклон по оси X\tSHIFT+X"
+msgid "&Skew on X axis\tShift+X"
+msgstr "&Наклон по оси X\tShift+X"
#: flatcamGUI/FlatCAMGUI.py:380
-msgid "S&kew on Y axis\tSHIFT+Y"
-msgstr "Н&аклон по оси Y\tSHIFT+Y"
+msgid "S&kew on Y axis\tShift+Y"
+msgstr "Н&аклон по оси Y\tShift+Y"
#: flatcamGUI/FlatCAMGUI.py:385
msgid "Flip on &X axis\tX"
@@ -5567,28 +5567,28 @@ msgid "Flip on &Y axis\tY"
msgstr "Отразить по оси &Y\tY"
#: flatcamGUI/FlatCAMGUI.py:392
-msgid "View source\tALT+S"
-msgstr "Просмотреть код\tALT+S"
+msgid "View source\tAlt+S"
+msgstr "Просмотреть код\tAlt+S"
#: flatcamGUI/FlatCAMGUI.py:394
-msgid "Tools DataBase\tCTRL+D"
-msgstr "База данных\tCTRL+D"
+msgid "Tools DataBase\tCtrl+D"
+msgstr "База данных\tCtrl+D"
#: flatcamGUI/FlatCAMGUI.py:401 flatcamGUI/FlatCAMGUI.py:2060
msgid "View"
msgstr "Вид"
#: flatcamGUI/FlatCAMGUI.py:403
-msgid "Enable all plots\tALT+1"
-msgstr "Включить все участки\tALT+1"
+msgid "Enable all plots\tAlt+1"
+msgstr "Включить все участки\tAlt+1"
#: flatcamGUI/FlatCAMGUI.py:405
-msgid "Disable all plots\tALT+2"
-msgstr "Отключить все участки\tALT+2"
+msgid "Disable all plots\tAlt+2"
+msgstr "Отключить все участки\tAlt+2"
#: flatcamGUI/FlatCAMGUI.py:407
-msgid "Disable non-selected\tALT+3"
-msgstr "Отключить не выбранные\tALT+3"
+msgid "Disable non-selected\tAlt+3"
+msgstr "Отключить не выбранные\tAlt+3"
#: flatcamGUI/FlatCAMGUI.py:411
msgid "&Zoom Fit\tV"
@@ -5607,16 +5607,16 @@ msgid "Redraw All\tF5"
msgstr "Перерисовать всё\tF5"
#: flatcamGUI/FlatCAMGUI.py:424
-msgid "Toggle Code Editor\tSHIFT+E"
-msgstr "Переключить редактор кода\tSHIFT+E"
+msgid "Toggle Code Editor\tShift+E"
+msgstr "Переключить редактор кода\tShift+E"
#: flatcamGUI/FlatCAMGUI.py:427
-msgid "&Toggle FullScreen\tALT+F10"
-msgstr "&Во весь экран\tALT+F10"
+msgid "&Toggle FullScreen\tAlt+F10"
+msgstr "&Во весь экран\tAlt+F10"
#: flatcamGUI/FlatCAMGUI.py:429
-msgid "&Toggle Plot Area\tCTRL+F10"
-msgstr "&Рабочая область\tCTRL+F10"
+msgid "&Toggle Plot Area\tCtrl+F10"
+msgstr "&Рабочая область\tCtrl+F10"
#: flatcamGUI/FlatCAMGUI.py:431
msgid "&Toggle Project/Sel/Tool\t`"
@@ -5627,16 +5627,16 @@ msgid "&Toggle Grid Snap\tG"
msgstr "&Привязка к сетке\tG"
#: flatcamGUI/FlatCAMGUI.py:437
-msgid "&Toggle Grid Lines\tALT+G"
-msgstr "&Переключить линии сетки \tALT+G"
+msgid "&Toggle Grid Lines\tAlt+G"
+msgstr "&Переключить линии сетки \tAlt+G"
#: flatcamGUI/FlatCAMGUI.py:439
-msgid "&Toggle Axis\tSHIFT+G"
-msgstr "&Оси\tSHIFT+G"
+msgid "&Toggle Axis\tShift+G"
+msgstr "&Оси\tShift+G"
#: flatcamGUI/FlatCAMGUI.py:441
-msgid "Toggle Workspace\tSHIFT+W"
-msgstr "Границы рабочего пространства\tSHIFT+W"
+msgid "Toggle Workspace\tShift+W"
+msgstr "Границы рабочего пространства\tShift+W"
#: flatcamGUI/FlatCAMGUI.py:446
msgid "Objects"
@@ -5735,8 +5735,8 @@ msgid "Paint Tool\tI"
msgstr "Рисование\tI"
#: flatcamGUI/FlatCAMGUI.py:543
-msgid "Transform Tool\tALT+R"
-msgstr "Трансформация\tALT+R"
+msgid "Transform Tool\tAlt+R"
+msgstr "Трансформация\tAlt+R"
#: flatcamGUI/FlatCAMGUI.py:547
msgid "Toggle Corner Snap\tK"
@@ -5799,8 +5799,8 @@ msgid "Add Region\tN"
msgstr "Добавить регион\tN"
#: flatcamGUI/FlatCAMGUI.py:598
-msgid "Poligonize\tALT+N"
-msgstr "Полигонизация\tALT+N"
+msgid "Poligonize\tAlt+N"
+msgstr "Полигонизация\tAlt+N"
#: flatcamGUI/FlatCAMGUI.py:600
msgid "Add SemiDisc\tE"
@@ -5819,16 +5819,16 @@ msgid "Scale\tS"
msgstr "Масштабировать\tS"
#: flatcamGUI/FlatCAMGUI.py:608
-msgid "Mark Area\tALT+A"
-msgstr "Обозначить области\tALT+A"
+msgid "Mark Area\tAlt+A"
+msgstr "Обозначить области\tAlt+A"
#: flatcamGUI/FlatCAMGUI.py:610
-msgid "Eraser\tCTRL+E"
-msgstr "Ластик\tCTRL+E"
+msgid "Eraser\tCtrl+E"
+msgstr "Ластик\tCtrl+E"
#: flatcamGUI/FlatCAMGUI.py:612
-msgid "Transform\tALT+R"
-msgstr "Трансформировать\tALT+R"
+msgid "Transform\tAlt+R"
+msgstr "Трансформировать\tAlt+R"
#: flatcamGUI/FlatCAMGUI.py:639
msgid "Enable Plot"
@@ -13901,7 +13901,7 @@ msgid ""
"\n"
"The coordinates set can be obtained:\n"
"- press SHIFT key and left mouse clicking on canvas. Then click Add.\n"
-"- press SHIFT key and left mouse clicking on canvas. Then CTRL+V in the "
+"- press SHIFT key and left mouse clicking on canvas. Then Ctrl+V in the "
"field.\n"
"- press SHIFT key and left mouse clicking on canvas. Then RMB click in the "
"field and click Paste.\n"
@@ -17736,8 +17736,8 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ msgid "[success] Paint done."
#~ msgstr "[success] Окраска выполнена."
-#~ msgid "Run Script ...\tSHIFT+S"
-#~ msgstr "Выполнить сценарий ...\tSHIFT+S"
+#~ msgid "Run Script ...\tShift+S"
+#~ msgstr "Выполнить сценарий ...\tShift+S"
#~ msgid "About"
#~ msgstr "О программе"
@@ -17853,39 +17853,39 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | CTRL+A | \n"
+#~ " Ctrl+A | \n"
#~ " Select All | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+C | \n"
+#~ " Ctrl+C | \n"
#~ " Copy Obj | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+E | \n"
+#~ " Ctrl+E | \n"
#~ " Open Excellon File | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+G | \n"
+#~ " Ctrl+G | \n"
#~ " Open Gerber File | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+N | \n"
+#~ " Ctrl+N | \n"
#~ " New Project | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Measurement Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+O | \n"
+#~ " Ctrl+O | \n"
#~ " Open Project | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Project As | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+F10 | \n"
+#~ " Ctrl+F10 | \n"
#~ " Toggle Plot Area | \n"
#~ "
\n"
#~ " \n"
@@ -17893,39 +17893,39 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+C | \n"
+#~ " Shift+C | \n"
#~ " Copy Obj_Name | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+E | \n"
+#~ " Shift+E | \n"
#~ " Toggle Code Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+G | \n"
+#~ " Shift+G | \n"
#~ " Toggle the axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+P | \n"
+#~ " Shift+P | \n"
#~ " Open Preferences Window | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+R | \n"
+#~ " Shift+R | \n"
#~ " Rotate by 90 degree CCW | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+S | \n"
+#~ " Shift+S | \n"
#~ " Run a Script | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+W | \n"
+#~ " Shift+W | \n"
#~ " Toggle the workspace | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Skew on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Skew on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -17933,59 +17933,59 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+C | \n"
+#~ " Alt+C | \n"
#~ " Calculators Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+D | \n"
+#~ " Alt+D | \n"
#~ " 2-Sided PCB Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+K | \n"
+#~ " Alt+K | \n"
#~ " Solder Paste Dispensing Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+L | \n"
+#~ " Alt+L | \n"
#~ " Film PCB Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Non-Copper Clearing Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+P | \n"
+#~ " Alt+P | \n"
#~ " Paint Area Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Q | \n"
+#~ " Alt+Q | \n"
#~ " PDF Import Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Transformations Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+S | \n"
+#~ " Alt+S | \n"
#~ " View File Source | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+U | \n"
+#~ " Alt+U | \n"
#~ " Cutout PCB Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+1 | \n"
+#~ " Alt+1 | \n"
#~ " Enable all Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+2 | \n"
+#~ " Alt+2 | \n"
#~ " Disable all Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+3 | \n"
+#~ " Alt+3 | \n"
#~ " Disable Non-selected Plots | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+F10 | \n"
+#~ " Alt+F10 | \n"
#~ " Toggle Full Screen | \n"
#~ "
\n"
#~ " \n"
@@ -17993,7 +17993,7 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+ALT+X"
+#~ " | Ctrl+Alt+X"
#~ "td>\n"
#~ " | Abort current task (gracefully) | \n"
#~ "
\n"
@@ -18151,39 +18151,39 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | CTRL+A | \n"
+#~ " Ctrl+A | \n"
#~ " Выбрать всё | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+C | \n"
+#~ " Ctrl+C | \n"
#~ " Копировать | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+E | \n"
+#~ " Ctrl+E | \n"
#~ " Открыть Excellon | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+G | \n"
+#~ " Ctrl+G | \n"
#~ " Открыть Gerber | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+N | \n"
+#~ " Ctrl+N | \n"
#~ " Новый проект | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Измеритель | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+O | \n"
+#~ " Ctrl+O | \n"
#~ " Открыть проект | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Сохранить проект как | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+F10 | \n"
+#~ " Ctrl+F10 | \n"
#~ " Переключить рабочую область | \n"
#~ "
\n"
#~ " \n"
@@ -18191,40 +18191,40 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+C | \n"
+#~ " Shift+C | \n"
#~ " Копировать имя объекта | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+E | \n"
+#~ " Shift+E | \n"
#~ " Редактор кода | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+G | \n"
+#~ " Shift+G | \n"
#~ " Оси | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+P | \n"
+#~ " Shift+P | \n"
#~ " Настройки | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+R | \n"
+#~ " Shift+R | \n"
#~ " Поворот на 90 градусов против часовой "
#~ "стрелки | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+S | \n"
+#~ " Shift+S | \n"
#~ " Выполнить сценарий | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+W | \n"
+#~ " Shift+W | \n"
#~ " Границы рабочего пространства | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Наклон по оси X | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Наклон по оси Y | \n"
#~ "
\n"
#~ " \n"
@@ -18232,59 +18232,59 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+C | \n"
+#~ " Alt+C | \n"
#~ " Калькуляторы | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+D | \n"
+#~ " Alt+D | \n"
#~ " 2-х сторонняя плата | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+K | \n"
+#~ " Alt+K | \n"
#~ " Паяльная паста | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+L | \n"
+#~ " Alt+L | \n"
#~ " Плёнка | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Очистка от меди | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+P | \n"
+#~ " Alt+P | \n"
#~ " Область рисования | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Q | \n"
+#~ " Alt+Q | \n"
#~ " Импорт PDF | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Трансформация | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+S | \n"
+#~ " Alt+S | \n"
#~ " Просмотреть код | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+U | \n"
+#~ " Alt+U | \n"
#~ " Обрезка платы | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+1 | \n"
+#~ " Alt+1 | \n"
#~ " Включить все участки | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+2 | \n"
+#~ " Alt+2 | \n"
#~ " Отключить все участки | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+3 | \n"
+#~ " Alt+3 | \n"
#~ " Отключить не выбранные | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+F10 | \n"
+#~ " Alt+F10 | \n"
#~ " Во весь экран | \n"
#~ "
\n"
#~ " \n"
@@ -18418,11 +18418,11 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Skew shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Skew shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -18430,15 +18430,15 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Editor Transformation Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+X | \n"
+#~ " Alt+X | \n"
#~ " Offset shape on X axis | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Y | \n"
+#~ " Alt+Y | \n"
#~ " Offset shape on Y axis | \n"
#~ "
\n"
#~ " \n"
@@ -18446,15 +18446,15 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Measurement Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+X | \n"
+#~ " Ctrl+X | \n"
#~ " Polygon Cut Tool | \n"
#~ "
\n"
#~ " \n"
@@ -18546,7 +18546,7 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " | Abort and return to Select | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
@@ -18634,11 +18634,11 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " Abort and return to Select | \n"
#~ " \n"
#~ " \n"
-#~ " | CTRL+E | \n"
+#~ " Ctrl+E | \n"
#~ " Eraser Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Save Object and Exit Editor | \n"
#~ "
\n"
#~ " \n"
@@ -18646,15 +18646,15 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+A | \n"
+#~ " Alt+A | \n"
#~ " Mark Area Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Poligonize Tool | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Transformation Tool | \n"
#~ "
\n"
#~ " \n"
@@ -18753,11 +18753,11 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | SHIFT+X | \n"
+#~ " Shift+X | \n"
#~ " Наклонить форму по оси X | \n"
#~ "
\n"
#~ " \n"
-#~ " | SHIFT+Y | \n"
+#~ " Shift+Y | \n"
#~ " Наклонить форму по оси Y | \n"
#~ "
\n"
#~ " \n"
@@ -18765,15 +18765,15 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Трансформация | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+X | \n"
+#~ " Alt+X | \n"
#~ " Смещение формы по оси X | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+Y | \n"
+#~ " Alt+Y | \n"
#~ " Смещение формы по оси Y | \n"
#~ "
\n"
#~ " \n"
@@ -18781,16 +18781,16 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " | | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+M | \n"
+#~ " Ctrl+M | \n"
#~ " Измеритель | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Сохранить объект и закрыть редактор"
#~ "td>\n"
#~ " |
\n"
#~ " \n"
-#~ " | CTRL+X | \n"
+#~ " Ctrl+X | \n"
#~ " Обрезка полигонов | \n"
#~ "
\n"
#~ " \n"
@@ -18886,7 +18886,7 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " | Прервать и вернуться к выбору | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Сохранить объект и закрыть редактор"
#~ "td>\n"
#~ " |
\n"
@@ -18976,11 +18976,11 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " Прервать и вернуться к выбору | \n"
#~ " \n"
#~ " \n"
-#~ " | CTRL+E | \n"
+#~ " Ctrl+E | \n"
#~ " Ластик | \n"
#~ "
\n"
#~ " \n"
-#~ " | CTRL+S | \n"
+#~ " Ctrl+S | \n"
#~ " Сохранить объект и закрыть редактор"
#~ "td>\n"
#~ " |
\n"
@@ -18989,15 +18989,15 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ " | \n"
#~ " \n"
#~ " \n"
-#~ " | ALT+A | \n"
+#~ " Alt+A | \n"
#~ " Обозначить области | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+N | \n"
+#~ " Alt+N | \n"
#~ " Полигонизация | \n"
#~ "
\n"
#~ " \n"
-#~ " | ALT+R | \n"
+#~ " Alt+R | \n"
#~ " Трансформация | \n"
#~ "
\n"
#~ " \n"
diff --git a/locale_template/strings.pot b/locale_template/strings.pot
index 50ee46f4..1b9bc7d7 100644
--- a/locale_template/strings.pot
+++ b/locale_template/strings.pot
@@ -4542,7 +4542,7 @@ msgid "File"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:69
-msgid "&New Project ...\tCTRL+N"
+msgid "&New Project ...\tCtrl+N"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:71
@@ -4595,11 +4595,11 @@ msgid "Open &Project ..."
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:109 flatcamGUI/FlatCAMGUI.py:4121
-msgid "Open &Gerber ...\tCTRL+G"
+msgid "Open &Gerber ...\tCtrl+G"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:114 flatcamGUI/FlatCAMGUI.py:4126
-msgid "Open &Excellon ...\tCTRL+E"
+msgid "Open &Excellon ...\tCtrl+E"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:118 flatcamGUI/FlatCAMGUI.py:4131
@@ -4736,7 +4736,7 @@ msgid "&Save Project ..."
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:256
-msgid "Save Project &As ...\tCTRL+S"
+msgid "Save Project &As ...\tCtrl+S"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:261
@@ -4756,7 +4756,7 @@ msgid "Edit Object\tE"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:285
-msgid "Close Editor\tCTRL+S"
+msgid "Close Editor\tCtrl+S"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:294
@@ -4821,7 +4821,7 @@ msgid "Convert Any to Gerber"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:341
-msgid "&Copy\tCTRL+C"
+msgid "&Copy\tCtrl+C"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:346
@@ -4841,11 +4841,11 @@ msgid "Toggle Units\tQ"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:360
-msgid "&Select All\tCTRL+A"
+msgid "&Select All\tCtrl+A"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:365
-msgid "&Preferences\tSHIFT+P"
+msgid "&Preferences\tShift+P"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:371 flatcamTools/ToolProperties.py:153
@@ -4853,15 +4853,15 @@ msgid "Options"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:373
-msgid "&Rotate Selection\tSHIFT+(R)"
+msgid "&Rotate Selection\tShift+(R)"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:378
-msgid "&Skew on X axis\tSHIFT+X"
+msgid "&Skew on X axis\tShift+X"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:380
-msgid "S&kew on Y axis\tSHIFT+Y"
+msgid "S&kew on Y axis\tShift+Y"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:385
@@ -4873,11 +4873,11 @@ msgid "Flip on &Y axis\tY"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:392
-msgid "View source\tALT+S"
+msgid "View source\tAlt+S"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:394
-msgid "Tools DataBase\tCTRL+D"
+msgid "Tools DataBase\tCtrl+D"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:401 flatcamGUI/FlatCAMGUI.py:2060
@@ -4885,15 +4885,15 @@ msgid "View"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:403
-msgid "Enable all plots\tALT+1"
+msgid "Enable all plots\tAlt+1"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:405
-msgid "Disable all plots\tALT+2"
+msgid "Disable all plots\tAlt+2"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:407
-msgid "Disable non-selected\tALT+3"
+msgid "Disable non-selected\tAlt+3"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:411
@@ -4913,15 +4913,15 @@ msgid "Redraw All\tF5"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:424
-msgid "Toggle Code Editor\tSHIFT+E"
+msgid "Toggle Code Editor\tShift+E"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:427
-msgid "&Toggle FullScreen\tALT+F10"
+msgid "&Toggle FullScreen\tAlt+F10"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:429
-msgid "&Toggle Plot Area\tCTRL+F10"
+msgid "&Toggle Plot Area\tCtrl+F10"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:431
@@ -4933,15 +4933,15 @@ msgid "&Toggle Grid Snap\tG"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:437
-msgid "&Toggle Grid Lines\tALT+G"
+msgid "&Toggle Grid Lines\tAlt+G"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:439
-msgid "&Toggle Axis\tSHIFT+G"
+msgid "&Toggle Axis\tShift+G"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:441
-msgid "Toggle Workspace\tSHIFT+W"
+msgid "Toggle Workspace\tShift+W"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:446
@@ -5041,7 +5041,7 @@ msgid "Paint Tool\tI"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:543
-msgid "Transform Tool\tALT+R"
+msgid "Transform Tool\tAlt+R"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:547
@@ -5105,7 +5105,7 @@ msgid "Add Region\tN"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:598
-msgid "Poligonize\tALT+N"
+msgid "Poligonize\tAlt+N"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:600
@@ -5125,15 +5125,15 @@ msgid "Scale\tS"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:608
-msgid "Mark Area\tALT+A"
+msgid "Mark Area\tAlt+A"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:610
-msgid "Eraser\tCTRL+E"
+msgid "Eraser\tCtrl+E"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:612
-msgid "Transform\tALT+R"
+msgid "Transform\tAlt+R"
msgstr ""
#: flatcamGUI/FlatCAMGUI.py:639
@@ -11925,7 +11925,7 @@ msgid ""
"\n"
"The coordinates set can be obtained:\n"
"- press SHIFT key and left mouse clicking on canvas. Then click Add.\n"
-"- press SHIFT key and left mouse clicking on canvas. Then CTRL+V in the field.\n"
+"- press SHIFT key and left mouse clicking on canvas. Then Ctrl+V in the field.\n"
"- press SHIFT key and left mouse clicking on canvas. Then RMB click in the field and "
"click Paste.\n"
"- by entering the coords manually in the format: (x1, y1), (x2, y2), ..."
From 13644187e44b79976a0a11722d58becd35431238 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Thu, 9 Apr 2020 22:40:43 +0300
Subject: [PATCH 163/209] - removed some packages from setup_ubuntu.sh as they
are not needed in FlatCAM beta
---
README.md | 5 +++--
setup_ubuntu.sh | 6 +++---
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 1aeb53f8..b33cb69b 100644
--- a/README.md
+++ b/README.md
@@ -9,12 +9,13 @@ CAD program, and create G-Code for Isolation routing.
=================================================
-10.04.2020
+9.04.2020
- if FlatCAM is not run with Python version >= 3.5 it will exit.
- modified all CTRL+ with Ctrl+ and all ALT+ with Alt+ and all SHIFT+ with Shift+. Fixed issue #387.
+- removed some packages from setup_ubuntu.sh as they are not needed in FlatCAM beta
-9.4.2020
+8.4.2020
- fixed the Tcl Command Delete to have an argument -f that will force deletion evading the popup (if the popup is enabled). The sme command without a name now will delete all objects
- fixed the Tcl Command JoinExcellons
diff --git a/setup_ubuntu.sh b/setup_ubuntu.sh
index 9054a57c..50da3fdf 100644
--- a/setup_ubuntu.sh
+++ b/setup_ubuntu.sh
@@ -1,9 +1,9 @@
#!/bin/bash
sudo apt install --reinstall libpng-dev libfreetype6 libfreetype6-dev libgeos-dev libspatialindex-dev
sudo apt install --reinstall python3-dev python3-pyqt5 python3-pyqt5.qtopengl python3-gdal python3-simplejson
-sudo apt install --reinstall python3-pip python3-tk python3-imaging
+sudo apt install --reinstall python3-pip python3-tk
-sudo python3 -m pip install --upgrade pyqt5==5.12
-sudo python3 -m pip install --upgrade pip numpy scipy shapely rtree tk lxml cycler python-dateutil kiwisolver dill
+sudo python3 -m pip install --upgrade pyqt5
+sudo python3 -m pip install --upgrade pip numpy shapely rtree tk lxml cycler python-dateutil kiwisolver dill
sudo python3 -m pip install --upgrade vispy pyopengl setuptools svg.path ortools freetype-py fontTools rasterio ezdxf
sudo python3 -m pip install --upgrade matplotlib qrcode reportlab svglib
\ No newline at end of file
From 496be49027a03ae10d999a59709546e4b1511f6b Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Fri, 10 Apr 2020 18:54:04 +0300
Subject: [PATCH 164/209] - made sure that the timeout parameter used by some
Tcl Commands is seen as an integer in all cases - minor changes in Paint Tool
---
README.md | 6 ++++++
flatcamTools/ToolPaint.py | 25 +++++++++++--------------
tclCommands/TclCommand.py | 3 ++-
3 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/README.md b/README.md
index b33cb69b..a85ea37d 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,12 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+10.04.2020
+
+- made sure that the timeout parameter used by some Tcl Commands is seen as an integer in all cases
+- minor changes in Paint Tool
+
+
9.04.2020
- if FlatCAM is not run with Python version >= 3.5 it will exit.
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 842b6c56..9e955766 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -12,12 +12,11 @@ from FlatCAMTool import FlatCAMTool
from copy import deepcopy
# from ObjectCollection import *
from flatcamParsers.ParseGerber import Gerber
-from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry
from camlib import Geometry, FlatCAMRTreeStorage
from flatcamGUI.GUIElements import FCTable, FCDoubleSpinner, FCCheckBox, FCInputDialog, RadioSet, FCButton, FCComboBox
import FlatCAMApp
-from shapely.geometry import base, Polygon, MultiPolygon, LinearRing, Point, MultiLineString
+from shapely.geometry import base, Polygon, MultiPolygon, LinearRing, Point
from shapely.ops import cascaded_union, unary_union, linemerge
from matplotlib.backend_bases import KeyEvent as mpl_key_event
@@ -2075,7 +2074,7 @@ class ToolPaint(FlatCAMTool, Gerber):
:return: None
"""
- if isinstance(obj, FlatCAMGerber):
+ if obj.kind == 'gerber':
# I don't do anything here, like buffering when the Gerber is loaded without buffering????!!!!
if self.app.defaults["gerber_buffering"] == 'no':
self.app.inform.emit('%s %s %s' %
@@ -2417,7 +2416,7 @@ class ToolPaint(FlatCAMTool, Gerber):
# "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
log.debug("Paint Tool. Normal painting all task started.")
- if isinstance(obj, FlatCAMGerber):
+ if obj.kind == 'gerber':
if app_obj.defaults["gerber_buffering"] == 'no':
app_obj.inform.emit('%s %s' %
(_("Paint Tool. Normal painting all task started."),
@@ -2435,7 +2434,7 @@ class ToolPaint(FlatCAMTool, Gerber):
else:
pass
- if isinstance(obj, FlatCAMGerber):
+ if obj.kind == 'gerber':
if self.app.defaults["tools_paint_plotting"] == 'progressive':
if isinstance(obj.solid_geometry, list):
obj.solid_geometry = MultiPolygon(obj.solid_geometry).buffer(0)
@@ -2629,7 +2628,7 @@ class ToolPaint(FlatCAMTool, Gerber):
# "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
log.debug("Paint Tool. Rest machining painting all task started.")
- if isinstance(obj, FlatCAMGerber):
+ if obj.kind == 'gerber':
if app_obj.defaults["gerber_buffering"] == 'no':
app_obj.inform.emit('%s %s %s' %
(_("Paint Tool."), _("Rest machining painting all task started."),
@@ -2644,7 +2643,7 @@ class ToolPaint(FlatCAMTool, Gerber):
tool_dia = None
sorted_tools.sort(reverse=True)
- if isinstance(obj, FlatCAMGerber):
+ if obj.kind == 'gerber':
if self.app.defaults["tools_paint_plotting"] == 'progressive':
if isinstance(obj.solid_geometry, list):
obj.solid_geometry = MultiPolygon(obj.solid_geometry).buffer(0)
@@ -3079,7 +3078,7 @@ class ToolPaint(FlatCAMTool, Gerber):
# "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
log.debug("Paint Tool. Normal painting area task started.")
- if isinstance(obj, FlatCAMGerber):
+ if obj.kind == 'gerber':
if app_obj.defaults["gerber_buffering"] == 'no':
app_obj.inform.emit('%s %s' %
(_("Paint Tool. Normal painting area task started."),
@@ -3100,14 +3099,13 @@ class ToolPaint(FlatCAMTool, Gerber):
# this is were heavy lifting is done and creating the geometry to be painted
target_geo = MultiPolygon(obj.solid_geometry)
- if isinstance(obj, FlatCAMGerber):
+ if obj.kind == 'gerber':
if self.app.defaults["tools_paint_plotting"] == 'progressive':
if isinstance(target_geo, list):
target_geo = MultiPolygon(target_geo).buffer(0)
else:
target_geo = target_geo.buffer(0)
-
geo_to_paint = target_geo.intersection(sel_obj)
painted_area = recurse(geo_to_paint)
@@ -3444,7 +3442,7 @@ class ToolPaint(FlatCAMTool, Gerber):
# "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
log.debug("Paint Tool. Rest machining painting area task started.")
- if isinstance(obj, FlatCAMGerber):
+ if obj.kind == 'gerber':
if app_obj.defaults["gerber_buffering"] == 'no':
app_obj.inform.emit('%s %s %s' %
(_("Paint Tool."), _("Rest machining painting area task started."),
@@ -3468,7 +3466,7 @@ class ToolPaint(FlatCAMTool, Gerber):
# this is were heavy lifting is done and creating the geometry to be painted
target_geo = obj.solid_geometry
- if isinstance(obj, FlatCAMGerber):
+ if obj.kind == 'gerber':
if self.app.defaults["tools_paint_plotting"] == 'progressive':
if isinstance(target_geo, list):
target_geo = MultiPolygon(target_geo).buffer(0)
@@ -3533,7 +3531,6 @@ class ToolPaint(FlatCAMTool, Gerber):
pol_nr = 0
-
for geo in poly_buf:
try:
cp = None
@@ -3952,7 +3949,7 @@ class ToolPaint(FlatCAMTool, Gerber):
for row in range(self.tools_table.rowCount()):
for col in [2, 4]:
try:
- self.ui.geo_tools_table.cellWidget(row, col).currentIndexChanged.disconnect()
+ self.tools_table.cellWidget(row, col).currentIndexChanged.disconnect()
except (TypeError, AttributeError):
pass
diff --git a/tclCommands/TclCommand.py b/tclCommands/TclCommand.py
index fd3058c9..0e5e6bab 100644
--- a/tclCommands/TclCommand.py
+++ b/tclCommands/TclCommand.py
@@ -387,7 +387,8 @@ class TclCommandSignaled(TclCommand):
# Terminate on timeout
if timeout is not None:
- QtCore.QTimer.singleShot(timeout, report_quit)
+ time_val = int(timeout)
+ QtCore.QTimer.singleShot(time_val, report_quit)
# Block
loop.exec_()
From 418ebd66062648a7e681c4a513c6822d888ea3bf Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 11 Apr 2020 01:51:43 +0300
Subject: [PATCH 165/209] - minor changes in GUI (Save locations in Menu ->
File) and the key shortcuts
---
FlatCAMApp.py | 2 +-
README.md | 1 +
flatcamGUI/FlatCAMGUI.py | 68 ++++++++++++++++++++++++----------------
3 files changed, 43 insertions(+), 28 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 6f6d0919..ef6c9357 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -2016,7 +2016,7 @@ class App(QtCore.QObject):
self.ui.menufilesaveproject.triggered.connect(self.on_file_saveproject)
self.ui.menufilesaveprojectas.triggered.connect(self.on_file_saveprojectas)
- self.ui.menufilesaveprojectcopy.triggered.connect(lambda: self.on_file_saveprojectas(make_copy=True))
+ # self.ui.menufilesaveprojectcopy.triggered.connect(lambda: self.on_file_saveprojectas(make_copy=True))
self.ui.menufilesavedefaults.triggered.connect(self.on_file_savedefaults)
self.ui.menufileexportpref.triggered.connect(self.on_export_preferences)
diff --git a/README.md b/README.md
index a85ea37d..6bcade76 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- made sure that the timeout parameter used by some Tcl Commands is seen as an integer in all cases
- minor changes in Paint Tool
+- minor changes in GUI (Save locations in Menu -> File) and the key shortcuts
9.04.2020
diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py
index 09bdb939..0401b164 100644
--- a/flatcamGUI/FlatCAMGUI.py
+++ b/flatcamGUI/FlatCAMGUI.py
@@ -51,7 +51,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# ######### ##
self.menu = self.menuBar()
- self.menu_toggle_nb = QtWidgets.QAction(QtGui.QIcon(self.app.resource_location + '/notebook32.png'), _("Toggle Panel"))
+ self.menu_toggle_nb = QtWidgets.QAction(
+ QtGui.QIcon(self.app.resource_location + '/notebook32.png'), _("Toggle Panel"))
self.menu_toggle_nb.setToolTip(
_("Toggle Panel")
)
@@ -139,6 +140,26 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.recent = self.menufile.addMenu(
QtGui.QIcon(self.app.resource_location + '/recent_files.png'), _("Recent files"))
+ # SAVE category
+ self.menufile_save = self.menufile.addMenu(QtGui.QIcon(self.app.resource_location + '/save_as.png'), _('Save'))
+
+ # Save Project
+ self.menufilesaveproject = QtWidgets.QAction(
+ QtGui.QIcon(self.app.resource_location + '/floppy16.png'), _('&Save Project ...\tCtrl+S'), self)
+ self.menufile_save.addAction(self.menufilesaveproject)
+
+ # Save Project As ...
+ self.menufilesaveprojectas = QtWidgets.QAction(
+ QtGui.QIcon(self.app.resource_location + '/floppy16.png'), _('Save Project &As ...\tCtrl+Shift+S'), self)
+ self.menufile_save.addAction(self.menufilesaveprojectas)
+
+ # Save Project Copy ...
+ # self.menufilesaveprojectcopy = QtWidgets.QAction(
+ # QtGui.QIcon(self.app.resource_location + '/floppy16.png'), _('Save Project C&opy ...'), self)
+ # self.menufile_save.addAction(self.menufilesaveprojectcopy)
+
+ self.menufile_save.addSeparator()
+
# Separator
self.menufile.addSeparator()
@@ -265,25 +286,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
QtGui.QIcon(self.app.resource_location + '/printer32.png'), '%s\tCtrl+P' % _('Print (PDF)'))
self.menufile.addAction(self.menufile_print)
- self.menufile_save = self.menufile.addMenu(QtGui.QIcon(self.app.resource_location + '/save_as.png'), _('Save'))
-
- # Save Project
- self.menufilesaveproject = QtWidgets.QAction(
- QtGui.QIcon(self.app.resource_location + '/floppy16.png'), _('&Save Project ...'), self)
- self.menufile_save.addAction(self.menufilesaveproject)
-
- # Save Project As ...
- self.menufilesaveprojectas = QtWidgets.QAction(
- QtGui.QIcon(self.app.resource_location + '/save_as.png'), _('Save Project &As ...\tCtrl+S'), self)
- self.menufile_save.addAction(self.menufilesaveprojectas)
-
- # Save Project Copy ...
- self.menufilesaveprojectcopy = QtWidgets.QAction(
- QtGui.QIcon(self.app.resource_location + '/floppy16.png'), _('Save Project C&opy ...'), self)
- self.menufile_save.addAction(self.menufilesaveprojectcopy)
-
- self.menufile_save.addSeparator()
-
# Separator
self.menufile.addSeparator()
@@ -541,7 +543,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
QtGui.QIcon(self.app.resource_location + '/text32.png'), _('Add Text\tT'))
self.geo_editor_menu.addSeparator()
self.geo_union_menuitem = self.geo_editor_menu.addAction(
- QtGui.QIcon(self.app.resource_location + '/union16.png'),_('Polygon Union\tU'))
+ QtGui.QIcon(self.app.resource_location + '/union16.png'), _('Polygon Union\tU'))
self.geo_intersection_menuitem = self.geo_editor_menu.addAction(
QtGui.QIcon(self.app.resource_location + '/intersection16.png'), _('Polygon Intersection\tE'))
self.geo_subtract_menuitem = self.geo_editor_menu.addAction(
@@ -550,7 +552,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.geo_editor_menu.addSeparator()
self.geo_cutpath_menuitem = self.geo_editor_menu.addAction(
QtGui.QIcon(self.app.resource_location + '/cutpath16.png'), _('Cut Path\tX'))
- # self.move_menuitem = self.menu.addAction(QtGui.QIcon(self.app.resource_location + '/move16.png'), "Move Objects 'm'")
+ # self.move_menuitem = self.menu.addAction(
+ # QtGui.QIcon(self.app.resource_location + '/move16.png'), "Move Objects 'm'")
self.geo_copy_menuitem = self.geo_editor_menu.addAction(
QtGui.QIcon(self.app.resource_location + '/copy16.png'), _("Copy Geom\tC"))
self.geo_delete_menuitem = self.geo_editor_menu.addAction(
@@ -1640,6 +1643,14 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
|
+
+ | Ctrl+Shift+S |
+ %s |
+
+
+ | |
+ |
+
| F1 |
%s |
@@ -1687,7 +1698,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# CTRL section
_("Select All"), _("Copy Obj"), _("Open Tools Database"),
_("Open Excellon File"), _("Open Gerber File"), _("Distance Tool"), _("New Project"),
- _("Open Project"), _("Print (PDF)"), _("PDF Import Tool"), _("Save Project As"), _("Toggle Plot Area"),
+ _("Open Project"), _("Print (PDF)"), _("PDF Import Tool"), _("Save Project"), _("Toggle Plot Area"),
# SHIFT section
_("Copy Obj_Name"),
@@ -1708,6 +1719,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# CTRL + ALT section
_("Abort current task (gracefully)"),
+ # CTRL + SHIFT section
+ _("Save Project As"),
+
# F keys section
_("Open Online Manual"),
_("Open Online Tutorials"), _("Refresh Plots"), _("Delete Object"), _("Alternate: Delete Tool"),
@@ -2816,7 +2830,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
if key == QtCore.Qt.Key_X:
self.app.abort_all_tasks()
return
-
+ if modifiers == QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier:
+ if key == QtCore.Qt.Key_S:
+ self.app.on_file_saveprojectas()
+ return
elif modifiers == QtCore.Qt.ControlModifier:
# Select All
if key == QtCore.Qt.Key_A:
@@ -2942,7 +2959,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.app.on_skewy()
return
elif modifiers == QtCore.Qt.AltModifier:
-
# Eanble all plots
if key == Qt.Key_1:
self.app.enable_all_plots()
@@ -3161,7 +3177,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
else:
self.app.collection.set_active(names_list[active_index+1])
-
# New Geometry
if key == QtCore.Qt.Key_B:
self.app.new_gerber_object()
@@ -3350,7 +3365,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# Abort the current action
if key == QtCore.Qt.Key_Escape or key == 'Escape':
- # TODO: ...?
# self.on_tool_select("select")
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled."))
From abce81d802df19e74b71b462bfece696c19197bb Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 11 Apr 2020 02:55:32 +0300
Subject: [PATCH 166/209] - fixed issue #394 - the saveDialog in Linux did not
added the selected extension - fixed issue #389 - in previous commits - fixed
issue #391 - in previous commits
---
FlatCAMApp.py | 49 +++++++++++++++--------------
FlatCAMCommon.py | 8 ++---
FlatCAMObj.py | 5 +--
README.md | 8 +++--
flatcamEditors/FlatCAMTextEditor.py | 12 +++----
flatcamGUI/GUIElements.py | 24 ++++++++++++++
flatcamTools/ToolFilm.py | 10 +++---
flatcamTools/ToolQRCode.py | 10 +++---
flatcamTools/ToolSolderPaste.py | 7 +++--
9 files changed, 82 insertions(+), 51 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index ef6c9357..001d8007 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -53,6 +53,7 @@ from camlib import to_dict, dict2obj, ET, ParseError
from flatcamGUI.PlotCanvas import *
from flatcamGUI.PlotCanvasLegacy import *
from flatcamGUI.FlatCAMGUI import *
+from flatcamGUI.GUIElements import FCFileSaveDialog
from FlatCAMCommon import LoudDict, BookmarkManager, ToolsDB, ToolsDB2, color_variant
from FlatCAMPostProc import load_preprocessors
@@ -4134,13 +4135,13 @@ class App(QtCore.QObject):
filter__ = "Config File (*.FlatConfig);;All Files (*.*)"
try:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+ filename, _f = FCFileSaveDialog.get_saved_filename(
caption=_("Export FlatCAM Preferences"),
directory=self.data_path + '/preferences_' + self.date,
filter=filter__
)
except TypeError:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export FlatCAM Preferences"),
+ filename, _f = FCFileSaveDialog.get_saved_filename( caption=_("Export FlatCAM Preferences"),
filter=filter__)
filename = str(filename)
@@ -9800,12 +9801,12 @@ class App(QtCore.QObject):
_filter = "SVG File (*.svg);;All Files (*.*)"
try:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+ filename, _f = FCFileSaveDialog.get_saved_filename(
caption=_("Export SVG"),
directory=self.get_last_save_folder() + '/' + str(name) + '_svg',
filter=_filter)
except TypeError:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export SVG"), filter=_filter)
+ filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Export SVG"), filter=_filter)
filename = str(filename)
@@ -9837,12 +9838,12 @@ class App(QtCore.QObject):
filter_ = "PNG File (*.png);;All Files (*.*)"
try:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+ filename, _f = FCFileSaveDialog.get_saved_filename(
caption=_("Export PNG Image"),
directory=self.get_last_save_folder() + '/png_' + self.date,
filter=filter_)
except TypeError:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export PNG Image"), filter=filter_)
+ filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Export PNG Image"), filter=filter_)
filename = str(filename)
@@ -9884,12 +9885,12 @@ class App(QtCore.QObject):
_filter = "Gerber File (*.GBR);;Gerber File (*.GRB);;All Files (*.*)"
try:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+ filename, _f = FCFileSaveDialog.get_saved_filename(
caption="Save Gerber source file",
directory=self.get_last_save_folder() + '/' + name,
filter=_filter)
except TypeError:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Save Gerber source file"), filter=_filter)
+ filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Save Gerber source file"), filter=_filter)
filename = str(filename)
@@ -9928,12 +9929,12 @@ class App(QtCore.QObject):
_filter = "FlatCAM Scripts (*.FlatScript);;All Files (*.*)"
try:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+ filename, _f = FCFileSaveDialog.get_saved_filename(
caption="Save Script source file",
directory=self.get_last_save_folder() + '/' + name,
filter=_filter)
except TypeError:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Save Script source file"), filter=_filter)
+ filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Save Script source file"), filter=_filter)
filename = str(filename)
@@ -9972,12 +9973,12 @@ class App(QtCore.QObject):
_filter = "FlatCAM Documents (*.FlatDoc);;All Files (*.*)"
try:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+ filename, _f = FCFileSaveDialog.get_saved_filename(
caption="Save Document source file",
directory=self.get_last_save_folder() + '/' + name,
filter=_filter)
except TypeError:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Save Document source file"), filter=_filter)
+ filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Save Document source file"), filter=_filter)
filename = str(filename)
@@ -10016,12 +10017,12 @@ class App(QtCore.QObject):
_filter = "Excellon File (*.DRL);;Excellon File (*.TXT);;All Files (*.*)"
try:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+ filename, _f = FCFileSaveDialog.get_saved_filename(
caption=_("Save Excellon source file"),
directory=self.get_last_save_folder() + '/' + name,
filter=_filter)
except TypeError:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Save Excellon source file"), filter=_filter)
+ filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Save Excellon source file"), filter=_filter)
filename = str(filename)
@@ -10060,12 +10061,12 @@ class App(QtCore.QObject):
_filter = self.defaults["excellon_save_filters"]
try:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+ filename, _f = FCFileSaveDialog.get_saved_filename(
caption=_("Export Excellon"),
directory=self.get_last_save_folder() + '/' + name,
filter=_filter)
except TypeError:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export Excellon"), filter=_filter)
+ filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Export Excellon"), filter=_filter)
filename = str(filename)
@@ -10107,12 +10108,12 @@ class App(QtCore.QObject):
_filter_ = self.defaults['gerber_save_filters']
try:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+ filename, _f = FCFileSaveDialog.get_saved_filename(
caption=_("Export Gerber"),
directory=self.get_last_save_folder() + '/' + name,
filter=_filter_)
except TypeError:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export Gerber"), filter=_filter_)
+ filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Export Gerber"), filter=_filter_)
filename = str(filename)
@@ -10166,12 +10167,12 @@ class App(QtCore.QObject):
_filter_ = "DXF File (*.DXF);;All Files (*.*)"
try:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+ filename, _f = FCFileSaveDialog.get_saved_filename(
caption=_("Export DXF"),
directory=self.get_last_save_folder() + '/' + name,
filter=_filter_)
except TypeError:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export DXF"),
+ filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Export DXF"),
filter=_filter_)
filename = str(filename)
@@ -10588,14 +10589,14 @@ class App(QtCore.QObject):
filter_ = "FlatCAM Project (*.FlatPrj);; All Files (*.*)"
try:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+ filename, _f = FCFileSaveDialog.get_saved_filename(
caption=_("Save Project As ..."),
directory='{l_save}/{proj}_{date}'.format(l_save=str(self.get_last_save_folder()), date=self.date,
proj=_("Project")),
filter=filter_
)
except TypeError:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Save Project As ..."), filter=filter_)
+ filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Save Project As ..."), filter=filter_)
filename = str(filename)
@@ -10642,7 +10643,7 @@ class App(QtCore.QObject):
filter_ = "PDF File (*.PDF);; All Files (*.*)"
try:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+ filename, _f = FCFileSaveDialog.get_saved_filename(
caption=_("Save Object as PDF ..."),
directory='{l_save}/{obj_name}_{date}'.format(l_save=str(self.get_last_save_folder()),
obj_name=obj_name,
@@ -10650,7 +10651,7 @@ class App(QtCore.QObject):
filter=filter_
)
except TypeError:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Save Object as PDF ..."), filter=filter_)
+ filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Save Object as PDF ..."), filter=filter_)
filename = str(filename)
diff --git a/FlatCAMCommon.py b/FlatCAMCommon.py
index 8940542f..52c42d92 100644
--- a/FlatCAMCommon.py
+++ b/FlatCAMCommon.py
@@ -13,7 +13,7 @@
from PyQt5 import QtGui, QtCore, QtWidgets
from flatcamGUI.GUIElements import FCTable, FCEntry, FCButton, FCDoubleSpinner, FCComboBox, FCCheckBox, FCSpinner, \
- FCTree, RadioSet
+ FCTree, RadioSet, FCFileSaveDialog
from camlib import to_dict
import sys
@@ -358,7 +358,7 @@ class BookmarkManager(QtWidgets.QWidget):
date = date.replace(' ', '_')
filter__ = "Text File (*.TXT);;All Files (*.*)"
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export FlatCAM Bookmarks"),
+ filename, _f = FCFileSaveDialog.get_saved_filename( caption=_("Export FlatCAM Bookmarks"),
directory='{l_save}/FlatCAM_{n}_{date}'.format(
l_save=str(self.app.get_last_save_folder()),
n=_("Bookmarks"),
@@ -1094,7 +1094,7 @@ class ToolsDB(QtWidgets.QWidget):
date = date.replace(' ', '_')
filter__ = "Text File (*.TXT);;All Files (*.*)"
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export Tools Database"),
+ filename, _f = FCFileSaveDialog.get_saved_filename( caption=_("Export Tools Database"),
directory='{l_save}/FlatCAM_{n}_{date}'.format(
l_save=str(self.app.get_last_save_folder()),
n=_("Tools_Database"),
@@ -2524,7 +2524,7 @@ class ToolsDB2(QtWidgets.QWidget):
date = date.replace(' ', '_')
filter__ = "Text File (*.TXT);;All Files (*.*)"
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export Tools Database"),
+ filename, _f = FCFileSaveDialog.get_saved_filename( caption=_("Export Tools Database"),
directory='{l_save}/FlatCAM_{n}_{date}'.format(
l_save=str(self.app.get_last_save_folder()),
n=_("Tools_Database"),
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index d803cea1..48480a5f 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -25,6 +25,7 @@ from datetime import datetime
from flatcamEditors.FlatCAMTextEditor import TextEditor
from flatcamGUI.ObjectUI import *
+from flatcamGUI.GUIElements import FCFileSaveDialog
from FlatCAMCommon import LoudDict
from flatcamGUI.PlotCanvasLegacy import ShapeCollectionLegacy
from flatcamParsers.ParseExcellon import Excellon
@@ -7024,13 +7025,13 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
try:
dir_file_to_save = self.app.get_last_save_folder() + '/' + str(name)
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+ filename, _f = FCFileSaveDialog.get_saved_filename(
caption=_("Export Machine Code ..."),
directory=dir_file_to_save,
filter=_filter_
)
except TypeError:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export Machine Code ..."), filter=_filter_)
+ filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Export Machine Code ..."), filter=_filter_)
filename = str(filename)
diff --git a/README.md b/README.md
index 6bcade76..bc4273d6 100644
--- a/README.md
+++ b/README.md
@@ -9,11 +9,15 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+11.04.2020
+
+- fixed issue #394 - the saveDialog in Linux did not added the selected extension
+
10.04.2020
-- made sure that the timeout parameter used by some Tcl Commands is seen as an integer in all cases
+- made sure that the timeout parameter used by some Tcl Commands is seen as an integer in all cases - fixed issue #389
- minor changes in Paint Tool
-- minor changes in GUI (Save locations in Menu -> File) and the key shortcuts
+- minor changes in GUI (Save locations in Menu -> File) and the key shortcuts - fixed issue #391
9.04.2020
diff --git a/flatcamEditors/FlatCAMTextEditor.py b/flatcamEditors/FlatCAMTextEditor.py
index fe0b847e..9159d823 100644
--- a/flatcamEditors/FlatCAMTextEditor.py
+++ b/flatcamEditors/FlatCAMTextEditor.py
@@ -5,14 +5,14 @@
# MIT Licence #
# ##########################################################
-from flatcamGUI.GUIElements import *
-from PyQt5 import QtPrintSupport
+from flatcamGUI.GUIElements import FCFileSaveDialog, FCEntry, FCTextAreaExtended, FCTextAreaLineNumber
+from PyQt5 import QtPrintSupport, QtWidgets, QtCore, QtGui
from reportlab.platypus import SimpleDocTemplate, Paragraph
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import inch, mm
-from io import StringIO
+# from io import StringIO
import gettext
import FlatCAMTranslation as fcTranslate
@@ -211,13 +211,13 @@ class TextEditor(QtWidgets.QWidget):
_filter_ = "FlatConfig Files (*.FlatConfig);;PDF Files (*.pdf);;All Files (*.*)"
try:
- filename = str(QtWidgets.QFileDialog.getSaveFileName(
+ filename = str(FCFileSaveDialog.get_saved_filename(
caption=_("Export Code ..."),
directory=self.app.defaults["global_last_folder"] + '/' + str(obj_name),
filter=_filter_
)[0])
except TypeError:
- filename = str(QtWidgets.QFileDialog.getSaveFileName(caption=_("Export Code ..."), filter=_filter_)[0])
+ filename = str(FCFileSaveDialog.get_saved_filename(caption=_("Export Code ..."), filter=_filter_)[0])
if filename == "":
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Export Code cancelled."))
@@ -236,7 +236,7 @@ class TextEditor(QtWidgets.QWidget):
styles = getSampleStyleSheet()
styleN = styles['Normal']
- styleH = styles['Heading1']
+ # styleH = styles['Heading1']
story = []
if self.app.defaults['units'].lower() == 'mm':
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index 4965b954..a3560bf2 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -2853,6 +2853,30 @@ class FCTextAreaLineNumber(QtWidgets.QFrame):
self.edit.setLineWrapMode(mode)
+class FCFileSaveDialog(QtWidgets.QFileDialog):
+
+ def __init__(self, *args):
+ super(FCFileSaveDialog, self).__init__(*args)
+
+ @staticmethod
+ def get_saved_filename(parent=None, caption='', directory='', filter='', initialFilter=''):
+ filename, _filter = QtWidgets.QFileDialog.getSaveFileName(parent=parent, caption=caption,
+ directory=directory, filter=filter,
+ initialFilter=initialFilter)
+
+ filename = str(filename)
+ if filename == '':
+ return filename, _filter
+
+ extension = '.' + _filter.strip(')').rpartition('.')[2]
+
+ if filename.endswith(extension) or extension == '.*':
+ return filename, _filter
+ else:
+ filename += extension
+ return filename, _filter
+
+
def rreplace(s, old, new, occurrence):
"""
Credits go here:
diff --git a/flatcamTools/ToolFilm.py b/flatcamTools/ToolFilm.py
index 4baae1a6..42787e5a 100644
--- a/flatcamTools/ToolFilm.py
+++ b/flatcamTools/ToolFilm.py
@@ -9,7 +9,7 @@ from PyQt5 import QtGui, QtCore, QtWidgets
from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, \
- OptionalHideInputSection, OptionalInputSection, FCComboBox
+ OptionalHideInputSection, OptionalInputSection, FCComboBox, FCFileSaveDialog
from copy import deepcopy
import logging
@@ -741,12 +741,12 @@ class Film(FlatCAMTool):
"All Files (*.*)"
try:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+ filename, _f = FCFileSaveDialog.get_saved_filename(
caption=_("Export positive film"),
directory=self.app.get_last_save_folder() + '/' + name + '_film',
filter=filter_ext)
except TypeError:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export positive film"))
+ filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Export positive film"))
filename = str(filename)
@@ -887,12 +887,12 @@ class Film(FlatCAMTool):
"All Files (*.*)"
try:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+ filename, _f = FCFileSaveDialog.get_saved_filename(
caption=_("Export negative film"),
directory=self.app.get_last_save_folder() + '/' + name + '_film',
filter=filter_ext)
except TypeError:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export negative film"))
+ filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Export negative film"))
filename = str(filename)
diff --git a/flatcamTools/ToolQRCode.py b/flatcamTools/ToolQRCode.py
index 438349d3..bc5c1fd1 100644
--- a/flatcamTools/ToolQRCode.py
+++ b/flatcamTools/ToolQRCode.py
@@ -9,7 +9,7 @@ from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtCore import Qt
from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import RadioSet, FCTextArea, FCSpinner, FCEntry, FCCheckBox, FCComboBox
+from flatcamGUI.GUIElements import RadioSet, FCTextArea, FCSpinner, FCEntry, FCCheckBox, FCComboBox, FCFileSaveDialog
from flatcamParsers.ParseSVG import *
from shapely.geometry.base import *
@@ -778,12 +778,12 @@ class QRCode(FlatCAMTool):
_filter = "PNG File (*.png);;All Files (*.*)"
try:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+ filename, _f = FCFileSaveDialog.get_saved_filename(
caption=_("Export PNG"),
directory=self.app.get_last_save_folder() + '/' + str(name) + '_png',
filter=_filter)
except TypeError:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export PNG"), filter=_filter)
+ filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Export PNG"), filter=_filter)
filename = str(filename)
@@ -825,12 +825,12 @@ class QRCode(FlatCAMTool):
_filter = "SVG File (*.svg);;All Files (*.*)"
try:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+ filename, _f = FCFileSaveDialog.get_saved_filename(
caption=_("Export SVG"),
directory=self.app.get_last_save_folder() + '/' + str(name) + '_svg',
filter=_filter)
except TypeError:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export SVG"), filter=_filter)
+ filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Export SVG"), filter=_filter)
filename = str(filename)
diff --git a/flatcamTools/ToolSolderPaste.py b/flatcamTools/ToolSolderPaste.py
index d42b39d6..3da208a0 100644
--- a/flatcamTools/ToolSolderPaste.py
+++ b/flatcamTools/ToolSolderPaste.py
@@ -7,7 +7,8 @@
from FlatCAMTool import FlatCAMTool
from FlatCAMCommon import LoudDict
-from flatcamGUI.GUIElements import FCComboBox, FCEntry, FCTable, FCInputDialog, FCDoubleSpinner, FCSpinner
+from flatcamGUI.GUIElements import FCComboBox, FCEntry, FCTable, \
+ FCInputDialog, FCDoubleSpinner, FCSpinner, FCFileSaveDialog
from FlatCAMApp import log
from camlib import distance
from FlatCAMObj import FlatCAMCNCjob
@@ -1492,13 +1493,13 @@ class SolderPaste(FlatCAMTool):
try:
dir_file_to_save = self.app.get_last_save_folder() + '/' + str(name)
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(
+ filename, _f = FCFileSaveDialog.get_saved_filename(
caption=_("Export GCode ..."),
directory=dir_file_to_save,
filter=_filter_
)
except TypeError:
- filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export Machine Code ..."), filter=_filter_)
+ filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Export Machine Code ..."), filter=_filter_)
if filename == '':
self.app.inform.emit('[WARNING_NOTCL] %s' %
From 45a2890850d1bdc41ce25de371decfe1001dc074 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Sat, 11 Apr 2020 04:37:37 +0300
Subject: [PATCH 167/209] - when the Save button is clicked in the Edit ->
Preferences the Preferences tab is closed.
---
FlatCAMApp.py | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 001d8007..5de1325e 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -7087,6 +7087,14 @@ class App(QtCore.QObject):
# This will write the setting to the platform specific storage.
del settgs
+ if save_to_file:
+ # close the tab and delete it
+ for idx in range(self.ui.plot_tab_area.count()):
+ if self.ui.plot_tab_area.tabText(idx) == _("Preferences"):
+ self.ui.plot_tab_area.tabBar.setTabTextColor(idx, QtGui.QColor('black'))
+ self.ui.plot_tab_area.closeTab(idx)
+ break
+
def on_pref_close_button(self):
# Preferences saved, update flag
self.preferences_changed_flag = False
@@ -8149,6 +8157,7 @@ class App(QtCore.QObject):
if isinstance(obj, FlatCAMGeometry):
obj.on_tool_from_db_inserted(tool=tool_from_db)
+ # close the tab and delete it
for idx in range(self.ui.plot_tab_area.count()):
if self.ui.plot_tab_area.tabText(idx) == _("Tools Database"):
wdg = self.ui.plot_tab_area.widget(idx)
diff --git a/README.md b/README.md
index bc4273d6..ce3daf76 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ CAD program, and create G-Code for Isolation routing.
11.04.2020
- fixed issue #394 - the saveDialog in Linux did not added the selected extension
+- when the Save button is clicked in the Edit -> Preferences the Preferences tab is closed.
10.04.2020
From 5dcddb168ed223d0e4fca7ecce4ff6fd59f2f967 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 13 Apr 2020 05:50:59 +0300
Subject: [PATCH 168/209] - added the outname parameter for the geocutout Tcl
command
---
README.md | 4 ++++
tclCommands/TclCommandGeoCutout.py | 15 ++++++++++-----
2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index ce3daf76..4dfeb150 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+13.04.2020
+
+- added the outname parameter for the geocutout Tcl command
+
11.04.2020
- fixed issue #394 - the saveDialog in Linux did not added the selected extension
diff --git a/tclCommands/TclCommandGeoCutout.py b/tclCommands/TclCommandGeoCutout.py
index c138d4ad..555c38bc 100644
--- a/tclCommands/TclCommandGeoCutout.py
+++ b/tclCommands/TclCommandGeoCutout.py
@@ -35,7 +35,8 @@ class TclCommandGeoCutout(TclCommandSignaled):
('dia', float),
('margin', float),
('gapsize', float),
- ('gaps', str)
+ ('gaps', str),
+ ('outname', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
@@ -50,7 +51,8 @@ class TclCommandGeoCutout(TclCommandSignaled):
('margin', 'Margin over bounds.'),
('gapsize', 'size of gap.'),
('gaps', "type of gaps. Can be: 'tb' = top-bottom, 'lr' = left-right, '2tb' = 2top-2bottom, "
- "'2lr' = 2left-2right, '4' = 4 cuts, '8' = 8 cuts")
+ "'2lr' = 2left-2right, '4' = 4 cuts, '8' = 8 cuts"),
+ ('outname', 'Name of the resulting Geometry object.'),
]),
'examples': [" #isolate margin for example from Fritzing arduino shield or any svg etc\n" +
" isolate BCu_margin -dia 3 -overlap 1\n" +
@@ -62,7 +64,7 @@ class TclCommandGeoCutout(TclCommandSignaled):
" delete BCu_margin_iso\n" +
"\n" +
" #finally cut holding gaps\n" +
- " geocutout BCu_margin_iso_exterior -dia 3 -gapsize 0.6 -gaps 4\n"]
+ " geocutout BCu_margin_iso_exterior -dia 3 -gapsize 0.6 -gaps 4 -outname cutout_geo\n"]
}
flat_geometry = []
@@ -156,6 +158,11 @@ class TclCommandGeoCutout(TclCommandSignaled):
else:
gapsize = 0.1
+ if 'outname' in args:
+ outname = args['outname']
+ else:
+ outname = str(name) + "_cutout"
+
# Get source object.
try:
cutout_obj = self.app.collection.get_by_name(str(name))
@@ -283,7 +290,6 @@ class TclCommandGeoCutout(TclCommandSignaled):
app_obj.inform.emit("[success] Any-form Cutout operation finished.")
- outname = cutout_obj.options["name"] + "_cutout"
self.app.new_object('geometry', outname, geo_init, plot=False)
# cutout_obj.plot()
@@ -342,7 +348,6 @@ class TclCommandGeoCutout(TclCommandSignaled):
geo_obj.options['ymax'] = cutout_obj.options['ymax']
app_obj.inform.emit("[success] Any-form Cutout operation finished.")
- outname = cutout_obj.options["name"] + "_cutout"
self.app.new_object('geometry', outname, geo_init, plot=False)
cutout_obj = self.app.collection.get_by_name(outname)
From 8a299e8fc8b203535e37a74ec8b84c224d2ec6b0 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 13 Apr 2020 19:15:20 +0300
Subject: [PATCH 169/209] - multiple fixes in the Tcl commands (especially
regarding the interchange between True/false and 1/0 values) - updated the
help for all Tcl Commands - in Tcl Shell, the 'help' command will add also a
brief description for each command in the list
---
FlatCAMApp.py | 22 +++++++++---
FlatCAMObj.py | 2 +-
README.md | 3 ++
tclCommands/TclCommand.py | 2 ++
tclCommands/TclCommandAddCircle.py | 2 ++
tclCommands/TclCommandAddPolygon.py | 2 ++
tclCommands/TclCommandAddPolyline.py | 2 ++
tclCommands/TclCommandAddRectangle.py | 4 ++-
tclCommands/TclCommandAlignDrill.py | 2 ++
tclCommands/TclCommandAlignDrillGrid.py | 4 ++-
tclCommands/TclCommandBbox.py | 12 ++++---
tclCommands/TclCommandBounds.py | 4 ++-
tclCommands/TclCommandClearShell.py | 4 ++-
tclCommands/TclCommandCncjob.py | 20 ++++++-----
tclCommands/TclCommandCopperClear.py | 40 ++++++++++++----------
tclCommands/TclCommandCutout.py | 33 +++++++++++-------
tclCommands/TclCommandDelete.py | 2 ++
tclCommands/TclCommandDrillcncjob.py | 18 +++++-----
tclCommands/TclCommandExportDXF.py | 19 +++++-----
tclCommands/TclCommandExportExcellon.py | 21 +++++++-----
tclCommands/TclCommandExportGcode.py | 13 ++++---
tclCommands/TclCommandExportGerber.py | 13 ++++---
tclCommands/TclCommandExportSVG.py | 8 +++--
tclCommands/TclCommandExteriors.py | 5 ++-
tclCommands/TclCommandFollow.py | 6 ++--
tclCommands/TclCommandGeoCutout.py | 12 ++++---
tclCommands/TclCommandGeoUnion.py | 2 ++
tclCommands/TclCommandGetNames.py | 6 +++-
tclCommands/TclCommandGetSys.py | 4 ++-
tclCommands/TclCommandImportSvg.py | 13 ++++---
tclCommands/TclCommandInteriors.py | 6 +++-
tclCommands/TclCommandIsolate.py | 12 ++++---
tclCommands/TclCommandJoinExcellon.py | 7 ++--
tclCommands/TclCommandJoinGeometry.py | 6 ++--
tclCommands/TclCommandListSys.py | 2 ++
tclCommands/TclCommandMillDrills.py | 14 +++++---
tclCommands/TclCommandMillSlots.py | 14 +++++---
tclCommands/TclCommandMirror.py | 4 ++-
tclCommands/TclCommandNew.py | 2 ++
tclCommands/TclCommandNewExcellon.py | 2 ++
tclCommands/TclCommandNewGeometry.py | 2 ++
tclCommands/TclCommandNewGerber.py | 2 ++
tclCommands/TclCommandNregions.py | 10 +++---
tclCommands/TclCommandOffset.py | 2 ++
tclCommands/TclCommandOpenExcellon.py | 4 ++-
tclCommands/TclCommandOpenGCode.py | 4 ++-
tclCommands/TclCommandOpenGerber.py | 2 ++
tclCommands/TclCommandOpenProject.py | 4 ++-
tclCommands/TclCommandOptions.py | 3 ++
tclCommands/TclCommandPaint.py | 35 ++++++++++---------
tclCommands/TclCommandPanelize.py | 15 ++++----
tclCommands/TclCommandPlotAll.py | 4 ++-
tclCommands/TclCommandPlotObjects.py | 9 +++--
tclCommands/TclCommandQuit.py | 2 ++
tclCommands/TclCommandSaveProject.py | 4 ++-
tclCommands/TclCommandSaveSys.py | 2 ++
tclCommands/TclCommandScale.py | 2 ++
tclCommands/TclCommandSetActive.py | 4 ++-
tclCommands/TclCommandSetOrigin.py | 6 ++--
tclCommands/TclCommandSetSys.py | 4 ++-
tclCommands/TclCommandSkew.py | 4 ++-
tclCommands/TclCommandSubtractPoly.py | 3 ++
tclCommands/TclCommandSubtractRectangle.py | 3 ++
tclCommands/TclCommandVersion.py | 2 ++
tclCommands/TclCommandWriteGCode.py | 14 ++++----
tclCommands/__init__.py | 7 +++-
66 files changed, 350 insertions(+), 172 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 5de1325e..1d4dde99 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -11927,9 +11927,22 @@ class App(QtCore.QObject):
def shelp(p=None):
if not p:
- return _("Available commands:\n") + \
- '\n'.join([' ' + cmd for cmd in sorted(commands)]) + \
- _("\n\nType help for usage.\n Example: help open_gerber")
+ cmd_enum = _("Available commands:\n")
+
+ displayed_text = []
+ try:
+ for cmd_name in sorted(commands):
+ cmd_description = commands[cmd_name]['description']
+
+ cmd_line_txt = ' %s\t\t%s' % (str(cmd_name), cmd_description)
+ displayed_text.append(cmd_line_txt)
+ except Exception as err:
+ log.debug("App.setup_shell.shelp() when run as 'help' --> %s" % str(err))
+ displayed_text = [' %s' % cmd for cmd in sorted(commands)]
+
+ cmd_enum += '\n'.join(displayed_text)
+ cmd_enum += '\n\n%s\n%s' % (_("Type help for usage."), _("Example: help open_gerber"))
+ return cmd_enum
if p not in commands:
return "Unknown command: %s" % p
@@ -12079,7 +12092,8 @@ class App(QtCore.QObject):
commands = {
'help': {
'fcn': shelp,
- 'help': _("Shows list of commands.")
+ 'help': _("Shows list of commands."),
+ 'description': ''
},
}
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 48480a5f..a8b388bf 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -7505,7 +7505,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
self.app.inform.emit('[ERROR] %s' % _("There is no preprocessor file."))
def get_gcode(self, preamble='', postamble=''):
- # we need this to be able get_gcode separatelly for shell command export_gcode
+ # we need this to be able get_gcode separately for shell command export_gcode
return preamble + '\n' + self.gcode + "\n" + postamble
def get_svg(self):
diff --git a/README.md b/README.md
index 4dfeb150..2b0ed24a 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,9 @@ CAD program, and create G-Code for Isolation routing.
13.04.2020
- added the outname parameter for the geocutout Tcl command
+- multiple fixes in the Tcl commands (especially regarding the interchange between True/false and 1/0 values)
+- updated the help for all Tcl Commands
+- in Tcl Shell, the 'help' command will add also a brief description for each command in the list
11.04.2020
diff --git a/tclCommands/TclCommand.py b/tclCommands/TclCommand.py
index 0e5e6bab..9971eeaf 100644
--- a/tclCommands/TclCommand.py
+++ b/tclCommands/TclCommand.py
@@ -58,6 +58,8 @@ class TclCommand(object):
raise TypeError('Expected FlatCAMApp, got %s.' % type(app))
self.log = self.app.log
+ self.error_info = None
+ self.error = None
def raise_tcl_error(self, text):
"""
diff --git a/tclCommands/TclCommandAddCircle.py b/tclCommands/TclCommandAddCircle.py
index f48ece80..f0cd87aa 100644
--- a/tclCommands/TclCommandAddCircle.py
+++ b/tclCommands/TclCommandAddCircle.py
@@ -13,6 +13,8 @@ class TclCommandAddCircle(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['add_circle']
+ description = '%s %s' % ("--", "Creates a circle in the given Geometry object.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
diff --git a/tclCommands/TclCommandAddPolygon.py b/tclCommands/TclCommandAddPolygon.py
index 08ec3798..88fea588 100644
--- a/tclCommands/TclCommandAddPolygon.py
+++ b/tclCommands/TclCommandAddPolygon.py
@@ -10,6 +10,8 @@ class TclCommandAddPolygon(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['add_polygon', 'add_poly']
+ description = '%s %s' % ("--", "Creates a polygon in the given Geometry object.")
+
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str)
diff --git a/tclCommands/TclCommandAddPolyline.py b/tclCommands/TclCommandAddPolyline.py
index b7c0a47b..79de3790 100644
--- a/tclCommands/TclCommandAddPolyline.py
+++ b/tclCommands/TclCommandAddPolyline.py
@@ -11,6 +11,8 @@ class TclCommandAddPolyline(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['add_polyline']
+ description = '%s %s' % ("--", "Creates a polyline in the given Geometry object.")
+
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str)
diff --git a/tclCommands/TclCommandAddRectangle.py b/tclCommands/TclCommandAddRectangle.py
index 0fa7096e..eff36327 100644
--- a/tclCommands/TclCommandAddRectangle.py
+++ b/tclCommands/TclCommandAddRectangle.py
@@ -10,6 +10,8 @@ class TclCommandAddRectangle(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['add_rectangle']
+ description = '%s %s' % ("--", "Creates a rectangle in the given Geometry object.")
+
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
@@ -31,7 +33,7 @@ class TclCommandAddRectangle(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Add a rectange to the given Geometry object.",
+ 'main': "Creates a rectangle in the given Geometry object.",
'args': collections.OrderedDict([
('name', 'Name of the Geometry object in which to add the rectangle.'),
('x0 y0', 'Bottom left corner coordinates.'),
diff --git a/tclCommands/TclCommandAlignDrill.py b/tclCommands/TclCommandAlignDrill.py
index 1659b2a4..8ed877eb 100644
--- a/tclCommands/TclCommandAlignDrill.py
+++ b/tclCommands/TclCommandAlignDrill.py
@@ -15,6 +15,8 @@ class TclCommandAlignDrill(TclCommandSignaled):
# backward compatibility (add_poly, add_polygon)
aliases = ['aligndrill']
+ description = '%s %s' % ("--", "Create an Excellon object with drills for alignment.")
+
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
diff --git a/tclCommands/TclCommandAlignDrillGrid.py b/tclCommands/TclCommandAlignDrillGrid.py
index ac86f198..6fe6188b 100644
--- a/tclCommands/TclCommandAlignDrillGrid.py
+++ b/tclCommands/TclCommandAlignDrillGrid.py
@@ -15,6 +15,8 @@ class TclCommandAlignDrillGrid(TclCommandSignaled):
# backward compatibility (add_poly, add_polygon)
aliases = ['aligndrillgrid']
+ description = '%s %s' % ("--", "Create an Excellon object with drills for alignment arranged in a grid.")
+
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
@@ -41,7 +43,6 @@ class TclCommandAlignDrillGrid(TclCommandSignaled):
help = {
'main': "Create an Excellon object with drills for alignment arranged in a grid.",
'args': collections.OrderedDict([
- ('outname', 'Name of the object to create.'),
('dia', 'Tool diameter.'),
('gridx', 'Grid size in X axis.'),
('gridoffsetx', 'Move grid from origin.'),
@@ -49,6 +50,7 @@ class TclCommandAlignDrillGrid(TclCommandSignaled):
('gridoffsety', 'Move grid from origin.'),
('colums', 'Number of grid holes on X axis.'),
('rows', 'Number of grid holes on Y axis.'),
+ ('outname', 'Name of the object to create.')
]),
'examples': ['aligndrillgrid -rows 2 -columns 2 -gridoffsetx 10 -gridoffsety 10 -gridx 2.54 -gridy 5.08']
}
diff --git a/tclCommands/TclCommandBbox.py b/tclCommands/TclCommandBbox.py
index a3df3d16..dd6ab627 100644
--- a/tclCommands/TclCommandBbox.py
+++ b/tclCommands/TclCommandBbox.py
@@ -21,6 +21,8 @@ class TclCommandBbox(TclCommand):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['bounding_box', 'bbox']
+ description = '%s %s' % ("--", "Creates a rectangular Geometry object that surrounds the object.")
+
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str)
@@ -30,7 +32,7 @@ class TclCommandBbox(TclCommand):
option_types = collections.OrderedDict([
('outname', str),
('margin', float),
- ('rounded', bool)
+ ('rounded', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
@@ -41,11 +43,11 @@ class TclCommandBbox(TclCommand):
'main': "Creates a rectangular Geometry object that surrounds the object.",
'args': collections.OrderedDict([
('name', 'Object name for which to create bounding box. String'),
- ('outname', 'Name of the resulting Geometry object. String.'),
('margin', "Distance of the edges of the box to the nearest polygon."
"Float number."),
('rounded', "If the bounding box is to have rounded corners their radius is equal to the margin. "
- "True or False.")
+ "True (1) or False (0)."),
+ ('outname', 'Name of the resulting Geometry object. String.')
]),
'examples': ['bbox name -outname name_bbox']
}
@@ -78,8 +80,8 @@ class TclCommandBbox(TclCommand):
margin = args['margin']
if 'rounded' not in args:
- args['rounded'] = self.app.defaults["gerber_bboxrounded"]
- rounded = bool(args['rounded'])
+ args['rounded'] = bool(eval(self.app.defaults["gerber_bboxrounded"]))
+ rounded = bool(eval(args['rounded']))
del args['name']
diff --git a/tclCommands/TclCommandBounds.py b/tclCommands/TclCommandBounds.py
index a03a97c0..0401938e 100644
--- a/tclCommands/TclCommandBounds.py
+++ b/tclCommands/TclCommandBounds.py
@@ -23,6 +23,8 @@ class TclCommandBounds(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['get_bounds', 'bounds']
+ description = '%s %s' % ("--", "Return in the console a list of bounds values for a list of objects.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('objects', str)
@@ -38,7 +40,7 @@ class TclCommandBounds(TclCommand):
# structured help for current command, args needs to be ordered
help = {
'main': "Will return a list of bounds values, each set of bound values is "
- "a list itself: [xmin, ymin, xmax, ymax].",
+ "a list itself: [xmin, ymin, xmax, ymax] corresponding to each of the provided objects.",
'args': collections.OrderedDict([
('objects', 'A list of object names separated by comma without spaces.'),
]),
diff --git a/tclCommands/TclCommandClearShell.py b/tclCommands/TclCommandClearShell.py
index 4672ecae..3297017f 100644
--- a/tclCommands/TclCommandClearShell.py
+++ b/tclCommands/TclCommandClearShell.py
@@ -20,6 +20,8 @@ class TclCommandClearShell(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['clear']
+ description = '%s %s' % ("--", "Clear the text in the Tcl Shell.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
@@ -35,7 +37,7 @@ class TclCommandClearShell(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Clear the text in the Tcl Shell browser.",
+ 'main': "Clear the text in the Tcl Shell.",
'args': collections.OrderedDict([
]),
'examples': ['clear']
diff --git a/tclCommands/TclCommandCncjob.py b/tclCommands/TclCommandCncjob.py
index ffb91ba7..70bfbcbc 100644
--- a/tclCommands/TclCommandCncjob.py
+++ b/tclCommands/TclCommandCncjob.py
@@ -20,6 +20,8 @@ class TclCommandCncjob(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['cncjob']
+ description = '%s %s' % ("--", "Generates a CNC Job object from a Geometry Object.")
+
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str)
@@ -42,7 +44,7 @@ class TclCommandCncjob(TclCommandSignaled):
('spindlespeed', int),
('dwelltime', float),
('pp', str),
- ('muted', int),
+ ('muted', str),
('outname', str)
])
@@ -51,7 +53,7 @@ class TclCommandCncjob(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Generates a CNC Job from a Geometry Object.",
+ 'main': "Generates a CNC Job object from a Geometry Object.",
'args': collections.OrderedDict([
('name', 'Name of the source object.'),
('dia', 'Tool diameter to show on screen.'),
@@ -72,7 +74,7 @@ class TclCommandCncjob(TclCommandSignaled):
'If it is not used in command then it will not be included'),
('outname', 'Name of the resulting Geometry object.'),
('pp', 'Name of the Geometry preprocessor. No quotes, case sensitive'),
- ('muted', 'It will not put errors in the Shell.')
+ ('muted', 'It will not put errors in the Shell. Can be True (1) or False (0)')
]),
'examples': ['cncjob geo_name -dia 0.5 -z_cut -1.7 -z_move 2 -feedrate 120 -pp default']
}
@@ -90,14 +92,14 @@ class TclCommandCncjob(TclCommandSignaled):
name = ''
if 'muted' in args:
- muted = args['muted']
+ muted = bool(eval(args['muted']))
else:
- muted = 0
+ muted = False
try:
name = args['name']
except KeyError:
- if muted == 0:
+ if muted is False:
self.raise_tcl_error("Object name is missing")
else:
return "fail"
@@ -108,13 +110,13 @@ class TclCommandCncjob(TclCommandSignaled):
obj = self.app.collection.get_by_name(str(name), isCaseSensitive=False)
if obj is None:
- if muted == 0:
+ if muted is False:
self.raise_tcl_error("Object not found: %s" % str(name))
else:
return "fail"
if not isinstance(obj, FlatCAMGeometry):
- if muted == 0:
+ if muted is False:
self.raise_tcl_error('Expected FlatCAMGeometry, got %s %s.' % (str(name), type(obj)))
else:
return
@@ -187,7 +189,7 @@ class TclCommandCncjob(TclCommandSignaled):
else:
if args[arg] is None:
print(arg, args[arg])
- if muted == 0:
+ if muted is False:
self.raise_tcl_error('One of the command parameters that have to be not None, is None.\n'
'The parameter that is None is in the default values found in the list \n'
'generated by the TclCommand "list_sys geom". or in the arguments.')
diff --git a/tclCommands/TclCommandCopperClear.py b/tclCommands/TclCommandCopperClear.py
index f80bc5a9..62eeb19e 100644
--- a/tclCommands/TclCommandCopperClear.py
+++ b/tclCommands/TclCommandCopperClear.py
@@ -22,6 +22,8 @@ class TclCommandCopperClear(TclCommand):
# Array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['ncc_clear', 'ncc']
+ description = '%s %s' % ("--", "Clear excess copper.")
+
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
@@ -34,13 +36,13 @@ class TclCommandCopperClear(TclCommand):
('order', str),
('margin', float),
('method', str),
- ('connect', bool),
- ('contour', bool),
- ('has_offset', bool),
+ ('connect', str),
+ ('contour', str),
+ ('has_offset', str),
('offset', float),
- ('rest', bool),
+ ('rest', str),
('all', int),
- ('ref', int),
+ ('ref', str),
('box', str),
('outname', str),
])
@@ -64,15 +66,15 @@ class TclCommandCopperClear(TclCommand):
'"fwd" -> tools are ordered from smallest to biggest.'
'"rev" -> tools are ordered from biggest to smallest.'),
('method', 'Algorithm for copper clearing. Can be: "standard", "seed" or "lines".'),
- ('connect', 'Draw lines to minimize tool lifts. True or False'),
- ('contour', 'Cut around the perimeter of the painting. True or False'),
- ('rest', 'Use rest-machining. True or False'),
- ('has_offset', 'The offset will used only if this is set True or present in args. True or False.'),
+ ('connect', 'Draw lines to minimize tool lifts. True (1) or False (0)'),
+ ('contour', 'Cut around the perimeter of the painting. True (1) or False (0)'),
+ ('rest', 'Use rest-machining. True (1) or False (0)'),
+ ('has_offset', 'The offset will used only if this is set True or present in args. True (1) or False (0).'),
('offset', 'The copper clearing will finish to a distance from copper features. Float number.'),
('all', 'Will copper clear the whole object. 1 or True = enabled, anything else = disabled'),
('ref', 'Will clear of extra copper all polygons within a specified object with the name in "box" '
- 'parameter. 1 or True = enabled, anything else = disabled'),
- ('box', 'Name of the object to be used as reference. Required when selecting "ref" = 1. String.'),
+ 'parameter. 1 or True = enabled, 0 or False = disabled'),
+ ('box', 'Name of the object to be used as reference. Required when selecting "ref" = 1 or True. String.'),
('outname', 'Name of the resulting Geometry object. String.'),
]),
'examples': ["ncc obj_name -tooldia 0.3,1 -overlap 10 -margin 1.0 -method 'lines' -all True"]
@@ -127,18 +129,18 @@ class TclCommandCopperClear(TclCommand):
method = str(self.app.defaults["tools_nccmethod"])
if 'connect' in args:
- connect = bool(args['connect'])
+ connect = bool(eval(args['connect']))
else:
- connect = eval(str(self.app.defaults["tools_nccconnect"]))
+ connect = bool(eval(str(self.app.defaults["tools_nccconnect"])))
if 'contour' in args:
- contour = bool(args['contour'])
+ contour = bool(eval(args['contour']))
else:
- contour = eval(str(self.app.defaults["tools_ncccontour"]))
+ contour = bool(eval(str(self.app.defaults["tools_ncccontour"])))
offset = 0.0
if 'has_offset' in args:
- has_offset = bool(args['has_offset'])
+ has_offset = bool(eval(args['has_offset']))
if args['has_offset'] is True:
if 'offset' in args:
offset = float(args['margin'])
@@ -206,9 +208,9 @@ class TclCommandCopperClear(TclCommand):
})
if 'rest' in args:
- rest = bool(args['rest'])
+ rest = bool(eval(args['rest']))
else:
- rest = eval(str(self.app.defaults["tools_nccrest"]))
+ rest = bool(eval(str(self.app.defaults["tools_nccrest"])))
if 'outname' in args:
outname = args['outname']
@@ -239,7 +241,7 @@ class TclCommandCopperClear(TclCommand):
return
# Non-Copper clear all polygons found within the box object from the the non_copper cleared object
- elif 'ref' in args and bool(args['ref']):
+ elif 'ref' in args and bool(eval(args['ref'])):
if 'box' not in args:
self.raise_tcl_error('%s' % _("Expected -box ."))
else:
diff --git a/tclCommands/TclCommandCutout.py b/tclCommands/TclCommandCutout.py
index c074fa8e..f780a8cf 100644
--- a/tclCommands/TclCommandCutout.py
+++ b/tclCommands/TclCommandCutout.py
@@ -21,6 +21,8 @@ class TclCommandCutout(TclCommand):
# names for backward compatibility (add_poly, add_polygon)
aliases = ['cutout']
+ description = '%s %s' % ("--", "Creates board cutout from an object (Gerber or Geometry) with a rectangular shape.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
@@ -32,7 +34,8 @@ class TclCommandCutout(TclCommand):
('dia', float),
('margin', float),
('gapsize', float),
- ('gaps', str)
+ ('gaps', str),
+ ('outname', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
@@ -40,15 +43,16 @@ class TclCommandCutout(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': 'Creates board cutout from an object (Gerber or Geometry) with a rectangular shape',
+ 'main': 'Creates board cutout from an object (Gerber or Geometry) with a rectangular shape.',
'args': collections.OrderedDict([
('name', 'Name of the object.'),
- ('dia', 'Tool diameter. Default = 0.1'),
- ('margin', 'Margin over bounds. Default = 0.001'),
- ('gapsize', 'Size of gap. Default = 0.1'),
- ('gaps', "Type of gaps. Can be: 'tb' = top-bottom, 'lr' = left-right and '4' = one each side. Default = 4"),
+ ('dia', 'Tool diameter.'),
+ ('margin', 'Margin over bounds.'),
+ ('gapsize', 'Size of gap.'),
+ ('gaps', "Type of gaps. Can be: 'tb' = top-bottom, 'lr' = left-right and '4' = one each side."),
+ ('outname', 'Name of the object to create.')
]),
- 'examples': ['cutout new_geo -dia 1.2 -margin 0.1 -gapsize 1 -gaps "tb" ']
+ 'examples': ['cutout new_geo -dia 1.2 -margin 0.1 -gapsize 1 -gaps "tb" -outname cut_geo']
}
def execute(self, args, unnamed_args):
@@ -69,22 +73,27 @@ class TclCommandCutout(TclCommand):
if 'margin' in args:
margin_par = float(args['margin'])
else:
- margin_par = 0.001
+ margin_par = float(self.app.defaults["tools_cutoutmargin"])
if 'dia' in args:
dia_par = float(args['dia'])
else:
- dia_par = 0.1
+ dia_par = float(self.app.defaults["tools_cutouttooldia"])
if 'gaps' in args:
gaps_par = args['gaps']
else:
- gaps_par = "4"
+ gaps_par = str(self.app.defaults["tools_gaps_ff"])
if 'gapsize' in args:
gapsize_par = float(args['gapsize'])
else:
- gapsize_par = 0.1
+ gapsize_par = float(self.app.defaults["tools_cutoutgapsize"])
+
+ if 'outname' in args:
+ outname = args['outname']
+ else:
+ outname = name + "_cutout"
try:
obj = self.app.collection.get_by_name(str(name))
@@ -128,7 +137,7 @@ class TclCommandCutout(TclCommand):
geo_obj.solid_geometry = cascaded_union([LineString(segment) for segment in cuts])
try:
- self.app.new_object("geometry", name + "_cutout", geo_init_me, plot=False)
+ self.app.new_object("geometry", outname, geo_init_me, plot=False)
self.app.inform.emit("[success] Rectangular-form Cutout operation finished.")
except Exception as e:
return "Operation failed: %s" % str(e)
diff --git a/tclCommands/TclCommandDelete.py b/tclCommands/TclCommandDelete.py
index 43a69693..1c482598 100644
--- a/tclCommands/TclCommandDelete.py
+++ b/tclCommands/TclCommandDelete.py
@@ -14,6 +14,8 @@ class TclCommandDelete(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['delete', 'del']
+ description = '%s %s' % ("--", "Deletes the given object. If no name is given will delete all objects.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
diff --git a/tclCommands/TclCommandDrillcncjob.py b/tclCommands/TclCommandDrillcncjob.py
index 64404fde..e0fd5dae 100644
--- a/tclCommands/TclCommandDrillcncjob.py
+++ b/tclCommands/TclCommandDrillcncjob.py
@@ -13,6 +13,8 @@ class TclCommandDrillcncjob(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['drillcncjob']
+ description = '%s %s' % ("--", "Generates a Drill CNC Job object from a Excellon Object.")
+
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str)
@@ -31,10 +33,10 @@ class TclCommandDrillcncjob(TclCommandSignaled):
('endz', float),
('dwelltime', float),
('pp', str),
- ('outname', str),
('opt_type', str),
('diatol', float),
- ('muted', int)
+ ('muted', str),
+ ('outname', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
@@ -60,7 +62,6 @@ class TclCommandDrillcncjob(TclCommandSignaled):
('dwelltime', 'Time to pause to allow the spindle to reach the full speed.\n'
'If it is not used in command then it will not be included'),
('pp', 'This is the Excellon preprocessor name: case_sensitive, no_quotes'),
- ('outname', 'Name of the resulting Geometry object.'),
('opt_type', 'Name of move optimization type. B by default for Basic OR-Tools, M for Metaheuristic OR-Tools'
'T from Travelling Salesman Algorithm. B and M works only for 64bit version of FlatCAM and '
'T works only for 32bit version of FlatCAM'),
@@ -69,7 +70,8 @@ class TclCommandDrillcncjob(TclCommandSignaled):
'diameter with value 1.0, in the Excellon we have a tool with dia = 1.05 and we set a tolerance '
'diatol = 5.0 then the drills with the dia = (0.95 ... 1.05) '
'in Excellon will be processed. Float number.'),
- ('muted', 'It will not put errors in the Shell or status bar.')
+ ('muted', 'It will not put errors in the Shell or status bar. Can be True (1) or False (0).'),
+ ('outname', 'Name of the resulting Geometry object.')
]),
'examples': ['drillcncjob test.TXT -drillz -1.5 -travelz 14 -feedrate 222 -feedrate_rapid 456 -spindlespeed 777'
' -toolchangez 33 -endz 22 -pp default\n'
@@ -94,7 +96,7 @@ class TclCommandDrillcncjob(TclCommandSignaled):
args['outname'] = name + "_cnc"
if 'muted' in args:
- muted = bool(args['muted'])
+ muted = bool(eval(args['muted']))
else:
muted = False
@@ -105,7 +107,7 @@ class TclCommandDrillcncjob(TclCommandSignaled):
return "fail"
if not isinstance(obj, FlatCAMExcellon):
- if muted == 0:
+ if muted is False:
self.raise_tcl_error('Expected FlatCAMExcellon, got %s %s.' % (name, type(obj)))
else:
return "fail"
@@ -143,7 +145,7 @@ class TclCommandDrillcncjob(TclCommandSignaled):
nr_diameters -= 1
if nr_diameters > 0:
- if muted == 0:
+ if muted is False:
self.raise_tcl_error("One or more tool diameters of the drills to be drilled passed to the "
"TclCommand are not actual tool diameters in the Excellon object.")
else:
@@ -164,7 +166,7 @@ class TclCommandDrillcncjob(TclCommandSignaled):
except Exception as e:
tools = 'all'
- if muted == 0:
+ if muted is False:
self.raise_tcl_error("Bad tools: %s" % str(e))
else:
return "fail"
diff --git a/tclCommands/TclCommandExportDXF.py b/tclCommands/TclCommandExportDXF.py
index 58aab483..1fe4a361 100644
--- a/tclCommands/TclCommandExportDXF.py
+++ b/tclCommands/TclCommandExportDXF.py
@@ -14,9 +14,11 @@ class TclCommandExportDXF(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['export_dxf', 'edxf']
+ description = '%s %s' % ("--", "Export a Geometry object as a DXF File.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
- ('obj_name', str),
+ ('name', str),
('filename', str)
])
@@ -29,12 +31,13 @@ class TclCommandExportDXF(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Export a Geometry Object as a DXF File.",
+ 'main': "Export a Geometry object as a DXF File.",
'args': collections.OrderedDict([
- ('obj_name', 'Name of the object to export.'),
- ('filename', 'Path to the file to export.')
+ ('name', 'Name of the Geometry object to export.'),
+ ('filename', 'Absolute path to file to export.\n'
+ 'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
]),
- 'examples': ['export_dxf my_geo path/my_file.dxf']
+ 'examples': ['export_dxf my_geo path/my_file.dxf', 'export_dxf my_geo D:/my_file.dxf']
}
def execute(self, args, unnamed_args):
@@ -44,6 +47,6 @@ class TclCommandExportDXF(TclCommand):
:param unnamed_args:
:return:
"""
- if 'filename' not in args:
- args['filename'] = self.app.defaults["global_last_save_folder"] + '/' + args['obj_name']
- self.app.export_dxf(use_thread=False,**args)
+ if 'filename' not in args:
+ args['filename'] = self.app.defaults["global_last_save_folder"] + '/' + args['name']
+ self.app.export_dxf(use_thread=False, **args)
diff --git a/tclCommands/TclCommandExportExcellon.py b/tclCommands/TclCommandExportExcellon.py
index 36e6e24c..a97ac054 100644
--- a/tclCommands/TclCommandExportExcellon.py
+++ b/tclCommands/TclCommandExportExcellon.py
@@ -14,9 +14,11 @@ class TclCommandExportExcellon(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['export_exc', 'ee', 'export_excellon']
+ description = '%s %s' % ("--", "Export a Excellon object as a Excellon File.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
- ('obj_name', str),
+ ('name', str),
('filename', str)
])
@@ -25,16 +27,17 @@ class TclCommandExportExcellon(TclCommand):
])
# array of mandatory options for current Tcl command: required = ['name','outname']
- required = ['obj_name']
+ required = ['name']
# structured help for current command, args needs to be ordered
help = {
- 'main': "Export a Excellon Object as a Excellon File.",
+ 'main': "Export a Excellon object as a Excellon File.",
'args': collections.OrderedDict([
- ('obj_name', 'Name of the object to export.'),
- ('filename', 'Path to the file to export.')
+ ('name', 'Name of the Excellon object to export.'),
+ ('filename', 'Absolute path to file to export.\n'
+ 'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
]),
- 'examples': ['export_excellon my_excellon path/my_file.drl']
+ 'examples': ['export_excellon my_excellon path/my_file.drl', 'export_excellon My_Excellon D:/drill_file.DRL']
}
def execute(self, args, unnamed_args):
@@ -44,6 +47,6 @@ class TclCommandExportExcellon(TclCommand):
:param unnamed_args:
:return:
"""
- if 'filename' not in args:
- args['filename'] = self.app.defaults["global_last_save_folder"] + '/' + args['obj_name']
- self.app.export_excellon(use_thread=False,**args)
+ if 'filename' not in args:
+ args['filename'] = self.app.defaults["global_last_save_folder"] + '/' + args['name']
+ self.app.export_excellon(use_thread=False, **args)
diff --git a/tclCommands/TclCommandExportGcode.py b/tclCommands/TclCommandExportGcode.py
index 2981e272..5572a285 100644
--- a/tclCommands/TclCommandExportGcode.py
+++ b/tclCommands/TclCommandExportGcode.py
@@ -13,7 +13,7 @@ class TclCommandExportGcode(TclCommandSignaled):
promises and send to background if there are promises.
- This export may be captured and passed as preable
+ This export may be captured and passed as preamble
to another "export_gcode" or "write_gcode" call to join G-Code.
example:
@@ -31,11 +31,13 @@ class TclCommandExportGcode(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['export_gcode']
+ description = '%s %s' % ("--", "Return Gcode into console output.")
+
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
('preamble', str),
- ('postamble', str)
+ ('postamble', str),
])
# dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
@@ -49,8 +51,8 @@ class TclCommandExportGcode(TclCommandSignaled):
'main': "Export gcode into console output.",
'args': collections.OrderedDict([
('name', 'Name of the source Geometry object. Required.'),
- ('preamble', 'Prepend GCODE.'),
- ('postamble', 'Append GCODE.')
+ ('preamble', 'Prepend GCode to the original GCode.'),
+ ('postamble', 'Append GCode o the original GCode.'),
]),
'examples': ['export_gcode geo_name -preamble "G01 X10 Y10" -postamble "G00 X20 Y20\nM04"']
}
@@ -78,4 +80,5 @@ class TclCommandExportGcode(TclCommandSignaled):
self.raise_tcl_error('!!!Promises exists, but should not here!!!')
del args['name']
- return obj.get_gcode(**args)
+ modified_gcode = obj.get_gcode(**args)
+ return
diff --git a/tclCommands/TclCommandExportGerber.py b/tclCommands/TclCommandExportGerber.py
index 0fc7b0aa..a4f143d9 100644
--- a/tclCommands/TclCommandExportGerber.py
+++ b/tclCommands/TclCommandExportGerber.py
@@ -14,9 +14,11 @@ class TclCommandExportGerber(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['export_grb', 'egr', 'export_gerber']
+ description = '%s %s' % ("--", "Export a Gerber object as a Gerber File.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
- ('obj_name', str),
+ ('name', str),
('filename', str)
])
@@ -31,8 +33,9 @@ class TclCommandExportGerber(TclCommand):
help = {
'main': "Export a Gerber Object as a Gerber File.",
'args': collections.OrderedDict([
- ('obj_name', 'Name of the object to export. Required.'),
- ('filename', 'Path to the file to export.')
+ ('name', 'Name of the object to export. Required.'),
+ ('filename', 'Absolute path to file to export.\n'
+ 'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
]),
'examples': ['export_gerber my_gerber path/my_file.gbr']
}
@@ -44,6 +47,6 @@ class TclCommandExportGerber(TclCommand):
:param unnamed_args:
:return:
"""
- if 'filename' not in args:
- args['filename'] = self.app.defaults["global_last_save_folder"] + '/' + args['obj_name']
+ if 'filename' not in args:
+ args['filename'] = self.app.defaults["global_last_save_folder"] + '/' + args['name']
self.app.export_gerber(use_thread=False,**args)
diff --git a/tclCommands/TclCommandExportSVG.py b/tclCommands/TclCommandExportSVG.py
index bc6efce9..ae5179c4 100644
--- a/tclCommands/TclCommandExportSVG.py
+++ b/tclCommands/TclCommandExportSVG.py
@@ -1,6 +1,7 @@
from tclCommands.TclCommand import TclCommand
import collections
+from copy import copy
class TclCommandExportSVG(TclCommand):
@@ -14,6 +15,8 @@ class TclCommandExportSVG(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['export_svg']
+ description = '%s %s' % ("--", "Export a Geometry object as a SVG File.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
@@ -31,10 +34,11 @@ class TclCommandExportSVG(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Export a Geometry Object as a SVG File.",
+ 'main': "Export a Geometry object as a SVG File.",
'args': collections.OrderedDict([
('name', 'Name of the object export. Required.'),
- ('filename', 'Path to the file to export.'),
+ ('filename', 'Absolute path to file to export.\n'
+ 'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
('scale_factor', 'Multiplication factor used for scaling line widths during export.')
]),
'examples': ['export_svg my_geometry my_file.svg']
diff --git a/tclCommands/TclCommandExteriors.py b/tclCommands/TclCommandExteriors.py
index cb3f041a..de4e6901 100644
--- a/tclCommands/TclCommandExteriors.py
+++ b/tclCommands/TclCommandExteriors.py
@@ -12,6 +12,9 @@ class TclCommandExteriors(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['exteriors', 'ext']
+ description = '%s %s' % ("--", "Get exteriors of polygons from a Geometry object and "
+ "from them create a new Geometry object.")
+
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str)
@@ -27,7 +30,7 @@ class TclCommandExteriors(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Get exteriors of polygons.",
+ 'main': "Get exteriors of polygons from a Geometry object and from them create a new Geometry object.",
'args': collections.OrderedDict([
('name', 'Name of the source Geometry object. Required.'),
('outname', 'Name of the resulting Geometry object.')
diff --git a/tclCommands/TclCommandFollow.py b/tclCommands/TclCommandFollow.py
index 0ca8ab5e..e4e13359 100644
--- a/tclCommands/TclCommandFollow.py
+++ b/tclCommands/TclCommandFollow.py
@@ -12,6 +12,8 @@ class TclCommandFollow(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['follow']
+ description = '%s %s' % ("--", "Creates a Geometry object following Gerber paths.")
+
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str)
@@ -27,7 +29,7 @@ class TclCommandFollow(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Creates a geometry object following gerber paths.",
+ 'main': "Creates a Geometry object following Gerber paths.",
'args': collections.OrderedDict([
('name', 'Object name to follow. Required.'),
('outname', 'Name of the resulting Geometry object.')
@@ -64,4 +66,4 @@ class TclCommandFollow(TclCommandSignaled):
return "Operation failed: %s" % str(e)
# in the end toggle the visibility of the origin object so we can see the generated Geometry
- self.app.collection.get_by_name(name).ui.plot_cb.toggle()
\ No newline at end of file
+ # self.app.collection.get_by_name(name).ui.plot_cb.toggle()
\ No newline at end of file
diff --git a/tclCommands/TclCommandGeoCutout.py b/tclCommands/TclCommandGeoCutout.py
index 555c38bc..40118c53 100644
--- a/tclCommands/TclCommandGeoCutout.py
+++ b/tclCommands/TclCommandGeoCutout.py
@@ -24,6 +24,8 @@ class TclCommandGeoCutout(TclCommandSignaled):
# names for backward compatibility (add_poly, add_polygon)
aliases = ['geocutout', 'geoc']
+ description = '%s %s' % ("--", "Creates board cutout from an object (Gerber or Geometry) of any shape.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
@@ -44,7 +46,7 @@ class TclCommandGeoCutout(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': 'Creates board cutout from an object (Gerber or Geometry) of any shape',
+ 'main': 'Creates board cutout from an object (Gerber or Geometry) of any shape.',
'args': collections.OrderedDict([
('name', 'Name of the object to be cutout. Required'),
('dia', 'Tool diameter.'),
@@ -141,22 +143,22 @@ class TclCommandGeoCutout(TclCommandSignaled):
if 'margin' in args:
margin = float(args['margin'])
else:
- margin = 0.001
+ margin = float(self.app.defaults["tools_cutoutmargin"])
if 'dia' in args:
dia = float(args['dia'])
else:
- dia = 0.1
+ dia = float(self.app.defaults["tools_cutouttooldia"])
if 'gaps' in args:
gaps = args['gaps']
else:
- gaps = 4
+ gaps = str(self.app.defaults["tools_gaps_ff"])
if 'gapsize' in args:
gapsize = float(args['gapsize'])
else:
- gapsize = 0.1
+ gapsize = float(self.app.defaults["tools_cutoutgapsize"])
if 'outname' in args:
outname = args['outname']
diff --git a/tclCommands/TclCommandGeoUnion.py b/tclCommands/TclCommandGeoUnion.py
index ac4fa4ea..4a698a2d 100644
--- a/tclCommands/TclCommandGeoUnion.py
+++ b/tclCommands/TclCommandGeoUnion.py
@@ -15,6 +15,8 @@ class TclCommandGeoUnion(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['geo_union']
+ description = '%s %s' % ("--", "Run the Union (join) geometry operation on the elements of a Geometry object.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
diff --git a/tclCommands/TclCommandGetNames.py b/tclCommands/TclCommandGetNames.py
index 7cca9a46..6bb45e14 100644
--- a/tclCommands/TclCommandGetNames.py
+++ b/tclCommands/TclCommandGetNames.py
@@ -14,6 +14,9 @@ class TclCommandGetNames(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['get_names']
+ description = '%s %s' % ("--", "Return to TCL the list of the project objects names "
+ "as a string with names separated by the '\\n' char.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
@@ -29,7 +32,8 @@ class TclCommandGetNames(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': 'Lists the names of objects in the project. It returns a string with names separated by \n',
+ 'main': 'Lists the names of objects in the project. '
+ 'It returns a string with names separated by "\\n" character',
'args': collections.OrderedDict([
]),
diff --git a/tclCommands/TclCommandGetSys.py b/tclCommands/TclCommandGetSys.py
index f98c3315..d5032464 100644
--- a/tclCommands/TclCommandGetSys.py
+++ b/tclCommands/TclCommandGetSys.py
@@ -21,6 +21,8 @@ class TclCommandGetSys(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['get_sys', 'getsys']
+ description = '%s %s' % ("--", "Returns to TCL the value for the entered system variable.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str)
@@ -36,7 +38,7 @@ class TclCommandGetSys(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Returns the value of the targeted system variable.",
+ 'main': "Returns to TCL the value for the entered system variable.",
'args': collections.OrderedDict([
('name', 'Name of the system variable. Required.'),
]),
diff --git a/tclCommands/TclCommandImportSvg.py b/tclCommands/TclCommandImportSvg.py
index 0617090e..9ef67e27 100644
--- a/tclCommands/TclCommandImportSvg.py
+++ b/tclCommands/TclCommandImportSvg.py
@@ -12,6 +12,8 @@ class TclCommandImportSvg(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['import_svg']
+ description = '%s %s' % ("--", "Import a SVG file as a Geometry (or Gerber) Object.")
+
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('filename', str)
@@ -28,10 +30,11 @@ class TclCommandImportSvg(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Import an SVG file as a Geometry Object..",
+ 'main': "Import a SVG file as a Geometry (or Gerber) Object.",
'args': collections.OrderedDict([
- ('filename', 'Absolute path to file to open. Required.'),
- ('type', 'Import as gerber or geometry(default).'),
+ ('filename', 'Absolute path to file to open. Required.\n'
+ 'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
+ ('type', 'Import as a Gerber or Geometry (default) object. Values can be: "geometry" or "gerber"'),
('outname', 'Name of the resulting Geometry object.')
]),
'examples': ['import_svg D:\\my_beautiful_svg_file.SVG']
@@ -63,12 +66,12 @@ class TclCommandImportSvg(TclCommandSignaled):
outname = filename.split('/')[-1].split('\\')[-1]
if 'type' in args:
- obj_type = args['type']
+ obj_type = args['type'].lower()
else:
obj_type = 'geometry'
if obj_type != "geometry" and obj_type != "gerber":
- self.raise_tcl_error("Option type can be 'geopmetry' or 'gerber' only, got '%s'." % obj_type)
+ self.raise_tcl_error("Option type can be 'geometry' or 'gerber' only, got '%s'." % obj_type)
with self.app.proc_container.new("Import SVG"):
diff --git a/tclCommands/TclCommandInteriors.py b/tclCommands/TclCommandInteriors.py
index f22ef1db..a7655204 100644
--- a/tclCommands/TclCommandInteriors.py
+++ b/tclCommands/TclCommandInteriors.py
@@ -12,6 +12,9 @@ class TclCommandInteriors(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['interiors']
+ description = '%s %s' % ("--", "Create a new Geometry object with the 'interiors' geo "
+ "elements of the source object.")
+
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str)
@@ -27,7 +30,8 @@ class TclCommandInteriors(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Return the interiors of polygons as a list of Shapely geometry elements.",
+ 'main': "Create a new Geometry object with the 'interiors' geometric elements of "
+ "the specified source Geometry object.",
'args': collections.OrderedDict([
('name', 'Name of the source Geometry object. Required.'),
('outname', 'Name of the resulting Geometry object.')
diff --git a/tclCommands/TclCommandIsolate.py b/tclCommands/TclCommandIsolate.py
index 542dd3c3..337280df 100644
--- a/tclCommands/TclCommandIsolate.py
+++ b/tclCommands/TclCommandIsolate.py
@@ -19,6 +19,8 @@ class TclCommandIsolate(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['isolate']
+ description = '%s %s' % ("--", "Creates isolation routing Geometry for the specified Gerber object.")
+
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str)
@@ -29,7 +31,7 @@ class TclCommandIsolate(TclCommandSignaled):
('dia', float),
('passes', int),
('overlap', float),
- ('combine', bool),
+ ('combine', str),
('outname', str),
('follow', str),
('iso_type', int)
@@ -41,14 +43,14 @@ class TclCommandIsolate(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Creates isolation routing geometry for the given Gerber.",
+ 'main': "Creates isolation routing Geometry for the specified Gerber object.",
'args': collections.OrderedDict([
('name', 'Name of the source object. Required.'),
('dia', 'Tool diameter.'),
('passes', 'Passes of tool width.'),
('overlap', 'Percentage of tool diameter to overlap current pass over previous pass. Float [0, 99.9999]\n'
'E.g: for a 25% from tool diameter overlap use -overlap 25'),
- ('combine', 'Combine all passes into one geometry. Can be True or False, 1 or 0'),
+ ('combine', 'Combine all passes into one geometry. Can be True (1) or False (0)'),
('outname', 'Name of the resulting Geometry object.'),
('follow', 'Create a Geometry that follows the Gerber path.'),
('iso_type', 'A value of 0 will isolate exteriors, a value of 1 will isolate interiors '
@@ -82,7 +84,9 @@ class TclCommandIsolate(TclCommandSignaled):
# evaluate this parameter so True, False, 0 and 1 works
if "combine" in args:
- args['combine'] = eval(args['combine'])
+ args['combine'] = bool(eval(args['combine']))
+ else:
+ args['combine'] = bool(eval(self.app.defaults["gerber_combine_passes"]))
obj = self.app.collection.get_by_name(name)
if obj is None:
diff --git a/tclCommands/TclCommandJoinExcellon.py b/tclCommands/TclCommandJoinExcellon.py
index c385b55c..efea9e7d 100644
--- a/tclCommands/TclCommandJoinExcellon.py
+++ b/tclCommands/TclCommandJoinExcellon.py
@@ -15,6 +15,9 @@ class TclCommandJoinExcellon(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['join_excellon', 'join_excellons']
+ description = '%s %s' % ("--", "Merge two or more Excellon objects drills and create "
+ "a new Excellon object with them.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('outname', str),
@@ -61,7 +64,7 @@ class TclCommandJoinExcellon(TclCommand):
def initialize(obj_, app):
FlatCAMExcellon.merge(self, objs, obj_)
- if objs:
+ if objs and len(objs) >= 2:
self.app.new_object("excellon", outname, initialize, plot=False)
else:
- return "No Excellon objects to be joined."
+ return "No Excellon objects to be joined or less than two Excellon objects specified for merging."
diff --git a/tclCommands/TclCommandJoinGeometry.py b/tclCommands/TclCommandJoinGeometry.py
index d3208877..25dcc26d 100644
--- a/tclCommands/TclCommandJoinGeometry.py
+++ b/tclCommands/TclCommandJoinGeometry.py
@@ -15,6 +15,8 @@ class TclCommandJoinGeometry(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['join_geometries', 'join_geometry']
+ description = '%s %s' % ("--", "Merge two or more Geometry objects and create a new Geometry object.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('outname', str),
@@ -62,7 +64,7 @@ class TclCommandJoinGeometry(TclCommand):
def initialize(obj_, app):
FlatCAMGeometry.merge(self, objs, obj_)
- if objs:
+ if objs and len(objs) >= 2:
self.app.new_object("geometry", outname, initialize, plot=False)
else:
- return "No Geometry objects to be joined."
+ return "No Geometry objects to be joined or less than two Geometry objects specified for merging."
diff --git a/tclCommands/TclCommandListSys.py b/tclCommands/TclCommandListSys.py
index cff9ca06..d9e359c8 100644
--- a/tclCommands/TclCommandListSys.py
+++ b/tclCommands/TclCommandListSys.py
@@ -19,6 +19,8 @@ class TclCommandListSys(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['list_sys', 'listsys']
+ description = '%s %s' % ("--", "Outputs in Tcl Shell the list with the names of system variables.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('selection', str),
diff --git a/tclCommands/TclCommandMillDrills.py b/tclCommands/TclCommandMillDrills.py
index 1e8684d0..e4e3df07 100644
--- a/tclCommands/TclCommandMillDrills.py
+++ b/tclCommands/TclCommandMillDrills.py
@@ -23,6 +23,8 @@ class TclCommandMillDrills(TclCommandSignaled):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['milldrills', 'milld']
+ description = '%s %s' % ("--", "Create a Geometry Object for milling drill holes from Excellon.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str)
@@ -34,7 +36,7 @@ class TclCommandMillDrills(TclCommandSignaled):
('milled_dias', str),
('outname', str),
('tooldia', float),
- ('use_thread', bool),
+ ('use_thread', str),
('diatol', float)
])
@@ -43,7 +45,7 @@ class TclCommandMillDrills(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Create Geometry Object for milling drill holes from Excellon.",
+ 'main': "Create a Geometry Object for milling drill holes from Excellon.",
'args': collections.OrderedDict([
('name', 'Name of the Excellon Object. Required.'),
('milled_dias', 'Comma separated tool diameters of the drills to be milled (example: 0.6, 1.0 or 3.125).\n'
@@ -51,8 +53,8 @@ class TclCommandMillDrills(TclCommandSignaled):
'WARNING: no spaces are allowed in the list of tools.\n'
'As a precaution you can enclose them with quotes.'),
('tooldia', 'Diameter of the milling tool (example: 0.1).'),
- ('outname', 'Name of object to be created holding the milled geometries.'),
- ('use_thread', 'If to use multithreading: True or False.'),
+ ('outname', 'Name of Geometry object to be created holding the milled geometries.'),
+ ('use_thread', 'If to use multithreading: True (1) or False (0).'),
('diatol', 'Tolerance. Percentange (0.0 ... 100.0) within which dias in milled_dias will be judged to be '
'the same as the ones in the tools from the Excellon object. E.g: if in milled_dias we have a '
'diameter with value 1.0, in the Excellon we have a tool with dia = 1.05 and we set a tolerance '
@@ -84,7 +86,9 @@ class TclCommandMillDrills(TclCommandSignaled):
args['outname'] = name + "_mill_drills"
if 'use_thread' in args:
- args['use_thread'] = bool(args['use_thread'])
+ args['use_thread'] = bool(eval(args['use_thread']))
+ else:
+ args['use_thread'] = False
if not obj.drills:
self.raise_tcl_error("The Excellon object has no drills: %s" % name)
diff --git a/tclCommands/TclCommandMillSlots.py b/tclCommands/TclCommandMillSlots.py
index af6070be..7d6b1f0c 100644
--- a/tclCommands/TclCommandMillSlots.py
+++ b/tclCommands/TclCommandMillSlots.py
@@ -23,6 +23,8 @@ class TclCommandMillSlots(TclCommandSignaled):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['millslots', 'mills']
+ description = '%s %s' % ("--", "Create a Geometry Object for milling slot holes from Excellon.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str)
@@ -34,7 +36,7 @@ class TclCommandMillSlots(TclCommandSignaled):
('milled_dias', str),
('outname', str),
('tooldia', float),
- ('use_thread', bool),
+ ('use_thread', str),
('diatol', float)
])
@@ -43,7 +45,7 @@ class TclCommandMillSlots(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Create Geometry Object for milling slot holes from Excellon.",
+ 'main': "Create a Geometry Object for milling slot holes from Excellon.",
'args': collections.OrderedDict([
('name', 'Name of the Excellon Object. Required.'),
('milled_dias', 'Comma separated tool diameters of the slots to be milled (example: 0.6, 1.0 or 3.125).\n'
@@ -52,7 +54,7 @@ class TclCommandMillSlots(TclCommandSignaled):
'As a precaution you can enclose them with quotes.'),
('tooldia', 'Diameter of the milling tool (example: 0.1).'),
('outname', 'Name of object to be created holding the milled geometries.'),
- ('use_thread', 'If to use multithreading: True or False.'),
+ ('use_thread', 'If to use multithreading: True (1) or False (0).'),
('diatol', 'Tolerance. Percentange (0.0 ... 100.0) within which dias in milled_dias will be judged to be '
'the same as the ones in the tools from the Excellon object. E.g: if in milled_dias we have a '
'diameter with value 1.0, in the Excellon we have a tool with dia = 1.05 and we set a tolerance '
@@ -84,12 +86,14 @@ class TclCommandMillSlots(TclCommandSignaled):
args['outname'] = name + "_mill_slots"
if 'use_thread' in args:
- args['use_thread'] = bool(args['use_thread'])
+ args['use_thread'] = bool(eval(args['use_thread']))
+ else:
+ args['use_thread'] = False
if not obj.slots:
self.raise_tcl_error("The Excellon object has no slots: %s" % name)
- units = self.app.defaults['units'].upper()
+ # units = self.app.defaults['units'].upper()
try:
if 'milled_dias' in args and args['milled_dias'] != 'all':
diameters = [x.strip() for x in args['milled_dias'].split(",")]
diff --git a/tclCommands/TclCommandMirror.py b/tclCommands/TclCommandMirror.py
index cc29852f..5d4425ab 100644
--- a/tclCommands/TclCommandMirror.py
+++ b/tclCommands/TclCommandMirror.py
@@ -13,6 +13,8 @@ class TclCommandMirror(TclCommandSignaled):
# old names for backward compatibility (add_poly, add_polygon)
aliases = ['mirror']
+ description = '%s %s' % ("--", "Will mirror the geometry of a named object. Does not create a new object.")
+
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
@@ -32,7 +34,7 @@ class TclCommandMirror(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Will mirror an named object.",
+ 'main': "Will mirror the geometry of a named object. Does not create a new object.",
'args': collections.OrderedDict([
('name', 'Name of the object (Gerber, Geometry or Excellon) to be mirrored. Required.'),
('axis', 'Mirror axis parallel to the X or Y axis.'),
diff --git a/tclCommands/TclCommandNew.py b/tclCommands/TclCommandNew.py
index 66ff83b9..9a2af1f2 100644
--- a/tclCommands/TclCommandNew.py
+++ b/tclCommands/TclCommandNew.py
@@ -11,6 +11,8 @@ class TclCommandNew(TclCommand):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['new']
+ description = '%s %s' % ("--", "Starts a new project. Clears objects from memory.")
+
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict()
diff --git a/tclCommands/TclCommandNewExcellon.py b/tclCommands/TclCommandNewExcellon.py
index c1322133..61689d6f 100644
--- a/tclCommands/TclCommandNewExcellon.py
+++ b/tclCommands/TclCommandNewExcellon.py
@@ -18,6 +18,8 @@ class TclCommandNewExcellon(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['new_excellon']
+ description = '%s %s' % ("--", "Creates a new empty Excellon object.")
+
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
diff --git a/tclCommands/TclCommandNewGeometry.py b/tclCommands/TclCommandNewGeometry.py
index 4af616c6..8fee996e 100644
--- a/tclCommands/TclCommandNewGeometry.py
+++ b/tclCommands/TclCommandNewGeometry.py
@@ -11,6 +11,8 @@ class TclCommandNewGeometry(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['new_geometry']
+ description = '%s %s' % ("--", "Creates a new empty Geometry object.")
+
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
diff --git a/tclCommands/TclCommandNewGerber.py b/tclCommands/TclCommandNewGerber.py
index 7a667813..9c162965 100644
--- a/tclCommands/TclCommandNewGerber.py
+++ b/tclCommands/TclCommandNewGerber.py
@@ -18,6 +18,8 @@ class TclCommandNewGerber(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['new_gerber']
+ description = '%s %s' % ("--", "Creates a new empty Gerber object.")
+
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
diff --git a/tclCommands/TclCommandNregions.py b/tclCommands/TclCommandNregions.py
index a4146792..f4b2a228 100644
--- a/tclCommands/TclCommandNregions.py
+++ b/tclCommands/TclCommandNregions.py
@@ -22,6 +22,8 @@ class TclCommandNregions(TclCommand):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['non_copper_regions', 'ncr']
+ description = '%s %s' % ("--", "Creates a Geometry object with the non-copper regions.")
+
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str)
@@ -31,7 +33,7 @@ class TclCommandNregions(TclCommand):
option_types = collections.OrderedDict([
('outname', str),
('margin', float),
- ('rounded', bool)
+ ('rounded', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
@@ -39,13 +41,13 @@ class TclCommandNregions(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Creates a geometry object with the non-copper regions.",
+ 'main': "Creates a Geometry object with the non-copper regions.",
'args': collections.OrderedDict([
('name', 'Object name for which to create non-copper regions. String. Required.'),
('outname', 'Name of the resulting Geometry object. String.'),
('margin', "Specify the edge of the PCB by drawing a box around all objects with this minimum distance. "
"Float number."),
- ('rounded', "Resulting geometry will have rounded corners. True or False.")
+ ('rounded', "Resulting geometry will have rounded corners. True (1) or False (0).")
]),
'examples': ['ncr name -margin 0.1 -rounded True -outname name_ncr']
}
@@ -78,7 +80,7 @@ class TclCommandNregions(TclCommand):
if 'rounded' not in args:
args['rounded'] = self.app.defaults["gerber_noncopperrounded"]
- rounded = bool(args['rounded'])
+ rounded = bool(eval(args['rounded']))
del args['name']
diff --git a/tclCommands/TclCommandOffset.py b/tclCommands/TclCommandOffset.py
index 6f5fd1c7..91fd46fc 100644
--- a/tclCommands/TclCommandOffset.py
+++ b/tclCommands/TclCommandOffset.py
@@ -14,6 +14,8 @@ class TclCommandOffset(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['offset']
+ description = '%s %s' % ("--", "Will offset the geometry of a named object. Does not create a new object.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
diff --git a/tclCommands/TclCommandOpenExcellon.py b/tclCommands/TclCommandOpenExcellon.py
index 167db227..5fc7cc64 100644
--- a/tclCommands/TclCommandOpenExcellon.py
+++ b/tclCommands/TclCommandOpenExcellon.py
@@ -11,6 +11,8 @@ class TclCommandOpenExcellon(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['open_excellon']
+ description = '%s %s' % ("--", "Opens an Excellon file, parse it and create a Excellon object from it.")
+
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
@@ -28,7 +30,7 @@ class TclCommandOpenExcellon(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Opens an Excellon file.",
+ 'main': "Opens an Excellon file, parse it and create a Excellon object from it.",
'args': collections.OrderedDict([
('filename', 'Absolute path to file to open. Required.\n'
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
diff --git a/tclCommands/TclCommandOpenGCode.py b/tclCommands/TclCommandOpenGCode.py
index 5eaa83c9..9b5db715 100644
--- a/tclCommands/TclCommandOpenGCode.py
+++ b/tclCommands/TclCommandOpenGCode.py
@@ -12,6 +12,8 @@ class TclCommandOpenGCode(TclCommandSignaled):
# backward compatibility (add_poly, add_polygon)
aliases = ['open_gcode']
+ description = '%s %s' % ("--", "Opens an GCode file, parse it and create a GCode object from it.")
+
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
@@ -29,7 +31,7 @@ class TclCommandOpenGCode(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Opens a G-Code file.",
+ 'main': "Opens an GCode file, parse it and create a GCode object from it.",
'args': collections.OrderedDict([
('filename', 'Absolute path to file to open. Required.\n'
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
diff --git a/tclCommands/TclCommandOpenGerber.py b/tclCommands/TclCommandOpenGerber.py
index 037882a1..c473d0de 100644
--- a/tclCommands/TclCommandOpenGerber.py
+++ b/tclCommands/TclCommandOpenGerber.py
@@ -13,6 +13,8 @@ class TclCommandOpenGerber(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['open_gerber']
+ description = '%s %s' % ("--", "Opens an Gerber file, parse it and create a Gerber object from it.")
+
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('filename', str)
diff --git a/tclCommands/TclCommandOpenProject.py b/tclCommands/TclCommandOpenProject.py
index 3dddad61..e1e1cd05 100644
--- a/tclCommands/TclCommandOpenProject.py
+++ b/tclCommands/TclCommandOpenProject.py
@@ -11,6 +11,8 @@ class TclCommandOpenProject(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['open_project']
+ description = '%s %s' % ("--", "Opens an FlatCAm project file, parse it and recreate all the objects.")
+
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
@@ -28,7 +30,7 @@ class TclCommandOpenProject(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Opens a FlatCAM project.",
+ 'main': "Opens an FlatCAm project file, parse it and recreate all the objects.",
'args': collections.OrderedDict([
('filename', 'Absolute path to file to open. Required.\n'
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
diff --git a/tclCommands/TclCommandOptions.py b/tclCommands/TclCommandOptions.py
index ab22599e..a6057bdc 100644
--- a/tclCommands/TclCommandOptions.py
+++ b/tclCommands/TclCommandOptions.py
@@ -11,6 +11,9 @@ class TclCommandOptions(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['options']
+ description = '%s %s' % ("--", "Will return the options (settings) for an object as a string "
+ "with values separated by \\n.")
+
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
diff --git a/tclCommands/TclCommandPaint.py b/tclCommands/TclCommandPaint.py
index e300e0c5..d0b099be 100644
--- a/tclCommands/TclCommandPaint.py
+++ b/tclCommands/TclCommandPaint.py
@@ -22,6 +22,8 @@ class TclCommandPaint(TclCommand):
# Array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['paint']
+ description = '%s %s' % ("--", "Paint polygons in the specified object by covering them with toolpaths.")
+
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
@@ -34,12 +36,12 @@ class TclCommandPaint(TclCommand):
('order', str),
('margin', float),
('method', str),
- ('connect', bool),
- ('contour', bool),
+ ('connect', str),
+ ('contour', str),
- ('all', bool),
- ('single', bool),
- ('ref', bool),
+ ('all', str),
+ ('single', str),
+ ('ref', str),
('box', str),
('x', float),
('y', float),
@@ -51,7 +53,7 @@ class TclCommandPaint(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Paint polygons",
+ 'main': "Paint polygons in the specified object by covering them with toolpaths.",
'args': collections.OrderedDict([
('name', 'Name of the source Geometry object. String.'),
('tooldia', 'Diameter of the tool to be used. Can be a comma separated list of diameters. No space is '
@@ -65,11 +67,12 @@ class TclCommandPaint(TclCommand):
'"fwd" -> tools are ordered from smallest to biggest.'
'"rev" -> tools are ordered from biggest to smallest.'),
('method', 'Algorithm for painting. Can be: "standard", "seed" or "lines".'),
- ('connect', 'Draw lines to minimize tool lifts. True or False'),
- ('contour', 'Cut around the perimeter of the painting. True or False'),
- ('all', 'Paint all polygons in the object. True or False'),
- ('single', 'Paint a single polygon specified by "x" and "y" parameters. True or False'),
- ('ref', 'Paint all polygons within a specified object with the name in "box" parameter. True or False'),
+ ('connect', 'Draw lines to minimize tool lifts. True (1) or False (0)'),
+ ('contour', 'Cut around the perimeter of the painting. True (1) or False (0)'),
+ ('all', 'Paint all polygons in the object. True (1) or False (0)'),
+ ('single', 'Paint a single polygon specified by "x" and "y" parameters. True (1) or False (0)'),
+ ('ref', 'Paint all polygons within a specified object with the name in "box" parameter. '
+ 'True (1) or False (0)'),
('box', 'name of the object to be used as paint reference when selecting "ref"" True. String.'),
('x', 'X value of coordinate for the selection of a single polygon. Float number.'),
('y', 'Y value of coordinate for the selection of a single polygon. Float number.'),
@@ -124,12 +127,12 @@ class TclCommandPaint(TclCommand):
method = str(self.app.defaults["tools_paintmethod"])
if 'connect' in args:
- connect = bool(args['connect'])
+ connect = bool(eval(args['connect']))
else:
connect = eval(str(self.app.defaults["tools_pathconnect"]))
if 'contour' in args:
- contour = bool(args['contour'])
+ contour = bool(eval(args['contour']))
else:
contour = eval(str(self.app.defaults["tools_paintcontour"]))
@@ -199,7 +202,7 @@ class TclCommandPaint(TclCommand):
return "Object not found: %s" % name
# Paint all polygons in the painted object
- if 'all' in args and bool(args['all']) is True:
+ if 'all' in args and bool(eval(args['all'])) is True:
self.app.paint_tool.paint_poly_all(obj=obj,
tooldia=tooldia,
overlap=overlap,
@@ -215,7 +218,7 @@ class TclCommandPaint(TclCommand):
return
# Paint single polygon in the painted object
- elif 'single' in args and bool(args['single']) is True:
+ elif 'single' in args and bool(eval(args['single'])) is True:
if 'x' not in args or 'y' not in args:
self.raise_tcl_error('%s' % _("Expected -x and -y ."))
else:
@@ -238,7 +241,7 @@ class TclCommandPaint(TclCommand):
return
# Paint all polygons found within the box object from the the painted object
- elif 'ref' in args and bool(args['ref']) is True:
+ elif 'ref' in args and bool(eval(args['ref'])) is True:
if 'box' not in args:
self.raise_tcl_error('%s' % _("Expected -box ."))
else:
diff --git a/tclCommands/TclCommandPanelize.py b/tclCommands/TclCommandPanelize.py
index 71d50199..e2c64dbc 100644
--- a/tclCommands/TclCommandPanelize.py
+++ b/tclCommands/TclCommandPanelize.py
@@ -19,7 +19,10 @@ class TclCommandPanelize(TclCommand):
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
- aliases = ['panelize','pan', 'panel']
+ aliases = ['panelize', 'pan', 'panel']
+
+ description = '%s %s' % ("--", "Create a new object with an array of duplicates of the original geometry, "
+ "arranged in a grid.")
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
@@ -34,7 +37,7 @@ class TclCommandPanelize(TclCommand):
('spacing_rows', float),
('box', str),
('outname', str),
- ('run_threaded', bool)
+ ('run_threaded', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
@@ -42,7 +45,7 @@ class TclCommandPanelize(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': 'Rectangular panelizing.',
+ 'main': 'Create a new object with an array of duplicates of the original geometry, arranged in a grid.',
'args': collections.OrderedDict([
('name', 'Name of the object to panelize.'),
('box', 'Name of object which acts as box (cutout for example.)'
@@ -52,7 +55,7 @@ class TclCommandPanelize(TclCommand):
('columns', 'Number of columns.'),
('rows', 'Number of rows;'),
('outname', 'Name of the new geometry object.'),
- ('run_threaded', 'False = non-threaded || True = threaded')
+ ('run_threaded', 'False (0) = non-threaded execution or True (1) = threaded execution')
]),
'examples': [
'panelize obj_name',
@@ -77,7 +80,7 @@ class TclCommandPanelize(TclCommand):
# Get source object.
try:
obj = self.app.collection.get_by_name(str(name))
- except Exception as e:
+ except Exception:
return "Could not retrieve object: %s" % name
if obj is None:
@@ -111,7 +114,7 @@ class TclCommandPanelize(TclCommand):
outname = name + '_panelized'
if 'run_threaded' in args:
- threaded = bool(args['run_threaded'])
+ threaded = bool(eval(args['run_threaded']))
else:
threaded = False
diff --git a/tclCommands/TclCommandPlotAll.py b/tclCommands/TclCommandPlotAll.py
index d3833dd0..8efae5fb 100644
--- a/tclCommands/TclCommandPlotAll.py
+++ b/tclCommands/TclCommandPlotAll.py
@@ -14,6 +14,8 @@ class TclCommandPlotAll(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['plot_all']
+ description = '%s %s' % ("--", "Plots all objects on GUI.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
@@ -29,7 +31,7 @@ class TclCommandPlotAll(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Updates the plot on the user interface.",
+ 'main': "Plots all objects on GUI.",
'args': collections.OrderedDict([
]),
diff --git a/tclCommands/TclCommandPlotObjects.py b/tclCommands/TclCommandPlotObjects.py
index 1df57886..34585efb 100644
--- a/tclCommands/TclCommandPlotObjects.py
+++ b/tclCommands/TclCommandPlotObjects.py
@@ -21,6 +21,8 @@ class TclCommandPlotObjects(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['plot_objects']
+ description = '%s %s' % ("--", "Plot a specified list of objects in GUI.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('names', str)
@@ -36,11 +38,12 @@ class TclCommandPlotObjects(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Plot a list of objects.",
+ 'main': "Plot a specified list of objects in GUI.",
'args': collections.OrderedDict([
- ('names', "A list of object names to be plotted separated by comma. Required.")
+ ('names', "A list of object names to be plotted separated by comma. Required.\n"
+ "WARNING: no spaces are allowed. If unsure enclose the entire list with quotes.")
]),
- 'examples': ["plot_objects gerber_obj.GRB, excellon_obj.DRL"]
+ 'examples': ["plot_objects gerber_obj.GRB,excellon_obj.DRL"]
}
def execute(self, args, unnamed_args):
diff --git a/tclCommands/TclCommandQuit.py b/tclCommands/TclCommandQuit.py
index e0470bdb..34e5f687 100644
--- a/tclCommands/TclCommandQuit.py
+++ b/tclCommands/TclCommandQuit.py
@@ -21,6 +21,8 @@ class TclCommandQuit(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['quit_flatcam']
+ description = '%s %s' % ("--", "Tcl shell command to quit FlatCAM from Tcl shell.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
diff --git a/tclCommands/TclCommandSaveProject.py b/tclCommands/TclCommandSaveProject.py
index 899247a2..049d7e74 100644
--- a/tclCommands/TclCommandSaveProject.py
+++ b/tclCommands/TclCommandSaveProject.py
@@ -11,6 +11,8 @@ class TclCommandSaveProject(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['save_project']
+ description = '%s %s' % ("--", "Saves the FlatCAM project to file.")
+
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
@@ -30,7 +32,7 @@ class TclCommandSaveProject(TclCommandSignaled):
help = {
'main': "Saves the FlatCAM project to file.",
'args': collections.OrderedDict([
- ('filename', 'Absolute path to file to open. Required.\n'
+ ('filename', 'Absolute path to file to save. Required.\n'
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
]),
'examples': ['save_project D:\\my_project_file.FlatPrj',
diff --git a/tclCommands/TclCommandSaveSys.py b/tclCommands/TclCommandSaveSys.py
index 5712515b..137ca8e7 100644
--- a/tclCommands/TclCommandSaveSys.py
+++ b/tclCommands/TclCommandSaveSys.py
@@ -16,6 +16,8 @@ class TclCommandSaveSys(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['save_sys', 'save']
+ description = '%s %s' % ("--", "Saves the FlatCAM system parameters to defaults file.")
+
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
diff --git a/tclCommands/TclCommandScale.py b/tclCommands/TclCommandScale.py
index aa5ebc3e..ac790842 100644
--- a/tclCommands/TclCommandScale.py
+++ b/tclCommands/TclCommandScale.py
@@ -25,6 +25,8 @@ class TclCommandScale(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['scale']
+ description = '%s %s' % ("--", "Will scale the geometry of a named object. Does not create a new object.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
diff --git a/tclCommands/TclCommandSetActive.py b/tclCommands/TclCommandSetActive.py
index 5144289a..6dfecd00 100644
--- a/tclCommands/TclCommandSetActive.py
+++ b/tclCommands/TclCommandSetActive.py
@@ -14,6 +14,8 @@ class TclCommandSetActive(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['set_active']
+ description = '%s %s' % ("--", "Sets a FlatCAM object as active (selected).")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
@@ -29,7 +31,7 @@ class TclCommandSetActive(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': 'Sets an object as active.',
+ 'main': 'Sets a FlatCAM object as active (selected).',
'args': collections.OrderedDict([
('name', 'Name of the FlatCAM object to be set as active (selected). Required.'),
]),
diff --git a/tclCommands/TclCommandSetOrigin.py b/tclCommands/TclCommandSetOrigin.py
index 895338e4..e801fd13 100644
--- a/tclCommands/TclCommandSetOrigin.py
+++ b/tclCommands/TclCommandSetOrigin.py
@@ -34,6 +34,8 @@ class TclCommandSetOrigin(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['set_origin', 'origin']
+ description = '%s %s' % ("--", "Set the origin at the specified x,y location.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('loc', str)
@@ -41,7 +43,7 @@ class TclCommandSetOrigin(TclCommand):
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
- ('auto', bool)
+ ('auto', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
@@ -55,7 +57,7 @@ class TclCommandSetOrigin(TclCommand):
('loc', 'Location to offset all the selected objects. NO SPACES ALLOWED in X and Y pair.\n'
'Use like this: 2,3'),
('auto', 'If set to True it will set the origin to the minimum x, y of the object selection bounding box.'
- '-auto=True is not correct but -auto 1 or -auto True is correct.')
+ '-auto=True is not correct but -auto 1 or -auto True is correct. True (1) or False (0).')
]),
'examples': ['set_origin 3,2', 'set_origin -auto 1', 'origin']
}
diff --git a/tclCommands/TclCommandSetSys.py b/tclCommands/TclCommandSetSys.py
index a8133317..8ef911bd 100644
--- a/tclCommands/TclCommandSetSys.py
+++ b/tclCommands/TclCommandSetSys.py
@@ -14,6 +14,8 @@ class TclCommandSetSys(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['set_sys', 'setsys']
+ description = '%s %s' % ("--", "Sets the value of the specified system variable.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
@@ -30,7 +32,7 @@ class TclCommandSetSys(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Sets the value of the system variable.",
+ 'main': "Sets the value of the specified system variable.",
'args': collections.OrderedDict([
('name', 'Name of the system variable. Required.'),
('value', 'Value to set.')
diff --git a/tclCommands/TclCommandSkew.py b/tclCommands/TclCommandSkew.py
index 28da6e1c..b181d9a2 100644
--- a/tclCommands/TclCommandSkew.py
+++ b/tclCommands/TclCommandSkew.py
@@ -14,6 +14,8 @@ class TclCommandSkew(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['skew']
+ description = '%s %s' % ("--", "Will deform (skew) the geometry of a named object. Does not create a new object.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
@@ -30,7 +32,7 @@ class TclCommandSkew(TclCommand):
# structured help for current command, args needs to be ordered
help = {
- 'main': "Shear/Skew an object by angles along x and y dimensions. The reference point is the left corner of "
+ 'main': "Shear/Skew an object along x and y dimensions. The reference point is the left corner of "
"the bounding box of the object.",
'args': collections.OrderedDict([
('name', 'Name of the object (Gerber, Geometry or Excellon) to be deformed (skewed). Required.'),
diff --git a/tclCommands/TclCommandSubtractPoly.py b/tclCommands/TclCommandSubtractPoly.py
index 98c43c66..74020f24 100644
--- a/tclCommands/TclCommandSubtractPoly.py
+++ b/tclCommands/TclCommandSubtractPoly.py
@@ -11,6 +11,9 @@ class TclCommandSubtractPoly(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['subtract_poly']
+ description = '%s %s' % ("--", "Subtract polygon from the given Geometry object. "
+ "The coordinates are provided in X Y pairs.")
+
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
diff --git a/tclCommands/TclCommandSubtractRectangle.py b/tclCommands/TclCommandSubtractRectangle.py
index 2453c584..b50a2467 100644
--- a/tclCommands/TclCommandSubtractRectangle.py
+++ b/tclCommands/TclCommandSubtractRectangle.py
@@ -19,6 +19,9 @@ class TclCommandSubtractRectangle(TclCommandSignaled):
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['subtract_rectangle']
+ description = '%s %s' % ("--", "Subtract a rectangle from the given Geometry object. "
+ "The coordinates are provided in X Y pairs.")
+
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
diff --git a/tclCommands/TclCommandVersion.py b/tclCommands/TclCommandVersion.py
index 86dcc24a..e5653dad 100644
--- a/tclCommands/TclCommandVersion.py
+++ b/tclCommands/TclCommandVersion.py
@@ -14,6 +14,8 @@ class TclCommandVersion(TclCommand):
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['version']
+ description = '%s %s' % ("--", "Checks the program version.")
+
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
diff --git a/tclCommands/TclCommandWriteGCode.py b/tclCommands/TclCommandWriteGCode.py
index 655f00cb..b96fdfd8 100644
--- a/tclCommands/TclCommandWriteGCode.py
+++ b/tclCommands/TclCommandWriteGCode.py
@@ -12,6 +12,8 @@ class TclCommandWriteGCode(TclCommandSignaled):
# old names for backward compatibility (add_poly, add_polygon)
aliases = ['write_gcode']
+ description = '%s %s' % ("--", "Saves G-code of a CNC Job object to file.")
+
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
@@ -24,7 +26,7 @@ class TclCommandWriteGCode(TclCommandSignaled):
option_types = collections.OrderedDict([
('preamble', str),
('postamble', str),
- ('muted', int)
+ ('muted', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
@@ -38,7 +40,7 @@ class TclCommandWriteGCode(TclCommandSignaled):
('filename', 'Output filename. Required.'),
('preamble', 'Text to append at the beginning.'),
('postamble', 'Text to append at the end.'),
- ('muted', 'It will not put errors in the Shell or status bar.')
+ ('muted', 'It will not put errors in the Shell or status bar. True (1) or False (0)')
]),
'examples': ["write_gcode name c:\\\\gcode_repo"]
@@ -67,9 +69,9 @@ class TclCommandWriteGCode(TclCommandSignaled):
postamble = args['postamble'] if 'postamble' in args else ''
if 'muted' in args:
- muted = args['muted']
+ muted = bool(eval(args['muted']))
else:
- muted = 0
+ muted = False
# TODO: This is not needed any more? All targets should be present.
# If there are promised objects, wait until all promises have been fulfilled.
@@ -91,7 +93,7 @@ class TclCommandWriteGCode(TclCommandSignaled):
try:
obj = self.app.collection.get_by_name(str(obj_name))
except Exception:
- if muted == 0:
+ if muted is False:
return "Could not retrieve object: %s" % obj_name
else:
return "fail"
@@ -99,7 +101,7 @@ class TclCommandWriteGCode(TclCommandSignaled):
try:
obj.export_gcode(str(filename), str(preamble), str(postamble))
except Exception as e:
- if not muted:
+ if muted is False:
return "Operation failed: %s" % str(e)
else:
return
diff --git a/tclCommands/__init__.py b/tclCommands/__init__.py
index a143eb30..e34cd733 100644
--- a/tclCommands/__init__.py
+++ b/tclCommands/__init__.py
@@ -99,7 +99,12 @@ def register_all_commands(app, commands):
command_instance = class_type(app)
for alias in command_instance.aliases:
+ try:
+ description = command_instance.description
+ except AttributeError:
+ description = ''
commands[alias] = {
'fcn': command_instance.execute_wrapper,
- 'help': command_instance.get_decorated_help()
+ 'help': command_instance.get_decorated_help(),
+ 'description': description
}
From 1b14e9d4510d1f76fdbbc003472006da339e4c77 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 13 Apr 2020 20:04:44 +0300
Subject: [PATCH 170/209] - updated the App.plot_all() method giving it the
possibility to be run as threaded or not - updated the Tcl command PlotAll to
be able to run threaded or not
---
FlatCAMApp.py | 15 ++++++++++-----
README.md | 2 ++
tclCommands/TclCommandDelete.py | 8 +++++---
tclCommands/TclCommandPlotAll.py | 16 +++++++++++-----
4 files changed, 28 insertions(+), 13 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 1d4dde99..5d895528 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -11888,11 +11888,13 @@ class App(QtCore.QObject):
if silent is False:
self.log.debug(" " + param + " OK!")
- def plot_all(self, zoom=True):
+ def plot_all(self, fit_view=True, use_thread=True):
"""
Re-generates all plots from all objects.
- :return: None
+ :param fit_view: if True will plot the objects and will adjust the zoom to fit all plotted objects into view
+ :param use_thread: if True will use threading for plotting the objects
+ :return:
"""
self.log.debug("Plot_all()")
self.inform.emit('[success] %s...' % _("Redrawing all objects"))
@@ -11901,11 +11903,14 @@ class App(QtCore.QObject):
def worker_task(obj):
with self.proc_container.new("Plotting"):
obj.plot(kind=self.defaults["cncjob_plot_kind"])
- if zoom:
+ if fit_view is True:
self.object_plotted.emit(obj)
- # Send to worker
- self.worker_task.emit({'fcn': worker_task, 'params': [obj]})
+ if use_thread is True:
+ # Send to worker
+ self.worker_task.emit({'fcn': worker_task, 'params': [obj]})
+ else:
+ worker_task(obj)
def register_folder(self, filename):
self.defaults["global_last_folder"] = os.path.split(str(filename))[0]
diff --git a/README.md b/README.md
index 2b0ed24a..c10a265e 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,8 @@ CAD program, and create G-Code for Isolation routing.
- multiple fixes in the Tcl commands (especially regarding the interchange between True/false and 1/0 values)
- updated the help for all Tcl Commands
- in Tcl Shell, the 'help' command will add also a brief description for each command in the list
+- updated the App.plot_all() method giving it the possibility to be run as threaded or not
+- updated the Tcl command PlotAll to be able to run threaded or not
11.04.2020
diff --git a/tclCommands/TclCommandDelete.py b/tclCommands/TclCommandDelete.py
index 1c482598..339a1120 100644
--- a/tclCommands/TclCommandDelete.py
+++ b/tclCommands/TclCommandDelete.py
@@ -23,7 +23,7 @@ class TclCommandDelete(TclCommand):
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
- ('f', bool)
+ ('f', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
@@ -34,7 +34,9 @@ class TclCommandDelete(TclCommand):
'main': 'Deletes the given object. If no name is given will delete all objects.',
'args': collections.OrderedDict([
('name', 'Name of the Object.'),
- ('f', 'Use this parameter to force deletion.')
+ ('f', 'Use this parameter to force deletion.\n'
+ 'Can be used without value which will be auto assumed to be True.\n'
+ 'Or it can have a value: True (1) or False (0).')
]),
'examples': ['del new_geo -f True\n'
'delete new_geo -f 1\n'
@@ -63,7 +65,7 @@ class TclCommandDelete(TclCommand):
if args['f'] is None:
is_forced = True
else:
- is_forced = True if eval(str(args['f'])) else False
+ is_forced = True if bool(eval(str(args['f']))) else False
except KeyError:
is_forced = True
diff --git a/tclCommands/TclCommandPlotAll.py b/tclCommands/TclCommandPlotAll.py
index 8efae5fb..d4194f4f 100644
--- a/tclCommands/TclCommandPlotAll.py
+++ b/tclCommands/TclCommandPlotAll.py
@@ -1,9 +1,9 @@
-from tclCommands.TclCommand import TclCommand
+from tclCommands.TclCommand import TclCommandSignaled
import collections
-class TclCommandPlotAll(TclCommand):
+class TclCommandPlotAll(TclCommandSignaled):
"""
Tcl shell command to update the plot on the user interface.
@@ -23,7 +23,7 @@ class TclCommandPlotAll(TclCommand):
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
-
+ ('use_thread', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
@@ -33,7 +33,7 @@ class TclCommandPlotAll(TclCommand):
help = {
'main': "Plots all objects on GUI.",
'args': collections.OrderedDict([
-
+ ('use_thread', 'If to use multithreading: True (1) or False (0).')
]),
'examples': ['plot_all']
}
@@ -45,5 +45,11 @@ class TclCommandPlotAll(TclCommand):
:param unnamed_args:
:return:
"""
+
+ if 'use_thread' in args:
+ threaded = bool(eval(args['use_thread']))
+ else:
+ threaded = False
+
if self.app.cmd_line_headless != 1:
- self.app.plot_all()
+ self.app.plot_all(use_thread=threaded)
From 742180d6e38a6605b3e8730aa4235f4614727e21 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 13 Apr 2020 20:28:39 +0300
Subject: [PATCH 171/209] - updated the Tcl commands PlotAll and PlotObjects to
have a parameter that control if the objects are to be plotted or not on
canvas; it serve as a disable/enable
---
FlatCAMApp.py | 34 ++++++++++++++++------------
ObjectCollection.py | 5 ++++
README.md | 1 +
tclCommands/TclCommandPlotAll.py | 15 +++++++++++-
tclCommands/TclCommandPlotObjects.py | 18 ++++++++++++---
5 files changed, 54 insertions(+), 19 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 5d895528..5e4ea70b 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -1029,8 +1029,10 @@ class App(QtCore.QObject):
'gbl, gbo, gbp, gbr, gbs, gdo, ger, gko, gm1, gm2, gm3, grb, gtl, gto, gtp, gts, ly15, ly2, '
'mil, pho, plc, pls, smb, smt, sol, spb, spt, ssb, sst, stc, sts, top, tsm',
# Keyword list
- "util_autocomplete_keywords": 'Desktop, Documents, FlatConfig, FlatPrj, Marius, My Documents, Paste_1, '
- 'Repetier, Roland_MDX_20, Users, Toolchange_Custom, Toolchange_Probe_MACH3, '
+ "util_autocomplete_keywords": 'Desktop, Documents, FlatConfig, FlatPrj, False, '
+ 'Marius, My Documents, Paste_1, '
+ 'Repetier, Roland_MDX_20, True, Users, Toolchange_Custom, '
+ 'Toolchange_Probe_MACH3, '
'Toolchange_manual, Users, all, angle_x, angle_y, axis, auto, axisoffset, '
'box, center_x, center_y, columns, combine, connect, contour, default, '
'depthperpass, dia, diatol, dist, drilled_dias, drillz, dwelltime, '
@@ -2305,28 +2307,30 @@ class App(QtCore.QObject):
# ######################### Auto-complete KEYWORDS ####################################
# #####################################################################################
self.tcl_commands_list = ['add_circle', 'add_poly', 'add_polygon', 'add_polyline', 'add_rectangle',
- 'aligndrill', 'aligndrillgrid', 'bbox', 'bounding_box', 'clear', 'cncjob', 'cutout',
- 'del', 'delete', 'drillcncjob', 'export_dxf', 'edxf', 'export_excellon', 'ee',
+ 'aligndrill', 'aligndrillgrid', 'bbox', 'clear', 'cncjob', 'cutout',
+ 'del', 'drillcncjob', 'export_dxf', 'edxf', 'export_excellon',
'export_exc',
- 'export_gcode', 'export_gerber', 'egr', 'export_svg', 'ext', 'exteriors', 'follow',
- 'geo_union', 'geocutout', 'get_names', 'get_sys', 'getsys', 'help', 'import_svg',
- 'interiors', 'isolate', 'join_excellon', 'join_excellons', 'join_geometries',
- 'join_geometry', 'list_sys', 'listsys', 'milld', 'mills', 'milldrills', 'millslots',
+ 'export_gcode', 'export_gerber', 'export_svg', 'ext', 'exteriors', 'follow',
+ 'geo_union', 'geocutout', 'get_bounds', 'get_names', 'get_sys', 'help', 'import_svg',
+ 'interiors', 'isolate', 'join_excellon',
+ 'join_geometry', 'list_sys', 'milld', 'mills', 'milldrills', 'millslots',
'mirror', 'ncc',
- 'ncc_clear', 'ncr', 'new', 'new_geometry', 'non_copper_regions', 'offset',
+ 'ncr', 'new', 'new_geometry', 'non_copper_regions', 'offset',
'open_excellon', 'open_gcode', 'open_gerber', 'open_project', 'options', 'origin',
- 'paint', 'pan', 'panel', 'panelize', 'plot_all', 'plot_objects', 'quit_flatcam',
+ 'paint', 'panelize', 'plot_all', 'plot_objects', 'plot_status', 'quit_flatcam',
'save', 'save_project',
'save_sys', 'scale', 'set_active', 'set_origin', 'set_sys',
- 'setsys', 'skew', 'subtract_poly', 'subtract_rectangle',
+ 'skew', 'subtract_poly', 'subtract_rectangle',
'version', 'write_gcode'
]
- self.default_keywords = ['Desktop', 'Documents', 'FlatConfig', 'FlatPrj', 'Marius', 'My Documents', 'Paste_1',
+ self.default_keywords = ['Desktop', 'Documents', 'FlatConfig', 'FlatPrj', 'False', 'Marius', 'My Documents',
+ 'Paste_1',
'Repetier', 'Roland_MDX_20', 'Users', 'Toolchange_Custom', 'Toolchange_Probe_MACH3',
- 'Toolchange_manual', 'Users', 'all', 'angle_x', 'angle_y', 'auto', 'axis',
- 'axisoffset',
- 'box', 'center_x', 'center_y', 'columns', 'combine', 'connect', 'contour', 'default',
+ 'Toolchange_manual', 'True', 'Users',
+ 'all', 'angle_x', 'angle_y', 'auto', 'axis',
+ 'axisoffset', 'box', 'center_x', 'center_y', 'columns', 'combine', 'connect',
+ 'contour', 'default',
'depthperpass', 'dia', 'diatol', 'dist', 'drilled_dias', 'drillz',
'dwelltime', 'extracut_length', 'f',
'feedrate_z', 'grbl_11', 'GRBL_laser', 'gridoffsety', 'gridx', 'gridy',
diff --git a/ObjectCollection.py b/ObjectCollection.py
index f015b031..62d6304d 100644
--- a/ObjectCollection.py
+++ b/ObjectCollection.py
@@ -912,6 +912,11 @@ class ObjectCollection(QtCore.QAbstractItemModel):
raise
def get_list(self):
+ """
+ Will return a list of all objects currently opened.
+
+ :return:
+ """
obj_list = []
for group in self.root_item.child_items:
for item in group.child_items:
diff --git a/README.md b/README.md
index c10a265e..99d47851 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,7 @@ CAD program, and create G-Code for Isolation routing.
- in Tcl Shell, the 'help' command will add also a brief description for each command in the list
- updated the App.plot_all() method giving it the possibility to be run as threaded or not
- updated the Tcl command PlotAll to be able to run threaded or not
+- updated the Tcl commands PlotAll and PlotObjects to have a parameter that control if the objects are to be plotted or not on canvas; it serve as a disable/enable
11.04.2020
diff --git a/tclCommands/TclCommandPlotAll.py b/tclCommands/TclCommandPlotAll.py
index d4194f4f..53da1e8f 100644
--- a/tclCommands/TclCommandPlotAll.py
+++ b/tclCommands/TclCommandPlotAll.py
@@ -23,6 +23,7 @@ class TclCommandPlotAll(TclCommandSignaled):
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
+ ('plot_status', str),
('use_thread', str)
])
@@ -33,9 +34,10 @@ class TclCommandPlotAll(TclCommandSignaled):
help = {
'main': "Plots all objects on GUI.",
'args': collections.OrderedDict([
+ ('plot_status', 'If to display or not the objects: True (1) or False (0).'),
('use_thread', 'If to use multithreading: True (1) or False (0).')
]),
- 'examples': ['plot_all']
+ 'examples': ['plot_all', 'plot_all -plot_status False']
}
def execute(self, args, unnamed_args):
@@ -51,5 +53,16 @@ class TclCommandPlotAll(TclCommandSignaled):
else:
threaded = False
+ if 'plot_status' in args:
+ if args['plot_status'] is None:
+ plot_status = True
+ else:
+ plot_status = bool(eval(args['plot_status']))
+ else:
+ plot_status = True
+
+ for obj in self.app.collection.get_list():
+ obj.options["plot"] = True if plot_status is True else False
+
if self.app.cmd_line_headless != 1:
self.app.plot_all(use_thread=threaded)
diff --git a/tclCommands/TclCommandPlotObjects.py b/tclCommands/TclCommandPlotObjects.py
index 34585efb..8a26e36c 100644
--- a/tclCommands/TclCommandPlotObjects.py
+++ b/tclCommands/TclCommandPlotObjects.py
@@ -30,7 +30,7 @@ class TclCommandPlotObjects(TclCommand):
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
-
+ ('plot_status', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
@@ -41,7 +41,8 @@ class TclCommandPlotObjects(TclCommand):
'main': "Plot a specified list of objects in GUI.",
'args': collections.OrderedDict([
('names', "A list of object names to be plotted separated by comma. Required.\n"
- "WARNING: no spaces are allowed. If unsure enclose the entire list with quotes.")
+ "WARNING: no spaces are allowed. If unsure enclose the entire list with quotes."),
+ ('plot_status', 'If to display or not the objects: True (1) or False (0).')
]),
'examples': ["plot_objects gerber_obj.GRB,excellon_obj.DRL"]
}
@@ -53,11 +54,22 @@ class TclCommandPlotObjects(TclCommand):
:param unnamed_args:
:return:
"""
+
+ if 'plot_status' in args:
+ if args['plot_status'] is None:
+ plot_status = True
+ else:
+ plot_status = bool(eval(args['plot_status']))
+ else:
+ plot_status = True
+
if self.app.cmd_line_headless != 1:
names = [x.strip() for x in args['names'].split(",") if x != '']
objs = []
for name in names:
- objs.append(self.app.collection.get_by_name(name))
+ obj= self.app.collection.get_by_name(name)
+ obj.options["plot"] = True if plot_status is True else False
+ objs.append(obj)
for obj in objs:
obj.plot()
From 7e98365885ea833e0ea0ac029398c4ba2103b435 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 13 Apr 2020 20:31:32 +0300
Subject: [PATCH 172/209] - minor update to the autocomplete dictionary
---
FlatCAMApp.py | 4 ++--
README.md | 1 +
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 5e4ea70b..61769ce8 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -1033,7 +1033,7 @@ class App(QtCore.QObject):
'Marius, My Documents, Paste_1, '
'Repetier, Roland_MDX_20, True, Users, Toolchange_Custom, '
'Toolchange_Probe_MACH3, '
- 'Toolchange_manual, Users, all, angle_x, angle_y, axis, auto, axisoffset, '
+ 'Toolchange_manual, Users, all, axis, auto, axisoffset, '
'box, center_x, center_y, columns, combine, connect, contour, default, '
'depthperpass, dia, diatol, dist, drilled_dias, drillz, dwelltime, '
'extracut_length, f, '
@@ -2328,7 +2328,7 @@ class App(QtCore.QObject):
'Paste_1',
'Repetier', 'Roland_MDX_20', 'Users', 'Toolchange_Custom', 'Toolchange_Probe_MACH3',
'Toolchange_manual', 'True', 'Users',
- 'all', 'angle_x', 'angle_y', 'auto', 'axis',
+ 'all', 'auto', 'axis',
'axisoffset', 'box', 'center_x', 'center_y', 'columns', 'combine', 'connect',
'contour', 'default',
'depthperpass', 'dia', 'diatol', 'dist', 'drilled_dias', 'drillz',
diff --git a/README.md b/README.md
index 99d47851..fb03c75d 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,7 @@ CAD program, and create G-Code for Isolation routing.
- updated the App.plot_all() method giving it the possibility to be run as threaded or not
- updated the Tcl command PlotAll to be able to run threaded or not
- updated the Tcl commands PlotAll and PlotObjects to have a parameter that control if the objects are to be plotted or not on canvas; it serve as a disable/enable
+- minor update to the autocomplete dictionary
11.04.2020
From 4c196f6baeae85084f75df320625257502dd871c Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 13 Apr 2020 20:44:51 +0300
Subject: [PATCH 173/209] - the Show Shell in Edit -> Preferences will now
toggle the Tcl shell based on the current status of the Tcl Shell - updated
the Tcl command Isolate help for follow parameter
---
FlatCAMApp.py | 15 +++++++++++++++
README.md | 2 ++
flatcamGUI/PreferencesUI.py | 2 +-
tclCommands/TclCommandIsolate.py | 2 +-
4 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 61769ce8..21aad659 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -5453,6 +5453,21 @@ class App(QtCore.QObject):
else:
self.ui.shell_dock.show()
+ def on_toggle_shell_from_settings(self, state):
+ """
+ Toggle shell: if is visible close it, if it is closed then open it
+ :return: None
+ """
+
+ self.report_usage("on_toggle_shell_from_settings()")
+
+ if state is True:
+ if not self.ui.shell_dock.isVisible():
+ self.ui.shell_dock.show()
+ else:
+ if self.ui.shell_dock.isVisible():
+ self.ui.shell_dock.hide()
+
def on_register_files(self, obj_type=None):
"""
Called whenever there is a need to register file extensions with FlatCAM.
diff --git a/README.md b/README.md
index fb03c75d..4996be13 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,8 @@ CAD program, and create G-Code for Isolation routing.
- updated the Tcl command PlotAll to be able to run threaded or not
- updated the Tcl commands PlotAll and PlotObjects to have a parameter that control if the objects are to be plotted or not on canvas; it serve as a disable/enable
- minor update to the autocomplete dictionary
+- the Show Shell in Edit -> Preferences will now toggle the Tcl shell based on the current status of the Tcl Shell
+- updated the Tcl command Isolate help for follow parameter
11.04.2020
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index 239b6fbb..33661845 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -1736,7 +1736,7 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
self.splash_cb.stateChanged.connect(self.on_splash_changed)
# Monitor the checkbox from the Application Defaults Tab and show the TCL shell or not depending on it's value
- self.shell_startup_cb.clicked.connect(self.app.on_toggle_shell)
+ self.shell_startup_cb.clicked.connect(self.app.on_toggle_shell_from_settings)
self.language_apply_btn.clicked.connect(lambda: fcTranslate.on_language_apply_click(app=self.app, restart=True))
diff --git a/tclCommands/TclCommandIsolate.py b/tclCommands/TclCommandIsolate.py
index 337280df..9fc4d214 100644
--- a/tclCommands/TclCommandIsolate.py
+++ b/tclCommands/TclCommandIsolate.py
@@ -52,7 +52,7 @@ class TclCommandIsolate(TclCommandSignaled):
'E.g: for a 25% from tool diameter overlap use -overlap 25'),
('combine', 'Combine all passes into one geometry. Can be True (1) or False (0)'),
('outname', 'Name of the resulting Geometry object.'),
- ('follow', 'Create a Geometry that follows the Gerber path.'),
+ ('follow', 'Create a Geometry that follows the Gerber path. Can be True (1) or False (0).'),
('iso_type', 'A value of 0 will isolate exteriors, a value of 1 will isolate interiors '
'and a value of 2 will do full isolation.')
]),
From e64c7060e57538fe7248119122432b9e1e2f749c Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Mon, 13 Apr 2020 23:43:48 +0300
Subject: [PATCH 174/209] - updated DrillCncJob Tcl Command with new parameters
and fixed it to work in the new format of the Excellon methods - changed
CncJob Tcl Command parameter 'depthperpass' to a shorter 'dpp'
---
FlatCAMApp.py | 15 ++--
FlatCAMObj.py | 2 -
README.md | 2 +
camlib.py | 35 +++++---
tclCommands/TclCommandCncjob.py | 14 +--
tclCommands/TclCommandDrillcncjob.py | 128 +++++++++++++++++++++------
6 files changed, 143 insertions(+), 53 deletions(-)
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 21aad659..3821dd84 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -1035,15 +1035,15 @@ class App(QtCore.QObject):
'Toolchange_Probe_MACH3, '
'Toolchange_manual, Users, all, axis, auto, axisoffset, '
'box, center_x, center_y, columns, combine, connect, contour, default, '
- 'depthperpass, dia, diatol, dist, drilled_dias, drillz, dwelltime, '
- 'extracut_length, f, '
+ 'depthperpass, dia, diatol, dist, drilled_dias, drillz, dpp, dwelltime, '
+ 'endxy, endz, extracut_length, f, feedrate, '
'feedrate_z, grbl_11, GRBL_laser, gridoffsety, gridx, gridy, has_offset, '
'holes, hpgl, iso_type, line_xyz, margin, marlin, method, milled_dias, '
'minoffset, name, offset, opt_type, order, outname, overlap, '
'passes, postamble, pp, ppname_e, ppname_g, preamble, radius, ref, rest, '
'rows, shellvar_, scale_factor, spacing_columns, spacing_rows, spindlespeed, '
- 'toolchange_xy, toolchangez, '
- 'tooldia, use_threads, value, x, x0, x1, y, y0, y1, z_cut, '
+ 'startz, startxy, toolchange_xy, toolchangez, '
+ 'tooldia, travelz, use_threads, value, x, x0, x1, y, y0, y1, z_cut, '
'z_move',
"script_autocompleter": True,
"script_text": "",
@@ -2331,15 +2331,16 @@ class App(QtCore.QObject):
'all', 'auto', 'axis',
'axisoffset', 'box', 'center_x', 'center_y', 'columns', 'combine', 'connect',
'contour', 'default',
- 'depthperpass', 'dia', 'diatol', 'dist', 'drilled_dias', 'drillz',
- 'dwelltime', 'extracut_length', 'f',
+ 'depthperpass', 'dia', 'diatol', 'dist', 'drilled_dias', 'drillz', 'dpp',
+ 'dwelltime', 'extracut_length', 'endxy', 'enz', 'f', 'feedrate',
'feedrate_z', 'grbl_11', 'GRBL_laser', 'gridoffsety', 'gridx', 'gridy',
'has_offset', 'holes', 'hpgl', 'iso_type', 'line_xyz', 'margin', 'marlin', 'method',
'milled_dias', 'minoffset', 'name', 'offset', 'opt_type', 'order',
'outname', 'overlap', 'passes', 'postamble', 'pp', 'ppname_e', 'ppname_g',
'preamble', 'radius', 'ref', 'rest', 'rows', 'shellvar_', 'scale_factor',
'spacing_columns',
- 'spacing_rows', 'spindlespeed', 'toolchange_xy', 'toolchangez',
+ 'spacing_rows', 'spindlespeed', 'startz', 'startxy',
+ 'toolchange_xy', 'toolchangez', 'travelz',
'tooldia', 'use_threads', 'value',
'x', 'x0', 'x1', 'y', 'y0', 'y1', 'z_cut', 'z_move'
]
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index a8b388bf..0256853a 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -3725,8 +3725,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
job_obj.options['type'] = 'Excellon'
job_obj.options['ppname_e'] = pp_excellon_name
- job_obj.z_cut = float(self.options["cutz"])
-
job_obj.multidepth = self.options["multidepth"]
job_obj.z_depthpercut = self.options["depthperpass"]
diff --git a/README.md b/README.md
index 4996be13..4c787ef8 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,8 @@ CAD program, and create G-Code for Isolation routing.
- minor update to the autocomplete dictionary
- the Show Shell in Edit -> Preferences will now toggle the Tcl shell based on the current status of the Tcl Shell
- updated the Tcl command Isolate help for follow parameter
+- updated DrillCncJob Tcl Command with new parameters and fixed it to work in the new format of the Excellon methods
+- changed CncJob Tcl Command parameter 'depthperpass' to a shorter 'dpp'
11.04.2020
diff --git a/camlib.py b/camlib.py
index bb192a4b..40d84cc0 100644
--- a/camlib.py
+++ b/camlib.py
@@ -2742,9 +2742,12 @@ class CNCjob(Geometry):
LineString([start, stop]).buffer((it[1] / 2.0), resolution=self.geo_steps_per_circle)
)
- try:
- z_off = float(exobj.tools[it[0]]['data']['offset']) * (-1)
- except KeyError:
+ if self.use_ui:
+ try:
+ z_off = float(exobj.tools[it[0]]['data']['offset']) * (-1)
+ except KeyError:
+ z_off = 0
+ else:
z_off = 0
default_data = {}
@@ -2790,7 +2793,7 @@ class CNCjob(Geometry):
# Initialization
gcode = self.doformat(p.start_code)
- if not use_ui:
+ if use_ui is False:
gcode += self.doformat(p.z_feedrate_code)
if self.toolchange is False:
@@ -2873,7 +2876,7 @@ class CNCjob(Geometry):
self.postdata['toolC'] = exobj.tools[tool]["C"]
self.tooldia = exobj.tools[tool]["C"]
- if use_ui:
+ if self.use_ui:
self.z_feedrate = exobj.tools[tool]['data']['feedrate_z']
self.feedrate = exobj.tools[tool]['data']['feedrate']
gcode += self.doformat(p.z_feedrate_code)
@@ -2906,6 +2909,8 @@ class CNCjob(Geometry):
self.dwelltime = exobj.tools[tool]['data']['dwelltime']
self.multidepth = exobj.tools[tool]['data']['multidepth']
self.z_depthpercut = exobj.tools[tool]['data']['depthperpass']
+ else:
+ old_zcut = deepcopy(self.z_cut)
# ###############################################
# ############ Create the data. #################
@@ -3000,8 +3005,10 @@ class CNCjob(Geometry):
str(self.units))
)
- # TODO apply offset only when using the GUI, for TclCommand this will create an error
+ # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ # APPLY Offset only when using the GUI, for TclCommand this will create an error
# because the values for Z offset are created in build_ui()
+ # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
try:
z_offset = float(exobj.tools[tool]['data']['offset']) * (-1)
except KeyError:
@@ -3099,7 +3106,7 @@ class CNCjob(Geometry):
self.postdata['toolC']=exobj.tools[tool]["C"]
self.tooldia = exobj.tools[tool]["C"]
- if use_ui:
+ if self.use_ui:
self.z_feedrate = exobj.tools[tool]['data']['feedrate_z']
self.feedrate = exobj.tools[tool]['data']['feedrate']
gcode += self.doformat(p.z_feedrate_code)
@@ -3132,6 +3139,8 @@ class CNCjob(Geometry):
self.dwelltime = exobj.tools[tool]['data']['dwelltime']
self.multidepth = exobj.tools[tool]['data']['multidepth']
self.z_depthpercut = exobj.tools[tool]['data']['depthperpass']
+ else:
+ old_zcut = deepcopy(self.z_cut)
# ###############################################
# ############ Create the data. #################
@@ -3215,8 +3224,10 @@ class CNCjob(Geometry):
str(self.units))
)
- # TODO apply offset only when using the GUI, for TclCommand this will create an error
+ # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ # APPLY Offset only when using the GUI, for TclCommand this will create an error
# because the values for Z offset are created in build_ui()
+ # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
try:
z_offset = float(exobj.tools[tool]['data']['offset']) * (-1)
except KeyError:
@@ -3316,7 +3327,7 @@ class CNCjob(Geometry):
self.postdata['toolC'] = exobj.tools[tool]["C"]
self.tooldia = exobj.tools[tool]["C"]
- if use_ui:
+ if self.use_ui:
self.z_feedrate = exobj.tools[tool]['data']['feedrate_z']
self.feedrate = exobj.tools[tool]['data']['feedrate']
gcode += self.doformat(p.z_feedrate_code)
@@ -3349,6 +3360,8 @@ class CNCjob(Geometry):
self.dwelltime = exobj.tools[tool]['data']['dwelltime']
self.multidepth = exobj.tools[tool]['data']['multidepth']
self.z_depthpercut = exobj.tools[tool]['data']['depthperpass']
+ else:
+ old_zcut = deepcopy(self.z_cut)
# Only if tool has points.
if tool in points:
@@ -3375,8 +3388,10 @@ class CNCjob(Geometry):
str(self.units))
)
- # TODO apply offset only when using the GUI, for TclCommand this will create an error
+ # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ # APPLY Offset only when using the GUI, for TclCommand this will create an error
# because the values for Z offset are created in build_ui()
+ # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
try:
z_offset = float(exobj.tools[tool]['data']['offset']) * (-1)
except KeyError:
diff --git a/tclCommands/TclCommandCncjob.py b/tclCommands/TclCommandCncjob.py
index 70bfbcbc..6f41e1df 100644
--- a/tclCommands/TclCommandCncjob.py
+++ b/tclCommands/TclCommandCncjob.py
@@ -36,7 +36,7 @@ class TclCommandCncjob(TclCommandSignaled):
('feedrate_z', float),
('feedrate_rapid', float),
('extracut_length', float),
- ('depthperpass', float),
+ ('dpp', float),
('toolchangez', float),
('toolchangexy', tuple),
('startz', float),
@@ -63,7 +63,7 @@ class TclCommandCncjob(TclCommandSignaled):
('feedrate_z', 'Moving speed on Z plane when cutting.'),
('feedrate_rapid', 'Rapid moving at speed when cutting.'),
('extracut_length', 'The value for extra cnccut over the first point in path,in the job end; float'),
- ('depthperpass', 'If present then use multidepth cnc cut. Height of one layer for multidepth.'),
+ ('dpp', 'If present then use multidepth cnc cut. Height of one layer for multidepth.'),
('toolchangez', 'Z distance for toolchange (example: 30.0).\n'
'If used in the command then a toolchange event will be included in gcode'),
('toolchangexy', 'X, Y coordonates for toolchange in format (x, y) (example: (2.0, 3.1) ).'),
@@ -141,12 +141,12 @@ class TclCommandCncjob(TclCommandSignaled):
else:
args["extracut"] = False
- if "depthperpass" in args:
+ if "dpp" in args:
args["multidepth"] = True
- if args["depthperpass"] is None:
- args["depthperpass"] = obj.options["depthperpass"]
+ if args["dpp"] is None:
+ args["dpp"] = obj.options["dpp"]
else:
- args["depthperpass"] = float(args["depthperpass"])
+ args["dpp"] = float(args["dpp"])
else:
args["multidepth"] = False
@@ -221,7 +221,7 @@ class TclCommandCncjob(TclCommandSignaled):
else:
local_tools_dict[tool_uid]['data']['extracut_length'] = None
- local_tools_dict[tool_uid]['data']['depthperpass'] = args["depthperpass"]
+ local_tools_dict[tool_uid]['data']['depthperpass'] = args["dpp"]
local_tools_dict[tool_uid]['data']['toolchange'] = args["toolchange"]
local_tools_dict[tool_uid]['data']['toolchangez'] = args["toolchangez"]
local_tools_dict[tool_uid]['data']['toolchangexy'] = args["toolchangexy"]
diff --git a/tclCommands/TclCommandDrillcncjob.py b/tclCommands/TclCommandDrillcncjob.py
index e0fd5dae..d2f31021 100644
--- a/tclCommands/TclCommandDrillcncjob.py
+++ b/tclCommands/TclCommandDrillcncjob.py
@@ -4,6 +4,14 @@ from FlatCAMObj import FlatCAMExcellon
import collections
import math
+import gettext
+import FlatCAMTranslation as fcTranslate
+import builtins
+
+fcTranslate.apply_language('strings')
+if '_' not in builtins.__dict__:
+ _ = gettext.gettext
+
class TclCommandDrillcncjob(TclCommandSignaled):
"""
@@ -24,13 +32,16 @@ class TclCommandDrillcncjob(TclCommandSignaled):
option_types = collections.OrderedDict([
('drilled_dias', str),
('drillz', float),
+ ('dpp', float),
('travelz', float),
- ('feedrate', float),
+ ('feedrate_z', float),
('feedrate_rapid', float),
('spindlespeed', int),
('toolchangez', float),
('toolchangexy', tuple),
+ ('startz', float),
('endz', float),
+ ('endxy', tuple),
('dwelltime', float),
('pp', str),
('opt_type', str),
@@ -50,15 +61,18 @@ class TclCommandDrillcncjob(TclCommandSignaled):
('drilled_dias',
'Comma separated tool diameters of the drills to be drilled (example: 0.6,1.0 or 3.125). '
'No space allowed'),
- ('drillz', 'Drill depth into material (example: -2.0).'),
+ ('drillz', 'Drill depth into material (example: -2.0). Negative value.'),
+ ('dpp', 'Progressive drilling into material with a specified step (example: 0.7). Positive value.'),
('travelz', 'Travel distance above material (example: 2.0).'),
- ('feedrate', 'Drilling feed rate.'),
+ ('feedrate_z', 'Drilling feed rate. It is the speed on the Z axis.'),
('feedrate_rapid', 'Rapid drilling feed rate.'),
('spindlespeed', 'Speed of the spindle in rpm (example: 4000).'),
('toolchangez', 'Z distance for toolchange (example: 30.0).\n'
'If used in the command then a toolchange event will be included in gcode'),
('toolchangexy', 'X, Y coordonates for toolchange in format (x, y) (example: (2.0, 3.1) ).'),
- ('endz', 'Z distance at job end (example: 30.0).'),
+ ('startz', 'The Z coordinate at job start (example: 30.0).'),
+ ('endz', 'The Z coordinate at job end (example: 30.0).'),
+ ('endxy', 'The X,Y coordinates at job end in format (x, y) (example: (30.0, 15.2)).'),
('dwelltime', 'Time to pause to allow the spindle to reach the full speed.\n'
'If it is not used in command then it will not be included'),
('pp', 'This is the Excellon preprocessor name: case_sensitive, no_quotes'),
@@ -73,9 +87,10 @@ class TclCommandDrillcncjob(TclCommandSignaled):
('muted', 'It will not put errors in the Shell or status bar. Can be True (1) or False (0).'),
('outname', 'Name of the resulting Geometry object.')
]),
- 'examples': ['drillcncjob test.TXT -drillz -1.5 -travelz 14 -feedrate 222 -feedrate_rapid 456 -spindlespeed 777'
- ' -toolchangez 33 -endz 22 -pp default\n'
- 'Usage of -feedrate_rapid matter only when the preprocessor is using it, like -marlin-.']
+ 'examples': ['drillcncjob test.TXT -drillz -1.5 -travelz 14 -feedrate_z 222 -feedrate_rapid 456 '
+ '-spindlespeed 777 -toolchangez 33 -endz 22 -pp default\n'
+ 'Usage of -feedrate_rapid matter only when the preprocessor is using it, like -marlin-.',
+ 'drillcncjob test.DRL -drillz -1.7 -dpp 0.5 -travelz 2 -feedrate_z 800 -endxy 3,3']
}
def execute(self, args, unnamed_args):
@@ -171,6 +186,35 @@ class TclCommandDrillcncjob(TclCommandSignaled):
else:
return "fail"
+ used_tools_info = []
+ used_tools_info.insert(0, [_("Tool_nr"), _("Diameter"), _("Drills_Nr"), _("Slots_Nr")])
+
+ # populate the information's list for used tools
+ if tools == 'all':
+ sort = []
+ for k, v in list(obj.tools.items()):
+ sort.append((k, v.get('C')))
+ sorted_tools = sorted(sort, key=lambda t1: t1[1])
+ use_tools = [i[0] for i in sorted_tools]
+
+ for tool_no in use_tools:
+ tool_dia_used = obj.tools[tool_no]['C']
+
+ drill_cnt = 0 # variable to store the nr of drills per tool
+ slot_cnt = 0 # variable to store the nr of slots per tool
+
+ # Find no of drills for the current tool
+ for drill in obj.drills:
+ if drill['tool'] == tool_no:
+ drill_cnt += 1
+
+ # Find no of slots for the current tool
+ for slot in obj.slots:
+ if slot['tool'] == tool_no:
+ slot_cnt += 1
+
+ used_tools_info.append([str(tool_no), str(tool_dia_used), str(drill_cnt), str(slot_cnt)])
+
drillz = args["drillz"] if "drillz" in args and args["drillz"] is not None else obj.options["cutz"]
if "toolchangez" in args:
@@ -183,17 +227,48 @@ class TclCommandDrillcncjob(TclCommandSignaled):
toolchange = False
toolchangez = 0.0
+ xy_toolchange = args["toolchangexy"] if "toolchangexy" in args and args["toolchangexy"] else \
+ obj.options["toolchangexy"]
+ xy_toolchange = ','.join([xy_toolchange[0], xy_toolchange[2]])
+
endz = args["endz"] if "endz" in args and args["endz"] is not None else obj.options["endz"]
+ xy_end = args["endxy"] if "endxy" in args and args["endxy"] else '0,0'
+ xy_end = ','.join([xy_end[0], xy_end[2]])
+ print(xy_end)
opt_type = args["opt_type"] if "opt_type" in args and args["opt_type"] else 'B'
- job_obj.z_move = args["travelz"] if "travelz" in args and args["travelz"] else obj.options["travelz"]
+ # ##########################################################################################
+ # ################# Set parameters #########################################################
+ # ##########################################################################################
+ job_obj.origin_kind = 'excellon'
- job_obj.feedrate = args["feedrate"] if "feedrate" in args and args["feedrate"] else obj.options["feedrate"]
- job_obj.z_feedrate = args["feedrate"] if "feedrate" in args and args["feedrate"] else \
- obj.options["feedrate"]
- job_obj.feedrate_rapid = args["feedrate_rapid"] \
+ job_obj.options['Tools_in_use'] = used_tools_info
+ job_obj.options['type'] = 'Excellon'
+
+ pp_excellon_name = args["pp"] if "pp" in args and args["pp"] else obj.options["ppname_e"]
+ job_obj.pp_excellon_name = pp_excellon_name
+ job_obj.options['ppname_e'] = pp_excellon_name
+
+ if 'dpp' in args:
+ job_obj.multidepth = True
+ if args['dpp'] is not None:
+ job_obj.z_depthpercut = float(args['dpp'])
+ else:
+ job_obj.z_depthpercut = float(obj.options["dpp"])
+ else:
+ job_obj.multidepth = False
+ job_obj.z_depthpercut = 0.0
+
+ job_obj.z_move = float(args["travelz"]) if "travelz" in args and args["travelz"] else obj.options["travelz"]
+ job_obj.feedrate = float(args["feedrate_z"]) if "feedrate_z" in args and args["feedrate_z"] else \
+ obj.options["feedrate_z"]
+ job_obj.z_feedrate = float(args["feedrate_z"]) if "feedrate_z" in args and args["feedrate_z"] else \
+ obj.options["feedrate_z"]
+ job_obj.feedrate_rapid = float(args["feedrate_rapid"]) \
if "feedrate_rapid" in args and args["feedrate_rapid"] else obj.options["feedrate_rapid"]
+ job_obj.spindlespeed = float(args["spindlespeed"]) if "spindlespeed" in args else None
+ job_obj.spindledir = self.app.defaults['excellon_spindledir']
if 'dwelltime' in args:
job_obj.dwell = True
if args['dwelltime'] is not None:
@@ -204,35 +279,34 @@ class TclCommandDrillcncjob(TclCommandSignaled):
job_obj.dwell = False
job_obj.dwelltime = 0.0
- job_obj.spindlespeed = args["spindlespeed"] if "spindlespeed" in args else None
- job_obj.pp_excellon_name = args["pp"] if "pp" in args and args["pp"] \
- else obj.options["ppname_e"]
-
+ job_obj.toolchange_xy_type = "excellon"
job_obj.coords_decimals = int(self.app.defaults["cncjob_coords_decimals"])
job_obj.fr_decimals = int(self.app.defaults["cncjob_fr_decimals"])
- job_obj.options['type'] = 'Excellon'
-
- job_obj.toolchangexy = args["toolchangexy"] if "toolchangexy" in args and args["toolchangexy"] else \
- obj.options["toolchangexy"]
-
- job_obj.toolchange_xy_type = "excellon"
-
job_obj.options['xmin'] = xmin
job_obj.options['ymin'] = ymin
job_obj.options['xmax'] = xmax
job_obj.options['ymax'] = ymax
- job_obj.generate_from_excellon_by_tool(obj, tools, drillz=drillz, toolchangez=toolchangez, endz=endz,
- toolchange=toolchange, excellon_optimization_type=opt_type)
+ job_obj.z_cut = float(drillz)
+ job_obj.toolchange = toolchange
+ job_obj.xy_toolchange = xy_toolchange
+ job_obj.z_toolchange = float(toolchangez)
+ job_obj.startz = float(args["startz"]) if "endz" in args and args["endz"] is not None else (0, 0)
+ job_obj.endz = float(endz)
+ job_obj.xy_end = xy_end
+ job_obj.excellon_optimization_type = opt_type
+
+ ret_val = job_obj.generate_from_excellon_by_tool(obj, tools, use_ui=False)
+
+ if ret_val == 'fail':
+ return 'fail'
for t_item in job_obj.exc_cnc_tools:
job_obj.exc_cnc_tools[t_item]['data']['offset'] = \
float(job_obj.exc_cnc_tools[t_item]['offset_z']) + float(drillz)
job_obj.exc_cnc_tools[t_item]['data']['ppname_e'] = obj.options['ppname_e']
- job_obj.origin_kind = 'excellon'
-
job_obj.gcode_parse()
job_obj.create_geometry()
From cb52f1c10aa290fb42521b2447f4894716f71589 Mon Sep 17 00:00:00 2001
From: Marius
Date: Tue, 14 Apr 2020 04:30:47 +0300
Subject: [PATCH 175/209] - lightened the hue of the color for 'success'
messages printed in the Tcl Shell browser
---
README.md | 5 +++++
flatcamTools/ToolShell.py | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 4c787ef8..54b7e758 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
=================================================
+14.04.2020
+
+- lightened the hue of the color for 'success' messages printed in the Tcl Shell browser
+
13.04.2020
- added the outname parameter for the geocutout Tcl command
@@ -22,6 +26,7 @@ CAD program, and create G-Code for Isolation routing.
- the Show Shell in Edit -> Preferences will now toggle the Tcl shell based on the current status of the Tcl Shell
- updated the Tcl command Isolate help for follow parameter
- updated DrillCncJob Tcl Command with new parameters and fixed it to work in the new format of the Excellon methods
+- fixed issue #399
- changed CncJob Tcl Command parameter 'depthperpass' to a shorter 'dpp'
11.04.2020
diff --git a/flatcamTools/ToolShell.py b/flatcamTools/ToolShell.py
index 9c216bc7..92c3f45c 100644
--- a/flatcamTools/ToolShell.py
+++ b/flatcamTools/ToolShell.py
@@ -102,7 +102,7 @@ class TermWidget(QWidget):
elif style == 'warning':
text = '%s' % text
elif style == 'success':
- text = '%s' % text
+ text = '%s' % text
elif style == 'selected':
text = ''
else:
From c5926ae99f24185f5172b406243682385a490069 Mon Sep 17 00:00:00 2001
From: Marius Stanciu
Date: Tue, 14 Apr 2020 13:42:49 +0300
Subject: [PATCH 176/209] - modified the extensions all over such the names
include also the extension name. For Linux who does not display the
extensions in the native FileDialog. - added descriptions for some of the
methods in the app. - added lightened icons for the dark theme from Leandro
Heck
---
FlatCAMApp.py | 218 ++++++++++--------
FlatCAMObj.py | 94 ++++++--
README.md | 3 +
share/dark_resources/about32.png | Bin 1996 -> 0 bytes
share/dark_resources/active_static.png | Bin 234 -> 424 bytes
share/dark_resources/addarray16.png | Bin 157 -> 378 bytes
share/dark_resources/addarray20.png | Bin 176 -> 540 bytes
share/dark_resources/addarray32.png | Bin 251 -> 423 bytes
share/dark_resources/aero.png | Bin 468 -> 1140 bytes
share/dark_resources/aero_arc.png | Bin 479 -> 1151 bytes
share/dark_resources/aero_array.png | Bin 482 -> 1157 bytes
share/dark_resources/aero_buffer.png | Bin 512 -> 1159 bytes
share/dark_resources/aero_circle.png | Bin 505 -> 1158 bytes
share/dark_resources/aero_circle_geo.png | Bin 505 -> 1160 bytes
share/dark_resources/aero_disc.png | Bin 481 -> 1143 bytes
share/dark_resources/aero_drill.png | Bin 461 -> 1142 bytes
share/dark_resources/aero_drill_array.png | Bin 492 -> 1162 bytes
share/dark_resources/aero_path1.png | Bin 516 -> 1152 bytes
share/dark_resources/aero_path2.png | Bin 500 -> 1154 bytes
share/dark_resources/aero_path3.png | Bin 482 -> 1145 bytes
share/dark_resources/aero_path4.png | Bin 481 -> 1145 bytes
share/dark_resources/aero_path5.png | Bin 553 -> 1194 bytes
share/dark_resources/aero_semidisc.png | Bin 469 -> 1143 bytes
share/dark_resources/aero_slot.png | Bin 460 -> 1136 bytes
share/dark_resources/aero_text.png | Bin 508 -> 1164 bytes
share/dark_resources/align_center32.png | Bin 168 -> 387 bytes
share/dark_resources/align_justify32.png | Bin 123 -> 347 bytes
share/dark_resources/align_left32.png | Bin 165 -> 373 bytes
share/dark_resources/align_right32.png | Bin 168 -> 363 bytes
share/dark_resources/aperture16.png | Bin 150 -> 554 bytes
share/dark_resources/aperture32.png | Bin 296 -> 920 bytes
share/dark_resources/arc16.png | Bin 326 -> 525 bytes
share/dark_resources/arc24.png | Bin 445 -> 653 bytes
share/dark_resources/arc32.png | Bin 625 -> 786 bytes
share/dark_resources/axis32.png | Bin 297 -> 645 bytes
share/dark_resources/backup24.png | Bin 199 -> 504 bytes
share/dark_resources/backup_export24.png | Bin 177 -> 356 bytes
share/dark_resources/backup_import24.png | Bin 186 -> 374 bytes
share/dark_resources/blocked16.png | Bin 2188 -> 2935 bytes
share/dark_resources/bold32.png | Bin 589 -> 622 bytes
share/dark_resources/bookmarks16.png | Bin 136 -> 377 bytes
share/dark_resources/bookmarks32.png | Bin 226 -> 431 bytes
share/dark_resources/buffer16-2.png | Bin 148 -> 493 bytes
share/dark_resources/buffer16.png | Bin 466 -> 579 bytes
share/dark_resources/buffer20.png | Bin 170 -> 509 bytes
share/dark_resources/buffer24.png | Bin 191 -> 565 bytes
share/dark_resources/bug16.png | Bin 189 -> 504 bytes
share/dark_resources/bug32.png | Bin 341 -> 958 bytes
share/dark_resources/calculator16.png | Bin 340 -> 549 bytes
share/dark_resources/calculator24.png | Bin 499 -> 679 bytes
share/dark_resources/calibrate_16.png | Bin 242 -> 380 bytes
share/dark_resources/calibrate_32.png | Bin 366 -> 459 bytes
share/dark_resources/cancel_edit16.png | Bin 453 -> 520 bytes
share/dark_resources/cancel_edit32.png | Bin 696 -> 625 bytes
share/dark_resources/circle32.png | Bin 271 -> 601 bytes
share/dark_resources/clear_plot16.png | Bin 640 -> 675 bytes
share/dark_resources/clear_plot32.png | Bin 1439 -> 1047 bytes
share/dark_resources/close_edit_file16.png | Bin 289 -> 494 bytes
share/dark_resources/close_edit_file32.png | Bin 252 -> 690 bytes
share/dark_resources/cnc16.png | Bin 431 -> 538 bytes
share/dark_resources/cnc32.png | Bin 967 -> 716 bytes
share/dark_resources/code.png | Bin 237 -> 676 bytes
share/dark_resources/code_editor32.png | Bin 214 -> 414 bytes
share/dark_resources/convert24.png | Bin 194 -> 565 bytes
share/dark_resources/copperfill16.png | Bin 187 -> 602 bytes
share/dark_resources/copperfill32.png | Bin 344 -> 1051 bytes
share/dark_resources/copy.png | Bin 170 -> 600 bytes
share/dark_resources/copy16.png | Bin 288 -> 526 bytes
share/dark_resources/copy32.png | Bin 832 -> 743 bytes
share/dark_resources/copy_16.png | Bin 288 -> 395 bytes
share/dark_resources/copy_file16.png | Bin 156 -> 462 bytes
share/dark_resources/copy_file32.png | Bin 227 -> 617 bytes
share/dark_resources/copy_geo.png | Bin 582 -> 605 bytes
share/dark_resources/corner32.png | Bin 913 -> 815 bytes
share/dark_resources/cut16.png | Bin 166 -> 504 bytes
share/dark_resources/cut16_bis.png | Bin 175 -> 578 bytes
share/dark_resources/cut32.png | Bin 268 -> 705 bytes
share/dark_resources/cut32_bis.png | Bin 335 -> 1122 bytes
share/dark_resources/cutpath16.png | Bin 465 -> 536 bytes
share/dark_resources/cutpath24.png | Bin 691 -> 675 bytes
share/dark_resources/cutpath32.png | Bin 853 -> 778 bytes
share/dark_resources/database32.png | Bin 296 -> 959 bytes
share/dark_resources/defaults.png | Bin 211 -> 834 bytes
share/dark_resources/delete32.png | Bin 943 -> 745 bytes
share/dark_resources/delete_file16.png | Bin 171 -> 547 bytes
share/dark_resources/delete_file32.png | Bin 281 -> 848 bytes
share/dark_resources/deleteshape16.png | Bin 386 -> 578 bytes
share/dark_resources/deleteshape24.png | Bin 493 -> 656 bytes
share/dark_resources/deleteshape32.png | Bin 600 -> 766 bytes
share/dark_resources/deselect_all32.png | Bin 267 -> 712 bytes
share/dark_resources/disable16.png | Bin 180 -> 522 bytes
share/dark_resources/disable32.png | Bin 320 -> 843 bytes
share/dark_resources/disc32.png | Bin 234 -> 650 bytes
share/dark_resources/distance16.png | Bin 169 -> 479 bytes
share/dark_resources/distance32.png | Bin 242 -> 612 bytes
share/dark_resources/distance_min16.png | Bin 133 -> 400 bytes
share/dark_resources/distance_min32.png | Bin 200 -> 408 bytes
share/dark_resources/doubleside16.png | Bin 350 -> 501 bytes
share/dark_resources/doubleside32.png | Bin 614 -> 661 bytes
share/dark_resources/draw32.png | Bin 279 -> 684 bytes
share/dark_resources/drill16.png | Bin 175 -> 509 bytes
share/dark_resources/drill32.png | Bin 251 -> 740 bytes
share/dark_resources/dxf16.png | Bin 344 -> 688 bytes
share/dark_resources/edit16.png | Bin 482 -> 537 bytes
share/dark_resources/edit32.png | Bin 912 -> 748 bytes
share/dark_resources/edit_file16.png | Bin 307 -> 510 bytes
share/dark_resources/edit_file32.png | Bin 277 -> 716 bytes
share/dark_resources/edit_ok16.png | Bin 486 -> 524 bytes
share/dark_resources/edit_ok32.png | Bin 843 -> 647 bytes
share/dark_resources/edit_ok32_bis.png | Bin 1581 -> 1235 bytes
share/dark_resources/eraser26.png | Bin 928 -> 1395 bytes
share/dark_resources/explode32.png | Bin 338 -> 830 bytes
share/dark_resources/export.png | Bin 203 -> 546 bytes
share/dark_resources/export_png32.png | Bin 275 -> 796 bytes
share/dark_resources/fiducials_32.png | Bin 191 -> 455 bytes
share/dark_resources/file16.png | Bin 479 -> 694 bytes
share/dark_resources/file32.png | Bin 200 -> 502 bytes
share/dark_resources/film16.png | Bin 258 -> 441 bytes
share/dark_resources/film32.png | Bin 179 -> 0 bytes
share/dark_resources/flatcam_icon128.png | Bin 1735 -> 1761 bytes
share/dark_resources/flatcam_icon16.png | Bin 219 -> 464 bytes
share/dark_resources/flatcam_icon24.png | Bin 314 -> 591 bytes
share/dark_resources/flatcam_icon256.png | Bin 4401 -> 3820 bytes
share/dark_resources/flatcam_icon32.png | Bin 359 -> 703 bytes
share/dark_resources/flatcam_icon32_green.png | Bin 994 -> 994 bytes
share/dark_resources/flatcam_icon48.png | Bin 614 -> 906 bytes
share/dark_resources/flipx.png | Bin 514 -> 515 bytes
share/dark_resources/flipy.png | Bin 522 -> 496 bytes
share/dark_resources/floppy16.png | Bin 458 -> 749 bytes
share/dark_resources/floppy32.png | Bin 373 -> 531 bytes
share/dark_resources/folder16.png | Bin 367 -> 615 bytes
share/dark_resources/folder32.png | Bin 391 -> 525 bytes
share/dark_resources/folder32_Excellon.png | Bin 453 -> 585 bytes
share/dark_resources/folder32_bis.png | Bin 208 -> 604 bytes
share/dark_resources/folder32_gerber.png | Bin 456 -> 593 bytes
share/dark_resources/fscreen32.png | Bin 10536 -> 3398 bytes
share/dark_resources/gear32.png | Bin 452 -> 876 bytes
share/dark_resources/gear48.png | Bin 727 -> 1146 bytes
share/dark_resources/geometry16.png | Bin 693 -> 617 bytes
share/dark_resources/globe16.png | Bin 884 -> 1152 bytes
share/dark_resources/goemetry32.png | Bin 1015 -> 658 bytes
share/dark_resources/grid16.png | Bin 499 -> 631 bytes
share/dark_resources/grid32.png | Bin 850 -> 877 bytes
share/dark_resources/grid32_menu.png | Bin 175 -> 444 bytes
share/dark_resources/help.png | Bin 422 -> 1144 bytes
share/dark_resources/home16.png | Bin 396 -> 629 bytes
share/dark_resources/image16.png | Bin 170 -> 468 bytes
share/dark_resources/image32.png | Bin 305 -> 677 bytes
share/dark_resources/import.png | Bin 213 -> 550 bytes
share/dark_resources/info16.png | Bin 603 -> 821 bytes
share/dark_resources/intersection16.png | Bin 476 -> 514 bytes
share/dark_resources/intersection24.png | Bin 639 -> 589 bytes
share/dark_resources/intersection32.png | Bin 829 -> 723 bytes
share/dark_resources/italic32.png | Bin 203 -> 463 bytes
share/dark_resources/join16.png | Bin 541 -> 548 bytes
share/dark_resources/join32.png | Bin 1275 -> 945 bytes
share/dark_resources/jump_to16.png | Bin 159 -> 478 bytes
share/dark_resources/jump_to32.png | Bin 296 -> 711 bytes
share/dark_resources/language32.png | Bin 262 -> 583 bytes
share/dark_resources/letter_t_32.png | Bin 135 -> 368 bytes
share/dark_resources/link16.png | Bin 168 -> 0 bytes
share/dark_resources/machine16.png | Bin 669 -> 932 bytes
share/dark_resources/markarea32.png | Bin 221 -> 745 bytes
share/dark_resources/move16.png | Bin 151 -> 489 bytes
share/dark_resources/move32.png | Bin 906 -> 772 bytes
share/dark_resources/move32_bis.png | Bin 253 -> 595 bytes
share/dark_resources/ncc16.png | Bin 161 -> 443 bytes
share/dark_resources/new_exc32.png | Bin 1235 -> 1064 bytes
share/dark_resources/new_file16.png | Bin 132 -> 405 bytes
share/dark_resources/new_file32.png | Bin 183 -> 487 bytes
share/dark_resources/new_file_exc16.png | Bin 642 -> 642 bytes
share/dark_resources/new_file_exc32.png | Bin 842 -> 842 bytes
share/dark_resources/new_file_geo16.png | Bin 605 -> 605 bytes
share/dark_resources/new_file_geo32.png | Bin 640 -> 640 bytes
share/dark_resources/new_file_grb16.png | Bin 679 -> 679 bytes
share/dark_resources/new_file_grb32.png | Bin 777 -> 777 bytes
share/dark_resources/new_geo16.png | Bin 255 -> 430 bytes
share/dark_resources/new_geo32.png | Bin 352 -> 523 bytes
share/dark_resources/new_geo32_bis.png | Bin 1504 -> 1201 bytes
share/dark_resources/notebook16.png | Bin 122 -> 400 bytes
share/dark_resources/notebook32.png | Bin 160 -> 433 bytes
share/dark_resources/notes16.png | Bin 148 -> 463 bytes
share/dark_resources/notes16_1.png | Bin 148 -> 438 bytes
share/dark_resources/offset32.png | Bin 195 -> 361 bytes
share/dark_resources/offsetx32.png | Bin 195 -> 399 bytes
share/dark_resources/offsety32.png | Bin 229 -> 436 bytes
share/dark_resources/open_excellon32.png | Bin 167 -> 737 bytes
share/dark_resources/open_script32.png | Bin 560 -> 831 bytes
share/dark_resources/origin.png | Bin 511 -> 610 bytes
share/dark_resources/origin16.png | Bin 182 -> 586 bytes
share/dark_resources/origin32.png | Bin 260 -> 804 bytes
share/dark_resources/padarray32.png | Bin 193 -> 409 bytes
share/dark_resources/paint16.png | Bin 168 -> 479 bytes
share/dark_resources/paint20.png | Bin 203 -> 569 bytes
share/dark_resources/paint20_1.png | Bin 167 -> 495 bytes
share/dark_resources/panel16.png | Bin 124 -> 534 bytes
share/dark_resources/panel32.png | Bin 279 -> 1108 bytes
share/dark_resources/panelize16.png | Bin 137 -> 449 bytes
share/dark_resources/panelize32.png | Bin 210 -> 554 bytes
share/dark_resources/path32.png | Bin 282 -> 724 bytes
share/dark_resources/pdf32.png | Bin 1539 -> 1884 bytes
share/dark_resources/pdf_link16.png | Bin 171 -> 412 bytes
share/dark_resources/plot32.png | Bin 226 -> 438 bytes
share/dark_resources/plus16.png | Bin 116 -> 338 bytes
share/dark_resources/plus32.png | Bin 152 -> 403 bytes
share/dark_resources/pointer.png | Bin 25986 -> 5167 bytes
share/dark_resources/pointer32.png | Bin 250 -> 616 bytes
share/dark_resources/poligonize32.png | Bin 218 -> 568 bytes
share/dark_resources/polygon32.png | Bin 282 -> 744 bytes
share/dark_resources/power16.png | Bin 669 -> 835 bytes
share/dark_resources/pref.png | Bin 237 -> 793 bytes
share/dark_resources/printer16.png | Bin 559 -> 565 bytes
share/dark_resources/printer32.png | Bin 325 -> 870 bytes
share/dark_resources/project16.png | Bin 204 -> 534 bytes
share/dark_resources/project_save16.png | Bin 496 -> 504 bytes
share/dark_resources/project_save32.png | Bin 217 -> 629 bytes
share/dark_resources/properties32.png | Bin 206 -> 413 bytes
share/dark_resources/qrcode32.png | Bin 765 -> 618 bytes
share/dark_resources/recent_files.png | Bin 265 -> 755 bytes
share/dark_resources/rectangle32.png | Bin 147 -> 442 bytes
share/dark_resources/recycle16.png | Bin 621 -> 890 bytes
share/dark_resources/replot16.png | Bin 547 -> 648 bytes
share/dark_resources/replot32.png | Bin 1102 -> 1008 bytes
share/dark_resources/resize16.png | Bin 161 -> 428 bytes
share/dark_resources/rotate.png | Bin 426 -> 1066 bytes
share/dark_resources/rules32.png | Bin 170 -> 423 bytes
share/dark_resources/save_as.png | Bin 246 -> 683 bytes
share/dark_resources/scale32.png | Bin 232 -> 680 bytes
share/dark_resources/script14.png | Bin 141 -> 418 bytes
share/dark_resources/script16.png | Bin 164 -> 509 bytes
share/dark_resources/script_new16.png | Bin 175 -> 449 bytes
share/dark_resources/script_new24.png | Bin 223 -> 455 bytes
share/dark_resources/script_open16.png | Bin 160 -> 501 bytes
share/dark_resources/script_open18.png | Bin 170 -> 423 bytes
share/dark_resources/script_open24.png | Bin 195 -> 525 bytes
share/dark_resources/select_all.png | Bin 650 -> 647 bytes
share/dark_resources/semidisc32.png | Bin 253 -> 645 bytes
share/dark_resources/shell16.png | Bin 150 -> 479 bytes
share/dark_resources/shell32.png | Bin 233 -> 597 bytes
share/dark_resources/shortcuts24.png | Bin 177 -> 726 bytes
share/dark_resources/skewX.png | Bin 296 -> 692 bytes
share/dark_resources/skewY.png | Bin 286 -> 655 bytes
share/dark_resources/slot26.png | Bin 131 -> 1023 bytes
share/dark_resources/slot_array26.png | Bin 143 -> 1025 bytes
share/dark_resources/snap_16.png | Bin 426 -> 557 bytes
share/dark_resources/snap_filled_16.png | Bin 176 -> 337 bytes
share/dark_resources/solderpaste32.png | Bin 315 -> 879 bytes
share/dark_resources/solderpastebis32.png | Bin 303 -> 602 bytes
share/dark_resources/source32.png | Bin 12171 -> 9304 bytes
share/dark_resources/sub32.png | Bin 243 -> 779 bytes
share/dark_resources/subtract16.png | Bin 461 -> 517 bytes
share/dark_resources/subtract24.png | Bin 766 -> 665 bytes
share/dark_resources/subtract32.png | Bin 954 -> 804 bytes
share/dark_resources/svg16.png | Bin 13012 -> 10390 bytes
share/dark_resources/svg32.png | Bin 296 -> 809 bytes
share/dark_resources/text32.png | Bin 167 -> 352 bytes
share/dark_resources/toggle_units16.png | Bin 191 -> 476 bytes
share/dark_resources/toggle_units32.png | Bin 349 -> 655 bytes
share/dark_resources/track32.png | Bin 246 -> 553 bytes
share/dark_resources/transform.png | Bin 202 -> 571 bytes
share/dark_resources/trash16.png | Bin 512 -> 791 bytes
share/dark_resources/trash32.png | Bin 297 -> 565 bytes
share/dark_resources/tv16.png | Bin 480 -> 761 bytes
share/dark_resources/underline32.png | Bin 204 -> 528 bytes
share/dark_resources/union16.png | Bin 466 -> 512 bytes
share/dark_resources/union32.png | Bin 849 -> 755 bytes
share/dark_resources/videohelp24.png | Bin 222 -> 684 bytes
share/dark_resources/view64.png | Bin 693 -> 1610 bytes
share/dark_resources/workspace24.png | Bin 146 -> 460 bytes
share/dark_resources/zoom_fit32.png | Bin 441 -> 790 bytes
share/dark_resources/zoom_in32.png | Bin 422 -> 772 bytes
share/dark_resources/zoom_out32.png | Bin 316 -> 723 bytes
272 files changed, 204 insertions(+), 111 deletions(-)
delete mode 100644 share/dark_resources/about32.png
delete mode 100644 share/dark_resources/film32.png
delete mode 100644 share/dark_resources/link16.png
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 3821dd84..dd8f0e61 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -545,23 +545,24 @@ class App(QtCore.QObject):
"gerber_def_units": 'IN',
"gerber_def_zeros": 'L',
- "gerber_save_filters": "Gerber File (*.gbr);;Gerber File (*.bot);;Gerber File (*.bsm);;"
- "Gerber File (*.cmp);;Gerber File (*.crc);;Gerber File (*.crs);;"
- "Gerber File (*.gb0);;Gerber File (*.gb1);;Gerber File (*.gb2);;"
- "Gerber File (*.gb3);;Gerber File (*.gb4);;Gerber File (*.gb5);;"
- "Gerber File (*.gb6);;Gerber File (*.gb7);;Gerber File (*.gb8);;"
- "Gerber File (*.gb9);;Gerber File (*.gbd);;Gerber File (*.gbl);;"
- "Gerber File (*.gbo);;Gerber File (*.gbp);;Gerber File (*.gbs);;"
- "Gerber File (*.gdo);;Gerber File (*.ger);;Gerber File (*.gko);;"
- "Gerber File (*.gm1);;Gerber File (*.gm2);;Gerber File (*.gm3);;"
- "Gerber File (*.grb);;Gerber File (*.gtl);;Gerber File (*.gto);;"
- "Gerber File (*.gtp);;Gerber File (*.gts);;Gerber File (*.ly15);;"
- "Gerber File (*.ly2);;Gerber File (*.mil);;Gerber File (*.pho);;"
- "Gerber File (*.plc);;Gerber File (*.pls);;Gerber File (*.smb);;"
- "Gerber File (*.smt);;Gerber File (*.sol);;Gerber File (*.spb);;"
- "Gerber File (*.spt);;Gerber File (*.ssb);;Gerber File (*.sst);;"
- "Gerber File (*.stc);;Gerber File (*.sts);;Gerber File (*.top);;"
- "Gerber File (*.tsm);;Gerber File (*.art)"
+ "gerber_save_filters": "Gerber File .gbr (*.gbr);;Gerber File .bot (*.bot);;Gerber File .bsm (*.bsm);;"
+ "Gerber File .cmp (*.cmp);;Gerber File .crc (*.crc);;Gerber File .crs (*.crs);;"
+ "Gerber File .gb0 (*.gb0);;Gerber File .gb1 (*.gb1);;Gerber File .gb2 (*.gb2);;"
+ "Gerber File .gb3 (*.gb3);;Gerber File .gb4 (*.gb4);;Gerber File .gb5 (*.gb5);;"
+ "Gerber File .gb6 (*.gb6);;Gerber File .gb7 (*.gb7);;Gerber File .gb8 (*.gb8);;"
+ "Gerber File .gb9 (*.gb9);;Gerber File .gbd (*.gbd);;Gerber File .gbl (*.gbl);;"
+ "Gerber File .gbo (*.gbo);;Gerber File .gbp (*.gbp);;Gerber File .gbs (*.gbs);;"
+ "Gerber File .gdo (*.gdo);;Gerber File .ger (*.ger);;Gerber File .gko (*.gko);;"
+ "Gerber File .gm1 (*.gm1);;Gerber File .gm2 (*.gm2);;Gerber File .gm3 (*.gm3);;"
+ "Gerber File .grb (*.grb);;Gerber File .gtl (*.gtl);;Gerber File .gto (*.gto);;"
+ "Gerber File .gtp (*.gtp);;Gerber File .gts (*.gts);;Gerber File .ly15 (*.ly15);;"
+ "Gerber File .ly2 (*.ly2);;Gerber File .mil (*.mil);;"
+ "Gerber File .outline (*.outline);;Gerber File .pho (*.pho);;"
+ "Gerber File .plc (*.plc);;Gerber File .pls (*.pls);;Gerber File .smb (*.smb);;"
+ "Gerber File .smt (*.smt);;Gerber File .sol (*.sol);;Gerber File .spb (*.spb);;"
+ "Gerber File .spt (*.spt);;Gerber File .ssb (*.ssb);;Gerber File .sst (*.sst);;"
+ "Gerber File .stc (*.stc);;Gerber File .sts (*.sts);;Gerber File .top (*.top);;"
+ "Gerber File .tsm (*.tsm);;Gerber File .art (*.art)"
"All Files (*.*)",
# Gerber Options
@@ -627,9 +628,11 @@ class App(QtCore.QObject):
"excellon_optimization_type": 'B',
"excellon_search_time": 3,
- "excellon_save_filters": "Excellon File (*.txt);;Excellon File (*.drd);;Excellon File (*.drl);;"
- "Excellon File (*.exc);;Excellon File (*.ncd);;Excellon File (*.tap);;"
- "Excellon File (*.xln);;All Files (*.*)",
+ "excellon_save_filters": "Excellon File .txt (*.txt);;Excellon File .drd (*.drd);;"
+ "Excellon File .drill (*.drill);;"
+ "Excellon File .drl (*.drl);;Excellon File .exc (*.exc);;"
+ "Excellon File .ncd (*.ncd);;Excellon File .tap (*.tap);;"
+ "Excellon File .xln (*.xln);;All Files (*.*)",
"excellon_plot_fill": '#C40000BF',
"excellon_plot_line": '#750000BF',
@@ -749,15 +752,15 @@ class App(QtCore.QObject):
"cncjob_steps_per_circle": 64,
"cncjob_footer": False,
"cncjob_line_ending": False,
- "cncjob_save_filters": "G-Code Files (*.nc);;G-Code Files (*.din);;G-Code Files (*.dnc);;"
- "G-Code Files (*.ecs);;G-Code Files (*.eia);;G-Code Files (*.fan);;"
- "G-Code Files (*.fgc);;G-Code Files (*.fnc);;G-Code Files (*.gc);;"
- "G-Code Files (*.gcd);;G-Code Files (*.gcode);;G-Code Files (*.h);;"
- "G-Code Files (*.hnc);;G-Code Files (*.i);;G-Code Files (*.min);;"
- "G-Code Files (*.mpf);;G-Code Files (*.mpr);;G-Code Files (*.cnc);;"
- "G-Code Files (*.ncc);;G-Code Files (*.ncg);;G-Code Files (*.ncp);;"
- "G-Code Files (*.ngc);;G-Code Files (*.out);;G-Code Files (*.ply);;"
- "G-Code Files (*.sbp);;G-Code Files (*.tap);;G-Code Files (*.xpi);;"
+ "cncjob_save_filters": "G-Code Files .nc (*.nc);;G-Code Files .din (*.din);;G-Code Files .dnc (*.dnc);;"
+ "G-Code Files .ecs (*.ecs);;G-Code Files .eia (*.eia);;G-Code Files .fan (*.fan);;"
+ "G-Code Files .fgc (*.fgc);;G-Code Files .fnc (*.fnc);;G-Code Files . gc (*.gc);;"
+ "G-Code Files .gcd (*.gcd);;G-Code Files .gcode (*.gcode);;G-Code Files .h (*.h);;"
+ "G-Code Files .hnc (*.hnc);;G-Code Files .i (*.i);;G-Code Files .min (*.min);;"
+ "G-Code Files .mpf (*.mpf);;G-Code Files .mpr (*.mpr);;G-Code Files .cnc (*.cnc);;"
+ "G-Code Files .ncc (*.ncc);;G-Code Files .ncg (*.ncg);;G-Code Files .ncp (*.ncp);;"
+ "G-Code Files .ngc (*.ngc);;G-Code Files .out (*.out);;G-Code Files .ply (*.ply);;"
+ "G-Code Files .sbp (*.sbp);;G-Code Files .tap (*.tap);;G-Code Files .xpi (*.xpi);;"
"All Files (*.*)",
"cncjob_plot_line": '#4650BDFF',
"cncjob_plot_fill": '#5E6CFFFF',
@@ -1022,12 +1025,12 @@ class App(QtCore.QObject):
# Utilities
# file associations
- "fa_excellon": 'drd, drl, exc, ncd, tap, xln',
+ "fa_excellon": 'drd, drill, drl, exc, ncd, tap, xln',
"fa_gcode": 'cnc, din, dnc, ecs, eia, fan, fgc, fnc, gc, gcd, gcode, h, hnc, i, min, mpf, mpr, nc, ncc, '
'ncg, ncp, ngc, out, ply, rol, sbp, tap, xpi',
"fa_gerber": 'art, bot, bsm, cmp, crc, crs, dim, gb0, gb1, gb2, gb3, gb4, gb5, gb6, gb7, gb8, gb9, gbd, '
'gbl, gbo, gbp, gbr, gbs, gdo, ger, gko, gm1, gm2, gm3, grb, gtl, gto, gtp, gts, ly15, ly2, '
- 'mil, pho, plc, pls, smb, smt, sol, spb, spt, ssb, sst, stc, sts, top, tsm',
+ 'mil, outline, pho, plc, pls, smb, smt, sol, spb, spt, ssb, sst, stc, sts, top, tsm',
# Keyword list
"util_autocomplete_keywords": 'Desktop, Documents, FlatConfig, FlatPrj, False, '
'Marius, My Documents, Paste_1, '
@@ -2726,10 +2729,11 @@ class App(QtCore.QObject):
self.grb_list = ['art', 'bot', 'bsm', 'cmp', 'crc', 'crs', 'dim', 'g4', 'gb0', 'gb1', 'gb2', 'gb3', 'gb5',
'gb6', 'gb7', 'gb8', 'gb9', 'gbd', 'gbl', 'gbo', 'gbp', 'gbr', 'gbs', 'gdo', 'ger', 'gko',
- 'gml', 'gm1', 'gm2', 'gm3', 'grb', 'gtl', 'gto', 'gtp', 'gts', 'ly15', 'ly2', 'mil', 'pho',
- 'plc', 'pls', 'smb', 'smt', 'sol', 'spb', 'spt', 'ssb', 'sst', 'stc', 'sts', 'top', 'tsm']
+ 'gml', 'gm1', 'gm2', 'gm3', 'grb', 'gtl', 'gto', 'gtp', 'gts', 'ly15', 'ly2', 'mil', 'outline',
+ 'pho', 'plc', 'pls', 'smb', 'smt', 'sol', 'spb', 'spt', 'ssb', 'sst', 'stc', 'sts', 'top',
+ 'tsm']
- self.exc_list = ['drd', 'drl', 'exc', 'ncd', 'tap', 'txt', 'xln']
+ self.exc_list = ['drd', 'drl', 'drill', 'exc', 'ncd', 'tap', 'txt', 'xln']
self.gcode_list = ['cnc', 'din', 'dnc', 'ecs', 'eia', 'fan', 'fgc', 'fnc', 'gc', 'gcd', 'gcode', 'h', 'hnc',
'i', 'min', 'mpf', 'mpr', 'nc', 'ncc', 'ncg', 'ngc', 'ncp', 'out', 'ply', 'rol',
@@ -10082,8 +10086,7 @@ class App(QtCore.QObject):
# Check for more compatible types and add as required
if not isinstance(obj, FlatCAMExcellon):
- self.inform.emit('[ERROR_NOTCL] %s' %
- _("Failed. Only Excellon objects can be saved as Excellon files..."))
+ self.inform.emit('[ERROR_NOTCL] %s' % _("Failed. Only Excellon objects can be saved as Excellon files..."))
return
name = self.collection.get_active().options["name"]
@@ -10100,8 +10103,7 @@ class App(QtCore.QObject):
filename = str(filename)
if filename == "":
- self.inform.emit('[WARNING_NOTCL] %s' %
- _("Export Excellon cancelled."))
+ self.inform.emit('[WARNING_NOTCL] %s' % _("Export Excellon cancelled."))
return
else:
used_extension = filename.rpartition('.')[2]
@@ -10147,8 +10149,7 @@ class App(QtCore.QObject):
filename = str(filename)
if filename == "":
- self.inform.emit('[WARNING_NOTCL] %s' %
- _("Export Gerber cancelled."))
+ self.inform.emit('[WARNING_NOTCL] %s' % _("Export Gerber cancelled."))
return
else:
used_extension = filename.rpartition('.')[2]
@@ -10170,8 +10171,7 @@ class App(QtCore.QObject):
obj = self.collection.get_active()
if obj is None:
- self.inform.emit('[WARNING_NOTCL] %s' %
- _("No object selected."))
+ self.inform.emit('[WARNING_NOTCL] %s' % _("No object selected."))
msg = _("Please Select a Geometry object to export")
msgbox = QtWidgets.QMessageBox()
msgbox.setInformativeText(msg)
@@ -10182,8 +10182,7 @@ class App(QtCore.QObject):
# Check for more compatible types and add as required
if not isinstance(obj, FlatCAMGeometry):
- msg = '[ERROR_NOTCL] %s' % \
- _("Only Geometry objects can be used.")
+ msg = '[ERROR_NOTCL] %s' % _("Only Geometry objects can be used.")
msgbox = QtWidgets.QMessageBox()
msgbox.setInformativeText(msg)
bt_ok = msgbox.addButton(_('Ok'), QtWidgets.QMessageBox.AcceptRole)
@@ -10194,21 +10193,19 @@ class App(QtCore.QObject):
name = self.collection.get_active().options["name"]
- _filter_ = "DXF File (*.DXF);;All Files (*.*)"
+ _filter_ = "DXF File .dxf (*.DXF);;All Files (*.*)"
try:
filename, _f = FCFileSaveDialog.get_saved_filename(
caption=_("Export DXF"),
directory=self.get_last_save_folder() + '/' + name,
filter=_filter_)
except TypeError:
- filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Export DXF"),
- filter=_filter_)
+ filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Export DXF"), filter=_filter_)
filename = str(filename)
if filename == "":
- self.inform.emit('[WARNING_NOTCL] %s' %
- _("Export DXF cancelled."))
+ self.inform.emit('[WARNING_NOTCL] %s' % _("Export DXF cancelled."))
return
else:
self.export_dxf(name, filename)
@@ -10226,7 +10223,7 @@ class App(QtCore.QObject):
self.report_usage("on_file_importsvg")
App.log.debug("on_file_importsvg()")
- _filter_ = "SVG File (*.svg);;All Files (*.*)"
+ _filter_ = "SVG File .svg (*.svg);;All Files (*.*)"
try:
filenames, _f = QtWidgets.QFileDialog.getOpenFileNames(caption=_("Import SVG"),
directory=self.get_last_folder(), filter=_filter_)
@@ -10240,8 +10237,7 @@ class App(QtCore.QObject):
filenames = [str(filename) for filename in filenames]
if len(filenames) == 0:
- self.inform.emit('[WARNING_NOTCL] %s' %
- _("Open SVG cancelled."))
+ self.inform.emit('[WARNING_NOTCL] %s' % _("Open SVG cancelled."))
else:
for filename in filenames:
if filename != '':
@@ -10258,7 +10254,7 @@ class App(QtCore.QObject):
self.report_usage("on_file_importdxf")
App.log.debug("on_file_importdxf()")
- _filter_ = "DXF File (*.DXF);;All Files (*.*)"
+ _filter_ = "DXF File .dxf (*.DXF);;All Files (*.*)"
try:
filenames, _f = QtWidgets.QFileDialog.getOpenFileNames(caption=_("Import DXF"),
directory=self.get_last_folder(),
@@ -10273,8 +10269,7 @@ class App(QtCore.QObject):
filenames = [str(filename) for filename in filenames]
if len(filenames) == 0:
- self.inform.emit('[WARNING_NOTCL] %s' %
- _("Open DXF cancelled."))
+ self.inform.emit('[WARNING_NOTCL] %s' % _("Open DXF cancelled."))
else:
for filename in filenames:
if filename != '':
@@ -10332,11 +10327,11 @@ class App(QtCore.QObject):
flt = "All Files (*.*)"
if obj.kind == 'gerber':
- flt = "Gerber Files (*.GBR);;PDF Files (*.PDF);;All Files (*.*)"
+ flt = "Gerber Files .gbr (*.GBR);;PDF Files .pdf (*.PDF);;All Files (*.*)"
elif obj.kind == 'excellon':
- flt = "Excellon Files (*.DRL);;PDF Files (*.PDF);;All Files (*.*)"
+ flt = "Excellon Files .drl (*.DRL);;PDF Files .pdf (*.PDF);;All Files (*.*)"
elif obj.kind == 'cncjob':
- flt = "GCode Files (*.NC);;PDF Files (*.PDF);;All Files (*.*)"
+ flt = "GCode Files .nc (*.NC);;PDF Files .pdf (*.PDF);;All Files (*.*)"
self.source_editor_tab = TextEditor(app=self, plain_text=True)
@@ -10497,7 +10492,8 @@ class App(QtCore.QObject):
self.report_usage("on_fileopenscript")
App.log.debug("on_fileopenscript()")
- _filter_ = "TCL script (*.FlatScript);;TCL script (*.TCL);;TCL script (*.TXT);;All Files (*.*)"
+ _filter_ = "TCL script .FlatScript (*.FlatScript);;TCL script .tcl (*.TCL);;TCL script .txt (*.TXT);;" \
+ "All Files (*.*)"
if name:
filenames = [name]
@@ -10539,7 +10535,8 @@ class App(QtCore.QObject):
alignment=Qt.AlignBottom | Qt.AlignLeft,
color=QtGui.QColor("gray"))
else:
- _filter_ = "TCL script (*.FlatScript);;TCL script (*.TCL);;TCL script (*.TXT);;All Files (*.*)"
+ _filter_ = "TCL script .FlatScript (*.FlatScript);;TCL script .tcl (*.TCL);;TCL script .txt (*.TXT);;" \
+ "All Files (*.*)"
try:
filename, _f = QtWidgets.QFileDialog.getOpenFileName(caption=_("Run TCL script"),
directory=self.get_last_folder(), filter=_filter_)
@@ -10616,7 +10613,7 @@ class App(QtCore.QObject):
self.date = ''.join(c for c in self.date if c not in ':-')
self.date = self.date.replace(' ', '_')
- filter_ = "FlatCAM Project (*.FlatPrj);; All Files (*.*)"
+ filter_ = "FlatCAM Project .FlatPrj (*.FlatPrj);; All Files (*.*)"
try:
filename, _f = FCFileSaveDialog.get_saved_filename(
caption=_("Save Project As ..."),
@@ -10670,7 +10667,7 @@ class App(QtCore.QObject):
self.inform.emit('[ERROR_NOTCL] %s' % _("No object selected."))
return
- filter_ = "PDF File (*.PDF);; All Files (*.*)"
+ filter_ = "PDF File .pdf (*.PDF);; All Files (*.*)"
try:
filename, _f = FCFileSaveDialog.get_saved_filename(
caption=_("Save Object as PDF ..."),
@@ -11542,10 +11539,11 @@ class App(QtCore.QObject):
Opens a G-gcode file, parses it and creates a new object for
it in the program. Thread-safe.
- :param outname: Name of the resulting object. None causes the name to be that of the file.
- :param filename: G-code file filename
- :type filename: str
- :return: None
+ :param filename: G-code file filename
+ :param outname: Name of the resulting object. None causes the name to be that of the file.
+ :param force_parsing:
+ :param plot:
+ :return: None
"""
App.log.debug("open_gcode()")
@@ -11605,11 +11603,9 @@ class App(QtCore.QObject):
Opens a HPGL2 file, parses it and creates a new object for
it in the program. Thread-safe.
- :param outname: Name of the resulting object. None causes the
- name to be that of the file.
- :param filename: HPGL2 file filename
- :type filename: str
- :return: None
+ :param outname: Name of the resulting object. None causes the name to be that of the file.
+ :param filename: HPGL2 file filename
+ :return: None
"""
filename = filename
@@ -11672,10 +11668,9 @@ class App(QtCore.QObject):
Opens a Script file, parses it and creates a new object for
it in the program. Thread-safe.
- :param outname: Name of the resulting object. None causes the name to be that of the file.
- :param filename: Script file filename
- :type filename: str
- :return: None
+ :param outname: Name of the resulting object. None causes the name to be that of the file.
+ :param filename: Script file filename
+ :return: None
"""
App.log.debug("open_script()")
@@ -11709,9 +11704,9 @@ class App(QtCore.QObject):
"""
Loads a config file from the specified file.
- :param filename: Name of the file from which to load.
- :type filename: str
- :return: None
+ :param filename: Name of the file from which to load.
+ :param run_from_arg: if True the FlatConfig file will be open as an command line argument
+ :return: None
"""
App.log.debug("Opening config file: " + filename)
@@ -11760,12 +11755,11 @@ class App(QtCore.QObject):
5) Calls new_object() with the object's from_dict() as init method.
6) Calls plot_all() if plot=True
- :param filename: Name of the file from which to load.
- :type filename: str
- :param run_from_arg: True if run for arguments
- :param plot: If True plot all objects in the project
- :param cli: run from command line
- :return: None
+ :param filename: Name of the file from which to load.
+ :param run_from_arg: True if run for arguments
+ :param plot: If True plot all objects in the project
+ :param cli: Run from command line
+ :return: None
"""
App.log.debug("Opening project: " + filename)
@@ -11870,7 +11864,8 @@ class App(QtCore.QObject):
an alternative to project options but allows the use
of values invisible to the user.
- :return: None
+ :param silent: No messages
+ :return: None
"""
if silent is False:
@@ -11914,7 +11909,7 @@ class App(QtCore.QObject):
:param fit_view: if True will plot the objects and will adjust the zoom to fit all plotted objects into view
:param use_thread: if True will use threading for plotting the objects
- :return:
+ :return: None
"""
self.log.debug("Plot_all()")
self.inform.emit('[success] %s...' % _("Redrawing all objects"))
@@ -11933,12 +11928,31 @@ class App(QtCore.QObject):
worker_task(obj)
def register_folder(self, filename):
+ """
+ Register the last folder used by the app to open something
+
+ :param filename: the last folder is extracted from the filename
+ :return: None
+ """
self.defaults["global_last_folder"] = os.path.split(str(filename))[0]
def register_save_folder(self, filename):
+ """
+ Register the last folder used by the app to save something
+
+ :param filename: the last folder is extracted from the filename
+ :return: None
+ """
self.defaults["global_last_save_folder"] = os.path.split(str(filename))[0]
def set_progress_bar(self, percentage, text=""):
+ """
+ Set a progress bar to a value (percentage)
+
+ :param percentage: Value set to the progressbar
+ :param text: Not used
+ :return: None
+ """
self.ui.progress_bar.setValue(int(percentage))
def setup_shell(self):
@@ -12143,7 +12157,11 @@ class App(QtCore.QObject):
''')
def setup_recent_items(self):
+ """
+ Setup a dictionary with the recent files accessed, organized by type
+ :return:
+ """
# TODO: Move this to constructor
icons = {
"gerber": self.resource_location + "/flatcam_icon16.png",
@@ -12309,6 +12327,11 @@ class App(QtCore.QObject):
self.log.debug("Recent items list has been populated.")
def setup_component_editor(self):
+ """
+ Default text for the Selected tab when is not taken by the Object UI.
+
+ :return:
+ """
# label = QtWidgets.QLabel("Choose an item from Project")
# label.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
@@ -12423,7 +12446,8 @@ class App(QtCore.QObject):
def setup_obj_classes(self):
"""
- Sets up application specifics on the FlatCAMObj class.
+ Sets up application specifics on the FlatCAMObj class. This way the object.app attribute will point to the App
+ class.
:return: None
"""
@@ -12504,10 +12528,10 @@ class App(QtCore.QObject):
def on_plotcanvas_setup(self, container=None):
"""
- This is doing the setup for the plot area (canvas)
+ This is doing the setup for the plot area (canvas).
- :param container: widget where to install the canvas
- :return: None
+ :param container: QT Widget where to install the canvas
+ :return: None
"""
if container:
plot_container = container
@@ -12571,8 +12595,8 @@ class App(QtCore.QObject):
toolbar button or the '1' key when the canvas is focused. Calls ``self.adjust_axes()``
with axes limits from the geometry bounds of all objects.
- :param event: Ignored.
- :return: None
+ :param event: Ignored.
+ :return: None
"""
if self.is_legacy is False:
self.plotcanvas.fit_view()
@@ -12723,8 +12747,9 @@ class App(QtCore.QObject):
def toggle_plots(self, objects):
"""
Toggle plots visibility
- :param objects: list of Objects for which to be toggled the visibility
- :return:
+
+ :param objects: list of Objects for which to be toggled the visibility
+ :return: None
"""
# if no objects selected then do nothing
@@ -12741,6 +12766,11 @@ class App(QtCore.QObject):
self.plots_updated.emit()
def clear_plots(self):
+ """
+ Clear the plots
+
+ :return: None
+ """
objects = self.collection.get_list()
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 0256853a..5176ea16 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -447,10 +447,10 @@ class FlatCAMObj(QtCore.QObject):
Will modify the filter string that is used when saving a file (a list of file extensions) to have the last
used file extension as the first one in the special string
- :param last_ext: the file extension that was last used to save a file
- :param filter_string: a key in self.app.defaults that holds a string with the filter from QFileDialog
+ :param last_ext: The file extension that was last used to save a file
+ :param filter_string: A key in self.app.defaults that holds a string with the filter from QFileDialog
used when saving a file
- :return: None
+ :return: None
"""
filters = copy(self.app.defaults[filter_string])
@@ -7007,6 +7007,12 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
self.app.worker_task.emit({'fcn': worker_task, 'params': []})
def on_exportgcode_button_click(self, *args):
+ """
+ Handler activated by a button clicked when exporting GCode.
+
+ :param args:
+ :return:
+ """
self.app.report_usage("cncjob_on_exportgcode_button")
self.read_form()
@@ -7014,9 +7020,9 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
save_gcode = False
if 'Roland' in self.pp_excellon_name or 'Roland' in self.pp_geometry_name:
- _filter_ = "RML1 Files (*.rol);;All Files (*.*)"
+ _filter_ = "RML1 Files .rol (*.rol);;All Files (*.*)"
elif 'hpgl' in self.pp_geometry_name:
- _filter_ = "HPGL Files (*.plt);;All Files (*.*)"
+ _filter_ = "HPGL Files .plt (*.plt);;All Files (*.*)"
else:
save_gcode = True
_filter_ = self.app.defaults['cncjob_save_filters']
@@ -7055,10 +7061,16 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
if self.app.defaults["global_open_style"] is False:
self.app.file_opened.emit("gcode", filename)
self.app.file_saved.emit("gcode", filename)
- self.app.inform.emit('[success] %s: %s' %
- (_("Machine Code file saved to"), filename))
+ self.app.inform.emit('[success] %s: %s' % (_("Machine Code file saved to"), filename))
def on_edit_code_click(self, *args):
+ """
+ Handler activated by a button clicked when editing GCode.
+
+ :param args:
+ :return:
+ """
+
self.app.proc_container.view.set_busy(_("Loading..."))
preamble = str(self.ui.prepend_text.get_value())
@@ -7116,9 +7128,9 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
"""
Will create a header to be added to all GCode files generated by FlatCAM
- :param comment_start_symbol: a symbol to be used as the first symbol in a comment
- :param comment_stop_symbol: a symbol to be used as the last symbol in a comment
- :return: a string with a GCode header
+ :param comment_start_symbol: A symbol to be used as the first symbol in a comment
+ :param comment_stop_symbol: A symbol to be used as the last symbol in a comment
+ :return: A string with a GCode header
"""
log.debug("FlatCAMCNCJob.gcode_header()")
@@ -7219,6 +7231,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
def gcode_footer(self, end_command=None):
"""
+ Will add the M02 to the end of GCode, if requested.
:param end_command: 'M02' or 'M30' - String
:return:
@@ -7232,11 +7245,11 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
"""
This will save the GCode from the Gcode object to a file on the OS filesystem
- :param filename: filename for the GCode file
- :param preamble: a custom Gcode block to be added at the beginning of the Gcode file
- :param postamble: a custom Gcode block to be added at the end of the Gcode file
- :param to_file: if False then no actual file is saved but the app will know that a file was created
- :return: None
+ :param filename: filename for the GCode file
+ :param preamble: a custom Gcode block to be added at the beginning of the Gcode file
+ :param postamble: a custom Gcode block to be added at the end of the Gcode file
+ :param to_file: if False then no actual file is saved but the app will know that a file was created
+ :return: None
"""
# gcode = ''
# roland = False
@@ -7482,6 +7495,13 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
return lines
def on_toolchange_custom_clicked(self, signal):
+ """
+ Handler for clicking toolchange custom.
+
+ :param signal:
+ :return:
+ """
+
try:
if 'toolchange_custom' not in str(self.options['ppname_e']).lower():
if self.ui.toolchange_cb.get_value():
@@ -7503,7 +7523,13 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
self.app.inform.emit('[ERROR] %s' % _("There is no preprocessor file."))
def get_gcode(self, preamble='', postamble=''):
- # we need this to be able get_gcode separately for shell command export_gcode
+ """
+ We need this to be able to get_gcode separately for shell command export_gcode
+
+ :param preamble: Extra GCode added to the beginning of the GCode
+ :param postamble: Extra GCode added at the end of the GCode
+ :return: The modified GCode
+ """
return preamble + '\n' + self.gcode + "\n" + postamble
def get_svg(self):
@@ -7511,6 +7537,12 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
pass
def on_plot_cb_click(self, *args):
+ """
+ Handler for clicking on the Plot checkbox.
+
+ :param args:
+ :return:
+ """
if self.muted_ui:
return
kind = self.ui.cncplot_method_combo.get_value()
@@ -7528,6 +7560,12 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
self.ui_connect()
def on_plot_cb_click_table(self):
+ """
+ Handler for clicking the plot checkboxes added into a Table on each row. Purpose: toggle visibility for the
+ tool/aperture found on that row.
+ :return:
+ """
+
# self.ui.cnc_tools_table.cellWidget(row, 2).widget().setCheckState(QtCore.Qt.Unchecked)
self.ui_disconnect()
# cw = self.sender()
@@ -7566,9 +7604,14 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
self.ui_connect()
def plot(self, visible=None, kind='all'):
-
+ """
# Does all the required setup and returns False
# if the 'ptint' option is set to False.
+
+ :param visible: Boolean to decide if the object will be plotted as visible or disabled on canvas
+ :param kind: String. Can be "all" or "travel" or "cut". For CNCJob plotting
+ :return: None
+ """
if not FlatCAMObj.plot(self):
return
@@ -7612,6 +7655,11 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
self.annotation.clear(update=True)
def on_annotation_change(self):
+ """
+ Handler for toggling the annotation display by clicking a checkbox.
+ :return:
+ """
+
if self.app.is_legacy is False:
if self.ui.annotation_cb.get_value():
self.text_col.enabled = True
@@ -7625,6 +7673,13 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
self.plot(kind=kind)
def convert_units(self, units):
+ """
+ Units conversion used by the CNCJob objects.
+
+ :param units: Can be "MM" or "IN"
+ :return:
+ """
+
log.debug("FlatCAMObj.FlatCAMECNCjob.convert_units()")
factor = CNCjob.convert_units(self, units)
@@ -7723,6 +7778,11 @@ class FlatCAMScript(FlatCAMObj):
self.script_editor_tab = TextEditor(app=self.app, plain_text=True)
def set_ui(self, ui):
+ """
+ Sets the Object UI in Selected Tab for the FlatCAM Script type of object.
+ :param ui:
+ :return:
+ """
FlatCAMObj.set_ui(self, ui)
FlatCAMApp.App.log.debug("FlatCAMScript.set_ui()")
diff --git a/README.md b/README.md
index 54b7e758..84ca08fc 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,9 @@ CAD program, and create G-Code for Isolation routing.
14.04.2020
- lightened the hue of the color for 'success' messages printed in the Tcl Shell browser
+- modified the extensions all over such the names include also the extension name. For Linux who does not display the extensions in the native FileDialog.
+- added descriptions for some of the methods in the app.
+- added lightened icons for the dark theme from Leandro Heck
13.04.2020
diff --git a/share/dark_resources/about32.png b/share/dark_resources/about32.png
deleted file mode 100644
index 91c2caf1c3c32a52dc722f3900addb264a9c7260..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 1996
zcmV;-2Q&DIP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006
zVoOIv0RI600RN!9r;`8x2IEOYK~z}7otIl|9aj~GzqR+woSTnN9GW<`vY#wIL%p9L%2tCr4XRJN@|JT3%wf5e^ZT`j|KD-yq11Q-k
z=&iY2W(x>~Vr9k{Gh=Yid9B(zQ*S(d1ZV-??W`;R19TnmooqJs-01Kfx#3L%WHTvh
zO(<1eT-QS@FkXw5VwL=@5=+a4LZe=KxqSWffw@z^Tm;-tL}2{OzulY7rVsACXDl~5
zvVqwfb>^3wEZ%B$%rn8?zLb!*A!);{l_CpE`9iHY_w3ZMXC{HhT8c<-@ZTNUv2Ezd
z`*&^UU-J#7=IS(CrW;tKa{&PnpGZP^EZtnDSeSqH%Io`{0?NJAkY3=s?;C$|WOx&2
zu9R3QyOv4uN+%Kl!_@Jz9OQcw21$%we47`je7aR
zKb-{XfUy9w+0=8JM>cTcpDSIF6M_dyh)}9|ym4wJl-mD)oMbq?!$5YrkL1AE~5?;iwe7VyCE-~coEW@kNjMD8y*u{p_S#xtucmvYTRl%N6=O88AQr|B8Q
zfRZGM+~{s#5-2JZI|tVFg&ocS60hq(_FBW^hlgj`_u^C+0c|NPOQGAt)>yXxY}p#i
z)@Vy1mLlaOu+r&v*vMG3_8UpsYf%GNZ+8
zX-B_YXi{yMFbXA|k*$>i6{w@M|4qCr`sy2u2bq+iRxK^IzqJfzM#OAE;Kt1c^`?nB
znIg=o3ObuoYZGWIAxfcCOo2dt;~5eO7t^XQ;BQKvWsH07=1Tcnuj2d9fnFAwOBGE`WO
z#e0~MgDfL6U$c)3=u(4UI(CJ}=u`ZW}2n=`J06+~|bN^Ba?
z6o*72k7!V!4o+oPQR+4e31$GO1vuwzvP^iAyj{UJNOWv?q)T9yRH($QvPM<&yu
z*>se1TVXjC**?w0kmlNSiIc}qpE&pH2loT>z#LE_IHt!Br3Pr_FCTep{rE$7Y1{cU
zl7My#)={40tyw9BXcZdKvJ`_kVWi*V?E5!4{qETl=YR9ieqaH(9tU4dpiQEgzx3Lh
znZbKLPGtH&k7!4x9B`nRowjz5L!UuCf&hy;v#blKy93Tq}Y~AzYM-uBscU!4}aqXlxCDZ+bq7=1idC|D_
zg=RHBRa?4xHr8ZT0=F0Wf3Ide)JOm+{4;$zcz0qcbOVq&QIn|#@1N{)x`rYaU05UK!IV~_bEipAz
zF*rIiH99pkD=;)VFfe?iwD|x403~!qSaf7zbY(hiZ)9m^c>ppnF*z+TIV~|YR53U@
eGc`IjG%GMPIxsK|`3yw>0000s1M_&9clSI#|s4Pek_^5?0bS`iLkl|
zQ$v78Uo4kozl*@p+^c53khf>R8pkBwKR7*`(w>VpBD@F&ukTvVZZZ<^0oaN*x^J
zpBe+*u3F+6QIe8al4_M)lnSI6j0}tnbPY^&4NXD}46F=ItxSz{4UDY}47$QszeCZG
bo1c=IR*74~Z!Td_TrhaL`njxgN@xNA1LTTq
delta 217
zcmV;~04D#a1L^^g8Gi-<0036bj#mHx0I^9#K~y+TwUprz1Q85{vmIzf1(cu@Eu;mV
zD1i=?q60U~?T)oMa&sGItwAZ(ierorLb$cGS2hLB6jF_Sn}X_L?|oBYjCnjT
zsc5vt9g7ooDcS~ldu}ts4R*6v!2g53u{Tclaz!Y6tQ8pxe_GmAld1gj8{tARQ79%kR8
zC+6RpfAIXF`G?-|tuR>_^6G|xg1lc6V^`41B?8ZQxKiD(znyB76rwDa%A>jFjNw(i
zpslrScHe)?+}>iexMG9vdG@j=<<1NO0y49WQpDyzboR((ky6b2;9LLUs`|vBS%SJ1
z!kIveRZCnWN>UO_QmvAUQh^kMk%5tcu7QcJp-G5=ft8_|m64&Yfw7f=L6k2us)pSB
al+3hB+#0k6c3%bBz~JfX=d#Wzp$Pz#6>fk4
delta 140
zcmV;70CWHP0-XVn8Gi-<001BJ|6u?C0Axu-K~y+TV{B+>_|Jd_8X6iH(ZxV~Y-$-n
zg2)=s`N#%gQ;XFAY_`M1&@H2m3n&T$B&VT-1p#ls)xtv?Tj0S$9X(c%)#5Y&J<4#!
u6zvQ^PB>(Ff#^USP0Ihld4ZCo3;?{tsRxjZ9L4|u002ovP6b4+LSTXbemAWE
diff --git a/share/dark_resources/addarray20.png b/share/dark_resources/addarray20.png
index f5892d5c084e5cba2cc427eb3105c46165133107..ce121e3487106922c644b93152f1f1945dfb3a86 100644
GIT binary patch
literal 540
zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc0wmQNuC@UwmUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^+
z;1OBOz`!jG!i)^F=12eq*-JcqUD=fWgDYg`bDIOk~oIVpcnS}H>mvL-bugi3QrQO``
ze>}gt$uIT#xbpa|lU>hmed&0AX5kFZt_cGC2R#dKAFknkbSRNwS;)-Waf{v6a?5gh
z_)3CH8}6)O6x;eYXG*Tds+wqoFF1m8Y#!b{
zwP)|+uyp$b=eg75C8Z@Kr2q213#tBc<%-1h|BW9$R3Glzqa85mUWFw{fQkei>9nO2Eg1J~2eNk9z@p00i_>zopr0Jr7G(EtDd
delta 159
zcmV;Q0AT-|1h4^+8Gi-<0051N9Sr~g0C!15K~y+T%~U}Sz#s@4Kkv`CWC?~SbkTs*
zqlQx2iU7E;-~bTsiPcCMpk>3FSjJvWW4HzIOGC;q5dQ#El$jdgjXCqyMw%(=oPKkx
zL?~bsAJ2?`09W+Q*Rbp_rw5xk*EjPbrgwXnL$r8}`-7=<3m7)bln1>Z!v`U(mo5MR
N002ovPDHLkV1f%&LXH3c
diff --git a/share/dark_resources/addarray32.png b/share/dark_resources/addarray32.png
index 7e855a71b13cc200253a229314874f50dba1290f..b4682112842c0c74cb60ef22d4bb51a4f88936ed 100644
GIT binary patch
literal 423
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50
z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-G$+Qd;gjJKptm-
zM`SSr1Gg{;GcwGYBLNg-FY)wsWq-oLD=Hv9RlHgSC^XB{#WBR=_}dUez6J#zotBCB
zB_97*SAJ+-ww_r?^p=975PM$Mp{;jhmvqUT`_NFjfq}n2_*AI%Q=8R4>QZ*7Yl1~6zEFT
z64!{5l*E!$tK_0oAjM#0U}T_cV4`bi5@KLrWoTw)WUOmoY-M0@_L7hTiiX_$l+3hB
W+#2@uulfVjz~JfX=d#Wzp$P!~hlue2
delta 234
zcmVfa)F!P@)|m)Bn$0+L)|>9l+j#
zb^wyN3P5%JKClv2zkAy0uI`t;UJ4)s+oHgK0?_G6*1N{jLt|(MSPq)^WkxZndk9+;
zAoo++l^(*(q7nd2^(>+c+S!5x>^}|3PAR_IA-y-_@}02S0&+$ffO`2uiPJx-v;uYj
kdkfkDNa890)wTP;3;k(Q95vAPaR2}S07*qoM6N<$f+=@t;{X5v
diff --git a/share/dark_resources/aero.png b/share/dark_resources/aero.png
index 4b17865e8b5475482ba5f8ba2275ed42ad2d8285..ad251cc0ece79a2bf520847ce9f70101e5fbc64f 100644
GIT binary patch
literal 1140
zcmeAS@N?(olHy`uVBq!ia0vp^hCpn=!VDyr?d5&Wz`$6O>FgYknVihPpfRy_qOHea
z2brVsm%A2;3UYT@q^$50b8(ef+U2?-;1<_fs~IuBSbe1?iHN%&-1^|b@uaHG
zhdT=VVJIvt4Jw%^^nbcY)RBsUJN@O~<;vePER0KAB{_p35Skd>g&2^8X&F0LPbG~;vuhGyv
z^8CnSw%7?jCcfTuI)4r~AGeKh%96>Sk0>T>yl|{Ydh?=%LjJ<-qM?gx6d!LoRN1{b
zYTc%1wm-R>Ept_mmd;Y{NaQS3QE+k-Rh^Qk=(O6ct5fBzyX~LDefExeGh7&H|6fVg?31We{epSZZGe
z6l5>)^mS!_!on*mAU$WHIX_S+$J50z#NzbZ3yORV20X0~Pu&t!u;p?;_{f53lj(+J
z;|qVA)ouzK-=9_LzhwDy_rfV%LKY%zK{7`JGFEghp{#bpct`N_;Qe_0~kk8br-c5&vRaul{5H`#S;ra#=HuuKNhISGB}7q9i4;B-JXp
zC>2OC7#SED=o*;l8k&R{7+4vaSs9t@8W>v{7+B6V1Nju8AvZrIGp!Q029E=M?|~Ym
zKsKaSWTsg;WtJ2Nq!tAy<`(3nGFa#+fRNBzJ9VHcMYt*#pesT$b3raKw6roXu`)DQ
zFf_3;HMcUh*r6(T1E^RSuGlj-F+J5MH7~s+gTd5H=F*ZCKxrXV>F~@Hpsb0d{iJ{L
zDDDZ)Pb(=;EJ|f?_w)@=Fw!$L03u!6tBgQZ(jYT{+14sKzo4=xGd-h(A)quVCo@^W
zB|kSYGjH2O!)Tx~C7805)Z*l#%z~24{5*(pNu`-NCAyh;3dKS0PCn_5!a&ucFx9z<
wd8KKI$t9&lsYPJrKJzA=0xIBxE67ht&0zp(jZW}%2Ffsay85}Sb4q9e0HaZzN&o-=
delta 454
zcmV;%0XhEk2-E|R7=H)`0000~lMvJZ00EmxL_t(&L+zNcY63wJhQ}`8gM_OSthBjQ
z5^KqW2q|x`2uVP}DqJJB;tPqbq!BA2LJ|TAb7bKN2KIJlc8_DW5#)Bx@Bj90cI`k5
zMyCY~pb$;5s3z0|V*37$>U<#xO~x)C4I$#(&9bf-y`|DK$Zgk8!e^
zU<{K~N==aBW1Ore7{er$QWGxm8DqYUF`{9K7Dq^g`27^SmsnwI2_dp9gFMd>NaTJZ
zMXSrqLg05&AVDFdK!QU^fJA}d28jm22@)0J8=J5q}T}vfI7Fa=GvV2@Y{Oy+gNqQT9V@et(BgR}Tt-0MqF+TwV8JbbG_r
z!Gl3q08H9$MJP+CYA^`IWO82`uuBCY(sT%eL65~o5QuYIacg6<*}{6g@_L}H4RMJ7
z4o(O$9^XNdT#{`>gWx=ShWg6?8{e^{M)Ka?8mIqvf7AOHXW07*qoM6N<$f_d=6E&u=k
diff --git a/share/dark_resources/aero_arc.png b/share/dark_resources/aero_arc.png
index 729f65236bd161914d3c7564f6a01d0e7d26f267..612858ac9f775725da8e22dddf373dae581266eb 100644
GIT binary patch
literal 1151
zcmeAS@N?(olHy`uVBq!ia0vp^hCpn=!VDyr?d5&Wz`$6W>FgYknVihPpfRy_qP552
z0Fk!;%eq`&F~3oGG-07tq(HodmuPpw!Y!gvr3O1+a?dhR(bVf}%077Tc+%B_MHQnfdy3l#UyBj*pJJQW`=YF;;>=0FL
z{V}KF%mQv9`=Z#gpS{Hg6C2apdP<7sS-9wk-HOOd4l@aPr1@yWqO2+UDKTLd`GsMp
zL$B>ouTL~szIMqDzibIZ9mPHtmlG=%wHWERWL)wAJtE&PF~I8*2fyM
zz^UlZgZdBE+tTWa4*7DqHJ%f{{ZE2%S6QRm*=_s#b9Waq{g~gVz4qz)D~&h(FJwAw`ue{-)daRL(`=`r7pDG{x?b)Zv&2xw8ZuYx7vz}YjGF&oQ{Z#tF
z0|5!$fN#5w?`D2m{CoRy%l-1X*+olNZ9bz3j1Prmk04(LhAK4%hK3dfhF?ITh8GMB
zr3MTPuM!v-tY$DUh!@P+6=(yLkPGk$asB`QKak1J#=_6fBQ7o~Cnv+r&7rBO{`vD~
zptx{s;c_6wQ4-`A45Yze`}3fMKn7!yx4R4Deg6vfL(m
zWTkz_4i39pdh$yj22QlEw-a&Z6glp_PUB{PNUNS`;FMz?pBgSndCI*u$_&x|WS6nc
zvh?fCFz!S#VKdST7*d=dCuG$yCuL^X5YKdz^
zNlIc#s#S7PDv)9@GB7gGH89aNGzl>dX5O(MCyw7I8TF`)}
z)c^)Ch+Hh12{R#>fDI?XFj=L{1S>wl&SpX|Ojao~!HQ3?vwxWo43kyLOt9h;>})0k
z!(^2*6Rh|IJDUl?Fj=L{L`Zzjxew=@YFMhp5fUN3KGoi(R+uayL{St_mL&qIyicX5
zKg1omya-=-q!+&4zbz1K)b!ST@P{bt3GvB^{5aCFdE&!!QnBSpPh)U
z;L#um0F$Pz2xkcS2BSa>hZkD|G*l3x*E@x7_ejJ>6o{X;;$&k!U%+hkQ0os(Hq;@0
zJ2)XkzdwLZXP<2&8HD74DJewA@iwH5L4>5VYn#xE1xmkNb|xAF@!#!8^#&z76Eti6
zwTG(O$`-=A^7;OaWT0v)O9=nYDrA?NHALvlW)PuCX}9|X9!A(XpWh~100000NkvXX
Hu0mjfT8hf5
diff --git a/share/dark_resources/aero_array.png b/share/dark_resources/aero_array.png
index b8efdcb2371be838c3d67398f2822efe53616fe1..011f5c7503d0e63f1a676b80c72a3dffe433c8f4 100644
GIT binary patch
literal 1157
zcmeAS@N?(olHy`uVBq!ia0vp^hCpn=!VDyr?d5&Wz`$6W>FgYknVihPpfRy_qP552
z0Fk!;%eq`&F~3oGG-07tq(HodmuPpw!Y!gvr3O1+a?dhR(bVf}%077Tc+%B_MHQnfdy3l#UyBj*pJJQW`=YF;;>=0FL
z{V}KF%mQv9`=Z#gpS{Hg6C2apdP<7sS-9wk-HOOd4l@aPr1@yWqO2+UDKTLd`GsMp
zL$B>ouTL~szIMqDzibIZ9mPHtmlG=%wHWERWL)wAJtE&PF~I8*2fyM
zz^UlZgZdBE+tTWa4*7DqHJ%f{{ZE2%S6QRm*=_s#b9Waq{g~gVz4qz)D~&h(FJwAw`ue{-)daRL(`=`r7pDG{x?b)Zv&2xw8ZuYx7vz}YjGF&oQ{Z#tF
z0|5!$fN#5w?`D2m{CoRy%l-1X*+olNZ9bz3j1Prmk04(LhAK4%hK3dfhF?ITh8GMB
zr3MTPuM!v-tY$DUh!@P+6=(yLkPGk$ah*MRGLXs6#=_6fBQ7o~Cnv+r&7rBO{`vFg
z(3vv>cmLQ3l;$W2@(TviV6gpp&_W=CG0EHAh4bUhrEh>7&H|6fVg?312@qz~TBWW4
z6l5>)^mS!_!on-cZ=B*cF&ijU*kacemBi1R#9gA~Yy)QZeBE2qqo;(*km;Kba5oKyx29R&~)dTXZ+RHX=4
zzKt=WVTm?JNQC%(6}y*MV`~W^vMhr<&k;!Eej-iX
zF|!c(o)kz_2q}>05E39sAh#{M1Scfi^aq4;YPJNFd1}5M;f6
zhw=C|800J<5PxK~dV}e75(E+*V!Qo>di~_Xh)ZR1l)mxrKJS#bP50#Hp>gwXs+%VLqP){h_T5afrVT
zP6*NK^`X(YB-=;^!Fgax3Q^{GTjo0oQ6?qdckKE5zfEWGAwrG#=AP>_(Q)FOd*AL>A&N$<5+>ZO1$8a(1@;32e)qO-_kyMX0000<
KMNUMnLSTa6tI`kv
diff --git a/share/dark_resources/aero_buffer.png b/share/dark_resources/aero_buffer.png
index 41f26dd74baed6b0bf1ac630e71c7553cc6add28..95778e3a8a9ae3bb836a823827b9ef8c6f105e20 100644
GIT binary patch
literal 1159
zcmeAS@N?(olHy`uVBq!ia0vp^wm|I0!VDyPS2o^YU|_7xbaoENOipHC(3n^|(c0s1
zfJoc_WnHeXnBOQony}C+QXt;KOSC&-;TF-TQiGi@xo4TEXzKMfWgk3vJn8Deqmkk4
z;f?||4Lf#NY3}mqe6H3iW+=DgPXGUT|DWG0W?UGTw(6!K--=nOD#?L{lVe49#|b*<
z|9W_M%Ml;jc~L%xH}8A5vj3Idq0M`K|63!cnr?JJUFf{w-3=Y)9qDGeb3fY^c8IFB
z{+Ls7W&yX5eNk-L&)(vLiH+%PJtal+EL?QNZbjrJhna*t(tNaGQPvdwl$bD!{KBx)
zq1X1P*C!e*U%O<7U$%syj$$8+%ZU|>T8wmDGOl|VPF(VNMSJ~;kLo8>C$DC4>thXB
z;8gVILH&p7ZE1ByhkUu*8qbN}{wKk>tE|!O?6&>=xw{LQe#~#wUi)LqiJ#!!Mvv!wUw6
zQUeBtR|yOZRx=nF#0%!^3bX-A$OZU>xc>kDAIM~9W8vrL5f>Mglat}*=Frqs|NQwg
zP+T~+a5<3TC<*cl2GU@#{dv$rAcHZ<+ueonKa=h~AcwQSBeIx*K~DmN8MRiaD*y%A
zOFVsD*`KiRiVCo%t>el83e|bKIEHu}e>-U-Z-W63OYAOQrYC_Ct<(AhHRiI}m^Cu~
zn<&6K$^WI^ru&61lTH%=
zpU0Ov{45XOvFO^aJSNK%TvuBc3x1e2Y5lVAl}`(6=kcGbH2r_$@jsRS@fM6d>t%&L
z-|n3Xbct$-YeY#(Vo9o1a#1RfVlXl=GSD?J(KR#)F)*+)G_x`=)ip4-GB9|fuE36>
zAvZrIGp!Q0hPhQUb^|p?fow>v$V{_x$}A}kNG%FZ%q_@CWw6ju03o5bcIrS?if~mf
zKv#rh=7L;eXlZ3&VP$Bd0Ad(h8JVX=x`_i73&RzA<|d}6`lRNimt-)Q8ys&>mIq1;
zp-P8mrT}Hl44Lai)}y#5I6tkVJh3R1!QIn0K*31Q&;W>ZZLcx{RY`-)0On+?H6Ahz*%9LQrQc{bPi!uvJGV}8w#wC?z=9K7W<|z~h
zxjXr!I|>6;i^5drCgzo_gGr7r*g
delta 498
zcmZqYY+#unQP07~z`#)7KIb(91LJW|7srr_xVJOyy_p>aj;ha{z^}AYRQvJ~uPuCa
z6B?er6%02(vc>C_oo8`U=kvD#yt^S>tcWEKV
zdcT%4EH5HL+Ajq}6|yGeAAR)Cu^G-*I+2inBf792ETObF5yZj5ZoYY2;&W~f=cf7z
zzBjXZ{{DXXS8h*!2EVwox~Eg-tRlue_u8+Y{dW0?)93Pi2VEV0vxzgm6^;?vqF+#W
z!R~;oQ+-X{#k+5NH;0IGp3TZP%Qu;6W5FoSefGiYuiC!L`|Ep~yW7$}Tz%F0>~rMe
z2T2RI-!6Yu#$WcA+g$tR>XYkySxlJwkAE*IsqvaFo_@}H%YzGIGp24?yOP`cy|uc=
zmyD9V!8f9&FJx~ne)Zjd&MH|EtM^wgt=b!7cRA_fm5heSt<8@A&1WUOc=(~KYOiy8
zR(JC^!vq1&*iwhg<@%-a+4*bR&)Mx?-LvqDqNbX6Cuy61lJf1>ODl_9%y4o36K##V*fvfV6Q8zyzZREuG0w#e$M
e-it$iv2V3z2)kZB`xP*989ZJ6T-G@yGywp-@A1O`
diff --git a/share/dark_resources/aero_circle.png b/share/dark_resources/aero_circle.png
index 63e0c9bad96fd838c6c0c99d920876626d80a20a..73d4f76d972eae9cc2a290d37b0dc0f8cc468f29 100644
GIT binary patch
literal 1158
zcmeAS@N?(olHy`uVBq!ia0vp^hCpn=!VDyr?d5&Wz`$6W>FgYknVihPpfRy_qP552
z0Fk!;%eq`&F~3oGG-07tq(HodmuPpw!Y!gvr3O1+a?dhR(bVf}%077Tc+%B_MHQnfdy3l#UyBj*pJJQW`=YF;;>=0FL
z{V}KF%mQv9`=Z#gpS{Hg6C2apdP<7sS-9wk-HOOd4l@aPr1@yWqO2+UDKTLd`GsMp
zL$B>ouTL~szIMqDzibIZ9mPHtmlG=%wHWERWL)wAJtE&PF~I8*2fyM
zz^UlZgZdBE+tTWa4*7DqHJ%f{{ZE2%S6QRm*=_s#b9Waq{g~gVz4qz)D~&h(FJwAw`ue{-)daRL(`=`r7pDG{x?b)Zv&2xw8ZuYx7vz}YjGF&oQ{Z#tF
z0|5!$fN#5w?`D2m{CoRy%l-1X*+olNZ9bz3j1Prmk04(LhAK4%hK3dfhF?ITh8GMB
zr3MTPuM!v-tY$DUh!@P+6=(yLkPGk$asB`QKak1J#=_6fBQ7o~Cnv+r&7rBO{`vD~
zptx{s;c_6wQ4-`A45Yze`}3fMKn7!yx4R4De7d=d6G#bNP%oft;kHXa>^_z4oEEuPRuRHNoBCmQ2-&Kw|444Rf=#`
zEAp>EalY;rw=ntv9oyK%4s9
z3GzZg+F{E&r)J3hQDi)QTid0TW2K6(hxSkBgJw5aRy#0ta-3ojpLX`?zO--6$?Gh4
z+@5>;d2M=m*?Lyq9Z|dq42>N}T??J&B!oCz>J0P=(kN_Fkxx!9Y$BSysHetjW&F}9
z!5inWxqGzy*l+!N+U5hdR9ieIv0O57RZzcQEOf=kn78qKOk+iB0qY~#L#!SG9C;HG
z1m-9>Dt^0f|KZOUkGQQ(P79=8e`P!NI9$l1fP*D+?Y;z~%GJC=tSn7B)8`w^_RVgr
zXupwHej#tZ>?=hv``@dAukLkHIFRv$>A84#L3#Dru!DOYGZ;dm@?AAFQ>^`r3ST{FVV2=}xA68`
znVpGz_vXAx$VLksMhLZ&a&vt{k~PXZ)(oZesXK0
z#$1hG)hTv#1;PfqLC)srz*x$cYB2)lk({nZuA67aOPM0oe92c@^&9R4tx|KadB
T>>D)&7^MuJu6{1-oD!MFgYknVihPpfRy_qP552
z0Fk!;%eq`&F~3oGG-07tq(HodmuPpw!Y!gvr3O1+a?dhR(bVf}%077Tc+%B_MHQnfdy3l#UyBj*pJJQW`=YF;;>=0FL
z{V}KF%mQv9`=Z#gpS{Hg6C2apdP<7sS-9wk-HOOd4l@aPr1@yWqO2+UDKTLd`GsMp
zL$B>ouTL~szIMqDzibIZ9mPHtmlG=%wHWERWL)wAJtE&PF~I8*2fyM
zz^UlZgZdBE+tTWa4*7DqHJ%f{{ZE2%S6QRm*=_s#b9Waq{g~gVz4qz)D~&h(FJwAw`ue{-)daRL(`=`r7pDG{x?b)Zv&2xw8ZuYx7vz}YjGF&oQ{Z#tF
z0|5!$fN#5w?`D2m{CoRy%l-1X*+olNZ9bz3j1Prmk04(LhAK4%hK3dfhF?ITh8GMB
zr3MTPuM!v-tY$DUh!@P+6=(yLkPGk$asB`QKak1J#=_6fBQ7o~Cnv+r&7rBO{`vD~
zptx{s;c_6wQ4-`A45Yze`}3fMKn7!yx4R4DeC{*w1;uvCa`t2n{zGefS*2Mm}V8%~@7GB|IeFrl1bNhT3
zdBuL%uOOx}FF<0SikX;_|GYaIeL;at{H+T`+zmynt{e%7^9xFwa?taX_4K1zR*Pn6
zeckqI#`kZ9tqZpaZS2g5dY#SttGHuVM*YRPwa!BS^}{)?KfL##y6(vSCpX{lt(9Z?
z)4P@%=oHlw*NBpo#FA92BVB8Vqv&q&)mfHRG-wm^pXq)Q!|-MOI84-
zg;1r#GgE-FCYJV-{>h`bCpbT?q&%@GmBHQ9H$cHi&(HvfbZxIP0#!+a%m8L(tK|HG
z%A(Blj1q=`(xjZsWCfS}+{DbhZ4(Wnfy$I%%2HB`lZ!G7N;32FAjTz?X6BUWX67jr
z2e~`>q&o@&Rg1z@=O*TrrX?nqloq8HftCBrn{W!KfDf)9KP5GX0i-oL!P6Ni!{F)a
K=d#Wzp$PybF{iKq
literal 505
zcmeAS@N?(olHy`uVBq!ia0vp^hCpn=!3HElCJS6)U|>Ap>EalY;rw>SelKQ6fn(}(
zC$LYv;-z)@h}RZAJC6gOzHtRAI%#
zK&?0O>=)j(yLr`Fr|w(m@>T4u4hSZ2@67wz-hn=Q%`isrJt{T`^;6{A%wwB@!6XW+818F?HoGxy7e-rn))pv~^=
zotEY
U&7M}40Hc(_)78&qol`;+0F+zY5dZ)H
diff --git a/share/dark_resources/aero_disc.png b/share/dark_resources/aero_disc.png
index 59f32773d8d94a015844404db7ff4de385441f62..0f75fe5377287190cde69cfd66f68710181d4fc9 100644
GIT binary patch
literal 1143
zcmeAS@N?(olHy`uVBq!ia0vp^hCpn=!VDyr?d5&Wz`$6W>FgYknVihPpfRy_qP552
z0Fk!;%eq`&F~3oGG-07tq(HodmuPpw!Y!gvr3O1+a?dhR(bVf}%077Tc+%B_MHQnfdy3l#UyBj*pJJQW`=YF;;>=0FL
z{V}KF%mQv9`=Z#gpS{Hg6C2apdP<7sS-9wk-HOOd4l@aPr1@yWqO2+UDKTLd`GsMp
zL$B>ouTL~szIMqDzibIZ9mPHtmlG=%wHWERWL)wAJtE&PF~I8*2fyM
zz^UlZgZdBE+tTWa4*7DqHJ%f{{ZE2%S6QRm*=_s#b9Waq{g~gVz4qz)D~&h(FJwAw`ue{-)daRL(`=`r7pDG{x?b)Zv&2xw8ZuYx7vz}YjGF&oQ{Z#tF
z0|5!$fN#5w?`D2m{CoRy%l-1X*+olNZ9bz3j1Prmk04(LhAK4%hK3dfhF?ITh8GMB
zr3MTPuM!v-tY$DUh!@P+6=(yLkPGk$asB`QKak1J#=_6fBQ7o~Cnv+r&7rBO{`vD~
zptx{s;c_6wQ4-`A45Yze`}3fMKn7!yx4R4DegHKtBE?JZm(Bfj
z-!EKa>)Z}!m&?)9OHX*rUGo0TNAuSDXv6X>A(N=yt6b-rgDVb@NxHT}p*xm%xAO*4^
zwIVak$|%CzZiMM*)O{-rA`HRVl(%xd2@el9>x~iJ_&HfrXW!i2{gW
zVr6K4VXbP0l+XkKt$m(n
delta 467
zcmV;^0WALa2;l>e7=H)`0000~lMvJZ00F2;L_t(&L+zL`Yr;Sj$Ddol4^o_4oa$ny
zVrTJ#2pw}7N-bD$5|`py{6gX?U8Ivxp%tO!#U31*hM4!>T?{XaAi037#phz#xO~x)C4I$#(&0Yf-y`|DK$ZgkFl|u
zU<{K~N==aBV{EJ@7{er$QWJUNGsgTFV?@IeEsl@~@%JnCEV07Y5<)~#1aTZAkjV2y
zin_zhLg0T=AYLJ)K)gdpfCPcy1_=hi2@(|Id%J_d(GZV_hRbXtkOwHoQQjZN;sP`FsJh*<0#_w%hoF
z4dqdv#UcJXIAI67-5xX=mq#|zI-m6d2nLaLU^**^G)zl*0GtC?A|a>=h1j3p)kL1J
zHHGe}#GG*7T3IQ$d#ut;?8-p6->mZNa!YCA)XAg}rzR$K|1Y(P*g1#cQabFgYknVihPpfRy_qP552
z0Fk!;%eq`&F~3oGG-07tq(HodmuPpw!Y!gvr3O1+a?dhR(bVf}%077Tc+%B_MHQnfdy3l#UyBj*pJJQW`=YF;;>=0FL
z{V}KF%mQv9`=Z#gpS{Hg6C2apdP<7sS-9wk-HOOd4l@aPr1@yWqO2+UDKTLd`GsMp
zL$B>ouTL~szIMqDzibIZ9mPHtmlG=%wHWERWL)wAJtE&PF~I8*2fyM
zz^UlZgZdBE+tTWa4*7DqHJ%f{{ZE2%S6QRm*=_s#b9Waq{g~gVz4qz)D~&h(FJwAw`ue{-)daRL(`=`r7pDG{x?b)Zv&2xw8ZuYx7vz}YjGF&oQ{Z#tF
z0|5!$fN#5w?`D2m{CoRy%l-1X*+olNZ9bz3j1Prmk04(LhAK4%hK3dfhF?ITh8GMB
zr3MTPuM!v-tY$DUh!@P+6=(yLkPGk$asB`QKak1J#=_6fBQ7o~Cnv+r&7rBO{`vD~
zptx{s;c_6wQ4-`A45Yze`}3fMKn7!yx4R4De%&tw1r=<$+z&poVA^DQA$jwH
z@7yPNPR{##>Fv|bFJJy>v86eWy*QIePL8a1BvR7q&=}nVW!arrMnC}Q!>*kaclU=>%Ic0K?-C;
zYDH$6l~ZO(aX@NOaAIyjPAY?ijsge?y|q&Zs#1ijasj#`Br_M}5<^QX0}Crd69o{%
z#LC$C>5uMjK*hpv#h$r|>8U=cdFdq?45nr>mzIER6hf5_&rAWznpoOT`X`U#p5Xkn
zlJdl&R0elX-v9+8JwpQ^(zU(H2vj8vG6R@#t&;N#DvL7HGfEf&N|SOjlNDU@a}zW3
zwoNpQ1}am6DN9K$PAlvuW6%1nWy>~nI|8WOv_W^xAB95`8@#)MTIDttnCe(}58
zmdmB4Wfiuibll&3Yws1VYHyy2%QRCXk2z?457yjuJ58=>eP$y|>jfrGzJ-iJtW3N@
zyiA-zqDh~By88F?KiVD^!m({*gwD$Q^@5Eq?Fkcp{%LMI?3g$q$iblgM9w$A#~)V+
zcocM8&GOxP>t>nllcV|nH8!ncZ%t^3dp}c8PrBsxzP7aw4l39%sK2#$Rngs&ZNTBO
zy?VdtgXmVpsI}5rX6qHqnjB<)iF`L(cG-NEPaL=Hg?nvQM>h5fJC|6MhpeC9o$J!<
zkT+wI)03O`o=GMPR0cWqS#FE}ZxOD>!*o+<`L$0k|9@QN=XKw2YQv5He~UA|>hI-j
gw)o1}WBHH0RN;&z%jUHkfHB43>FVdQ&MBb@0DT+9s{jB1
diff --git a/share/dark_resources/aero_drill_array.png b/share/dark_resources/aero_drill_array.png
index 0cd39bc340d8744ed2bab075b833f7d4eb763adc..f8203bad31436518d12a0e742bce7d5538b3d647 100644
GIT binary patch
literal 1162
zcmeAS@N?(olHy`uVBq!ia0vp^hCpn=!VDyr?d5&Wz`$6W>FgYknVihPpfRy_qP552
z0Fk!;%eq`&F~3oGG-07tq(HodmuPpw!Y!gvr3O1+a?dhR(bVf}%077Tc+%B_MHQnfdy3l#UyBj*pJJQW`=YF;;>=0FL
z{V}KF%mQv9`=Z#gpS{Hg6C2apdP<7sS-9wk-HOOd4l@aPr1@yWqO2+UDKTLd`GsMp
zL$B>ouTL~szIMqDzibIZ9mPHtmlG=%wHWERWL)wAJtE&PF~I8*2fyM
zz^UlZgZdBE+tTWa4*7DqHJ%f{{ZE2%S6QRm*=_s#b9Waq{g~gVz4qz)D~&h(FJwAw`ue{-)daRL(`=`r7pDG{x?b)Zv&2xw8ZuYx7vz}YjGF&oQ{Z#tF
z0|5!$fN#5w?`D2m{CoRy%l-1X*+olNZ9bz3j1Prmk04(LhAK4%hK3dfhF?ITh8GMB
zr3MTPuM!v-tY$DUh!@P+6=(yLkPGk$asB`QKak1J#=_6fBQ7o~Cnv+r&7rBO{`vD~
zptx{s;c_6wQ4-`A45Yze`}3fMKn7!yx4R4De`PZ^
zEjsdI1;{a~C9V-ADTyViR>?)FK#IZ0z{o(?z(m*3B*ehL%FxWp&`{UF*vi1*$|066
z6b-rgDVb@NxHT-DzsC%yK?-C;YDH$6l~ZO(aX@NOaAIyjPAY?ijsge?y|q&Zs#1ij
zasj#`Br_M}5<^QX0}Crd69o{%#LC2c?UkDvK*hpv#h$r|>8U=cdFdq?45nr>mzJym
zN(-S%hi9e$Wlb#YC;gL0aZhl5T1k0gQ7VJGr*D9Qk)ELe5b4@pWdy2{2AKiO%vQ7AF^F7L;V>=Ru51D$UF((ap?L
zC=POW@=13T2C5c?sm@KzD@{vGE-5WaEdnd|nK$7SPyruYL4HbV4g*MQbb_ZdP=>+N
L)z4*}Q$iB})k&qa
delta 478
zcmV<40U`d13G4%q7=H)`0000~lMvJZ00FZ}L_t(&L+zNqY63wJ#>YP*d_(GCa(nu;HLJ|TABUzBelewLlU6Hxw;Mke<_kFW}#s(b0
z(>MYKFo;8O(VQ?R1QoDy5)_k_%A8=yCm3u_2#U!{Wlpf<6MqagCj`Z0r7|a2@(Bi;
z6M|y0QkfGh`2>T_2|+PgsmuwAe9pOF=bWlos>u-&A^zWLbEzfvE+Irw6i}8W0;$ZW
zl61SwJOqBz0!a#?1(F;>10)NCG)OiGNsz1%U*A9QaDT_%wX#B>8>`g^j7Co^kn9i$
zvRuByc>EjT8wmDGOl|VPF(VNMSJ~;kLo8>C$DC4>thXB
z;8gVILH&p7ZE1ByhkUu*8qbN}{wKk>tE|!O?6&>=xw{LQe#~#wUi)LqiJ#!!Mvv!wUw6
zQUeBtR|yOZRx=nF#0%!^3bX-A$OZU>xc>kDAIM~9W8vrL5f>Mglat}*=Frqs|NQwg
zP+T~+a5<3TC<*cl2GU@#{dv$rAcHZ<+ueonKa=h~AcwQSBeIx*K~DmN8MRiaD*y%A
zOFVsD*`KiRiVBEUOG9nO2Eg
zgSNo#t3VA>ARAIEGSjS_GE0gBQj3BUa|?1(87y=ZKuGAVojOpJB3zXV&=nz>xgeJq
zT3Q)cSQ(lqfEcDgH@r`H_X?<37_QheH!(fcCp9mqPu`DrEPiAAXl?w-B@3PyT{20)~1dzBHWN*ZJaFbi8H=ND8KWu|A8Fa(q)
zChwYB;8cwvr{Z)-pQwcfs4H|xRG
zECpl6U7FVtrIzuAGki4D`OYrob9l=`E`@t-PZv#8yw|b)Ay++^Q>_f*=
zY$=}lN29sun#8Z)!G9!=uz#7{y>PP1LKEMe42#YyTHPo!|9IigT$3GK8JPv97bZPe
zwP5LitB&3ct6S=-|1X&RdUZl~-*}!}{y%ujIYYy{5k>;%9B>&a7a@vj+}8)RmQyyZrN}=LgZKk_`ScYJV@8
zxGdQ|Sy;5nV8Tv#J!)g>+a$O+ZH>e=j!f#`}5Dlw9V~a(lfTp^8Q-CShMZj
zcl{NYZ}O)_%WgTs*zEP<0{fH(zSzW*zw`f>f5^D>W!>bk;tRVQEOVDF_$;SAyZPK^
zLqq1d>esTuQ&O#J1QUddt=`*&Z9J`&Z1URPRrmV663GWq&eK`@_})HGzPaLgrETin
q+h?>_dpu-_T@qFLFIU;Op0Q-n9e0PRPxb>Nn8DN4&t;ucLK6VdOz|NA
diff --git a/share/dark_resources/aero_path2.png b/share/dark_resources/aero_path2.png
index 80a83881f9310c289f5742813e481637426e3ea4..cd95994c39fe1f2cf5ea0b1528dd2359d7ce26d5 100644
GIT binary patch
literal 1154
zcmeAS@N?(olHy`uVBq!ia0vp^wm|I0!VDyPS2o^YU|_7xbaoENOipHC(3n^|(c0s1
zfJoc_WnHeXnBOQony}C+QXt;KOSC&-;TF-TQiGi@xo4TEXzKMfWgk3vJn8Deqmkk4
z;f?||4Lf#NY3}mqe6H3iW+=DgPXGUT|DWG0W?UGTw(6!K--=nOD#?L{lVe49#|b*<
z|9W_M%Ml;jc~L%xH}8A5vj3Idq0M`K|63!cnr?JJUFf{w-3=Y)9qDGeb3fY^c8IFB
z{+Ls7W&yX5eNk-L&)(vLiH+%PJtal+EL?QNZbjrJhna*t(tNaGQPvdwl$bD!{KBx)
zq1X1P*C!e*U%O<7U$%syj$$8+%ZU|>T8wmDGOl|VPF(VNMSJ~;kLo8>C$DC4>thXB
z;8gVILH&p7ZE1ByhkUu*8qbN}{wKk>tE|!O?6&>=xw{LQe#~#wUi)LqiJ#!!Mvv!wUw6
zQUeBtR|yOZRx=nF#0%!^3bX-A$OZU>xc-0rAIM~9W8vrL5f>Mglat}*=Frqs|NQwg
z!zzYp!lwj)(i|m0e!)N*47NWHS_ot?CV9KNaDKeG^bL^1S>O>_%)p>00m6)0tJD>M
zg6t)pzOL*~Sa?MRgr3&+uLcTLdb&7>Z6(i1D(?#(X@7KNI@F=>w@0v_d6xMj_T&3>j`a7{MozrHrfE|0
zx{Cj?>RbN5
z9idv{8c~vxSdwa$T$Bo=7>o>z40H`lbPY{H3=FIc&8!S9bPbHH3=ABj93xRQIt27|f5@%ChSptKOGba-Y8
zP}aFQ_caOwTA`
z2q;a;$xK#o$#38pM1wK%ybv!En1KM!JDQfX#RiEd_|LUEA0lTW&%
zFi^E9Om%KzUTIola!F}XY7tnu&%6nzfC~8F3i4A@a~MEcqZ2%xfieu9u6{1-oD!M<
DjbEW!
delta 486
zcmV+3G@Sy7=H)`0001ghn(vG00Fy6L_t(|UhUaIO9DX@2k_@D@PmZs!c$)C
z6m^z9h|qCo4^e@Er|=?P!!IOWrHgbD5-Nh?Ne{L~H<6v0$D6+w!Gp8E`TutuXB(8@
ztC66YfKDZKB#opE&j9LeINU!pB#opE&j9LeI9x1bs5k0ucz*^^Z^PkY^+vr>Z^JWy
zdK(TGt2gS6dK;br)Z1{lSiPgw+d22`oQpDkltH;`jQ)KOeht9~l$(puS(Z_r=R5&H
zuOsMS#nnX6{8?zY3Up|=8gxjwDs(8gI&=uQO7zF)7v108dRx_1qB-r=>WzlOM=x--
zXofGBuQVDx)qf6Gjb`{_@j{cyxK_9t^m_eH&F0Z&|H7M<@~h5Wn+i082ZIMXIX$DR
z%X9BLwCHF7bCR+(^-<|!bE2aA{hLj~Qe8%OyBE~yw7sSs6}|1RrKCNZ&1pJ)u5|&E
zw4)2b`>d+w$7*wKtA5a4Adxo`qKVOp8l7#Q;P?xkE4Ic{MXOFH9
zeJECb>XJk63pbT?@j*gW;%3oRkBm&B|EsxKbQRn*dKWwibou@^kKUGc66i8K8FUez
c6k0YfKip8T8wmDGOl|VPF(VNMSJ~;kLo8>C$DC4>thXB
z;8gVILH&p7ZE1ByhkUu*8qbN}{wKk>tE|!O?6&>=xw{LQe#~#wUi)LqiJ#!!Mvv!wUw6
zQUeBtR|yOZRx=nF#0%!^3bX-A$OZU>xc>kDAIM~9W8vrL5f>Mglat}*=Frqs|NQwg
zP+T~+a5<3TC<*cl2GU@#{dv$rAcHZ<+ueonKa=h~AcwQSBeIx*K~DmN8MRiaD*y%A
zOFVsD*`KiRiVAQ@$d_FN3Ke*|IEHu}e|u4pufc$)_2J1|f(o`=?gt-PFl{ouki40t
zS>b)6hrr*r(@W2Wc}+{bxx1%Apxo%d)C$u_UNZa{>yB6-j#GcMH*vl3Cs$^hP5q7E
z<5L}ezgPRvee3Ez(Hn))4>G4ne5-!>zob*U?B8drvbj
zoS#-wo>-L1;O^-gpkSnDXaGdIwpST}s-!_?0Q0U@a(+Q&QD%BZ2}3|>Qch;Ff=hmG
zVrJg9iH6ZYWlAt*DXGQDMVSR9nfZAT~-mR*C%MMfD3Vn)q6;V|e^FLQh)q@!1L>yB@^ZZ4TjJu*pUXO@
GgeCyLz2gM{
diff --git a/share/dark_resources/aero_path4.png b/share/dark_resources/aero_path4.png
index 5cca6e2efc28e8255674b754604f08c31e3d3db7..155b03292776f7dcc69495116a9a030e30ee4027 100644
GIT binary patch
literal 1145
zcmeAS@N?(olHy`uVBq!ia0vp^wm|I0!VDyPS2o^YU|_7xbaoENOipHC(3n^|(c0s1
zfJoc_WnHeXnBOQony}C+QXt;KOSC&-;TF-TQiGi@xo4TEXzKMfWgk3vJn8Deqmkk4
z;f?||4Lf#NY3}mqe6H3iW+=DgPXGUT|DWG0W?UGTw(6!K--=nOD#?L{lVe49#|b*<
z|9W_M%Ml;jc~L%xH}8A5vj3Idq0M`K|63!cnr?JJUFf{w-3=Y)9qDGeb3fY^c8IFB
z{+Ls7W&yX5eNk-L&)(vLiH+%PJtal+EL?QNZbjrJhna*t(tNaGQPvdwl$bD!{KBx)
zq1X1P*C!e*U%O<7U$%syj$$8+%ZU|>T8wmDGOl|VPF(VNMSJ~;kLo8>C$DC4>thXB
z;8gVILH&p7ZE1ByhkUu*8qbN}{wKk>tE|!O?6&>=xw{LQe#~#wUi)LqiJ#!!Mvv!wUw6
zQUeBtR|yOZRx=nF#0%!^3bX-A$OZU>xc>kDAIM~9W8vrL5f>Mglat}*=Frqs|NQwg
zP+T~+a5<3TC<*cl2GU@#{dv$rAcHZ<+ueonKa=h~AcwQSBeIx*K~DmN8MRiaD*y%A
zOFVsD*`KiRiV6r%s@e}qGzFe6jv*e$-(FPYYcSwxeR%4Ypn@%z`@u&ROq+}^ByVnE
zIbJOxVnv|27tl*NL
zo0yrmZK7c`P?-`;SxRbga#3bMNoIZ?#JHr=%$yS4%shqSAa^I9bVp&JYEhW#+{C=n
uw8Z3+(xTKNuyUVy6HWmY@WB=2r=;dEfV4&@csc`R7(8A5T-G@yGywp^b)VY+
delta 467
zcmV;^0WALc2;l>e7=H)`0001ghn(vG00F2;L_t(|UhSB%N&`U;3e7Yeq)CRhaws0hjg7ouo0?#@o;{%Zn(y}R%KzYLpgQ3J15
z1DOfXO=%rXqiM$pKySz8enUgkXxecC(A#mj7-Y~JdOJ=4dVf1E7t%Oz&cPhY&tO2t}S>tE!^9t~mhJ_fUP<
z<}``W{GB$q321F_Gtipgrl7UJ%|UB`n}mLSd#9_*i)>TfBs90ZTt3ribdv?#EHr~J
z7Ed%D-zEn)4S&tx^Z6r9CU;4}%|NeKFVt@DtoJXxS^0UT+_jm2X5iuQn)db&>Gb3%
z`wp!*bOh!m2Jv
z#i0K>nqugF|BO1F-E3`}gVs1;FbSRefD+KT6Hayicuc+~z28HeXhoJlZ$a$PTM$~2CD2T8wmDGOl|VPF(VNMSJ~;kLo8>C$DC4>thXB
z;8gVILH&p7ZE1ByhkUu*8qbN}{wKk>tE|!O?6&>=xw{LQe#~#wUi)LqiJ#!!Mvv!wUw6
zQUeBtR|yOZRx=nF#0%!^3bX-A$OZU>xc>kDAIM~9W8vrL5f>Mglat}*=Frqs|NQwg
zP+T~+a5<3TC<*cl2GU@#{dv$rAcHZ<+ueonKa=h~AcwQSBeIx*K~DmN8MRiaD*y%A
zOFVsD*`KiRiVAQyim7J6
z&N-{!{qLLns$TJ)cGK(Em!E#L{8^dDyWu;}j;Z0fChaBvo*Vp~uAE-(|MZ5{W`{>WSKhL(lk6&)gxcBD#Jq(3s6lV3Z94-JlR<*=6q9i4;B-JXp
zC>2OC7#SED=o*;l8k&R{7+4vaSs5DY8W>v{7+g8T(uJZSH$NpatrE9}rStcg0X0a0
zY)GxhOtW&zEGZ61EecM|Eyzh_u+UKeA)&W+>OfVBa8)iqSA=Bdf?Q%~X=PwxWoV)R
zVwhT)nEpir+Q-Uc=Ni9w;$}A|!%+G@umsFaWQ=*%hr%)W^?&Op1C=66B3R9h%m{*#X
sm|Rj?lv)HmdKI;Vst00mOC`~Uy|
delta 540
zcmV+%0^|Lv38@5-7=H)`0001ghn(vG00HnxL_t(|UhSDNOT$1E$6q(0A4EDUPIjr2
z=v@3D1;<Tj4L4VW-M14nZ#S-&40K85^u(GrF%=fCEkoH
zAn|4_SGu>vTjI^Q0upb=a;19*i?>qhM=2F#{2+s3))4yd)%!JgA5c#&giewK(lo^a
zc)bpX%mq)lM@trG`ijz*3m`i!QdSF{gXUhmM!wzgcxHaX}j4}Ta;(AGk`KA_Bk7J-vA?E-BB
z6lhBYTWxxm(OsVjw98xyeQwdb)pr5gn!UBAqk}F3%+7RK=sfVoGlqT4)M?l0000FgYknVihPpfRy_qP552
z0Fk!;%eq`&F~3oGG-07tq(HodmuPpw!Y!gvr3O1+a?dhR(bVf}%077Tc+%B_MHQnfdy3l#UyBj*pJJQW`=YF;;>=0FL
z{V}KF%mQv9`=Z#gpS{Hg6C2apdP<7sS-9wk-HOOd4l@aPr1@yWqO2+UDKTLd`GsMp
zL$B>ouTL~szIMqDzibIZ9mPHtmlG=%wHWERWL)wAJtE&PF~I8*2fyM
zz^UlZgZdBE+tTWa4*7DqHJ%f{{ZE2%S6QRm*=_s#b9Waq{g~gVz4qz)D~&h(FJwAw`ue{-)daRL(`=`r7pDG{x?b)Zv&2xw8ZuYx7vz}YjGF&oQ{Z#tF
z0|5!$fN#5w?`D2m{CoRy%l-1X*+olNZ9bz3j1Prmk04(LhAK4%hK3dfhF?ITh8GMB
zr3MTPuM!v-tY$DUh!@P+6=(yLkPGk$asB`QKak1J#=_6fBQ7o~Cnv+r&7rBO{`vD~
zptx{s;c_6wQ4-`A45Yze`}3fMKn7!yx4R4De^XjNhbh+hoMfc72j6xxLc+
z_qN-jUb@OfVBa8)iqSA=Bdf?Q%~X=PwxWoV)R
zVwhT)TE0HLh#RO_7_QheH!(fcCp9m16IqA=CDiFu`I
tiOD6UMX5z#Wc)I$ztaD0e0swTUphW-x
delta 455
zcmV;&0XY8m2-O3S7=H)`0000~lMvJZ00EpyL_t(&L+zNqY63wJhsQ49g9PgYtJs(-
zB(>y0gp{{egcvYj6>P*d_(EbUX(W}PU_u~a#DOIwVee*Ucagb9kli`H-#6|b8*l_q
z;|LhQAab#2Cd`Cj0@hA~VX{h@308c9lg)%+n5r1g6
zJQ@T6VA6CH;k1x%FbYJ!f44V4t%4BU?iF-8Z4nz$AbvZFla2X&0khdltsgYmP>1;I
z;)D>r-Yv9Rr)(R^AS5qLNg+b6w;^K;A|$1%W9UvEGC+@3yX;IDM2NmvV?u2BXRPen
x$zOW^3oUyH|39mcQ*M?fsFgYknVihPpfRy_qP552
z0Fk!;%eq`&F~3oGG-07tq(HodmuPpw!Y!gvr3O1+a?dhR(bVf}%077Tc+%B_MHQnfdy3l#UyBj*pJJQW`=YF;;>=0FL
z{V}KF%mQv9`=Z#gpS{Hg6C2apdP<7sS-9wk-HOOd4l@aPr1@yWqO2+UDKTLd`GsMp
zL$B>ouTL~szIMqDzibIZ9mPHtmlG=%wHWERWL)wAJtE&PF~I8*2fyM
zz^UlZgZdBE+tTWa4*7DqHJ%f{{ZE2%S6QRm*=_s#b9Waq{g~gVz4qz)D~&h(FJwAw`ue{-)daRL(`=`r7pDG{x?b)Zv&2xw8ZuYx7vz}YjGF&oQ{Z#tF
z0|5!$fN#5w?`D2m{CoRy%l-1X*+olNZ9bz3j1Prmk04(LhAK4%hK3dfhF?ITh8GMB
zr3MTPuM!v-tY$DUh!@P+6=(yLkPGk$asB@v$YNk;W8vrL5f>Mglat}*=Frqs|NQwg
z1H=EdGwc+B(i|m0e!(DhAh7*;&_W=^nB?v5!uj#$(l{rCvOQV*mAiad}P72$u#+R
z8q4kL4-|g;9G(1ciRRZYH5zR}fikmW0yizx;4(E0oO00PQzm0Xkxq!^40
zj0|)QOmq!RLJSP749%200kpGLjxevwY|y+R3!~E1DIv4lJg5Hi!#$QN*Dr4lX5bX6(P=Kpc
z00vNqSS+duHNlvGwi9ERq*7{v6d&VYHNhArsg#-^#m6{UO@AEYac!i4gyHv3H3Tww4egNfJoY6oEwECsH)q
zW)=dUNr8BUkOJ`zApsHuf*T|l1Sd#Ph~NDIK6>xuuU1e9w6WcO!*KXX0tpU*AnWx8
z#^X_LkSHJ!WPiC_!E`#w1>zlIxBG!|`Qfx4;^KFHc(pKEsSS-F^KA&Bk&~__-YdbFv
zaqZxQf3DqrgG%M`rj4i}Tn|jqL%1GqGY71TofE8`TsHu+wxXO93UQWzwv%g1P=2Rh
oCrWypV+&!zC6MSR_T4}n0WO)?Ibv*4=>Px#07*qoM6N<$g8m)C6951J
diff --git a/share/dark_resources/aero_text.png b/share/dark_resources/aero_text.png
index 62862d14202808fa6ca7a30674bd981e5ca96cd8..59fd5a1b8c337622bcc1a5bba09d2e0ad1ee8d54 100644
GIT binary patch
literal 1164
zcmeAS@N?(olHy`uVBq!ia0vp^hCpn=!VDyr?d5&Wz`$6W>FgYknVihPpfRy_qP552
z0Fk!;%eq`&F~3oGG-07tq(HodmuPpw!Y!gvr3O1+a?dhR(bVf}%077Tc+%B_MHQnfdy3l#UyBj*pJJQW`=YF;;>=0FL
z{V}KF%mQv9`=Z#gpS{Hg6C2apdP<7sS-9wk-HOOd4l@aPr1@yWqO2+UDKTLd`GsMp
zL$B>ouTL~szIMqDzibIZ9mPHtmlG=%wHWERWL)wAJtE&PF~I8*2fyM
zz^UlZgZdBE+tTWa4*7DqHJ%f{{ZE2%S6QRm*=_s#b9Waq{g~gVz4qz)D~&h(FJwAw`ue{-)daRL(`=`r7pDG{x?b)Zv&2xw8ZuYx7vz}YjGF&oQ{Z#tF
z0|5!$fN#5w?`D2m{CoRy%l-1X*+olNZ9bz3j1Prmk04(LhAK4%hK3dfhF?ITh8GMB
zr3MTPuM!v-tY$DUh!@P+6=(yLkPGk$asB`QKak1J#=_6fBQ7o~Cnv+r&7rBO{`vD~
zptx{s;c_6wQ4-`A45Yze`}3fMKn7!yx4R4De|nI`LC!G=p5A&*NBpo#FA92n)jwVXWq3KT$hpAUHtv;|2J>nY#PxSLJ-QT+;Eu<`9KQ#h}KNb`QoyOp3gV*c3Szaee&y
zmzn>2`J4UIv{-g+jH*45@#P3pV7tSFr=MhxJ$`&w9oR%ZVERQuf6uq
z*xtYDuYmdf4_TX5r?)yZJp3T&=Xd_$uUAev?C04W8CIA~RhlF6N%jnrp~RgqzJOH<
zF6+xV@4lPaAswmk%B!#_*{;6z=9{G#o7BuFIpuuv~c^MhqvUza3R2S1s0-E*Z+K&n9nj93OwS3j3^P6k4UEa{HEjtmSN`?>!lvVtU&J%W50
z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-G$+Qd;gjJKpuOE
zr>`sf6Bb@k0kKB{-kX3z-JULvAs)xihFbGAD2Ti^R?*9Ok!jPlc>71Wd44k!3J-aD
z%xIbP;P&k=&dn?Z<`XJ3-pDjsTxxDo6)oZ4=*a!PH-fu>{hdwo$@%v`Rvo)~!YN3>
zfYqXVf^bM&vzV9>a~U^pRD$lG1+6QVzEf0Xx}3@F*?2jc@to`PyU`DfKZv_K^m{V>
z-ddXfknzPkrQH_KJdAcptHiBA>c>J4paup{S3j3^P6Lz8Gi-<0047(dh`GQ0B=b|K~z{r?UgYO03Zm&L
diff --git a/share/dark_resources/align_justify32.png b/share/dark_resources/align_justify32.png
index a2e329a30043e30030f689fab74a6658d3478c64..be35b0e557aca96a6310ec6329325530f6c04d46 100644
GIT binary patch
literal 347
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50
z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-G$+Qd;gjJKpuOE
zr>`sf6Bb@k0k;3kqptyll097T-E
z?|ymBhRqNEN)$#m))*e{V7JbYf5g%%oW6idMlt(3(~W~Ht<1_g3l<291zd2Aa&Vkq
zyt~P`&itH%@3O~4RgVDNPHb6Mw<&;$SuwP>sW
delta 104
zcmcc3R6Rj5iH(7Qp}4B*3y^a1ba4!caDO}bpdbSSM^jO;`TA@wyDbfJiER50{G7ba
zd)fwu_Y6P(pMS==g9(UaCp2hZU<5MeGzdLnDPVuW#O`dV%iqJm&IL4$!PC{xWt~$(
F69A?pBmDpX
diff --git a/share/dark_resources/align_left32.png b/share/dark_resources/align_left32.png
index 14aafdf8b74f07ae267c0fc9c065b34d27b8a193..9cd3ca91ae74e9323510864a4a42f260c8115131 100644
GIT binary patch
literal 373
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50
z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-G$+Qd;gjJKpuOE
zr>`sf6Bb@ke(S8Ml9526T2B|p5Rc=@f6hBdCM*iDXXbVmPh~TxTXun8hbLdNUTNN)UO@Z(dP5wpfQpPv7kYj3gHh%toRQ`q^Y^ISjB
zA*v;=5hW>!C8<`)MX5lF!N|bKK-a)T*U%)yz`)AT)XLOS*TC4yz@Q`GzX*zk-29Zx
Yv`X9>e)77n0BT_HboFyt=akR{0F}UT-~a#s
delta 148
zcmey$w3KmzWIY=L14D6D)fXU@PA5ZMV`Yap56QNKcR8Q#hr$_GJO2EtqI!f2q_^U?#sdZbz
ydd)ecp@OMoa_;Zvx;HppR)#pU?_&9MQvA)AJYF-P#SEUVelF{r5}E)C`#LEA
diff --git a/share/dark_resources/align_right32.png b/share/dark_resources/align_right32.png
index 3044f6ac5c8dc0fb75c79fac0eb89ea988b04a49..480b1d5923315347f8142ef1016e44eecbc960eb 100644
GIT binary patch
literal 363
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50
z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-G$+Qd;gjJKpuOE
zr>`sf6Bb@k0imb0{i}gO#hxyXAs)w*|D1P_Ojs0P&&=&Cp2}uWx9kGH4o|*j$-xG8
zCD9~C;SYu_0b*>g;`1(Cn82ecnQst$Lrg(>T0P~-`)Q(ken1`pa8mo<>&pIwg;!KSghx(m9s>iTtfz}(h{pM)6W4n;CyKPr
zKlvjpF2F7z#ZCMVbBuxBEZ!!z$Up(fE=L_U$8HH7rAPe=Gukqf1aqXhlbg7dq>e05
zvbtFvDezFjZu?A^5BG{JzdtOpFjuQv&-agq<%!1ZnSn~~7cPmG&OaCW$#kh`*5UoD
zSEX#})KjrgJU?N!y8nsAw-+5KEKy}zwr0A&*o$W~je|N=?PlaKC$Do5Z{FtB+LYS3
zhS%WUrw6_ZgQ_kp6NtLL^xf2NrHYU4$NfI}`AX3}&$jIuJ2S82qu~xQn78H$NpatrE9}-t-NLKn)C@u6{1-oD!M<
DmI%n}
delta 132
zcmZ3*GL3P9WGx#51B3kM|A{~<*3-o?#KJ#0Wr2V}(2Dttha1}3+W!CG$<4@cxY&G1
zafxJ_!6wB5<_V_FA_7J{X&hn99h~C7Bp5cc&MxmLVm!(wAUwBOL%{Kzs>t^WVWCMX
kKRsv8U};&`_UH}=gZn=lLB%&8LH03ty85}Sb4q9e0Po2zl>h($
diff --git a/share/dark_resources/aperture32.png b/share/dark_resources/aperture32.png
index c155cf1a9d491681a424bf08d429fcf950c9349a..3c9156ab0630839fed62ee1c762634f0db648897 100644
GIT binary patch
delta 909
zcmZ3%G=qJDWIYQ51H;YYP4z&ECEd~2k%3`jKlh(RRv=#?*(1o8fuTx`fuW&=f#DZW
zsNn?zL#Y7+!>a@a2CEqi4B`cIb_Lo1C76=D-CY>|xA&jf59DzcctjR6Fz_7)VaDV6
zD^h@h>?NMQuIx`(ct!awKF{%Z4Aj)^S?}T);&J@w)U*DS?_*vys4Gw$|&r+
z<&l?ir$$Z>TiCDq9~+Gf-8OV`Kfcb!#5nzs+hS?W))jxaHC}mfn|9>-_#X}ZxpRTW
z()W_W;%8#doSr-L^Rs)^?`BH;+Q0F+{rS~~S8lI#{JL`M9W_=OIB$x426M6Un6y2F8g(e2mka{QlPJHF8o=!YvpRDm3UlgT2g#$%$TKvkB^rV)R-B~m<^Krh4;P%5S_FVP3Ti+ok-g7-`
zR_56s(#r*o?|sMRzWDY|(TOSh*3EsM;l5>}@g45#&1{?6WR43gnl307Th!_5X3;Bf
z{G_B&V3U$iO3!u4MN9QMb?ibfMzniBE0n@8$
ziEBhjN@7W>RdP`(kYX@0Ff!0JFwr$M2{ACRGBmX^HPbaPwlXlNlj#48q9HdwB{QuO
Xw+4P!b6`eeVDNNh^K)6}l+XkKdwGOi
delta 280
zcmV+z0q6dh2dDy&8Gi-<0047(dh`GQ0PjgeK~z{r?UvyVgfIw$_04(nGfQp;xw3Y<
zC2BJND)gf`#=hPB>^JLgGJu(V6j(EpbC!JcV^ui9sURu9sBkX`1jxi$RU>gf04PZn
zX0Eip%it+M31q^^_821pprBsy3WLBA#Ki$GmQ|irlC>`8jDK#O07~_}KcV6R1W*FA
zp~MP_MMwZXNI7b)RxW_$z&jl%M~=+^HvunuLp;)w165F+=c+g=gU_`b2LdCEe9T=2HG+MwJM>2(aY8fgt@{{=g~&t1z$9bpyAEnwEpdQV$0
eODM~;01jx6ND(kWy?ki^0000)-zW^51U;*P3^C_Dnr_;J|?o@vrLd{Ga@P`d@M9
z;7PM)yD3U$mOdd>9|wAM51#$us-^YDLW-wY&=(8iAnjvG`B@
z=l{45i|YJ1aG-yJpP1LoV;|-}R6iWwBFe*4|5`EU*cOpxSN~7{RP>q4xGo_fp;3Fs
zcc+;T%XXdIzwLjt{f@Q&xVQ5htEg-YUQqhqTJ74WO#KaP*Pc(G|9?%-LE$_5mH$2Y
zm%h~R%0ecFv-?78U2D>TLBOC|;u=wsl30>zm0Xkxq!^40j0|)QOmq!RLJSP73{9;}
z%ykWntqcrAj<#G!(U6;;l9^VCTSMv$n{1#4NstY}`DrEPiAAXl<>lpinR(g8$%zH2
Ydih1^v)|cB0TnTLy85}Sb4q9e0G{H_!2kdN
delta 310
zcmV-60m=T21jYi88Gi-<001BJ|6u?C0S!q+K~y+TrP8rV#6S=R;F+ybhCGXv%{_sQ
zML^K%;t
zf$!lLkWy+BlTuC=_!H=ZHf#W7S++yOhq5d;?c+JA1`(P05`O?biRjs=K4`C>#srQ5
zU_nH8W5ewy>W~4Drm3rxS`*Q^?eCb#-jtd7g@{f}AW0HWYkgBy)m8VcO)&;+>$*Ob
zQa0^Htu-?95)sdY5Z6Hvy!G)h;J#^^O&EsnaU35BA#MTS)pgyq@B3e7vOS>d(Q%wd
z&+~**Y86G%hc9g=R-h<~i#*StrdHhw{4CP^Ri3IeyM_Nk-$rM05%JHl-v9sr07*qo
IM6N<$f~}d4hyVZp
diff --git a/share/dark_resources/arc24.png b/share/dark_resources/arc24.png
index a6e15d91e4cd42f57886fdadd49150fda87ee63e..202cbb068d524c81c8038d6382a27c547008a2d5 100644
GIT binary patch
literal 653
zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^+
z;1LNlk>v;oGuoWF(hL-2FY)wsWq-oLD=NU=u^`)lfq^mF)5S5w;`G^x_8v}wBFFZx
z7E4m<>h_3k?)q4eos*U2+o6yV@LVc-mQqwv=A@Q34Jqj&t;LEuTrM7}s}?SF;+SOR
z@6q#pYsxR5qZjjceZTYh_qqApJaa=nA7I@P5F*aZbmfb*guxu?4+nay=P0i4v6E2_
z66X4ONJ;;xvqq>~;V$zBsg6=bf2ubZb*
zVvbb5)>|IS^IvPvm9Yi{P5xgN6d3q?VcmfX45I%;oMX=$JG;Br6#BfncrmZ#O6#Yi
z3Jf=*9`2p>_p0!L+~vKsyvl3kH_wdo=9%5-GR5=Bm(=<4?<-!gZRwrMQ8fGUw51_s
z%YR2PhK4;%Q~r2%t&HE)X{TmIn}p7&_|O8Y+9Dw&Dx((bmZw`?afg!J2;u=ws
zl30>zm0Xkxq!^40j0|)QOmq!RLJSP749%lpinR(g8$%zH2dih1^v)|cB0TnTLy85}Sb4q9e034q5
AbN~PV
delta 430
zcmV;f0a5;q1-%218Gi-<007{3J@^0s0fb3JK~zXf)s??X12GiG-^(h};%vcDoZX!Z
zB099I)62D>phKNJImbE_#K9(uayU3R>LiZ-*!=^fAUC=R#U70u^yEB}G}ltW%rEcr
zzTbS4Ak28-jQhji1A-t>sj46drXJu|gKTq~bw$7v0g5QJ0)MiT+SJ(;X+4%w-XY=z
z5#8vl(!op+EkFoy!WjD`qT?}V@e_!oP6sgowh?iib6#_~C${8i0o`tQl`$4_&R2>8
z@&V8S!Z4ic_xm5^a(TX9uYXMfN$oOTBq`;aQfkBVyjL4wG|W*HMF-hB7r-q5Tyf5?
zO#mT84G}v4@PFj{{$sP*Jaw`tDUwpQ5ph67hk1YyVi^(70AO)A9PTt4jR(^ZMvH_H
zNs=}>=UeIKksUq&Z~$m4r8=JH4Qv(~0j*YRtyC&q#&Nuq_?fZe1rhg&=-uV;jeu;n
z<2Zhb^s@U=_eU*QQ`zB^8V+cQ~y}wRQ!Ly
YH@6$68RBv40{{R307*qoM6N<$g0{ZHRsaA1
diff --git a/share/dark_resources/arc32.png b/share/dark_resources/arc32.png
index 391325ed3e9d3eaaa29ac6dfb803c3a8c9e2a038..29f355a6f71c4762624a24f2521c504ad58d0e47 100644
GIT binary patch
literal 786
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50
z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-G$+Qd;gjJKptm-
zM`SSr16wo*Gj6g|ZU+jomw5WRvOi(r6&2u+kT1K)z`*#x)5S5w1;^O8>YC1ukdga&Yrs7+(8D
zKQTsQitoJJ^H-*6x9?Dyq7(nIM_$21x^_Zs&GFQyX7wDYb949Uo!KN=(3)*GeanRW
zm7l^-@xAR?U3ERoa+Q1hreM^5Mpv=gv3#Zwm(o`I<_GJMRy6MZ9Ns-yoH3A$>Jb_L|_=)34=jsazI5XP##-
zbbL*eu7=w(zYKG^p7&<6T|H+mpF7ocDRWss&@yB3`_}pUg=Yo6E}D3f;lS#{_RH-z
zuC`CH6*0`7_Mh2`C1TQ=lve%lldzUc54VBQuUg_7QIe8al4_M)lnSI6j0}tnbPY^&
z4NXD}46F>ztPCu44UDY}40=B}9!JrTo1c=IR*74~pS3@$ff^)1HU#IVm6RtIr81P4
im+NKbWfvzW7NqLs7p2dBXCnnv#Ng@b=d#Wzp$PzJ<0sGn
delta 611
zcmV-p0-XJl2Jr-t8Gi-<0047(dh`GQ0ys%TK~z{r?bW}F6G0RQ@b6nt1Ns*jD}R6>
zL_tznYL`Y4IZkvzWM+ySkxLmtmus|95sO@Aizo+*aIvuzEK@2RikygrkZlYEBx1}$
zo-AA-hRx1w_B73@*aSS!Jb&+>C1nMOo0Hu_%?+4F
z%?sK!z!;PkVhxxsJUu7#CNdMyYPF8JuKOhn!yC0)?U`v`#DQ$mNSto1^;ZBJQp&p~
zKy*GUl_ZD>@S2&2N~y~>fQdP<{u?I(eBZw}8jUU~rB0>+#HBGS1ry*JGd~>+1_vvZ
z%I~a*9oSzzO@CK#2EcnFIxU3QN(-1Z7n5lu0-DWcE)2sy5nUHTy!h{csG-(+o0&J2
zQn%9p8jZ$2BB};Ka6f5B7#|s}^(z35l=7l2Kx=&gz!LyRgCN+S3E=zw8Z$3TDNmRH
zzV9Ca@Q|6W0C)pnB?yA;q?gs0fbaWD%>2CH?;omGtAD@Z5K-I!R*C2ifF2R83L!R4
z;ON{4&|04Y@PV1nDy7~{7hPXpKkqnB6!&oek8-)(n(MkhZJJvFc7`b`cvDKbF)m!M
z*Yl3!JRqVa0B?zCMF{c9w(jDvtmF002ovPDHLkV1f*`60!gQ
diff --git a/share/dark_resources/axis32.png b/share/dark_resources/axis32.png
index 2d4259ebac4ae0fc5f0b9e0d7b541c9ce24ea1c1..03ec180675727fd4ee364649614f651403bc25a6 100644
GIT binary patch
literal 645
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50
z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-G$+Qd;gjJKptm-
zM`SSr1K(i~W;~w1A_XYOUgGKN%Kn6fS5!dkk%0Fm1_s6oPZ!4!kK;?HSbH-&inQ*x
zIlwNhC?+Npl%c#xDQThEB8`p*{TnU@@!W`t=(IoJcF-XpI3n83B}p+%Y|+$?)*C-&
zx%xcb7@*R*dvavavdA{e`*Vxm8yQ}l^T=V23Fj>j#tDl|wGn-
zjNjJiAGq^=4O4Xk+m&=*n-n|Ku-)O@8`ihzZOP3}QeOK*GJjj0@w=S-&*pp7w?%CB
zRgB==Ct&zq!sGUAi8*@~_->ci+);He{zKZD$6N0xENrU0x+2%itfBcXTfwGwW|_B%
z4C&Pd2lD(^u83Qhx|WSuD*XQSc~)n4t2Hy|O@D7JD*Hl3qbd7av9j(z_8qr=`?|8u
zy~cdUx_(9M(zCOdtztZU?i-)zRpl*9VoVpjvHJc?R5;~t^@p+@Js+$XZHie89nI4P
z*V^w&{l|V`%ANa11ZtW86n5NM!uH=A7%i$Lt`Q|Ei6yC4$wjF^iowXh$UxV?MAy(H
x#K6GH(9FunNY}vF%D^CdspJ{Ay^cMgC
delta 281
zcmV+!0p|XN1*rm%8Gi-<0047(dh`GQ0PsmfK~z{r)tA{4gCGn=>!0V(?cm5vq}jPt
z^{p0iPd13#=jLZ?`b4yk97J^aum48#ssI|$a)9RP7?D-pH)nn#@CX227c0G2BQOJC
z6|_`8VhUaj(7oi5u+peTV5Z%o;${uJ764X+nFw@I=?pmw`hQ4ustck3nS8?m5Jz^o
z3lQSvENS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^>
z;_2(k{)B~Bl;28rlID2^21W)?7sn8b(_1HQ^gC=I(Dr|UQDT~ez!L5^4wcLftxqIFHZ^<0(XpnqFO!--xu7wA~l#DEc?ngTh=88Yy^;`Vo
z%!94TUJI`*EB>`g`1Znpn}(|2HD7v6wkp)v*}tUm#23*=#~v)rGkI+J@qmR}g~OX$
ztjQ)1c*14sQac_l-=6<$E$-v-IEpd$~Nl7e8wMs5Z
z1yT$~21W+D1}3_OCLsm}R)(flrWU#e##ROfdg@;mplHa=PsvQH#H}H|%0~vMfx*+&
K&t;ucLK6V8*1X&R
delta 182
zcmV;n07?J&1IGc78Gi-<007{3J@^0s0FFsSK~zXf?N(b3z#s_In{)Fme6TRaOEzP&
z=%*;PEuy_m9({8D_5c8Y;|(YP+;Xl1kSB>)5%V;I4M38vGdVKVif@yLl`~Dw+yk$z
z(Ed^t;pR-w!ga#{+2r9p@Fe1=*VgfP$%B6Zpw?2Rltf-DkS`U)0c7lxDk1=_bW4xE
k#Xy@c0XXtq9|mG|0`Cr`lIy*mq5uE@07*qoM6N<$f=^yhjQ{`u
diff --git a/share/dark_resources/backup_export24.png b/share/dark_resources/backup_export24.png
index 5e12a21ce4699092d785d479eba06ee2d9057dd0..0dd0cbe3783b2a9b4780150dbc5b5400d620a563 100644
GIT binary patch
literal 356
zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1mUKs7M+SzC{oH>NS%G|}ByV>Y
zhX3vTXZ8bm>?NMQuIx`(ctr(-CspmY1q#jZba4!^IDK}qBVV(Eh>JY0ci)9CcFWk4
zGW#Fz{lNC`Z^=ck`rcVmrZ0UW1k!%YXKcFBcG_*P@tv2xpO;+d*%T11RTg{CTr^L(
znKNj{^xs=$(=AR5EZ;jXI#G9NvX;)la67xDB4zi!_-j`Fc^JK_?aJZn`mZ}2%=T_F
zo|(ben-juTxhh!XROvk~%fm*W-SxgNzy6_u{{g4c*XD08A4G}*-KbjP8c~vxSdwa$
zT$Bo=7>o>z40H`lbPY{H3=FIc&8!S9bq$QI3=E#@dc8%_kei>9nO2Eg!?c1=fj|um
Mp00i_>zopr08+SqG5`Po
delta 160
zcmV;R0AK&)0{65(~ZQCuc%!`UlYrw+#JW$-6NS%G|}ByV>Y
zhX3vTXZ8bm>?NMQuIx`(ctr&m6Azy&1q!Y5ba4!^IK6kWBiA7V0oQm{X+?K|_rZG_
z#a~{^+3R^Qd8v8Ef!+^yGkl$INh~=RfA-1$nLjx*U1Hy8{havVh`Cfe^ethQfYfeqs3*3v{I(1^^
zOl8fB)8~wdGG8qgvqQ&jj;zA3WLvf!>9c$eNBso>z40H`lbPY{H3=FIc&8!Rzbq$QI3=AYP
gSVT}XmdKI;Vst0MB8BLI3~&
delta 169
zcmV;a09OC@0=fZ^8Gi-<007{3J@^0s0D(zFK~zXf?Uhjuz#s@i_2#|#7M7Vfmkv;g
z`_Nw#o^3&L3O+fwetH1_93xNwkDBWM?MpOOMY&nQ1{6!zg{+0j?sv%4x&O_9H)J-L
zQ`+=v>M6kURfzv?1y%qHSDj=FpxzzR6<8NjSIF|(P=NT`LL$r-b@czW!@~e~aoVOQ
XoL!9<8%Con00000NkvXXu0mjf!iPzK
diff --git a/share/dark_resources/blocked16.png b/share/dark_resources/blocked16.png
index 79e31c3faafd1742b7b27e9945e3c39fbe7fca0a..270a727a1abba5ca4d4ac510dbcfa8add0522866 100644
GIT binary patch
literal 2935
zcmZ`*c{tQx7yr%}d$LBhrcnJ7HFjAVF=T0oOl2K4V|x+VNrhx5F@zENS+f0XF&KL!
z`-pci_AP6SEt#3{PVay3AMd%(IiGvaeLl}~?!D*Udt&aI-sa&F;{pJH$H)+2!9>^}
zJ9hrN36{8d5ob25&(iP0YGR30MMDP&{Y8NV-nXL06-%h
z07Sg9h~`?%3AV>3w-La}pO)MFF@@>j^fI*aVWQ!G)u6}iCbPrtYlPHiUxM(Q;o}Yy
zzU&47Tuw%aTb3>}WUJ@ysbtX;ZR#@;W9An@gnkSDS2TyUen!2+-}v-Zf}xBOKG}l;
zU$0gdIAi=d?Wl_O)d8W$TD)MJC6&&KwMuu;wC=w@V$JeREznKvyf
zO;G2T`}R#}`6HlC+sMZ=n8e7Mr3SrNxk0_bYjkDj#J%^Wc$@8jPqX9%!H#QA70?$L
z<__iP1VKQ)Cf#xU9aATw;55hYg5NZN4IpGvdEhZ1prc{<8PWB%+vM^^tfWk$Vi((r
zB7DG~hr?v*76RYU17&vrDuHo8M#Q$uDBsioAvPie$O3F_aLCE}|9$tb}U{f|{N3D`?s`uI|JKsvt{!
z?0$(>jA^PmgTJ|0V&XRib+u$8U>BFjUvBVt38wHpid9%Uc~!oqG4il+g9wK;8F-CC
z9#@^chw^K6v~p{h3n{58-ypKEu!NNlmbWv-q}>7Lkm+>C_==yM+V1WiSFdndsvNqd
z$$d@UBu@JrDgO-2G+d!;P_umRdCt6e#+fifjx!;ytYSzn*r%x7q3*x
zZ453XFHqgbE9Z^6(luf_bKQuhh(>R3Z-N>-iRPToGl?{Apue)4$cVQ)Xq+x-p~i`-Ec
znKDg`$0g_EwyIj8ZZ58_l)kf?JH1yc5KdqT034>%GPa>DThR21`w8eC6-q2DO|?x7yB!Ke
z71q^CJGNm1>7!IlAv#j$o*Eps@CwzM4cbil0rx2AfWK`lBca$e$MnIT(_DsS>i
z{7D%16E`BEc+oaW<4V}_^6~<0Zw21V8UPB7#!4j+JZ#8hGJ~hXrM#?6=u=EnNy%-A
zuMJ|f2x_NRnxj?JjHV@ALqp6o2O8Qx(9?WXAh9eP2k`&1S9DHWTM?q`=C5fw+L#Rgw2M226;$m=_y9Q1X7bUvJ>1B{aDBRS(gTWy(W%MR~
zgE-hDc==>KX9b#`=MDifen0`azUtHG)DP>J+fo;D6TP=K^6^9+j
zuJEy^TYGZX3TCP3$KIdh?&(J0eeFnQXhc#jGtuw2&cZ{Qu_@a*Nk}w$c9K|L*ZO<6
z?=)~WQel`({>gc%SF1pKr6e}kj1BY}=M6jwp3rF<8X8);nM29~9eysxraY|Vq^uHO
z5UQ(p|3#T0c;KI}4Hvw;*eACmAz~Zu<;DgYQI1=@Tilku1Nn98=u&xnq}u
znrEiuP#lG>kvCR~A>aq#SArSFNO2Kc`U;Io*TAN@2hoB89QWA4;q7y|u9=Fjbz}tA
z>f|+Tig9Y!8)#vLg@w4WMDYvwnp0ZpMySs1?d{jGv9Xq5gt8(GHiW-$fm2S-CNKwA
zEhE1>W~a*O=HfE+P9A;m*8)m`5}+(58E25!98-n%z{UzR4+VWljZPxGHCldT{pitr
z3c$zpI=P(`n39?Jo$dqOS)q$K?@f~_egaO5~&iMV=m~Lk~9~t
zsmqa}-eK=a0oumL$D42FP+70lU%YTn4V9$zEo31lv;5~Jc#7^^!8?0J27|E?%#=@u
z?{>svPfhouQ~^HmH>pZpr#p|F`}xH<6KV*Aa|cD)+xZYcXQU>30#nQW>7Uo`{@PfK
z_n!T0oY>c=%a;>Bt+khy{=*1W@DH9OcwA|9<{PiV+?M0xkSMLF@a$F>KmR=!2`tTb
zM3qKGM$X8#HivXo^Xmpi@R26c?A#^~w64{sY~Gz69UXmo{F|m1`*+0fb8K@CHvXrY
zipr*4HMVDXce3xDQ)4s|;&4R&IV&kCdUVGeX9|pHC~=q+B?U%Azv#Gu=4`uTOa3^^
z&BM#f?pES6-hrLr@ntTIdzjFlsjQ*~mpn$tNA!ar+2v{YSvq!H+
zN0hN_U)ig?+Jo_!%)Wf#0srbVi(aVrpl5q0s+pCu`wm4~Af|JM!Wa~PYluA=e6Lx7
z{Q@I@8D1X1i@0PSAY
z4n8Gn&K~Neu64Y195BlR0W(TVN?OuSE#f>zryB#%{JIh|b)K{0({|HnQw7V+Dc}0J
zOCnnFF?iQ6$^+mLW$uO^(NGQ%tQXb$GFYlWlf4JxQ4wW!vFJ|}4o@KV?_Vz7Bxw+>>c7)f3E_KXr2R?W(HbhZ!zP`V|pXF^=
zhcd_c19=rK^!0dPfcQ<4N;nJj0#jUb!mYEd^))rV=JVm7!?Us^^q60&&Qg7%(m8Q8
zW(lx5TwubyIW9WJl-me9gfG9&Qtg;M{!EgUprLdgcpIF~ejaU{aT{?H$gX#H2No@Q
z&84_NXIc3sKRJ`)(V9;pF!02XgR!WdHyG
delta 2176
zcmV-`2!HqY7K{;)BYy}}NklCB8AG2b+HiYC{o7Mx+60PNGm^N+0p=7RxGl+
zgp#oE2F4_k_pur;8i!YmqKslv^n77IcfV7Y}a6@(VRN{cs!p}HfK0A8kWx)7uQ|1a?d
z5VD=H3P4xVNFI7aS7Y?d7YFbtcCB
ziV(w^h=>T6o}QjtX=!OeRPA68&>bMl{?n&Vulf7?|Cz~TcBH4L&rlU$^kR~Z8U
zLo5LB@bK_UNlB4ga?sn`+pu%z&QCB5dwBHdQSHkVUtV4wt57H!jAJeUc#Zd3d1_kf
zA($|kOn=syoSgijN~LNA0K9ma;w^P06M*30VArs)u%9dmLlESMUazkK0IXQqD3!`u
z*)3T>$_FW%VLBQb8UlNJd%FzJOaKA`0z^?!QB^R*j*gCosHmvp85tQru2kkx6fO4h
z@~ZFd?iPA_dZxqT)YsR4ESJl(7XT11Ze3m7wSV~d_ym|CgTYAT@pyHqsj0Jc0LU7G
z!5506m-u}C6*?v)Ba_KwCIE49aghRn
z;A@zHN~QW>?b@|f005i{01feTWiv4`(QocMH#he;I-RZ!7O$(T>-e2Jcjn;cOX$FX
z10pXkFX#(AJ3ISUUS8h)l@M>7d1L<0H
z&o6};Xs5M4`G3rROa?$B^9#zx+;>h+jD-AmF$Oz~SE=PJGqA`XQo%83<&n0{QB?bUEH8eEbjERW}g&8$9HMzC5wJC^aG{n;?8$(=cQ$bl-
z*${eY}su0Hjjs=_gN~6wnZF@gqgnj<;^zx_>J+Hg@hy
zYyN9(ZLJRv4^KIL`ZQ{?1H^eXH#av5!?3R`1t=*g@fM54KadG93}$4l66R;imMykI
zq0r(%X>wvRlk3d=%y5J?8K;Yiiq=b|(yP(Y(a)YsSd
zLqqwPl#n67rAwFmYN~6>qIX4yPzh=-elcZ3r7=`psTz=ENzzdiy>C4DEjSYc0N6N=
zCovd|5~=`8EgQ1T6FQViWr3HM*T-2|S^qZH1-(|ec<~~?qod;^AAcX8_sAerDxk&(ebK1qG`e92^2iM@M(bWU^49P)Pf|um*JX>ea#MsOWFKU-yb2;p!3_RYTS{@YtvELIzv&3>GeltihU
z(b@rH5TZk27=N~j#bRwA85!9o|6cAhFfic$zUY1EeWrOPD=RC9d|vla_zC<5H*MPV
zHyaz9o)<4(3`isrl&oaTebL$hV`E}^t*EGQ(CKt;Ha0dJ84SiRQ50P_Ha6z2QmLG#
zr>7lo9nRDvdW4BEG4?BL4VTNEba!`GI5|1}Q?J(#>v?p#Cu+6&AE!>8nxQM)pk>hj
z#xOT-++aR?_RQYV(a}+>)pD6k<}WY|V>6jd7J?uMj^jE6LDV>oqk6r5lEdMkt5>gn
zPFy2WsdH;{N
diff --git a/share/dark_resources/bold32.png b/share/dark_resources/bold32.png
index 46a46d9a0ec5573d70b858b1ec75a7e4f5707465..774d0f93c04dc2b15da3bb0f080fbdfea335e5bc 100644
GIT binary patch
literal 622
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50
z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-G$+Qd;gjJKpuOE
zr>`sf6Bb@k0k;3kqpvYAFqV0`IEHu}KN{lbci4faL`*|OMJVKou+zhkgPM<+ed{mC
z2gEtl9}xDa7pR*czoC*rX{wfrUyF3RlX(|c%!?w<6xpP=&zQa){d8mVHw&%<^|M3U
zwsRMp*d=1Yvi$P>T&{z2uh@wnJaM`}npySAuL&QumOCZP++n_3#dOBYa0UkNId24|
z?yP2Enxs^8aBablu-Tr`$F{>5}
zNj)e@Z@TEZUy<=Zy3;}y#(Rd_uiJ2$&Pd4Iyr5~>)|3}LO@Ddze)@2K*3#SVTkS-<~dw`{6j
zZr-`q6BsF~C9V-ADTyViR>?)FK#IZ0z{o(?z(m*3B*ehL%FxWpz)aV`*vi1*?s=nC}Q!>*kacfvJsR@`!7#KWV{an^LB{Ts5(97?b
delta 575
zcmV-F0>J(51kD7H8Gi-<0047(dh`GQ0u)I^K~z{r?UzrA;!qIA>%{}~=vpKs1Qk&n
zPmsPr-=Lkfpxrk}?_9XZfFQV;Il}Y_+BtyOEh7Gjv0G3OgieDCSJv=gghuPd#ChUo
z9%Pf$tM8Yu>QxAX3omwIeINk}g~B@kd^rK`6#!a@Xm>iDmwzDpNq~Glk3lvciTM?Y
zM2hWp`@=7e1jyxbG61;lbGO_58X6#*&B_7*M6`On-h&8&bRd(-$OQ2E{eCnQKsuck
z0eIZjy<{o?@JqN5(Hsm0zo`Jyfn+i%0%#3~!|VM-sZ{C~5r2vZco{~c5m^Qjz%UFU
zz<4}90N}!gVShXUfJs4c0LO8H1L(Rg1ei=FB!I5#KLDU80&rb7IDn>UBmg3|rqk&G
zfTn3zi1^AFBZrrwC^wGdJO=IoRaHd*&y2CV&xy9%ZJys_jENf2QxrvYU6&k4WDg_~
z32Da=0Pbe9+4oS#FdmOf0pKTNKA(RJJqaz#`e%S>2Z%N
zE_4a}rZ}44GigouAK(-RME3JsXYT<&@v{OP6ZZWYo?`QT^&wCLRu}*P
N002ovPDHLkV1gps05$*s
diff --git a/share/dark_resources/bookmarks16.png b/share/dark_resources/bookmarks16.png
index 63304362d976cadedfce2e9f31743ee3e1021f1c..71e829147a44ed34a1d4b1f212367201c2615baf 100644
GIT binary patch
literal 377
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijSl0AZa
z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+ueoXe|!I#{Xiaj
ziKnkC`x6#kQ2`$LqD?1&LXDm-jv*T7k507ba|qyRx33pdFA$Wz+`Xgoh^|HV5!E9q
zF^4#Byfw9{tmI&8F3Y%Fw|`lt?8BRPrrZ6K6Mht&p0c5FN{D!mf(6rsz{rM^@#Q}l
z16EWYSiEG}vLn0YxSXOCn53fArd@6^U9O&-rnWe~SXtz4tH!}1)z))!&fmYopf_Lb
zul&q<37}(COI#yLQW8s2t&)pUffR$0fsui(fr+l6Nr-`gm7$rHp^>hEv6X?rQ!P1h
e6b-rgDVb@NxHU{EU$z>kfx*+&&t;ucLK6V2;C8J5
delta 118
zcmey#)WJAGGM|lsfkFQB|3o0=@9E+gV&R{hvOvHfXvKWSqYZ6sZU2u*+_-Ro;kvst
z^MqW7GQl&gEU^Yz49v_rJQtXIUpS~t5#u<dD
W5WxvMPsjs}X7F_Nb6Mw<&;$UH7$@ie
diff --git a/share/dark_resources/bookmarks32.png b/share/dark_resources/bookmarks32.png
index 5bf9f69830a0feee9e702759ff220556d9d392ea..1394db58dd8b43e62a196fb6dfa35a46a6b2adde 100644
GIT binary patch
literal 431
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50
z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-G$+Qd;gjJKpuOE
zr>`sf6Bb@ke&ZCsiP=D*?Vc`^r1?6o
zqs@QBrk{6JoRpQjq(k9se9O#}d;XkJlQhd;oA&KLbAoJp?jfJ;H_c^j?i)P)@ZC9v
zfm?y~!I`s+Ps+A+Pt89s;MpNixz%aK(fw$GMw8K+#K3$|@yCs%tje94y$^s{ArV6nk&%43Q2O;7W;
zSoi&Q+W+udh&|8?swJ)wB`Jv|saDBFsX&Us$iT=z*T6*A&?Lmbz{=3n%G6NTz}U*b
jVE6uw#V8tb^HVa@DsgK#^@#I4Py>UftDnm{r-UW|$t;ym
delta 209
zcmV;?051Qp1L6UY8Gi-<0047(dh`GQ0I5ktK~z{r?U&6803is3>&<=hT{;*c{tPJ8
z!M$cVerVIqarv8<^N$wrHUT2~Dtd&7%tBoP&j|1;@Cb1MX#y>v2{eHw&;%?3(N!C*
zuWKAKBTaxbDlewo3oMtEiOLC}_RK;`1!&1-qSKn!TA2XN^GYq;NbDH{HK9B-nhG=?
zo&r7)y^xRz;WJ?ZX!1kse$bYWA^K8IHzArR6ZiIyNv1M%?{xw{opi_{9S<>&pIwg;$i{v{%<84k+}%)5S4F<9zKzLvN=*nWOdR
zLwMEB{Db&6${ly*MQt!-OY*1ql9f}0053nqjWPCTG5@KEmJqh|_txC1keKa89I
z-Zp;T|02Hc1^>R^>AtXVS=h?Rmyx0m*%x-7*|=uSmqnY*r*Ind*RV+K)-F%Bd&zK{
zWvki3Rj=-PIj{G6^Jx0bFcHbVyQ&}Fx)!mUCrM_oGJh#zd$n^;w%VU1Jj+gpFA&`R
z?#kVn!jB$_z3^BcR`xNTJHp`Jb*1Jc=U%f9({n!_uz8rijx%jT<*Q@w(j!-{XI4~l
z>{LHj?0s)XI_m~D_r}TlqeUh>2l`dD#5JNMC9x#cD!C{XNHG{07#ZjqnCKdsgculD
t8Jb#|8tWPuTNxPWC@hFV(U6;;l9^VCTSIKE#514<22WQ%mvv4FO#tDNvk(9P
delta 130
zcmV-|0Db@M1C#-f8G8l*001BJ|6u?C09#2!K~y+TwUI#z03Zki?dSXRqKFVlRtvp^
zB*W@75fK1=zL5gZ^xSGPfIWX8H2@paCe;7e1QuY|Oasyhm<^hM0knxH3lzYP_yq7w
kgf)HxJe4&^EZ3+l4H*4g5g^zN=Kufz07*qoM6N<$f=x&;S^xk5
diff --git a/share/dark_resources/buffer16.png b/share/dark_resources/buffer16.png
index 1e215e8513f90044e29e91bc17ca0780d31a9a17..ae5b80219591b9ebe04cfefa1cea915818c4601e 100644
GIT binary patch
literal 579
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijSl0AZa
z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+ueoXe|!I#{XiaP
zfk$L90|Vb-5N14{zaj-F$X?><>&pIwg;$i{;II3Eiwq2mW}YsNAsXj>FB|PCVk8XsD*<)3!8mv6^Y-
z;ufcd6Dd`(^A>&QG5=q^tlCfTlS*#v($0nRCgzA#>Q^m$+Mev0d9vL4m_o~oV`Vm7
zJ12y8f2|OHE6@_r^L9sluHROn^^3(O9h$YC&tUP(X}g$e%2K9wSx4P#>=S2u^{s|s
z_coJB>l(ccmcO6+U2avw{ByeDQ~EwHUYP8BeV_eIf0N0bCcTFu&WnG)Vl1vCskQ#&
zm4)*z<@Bw~47vE(;jrepJ0C9f^t(OSwrZb%^hPYo+x`Ac4c)xz@tugG;H&1<>;B~nOHJGA)AJ?Pr@x-@
z{^I)YQGP4_0RvUF#5JNMC9x#cD!C{XNHG{07#ZjqnCKdsgculD8Jb#|Sm+uUTNxNU
i>iuGeq9HdwB{QuOw}#0Ve42n77(8A5T-G@yGywo8xZ?`|
delta 451
zcmV;!0X+W01kwYL8Gi-<001BJ|6u?C0hvieK~y+Tb<<0zh*1;;;P1K&m|TzKSrQYE
zGBILCNg>IcO$-Pv?O&%Kr~djoXYaN4
z+I#H*f1h!fhozW_A9#-Y7{kvtWuTWo2b(biPw@%?4A5LW!ha~