Procházet zdrojové kódy

- Tools Database - remade the UI
- made sure that the serializable attributes are added correctly and only once (self.ser_attrs)

Marius Stanciu před 5 roky
rodič
revize
5748eb049b

+ 2 - 0
CHANGELOG.md

@@ -10,6 +10,8 @@ CHANGELOG for FlatCAM beta
 14.07.2020
 
 - Drilling Tool - now there is an Excellon preference that control the autoload of tools from the Tools Database
+- Tools Database - remade the UI
+- made sure that the serializable attributes are added correctly and only once (self.ser_attrs)
 
 13.07.2020
 

+ 275 - 253
appDatabase.py

@@ -941,15 +941,15 @@ class ToolsDB2UI:
     def __init__(self, app, grid_layout):
         self.app = app
         self.decimals = self.app.decimals
-        
+
         settings = QtCore.QSettings("Open Source", "FlatCAM")
         if settings.contains("machinist"):
             self.machinist_setting = settings.value('machinist', type=int)
         else:
             self.machinist_setting = 0
-        
+
         g_lay = grid_layout
-        
+
         tree_layout = QtWidgets.QVBoxLayout()
         g_lay.addLayout(tree_layout, 0, 0)
 
@@ -995,31 +995,18 @@ class ToolsDB2UI:
         self.tool_description_box.setTitle(_("Tool Description"))
         self.tool_description_box.setFixedWidth(250)
 
