Jelajahi Sumber

- remade the Excellon export function to work with parameters entered in Edit -> Preferences -> Excellon Export
- added a new entry in the Project Context Menu named 'Save'. It will actually work for Geometry and it will do Export DXF and for Excellon and it will do Export Excellon

Marius Stanciu 7 tahun lalu
induk
melakukan
e717cb8f15
5 mengubah file dengan 198 tambahan dan 160 penghapusan
  1. 68 32
      FlatCAMApp.py
  2. 6 11
      FlatCAMGUI.py
  3. 118 116
      FlatCAMObj.py
  4. 3 0
      ObjectCollection.py
  5. 3 1
      README.md

+ 68 - 32
FlatCAMApp.py

@@ -1079,8 +1079,8 @@ class App(QtCore.QObject):
 
         self.ui.menufileexportsvg.triggered.connect(self.on_file_exportsvg)
         self.ui.menufileexportpng.triggered.connect(self.on_file_exportpng)
-        self.ui.menufileexportexcellon.triggered.connect(lambda: self.on_file_exportexcellon(altium_format=None))
-        self.ui.menufileexportexcellon_altium.triggered.connect(lambda: self.on_file_exportexcellon(altium_format=True))
+        self.ui.menufileexportexcellon.triggered.connect(self.on_file_exportexcellon)
+
 
         self.ui.menufileexportdxf.triggered.connect(self.on_file_exportdxf)
 
@@ -1156,6 +1156,7 @@ class App(QtCore.QObject):
         self.ui.menuprojectedit.triggered.connect(self.object2editor)
 
         self.ui.menuprojectdelete.triggered.connect(self.on_delete)
+        self.ui.menuprojectsave.triggered.connect(self.on_project_context_save)
         self.ui.menuprojectproperties.triggered.connect(self.obj_properties)
 
         # Toolbar
@@ -4693,6 +4694,13 @@ class App(QtCore.QObject):
 
         self.properties_tool.run()
 
+    def on_project_context_save(self):
+        obj = self.collection.get_active()
+        if type(obj) == FlatCAMGeometry:
+            self.on_file_exportdxf()
+        elif type(obj) == FlatCAMExcellon:
+            self.on_file_exportexcellon()
+
     def obj_move(self):
         self.report_usage("obj_move()")
 
@@ -4939,7 +4947,7 @@ class App(QtCore.QObject):
             write_png(filename, data)
             self.file_saved.emit("png", filename)
 
-    def on_file_exportexcellon(self, altium_format=None):
+    def on_file_exportexcellon(self):
         """
         Callback for menu item File->Export SVG.
 
@@ -4971,7 +4979,7 @@ class App(QtCore.QObject):
 
         name = self.collection.get_active().options["name"]
 
-        filter = "Excellon File (*.drl);;Excellon File (*.txt);;All Files (*.*)"
+        filter = "Excellon File (*.DRL);;Excellon File (*.TXT);;All Files (*.*)"
         try:
             filename, _ = QtWidgets.QFileDialog.getSaveFileName(
                 caption="Export Excellon",
@@ -4986,12 +4994,8 @@ class App(QtCore.QObject):
             self.inform.emit("[WARNING_NOTCL]Export Excellon cancelled.")
             return
         else:
-            if altium_format is None:
-                self.export_excellon(name, filename)
-                self.file_saved.emit("Excellon", filename)
-            else:
-                self.export_excellon(name, filename, altium_format=True)
-                self.file_saved.emit("Excellon", filename)
+            self.export_excellon(name, filename)
+            self.file_saved.emit("Excellon", filename)
 
     def on_file_exportdxf(self):
         """
@@ -5528,9 +5532,17 @@ class App(QtCore.QObject):
             return "Could not retrieve object: %s" % obj_name
 
         # updated units
-        units = self.defaults["excellon_exp_units"]
-        whole = self.defaults["excellon_exp_integer"]
-        fract = self.defaults["excellon_exp_decimals"]
+        eunits = self.defaults["excellon_exp_units"]
+        ewhole = self.defaults["excellon_exp_integer"]
+        efract = self.defaults["excellon_exp_decimals"]
+        ezeros = self.defaults["excellon_exp_zeros"]
+        eformat = self.defaults[ "excellon_exp_format"]
+
+        fc_units = self.general_options_form.general_app_group.units_radio.get_value().upper()
+        if fc_units == 'MM':
+            factor = 1 if eunits == 'METRIC' else 0.03937
+        else:
+            factor = 25.4 if eunits == 'METRIC' else 1
 
         def make_excellon():
             try:
@@ -5538,32 +5550,55 @@ class App(QtCore.QObject):
 
                 header = 'M48\n'
                 header += ';EXCELLON GENERATED BY FLATCAM v%s - www.flatcam.org - Version Date: %s\n' % \
-                          (str(self.app.version), str(self.app.version_date))
+                          (str(self.version), str(self.version_date))
 
                 header += ';Filename: %s' % str(obj_name) + '\n'
                 header += ';Created on : %s' % time_str + '\n'
 
-                if self.defaults["excellon_exp_format"] == 'dec':
-                    has_slots, excellon_code = obj.export_excellon_decimals(whole, fract, units)
-                    header += units + '\n'
+                if eformat == 'dec':
+                    has_slots, excellon_code = obj.export_excellon(ewhole, efract, factor=factor)
+                    header += eunits + '\n'
 
                     for tool in obj.tools:
-                        if units == 'METRIC':
-                            header += 'T' + str(tool) + 'F00S00' + 'C' + '%.2f' % float(obj.tools[tool]['C']) + '\n'
+                        if eunits == 'METRIC':
+                            header += "T{tool}F00S00C{:.{dec}f}\n".format(float(obj.tools[tool]['C']) * factor,
+                                                                          tool=str(tool),
+                                                                          dec=2)
                         else:
-                            header += 'T' + str(tool) + 'F00S00' + 'C' + '%.4f' % float(obj.tools[tool]['C']) + '\n'
+                            header += "T{tool}F00S00C{:.{dec}f}\n".format(float(obj.tools[tool]['C']) * factor,
+                                                                          tool=str(tool),
+                                                                          dec=4)
                 else:
-                    has_slots, excellon_code = obj.export_excellon_ndecimals(whole, fract, units)
-                    header += '%s,%s\n' % (units, self.defaults["excellon_exp_zeros"])
-                    header += format_exc
-
-                    for tool in obj.tools:
-                        if units == 'METRIC':
-                            header += 'T' + str(tool) + 'F00S00' + 'C' + \
-                                      '%.2f' % (float(obj.tools[tool]['C']) / 25.4) + '\n'
-                        else:
-                            header += 'T' + str(tool) + 'F00S00' + 'C' + '%.4f' % float(obj.tools[tool]['C']) + '\n'
-
+                    if ezeros == 'LZ':
+                        has_slots, excellon_code = obj.export_excellon(ewhole, efract,
+                                                                       form='ndec', e_zeros='LZ', factor=factor)
+                        header += '%s,%s\n' % (eunits, 'LZ')
+                        header += format_exc
+
+                        for tool in obj.tools:
+                            if eunits == 'METRIC':
+                                header += "T{tool}F00S00C{:.{dec}f}\n".format(float(obj.tools[tool]['C']) * factor,
+                                                                              tool=str(tool),
+                                                                              dec=2)
+                            else:
+                                header += "T{tool}F00S00C{:.{dec}f}\n".format(float(obj.tools[tool]['C']) * factor,
+                                                                              tool=str(tool),
+                                                                              dec=4)
+                    else:
+                        has_slots, excellon_code = obj.export_excellon(ewhole, efract,
+                                                                       form='ndec', e_zeros='TZ', factor=factor)
+                        header += '%s,%s\n' % (eunits, 'TZ')
+                        header += format_exc
+
+                        for tool in obj.tools:
+                            if eunits == 'METRIC':
+                                header += "T{tool}F00S00C{:.{dec}f}\n".format(float(obj.tools[tool]['C']) * factor,
+                                                                              tool=str(tool),
+                                                                              dec=2)
+                            else:
+                                header += "T{tool}F00S00C{:.{dec}f}\n".format(float(obj.tools[tool]['C']) * factor,
+                                                                              tool=str(tool),
+                                                                              dec=4)
                 header += '%\n'
                 footer = 'M30\n'
 
@@ -5576,7 +5611,8 @@ class App(QtCore.QObject):
 
                 self.file_saved.emit("Excellon", filename)
                 self.inform.emit("[success] Excellon file exported to " + filename)
