- 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'
- 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
This commit is contained in:
Marius Stanciu 2019-02-09 00:08:54 +02:00 committed by Marius S
parent 824b1a95ab
commit 8f000c0a18
11 changed files with 347 additions and 112 deletions

View File

@ -1714,16 +1714,14 @@ class App(QtCore.QObject):
try: try:
if error: if error:
self.shell.append_error(msg + "\n") self.shell.append_error(msg + "\n")
elif warning:
self.shell.append_warning(msg + "\n")
elif success:
self.shell.append_success(msg + "\n")
elif selected:
self.shell.append_selected(msg + "\n")
else: else:
if warning: self.shell.append_output(msg + "\n")
self.shell.append_warning(msg + "\n")
else:
if success:
self.shell.append_success(msg + "\n")
if success:
self.shell.append_selected(msg + "\n")
else:
self.shell.append_output(msg + "\n")
except AttributeError: except AttributeError:
log.debug("shell_message() is called before Shell Class is instantiated. The message is: %s", str(msg)) log.debug("shell_message() is called before Shell Class is instantiated. The message is: %s", str(msg))
@ -2298,6 +2296,7 @@ class App(QtCore.QObject):
self.collection.set_all_inactive() self.collection.set_all_inactive()
self.collection.set_active(obj.options["name"]) self.collection.set_active(obj.options["name"])
# here it is done the object plotting
def worker_task(obj): def worker_task(obj):
with self.proc_container.new("Plotting"): with self.proc_container.new("Plotting"):
if isinstance(obj, FlatCAMCNCjob): if isinstance(obj, FlatCAMCNCjob):
@ -2740,6 +2739,60 @@ class App(QtCore.QObject):
self.inform.emit("[success] A Geometry object was converted to SingleGeo type.") self.inform.emit("[success] A Geometry object was converted to SingleGeo type.")
def on_skey_tool_add(self):
## Current application units in Upper Case
self.units = self.general_options_form.general_app_group.units_radio.get_value().upper()
# work only if the notebook tab on focus is the Selected_Tab and only if the object is Geometry
if self.ui.notebook.currentWidget().objectName() == 'selected_tab':
if str(type(self.collection.get_active())) == "<class 'FlatCAMObj.FlatCAMGeometry'>":
tool_add_popup = FCInputDialog(title="New Tool ...",
text='Enter a Tool Diameter:',
min=0.0000, max=99.9999, decimals=4)
tool_add_popup.setWindowIcon(QtGui.QIcon('share/letter_t_32.png'))
val, ok = tool_add_popup.get_value()
if ok:
self.collection.get_active().on_tool_add(dia=float(val))
self.inform.emit(
"[success]Added new tool with dia: %s %s" % ('%.4f' % float(val), str(self.units)))
else:
self.inform.emit(
"[WARNING_NOTCL] Adding Tool cancelled ...")
# work only if the notebook tab on focus is the Tools_Tab
if self.ui.notebook.currentWidget().objectName() == 'tool_tab':
# and only if the tool is NCC Tool
if self.ui.tool_scroll_area.widget().objectName() == self.ncclear_tool.toolName:
tool_add_popup = FCInputDialog(title="New Tool ...",
text='Enter a Tool Diameter:',
min=0.0000, max=99.9999, decimals=4)
tool_add_popup.setWindowIcon(QtGui.QIcon('share/letter_t_32.png'))
val, ok = tool_add_popup.get_value()
if ok:
self.ncclear_tool.on_tool_add(dia=float(val))
self.inform.emit(
"[success]Added new tool with dia: %s %s" % ('%.4f' % float(val), str(self.units)))
else:
self.inform.emit(
"[WARNING_NOTCL] Adding Tool cancelled ...")
# and only if the tool is Paint Area Tool
if self.ui.tool_scroll_area.widget().objectName() == self.paint_tool.toolName:
tool_add_popup = FCInputDialog(title="New Tool ...",
text='Enter a Tool Diameter:',
min=0.0000, max=99.9999, decimals=4)
tool_add_popup.setWindowIcon(QtGui.QIcon('share/letter_t_32.png'))
val, ok = tool_add_popup.get_value()
if ok:
self.paint_tool.on_tool_add(dia=float(val))
self.inform.emit(
"[success]Added new tool with dia: %s %s" % ('%.4f' % float(val), str(self.units)))
else:
self.inform.emit(
"[WARNING_NOTCL] Adding Tool cancelled ...")
def on_options_dict_change(self, field): def on_options_dict_change(self, field):
self.options_write_form_field(field) self.options_write_form_field(field)

View File

@ -3255,7 +3255,8 @@ class FlatCAMExcEditor(QtCore.QObject):
grid1.addWidget(addtool_entry_lbl, 0, 0) grid1.addWidget(addtool_entry_lbl, 0, 0)
hlay = QtWidgets.QHBoxLayout() hlay = QtWidgets.QHBoxLayout()
self.addtool_entry = LengthEntry() self.addtool_entry = FCEntry()
self.addtool_entry.setValidator(QtGui.QDoubleValidator(0.0001, 99.9999, 4))
hlay.addWidget(self.addtool_entry) hlay.addWidget(self.addtool_entry)
self.addtool_btn = QtWidgets.QPushButton('Add Tool') self.addtool_btn = QtWidgets.QPushButton('Add Tool')
@ -3663,7 +3664,7 @@ class FlatCAMExcEditor(QtCore.QObject):
if self.units == "IN": if self.units == "IN":
self.addtool_entry.set_value(0.039) self.addtool_entry.set_value(0.039)
else: else:
self.addtool_entry.set_value(1) self.addtool_entry.set_value(1.00)
sort_temp = [] sort_temp = []
@ -3847,9 +3848,21 @@ class FlatCAMExcEditor(QtCore.QObject):
# we reactivate the signals after the after the tool adding as we don't need to see the tool been populated # we reactivate the signals after the after the tool adding as we don't need to see the tool been populated
self.tools_table_exc.itemChanged.connect(self.on_tool_edit) self.tools_table_exc.itemChanged.connect(self.on_tool_edit)
def on_tool_add(self): def on_tool_add(self, tooldia=None):
self.is_modified = True self.is_modified = True
tool_dia = float(self.addtool_entry.get_value()) if tooldia:
tool_dia = tooldia
else:
try:
tool_dia = float(self.addtool_entry.get_value())
except ValueError:
# try to convert comma to decimal point. if it's still not working error message and return
try:
tool_dia = float(self.addtool_entry.get_value().replace(',', '.'))
except ValueError:
self.app.inform.emit("[ERROR_NOTCL]Wrong value format entered, "
"use a number.")
return
if tool_dia not in self.olddia_newdia: if tool_dia not in self.olddia_newdia:
storage_elem = FlatCAMGeoEditor.make_storage() storage_elem = FlatCAMGeoEditor.make_storage()
@ -4156,6 +4169,9 @@ class FlatCAMExcEditor(QtCore.QObject):
self.replot() self.replot()
# add a first tool in the Tool Table
self.on_tool_add(tooldia=1.00)
def update_fcexcellon(self, exc_obj): def update_fcexcellon(self, exc_obj):
""" """
Create a new Excellon object that contain the edited content of the source Excellon object Create a new Excellon object that contain the edited content of the source Excellon object

View File

@ -563,6 +563,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
### Project ### ### Project ###
self.project_tab = QtWidgets.QWidget() self.project_tab = QtWidgets.QWidget()
self.project_tab.setObjectName("project_tab")
# project_tab.setMinimumWidth(250) # Hack # project_tab.setMinimumWidth(250) # Hack
self.project_tab_layout = QtWidgets.QVBoxLayout(self.project_tab) self.project_tab_layout = QtWidgets.QVBoxLayout(self.project_tab)
self.project_tab_layout.setContentsMargins(2, 2, 2, 2) self.project_tab_layout.setContentsMargins(2, 2, 2, 2)
@ -570,6 +571,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
### Selected ### ### Selected ###
self.selected_tab = QtWidgets.QWidget() self.selected_tab = QtWidgets.QWidget()
self.selected_tab.setObjectName("selected_tab")
self.selected_tab_layout = QtWidgets.QVBoxLayout(self.selected_tab) self.selected_tab_layout = QtWidgets.QVBoxLayout(self.selected_tab)
self.selected_tab_layout.setContentsMargins(2, 2, 2, 2) self.selected_tab_layout.setContentsMargins(2, 2, 2, 2)
self.selected_scroll_area = VerticalScrollArea() self.selected_scroll_area = VerticalScrollArea()
@ -578,6 +580,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
### Tool ### ### Tool ###
self.tool_tab = QtWidgets.QWidget() self.tool_tab = QtWidgets.QWidget()
self.tool_tab.setObjectName("tool_tab")
self.tool_tab_layout = QtWidgets.QVBoxLayout(self.tool_tab) self.tool_tab_layout = QtWidgets.QVBoxLayout(self.tool_tab)
self.tool_tab_layout.setContentsMargins(2, 2, 2, 2) self.tool_tab_layout.setContentsMargins(2, 2, 2, 2)
self.notebook.addTab(self.tool_tab, "Tool") self.notebook.addTab(self.tool_tab, "Tool")
@ -826,6 +829,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
<td height="20"><strong>S</strong></td> <td height="20"><strong>S</strong></td>
<td>&nbsp;Shell Toggle</td> <td>&nbsp;Shell Toggle</td>
</tr> </tr>
<tr height="20">
<td height="20"><strong>T</strong></td>
<td>&nbsp;Add a Tool (when in Geometry Selected Tab)</td>
</tr>
<tr height="20"> <tr height="20">
<td height="20"><strong>V</strong></td> <td height="20"><strong>V</strong></td>
<td>&nbsp;Zoom Fit</td> <td>&nbsp;Zoom Fit</td>
@ -948,7 +955,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
</tr> </tr>
<tr height="20"> <tr height="20">
<td height="20"><strong>ALT+R</strong></td> <td height="20"><strong>ALT+R</strong></td>
<td>&nbsp;Transformation Tool</td> <td>&nbsp;Transformations Tool</td>
</tr> </tr>
<tr height="20"> <tr height="20">
<td height="20"><strong>ALT+U</strong></td> <td height="20"><strong>ALT+U</strong></td>
@ -1131,6 +1138,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
<td height="20"><strong>R</strong></td> <td height="20"><strong>R</strong></td>
<td>&nbsp;Resize Drill(s)</td> <td>&nbsp;Resize Drill(s)</td>
</tr> </tr>
<tr height="20">
<td height="20"><strong>T</strong></td>
<td>&nbsp;Add a new Tool</td>
</tr>
<tr height="20"> <tr height="20">
<td height="20">&nbsp;</td> <td height="20">&nbsp;</td>
<td>&nbsp;</td> <td>&nbsp;</td>
@ -1755,9 +1766,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
if key == QtCore.Qt.Key_S: if key == QtCore.Qt.Key_S:
self.app.on_toggle_shell() self.app.on_toggle_shell()
# Transform Tool # Add a Tool from shortcut
if key == QtCore.Qt.Key_T: if key == QtCore.Qt.Key_T:
self.app.transform_tool.run() self.app.on_skey_tool_add()
# Zoom Fit # Zoom Fit
if key == QtCore.Qt.Key_V: if key == QtCore.Qt.Key_V:
@ -1801,6 +1812,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
elif modifiers == QtCore.Qt.AltModifier: elif modifiers == QtCore.Qt.AltModifier:
pass pass
else: else:
# toggle display of Notebook area
if key == QtCore.Qt.Key_QuoteLeft or key == '`':
self.app.on_toggle_notebook()
# Finish the current action. Use with tools that do not # Finish the current action. Use with tools that do not
# complete automatically, like a polygon or path. # complete automatically, like a polygon or path.
if key == QtCore.Qt.Key_Enter or key == 'Enter': if key == QtCore.Qt.Key_Enter or key == 'Enter':
@ -1840,14 +1855,25 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.app.geo_editor.active_tool.set_origin( self.app.geo_editor.active_tool.set_origin(
self.app.geo_editor.snap(self.app.geo_editor.x, self.app.geo_editor.y)) self.app.geo_editor.snap(self.app.geo_editor.x, self.app.geo_editor.y))
if key == QtCore.Qt.Key_1 or key== '1': if key == QtCore.Qt.Key_Minus or key == '-':
self.app.on_zoom_fit(None) self.app.plotcanvas.zoom(1 / self.app.defaults['zoom_ratio'],
[self.app.geo_editor.snap_x, self.app.geo_editor.snap_y])
if key == QtCore.Qt.Key_Equal or key == '=':
self.app.plotcanvas.zoom(self.app.defaults['zoom_ratio'],
[self.app.geo_editor.snap_x, self.app.geo_editor.snap_y])
# Switch to Project Tab
if key == QtCore.Qt.Key_1 or key == '1':
self.app.on_select_tab('project')
# Switch to Selected Tab
if key == QtCore.Qt.Key_2 or key == '2': if key == QtCore.Qt.Key_2 or key == '2':
self.app.plotcanvas.zoom(1 / self.app.defaults['zoom_ratio'], [self.snap_x, self.snap_y]) self.app.on_select_tab('selected')
# Switch to Tool Tab
if key == QtCore.Qt.Key_3 or key == '3': if key == QtCore.Qt.Key_3 or key == '3':
self.app.plotcanvas.zoom(self.app.defaults['zoom_ratio'], [self.snap_x, self.snap_y]) self.app.on_select_tab('tool')
# Arc Tool # Arc Tool
if key == QtCore.Qt.Key_A or key == 'A': if key == QtCore.Qt.Key_A or key == 'A':
@ -1954,6 +1980,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
messagebox.setDefaultButton(QtWidgets.QMessageBox.Ok) messagebox.setDefaultButton(QtWidgets.QMessageBox.Ok)
messagebox.exec_() messagebox.exec_()
if key == QtCore.Qt.Key_V or key == 'V':
self.app.on_zoom_fit(None)
# Cut Action Tool # Cut Action Tool
if key == QtCore.Qt.Key_X or key == 'X': if key == QtCore.Qt.Key_X or key == 'X':
if self.app.geo_editor.get_selected() is not None: if self.app.geo_editor.get_selected() is not None:
@ -1975,7 +2004,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# Propagate to tool # Propagate to tool
response = None response = None
if self.app.geo_editor.active_tool is not None: if self.app.geo_editor.active_tool is not None:
response = self.app.geo_editor.active_tool.on_key(event.key) response = self.app.geo_editor.active_tool.on_key(event)
if response is not None: if response is not None:
self.app.inform.emit(response) self.app.inform.emit(response)
@ -2024,17 +2053,41 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.app.inform.emit("[WARNING_NOTCL]Cancelled. Nothing selected to delete.") self.app.inform.emit("[WARNING_NOTCL]Cancelled. Nothing selected to delete.")
return return
if key == QtCore.Qt.Key_Minus or key == '-':
self.app.exc_editor.launched_from_shortcuts = True
self.app.plotcanvas.zoom(1 / self.app.defaults['zoom_ratio'],
[self.app.exc_editor.snap_x, self.app.exc_editor.snap_y])
return
if key == QtCore.Qt.Key_Equal or key == '=':
self.app.exc_editor.launched_from_shortcuts = True
self.app.plotcanvas.zoom(self.app.defaults['zoom_ratio'],
[self.app.exc_editor.snap_x, self.app.exc_editor.snap_y])
return
# toggle display of Notebook area
if key == QtCore.Qt.Key_QuoteLeft or key == '`':
self.app.exc_editor.launched_from_shortcuts = True
self.app.on_toggle_notebook()
return
# Switch to Project Tab
if key == QtCore.Qt.Key_1 or key == '1': if key == QtCore.Qt.Key_1 or key == '1':
self.app.exc_editor.launched_from_shortcuts = True self.app.exc_editor.launched_from_shortcuts = True
self.app.on_zoom_fit(None) self.app.on_select_tab('project')
return
# Switch to Selected Tab
if key == QtCore.Qt.Key_2 or key == '2': if key == QtCore.Qt.Key_2 or key == '2':
self.app.exc_editor.launched_from_shortcuts = True self.app.exc_editor.launched_from_shortcuts = True
self.app.plotcanvas.zoom(1 / self.app.defaults['zoom_ratio'], [self.snap_x, self.snap_y]) self.app.on_select_tab('selected')
return
# Switch to Tool Tab
if key == QtCore.Qt.Key_3 or key == '3': if key == QtCore.Qt.Key_3 or key == '3':
self.app.exc_editor.launched_from_shortcuts = True self.app.exc_editor.launched_from_shortcuts = True
self.app.plotcanvas.zoom(self.app.defaults['zoom_ratio'], [self.snap_x, self.snap_y]) self.app.on_select_tab('tool')
return
# Add Array of Drill Hole Tool # Add Array of Drill Hole Tool
if key == QtCore.Qt.Key_A or key == 'A': if key == QtCore.Qt.Key_A or key == 'A':
@ -2100,10 +2153,36 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.app.exc_editor.select_tool('resize') self.app.exc_editor.select_tool('resize')
return return
# Add Tool
if key == QtCore.Qt.Key_T or key == 'T':
self.app.exc_editor.launched_from_shortcuts = True
## Current application units in Upper Case
self.units = self.app.general_options_form.general_app_group.units_radio.get_value().upper()
tool_add_popup = FCInputDialog(title="New Tool ...",
text='Enter a Tool Diameter:',
min=0.0000, max=99.9999, decimals=4)
tool_add_popup.setWindowIcon(QtGui.QIcon('share/letter_t_32.png'))
val, ok = tool_add_popup.get_value()
if ok:
self.app.exc_editor.on_tool_add(tooldia=val)
self.app.inform.emit(
"[success]Added new tool with dia: %s %s" % ('%.4f' % float(val), str(self.units)))
else:
self.app.inform.emit(
"[WARNING_NOTCL] Adding Tool cancelled ...")
return
# Zoom Fit
if key == QtCore.Qt.Key_V or key == 'V':
self.app.exc_editor.launched_from_shortcuts = True
self.app.on_zoom_fit(None)
return
# Propagate to tool # Propagate to tool
response = None response = None
if self.app.exc_editor.active_tool is not None: if self.app.exc_editor.active_tool is not None:
response = self.app.exc_editor.active_tool.on_key(event.key) response = self.app.exc_editor.active_tool.on_key(event)
if response is not None: if response is not None:
self.app.inform.emit(response) self.app.inform.emit(response)