-        # Geometry Basic box
-        self.basic_box = QtWidgets.QGroupBox()
-        self.basic_box.setStyleSheet("""
+        # Milling box
+        self.milling_box = QtWidgets.QGroupBox()
+        self.milling_box.setStyleSheet("""
         QGroupBox
         {
             font-size: 16px;
             font-weight: bold;
         }
         """)
-        self.basic_vlay = QtWidgets.QVBoxLayout()
-        self.basic_box.setTitle(_("Basic Geo Parameters"))
-        self.basic_box.setFixedWidth(250)
-
-        # Geometry Advanced box
-        self.advanced_box = QtWidgets.QGroupBox()
-        self.advanced_box.setStyleSheet("""
-                QGroupBox
-                {
-                    font-size: 16px;
-                    font-weight: bold;
-                }
-                """)
-        self.advanced_vlay = QtWidgets.QVBoxLayout()
-        self.advanced_box.setTitle(_("Advanced Geo Parameters"))
-        self.advanced_box.setFixedWidth(250)
+        self.milling_vlay = QtWidgets.QVBoxLayout()
+        self.milling_box.setTitle(_("Milling Parameters"))
+        self.milling_box.setFixedWidth(250)
 
         # NCC TOOL BOX
         self.ncc_box = QtWidgets.QGroupBox()
@@ -1075,28 +1062,37 @@ class ToolsDB2UI:
 
         # Layout Constructor
         self.tool_description_box.setLayout(self.description_vlay)
-        self.basic_box.setLayout(self.basic_vlay)
-        self.advanced_box.setLayout(self.advanced_vlay)
+        self.milling_box.setLayout(self.milling_vlay)
         self.ncc_box.setLayout(self.ncc_vlay)
         self.paint_box.setLayout(self.paint_vlay)
         self.iso_box.setLayout(self.iso_vlay)
         self.drill_box.setLayout(self.drill_vlay)
 
-        geo_vlay = QtWidgets.QVBoxLayout()
-        geo_vlay.addWidget(self.tool_description_box)
-        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.addWidget(self.iso_box)
-        tools_vlay.addWidget(self.drill_box)
-        tools_vlay.addStretch()
-
-        param_hlay.addLayout(geo_vlay)
-        param_hlay.addLayout(tools_vlay)
+        descript_vlay = QtWidgets.QVBoxLayout()
+        descript_vlay.addWidget(self.tool_description_box)
+        descript_vlay.addStretch()
+
+        milling_vlay = QtWidgets.QVBoxLayout()
+        milling_vlay.addWidget(self.milling_box)
+        milling_vlay.addStretch()
+
+        tools1_vlay = QtWidgets.QVBoxLayout()
+        tools1_vlay.addWidget(self.drill_box)
+        tools1_vlay.addWidget(self.iso_box)
+        tools1_vlay.addStretch()
+
+        tools2_vlay = QtWidgets.QVBoxLayout()
+        tools2_vlay.addWidget(self.paint_box)
+        tools2_vlay.addWidget(self.ncc_box)
+        tools2_vlay.addStretch()
+
+        param_hlay.addLayout(descript_vlay)
+        param_hlay.addLayout(tools1_vlay)
+        param_hlay.addLayout(tools2_vlay)
+
+        # always visible, always to be included last
+        param_hlay.addLayout(milling_vlay)
+
         param_hlay.addStretch()
 
         # ###########################################################################
@@ -1109,7 +1105,7 @@ class ToolsDB2UI:
         self.description_vlay.addStretch()
 
         # Tool Name
-        self.name_label = QtWidgets.QLabel('<span style="color:red;"><b>%s:</b></span>' % _('Tool Name'))
+        self.name_label = QtWidgets.QLabel('<span style="color:red;"><b>%s:</b></span>' % _('Name'))
         self.name_label.setToolTip(
             _("Tool name.\n"
               "This is not used in the app, it's function\n"
@@ -1122,7 +1118,7 @@ class ToolsDB2UI:
         self.grid_tool.addWidget(self.name_entry, 0, 1)
 
         # Tool Dia
-        self.dia_label = QtWidgets.QLabel('%s:' % _('Tool Dia'))
+        self.dia_label = QtWidgets.QLabel('%s:' % _('Diameter'))
         self.dia_label.setToolTip(
             _("Tool Diameter."))
 
@@ -1134,26 +1130,13 @@ class ToolsDB2UI:
         self.grid_tool.addWidget(self.dia_label, 1, 0)
         self.grid_tool.addWidget(self.dia_entry, 1, 1)
 
-        # Tool Object Type
-        self.tool_object_label = QtWidgets.QLabel('<b>%s:</b>' % _('Object Type'))
-        self.tool_object_label.setToolTip(
-            _("The kind of application object where the tool is to be used."))
-
-        self.object_type_combo = FCComboBox()
-        self.object_type_combo.addItems([_("General"), _("Milling"), _("Drilling")])
-        self.object_type_combo.setObjectName('gdb_object_type')
-
-        self.grid_tool.addWidget(self.tool_object_label, 2, 0)
-        self.grid_tool.addWidget(self.object_type_combo, 2, 1)
-
         # Tool Tolerance
-        self.tol_label = QtWidgets.QLabel("<b>%s:</b>" % _("Tolerance"))
+        self.tol_label = QtWidgets.QLabel("<b>%s:</b>" % _("Diameter Tolerance"))
         self.tol_label.setToolTip(
-            _("Tool tolerance. If there is a tool in the Excellon object with\n"
-              "the value within the limits then this tool from DB will be used.\n"
-              "This behavior is enabled in the Drilling Tool.")
+            _("Tool tolerance. If there is a tool in the targeted tools table with\n"
+              "the value within the limits then this tool from DB will be used.")
         )
-        self.grid_tool.addWidget(self.tol_label, 4, 0, 1, 2)
+        self.grid_tool.addWidget(self.tol_label, 2, 0, 1, 2)
 
         # Tolerance Min Limit
         self.min_limit_label = QtWidgets.QLabel('%s:' % _("Min"))
@@ -1166,8 +1149,8 @@ class ToolsDB2UI:
         self.tol_min_entry.setSingleStep(0.1)
         self.tol_min_entry.setObjectName("gdb_tol_min")
 
-        self.grid_tool.addWidget(self.min_limit_label, 6, 0)
-        self.grid_tool.addWidget(self.tol_min_entry, 6, 1)
+        self.grid_tool.addWidget(self.min_limit_label, 4, 0)
+        self.grid_tool.addWidget(self.tol_min_entry, 4, 1)
 
         # Tolerance Min Limit
         self.max_limit_label = QtWidgets.QLabel('%s:' % _("Max"))
@@ -1180,20 +1163,32 @@ class ToolsDB2UI:
         self.tol_max_entry.setSingleStep(0.1)
         self.tol_max_entry.setObjectName("gdb_tol_max")
 
-        self.grid_tool.addWidget(self.max_limit_label, 7, 0)
-        self.grid_tool.addWidget(self.tol_max_entry, 7, 1)
+        self.grid_tool.addWidget(self.max_limit_label, 6, 0)
+        self.grid_tool.addWidget(self.tol_max_entry, 6, 1)
+
+        # Tool Object Type
+        self.tool_op_label = QtWidgets.QLabel('<b>%s:</b>' % _('Operation'))
+        self.tool_op_label.setToolTip(
+            _("The kind of Application Tool where this tool is to be used."))
+
+        self.tool_op_combo = FCComboBox()
+        self.tool_op_combo.addItems([_("General"), _("Milling"), _("Drilling"), _('Isolation'), _('Paint'), _('NCC')])
+        self.tool_op_combo.setObjectName('gdb_tool_target')
+
+        self.grid_tool.addWidget(self.tool_op_label, 8, 0)
+        self.grid_tool.addWidget(self.tool_op_combo, 8, 1)
 
         # ###########################################################################
-        # ############### BASIC GEOMETRY UI form ####################################
+        # ############### MILLING UI form ####################################
         # ###########################################################################
         self.grid0 = QtWidgets.QGridLayout()
-        self.basic_vlay.addLayout(self.grid0)
+        self.milling_vlay.addLayout(self.grid0)
         self.grid0.setColumnStretch(0, 0)
         self.grid0.setColumnStretch(1, 1)
-        self.basic_vlay.addStretch()
+        self.milling_vlay.addStretch()
 
         # Tool Shape
-        self.shape_label = QtWidgets.QLabel('%s:' % _('Tool Shape'))
+        self.shape_label = QtWidgets.QLabel('%s:' % _('Shape'))
         self.shape_label.setToolTip(
             _("Tool Shape. \n"
               "Can be:\n"
@@ -1208,6 +1203,91 @@ class ToolsDB2UI:
         self.grid0.addWidget(self.shape_label, 2, 0)
         self.grid0.addWidget(self.shape_combo, 2, 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')
+
+        self.grid0.addWidget(self.vdia_label, 4, 0)
+        self.grid0.addWidget(self.vdia_entry, 4, 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')
+
+        self.grid0.addWidget(self.vangle_label, 6, 0)
+        self.grid0.addWidget(self.vangle_entry, 6, 1)
+
+        separator_line = QtWidgets.QFrame()
+        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.grid0.addWidget(separator_line, 8, 0, 1, 2)
+
+        # 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')
+
+        self.grid0.addWidget(self.type_label, 10, 0)
+        self.grid0.addWidget(self.type_combo, 10, 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')
+
+        self.grid0.addWidget(self.tooloffset_label, 12, 0)
+        self.grid0.addWidget(self.tooloffset_combo, 12, 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')
+
+        self.grid0.addWidget(self.custom_offset_label, 14, 0)
+        self.grid0.addWidget(self.custom_offset_entry, 14, 1)
+
+        separator_line = QtWidgets.QFrame()
+        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.grid0.addWidget(separator_line, 16, 0, 1, 2)
+
         # Cut Z
         self.cutz_label = QtWidgets.QLabel('%s:' % _("Cut Z"))
         self.cutz_label.setToolTip(
@@ -1219,8 +1299,8 @@ class ToolsDB2UI:
         self.cutz_entry.set_precision(self.decimals)
         self.cutz_entry.setObjectName('gdb_cutz')
 
-        self.grid0.addWidget(self.cutz_label, 4, 0)
-        self.grid0.addWidget(self.cutz_entry, 4, 1)
+        self.grid0.addWidget(self.cutz_label, 18, 0)
+        self.grid0.addWidget(self.cutz_entry, 18, 1)
 
         # Multi Depth
         self.multidepth_label = QtWidgets.QLabel('%s:' % _("MultiDepth"))
@@ -1232,8 +1312,8 @@ class ToolsDB2UI:
         self.multidepth_cb = FCCheckBox()
         self.multidepth_cb.setObjectName('gdb_multidepth')
 
-        self.grid0.addWidget(self.multidepth_label, 5, 0)
-        self.grid0.addWidget(self.multidepth_cb, 5, 1)
+        self.grid0.addWidget(self.multidepth_label, 20, 0)
+        self.grid0.addWidget(self.multidepth_cb, 20, 1)
 
         # Depth Per Pass
         self.dpp_label = QtWidgets.QLabel('%s:' % _("DPP"))
@@ -1246,8 +1326,8 @@ class ToolsDB2UI:
         self.multidepth_entry.set_precision(self.decimals)
         self.multidepth_entry.setObjectName('gdb_multidepth_entry')
 
-        self.grid0.addWidget(self.dpp_label, 7, 0)
-        self.grid0.addWidget(self.multidepth_entry, 7, 1)
+        self.grid0.addWidget(self.dpp_label, 22, 0)
+        self.grid0.addWidget(self.multidepth_entry, 22, 1)
 
         # Travel Z
         self.travelz_label = QtWidgets.QLabel('%s:' % _("Travel Z"))
@@ -1261,8 +1341,46 @@ class ToolsDB2UI:
         self.travelz_entry.set_precision(self.decimals)
         self.travelz_entry.setObjectName('gdb_travel')
 
-        self.grid0.addWidget(self.travelz_label, 9, 0)
-        self.grid0.addWidget(self.travelz_entry, 9, 1)
+        self.grid0.addWidget(self.travelz_label, 24, 0)
+        self.grid0.addWidget(self.travelz_entry, 24, 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')
+
+        self.grid0.addWidget(self.ecut_label, 26, 0)
+        self.grid0.addWidget(self.ecut_cb, 26, 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')
+
+        self.grid0.addWidget(self.ecut_length_label, 28, 0)
+        self.grid0.addWidget(self.ecut_length_entry, 28, 1)
+
+        separator_line = QtWidgets.QFrame()
+        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.grid0.addWidget(separator_line, 30, 0, 1, 2)
 
         # Feedrate X-Y
         self.frxy_label = QtWidgets.QLabel('%s:' % _("Feedrate X-Y"))
@@ -1275,8 +1393,8 @@ class ToolsDB2UI:
         self.frxy_entry.set_precision(self.decimals)
         self.frxy_entry.setObjectName('gdb_frxy')
 
-        self.grid0.addWidget(self.frxy_label, 12, 0)
-        self.grid0.addWidget(self.frxy_entry, 12, 1)
+        self.grid0.addWidget(self.frxy_label, 32, 0)
+        self.grid0.addWidget(self.frxy_entry, 32, 1)
 
         # Feedrate Z
         self.frz_label = QtWidgets.QLabel('%s:' % _("Feedrate Z"))
@@ -1289,8 +1407,29 @@ class ToolsDB2UI:
         self.frz_entry.set_precision(self.decimals)
         self.frz_entry.setObjectName('gdb_frz')
 
-        self.grid0.addWidget(self.frz_label, 14, 0)
-        self.grid0.addWidget(self.frz_entry, 14, 1)
+        self.grid0.addWidget(self.frz_label, 34, 0)
+        self.grid0.addWidget(self.frz_entry, 34, 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')
+
+        self.grid0.addWidget(self.frapids_label, 36, 0)
+        self.grid0.addWidget(self.frapids_entry, 36, 1)
+
+        separator_line = QtWidgets.QFrame()
+        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.grid0.addWidget(separator_line, 38, 0, 1, 2)
 
         # Spindle Spped
         self.spindle_label = QtWidgets.QLabel('%s:' % _("Spindle Speed"))
@@ -1304,8 +1443,8 @@ class ToolsDB2UI:
         self.spindle_entry.set_precision(self.decimals)
         self.spindle_entry.setObjectName('gdb_spindle')
 
-        self.grid0.addWidget(self.spindle_label, 15, 0)
-        self.grid0.addWidget(self.spindle_entry, 15, 1)
+        self.grid0.addWidget(self.spindle_label, 40, 0)
+        self.grid0.addWidget(self.spindle_entry, 40, 1)
 
         # Dwell
         self.dwell_label = QtWidgets.QLabel('%s:' % _("Dwell"))
@@ -1317,8 +1456,8 @@ class ToolsDB2UI:
         self.dwell_cb = FCCheckBox()
         self.dwell_cb.setObjectName('gdb_dwell')
 
-        self.grid0.addWidget(self.dwell_label, 16, 0)
-        self.grid0.addWidget(self.dwell_cb, 16, 1)
+        self.grid0.addWidget(self.dwell_label, 42, 0)
+        self.grid0.addWidget(self.dwell_cb, 42, 1)
 
         # Dwell Time
         self.dwelltime_label = QtWidgets.QLabel('%s:' % _("Dwelltime"))
@@ -1331,142 +1470,8 @@ class ToolsDB2UI:
         self.dwelltime_entry.set_precision(self.decimals)
         self.dwelltime_entry.setObjectName('gdb_dwelltime')
 
-        self.grid0.addWidget(self.dwelltime_label, 17, 0)
-        self.grid0.addWidget(self.dwelltime_entry, 17, 1)
-
-        # ###########################################################################
-        # ############### ADVANCED GEOMETRY UI form #################################
-        # ###########################################################################
-
-        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"))
-        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')
-
-        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'))
-        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')
-
-        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"))
-        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')
-
-        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"))
-        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')
-
-        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"))
-        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')
-
-        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"))
-        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')
-
-        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"))
-        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')
-
-        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"))
-        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')
-
-        self.grid1.addWidget(self.ecut_length_label, 13, 0)
-        self.grid1.addWidget(self.ecut_length_entry, 13, 1)
+        self.grid0.addWidget(self.dwelltime_label, 44, 0)
+        self.grid0.addWidget(self.dwelltime_entry, 44, 1)
 
         # ###########################################################################
         # ############### NCC UI form ###############################################
@@ -2149,7 +2154,7 @@ class ToolsDB2(QtWidgets.QWidget):
         # ##############################################################################
 
         self.form_fields = {
-            "object_type":      self.ui.object_type_combo,
+            "tool_target":      self.ui.tool_op_combo,
             "tol_min":          self.ui.tol_min_entry,
             "tol_max":          self.ui.tol_max_entry,
             # Basic
@@ -2221,7 +2226,7 @@ class ToolsDB2(QtWidgets.QWidget):
         }
 
         self.name2option = {
-            "gdb_object_type":      "object_type",
+            "gdb_tool_target":      "tool_target",
             "gdb_tol_min":          "tol_min",
             "gdb_tol_max":          "tol_max",
 
@@ -2319,7 +2324,7 @@ class ToolsDB2(QtWidgets.QWidget):
 
         self.ui.tree_widget.itemDoubleClicked.connect(self.on_item_double_clicked)
 
-        self.ui.object_type_combo.currentIndexChanged.connect(self.on_object_type_changed)
+        self.ui.tool_op_combo.currentIndexChanged.connect(self.on_object_type_changed)
 
         self.setup_db_ui()
 
@@ -2454,22 +2459,25 @@ class ToolsDB2(QtWidgets.QWidget):
                 self.storage_to_form(self.db_tool_dict['1'])
 
                 # Enable appGUI
-                self.ui.tool_description_box.setEnabled(True)
-                self.ui.basic_box.setEnabled(True)
-                self.ui.advanced_box.setEnabled(True)
-                self.ui.ncc_box.setEnabled(True)
-                self.ui.paint_box.setEnabled(True)
-                self.ui.iso_box.setEnabled(True)
-                self.ui.drill_box.setEnabled(True)
+                try:
+                    self.on_object_type_changed(val=self.db_tool_dict['1']['data']['tool_target'])
+                except KeyError:
+                    self.on_object_type_changed(val=_("General"))
 
                 self.ui.tree_widget.setCurrentItem(self.ui.tree_widget.topLevelItem(0))
                 # self.ui.tree_widget.setFocus()
 
             else:
                 # Disable appGUI
+                self.ui.tool_description_box.show()
+                self.ui.milling_box.show()
+                self.ui.ncc_box.show()
+                self.ui.paint_box.show()
+                self.ui.iso_box.show()
+                self.ui.drill_box.show()
+
                 self.ui.tool_description_box.setEnabled(False)
-                self.ui.basic_box.setEnabled(False)
-                self.ui.advanced_box.setEnabled(False)
+                self.ui.milling_box.setEnabled(False)
                 self.ui.ncc_box.setEnabled(False)
                 self.ui.paint_box.setEnabled(False)
                 self.ui.iso_box.setEnabled(False)
@@ -2482,35 +2490,49 @@ class ToolsDB2(QtWidgets.QWidget):
     def on_object_type_changed(self, index=None, val=None):
 
         if val is None:
-            object_type = self.ui.object_type_combo.get_value()
+            tool_target = self.ui.tool_op_combo.get_value()
         else:
-            object_type = val
+            tool_target = val
 
         self.ui.tool_description_box.setEnabled(True)
         if self.db_tool_dict:
-            if object_type == _("General"):
-                self.ui.basic_box.setEnabled(True)
-                self.ui.advanced_box.setEnabled(True)
+            if tool_target == _("General"):
+                self.ui.milling_box.setEnabled(True)
                 self.ui.ncc_box.setEnabled(True)
                 self.ui.paint_box.setEnabled(True)
                 self.ui.iso_box.setEnabled(True)
                 self.ui.drill_box.setEnabled(True)
 
-            if object_type == _("Milling"):
-                self.ui.basic_box.setEnabled(True)
-                self.ui.advanced_box.setEnabled(True)
-                self.ui.ncc_box.setEnabled(False)
-                self.ui.paint_box.setEnabled(False)
-                self.ui.iso_box.setEnabled(False)
-                self.ui.drill_box.setEnabled(False)
+                self.ui.milling_box.show()
+                self.ui.ncc_box.show()
+                self.ui.paint_box.show()
+                self.ui.iso_box.show()
+                self.ui.drill_box.show()
+            else:
+                self.ui.ncc_box.hide()
+                self.ui.paint_box.hide()
+                self.ui.iso_box.hide()
+                self.ui.drill_box.hide()
 
-            if object_type == _("Drilling"):
-                self.ui.basic_box.setEnabled(False)
-                self.ui.advanced_box.setEnabled(False)
-                self.ui.ncc_box.setEnabled(False)
-                self.ui.paint_box.setEnabled(False)
-                self.ui.iso_box.setEnabled(False)
-                self.ui.drill_box.setEnabled(True)
+                if tool_target == _("Milling"):
+                    self.ui.milling_box.setEnabled(True)
+                    self.ui.milling_box.show()
+
+                if tool_target == _("Drilling"):
+                    self.ui.drill_box.setEnabled(True)
+                    self.ui.drill_box.show()
+
+                if tool_target == _("Isolation"):
+                    self.ui.iso_box.setEnabled(True)
+                    self.ui.iso_box.show()
+
+                if tool_target == _("Paint"):
+                    self.ui.paint_box.setEnabled(True)
+                    self.ui.paint_box.show()
+
+                if tool_target == _("NCC"):
+                    self.ui.ncc_box.setEnabled(True)
+                    self.ui.ncc_box.show()
 
     def on_tool_add(self):
         """
@@ -2542,7 +2564,7 @@ class ToolsDB2(QtWidgets.QWidget):
             "startz":           self.app.defaults["geometry_startz"],
             "endz":             float(self.app.defaults["geometry_endz"]),
 
-            "object_type":      _("General"),
+            "tool_target":      _("General"),
             "tol_min":          0.0,
             "tol_max":          0.0,
 
@@ -2632,7 +2654,7 @@ class ToolsDB2(QtWidgets.QWidget):
             self.ui.tree_widget.setCurrentItem(last_item)
             last_item.setSelected(True)
 
-        self.on_object_type_changed(val=dict_elem['data']['object_type'])
+        self.on_object_type_changed(val=dict_elem['data']['tool_target'])
         self.app.inform.emit('[success] %s' % _("Tool added to DB."))
 
     def on_tool_copy(self):
@@ -2966,8 +2988,8 @@ class ToolsDB2(QtWidgets.QWidget):
         elif wdg_name == "gdb_shape":
             self.db_tool_dict[tool_id]['tool_type'] = val
         else:
-            if wdg_name == "gdb_object_type":
-                self.db_tool_dict[tool_id]['data']['object_type'] = val
+            if wdg_name == "gdb_tool_target":
+                self.db_tool_dict[tool_id]['data']['tool_target'] = val
             elif wdg_name == "gdb_tol_min":
                 self.db_tool_dict[tool_id]['data']['tol_min'] = val
             elif wdg_name == "gdb_tol_max":

+ 1 - 1
appObjects/FlatCAMGeometry.py

@@ -161,7 +161,7 @@ class GeometryObject(FlatCAMObj, Geometry):
         # Attributes to be included in serialization
         # Always append to it because it carries contents
         # from predecessors.
-        self.ser_attrs += ['options', 'kind', 'tools', 'multigeo']
+        self.ser_attrs += ['options', 'kind', 'multigeo', 'fill_color', 'outline_color', 'alpha_level']
 
     def build_ui(self):
         self.ui_disconnect()

+ 60 - 60
appObjects/FlatCAMGerber.py

@@ -41,66 +41,6 @@ class GerberObject(FlatCAMObj, Gerber):
 
     ui_type = GerberObjectUI
 
-    @staticmethod
-    def merge(grb_list, grb_final):
-        """
-        Merges the geometry of objects in geo_list into
-        the geometry of geo_final.
-
-        :param grb_list: List of GerberObject Objects to join.
-        :param grb_final: Destination GeometryObject object.
-        :return: None
-        """
-
-        if grb_final.solid_geometry is None:
-            grb_final.solid_geometry = []
-            grb_final.follow_geometry = []
-
-        if not grb_final.apertures:
-            grb_final.apertures = {}
-
-        if type(grb_final.solid_geometry) is not list:
-            grb_final.solid_geometry = [grb_final.solid_geometry]
-            grb_final.follow_geometry = [grb_final.follow_geometry]
-
-        for grb in grb_list:
-
-            # Expand lists
-            if type(grb) is list:
-                GerberObject.merge(grb_list=grb, grb_final=grb_final)
-            else:   # If not list, just append
-                for option in grb.options:
-                    if option != 'name':
-                        try:
-                            grb_final.options[option] = grb.options[option]
-                        except KeyError:
-                            log.warning("Failed to copy option.", option)
-
-                try:
-                    for geos in grb.solid_geometry:
-                        grb_final.solid_geometry.append(geos)
-                        grb_final.follow_geometry.append(geos)
-                except TypeError:
-                    grb_final.solid_geometry.append(grb.solid_geometry)
-                    grb_final.follow_geometry.append(grb.solid_geometry)
-
-                for ap in grb.apertures:
-                    if ap not in grb_final.apertures:
-                        grb_final.apertures[ap] = grb.apertures[ap]
-                    else:
-                        # create a list of integers out of the grb.apertures keys and find the max of that value
-                        # then, the aperture duplicate is assigned an id value incremented with 1,
-                        # and finally made string because the apertures dict keys are strings
-                        max_ap = str(max([int(k) for k in grb_final.apertures.keys()]) + 1)
-                        grb_final.apertures[max_ap] = {}
-                        grb_final.apertures[max_ap]['geometry'] = []
-
-                        for k, v in grb.apertures[ap].items():
-                            grb_final.apertures[max_ap][k] = deepcopy(v)
-
-        grb_final.solid_geometry = MultiPolygon(grb_final.solid_geometry)
-        grb_final.follow_geometry = MultiPolygon(grb_final.follow_geometry)
-
     def __init__(self, name):
         self.decimals = self.app.decimals
 
@@ -1515,6 +1455,66 @@ class GerberObject(FlatCAMObj, Gerber):
 
         return gerber_code
 
+    @staticmethod
+    def merge(grb_list, grb_final):
+        """
+        Merges the geometry of objects in geo_list into
+        the geometry of geo_final.
+
+        :param grb_list: List of GerberObject Objects to join.
+        :param grb_final: Destination GeometryObject object.
+        :return: None
+        """
+
+        if grb_final.solid_geometry is None:
+            grb_final.solid_geometry = []
+            grb_final.follow_geometry = []
+
+        if not grb_final.apertures:
+            grb_final.apertures = {}
+
+        if type(grb_final.solid_geometry) is not list:
+            grb_final.solid_geometry = [grb_final.solid_geometry]
+            grb_final.follow_geometry = [grb_final.follow_geometry]
+
+        for grb in grb_list:
+
+            # Expand lists
+            if type(grb) is list:
+                GerberObject.merge(grb_list=grb, grb_final=grb_final)
+            else:   # If not list, just append
+                for option in grb.options:
+                    if option != 'name':
+                        try:
+                            grb_final.options[option] = grb.options[option]
+                        except KeyError:
+                            log.warning("Failed to copy option.", option)
+
+                try:
+                    for geos in grb.solid_geometry:
+                        grb_final.solid_geometry.append(geos)
+                        grb_final.follow_geometry.append(geos)
+                except TypeError:
+                    grb_final.solid_geometry.append(grb.solid_geometry)
+                    grb_final.follow_geometry.append(grb.solid_geometry)
+
+                for ap in grb.apertures:
+                    if ap not in grb_final.apertures:
+                        grb_final.apertures[ap] = grb.apertures[ap]
+                    else:
+                        # create a list of integers out of the grb.apertures keys and find the max of that value
+                        # then, the aperture duplicate is assigned an id value incremented with 1,
+                        # and finally made string because the apertures dict keys are strings
+                        max_ap = str(max([int(k) for k in grb_final.apertures.keys()]) + 1)
+                        grb_final.apertures[max_ap] = {}
+                        grb_final.apertures[max_ap]['geometry'] = []
+
+                        for k, v in grb.apertures[ap].items():
+                            grb_final.apertures[max_ap][k] = deepcopy(v)
+
+        grb_final.solid_geometry = MultiPolygon(grb_final.solid_geometry)
+        grb_final.follow_geometry = MultiPolygon(grb_final.follow_geometry)
+
     def mirror(self, axis, point):
         Gerber.mirror(self, axis=axis, point=point)
         self.replotApertures.emit()

+ 1 - 1
appParsers/ParseExcellon.py

@@ -118,7 +118,7 @@ class Excellon(Geometry):
         # Attributes to be included in serialization
         # Always append to it because it carries contents
         # from Geometry.
-        self.ser_attrs += ['tools', 'zeros', 'excellon_format_upper_mm', 'excellon_format_lower_mm',
+        self.ser_attrs += ['zeros', 'excellon_format_upper_mm', 'excellon_format_lower_mm',
                            'excellon_format_upper_in', 'excellon_format_lower_in', 'excellon_units', 'source_file']
 
         # ### Patterns ####

+ 5 - 6
appParsers/ParseGerber.py

@@ -142,12 +142,6 @@ class Gerber(Geometry):
 
         self.source_file = ''
 
-        # Attributes to be included in serialization
-        # Always append to it because it carries contents
-        # from Geometry.
-        self.ser_attrs += ['int_digits', 'frac_digits', 'apertures',
-                           'aperture_macros', 'solid_geometry', 'source_file']
-
         # ### Parser patterns ## ##
         # FS - Format Specification
         # The format of X and Y must be the same!
@@ -234,6 +228,11 @@ class Gerber(Geometry):
 
         self.use_buffer_for_union = self.app.defaults["gerber_use_buffer_for_union"]
 
+        # Attributes to be included in serialization
+        # Always append to it because it carries contents
+        # from Geometry.
+        self.ser_attrs += ['apertures', 'int_digits', 'frac_digits', 'aperture_macros', 'solid_geometry', 'source_file']
+
     def aperture_parse(self, apertureId, apertureType, apParameters):
         """
         Parse gerber aperture definition into dictionary of apertures.

+ 5 - 3
app_Main.py

@@ -10181,9 +10181,11 @@ class App(QtCore.QObject):
                 pass
 
             # Serialize the whole project
-            d = {"objs": [obj.to_dict() for obj in self.collection.get_list()],
-                 "options": self.options,
-                 "version": self.version}
+            d = {
+                "objs":     [obj.to_dict() for obj in self.collection.get_list()],
+                "options":  self.options,
+                "version":  self.version
+            }
 
             if self.defaults["global_save_compressed"] is True:
                 with lzma.open(filename, "w", preset=int(self.defaults['global_compression_level'])) as f:

+ 3 - 3
camlib.py

@@ -478,9 +478,6 @@ class Geometry(object):
         # Final geometry: MultiLineString or list (of LineString or Points)
         self.follow_geometry = None
 
-        # Attributes to be included in serialization
-        self.ser_attrs = ["units", 'solid_geometry', 'follow_geometry']
-
         # Flattened geometry (list of paths only)
         self.flat_geometry = []
 
@@ -503,6 +500,9 @@ class Geometry(object):
             from appGUI.PlotCanvasLegacy import ShapeCollectionLegacy
             self.temp_shapes = ShapeCollectionLegacy(obj=self, app=self.app, name='camlib.geometry')
 
+        # Attributes to be included in serialization
+        self.ser_attrs = ["units", 'solid_geometry', 'follow_geometry', 'tools']
+
     def plot_temp_shapes(self, element, color='red'):
 
         try: