Procházet zdrojové kódy

- fixed the --shellvar and --shellfile FlatCAM arguments to work together but the --shellvar has precedence over --shellfile as it is most likely that whatever variable set by --shellvar will be used in the script file run by --shellfile

Marius Stanciu před 6 roky
rodič
revize
8958ef8007
4 změnil soubory, kde provedl 291 přidání a 56 odebrání
  1. 161 34
      FlatCAMApp.py
  2. 4 0
      README.md
  3. 9 8
      flatcamEditors/FlatCAMGrbEditor.py
  4. 117 14
      flatcamGUI/FlatCAMGUI.py

+ 161 - 34
FlatCAMApp.py

@@ -1163,12 +1163,13 @@ class App(QtCore.QObject):
             "tools_sub_close_paths": True,
 
             # file associations
-            "fa_excellon": ".drl, .xln, .drd, .tap, .exc, .ncd",
-            "fa_gcode": ".nc, .ncc, .tap, .gcode, .cnc, .ecs, .fnc, .dnc, .ncg, .gc, .fan, .fgc, .din, .xpi,"
-                        " .hnc, .h, .i, .ncp, .min, .gcd, .rol, .mpr, .ply, .out, .eia, .plt, .sbp, .mpf",
-            "fa_gerber": ".gbr, .ger, .gtl, .gbl, .gts, .gbs, .gtp, .gbp, .gto, .gbo, .gm1, .gml, .gm3, .gko, .cmp, "
-                         ".sol, .stc, .sts, .plc, .pls, .crc, .crs, .tsm, .bsm, .ly2, .ly15, .dim, .mil, .grb, .top, "
-                         ".bot, .smt, .smb, .sst, .ssb, .spt, .spb, .pho, .gdo, .art, .gbd",
+            "fa_excellon": 'drd, drl, exc, ncd, tap, xln',
+            "fa_gcode": 'cnc, din, dnc, ecs, eia, fan, fgc, fnc, gc, gcd, gcode, h, hnc, i, min, mpf, mpr, nc, ncc, '
+                        'ncg, ncp, out, plt, ply, rol, sbp, tap, xpi',
+            "fa_gerber": 'art, bot, bsm, cmp, crc, crs, dim, g4, gb0, gb1, gb2, gb3, gb5, gb6, gb7, gb8, gb9, gbd, '
+                         'gbl, gbo, gbp, gbr, gbs, gdo, ger, gko, gm1, gm2, gm3, grb, gtl, gto, gtp, gts, ly15, ly2, '
+                         'mil, pho, plc, pls, smb, smt, sol, spb, spt, ssb, sst, stc, sts, top, tsm'
+,
         })
 
         # ############################################################
@@ -1913,6 +1914,38 @@ class App(QtCore.QObject):
         # when there are arguments at application startup this get launched
         self.args_at_startup[list].connect(self.on_startup_args)
 
+        # ##############################################################
+        # ############### FILE ASSOCIATIONS SIGNALS ####################
+        # ##############################################################
+
+        self.ui.fa_defaults_form.fa_excellon_group.restore_btn.clicked.connect(
+            lambda: self.restore_extensions(ext_type='excellon'))
+        self.ui.fa_defaults_form.fa_gcode_group.restore_btn.clicked.connect(
+            lambda: self.restore_extensions(ext_type='gcode'))
+        self.ui.fa_defaults_form.fa_gerber_group.restore_btn.clicked.connect(
+            lambda: self.restore_extensions(ext_type='gerber'))
+
+        self.ui.fa_defaults_form.fa_excellon_group.del_all_btn.clicked.connect(
+            lambda: self.delete_all_extensions(ext_type='excellon'))
+        self.ui.fa_defaults_form.fa_gcode_group.del_all_btn.clicked.connect(
+            lambda: self.delete_all_extensions(ext_type='gcode'))
+        self.ui.fa_defaults_form.fa_gerber_group.del_all_btn.clicked.connect(
+            lambda: self.delete_all_extensions(ext_type='gerber'))
+
+        self.ui.fa_defaults_form.fa_excellon_group.add_btn.clicked.connect(
+            lambda: self.add_extension(ext_type='excellon'))
+        self.ui.fa_defaults_form.fa_gcode_group.add_btn.clicked.connect(
+            lambda: self.add_extension(ext_type='gcode'))
+        self.ui.fa_defaults_form.fa_gerber_group.add_btn.clicked.connect(
+            lambda: self.add_extension(ext_type='gerber'))
+
+        self.ui.fa_defaults_form.fa_excellon_group.del_btn.clicked.connect(
+            lambda: self.del_extension(ext_type='excellon'))
+        self.ui.fa_defaults_form.fa_gcode_group.del_btn.clicked.connect(
+            lambda: self.del_extension(ext_type='gcode'))
+        self.ui.fa_defaults_form.fa_gerber_group.del_btn.clicked.connect(
+            lambda: self.del_extension(ext_type='gerber'))
+
         # connect the 'Apply' buttons from the Preferences/File Associations
         self.ui.fa_defaults_form.fa_excellon_group.exc_list_btn.clicked.connect(
             lambda: self.on_register_files(obj_type='excellon'))