-            except:
+            except Exception as e:
+                log.debug("App.export_excellon.make_excellon() --> %s" % str(e))
                 return 'fail'
 
         if use_thread is True:

+ 6 - 11
FlatCAMGUI.py

@@ -154,19 +154,11 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         self.menufileexportexcellon = QtWidgets.QAction(QtGui.QIcon('share/drill32.png'), 'Export &Excellon ...', self)
         self.menufileexportexcellon.setToolTip(
             "Will export an Excellon Object as Excellon file,\n"
-            "the coordinates format is decimal and the file units\n"
-            "are the current units set in FlatCAM."
+            "the coordinates format, the file units and zeros\n"
+            "are set in Preferences -> Excellon Export."
         )
         self.menufileexport.addAction(self.menufileexportexcellon)
 
-        self.menufileexportexcellon_altium = QtWidgets.QAction(QtGui.QIcon('share/drill32.png'),
-                                                           'Export Excellon 2:4 LZ INCH ...', self)
-        self.menufileexportexcellon_altium.setToolTip(
-            "Will export an Excellon Object as Excellon file,\n"
-            "the coordinates format is 2:4, excellon zeros are LZ \n"
-            "and the file units are INCH."
-        )
-        self.menufileexport.addAction(self.menufileexportexcellon_altium)
 
         # Separator
         self.menufile.addSeparator()
@@ -428,10 +420,13 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         self.menuproject.addSeparator()
         self.menuprojectgeneratecnc = self.menuproject.addAction(QtGui.QIcon('share/cnc32.png'), 'Generate CNC')
         self.menuproject.addSeparator()
+
+        self.menuprojectedit = self.menuproject.addAction(QtGui.QIcon('share/edit_ok32.png'), 'Edit')
         self.menuprojectcopy = self.menuproject.addAction(QtGui.QIcon('share/copy32.png'), 'Copy')
         self.menuprojectdelete = self.menuproject.addAction(QtGui.QIcon('share/delete32.png'), 'Delete')
-        self.menuprojectedit = self.menuproject.addAction(QtGui.QIcon('share/edit_ok32.png'), 'Edit')
+        self.menuprojectsave= self.menuproject.addAction(QtGui.QIcon('share/save_as.png'), 'Save')
         self.menuproject.addSeparator()
+
         self.menuprojectproperties = self.menuproject.addAction(QtGui.QIcon('share/properties32.png'), 'Properties')
 
         ################

+ 118 - 116
FlatCAMObj.py

@@ -1612,102 +1612,64 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             item[0] = str(item[0])
         return table_tools_items
 
-    def export_excellon_decimals(self, whole, fract, units):
+    def export_excellon(self, whole, fract, e_zeros=None, form='dec', factor=1):
         """
         Returns two values, first is a boolean , if 1 then the file has slots and second contain the Excellon code
         :return: has_slots and Excellon_code
         """
 
         excellon_code = ''
-        units = units
 
         # store here if the file has slots, return 1 if any slots, 0 if only drills
         has_slots = 0
 
         # drills processing
         try:
-            for tool in self.tools:
-                if int(tool) < 10:
-                    excellon_code += 'T0' + str(tool) + '\n'
-                else:
-                    excellon_code += 'T' + str(tool) + '\n'
-
-                for drill in self.drills:
-                    if tool == drill['tool']:
-                        if units == 'MM':
-                            excellon_code += 'X' + '%.3f' % drill['point'].x + 'Y' + '%.3f' % drill['point'].y + '\n'
-                        else:
-                            excellon_code += 'X' + '%.4f' % drill['point'].x + 'Y' + '%.4f' % drill['point'].y + '\n'
-        except Exception as e:
-            log.debug(str(e))
-
-        # slots processing
-        try:
-            if self.slots:
-                has_slots = 1
+            if self.drills:
+                length = whole + fract
                 for tool in self.tools:
-                    if int(tool) < 10:
-                        excellon_code += 'T0' + str(tool) + '\n'
-                    else:
-                        excellon_code += 'T' + str(tool) + '\n'
-
-                    for slot in self.slots:
-                        if tool == slot['tool']:
-                            if units == 'MM':
-                                excellon_code += 'G00' + 'X' + '%.3f' % slot['start'].x + 'Y' + \
-                                                 '%.3f' % slot['start'].y + '\n'
-                                excellon_code += 'M15\n'
-                                excellon_code += 'G01' + 'X' + '%.3f' % slot['stop'].x + 'Y' + \
-                                                 '%.3f' % slot['stop'].y + '\n'
-                                excellon_code += 'M16\n'
-                            else:
-                                excellon_code += 'G00' + 'X' + '%.4f' % slot['start'].x + 'Y' + \
-                                                 '%.4f' % slot['start'].y + '\n'
-                                excellon_code += 'M15\n'
-                                excellon_code += 'G01' + 'X' + '%.4f' % slot['stop'].x + 'Y' + \
-                                                 '%.4f' % slot['stop'].y + '\n'
-                                excellon_code += 'M16\n'
-        except Exception as e:
-            log.debug(str(e))
-
-        return has_slots, excellon_code
-
-    def export_excellon_ndecimals(self, whole, fract, units):
-        """
-        Returns two values, first is a boolean , if 1 then the file has slots and second contain the Excellon code
-        :return: has_slots and Excellon_code
-        """
-
-        excellon_code = ''
-        units = units
-
-        # store here if the file has slots, return 1 if any slots, 0 if only drills
-        has_slots = 0
-
-        # drills processing
-        try:
-            for tool in self.tools:
-                if int(tool) < 10:
-                    excellon_code += 'T0' + str(tool) + '\n'
-                else:
-                    excellon_code += 'T' + str(tool) + '\n'
-
-                for drill in self.drills:
-                    if tool == drill['tool']:
-                        drill_x = drill['point'].x
-                        drill_y = drill['point'].y
-                        if units == 'MM':
-                            drill_x /= 25.4
-                            drill_y /= 25.4
-                        exc_x_formatted = ('%.4f' % drill_x).replace('.', '')
-                        if drill_x < 10:
-                            exc_x_formatted = '0' + exc_x_formatted
-
-                        exc_y_formatted = ('%.4f' % drill_y).replace('.', '')
-                        if drill_y < 10:
-                            exc_y_formatted = '0' + exc_y_formatted
-
-                        excellon_code += 'X' + exc_x_formatted + 'Y' + exc_y_formatted + '\n'
+                    excellon_code += 'T0%s\n' % str(tool) if int(tool) < 10 else 'T%s\n' % str(tool)
+
+                    for drill in self.drills:
+                        if form == 'dec' and tool == drill['tool']:
+                            drill_x = drill['point'].x * factor
+                            drill_y = drill['point'].y * factor
+                            excellon_code += "X{:.{dec}f}Y{:.{dec}f}\n".format(drill_x, drill_y, dec=fract)
+                        elif e_zeros == 'LZ' and tool == drill['tool']:
+                            drill_x = drill['point'].x * factor
+                            drill_y = drill['point'].y * factor
+
+                            exc_x_formatted = "{:.{dec}f}".format(drill_x, dec=fract)
+                            exc_y_formatted = "{:.{dec}f}".format(drill_y, dec=fract)
+
+                            # extract whole part and decimal part
+                            exc_x_formatted = exc_x_formatted.partition('.')
+                            exc_y_formatted = exc_y_formatted.partition('.')
+
+                            # left padd the 'whole' part with zeros
+                            x_whole = exc_x_formatted[0].rjust(whole, '0')
+                            y_whole = exc_y_formatted[0].rjust(whole, '0')
+
+                            # restore the coordinate padded in the left with 0 and added the decimal part
+                            # without the decinal dot
+                            exc_x_formatted = x_whole + exc_x_formatted[2]
+                            exc_y_formatted = y_whole + exc_y_formatted[2]
+
+                            excellon_code += "X{xform}Y{yform}\n".format(xform=exc_x_formatted,
+                                                                         yform=exc_y_formatted)
+                        elif tool == drill['tool']:
+                            drill_x = drill['point'].x * factor
+                            drill_y = drill['point'].y * factor
+
+                            exc_x_formatted = "{:.{dec}f}".format(drill_x, dec=fract).replace('.', '')
+                            exc_y_formatted = "{:.{dec}f}".format(drill_y, dec=fract).replace('.', '')
+
+                            # pad with rear zeros
+                            exc_x_formatted.ljust(length, '0')
+                            exc_y_formatted.ljust(length, '0')
+
+                            excellon_code += "X{xform}Y{yform}\n".format(xform=exc_x_formatted,
+                                                                         yform=exc_y_formatted)
         except Exception as e:
             log.debug(str(e))
 
@@ -1722,42 +1684,82 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
                         excellon_code += 'T' + str(tool) + '\n'
 
                     for slot in self.slots:
-                        if tool == slot['tool']:
-                            start_slot_x = slot['start'].x
-                            start_slot_y = slot['start'].y
-                            stop_slot_x = slot['stop'].x
-                            stop_slot_y = slot['stop'].y
-                            if units == 'MM':
-                                start_slot_x /= 25.4
-                                start_slot_y /= 25.4
-                                stop_slot_x /= 25.4
-                                stop_slot_y /= 25.4
-
-                            start_slot_x_formatted = ('%.4f' % start_slot_x).replace('.', '')
-                            if start_slot_x < 10:
-                                start_slot_x_formatted = '0' + start_slot_x_formatted
-
-                            start_slot_y_formatted = ('%.4f' % start_slot_y).replace('.', '')
-                            if start_slot_y < 10:
-                                start_slot_y_formatted = '0' + start_slot_y_formatted
-
-                            stop_slot_x_formatted = ('%.4f' % stop_slot_x).replace('.', '')
-                            if stop_slot_x < 10:
-                                stop_slot_x_formatted = '0' + stop_slot_x_formatted
-
-                            stop_slot_y_formatted = ('%.4f' % stop_slot_y).replace('.', '')
-                            if stop_slot_y < 10:
-                                stop_slot_y_formatted = '0' + stop_slot_y_formatted
-
-                            excellon_code += 'G00' + 'X' + start_slot_x_formatted + 'Y' + \
-                                             start_slot_y_formatted + '\n'
-                            excellon_code += 'M15\n'
-                            excellon_code += 'G01' + 'X' + stop_slot_x_formatted + 'Y' + \
-                                             stop_slot_y_formatted + '\n'
-                            excellon_code += 'M16\n'
+                        if form == 'dec' and tool == slot['tool']:
+                            start_slot_x = slot['start'].x * factor
+                            start_slot_y = slot['start'].y * factor
+                            stop_slot_x = slot['stop'].x * factor
+                            stop_slot_y = slot['stop'].y * factor
+
+                            excellon_code += "G00X{:.{dec}f}Y{:.{dec}f}\nM15\n".format(start_slot_x,
+                                                                                       start_slot_y,
+                                                                                       dec=fract)
+                            excellon_code += "G00X{:.{dec}f}Y{:.{dec}f}\nM16\n".format(stop_slot_x,
+                                                                                       stop_slot_y,
+                                                                                       dec=fract)
+
+                        elif e_zeros == 'LZ' and tool == slot['tool']:
+                            start_slot_x = slot['start'].x * factor
+                            start_slot_y = slot['start'].y * factor
+                            stop_slot_x = slot['stop'].x * factor
+                            stop_slot_y = slot['stop'].y * factor
+
+                            start_slot_x_formatted = "{:.{dec}f}".format(start_slot_x, dec=fract).replace('.', '')
+                            start_slot_y_formatted = "{:.{dec}f}".format(start_slot_y, dec=fract).replace('.', '')
+                            stop_slot_x_formatted = "{:.{dec}f}".format(stop_slot_x, dec=fract).replace('.', '')
+                            stop_slot_y_formatted = "{:.{dec}f}".format(stop_slot_y, dec=fract).replace('.', '')
+
+                            # extract whole part and decimal part
+                            start_slot_x_formatted = start_slot_x_formatted.partition('.')
+                            start_slot_y_formatted = start_slot_y_formatted.partition('.')
+                            stop_slot_x_formatted = stop_slot_x_formatted.partition('.')
+                            stop_slot_y_formatted = stop_slot_y_formatted.partition('.')
+
+                            # left padd the 'whole' part with zeros
+                            start_x_whole = start_slot_x_formatted[0].rjust(whole, '0')
+                            start_y_whole = start_slot_y_formatted[0].rjust(whole, '0')
+                            stop_x_whole = stop_slot_x_formatted[0].rjust(whole, '0')
+                            stop_y_whole = stop_slot_y_formatted[0].rjust(whole, '0')
+
+                            # restore the coordinate padded in the left with 0 and added the decimal part
+                            # without the decinal dot
+                            start_slot_x_formatted = start_x_whole + start_slot_x_formatted[2]
+                            start_slot_y_formatted = start_y_whole + start_slot_y_formatted[2]
+                            stop_slot_x_formatted = stop_x_whole + stop_slot_x_formatted[2]
+                            stop_slot_y_formatted = stop_y_whole + stop_slot_y_formatted[2]
+
+                            excellon_code += "G00X{xstart}Y{ystart}\nM15\n".format(xstart=start_slot_x_formatted,
+                                                                                   ystart=start_slot_y_formatted)
+                            excellon_code += "G00X{xstop}Y{ystop}\nM16\n".format(xstop=stop_slot_x_formatted,
+                                                                                 ystop=stop_slot_y_formatted)
+                        elif tool == slot['tool']:
+                            start_slot_x = slot['start'].x * factor
+                            start_slot_y = slot['start'].y * factor
+                            stop_slot_x = slot['stop'].x * factor
+                            stop_slot_y = slot['stop'].y * factor
+                            length = whole + fract
+
+                            start_slot_x_formatted = "{:.{dec}f}".format(start_slot_x, dec=fract).replace('.', '')
+                            start_slot_y_formatted = "{:.{dec}f}".format(start_slot_y, dec=fract).replace('.', '')
+                            stop_slot_x_formatted = "{:.{dec}f}".format(stop_slot_x, dec=fract).replace('.', '')
+                            stop_slot_y_formatted = "{:.{dec}f}".format(stop_slot_y, dec=fract).replace('.', '')
+
+                            # pad with rear zeros
+                            start_slot_x_formatted.ljust(length, '0')
+                            start_slot_y_formatted.ljust(length, '0')
+                            stop_slot_x_formatted.ljust(length, '0')
+                            stop_slot_y_formatted.ljust(length, '0')
+
+                            excellon_code += "G00X{xstart}Y{ystart}\nM15\n".format(xstart=start_slot_x_formatted,
+                                                                                   ystart=start_slot_y_formatted)
+                            excellon_code += "G00X{xstop}Y{ystop}\nM16\n".format(xstop=stop_slot_x_formatted,
+                                                                                 ystop=stop_slot_y_formatted)
         except Exception as e:
             log.debug(str(e))
 
+        if not self.drills and not self.slots:
+            log.debug("FlatCAMObj.FlatCAMExcellon.export_excellon() --> Excellon Object is empty: no drills, no slots.")
+            return 'fail'
+
         return has_slots, excellon_code
 
     def generate_milling_drills(self, tools=None, outname=None, tooldia=None, use_thread=False):

+ 3 - 0
ObjectCollection.py

@@ -507,17 +507,20 @@ class ObjectCollection(QtCore.QAbstractItemModel):
         self.app.ui.menuprojectcopy.setEnabled(sel)
         self.app.ui.menuprojectedit.setEnabled(sel)
         self.app.ui.menuprojectdelete.setEnabled(sel)
+        self.app.ui.menuprojectsave.setEnabled(sel)
         self.app.ui.menuprojectproperties.setEnabled(sel)
 
         if sel:
             self.app.ui.menuprojectgeneratecnc.setVisible(True)
             self.app.ui.menuprojectedit.setVisible(True)
+            self.app.ui.menuprojectsave.setVisible(True)
 
             for obj in self.get_selected():
                 if type(obj) != FlatCAMGeometry:
                     self.app.ui.menuprojectgeneratecnc.setVisible(False)
                 if type(obj) != FlatCAMGeometry and type(obj) != FlatCAMExcellon:
                     self.app.ui.menuprojectedit.setVisible(False)
+                    self.app.ui.menuprojectsavet.setVisible(False)
         else:
             self.app.ui.menuprojectgeneratecnc.setVisible(False)
 

+ 3 - 1
README.md

@@ -11,9 +11,11 @@ CAD program, and create G-Code for Isolation routing.
 
 15.02.2019
 
-- rearranged the FIle and Edit menu's and added some explanatory tooltips on certain menu items that could be seen as cryptic
+- rearranged the File and Edit menu's and added some explanatory tooltips on certain menu items that could be seen as cryptic
 - added Excellon Export Options in Edit -> Preferences
 - started to work in using the Excellon Export parameters
+- remade the Excellon export function to work with parameters entered in Edit -> Preferences -> Excellon Export
+- added a new entry in the Project Context Menu named 'Save'. It will actually work for Geometry and it will do Export DXF and for Excellon and it will do Export Excellon
 
 14.02.2019