View File

@ -480,7 +480,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
def geo_init(geo_obj, app_obj): def geo_init(geo_obj, app_obj):
assert isinstance(geo_obj, FlatCAMGeometry) assert isinstance(geo_obj, FlatCAMGeometry)
bounding_box = self.solid_geometry.envelope.buffer(self.options["noncoppermargin"]) bounding_box = self.solid_geometry.envelope.buffer(float(self.options["noncoppermargin"]))
if not self.options["noncopperrounded"]: if not self.options["noncopperrounded"]:
bounding_box = bounding_box.envelope bounding_box = bounding_box.envelope
non_copper = bounding_box.difference(self.solid_geometry) non_copper = bounding_box.difference(self.solid_geometry)
@ -497,7 +497,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
def geo_init(geo_obj, app_obj): def geo_init(geo_obj, app_obj):
assert isinstance(geo_obj, FlatCAMGeometry) assert isinstance(geo_obj, FlatCAMGeometry)
# Bounding box with rounded corners # Bounding box with rounded corners
bounding_box = self.solid_geometry.envelope.buffer(self.options["bboxmargin"]) bounding_box = self.solid_geometry.envelope.buffer(float(self.options["bboxmargin"]))
if not self.options["bboxrounded"]: # Remove rounded corners if not self.options["bboxrounded"]: # Remove rounded corners
bounding_box = bounding_box.envelope bounding_box = bounding_box.envelope
geo_obj.solid_geometry = bounding_box geo_obj.solid_geometry = bounding_box
@ -557,7 +557,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
def follow_init(follow_obj, app): def follow_init(follow_obj, app):
# Propagate options # Propagate options
follow_obj.options["cnctooldia"] = self.options["isotooldia"] follow_obj.options["cnctooldia"] = float(self.options["isotooldia"])
follow_obj.solid_geometry = self.solid_geometry follow_obj.solid_geometry = self.solid_geometry
# TODO: Do something if this is None. Offer changing name? # TODO: Do something if this is None. Offer changing name?
@ -579,11 +579,11 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
:return: None :return: None
""" """
if dia is None: if dia is None:
dia = self.options["isotooldia"] dia = float(self.options["isotooldia"])
if passes is None: if passes is None:
passes = int(self.options["isopasses"]) passes = int(self.options["isopasses"])
if overlap is None: if overlap is None:
overlap = self.options["isooverlap"] overlap = float(self.options["isooverlap"])
if combine is None: if combine is None:
combine = self.options["combine_passes"] combine = self.options["combine_passes"]
else: else:
@ -638,7 +638,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
# TODO: This is ugly. Create way to pass data into init function. # TODO: This is ugly. Create way to pass data into init function.
def iso_init(geo_obj, app_obj): def iso_init(geo_obj, app_obj):
# Propagate options # Propagate options
geo_obj.options["cnctooldia"] = self.options["isotooldia"] geo_obj.options["cnctooldia"] = float(self.options["isotooldia"])
geo_obj.solid_geometry = [] geo_obj.solid_geometry = []
for i in range(passes): for i in range(passes):
iso_offset = (((2 * i + 1) / 2.0) * dia) - (i * overlap * dia) iso_offset = (((2 * i + 1) / 2.0) * dia) - (i * overlap * dia)
@ -693,7 +693,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
# TODO: This is ugly. Create way to pass data into init function. # TODO: This is ugly. Create way to pass data into init function.
def iso_init(geo_obj, app_obj): def iso_init(geo_obj, app_obj):
# Propagate options # Propagate options
geo_obj.options["cnctooldia"] = self.options["isotooldia"] geo_obj.options["cnctooldia"] = float(self.options["isotooldia"])
# if milling type is climb then the move is counter-clockwise around features # if milling type is climb then the move is counter-clockwise around features
if milling_type == 'cl': if milling_type == 'cl':
@ -753,8 +753,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
factor = Gerber.convert_units(self, units) factor = Gerber.convert_units(self, units)
self.options['isotooldia'] *= factor self.options['isotooldia'] = float(self.options['isotooldia']) * factor
self.options['bboxmargin'] *= factor self.options['bboxmargin'] = float(self.options['bboxmargin']) * factor
def plot(self, **kwargs): def plot(self, **kwargs):
""" """
@ -1458,7 +1458,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
outname = self.options["name"] + "_mill" outname = self.options["name"] + "_mill"
if tooldia is None: if tooldia is None:
tooldia = self.options["tooldia"] tooldia = float(self.options["tooldia"])
# Sort tools by diameter. items() -> [('name', diameter), ...] # Sort tools by diameter. items() -> [('name', diameter), ...]
# sorted_tools = sorted(list(self.tools.items()), key=lambda tl: tl[1]) # no longer works in Python3 # sorted_tools = sorted(list(self.tools.items()), key=lambda tl: tl[1]) # no longer works in Python3
@ -1545,7 +1545,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
outname = self.options["name"] + "_mill" outname = self.options["name"] + "_mill"
if tooldia is None: if tooldia is None:
tooldia = self.options["slot_tooldia"] tooldia = float(self.options["slot_tooldia"])
# Sort tools by diameter. items() -> [('name', diameter), ...] # Sort tools by diameter. items() -> [('name', diameter), ...]
# sorted_tools = sorted(list(self.tools.items()), key=lambda tl: tl[1]) # no longer works in Python3 # sorted_tools = sorted(list(self.tools.items()), key=lambda tl: tl[1]) # no longer works in Python3
@ -1693,13 +1693,13 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
job_obj.options['ppname_e'] = pp_excellon_name job_obj.options['ppname_e'] = pp_excellon_name
app_obj.progress.emit(20) app_obj.progress.emit(20)
job_obj.z_cut = self.options["drillz"] job_obj.z_cut = float(self.options["drillz"])
job_obj.z_move = self.options["travelz"] job_obj.z_move = float(self.options["travelz"])
job_obj.feedrate = self.options["feedrate"] job_obj.feedrate = float(self.options["feedrate"])
job_obj.feedrate_rapid = self.options["feedrate_rapid"] job_obj.feedrate_rapid = float(self.options["feedrate_rapid"])
job_obj.spindlespeed = self.options["spindlespeed"] job_obj.spindlespeed = float(self.options["spindlespeed"])
job_obj.dwell = self.options["dwell"] job_obj.dwell = self.options["dwell"]
job_obj.dwelltime = self.options["dwelltime"] job_obj.dwelltime = float(self.options["dwelltime"])
job_obj.pp_excellon_name = pp_excellon_name job_obj.pp_excellon_name = pp_excellon_name
job_obj.toolchange_xy_type = "excellon" job_obj.toolchange_xy_type = "excellon"
@ -1738,12 +1738,13 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
tools_csv = ','.join(tools) tools_csv = ','.join(tools)
ret_val = job_obj.generate_from_excellon_by_tool(self, tools_csv, ret_val = job_obj.generate_from_excellon_by_tool(self, tools_csv,
drillz=self.options['drillz'], drillz=float(self.options['drillz']),
toolchange=self.options["toolchange"], toolchange=float(self.options["toolchange"]),
toolchangexy=self.app.defaults["excellon_toolchangexy"], toolchangexy=self.app.defaults["excellon_toolchangexy"],
toolchangez=self.options["toolchangez"], toolchangez=float(self.options["toolchangez"]),
startz=self.options["startz"], startz=float(self.options["startz"]) if
endz=self.options["endz"], self.options["startz"] else None,
endz=float(self.options["endz"]),
excellon_optimization_type=self.app.defaults[ excellon_optimization_type=self.app.defaults[
"excellon_optimization_type"]) "excellon_optimization_type"])
if ret_val == 'fail': if ret_val == 'fail':
@ -1783,11 +1784,11 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
def convert_units(self, units): def convert_units(self, units):
factor = Excellon.convert_units(self, units) factor = Excellon.convert_units(self, units)
self.options['drillz'] *= factor self.options['drillz'] = float(self.options['drillz']) * factor
self.options['travelz'] *= factor self.options['travelz'] = float(self.options['travelz']) * factor
self.options['feedrate'] *= factor self.options['feedrate'] = float(self.options['feedrate']) * factor
self.options['feedrate_rapid'] *= factor self.options['feedrate_rapid'] = float(self.options['feedrate_rapid']) * factor
self.options['toolchangez'] *= factor self.options['toolchangez'] = float(self.options['toolchangez']) * factor
if self.app.defaults["excellon_toolchangexy"] == '': if self.app.defaults["excellon_toolchangexy"] == '':
self.options['toolchangexy'] = "0.0, 0.0" self.options['toolchangexy'] = "0.0, 0.0"
@ -1802,8 +1803,8 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.options['toolchangexy'] = "%f, %f" % (coords_xy[0], coords_xy[1]) self.options['toolchangexy'] = "%f, %f" % (coords_xy[0], coords_xy[1])
if self.options['startz'] is not None: if self.options['startz'] is not None:
self.options['startz'] *= factor self.options['startz'] = float(self.options['startz']) * factor
self.options['endz'] *= factor self.options['endz'] = float(self.options['endz']) * factor
def plot(self): def plot(self):
@ -2271,7 +2272,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
if not self.tools: if not self.tools:
self.tools.update({ self.tools.update({
self.tooluid: { self.tooluid: {
'tooldia': self.options["cnctooldia"], 'tooldia': float(self.options["cnctooldia"]),
'offset': 'Path', 'offset': 'Path',
'offset_value': 0.0, 'offset_value': 0.0,
'type': 'Rough', 'type': 'Rough',
@ -2816,8 +2817,28 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.cutz_entry.setDisabled(False) self.ui.cutz_entry.setDisabled(False)
def update_cutz(self): def update_cutz(self):
vdia = float(self.ui.tipdia_entry.get_value()) try:
half_vangle = float(self.ui.tipangle_entry.get_value()) / 2 vdia = float(self.ui.tipdia_entry.get_value())
except ValueError:
# try to convert comma to decimal point. if it's still not working error message and return
try:
vdia = float(self.ui.tipdia_entry.get_value().replace(',', '.'))
except ValueError:
self.app.inform.emit("[ERROR_NOTCL]Wrong value format entered, "
"use a number.")
return
try:
half_vangle = float(self.ui.tipangle_entry.get_value()) / 2
except ValueError:
# try to convert comma to decimal point. if it's still not working error message and return
try:
half_vangle = float(self.ui.tipangle_entry.get_value().replace(',', '.')) / 2
except ValueError:
self.app.inform.emit("[ERROR_NOTCL]Wrong value format entered, "
"use a number.")
return
row = self.ui.geo_tools_table.currentRow() row = self.ui.geo_tools_table.currentRow()
tool_uid = int(self.ui.geo_tools_table.item(row, 5).text()) tool_uid = int(self.ui.geo_tools_table.item(row, 5).text())
@ -3615,36 +3636,36 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
:return: None :return: None
""" """
tooldia = tooldia if tooldia else self.options["cnctooldia"] tooldia = tooldia if tooldia else float(self.options["cnctooldia"])
outname = outname if outname is not None else self.options["name"] outname = outname if outname is not None else float(self.options["name"])
z_cut = z_cut if z_cut is not None else self.options["cutz"] z_cut = z_cut if z_cut is not None else float(self.options["cutz"])
z_move = z_move if z_move is not None else self.options["travelz"] z_move = z_move if z_move is not None else float(self.options["travelz"])
feedrate = feedrate if feedrate is not None else self.options["feedrate"] feedrate = feedrate if feedrate is not None else float(self.options["feedrate"])
feedrate_z = feedrate_z if feedrate_z is not None else self.options["feedrate_z"] feedrate_z = feedrate_z if feedrate_z is not None else float(self.options["feedrate_z"])
feedrate_rapid = feedrate_rapid if feedrate_rapid is not None else self.options["feedrate_rapid"] feedrate_rapid = feedrate_rapid if feedrate_rapid is not None else float(self.options["feedrate_rapid"])
multidepth = multidepth if multidepth is not None else self.options["multidepth"] multidepth = multidepth if multidepth is not None else self.options["multidepth"]
depthperpass = depthperpass if depthperpass is not None else self.options["depthperpass"] depthperpass = depthperpass if depthperpass is not None else float(self.options["depthperpass"])
segx = segx if segx is not None else float(self.app.defaults['geometry_segx']) segx = segx if segx is not None else float(self.app.defaults['geometry_segx'])
segy = segy if segy is not None else float(self.app.defaults['geometry_segy']) segy = segy if segy is not None else float(self.app.defaults['geometry_segy'])
extracut = extracut if extracut is not None else self.options["extracut"] extracut = extracut if extracut is not None else float(self.options["extracut"])
startz = startz if startz is not None else self.options["startz"] startz = startz if startz is not None else float(self.options["startz"])
endz = endz if endz is not None else self.options["endz"] endz = endz if endz is not None else float(self.options["endz"])
toolchangez = toolchangez if toolchangez else self.options["toolchangez"] toolchangez = toolchangez if toolchangez else float(self.options["toolchangez"])
toolchangexy = toolchangexy if toolchangexy else self.options["toolchangexy"] toolchangexy = toolchangexy if toolchangexy else self.options["toolchangexy"]
toolchange = toolchange if toolchange else self.options["toolchange"] toolchange = toolchange if toolchange else self.options["toolchange"]
offset = offset if offset else 0.0 offset = offset if offset else 0.0
# int or None. # int or None.
spindlespeed = spindlespeed if spindlespeed else self.options['spindlespeed'] spindlespeed = spindlespeed if spindlespeed else int(self.options['spindlespeed'])
dwell = dwell if dwell else self.options["dwell"] dwell = dwell if dwell else self.options["dwell"]
dwelltime = dwelltime if dwelltime else self.options["dwelltime"] dwelltime = dwelltime if dwelltime else float(self.options["dwelltime"])
ppname_g = ppname_g if ppname_g else self.options["ppname_g"] ppname_g = ppname_g if ppname_g else self.options["ppname_g"]
@ -3827,19 +3848,19 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
factor = Geometry.convert_units(self, units) factor = Geometry.convert_units(self, units)
self.options['cutz'] *= factor self.options['cutz'] = float(self.options['cutz']) * factor
self.options['depthperpass'] *= factor self.options['depthperpass'] = float(self.options['depthperpass']) * factor
self.options['travelz'] *= factor self.options['travelz'] = float(self.options['travelz']) * factor
self.options['feedrate'] *= factor self.options['feedrate'] = float(self.options['feedrate']) * factor
self.options['feedrate_z'] *= factor self.options['feedrate_z'] = float(self.options['feedrate_z']) * factor
self.options['feedrate_rapid'] *= factor self.options['feedrate_rapid'] = float(self.options['feedrate_rapid']) * factor
self.options['endz'] *= factor self.options['endz'] = float(self.options['endz']) * factor
# self.options['cnctooldia'] *= factor # self.options['cnctooldia'] *= factor
# self.options['painttooldia'] *= factor # self.options['painttooldia'] *= factor
# self.options['paintmargin'] *= factor # self.options['paintmargin'] *= factor
# self.options['paintoverlap'] *= factor # self.options['paintoverlap'] *= factor
self.options["toolchangez"] *= factor self.options["toolchangez"] = float(self.options["toolchangez"]) * factor
if self.app.defaults["geometry_toolchangexy"] == '': if self.app.defaults["geometry_toolchangexy"] == '':
self.options['toolchangexy'] = "0.0, 0.0" self.options['toolchangexy'] = "0.0, 0.0"
@ -3854,7 +3875,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.options['toolchangexy'] = "%f, %f" % (coords_xy[0], coords_xy[1]) self.options['toolchangexy'] = "%f, %f" % (coords_xy[0], coords_xy[1])
if self.options['startz'] is not None: if self.options['startz'] is not None:
self.options['startz'] *= factor self.options['startz'] = float(self.options['startz']) * factor
param_list = ['cutz', 'depthperpass', 'travelz', 'feedrate', 'feedrate_z', 'feedrate_rapid', param_list = ['cutz', 'depthperpass', 'travelz', 'feedrate', 'feedrate_z', 'feedrate_rapid',
'endz', 'toolchangez'] 'endz', 'toolchangez']
@ -4582,7 +4603,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
try: try:
if self.multitool is False: # single tool usage if self.multitool is False: # single tool usage
self.plot2(tooldia=self.options["tooldia"], obj=self, visible=visible, kind=kind) self.plot2(tooldia=float(self.options["tooldia"]), obj=self, visible=visible, kind=kind)
else: else:
# multiple tools usage # multiple tools usage
for tooluid_key in self.cnc_tools: for tooluid_key in self.cnc_tools:
@ -4597,7 +4618,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
def convert_units(self, units): def convert_units(self, units):
factor = CNCjob.convert_units(self, units) factor = CNCjob.convert_units(self, units)
FlatCAMApp.App.log.debug("FlatCAMCNCjob.convert_units()") FlatCAMApp.App.log.debug("FlatCAMCNCjob.convert_units()")
self.options["tooldia"] *= factor self.options["tooldia"] = float(self.options["tooldia"]) * factor
param_list = ['cutz', 'depthperpass', 'travelz', 'feedrate', 'feedrate_z', 'feedrate_rapid', param_list = ['cutz', 'depthperpass', 'travelz', 'feedrate', 'feedrate_z', 'feedrate_rapid',
'endz', 'toolchangez'] 'endz', 'toolchangez']

View File

@ -83,6 +83,9 @@ class FlatCAMTool(QtWidgets.QWidget):
# Put ourself in the GUI # Put ourself in the GUI
self.app.ui.tool_scroll_area.setWidget(self) self.app.ui.tool_scroll_area.setWidget(self)
# Set the tool name as the widget object name
self.app.ui.tool_scroll_area.widget().setObjectName(self.toolName)
# Switch notebook to tool page # Switch notebook to tool page
self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab) self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)

View File

@ -233,7 +233,6 @@ class FloatEntry(QtWidgets.QLineEdit):
else: else:
self.setText("") self.setText("")
def sizeHint(self): def sizeHint(self):
default_hint_size = super(FloatEntry, self).sizeHint() default_hint_size = super(FloatEntry, self).sizeHint()
return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height()) return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())
@ -351,7 +350,7 @@ class FCEntry2(FCEntry):
self.readyToEdit = True self.readyToEdit = True
def set_value(self, val): def set_value(self, val):
self.setText('%.5f' % float(val)) self.setText('%.4f' % float(val))
class EvalEntry(QtWidgets.QLineEdit): class EvalEntry(QtWidgets.QLineEdit):
@ -474,6 +473,7 @@ class FCTextAreaRich(QtWidgets.QTextEdit):
default_hint_size = super(FCTextAreaRich, self).sizeHint() default_hint_size = super(FCTextAreaRich, self).sizeHint()
return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height()) return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())
class FCComboBox(QtWidgets.QComboBox): class FCComboBox(QtWidgets.QComboBox):
def __init__(self, parent=None): def __init__(self, parent=None):
super(FCComboBox, self).__init__(parent) super(FCComboBox, self).__init__(parent)
@ -494,6 +494,10 @@ class FCInputDialog(QtWidgets.QInputDialog):
super(FCInputDialog, self).__init__(parent) super(FCInputDialog, self).__init__(parent)
self.allow_empty = ok self.allow_empty = ok
self.empty_val = val self.empty_val = val
self.val = 0.0
self.ok = ''
if title is None: if title is None:
self.title = 'title' self.title = 'title'
else: else:
@ -515,9 +519,8 @@ class FCInputDialog(QtWidgets.QInputDialog):
else: else:
self.decimals = decimals self.decimals = decimals
def get_value(self): def get_value(self):
self.val,self.ok = self.getDouble(self, self.title, self.text, min=self.min, self.val, self.ok = self.getDouble(self, self.title, self.text, min=self.min,
max=self.max, decimals=self.decimals) max=self.max, decimals=self.decimals)
return [self.val, self.ok] return [self.val, self.ok]

View File

@ -783,7 +783,8 @@ class GeometryObjectUI(ObjectUI):
"cut and negative for 'inside' cut." "cut and negative for 'inside' cut."
) )
self.grid1.addWidget(self.tool_offset_lbl, 0, 0) self.grid1.addWidget(self.tool_offset_lbl, 0, 0)
self.tool_offset_entry = FCEntry() self.tool_offset_entry = FloatEntry()
self.tool_offset_entry.setValidator(QtGui.QDoubleValidator(-9999.9999, 9999.9999, 4))
spacer_lbl = QtWidgets.QLabel(" ") spacer_lbl = QtWidgets.QLabel(" ")
spacer_lbl.setFixedWidth(80) spacer_lbl.setFixedWidth(80)

View File

@ -16,6 +16,13 @@ CAD program, and create G-Code for Isolation routing.
- fixed errors in Toggle Axis - fixed errors in Toggle Axis
- fixed error with shortcut key triggering twice the keyPressEvent when in the Project List View - fixed error with shortcut key triggering twice the keyPressEvent when in the Project List View
- moved all shortcut keys handlers from Editors to the keyPressEvent() handler from FLatCAMGUI - moved all shortcut keys handlers from Editors to the keyPressEvent() handler from FLatCAMGUI
- 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'
- 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
7.02.2019 7.02.2019

101
camlib.py
View File

@ -4939,25 +4939,25 @@ class CNCjob(Geometry):
flat_geometry = self.flatten(temp_solid_geometry, pathonly=True) flat_geometry = self.flatten(temp_solid_geometry, pathonly=True)
log.debug("%d paths" % len(flat_geometry)) log.debug("%d paths" % len(flat_geometry))
self.tooldia = tooldia self.tooldia = float(tooldia) if tooldia else None
self.z_cut = z_cut self.z_cut = float(z_cut) if z_cut else None
self.z_move = z_move self.z_move = float(z_move) if z_move else None
self.feedrate = feedrate self.feedrate = float(feedrate) if feedrate else None
self.feedrate_z = feedrate_z self.feedrate_z = float(feedrate_z) if feedrate_z else None
self.feedrate_rapid = feedrate_rapid self.feedrate_rapid = float(feedrate_rapid) if feedrate_rapid else None
self.spindlespeed = spindlespeed self.spindlespeed = int(spindlespeed) if spindlespeed else None
self.dwell = dwell self.dwell = dwell
self.dwelltime = dwelltime self.dwelltime = float(dwelltime) if dwelltime else None
self.startz = startz self.startz = float(startz) if startz else None
self.endz = endz self.endz = float(endz) if endz else None
self.depthpercut = depthpercut self.depthpercut = float(depthpercut) if depthpercut else None
self.multidepth = multidepth self.multidepth = multidepth
self.toolchangez = toolchangez self.toolchangez = float(toolchangez) if toolchangez else None
try: try:
if toolchangexy == '': if toolchangexy == '':
@ -5120,14 +5120,57 @@ class CNCjob(Geometry):
"from a Geometry object without solid_geometry.") "from a Geometry object without solid_geometry.")
temp_solid_geometry = [] temp_solid_geometry = []
def bounds_rec(obj):
if type(obj) is list:
minx = Inf
miny = Inf
maxx = -Inf
maxy = -Inf
for k in obj:
if type(k) is dict:
for key in k:
minx_, miny_, maxx_, maxy_ = bounds_rec(k[key])
minx = min(minx, minx_)
miny = min(miny, miny_)
maxx = max(maxx, maxx_)
maxy = max(maxy, maxy_)
else:
minx_, miny_, maxx_, maxy_ = bounds_rec(k)
minx = min(minx, minx_)
miny = min(miny, miny_)
maxx = max(maxx, maxx_)
maxy = max(maxy, maxy_)
return minx, miny, maxx, maxy
else:
# it's a Shapely object, return it's bounds
return obj.bounds
if offset != 0.0: if offset != 0.0:
offset_for_use = offset
if offset <0:
a, b, c, d = bounds_rec(geometry.solid_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]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
elif -offset == ((c - a) / 2) or -offset == ((d - b) / 2):
offset_for_use = offset - 0.0000000001
for it in geometry.solid_geometry: for it in geometry.solid_geometry:
# if the geometry is a closed shape then create a Polygon out of it # if the geometry is a closed shape then create a Polygon out of it
if isinstance(it, LineString): if isinstance(it, LineString):
c = it.coords c = it.coords
if c[0] == c[-1]: if c[0] == c[-1]:
it = Polygon(it) it = Polygon(it)
temp_solid_geometry.append(it.buffer(offset, join_style=2)) temp_solid_geometry.append(it.buffer(offset_for_use, join_style=2))
else: else:
temp_solid_geometry = geometry.solid_geometry temp_solid_geometry = geometry.solid_geometry
@ -5135,25 +5178,33 @@ class CNCjob(Geometry):
flat_geometry = self.flatten(temp_solid_geometry, pathonly=True) flat_geometry = self.flatten(temp_solid_geometry, pathonly=True)
log.debug("%d paths" % len(flat_geometry)) log.debug("%d paths" % len(flat_geometry))
self.tooldia = tooldia self.tooldia = float(tooldia) if tooldia else None
self.z_cut = z_cut
self.z_move = z_move
self.feedrate = feedrate self.z_cut = float(z_cut) if z_cut else None
self.feedrate_z = feedrate_z
self.feedrate_rapid = feedrate_rapid self.z_move = float(z_move) if z_move else None
self.feedrate = float(feedrate) if feedrate else None
self.feedrate_z = float(feedrate_z) if feedrate_z else None
self.feedrate_rapid = float(feedrate_rapid) if feedrate_rapid else None
self.spindlespeed = int(spindlespeed) if spindlespeed else None
self.spindlespeed = spindlespeed
self.dwell = dwell self.dwell = dwell
self.dwelltime = dwelltime
self.startz = startz self.dwelltime = float(dwelltime) if dwelltime else None
self.endz = endz
self.startz = float(startz) if startz else None
self.endz = float(endz) if endz else None
self.depthpercut = float(depthpercut) if depthpercut else None
self.depthpercut = depthpercut
self.multidepth = multidepth self.multidepth = multidepth
self.toolchangez = toolchangez self.toolchangez = float(toolchangez) if toolchangez else None
try: try:
if toolchangexy == '': if toolchangexy == '':

View File

@ -5,6 +5,7 @@ from copy import copy,deepcopy
from ObjectCollection import * from ObjectCollection import *
import time import time
class NonCopperClear(FlatCAMTool, Gerber): class NonCopperClear(FlatCAMTool, Gerber):
toolName = "Non-Copper Clearing" toolName = "Non-Copper Clearing"

BIN
share/letter_t_32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B