@@ -2312,16 +2345,16 @@ class App(QtCore.QObject):
         # if Preferences are changed in the Edit -> Preferences tab the value will be set to True
         self.preferences_changed_flag = False
 
-        self.grb_list = ['gbr', 'ger', 'gtl', 'gbl', 'gts', 'gbs', 'gtp', 'gbp', 'gto', 'gbo', 'gm1', 'gm2', 'gm3',
-                         'gko', 'cmp', 'sol', 'stc', 'sts', 'plc', 'pls', 'crc', 'crs', 'tsm', 'bsm', 'ly2', 'ly15',
-                         'dim', 'mil', 'grb', 'top', 'bot', 'smt', 'smb', 'sst', 'ssb', 'spt', 'spb', 'pho', 'gdo',
-                         'art', 'gbd', 'gb0', 'gb1', 'gb2', 'gb3', 'g4', 'gb5', 'gb6', 'gb7', 'gb8', 'gb9'
-                         ]
-        self.exc_list = ['drl', 'txt', 'xln', 'drd', 'tap', 'exc', 'ncd']
-        self.gcode_list = ['nc', 'ncc', 'tap', 'gcode', 'cnc', 'ecs', 'fnc', 'dnc', 'ncg', 'gc', 'fan', 'fgc', 'din',
-                           'xpi', 'hnc', 'h', 'i', 'ncp', 'min', 'gcd', 'rol', 'mpr', 'ply', 'out', 'eia', 'plt', 'sbp',
-                           'mpf'
-                           ]
+        self.grb_list = ['art', 'bot', 'bsm', 'cmp', 'crc', 'crs', 'dim', 'g4', 'gb0', 'gb1', 'gb2', 'gb3', 'gb5',
+                         'gb6', 'gb7', 'gb8', 'gb9', 'gbd', 'gbl', 'gbo', 'gbp', 'gbr', 'gbs', 'gdo', 'ger', 'gko',
+                         'gml', 'gm1', 'gm2', 'gm3', 'grb', 'gtl', 'gto', 'gtp', 'gts', 'ly15', 'ly2', 'mil', 'pho',
+                         'plc', 'pls', 'smb', 'smt', 'sol', 'spb', 'spt', 'ssb', 'sst', 'stc', 'sts', 'top', 'tsm']
+
+        self.exc_list = ['drd', 'drl', 'exc', 'ncd', 'tap', 'txt', 'xln']
+
+        self.gcode_list = ['cnc', 'din', 'dnc', 'ecs', 'eia', 'fan', 'fgc', 'fnc', 'gc', 'gcd', 'gcode', 'h', 'hnc',
+                           'i', 'min', 'mpf', 'mpr', 'nc', 'ncc', 'ncg', 'ncp', 'out', 'plt', 'ply', 'rol', 'sbp',
+                           'tap', 'xpi']
         self.svg_list = ['svg']
         self.dxf_list = ['dxf']
         self.pdf_list = ['pdf']
@@ -4582,19 +4615,19 @@ class App(QtCore.QObject):
 
             # register all keys in the Preferences window
             for ext in exc_list:
-                new_k = new_reg_path + ext
+                new_k = new_reg_path + '.%s' % ext
                 set_reg('', root_path=root_path, new_reg_path=new_k, value='FlatCAM')
 
             # and unregister those that are no longer in the Preferences windows but are in the file
             for ext in self.defaults["fa_excellon"].replace(' ', '').split(','):
                 if ext not in exc_list:
-                    delete_reg(root_path=root_path, reg_path=new_reg_path, key_to_del=ext)
+                    delete_reg(root_path=root_path, reg_path=new_reg_path, key_to_del='.%s' % ext)
 
             # now write the updated extensions to the self.defaults
-            new_ext = ''
-            for ext in exc_list:
-                new_ext = new_ext + ext + ', '
-            self.defaults["fa_excellon"] = new_ext
+            # new_ext = ''
+            # for ext in exc_list:
+            #     new_ext = new_ext + ext + ', '
+            # self.defaults["fa_excellon"] = new_ext
             self.inform.emit('[success] %s' % _("Selected Excellon file extensions registered with FlatCAM."))
 
         if obj_type is None or obj_type == 'gcode':
@@ -4603,19 +4636,19 @@ class App(QtCore.QObject):
 
             # register all keys in the Preferences window
             for ext in gco_list:
-                new_k = new_reg_path + ext
+                new_k = new_reg_path + '.%s' % ext
                 set_reg('', root_path=root_path, new_reg_path=new_k, value='FlatCAM')
 
             # and unregister those that are no longer in the Preferences windows but are in the file
             for ext in self.defaults["fa_gcode"].replace(' ', '').split(','):
                 if ext not in gco_list:
-                    delete_reg(root_path=root_path, reg_path=new_reg_path, key_to_del=ext)
+                    delete_reg(root_path=root_path, reg_path=new_reg_path, key_to_del='.%s' % ext)
 
             # now write the updated extensions to the self.defaults
-            new_ext = ''
-            for ext in gco_list:
-                new_ext = new_ext + ext + ', '
-            self.defaults["fa_gcode"] = new_ext
+            # new_ext = ''
+            # for ext in gco_list:
+            #     new_ext = new_ext + ext + ', '
+            # self.defaults["fa_gcode"] = new_ext
             self.inform.emit('[success] %s' %
                              _("Selected GCode file extensions registered with FlatCAM."))
 
@@ -4625,22 +4658,116 @@ class App(QtCore.QObject):
 
             # register all keys in the Preferences window
             for ext in grb_list:
-                new_k = new_reg_path + ext
+                new_k = new_reg_path + '.%s' % ext
                 set_reg('', root_path=root_path, new_reg_path=new_k, value='FlatCAM')
 
             # and unregister those that are no longer in the Preferences windows but are in the file
             for ext in self.defaults["fa_gerber"].replace(' ', '').split(','):
                 if ext not in grb_list:
-                    delete_reg(root_path=root_path, reg_path=new_reg_path, key_to_del=ext)
+                    delete_reg(root_path=root_path, reg_path=new_reg_path, key_to_del='.%s' % ext)
 
             # now write the updated extensions to the self.defaults
-            new_ext = ''
-            for ext in grb_list:
-                new_ext = new_ext + ext + ', '
-            self.defaults["fa_gerber"] = new_ext
+            # new_ext = ''
+            # for ext in grb_list:
+            #     new_ext = new_ext + ext + ', '
+            # self.defaults["fa_gerber"] = new_ext
             self.inform.emit('[success] %s' %
                              _("Selected Gerber file extensions registered with FlatCAM."))
 
+    def add_extension(self, ext_type):
+        if ext_type == 'excellon':
+            new_ext = self.ui.fa_defaults_form.fa_excellon_group.ext_entry.get_value()
+            if new_ext == '':
+                return
+
+            old_val = self.ui.fa_defaults_form.fa_excellon_group.exc_list_text.get_value().replace(' ', '').split(',')
+            if new_ext in old_val:
+                return
+            old_val.append(new_ext)
+            old_val.sort()
+            self.ui.fa_defaults_form.fa_excellon_group.exc_list_text.set_value(', '.join(old_val))
+        if ext_type == 'gcode':
+            new_ext = self.ui.fa_defaults_form.fa_gcode_group.ext_entry.get_value()
+            if new_ext == '':
+                return
+
+            old_val = self.ui.fa_defaults_form.fa_gcode_group.gco_list_text.get_value().replace(' ', '').split(',')
+            if new_ext in old_val:
+                return
+            old_val.append(new_ext)
+            old_val.sort()
+            self.ui.fa_defaults_form.fa_gcode_group.gco_list_text.set_value(', '.join(old_val))
+        if ext_type == 'gerber':
+            new_ext = self.ui.fa_defaults_form.fa_gerber_group.ext_entry.get_value()
+            if new_ext == '':
+                return
+
+            old_val = self.ui.fa_defaults_form.fa_gerber_group.grb_list_text.get_value().replace(' ', '').split(',')
+            if new_ext in old_val:
+                return
+            old_val.append(new_ext)
+            old_val.sort()
+            self.ui.fa_defaults_form.fa_gerber_group.grb_list_text.set_value(', '.join(old_val))
+
+    def del_extension(self, ext_type):
+        if ext_type == 'excellon':
+            new_ext = self.ui.fa_defaults_form.fa_excellon_group.ext_entry.get_value()
+            if new_ext == '':
+                return
+
+            old_val = self.ui.fa_defaults_form.fa_excellon_group.exc_list_text.get_value().replace(' ', '').split(',')
+            if new_ext not in old_val:
+                return
+            old_val.remove(new_ext)
+            old_val.sort()
+            self.ui.fa_defaults_form.fa_excellon_group.exc_list_text.set_value(', '.join(old_val))
+        if ext_type == 'gcode':
+            new_ext = self.ui.fa_defaults_form.fa_gcode_group.ext_entry.get_value()
+            if new_ext == '':
+                return
+
+            old_val = self.ui.fa_defaults_form.fa_gcode_group.gco_list_text.get_value().replace(' ', '').split(',')
+            if new_ext not in old_val:
+                return
+            old_val.remove(new_ext)
+            old_val.sort()
+            self.ui.fa_defaults_form.fa_gcode_group.gco_list_text.set_value(', '.join(old_val))
+        if ext_type == 'gerber':
+            new_ext = self.ui.fa_defaults_form.fa_gerber_group.ext_entry.get_value()
+            if new_ext == '':
+                return
+
+            old_val = self.ui.fa_defaults_form.fa_gerber_group.grb_list_text.get_value().replace(' ', '').split(',')
+            if new_ext not in old_val:
+                return
+            old_val.remove(new_ext)
+            old_val.sort()
+            self.ui.fa_defaults_form.fa_gerber_group.grb_list_text.set_value(', '.join(old_val))
+
+    def restore_extensions(self, ext_type):
+        if ext_type == 'excellon':
+            # don't add 'txt' to the associations (too many files are .txt and not Excellon) but keep it in the list
+            # for the ability to open Excellon files with .txt extension
+            new_exc_list = deepcopy(self.exc_list)
+
+            try:
+                new_exc_list.remove('txt')
+            except ValueError:
+                pass
+            self.ui.fa_defaults_form.fa_excellon_group.exc_list_text.set_value(', '.join(new_exc_list))
+        if ext_type == 'gcode':
+            self.ui.fa_defaults_form.fa_gcode_group.gco_list_text.set_value(', '.join(self.gcode_list))
+        if ext_type == 'gerber':
+            self.ui.fa_defaults_form.fa_gerber_group.grb_list_text.set_value(', '.join(self.grb_list))
+
+    def delete_all_extensions(self, ext_type):
+        if ext_type == 'excellon':
+            self.ui.fa_defaults_form.fa_excellon_group.exc_list_text.set_value('')
+        if ext_type == 'gcode':
+            self.ui.fa_defaults_form.fa_gcode_group.gco_list_text.set_value('')
+        if ext_type == 'gerber':
+            self.ui.fa_defaults_form.fa_gerber_group.grb_list_text.set_value('')
+
     def on_edit_join(self, name=None):
         """
         Callback for Edit->Join. Joins the selected geometry objects into

+ 4 - 0
README.md

@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
 
 =================================================
 
+18.09.2019
+
+- added more funtionality to the Extension registration with FLatCAM and added to the GUI in Edit -> Preferences -> Utilities
+
 17.09.2019
 
 - added more programmers that contributed to FlatCAM over the years, in the "About FlatCAM" -> Programmers window

+ 9 - 8
flatcamEditors/FlatCAMGrbEditor.py

@@ -3742,7 +3742,6 @@ class FlatCAMGrbEditor(QtCore.QObject):
                 #             temp_elem.append(deepcopy(new_elem))
                 for elem in self.gerber_obj.apertures[apid]['geometry']:
                     new_elem = dict()
-
                     if 'solid' in elem:
                         solid_geo = elem['solid']
                         for clear_geo in global_clear_geo:
@@ -4434,16 +4433,18 @@ class FlatCAMGrbEditor(QtCore.QObject):
                             self.plot_shape(geometry=geometric_data,
                                             color=self.app.defaults['global_sel_draw_color'],
                                             linewidth=2)
-                            continue
-                        self.plot_shape(geometry=geometric_data,
-                                        color=self.app.defaults['global_draw_color'])
+
+                        else:
+                            self.plot_shape(geometry=geometric_data,
+                                            color=self.app.defaults['global_draw_color'])
                 except KeyError:
                     pass
 
-            for elem in self.utility:
-                geometric_data = elem.geo['solid']
-                self.plot_shape(geometry=geometric_data, linewidth=1)
-                continue
+            if self.utility:
+                for elem in self.utility:
+                    geometric_data = elem.geo['solid']
+                    self.plot_shape(geometry=geometric_data, linewidth=1)
+                    continue
 
             self.shapes.redraw()
 

+ 117 - 14
flatcamGUI/FlatCAMGUI.py

@@ -958,7 +958,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
 
         self.fa_tab = QtWidgets.QWidget()
         self.fa_tab.setObjectName("fa_tab")
-        self.pref_tab_area.addTab(self.fa_tab, _("FILE ASSOCIATIONS"))
+        self.pref_tab_area.addTab(self.fa_tab, _("UTILITIES"))
         self.fa_tab_lay = QtWidgets.QVBoxLayout()
         self.fa_tab_lay.setContentsMargins(2, 2, 2, 2)
         self.fa_tab.setLayout(self.fa_tab_lay)
@@ -7794,34 +7794,77 @@ class ToolsSubPrefGroupUI(OptionsGroupUI):
 class FAExcPrefGroupUI(OptionsGroupUI):
     def __init__(self, parent=None):
         # OptionsGroupUI.__init__(self, "Excellon File associations Preferences", parent=None)
-        super(FAExcPrefGroupUI, self).__init__(self)
+        super().__init__(self)
 
         self.setTitle(str(_("Excellon File associations")))
 
-        # ## Export G-Code
-        self.exc_list_label = QtWidgets.QLabel("<b>%s:</b>" % _("Extensions list"))
-        self.exc_list_label.setToolTip(
+        self.layout.setContentsMargins(2, 2, 2, 2)
+
+        self.vertical_lay = QtWidgets.QVBoxLayout()
+        scroll_widget = QtWidgets.QWidget()
+
+        scroll = VerticalScrollArea()
+        scroll.setWidget(scroll_widget)
+        scroll.setWidgetResizable(True)
+        scroll.setFrameShape(QtWidgets.QFrame.NoFrame)
+
+        self.restore_btn = FCButton(_("Restore"))
+        self.restore_btn.setToolTip(_("Restore the extension list to the default state."))
+        self.del_all_btn = FCButton(_("Delete All"))
+        self.del_all_btn.setToolTip(_("Delete all extensions from the list."))
+
+        hlay0 = QtWidgets.QHBoxLayout()
+        hlay0.addWidget(self.restore_btn)
+        hlay0.addWidget(self.del_all_btn)
+        self.vertical_lay.addLayout(hlay0)
+
+        # # ## Excellon associations
+        list_label = QtWidgets.QLabel("<b>%s:</b>" % _("Extensions list"))
+        list_label.setToolTip(
             _("List of file extensions to be\n"
               "associated with FlatCAM.")
         )
-        self.layout.addWidget(self.exc_list_label)
+        self.vertical_lay.addWidget(list_label)
 
         self.exc_list_text = FCTextArea()
+        self.exc_list_text.setReadOnly(True)
         # self.exc_list_text.sizeHint(custom_sizehint=150)
         font = QtGui.QFont()
         font.setPointSize(12)
         self.exc_list_text.setFont(font)
 
-        self.layout.addWidget(self.exc_list_text)
+        self.vertical_lay.addWidget(self.exc_list_text)
+
+        self.ext_label = QtWidgets.QLabel('%s:' % _("Extension"))
+        self.ext_label.setToolTip(_("A file extension to be added or deleted to the list."))
+        self.ext_entry = FCEntry()
+
+        hlay1 = QtWidgets.QHBoxLayout()
+        self.vertical_lay.addLayout(hlay1)
+        hlay1.addWidget(self.ext_label)
+        hlay1.addWidget(self.ext_entry)
+
+        self.add_btn = FCButton(_("Add Extension"))
+        self.add_btn.setToolTip(_("Add a file extension to the list"))
+        self.del_btn = FCButton(_("Delete Extension"))
+        self.del_btn.setToolTip(_("Delete a file extension from the list"))
+
+        hlay2 = QtWidgets.QHBoxLayout()
+        self.vertical_lay.addLayout(hlay2)
+        hlay2.addWidget(self.add_btn)
+        hlay2.addWidget(self.del_btn)
 
-        self.exc_list_btn = FCButton(_("Apply"))
+        self.exc_list_btn = FCButton(_("Apply Association"))
         self.exc_list_btn.setToolTip(_("Apply the file associations between\n"
                                        "FlatCAM and the files with above extensions.\n"
                                        "They will be active after next logon.\n"
                                        "This work only in Windows."))
-        self.layout.addWidget(self.exc_list_btn)
+        self.vertical_lay.addWidget(self.exc_list_btn)
 
-        # self.layout.addStretch()
+        scroll_widget.setLayout(self.vertical_lay)
+        self.layout.addWidget(scroll)
+
+        # self.vertical_lay.addStretch()
 
 
 class FAGcoPrefGroupUI(OptionsGroupUI):
@@ -7831,7 +7874,17 @@ class FAGcoPrefGroupUI(OptionsGroupUI):
 
         self.setTitle(str(_("GCode File associations")))
 
-        # ## Export G-Code
+        self.restore_btn = FCButton(_("Restore"))
+        self.restore_btn.setToolTip(_("Restore the extension list to the default state."))
+        self.del_all_btn = FCButton(_("Delete All"))
+        self.del_all_btn.setToolTip(_("Delete all extensions from the list."))
+
+        hlay0 = QtWidgets.QHBoxLayout()
+        self.layout.addLayout(hlay0)
+        hlay0.addWidget(self.restore_btn)
+        hlay0.addWidget(self.del_all_btn)
+
+        # ## G-Code associations
         self.gco_list_label = QtWidgets.QLabel("<b>%s:</b>" % _("Extensions list"))
         self.gco_list_label.setToolTip(
             _("List of file extensions to be\n"
@@ -7840,6 +7893,7 @@ class FAGcoPrefGroupUI(OptionsGroupUI):
         self.layout.addWidget(self.gco_list_label)
 
         self.gco_list_text = FCTextArea()
+        self.gco_list_text.setReadOnly(True)
         # self.gco_list_text.sizeHint(custom_sizehint=150)
         font = QtGui.QFont()
         font.setPointSize(12)
@@ -7847,7 +7901,26 @@ class FAGcoPrefGroupUI(OptionsGroupUI):
 
         self.layout.addWidget(self.gco_list_text)
 
-        self.gco_list_btn = FCButton(_("Apply"))
+        self.ext_label = QtWidgets.QLabel('%s:' % _("Extension"))
+        self.ext_label.setToolTip(_("A file extension to be added or deleted to the list."))
+        self.ext_entry = FCEntry()
+
+        hlay1 = QtWidgets.QHBoxLayout()
+        self.layout.addLayout(hlay1)
+        hlay1.addWidget(self.ext_label)
+        hlay1.addWidget(self.ext_entry)
+
+        self.add_btn = FCButton(_("Add Extension"))
+        self.add_btn.setToolTip(_("Add a file extension to the list"))
+        self.del_btn = FCButton(_("Delete Extension"))
+        self.del_btn.setToolTip(_("Delete a file extension from the list"))
+
+        hlay2 = QtWidgets.QHBoxLayout()
+        self.layout.addLayout(hlay2)
+        hlay2.addWidget(self.add_btn)
+        hlay2.addWidget(self.del_btn)
+
+        self.gco_list_btn = FCButton(_("Apply Association"))
         self.gco_list_btn.setToolTip(_("Apply the file associations between\n"
                                        "FlatCAM and the files with above extensions.\n"
                                        "They will be active after next logon.\n"
@@ -7864,7 +7937,17 @@ class FAGrbPrefGroupUI(OptionsGroupUI):
 
         self.setTitle(str(_("Gerber File associations")))
 
-        # ## Export G-Code
+        self.restore_btn = FCButton(_("Restore"))
+        self.restore_btn.setToolTip(_("Restore the extension list to the default state."))
+        self.del_all_btn = FCButton(_("Delete All"))
+        self.del_all_btn.setToolTip(_("Delete all extensions from the list."))
+
+        hlay0 = QtWidgets.QHBoxLayout()
+        self.layout.addLayout(hlay0)
+        hlay0.addWidget(self.restore_btn)
+        hlay0.addWidget(self.del_all_btn)
+
+        # ## Gerber associations
         self.grb_list_label = QtWidgets.QLabel("<b>%s:</b>" % _("Extensions list"))
         self.grb_list_label.setToolTip(
             _("List of file extensions to be\n"
@@ -7873,13 +7956,33 @@ class FAGrbPrefGroupUI(OptionsGroupUI):
         self.layout.addWidget(self.grb_list_label)
 
         self.grb_list_text = FCTextArea()
+        self.grb_list_text.setReadOnly(True)
         # self.grb_list_text.sizeHint(custom_sizehint=150)
         self.layout.addWidget(self.grb_list_text)
         font = QtGui.QFont()
         font.setPointSize(12)
         self.grb_list_text.setFont(font)
 
-        self.grb_list_btn = FCButton(_("Apply"))
+        self.ext_label = QtWidgets.QLabel('%s:' % _("Extension"))
+        self.ext_label.setToolTip(_("A file extension to be added or deleted to the list."))
+        self.ext_entry = FCEntry()
+
+        hlay1 = QtWidgets.QHBoxLayout()
+        self.layout.addLayout(hlay1)
+        hlay1.addWidget(self.ext_label)
+        hlay1.addWidget(self.ext_entry)
+
+        self.add_btn = FCButton(_("Add Extension"))
+        self.add_btn.setToolTip(_("Add a file extension to the list"))
+        self.del_btn = FCButton(_("Delete Extension"))
+        self.del_btn.setToolTip(_("Delete a file extension from the list"))
+
+        hlay2 = QtWidgets.QHBoxLayout()
+        self.layout.addLayout(hlay2)
+        hlay2.addWidget(self.add_btn)
+        hlay2.addWidget(self.del_btn)
+
+        self.grb_list_btn = FCButton(_("Apply Association"))
         self.grb_list_btn.setToolTip(_("Apply the file associations between\n"
                                        "FlatCAM and the files with above extensions.\n"
                                        "They will be active after next logon.\n"