diff --git a/CHANGELOG.md b/CHANGELOG.md
index d98e5336..38450de8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,7 @@ CHANGELOG for FlatCAM beta
- minimized the number of tools present in the Tools Toolbar to the bare minimum
- fixed an error in the Follow Tool
- started to work in Milling Tool - designing the Tool UI
+- Milling Tool - finished the UI and also the button handlers in the Geometry and Excellon objects Properties UI
12.11.2020
diff --git a/appGUI/ObjectUI.py b/appGUI/ObjectUI.py
index d645e30b..813f55d5 100644
--- a/appGUI/ObjectUI.py
+++ b/appGUI/ObjectUI.py
@@ -755,8 +755,6 @@ class ExcellonObjectUI(ObjectUI):
# }
# """)
grid2.addWidget(self.milling_button, 6, 0, 1, 2)
- # TODO until the Milling Tool is finished this stays disabled
- self.milling_button.setDisabled(True)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
@@ -1810,8 +1808,6 @@ class GeometryObjectUI(ObjectUI):
}
""")
self.grid4.addWidget(self.milling_button, 34, 0, 1, 2)
- # FIXME: until the Milling Tool is ready, this get disabled
- self.milling_button.setDisabled(True)
# Paint Button
self.paint_tool_button = FCButton(_('Paint Tool'))
diff --git a/appObjects/FlatCAMExcellon.py b/appObjects/FlatCAMExcellon.py
index c036c731..955b5998 100644
--- a/appObjects/FlatCAMExcellon.py
+++ b/appObjects/FlatCAMExcellon.py
@@ -181,8 +181,7 @@ class ExcellonObject(FlatCAMObj, Excellon):
self.calculations_finished.connect(self.update_area_chull)
self.ui.drill_button.clicked.connect(lambda: self.app.drilling_tool.run(toggle=True))
- # FIXME will uncomment when Milling Tool is ready
- # self.ui.milling_button.clicked.connect(lambda: self.app.milling_tool.run(toggle=True))
+ self.ui.milling_button.clicked.connect(self.on_milling_button_clicked)
# UTILITIES
self.ui.util_button.clicked.connect(lambda st: self.ui.util_frame.show() if st else self.ui.util_frame.hide())
@@ -632,6 +631,12 @@ class ExcellonObject(FlatCAMObj, Excellon):
# make sure that the FCTree widget columns are resized to content
self.ui.treeWidget.resize_sig.emit()
+ def on_milling_button_clicked(self):
+ self.app.milling_tool.run(toggle=False)
+ self.app.milling_tool.ui.target_radio.set_value('exc')
+ current_obj = self.app.collection.get_active()
+ self.app.milling_tool.ui.object_combo.set_value(current_obj.options['name'])
+
def export_excellon(self, whole, fract, e_zeros=None, form='dec', factor=1, slot_type='routing'):
"""
Returns two values, first is a boolean , if 1 then the file has slots and second contain the Excellon code
diff --git a/appObjects/FlatCAMGeometry.py b/appObjects/FlatCAMGeometry.py
index d2483f7c..4e186108 100644
--- a/appObjects/FlatCAMGeometry.py
+++ b/appObjects/FlatCAMGeometry.py
@@ -657,6 +657,7 @@ class GeometryObject(FlatCAMObj, Geometry):
self.ui.generate_cnc_button.clicked.connect(self.on_generatecnc_button_click)
self.ui.paint_tool_button.clicked.connect(lambda: self.app.paint_tool.run(toggle=False))
self.ui.generate_ncc_button.clicked.connect(lambda: self.app.ncclear_tool.run(toggle=False))
+ self.ui.milling_button.clicked.connect(self.on_milling_button_clicked)
# Postprocessor change
self.ui.pp_geometry_name_cb.activated.connect(self.on_pp_changed)
@@ -698,6 +699,12 @@ class GeometryObject(FlatCAMObj, Geometry):
# make sure that the FCTree widget columns are resized to content
self.ui.treeWidget.resize_sig.emit()
+ def on_milling_button_clicked(self):
+ self.app.milling_tool.run(toggle=False)
+ self.app.milling_tool.ui.target_radio.set_value('geo')
+ current_obj = self.app.collection.get_active()
+ self.app.milling_tool.ui.object_combo.set_value(current_obj.options['name'])
+
def on_rebuild_ui(self):
# read the table tools uid
current_uid_list = []
diff --git a/appTools/ToolMilling.py b/appTools/ToolMilling.py
index d2ec3b4e..c1be0a0e 100644
--- a/appTools/ToolMilling.py
+++ b/appTools/ToolMilling.py
@@ -8,12 +8,13 @@
from PyQt5 import QtWidgets, QtCore, QtGui
from appTool import AppTool
-from appGUI.GUIElements import FCCheckBox, FCDoubleSpinner, RadioSet, FCTable, FCButton, \
+from appGUI.GUIElements import FCCheckBox, FCDoubleSpinner, RadioSet, FCTable, FCButton, FCComboBox2, \
FCComboBox, OptionalInputSection, FCSpinner, NumericalEvalEntry, OptionalHideInputSection, FCLabel
from appParsers.ParseExcellon import Excellon
from copy import deepcopy
+from appObjects.FlatCAMObj import FlatCAMObj
# import numpy as np
# import math
@@ -129,7 +130,7 @@ class ToolMilling(AppTool, Excellon):
self.connect_signals_at_init()
def install(self, icon=None, separator=None, **kwargs):
- AppTool.install(self, icon, separator, shortcut='Alt+D', **kwargs)
+ AppTool.install(self, icon, separator, shortcut='Alt+B', **kwargs)
def run(self, toggle=True):
self.app.defaults.report_usage("ToolMilling()")
@@ -174,6 +175,8 @@ class ToolMilling(AppTool, Excellon):
# #############################################################################
self.ui.target_radio.activated_custom.connect(self.on_target_changed)
+ self.ui.operation_type_combo.currentIndexChanged.connect(self.on_operation_changed)
+ self.ui.offset_type_combo.currentIndexChanged.connect(self.on_offset_type_changed)
self.ui.apply_param_to_all.clicked.connect(self.on_apply_param_to_all_clicked)
self.ui.generate_cnc_button.clicked.connect(self.on_cnc_button_click)
@@ -373,6 +376,8 @@ class ToolMilling(AppTool, Excellon):
pass
self.ui.object_combo.currentIndexChanged.connect(self.on_object_changed)
+ self.ui.offset_type_combo.set_value(0) # 'Path'
+
def rebuild_ui(self):
# read the table tools uid
current_uid_list = []
@@ -395,6 +400,16 @@ class ToolMilling(AppTool, Excellon):
def build_ui(self):
self.ui_disconnect()
+ # load the Milling object
+ self.obj_name = self.ui.object_combo.currentText()
+
+ # Get source object.
+ try:
+ self.target_obj = self.app.collection.get_by_name(self.obj_name)
+ except Exception:
+ self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), str(self.obj_name)))
+ return
+
if self.ui.target_radio.get_value() == 'geo':
self.build_ui_mill()
else:
@@ -465,7 +480,134 @@ class ToolMilling(AppTool, Excellon):
)
def build_ui_mill(self):
- pass
+ self.ui_disconnect()
+
+ # Area Exception - exclusion shape added signal
+ # first disconnect it from any other object
+ try:
+ self.app.exc_areas.e_shape_modified.disconnect()
+ except (TypeError, AttributeError):
+ pass
+ # then connect it to the current build_ui() method
+ self.app.exc_areas.e_shape_modified.connect(self.update_exclusion_table)
+
+ self.units = self.app.defaults['units']
+
+ row_idx = 0
+
+ n = len(self.target_obj.tools)
+ self.ui.geo_tools_table.setRowCount(n)
+
+ for tooluid_key, tooluid_value in self.target_obj.tools.items():
+
+ # -------------------- ID ------------------------------------------ #
+ tool_id = QtWidgets.QTableWidgetItem('%d' % int(row_idx + 1))
+ tool_id.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
+ self.ui.geo_tools_table.setItem(row_idx, 0, tool_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 3 decimals diameter.
+ # For INCH the decimals should be no more than 3. There are no tools under 10mils.
+
+ # -------------------- DIAMETER ------------------------------------- #
+ dia_item = QtWidgets.QTableWidgetItem('%.*f' % (self.decimals, float(tooluid_value['tooldia'])))
+ dia_item.setFlags(QtCore.Qt.ItemIsEnabled)
+ self.ui.geo_tools_table.setItem(row_idx, 1, dia_item) # Diameter
+
+ # -------------------- TOOL TYPE ------------------------------------- #
+ tool_type_item = FCComboBox(policy=False)
+ for item in ["C1", "C2", "C3", "C4", "B", "V"]:
+ tool_type_item.addItem(item)
+ idx = tool_type_item.findText(tooluid_value['tool_type'])
+ # protection against having this translated or loading a project with translated values
+ if idx == -1:
+ tool_type_item.setCurrentIndex(0)
+ else:
+ tool_type_item.setCurrentIndex(idx)
+ self.ui.geo_tools_table.setCellWidget(row_idx, 2, tool_type_item)
+
+ # -------------------- TOOL UID ------------------------------------- #
+ tool_uid_item = QtWidgets.QTableWidgetItem(str(tooluid_key))
+ # ## REMEMBER: THIS COLUMN IS HIDDEN IN OBJECTUI.PY ###
+ self.ui.geo_tools_table.setItem(row_idx, 3, tool_uid_item) # Tool unique ID
+
+ # -------------------- PLOT ------------------------------------- #
+ empty_plot_item = QtWidgets.QTableWidgetItem('')
+ empty_plot_item.setFlags(~QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
+ self.ui.geo_tools_table.setItem(row_idx, 4, empty_plot_item)
+ plot_item = FCCheckBox()
+ plot_item.setLayoutDirection(QtCore.Qt.RightToLeft)
+ if self.ui.plot_cb.isChecked():
+ plot_item.setChecked(True)
+ self.ui.geo_tools_table.setCellWidget(row_idx, 4, plot_item)
+
+ row_idx += 1
+
+ # make the diameter column editable
+ for row in range(row_idx):
+ self.ui.geo_tools_table.item(row, 1).setFlags(QtCore.Qt.ItemIsSelectable |
+ QtCore.Qt.ItemIsEditable |
+ QtCore.Qt.ItemIsEnabled)
+
+ # sort the tool diameter column
+ # self.ui.geo_tools_table.sortItems(1)
+ # all the tools are selected by default
+ # self.ui.geo_tools_table.selectColumn(0)
+
+ self.ui.geo_tools_table.resizeColumnsToContents()
+ self.ui.geo_tools_table.resizeRowsToContents()
+
+ vertical_header = self.ui.geo_tools_table.verticalHeader()
+ # vertical_header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
+ vertical_header.hide()
+ self.ui.geo_tools_table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+
+ horizontal_header = self.ui.geo_tools_table.horizontalHeader()
+ horizontal_header.setMinimumSectionSize(10)
+ horizontal_header.setDefaultSectionSize(70)
+ horizontal_header.setSectionResizeMode(0, QtWidgets.QHeaderView.Fixed)
+ horizontal_header.resizeSection(0, 20)
+ horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
+ horizontal_header.setSectionResizeMode(2, QtWidgets.QHeaderView.Fixed)
+ horizontal_header.resizeSection(2, 40)
+ horizontal_header.setSectionResizeMode(4, QtWidgets.QHeaderView.Fixed)
+ horizontal_header.resizeSection(4, 17)
+ # horizontal_header.setStretchLastSection(True)
+ self.ui.geo_tools_table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+
+ self.ui.geo_tools_table.setColumnWidth(0, 20)
+ self.ui.geo_tools_table.setColumnWidth(2, 40)
+ self.ui.geo_tools_table.setColumnWidth(4, 17)
+
+ # self.ui.geo_tools_table.setSortingEnabled(True)
+
+ self.ui.geo_tools_table.setMinimumHeight(self.ui.geo_tools_table.getHeight())
+ self.ui.geo_tools_table.setMaximumHeight(self.ui.geo_tools_table.getHeight())
+
+ # update UI for all rows - useful after units conversion but only if there is at least one row
+ # row_cnt = self.ui.geo_tools_table.rowCount()
+ # if row_cnt > 0:
+ # for r in range(row_cnt):
+ # self.update_ui(r)
+
+ # select only the first tool / row
+ # selected_row = 0
+ # try:
+ # self.select_tools_table_row(selected_row, clearsel=True)
+ # # update the Geometry UI
+ # self.update_ui()
+ # except Exception as e:
+ # # when the tools table is empty there will be this error but once the table is populated it will go away
+ # log.debug(str(e))
+
+ # disable the Plot column in Tool Table if the geometry is SingleGeo as it is not needed
+ # and can create some problems
+ if self.target_obj.multigeo is False:
+ self.ui.geo_tools_table.setColumnHidden(4, True)
+ else:
+ self.ui.geo_tools_table.setColumnHidden(4, False)
+
+ self.ui_connect()
def build_ui_exc(self):
self.ui_disconnect()
@@ -473,15 +615,6 @@ class ToolMilling(AppTool, Excellon):
# updated units
self.units = self.app.defaults['units'].upper()
- self.obj_name = self.ui.object_combo.currentText()
-
- # Get source object.
- try:
- self.target_obj = self.app.collection.get_by_name(self.obj_name)
- except Exception as e:
- self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), str(self.obj_name)))
- return "Could not retrieve object: %s with error: %s" % (self.obj_name, str(e))
-
if self.target_obj:
self.ui.param_frame.setDisabled(False)
@@ -632,8 +765,53 @@ class ToolMilling(AppTool, Excellon):
"exc": "Excellon", "geo": "Geometry"
}[val]
+ if val == 'exc':
+ self.ui.tools_table.show()
+ self.ui.order_label.show()
+ self.ui.order_radio.show()
+
+ self.ui.geo_tools_table.hide()
+
+ self.ui.mill_type_label.show()
+ self.ui.milling_type_radio.show()
+ self.ui.mill_dia_label.show()
+ self.ui.mill_dia_entry.show()
+
+ self.ui.frxylabel.hide()
+ self.ui.xyfeedrate_entry.hide()
+ self.ui.extracut_cb.hide()
+ self.ui.e_cut_entry.hide()
+
+ self.ui.operation_type_lbl.hide()
+ self.ui.operation_type_combo.hide()
+ self.ui.operation_type_combo.set_value(0) # 'iso' - will hide the Polish UI elements
+
+ self.ui.add_tool_frame.hide()
+ else:
+ self.ui.tools_table.hide()
+ self.ui.order_label.hide()
+ self.ui.order_radio.hide()
+
+ self.ui.geo_tools_table.show()
+
+ self.ui.mill_type_label.hide()
+ self.ui.milling_type_radio.hide()
+ self.ui.mill_dia_label.hide()
+ self.ui.mill_dia_entry.hide()
+
+ self.ui.frxylabel.show()
+ self.ui.xyfeedrate_entry.show()
+ self.ui.extracut_cb.show()
+ self.ui.e_cut_entry.show()
+
+ self.ui.operation_type_lbl.show()
+ self.ui.operation_type_combo.show()
+ # self.ui.operation_type_combo.set_value(self.app.defaults["tools_mill_operation_val"])
+
+ self.ui.add_tool_frame.show()
+
def on_object_changed(self):
- # load the Excellon object
+ # load the Milling object
self.obj_name = self.ui.object_combo.currentText()
# Get source object.
@@ -651,6 +829,35 @@ class ToolMilling(AppTool, Excellon):
self.build_ui()
+ def on_operation_changed(self, idx):
+ if self.ui.target_radio.get_value() == 'geo':
+ if idx == 3: # 'Polish'
+ self.ui.polish_margin_lbl.show()
+ self.ui.polish_margin_entry.show()
+ self.ui.polish_over_lbl.show()
+ self.ui.polish_over_entry.show()
+ self.ui.polish_method_lbl.show()
+ self.ui.polish_method_combo.show()
+
+ self.ui.cutzlabel.setText('%s:' % _("Pressure"))
+ else:
+ self.ui.polish_margin_lbl.hide()
+ self.ui.polish_margin_entry.hide()
+ self.ui.polish_over_lbl.hide()
+ self.ui.polish_over_entry.hide()
+ self.ui.polish_method_lbl.hide()
+ self.ui.polish_method_combo.hide()
+
+ self.ui.cutzlabel.setText('%s:' % _('Cut Z'))
+
+ def on_offset_type_changed(self, idx):
+ if idx == 3: # 'Custom'
+ self.ui.offset_label.show()
+ self.ui.offset_entry.show()
+ else:
+ self.ui.offset_label.hide()
+ self.ui.offset_entry.hide()
+
def ui_connect(self):
# Area Exception - exclusion shape added signal
@@ -1248,12 +1455,6 @@ class ToolMilling(AppTool, Excellon):
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()
@@ -1281,12 +1482,6 @@ class ToolMilling(AppTool, Excellon):
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_cnc_button_click(self):
self.obj_name = self.ui.object_combo.currentText()
@@ -1574,7 +1769,7 @@ class MillingUI:
self.tools_box.addLayout(self.title_box)
# ## Title
- title_label = QtWidgets.QLabel("%s" % self.toolName)
+ title_label = FCLabel("%s" % self.toolName)
title_label.setStyleSheet("""
QLabel
{
@@ -1589,7 +1784,7 @@ class MillingUI:
self.title_box.addWidget(title_label)
# App Level label
- self.level = QtWidgets.QLabel("")
+ self.level = FCLabel("")
self.level.setToolTip(
_(
"BASIC is suitable for a beginner. Many parameters\n"
@@ -1609,7 +1804,7 @@ class MillingUI:
grid0.setColumnStretch(1, 1)
self.tools_box.addLayout(grid0)
- self.target_label = QtWidgets.QLabel('%s:' % _("Target"))
+ self.target_label = FCLabel('%s:' % _("Target"))
self.target_label.setToolTip(
_("Object for milling operation.")
)
@@ -1632,18 +1827,31 @@ class MillingUI:
# self.object_combo.setCurrentIndex(1)
self.object_combo.is_last = True
- grid0.addWidget(self.object_combo, 1, 0, 1, 2)
+ grid0.addWidget(self.object_combo, 2, 0, 1, 2)
- separator_line = QtWidgets.QFrame()
- separator_line.setFrameShape(QtWidgets.QFrame.HLine)
- separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
- grid0.addWidget(separator_line, 2, 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)
+
+ # ### Tools ####
+ self.tools_table_label = FCLabel('%s:' % _('Tools Table'))
+ self.tools_table_label.setToolTip(
+ _("Tools in the object used for milling.")
+ )
+ grid0.addWidget(self.tools_table_label, 6, 0)
+
+ # Plot CB
+ self.plot_cb = FCCheckBox(_('Plot Object'))
+ self.plot_cb.setToolTip(_("Plot (show) this object."))
+ self.plot_cb.setLayoutDirection(QtCore.Qt.RightToLeft)
+ grid0.addWidget(self.plot_cb, 6, 1)
# ################################################
# ########## Excellon Tool Table #################
# ################################################
self.tools_table = FCTable(drag_drop=True)
- grid0.addWidget(self.tools_table, 3, 0, 1, 2)
+ grid0.addWidget(self.tools_table, 8, 0, 1, 2)
self.tools_table.setColumnCount(5)
self.tools_table.setColumnHidden(3, True)
@@ -1666,7 +1874,7 @@ class MillingUI:
"milling them with an endmill bit."))
# Tool order
- self.order_label = QtWidgets.QLabel('%s:' % _('Tool order'))
+ self.order_label = FCLabel('%s:' % _('Tool order'))
self.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"
@@ -1678,18 +1886,131 @@ class MillingUI:
{'label': _('Forward'), 'value': 'fwd'},
{'label': _('Reverse'), 'value': 'rev'}])
- grid0.addWidget(self.order_label, 4, 0)
- grid0.addWidget(self.order_radio, 4, 1)
+ grid0.addWidget(self.order_label, 10, 0)
+ grid0.addWidget(self.order_radio, 10, 1)
+
+ # ************************************************************************
+ # ************** Geometry Tool Table *************************************
+ # ************************************************************************
+
+ # Tool Table for Geometry
+ self.geo_tools_table = FCTable(drag_drop=True)
+ self.geo_tools_table.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
+
+ grid0.addWidget(self.geo_tools_table, 12, 0, 1, 2)
+
+ self.geo_tools_table.setColumnCount(5)
+ self.geo_tools_table.setColumnWidth(0, 20)
+ self.geo_tools_table.setHorizontalHeaderLabels(['#', _('Dia'), _('TT'), '', 'P'])
+ self.geo_tools_table.setColumnHidden(3, True)
+
+ self.geo_tools_table.horizontalHeaderItem(0).setToolTip(
+ _(
+ "This is the Tool Number.\n"
+ "When ToolChange is checked, on toolchange event this value\n"
+ "will be showed as a T1, T2 ... Tn")
+ )
+ self.geo_tools_table.horizontalHeaderItem(1).setToolTip(
+ _("Tool Diameter. Its value\n"
+ "is the cut width into the material."))
+ self.geo_tools_table.horizontalHeaderItem(2).setToolTip(
+ _(
+ "The Tool Type (TT) can be:\n"
+ "- Circular with 1 ... 4 teeth -> it is informative only. Being circular the cut width in material\n"
+ "is exactly the tool diameter.\n"
+ "- Ball -> informative only and make reference to the Ball type endmill.\n"
+ "- V-Shape -> it will disable Z-Cut parameter in the UI form and enable two additional UI form\n"
+ "fields: V-Tip Dia and V-Tip Angle. Adjusting those two values will adjust the Z-Cut parameter such\n"
+ "as the cut width into material will be equal with the value in the Tool "
+ "Diameter column of this table."
+ ))
+ self.geo_tools_table.horizontalHeaderItem(4).setToolTip(
+ _(
+ "Plot column. It is visible only for MultiGeo geometries, meaning geometries that holds the geometry\n"
+ "data into the tools. For those geometries, deleting the tool will delete the geometry data also,\n"
+ "so be WARNED. From the checkboxes on each row it can be enabled/disabled the plot on canvas\n"
+ "for the corresponding tool."
+ ))
+
+ # Hide the Tools Table on start
+ self.tools_table.hide()
+ self.geo_tools_table.hide()
+ self.order_label.hide()
+ self.order_radio.hide()
+
+ # ADD TOOLS FOR GEOMETRY OBJECT
+ self.add_tool_frame = QtWidgets.QFrame()
+ self.add_tool_frame.setContentsMargins(0, 0, 0, 0)
+ grid0.addWidget(self.add_tool_frame, 14, 0, 1, 2)
+ grid_tool = QtWidgets.QGridLayout()
+ grid_tool.setColumnStretch(0, 0)
+ grid_tool.setColumnStretch(1, 1)
+ grid_tool.setContentsMargins(0, 0, 0, 0)
+ self.add_tool_frame.setLayout(grid_tool)
+
+ self.tool_sel_label = FCLabel('%s' % _("Add from DB"))
+ grid_tool.addWidget(self.tool_sel_label, 2, 0, 1, 2)
+
+ self.addtool_entry_lbl = FCLabel('%s:' % _('Tool Dia'))
+ self.addtool_entry_lbl.setToolTip(
+ _("Diameter for the new tool")
+ )
+ self.addtool_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.addtool_entry.set_precision(self.decimals)
+ self.addtool_entry.set_range(0.00001, 10000.0000)
+ self.addtool_entry.setSingleStep(0.1)
+
+ grid_tool.addWidget(self.addtool_entry_lbl, 3, 0)
+ grid_tool.addWidget(self.addtool_entry, 3, 1)
+
+ bhlay = QtWidgets.QHBoxLayout()
+
+ self.search_and_add_btn = FCButton(_('Search and Add'))
+ self.search_and_add_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/plus16.png'))
+ self.search_and_add_btn.setToolTip(
+ _("Add a new tool to the Tool Table\n"
+ "with the diameter specified above.")
+ )
+
+ self.addtool_from_db_btn = FCButton(_('Pick from DB'))
+ self.addtool_from_db_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/search_db32.png'))
+ self.addtool_from_db_btn.setToolTip(
+ _("Add a new tool to the Tool Table\n"
+ "from the Tools Database.\n"
+ "Tools database administration in in:\n"
+ "Menu: Options -> Tools Database")
+ )
+
+ bhlay.addWidget(self.search_and_add_btn)
+ bhlay.addWidget(self.addtool_from_db_btn)
+
+ grid_tool.addLayout(bhlay, 5, 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)
+ grid_tool.addWidget(separator_line, 9, 0, 1, 2)
+
+ self.deltool_btn = FCButton(_('Delete'))
+ self.deltool_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/trash16.png'))
+ self.deltool_btn.setToolTip(
+ _("Delete a selection of tools in the Tool Table\n"
+ "by first selecting a row in the Tool Table.")
+ )
+
+ grid_tool.addWidget(self.deltool_btn, 12, 0, 1, 2)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ grid0.addWidget(separator_line, 15, 0, 1, 2)
+
+ self.add_tool_frame.hide()
# ###########################################################
# ############# Create CNC Job ##############################
# ###########################################################
- self.tool_data_label = QtWidgets.QLabel(
+ self.tool_data_label = FCLabel(
"%s: %s %d" % (_('Parameters for'), _("Tool"), int(1)))
self.tool_data_label.setToolTip(
_(
@@ -1697,11 +2018,11 @@ class MillingUI:
"Each tool store it's own set of such data."
)
)
- grid0.addWidget(self.tool_data_label, 6, 0, 1, 2)
+ grid0.addWidget(self.tool_data_label, 16, 0, 1, 2)
self.param_frame = QtWidgets.QFrame()
self.param_frame.setContentsMargins(0, 0, 0, 0)
- grid0.addWidget(self.param_frame, 7, 0, 1, 2)
+ grid0.addWidget(self.param_frame, 18, 0, 1, 2)
self.exc_tools_box = QtWidgets.QVBoxLayout()
self.exc_tools_box.setContentsMargins(0, 0, 0, 0)
@@ -1721,7 +2042,8 @@ class MillingUI:
# separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
# self.grid3.addWidget(separator_line, 1, 0, 1, 2)
- self.mill_type_label = QtWidgets.QLabel('%s:' % _('Milling Type'))
+ # Milling Type
+ self.mill_type_label = FCLabel('%s:' % _('Milling Type'))
self.mill_type_label.setToolTip(
_("Milling type:\n"
"- Drills -> will mill the drills associated with this tool\n"
@@ -1737,10 +2059,11 @@ class MillingUI:
)
self.milling_type_radio.setObjectName("milling_type")
- self.grid1.addWidget(self.mill_type_label, 2, 0)
- self.grid1.addWidget(self.milling_type_radio, 2, 1)
+ self.grid1.addWidget(self.mill_type_label, 0, 0)
+ self.grid1.addWidget(self.milling_type_radio, 0, 1)
- self.mill_dia_label = QtWidgets.QLabel('%s:' % _('Milling Diameter'))
+ # Milling Diameter
+ self.mill_dia_label = FCLabel('%s:' % _('Milling Diameter'))
self.mill_dia_label.setToolTip(
_("The diameter of the tool who will do the milling")
)
@@ -1750,11 +2073,140 @@ class MillingUI:
self.mill_dia_entry.set_range(0.0000, 10000.0000)
self.mill_dia_entry.setObjectName("milling_dia")
- self.grid1.addWidget(self.mill_dia_label, 3, 0)
- self.grid1.addWidget(self.mill_dia_entry, 3, 1)
+ self.grid1.addWidget(self.mill_dia_label, 2, 0)
+ self.grid1.addWidget(self.mill_dia_entry, 2, 1)
+
+ self.mill_type_label.hide()
+ self.milling_type_radio.hide()
+ self.mill_dia_label.hide()
+ self.mill_dia_entry.hide()
+
+ # Offset Type
+ self.offset_type_lbl = FCLabel('%s:' % _('Offset Type'))
+ self.offset_type_lbl.setToolTip(
+ _(
+ "The value for the Offset can be:\n"
+ "- Path -> There is no offset, the tool cut will be done through the geometry line.\n"
+ "- In(side) -> The tool cut will follow the geometry inside. It will create a 'pocket'.\n"
+ "- Out(side) -> The tool cut will follow the geometry line on the outside.\n"
+ "- Custom -> The tool will cut at an chosen offset."
+ ))
+
+ self.offset_type_combo = FCComboBox2()
+ self.offset_type_combo.addItems(
+ ["Path", "In", "Out", "Custom"]
+ )
+ self.offset_type_combo.setObjectName('mill_offset_type')
+
+ self.grid1.addWidget(self.offset_type_lbl, 4, 0)
+ self.grid1.addWidget(self.offset_type_combo, 4, 1)
+
+ # Tool Offset
+ self.offset_label = FCLabel('%s:' % _('Custom'))
+ self.offset_label.setToolTip(
+ _(
+ "The value to offset the cut when \n"
+ "the Offset type selected is 'Custom'.\n"
+ "The value can be positive for 'outside'\n"
+ "cut and negative for 'inside' cut."
+ )
+ )
+
+ self.offset_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.offset_entry.set_precision(self.decimals)
+ self.offset_entry.set_range(-10000.0000, 10000.0000)
+ self.offset_entry.setObjectName("mill_offset")
+
+ self.offset_label.hide()
+ self.offset_entry.hide()
+
+ self.grid1.addWidget(self.offset_label, 6, 0)
+ self.grid1.addWidget(self.offset_entry, 6, 1)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.grid1.addWidget(separator_line, 8, 0, 1, 2)
+
+ # Operation Type
+ self.operation_type_lbl = FCLabel('%s:' % _('Operation'))
+ self.operation_type_lbl.setToolTip(
+ _(
+ "- Isolation -> informative - lower Feedrate as it uses a milling bit with a fine tip.\n"
+ "- Roughing -> informative - lower Feedrate and multiDepth cut.\n"
+ "- Finishing -> infrmative - higher Feedrate, without multiDepth.\n"
+ "- Polish -> adds a painting sequence over the whole area of the object"
+ ))
+
+ self.operation_type_combo = FCComboBox2()
+ self.operation_type_combo.addItems(
+ ['Iso', 'Rough', 'Finish', 'Polish']
+ )
+ self.operation_type_combo.setObjectName('mill_operation_type')
+
+ self.grid1.addWidget(self.operation_type_lbl, 10, 0)
+ self.grid1.addWidget(self.operation_type_combo, 10, 1)
+
+ # Polish Margin
+ self.polish_margin_lbl = FCLabel('%s:' % _('Margin'))
+ self.polish_margin_lbl.setToolTip(
+ _("Bounding box margin.")
+ )
+ self.polish_margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
+ self.polish_margin_entry.set_precision(self.decimals)
+ self.polish_margin_entry.set_range(-10000.0000, 10000.0000)
+ self.polish_margin_entry.setObjectName("mill_polish_margin")
+
+ self.grid1.addWidget(self.polish_margin_lbl, 12, 0)
+ self.grid1.addWidget(self.polish_margin_entry, 12, 1)
+
+ # Polish Overlap
+ self.polish_over_lbl = FCLabel('%s:' % _('Overlap'))
+ self.polish_over_lbl.setToolTip(
+ _("How much (percentage) of the tool width to overlap each tool pass.")
+ )
+ self.polish_over_entry = FCDoubleSpinner(suffix='%', callback=self.confirmation_message)
+ self.polish_over_entry.set_precision(self.decimals)
+ self.polish_over_entry.setWrapping(True)
+ self.polish_over_entry.set_range(0.0000, 99.9999)
+ self.polish_over_entry.setSingleStep(0.1)
+ self.polish_over_entry.setObjectName("mill_polish_overlap")
+
+ self.grid1.addWidget(self.polish_over_lbl, 14, 0)
+ self.grid1.addWidget(self.polish_over_entry, 14, 1)
+
+ # Polish Method
+ self.polish_method_lbl = FCLabel('%s:' % _('Method'))
+ self.polish_method_lbl.setToolTip(
+ _("Algorithm for polishing:\n"
+ "- Standard: Fixed step inwards.\n"
+ "- Seed-based: Outwards from seed.\n"
+ "- Line-based: Parallel lines.")
+ )
+
+ self.polish_method_combo = FCComboBox2()
+ self.polish_method_combo.addItems(
+ [_("Standard"), _("Seed"), _("Lines")]
+ )
+ self.polish_method_combo.setObjectName('mill_polish_method')
+
+ self.grid1.addWidget(self.polish_method_lbl, 16, 0)
+ self.grid1.addWidget(self.polish_method_combo, 16, 1)
+
+ self.polish_margin_lbl.hide()
+ self.polish_margin_entry.hide()
+ self.polish_over_lbl.hide()
+ self.polish_over_entry.hide()
+ self.polish_method_lbl.hide()
+ self.polish_method_combo.hide()
+
+ separator_line2 = QtWidgets.QFrame()
+ separator_line2.setFrameShape(QtWidgets.QFrame.HLine)
+ separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.grid1.addWidget(separator_line2, 18, 0, 1, 2)
# Cut Z
- self.cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
+ self.cutzlabel = FCLabel('%s:' % _('Cut Z'))
self.cutzlabel.setToolTip(
_("Drill depth (negative)\n"
"below the copper surface.")
@@ -1771,8 +2223,8 @@ class MillingUI:
self.cutz_entry.setSingleStep(0.1)
self.cutz_entry.setObjectName("mill_cutz")
- self.grid1.addWidget(self.cutzlabel, 4, 0)
- self.grid1.addWidget(self.cutz_entry, 4, 1)
+ self.grid1.addWidget(self.cutzlabel, 20, 0)
+ self.grid1.addWidget(self.cutz_entry, 20, 1)
# Multi-Depth
self.mpass_cb = FCCheckBox('%s:' % _("Multi-Depth"))
@@ -1796,11 +2248,11 @@ class MillingUI:
self.mis_mpass_geo = OptionalInputSection(self.mpass_cb, [self.maxdepth_entry])
- self.grid1.addWidget(self.mpass_cb, 5, 0)
- self.grid1.addWidget(self.maxdepth_entry, 5, 1)
+ self.grid1.addWidget(self.mpass_cb, 22, 0)
+ self.grid1.addWidget(self.maxdepth_entry, 22, 1)
# Travel Z (z_move)
- self.travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z'))
+ self.travelzlabel = FCLabel('%s:' % _('Travel Z'))
self.travelzlabel.setToolTip(
_("Tool height when travelling\n"
"across the XY plane.")
@@ -1817,11 +2269,11 @@ class MillingUI:
self.travelz_entry.setSingleStep(0.1)
self.travelz_entry.setObjectName("mill_travelz")
- self.grid1.addWidget(self.travelzlabel, 6, 0)
- self.grid1.addWidget(self.travelz_entry, 6, 1)
+ self.grid1.addWidget(self.travelzlabel, 24, 0)
+ self.grid1.addWidget(self.travelz_entry, 24, 1)
# Feedrate X-Y
- self.frxylabel = QtWidgets.QLabel('%s:' % _('Feedrate X-Y'))
+ self.frxylabel = FCLabel('%s:' % _('Feedrate X-Y'))
self.frxylabel.setToolTip(
_("Cutting speed in the XY\n"
"plane in units per minute")
@@ -1832,11 +2284,14 @@ class MillingUI:
self.xyfeedrate_entry.setSingleStep(0.1)
self.xyfeedrate_entry.setObjectName("mill_feedratexy")
- self.grid1.addWidget(self.frxylabel, 12, 0)
- self.grid1.addWidget(self.xyfeedrate_entry, 12, 1)
+ self.grid1.addWidget(self.frxylabel, 26, 0)
+ self.grid1.addWidget(self.xyfeedrate_entry, 26, 1)
- # Excellon Feedrate Z
- self.frzlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z'))
+ self.frxylabel.hide()
+ self.xyfeedrate_entry.hide()
+
+ # Feedrate Z
+ self.frzlabel = FCLabel('%s:' % _('Feedrate Z'))
self.frzlabel.setToolTip(
_("Tool speed while drilling\n"
"(in units per minute).\n"
@@ -1849,11 +2304,11 @@ class MillingUI:
self.feedrate_z_entry.setSingleStep(0.1)
self.feedrate_z_entry.setObjectName("mill_feedratez")
- self.grid1.addWidget(self.frzlabel, 14, 0)
- self.grid1.addWidget(self.feedrate_z_entry, 14, 1)
+ self.grid1.addWidget(self.frzlabel, 28, 0)
+ self.grid1.addWidget(self.feedrate_z_entry, 28, 1)
- # Excellon Rapid Feedrate
- self.feedrate_rapid_label = QtWidgets.QLabel('%s:' % _('Feedrate Rapids'))
+ # Rapid Feedrate
+ self.feedrate_rapid_label = FCLabel('%s:' % _('Feedrate Rapids'))
self.feedrate_rapid_label.setToolTip(
_("Tool speed while drilling\n"
"(in units per minute).\n"
@@ -1867,8 +2322,8 @@ class MillingUI:
self.feedrate_rapid_entry.setSingleStep(0.1)
self.feedrate_rapid_entry.setObjectName("mill_fr_rapid")
- self.grid1.addWidget(self.feedrate_rapid_label, 16, 0)
- self.grid1.addWidget(self.feedrate_rapid_entry, 16, 1)
+ self.grid1.addWidget(self.feedrate_rapid_label, 30, 0)
+ self.grid1.addWidget(self.feedrate_rapid_entry, 30, 1)
# default values is to hide
self.feedrate_rapid_label.hide()
@@ -1899,11 +2354,14 @@ class MillingUI:
self.ois_recut = OptionalInputSection(self.extracut_cb, [self.e_cut_entry])
- self.grid1.addWidget(self.extracut_cb, 17, 0)
- self.grid1.addWidget(self.e_cut_entry, 17, 1)
+ self.extracut_cb.hide()
+ self.e_cut_entry.hide()
+
+ self.grid1.addWidget(self.extracut_cb, 32, 0)
+ self.grid1.addWidget(self.e_cut_entry, 32, 1)
# Spindlespeed
- self.spindle_label = QtWidgets.QLabel('%s:' % _('Spindle speed'))
+ self.spindle_label = FCLabel('%s:' % _('Spindle speed'))
self.spindle_label.setToolTip(
_("Speed of the spindle\n"
"in RPM (optional)")
@@ -1914,8 +2372,8 @@ class MillingUI:
self.spindlespeed_entry.set_step(100)
self.spindlespeed_entry.setObjectName("mill_spindlespeed")
- self.grid1.addWidget(self.spindle_label, 19, 0)
- self.grid1.addWidget(self.spindlespeed_entry, 19, 1)
+ self.grid1.addWidget(self.spindle_label, 34, 0)
+ self.grid1.addWidget(self.spindlespeed_entry, 34, 1)
# Dwell
self.dwell_cb = FCCheckBox('%s:' % _('Dwell'))
@@ -1935,27 +2393,11 @@ class MillingUI:
)
self.dwelltime_entry.setObjectName("mill_dwelltime")
- self.grid1.addWidget(self.dwell_cb, 20, 0)
- self.grid1.addWidget(self.dwelltime_entry, 20, 1)
+ self.grid1.addWidget(self.dwell_cb, 36, 0)
+ self.grid1.addWidget(self.dwelltime_entry, 36, 1)
self.ois_dwell = OptionalInputSection(self.dwell_cb, [self.dwelltime_entry])
- # 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(callback=self.confirmation_message)
- self.offset_entry.set_precision(self.decimals)
- self.offset_entry.set_range(-10000.0000, 10000.0000)
- self.offset_entry.setObjectName("mill_offset")
-
- self.grid1.addWidget(self.tool_offset_label, 25, 0)
- self.grid1.addWidget(self.offset_entry, 25, 1)
-
# #################################################################
# ################# GRID LAYOUT 5 ###############################
# #################################################################
@@ -1984,8 +2426,10 @@ class MillingUI:
separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
self.grid3.addWidget(separator_line2, 2, 0, 1, 2)
- # General Parameters
- self.gen_param_label = QtWidgets.QLabel('%s' % _("Common Parameters"))
+ # #############################################################################################################
+ # #################################### General Parameters #####################################################
+ # #############################################################################################################
+ self.gen_param_label = FCLabel('%s' % _("Common Parameters"))
self.gen_param_label.setToolTip(
_("Parameters that are common for all tools.")
)
@@ -2016,7 +2460,7 @@ class MillingUI:
self.grid3.addWidget(self.toolchangez_entry, 8, 1)
# End move Z:
- self.endz_label = QtWidgets.QLabel('%s:' % _("End move Z"))
+ self.endz_label = FCLabel('%s:' % _("End move Z"))
self.endz_label.setToolTip(
_("Height of the tool after\n"
"the last move at the end of the job.")
@@ -2035,7 +2479,7 @@ class MillingUI:
self.grid3.addWidget(self.endz_entry, 11, 1)
# End Move X,Y
- endmove_xy_label = QtWidgets.QLabel('%s:' % _('End move X,Y'))
+ endmove_xy_label = FCLabel('%s:' % _('End move X,Y'))
endmove_xy_label.setToolTip(
_("End move X,Y position. In format (x,y).\n"
"If no value is entered then there is no move\n"
@@ -2047,7 +2491,7 @@ class MillingUI:
self.grid3.addWidget(self.endxy_entry, 12, 1)
# Probe depth
- self.pdepth_label = QtWidgets.QLabel('%s:' % _("Probe Z depth"))
+ self.pdepth_label = FCLabel('%s:' % _("Probe Z depth"))
self.pdepth_label.setToolTip(
_("The maximum depth that the probe is allowed\n"
"to probe. Negative value, in current units.")
@@ -2066,7 +2510,7 @@ class MillingUI:
self.pdepth_entry.setVisible(False)
# Probe feedrate
- self.feedrate_probe_label = QtWidgets.QLabel('%s:' % _("Feedrate Probe"))
+ self.feedrate_probe_label = FCLabel('%s:' % _("Feedrate Probe"))
self.feedrate_probe_label.setToolTip(
_("The feedrate used while the probe is probing.")
)
@@ -2084,7 +2528,7 @@ class MillingUI:
self.feedrate_probe_entry.setVisible(False)
# Preprocessor Geometry selection
- pp_geo_label = QtWidgets.QLabel('%s:' % _("Preprocessor"))
+ pp_geo_label = FCLabel('%s:' % _("Preprocessor"))
pp_geo_label.setToolTip(
_("The preprocessor JSON file that dictates\n"
"Gcode output for Geometry (Milling) Objects.")