Просмотр исходного кода

Merged in marius_stanciu/flatcam_beta/Beta (pull request #217)

Beta - headless mode and sys tray icon
Marius Stanciu 6 лет назад
Родитель
Сommit
a4f30891da

Разница между файлами не показана из-за своего большого размера
+ 468 - 157
FlatCAMApp.py


+ 23 - 1
README.md

@@ -1,4 +1,4 @@
-latCAM: 2D Computer-Aided PCB Manufacturing
+FlatCAM: 2D Computer-Aided PCB Manufacturing
 =================================================
 =================================================
 
 
 (c) 2014-2019 Juan Pablo Caram
 (c) 2014-2019 Juan Pablo Caram
@@ -9,6 +9,28 @@ CAD program, and create G-Code for Isolation routing.
 
 
 =================================================
 =================================================
 
 
+19.09.2019
+
+- made sure that if FlatCAM is registered with a file extension that it does not recognize it will exit
+- added some fixes in the the file extension detection
+- added some status messages for the Tcl script related methods
+- made sure that optionally, when a script is run then it is also loaded into the code editor
+- added control over the display of Sys Tray Icon in Edit -> Preferences -> General -> GUI Settings -> Sys Tray Icon checkbox
+- updated some of the default values to more reasonable ones
+- FlatCAM can be run in HEADLESS mode now. This mode can be selected by using the --headless=1 command line argument or by changing the line headless=False to True in config/configuration.txt file. In this mod the Sys Tray Icon menu will hold only the Run Scrip menu entry and Exit entry.
+- added a new TclCommand named quit_flatcam which will ... quit FlatCAM from Tcl Shell or from a script
+
+18.09.2019
+
+- added more functionality to the Extension registration with FLatCAM and added to the GUI in Edit -> Preferences -> Utilities
+- fixed the parsing of the Manufacturing files when double clicking them and they are registered with FlatCAM
+- fixed showing the GUI when some settings (maximized_GUI) are missing from QSettings
+- added sys tray menu
+- added possibility to edit the custom keywords used by the autocompleter (in Tcl Shell and in the Code Editor). It is done in the Edit -> Preferences -> Utilities
+- added a new setting in Edit -> Preferences -> General -> GUI Settings -> Textbox Font which control the font on the Textbox GUI elements
+- fixed issue with the sys tray icon not hiding after application close
+- added option to run a script from the context menu of the sys tray icon. Changed the color of the sys tray icon to a green one so it will be visible on light and dark themes
+
 17.09.2019
 17.09.2019
 
 
 - added more programmers that contributed to FlatCAM over the years, in the "About FlatCAM" -> Programmers window
 - 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))
                 #             temp_elem.append(deepcopy(new_elem))
                 for elem in self.gerber_obj.apertures[apid]['geometry']:
                 for elem in self.gerber_obj.apertures[apid]['geometry']:
                     new_elem = dict()
                     new_elem = dict()
-
                     if 'solid' in elem:
                     if 'solid' in elem:
                         solid_geo = elem['solid']
                         solid_geo = elem['solid']
                         for clear_geo in global_clear_geo:
                         for clear_geo in global_clear_geo:
@@ -4434,16 +4433,18 @@ class FlatCAMGrbEditor(QtCore.QObject):
                             self.plot_shape(geometry=geometric_data,
                             self.plot_shape(geometry=geometric_data,
                                             color=self.app.defaults['global_sel_draw_color'],
                                             color=self.app.defaults['global_sel_draw_color'],
                                             linewidth=2)
                                             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:
                 except KeyError:
                     pass
                     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()
             self.shapes.redraw()
 
 

+ 319 - 22
flatcamGUI/FlatCAMGUI.py

@@ -958,7 +958,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
 
 
         self.fa_tab = QtWidgets.QWidget()
         self.fa_tab = QtWidgets.QWidget()
         self.fa_tab.setObjectName("fa_tab")
         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 = QtWidgets.QVBoxLayout()
         self.fa_tab_lay.setContentsMargins(2, 2, 2, 2)
         self.fa_tab_lay.setContentsMargins(2, 2, 2, 2)
         self.fa_tab.setLayout(self.fa_tab_lay)
         self.fa_tab.setLayout(self.fa_tab_lay)
@@ -1972,7 +1972,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         self.geometry_defaults_form = GeometryPreferencesUI()
         self.geometry_defaults_form = GeometryPreferencesUI()
         self.cncjob_defaults_form = CNCJobPreferencesUI()
         self.cncjob_defaults_form = CNCJobPreferencesUI()
         self.tools_defaults_form = ToolsPreferencesUI()
         self.tools_defaults_form = ToolsPreferencesUI()
-        self.fa_defaults_form = FAPreferencesUI()
+        self.util_defaults_form = UtilPreferencesUI()
 
 
         self.general_options_form = GeneralPreferencesUI()
         self.general_options_form = GeneralPreferencesUI()
         self.gerber_options_form = GerberPreferencesUI()
         self.gerber_options_form = GerberPreferencesUI()
@@ -1980,7 +1980,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         self.geometry_options_form = GeometryPreferencesUI()
         self.geometry_options_form = GeometryPreferencesUI()
         self.cncjob_options_form = CNCJobPreferencesUI()
         self.cncjob_options_form = CNCJobPreferencesUI()
         self.tools_options_form = ToolsPreferencesUI()
         self.tools_options_form = ToolsPreferencesUI()
-        self.fa_options_form = FAPreferencesUI()
+        self.util_options_form = UtilPreferencesUI()
 
 
         QtWidgets.qApp.installEventFilter(self)
         QtWidgets.qApp.installEventFilter(self)
 
 
@@ -3631,23 +3631,32 @@ class CNCJobPreferencesUI(QtWidgets.QWidget):
         self.layout.addStretch()
         self.layout.addStretch()
 
 
 
 
-class FAPreferencesUI(QtWidgets.QWidget):
+class UtilPreferencesUI(QtWidgets.QWidget):
 
 
     def __init__(self, parent=None):
     def __init__(self, parent=None):
         QtWidgets.QWidget.__init__(self, parent=parent)
         QtWidgets.QWidget.__init__(self, parent=parent)
         self.layout = QtWidgets.QHBoxLayout()
         self.layout = QtWidgets.QHBoxLayout()
         self.setLayout(self.layout)
         self.setLayout(self.layout)
 
 
+        self.vlay = QtWidgets.QVBoxLayout()
         self.fa_excellon_group = FAExcPrefGroupUI()
         self.fa_excellon_group = FAExcPrefGroupUI()
         self.fa_excellon_group.setMinimumWidth(260)
         self.fa_excellon_group.setMinimumWidth(260)
+
         self.fa_gcode_group = FAGcoPrefGroupUI()
         self.fa_gcode_group = FAGcoPrefGroupUI()
         self.fa_gcode_group.setMinimumWidth(260)
         self.fa_gcode_group.setMinimumWidth(260)
+
+        self.vlay.addWidget(self.fa_excellon_group)
+        self.vlay.addWidget(self.fa_gcode_group)
+
         self.fa_gerber_group = FAGrbPrefGroupUI()
         self.fa_gerber_group = FAGrbPrefGroupUI()
         self.fa_gerber_group.setMinimumWidth(260)
         self.fa_gerber_group.setMinimumWidth(260)
 
 
-        self.layout.addWidget(self.fa_excellon_group)
-        self.layout.addWidget(self.fa_gcode_group)
+        self.kw_group = AutoCompletePrefGroupUI()
+        self.kw_group.setMinimumWidth(260)
+
+        self.layout.addLayout(self.vlay)
         self.layout.addWidget(self.fa_gerber_group)
         self.layout.addWidget(self.fa_gerber_group)
+        self.layout.addWidget(self.kw_group)
 
 
         self.layout.addStretch()
         self.layout.addStretch()
 
 
@@ -4073,6 +4082,23 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         else:
         else:
             self.axis_font_size_spinner.set_value(8)
             self.axis_font_size_spinner.set_value(8)
 
 
+        # TextBox Font Size
+        self.textbox_font_size_label = QtWidgets.QLabel('%s:' % _('Textbox Font Size'))
+        self.textbox_font_size_label.setToolTip(
+            _("This sets the font size for the Textbox GUI\n"
+              "elements that are used in FlatCAM.")
+        )
+
+        self.textbox_font_size_spinner = FCSpinner()
+        self.textbox_font_size_spinner.setRange(8, 40)
+        self.textbox_font_size_spinner.setWrapping(True)
+
+        settings = QSettings("Open Source", "FlatCAM")
+        if settings.contains("textbox_font_size"):
+            self.textbox_font_size_spinner.set_value(settings.value('textbox_font_size', type=int))
+        else:
+            self.textbox_font_size_spinner.set_value(10)
+
         # Just to add empty rows
         # Just to add empty rows
         self.spacelabel = QtWidgets.QLabel('')
         self.spacelabel = QtWidgets.QLabel('')
 
 
@@ -4088,6 +4114,13 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         else:
         else:
             self.splash_cb.set_value(False)
             self.splash_cb.set_value(False)
 
 
+        # Sys Tray Icon
+        self.systray_label = QtWidgets.QLabel('%s:' % _('Sys Tray Icon'))
+        self.systray_label.setToolTip(
+            _("Enable display of FlatCAM icon in Sys Tray.")
+        )
+        self.systray_cb = FCCheckBox()
+
         # Shell StartUp CB
         # Shell StartUp CB
         self.shell_startup_label = QtWidgets.QLabel('%s:' % _('Shell at StartUp'))
         self.shell_startup_label = QtWidgets.QLabel('%s:' % _('Shell at StartUp'))
         self.shell_startup_label.setToolTip(
         self.shell_startup_label.setToolTip(
@@ -4150,8 +4183,10 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         self.form_box.addRow(QtWidgets.QLabel(''))
         self.form_box.addRow(QtWidgets.QLabel(''))
         self.form_box.addRow(self.notebook_font_size_label, self.notebook_font_size_spinner)
         self.form_box.addRow(self.notebook_font_size_label, self.notebook_font_size_spinner)
         self.form_box.addRow(self.axis_font_size_label, self.axis_font_size_spinner)
         self.form_box.addRow(self.axis_font_size_label, self.axis_font_size_spinner)
+        self.form_box.addRow(self.textbox_font_size_label, self.textbox_font_size_spinner)
         self.form_box.addRow(QtWidgets.QLabel(''))
         self.form_box.addRow(QtWidgets.QLabel(''))
         self.form_box.addRow(self.splash_label, self.splash_cb)
         self.form_box.addRow(self.splash_label, self.splash_cb)
+        self.form_box.addRow(self.systray_label, self.systray_cb)
         self.form_box.addRow(self.shell_startup_label, self.shell_startup_cb)
         self.form_box.addRow(self.shell_startup_label, self.shell_startup_cb)
         self.form_box.addRow(self.project_startup_label, self.project_startup_cb)
         self.form_box.addRow(self.project_startup_label, self.project_startup_cb)
         self.form_box.addRow(self.project_autohide_label, self.project_autohide_cb)
         self.form_box.addRow(self.project_autohide_label, self.project_autohide_cb)
@@ -6463,6 +6498,14 @@ class CNCJobOptPrefGroupUI(OptionsGroupUI):
         )
         )
         self.layout.addWidget(self.export_gcode_label)
         self.layout.addWidget(self.export_gcode_label)
 
 
+        settings = QSettings("Open Source", "FlatCAM")
+        if settings.contains("textbox_font_size"):
+            tb_fsize = settings.value('textbox_font_size', type=int)
+        else:
+            tb_fsize = 10
+        font = QtGui.QFont()
+        font.setPointSize(tb_fsize)
+
         # Prepend to G-Code
         # Prepend to G-Code
         prependlabel = QtWidgets.QLabel('%s:' % _('Prepend to G-Code'))
         prependlabel = QtWidgets.QLabel('%s:' % _('Prepend to G-Code'))
         prependlabel.setToolTip(
         prependlabel.setToolTip(
@@ -6473,6 +6516,7 @@ class CNCJobOptPrefGroupUI(OptionsGroupUI):
 
 
         self.prepend_text = FCTextArea()
         self.prepend_text = FCTextArea()
         self.layout.addWidget(self.prepend_text)
         self.layout.addWidget(self.prepend_text)
+        self.prepend_text.setFont(font)
 
 
         # Append text to G-Code
         # Append text to G-Code
         appendlabel = QtWidgets.QLabel('%s:' % _('Append to G-Code'))
         appendlabel = QtWidgets.QLabel('%s:' % _('Append to G-Code'))
@@ -6485,6 +6529,7 @@ class CNCJobOptPrefGroupUI(OptionsGroupUI):
 
 
         self.append_text = FCTextArea()
         self.append_text = FCTextArea()
         self.layout.addWidget(self.append_text)
         self.layout.addWidget(self.append_text)
+        self.append_text.setFont(font)
 
 
         self.layout.addStretch()
         self.layout.addStretch()
 
 
@@ -6520,8 +6565,17 @@ class CNCJobAdvOptPrefGroupUI(OptionsGroupUI):
         )
         )
         self.layout.addWidget(toolchangelabel)
         self.layout.addWidget(toolchangelabel)
 
 
+        settings = QSettings("Open Source", "FlatCAM")
+        if settings.contains("textbox_font_size"):
+            tb_fsize = settings.value('textbox_font_size', type=int)
+        else:
+            tb_fsize = 10
+        font = QtGui.QFont()
+        font.setPointSize(tb_fsize)
+
         self.toolchange_text = FCTextArea()
         self.toolchange_text = FCTextArea()
         self.layout.addWidget(self.toolchange_text)
         self.layout.addWidget(self.toolchange_text)
+        self.toolchange_text.setFont(font)
 
 
         hlay = QtWidgets.QHBoxLayout()
         hlay = QtWidgets.QHBoxLayout()
         self.layout.addLayout(hlay)
         self.layout.addLayout(hlay)
@@ -7794,34 +7848,83 @@ class ToolsSubPrefGroupUI(OptionsGroupUI):
 class FAExcPrefGroupUI(OptionsGroupUI):
 class FAExcPrefGroupUI(OptionsGroupUI):
     def __init__(self, parent=None):
     def __init__(self, parent=None):
         # OptionsGroupUI.__init__(self, "Excellon File associations Preferences", 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")))
         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"
             _("List of file extensions to be\n"
               "associated with FlatCAM.")
               "associated with FlatCAM.")
         )
         )
-        self.layout.addWidget(self.exc_list_label)
+        self.vertical_lay.addWidget(list_label)
+
+        settings = QSettings("Open Source", "FlatCAM")
+        if settings.contains("textbox_font_size"):
+            tb_fsize = settings.value('textbox_font_size', type=int)
+        else:
+            tb_fsize = 10
 
 
         self.exc_list_text = FCTextArea()
         self.exc_list_text = FCTextArea()
+        self.exc_list_text.setReadOnly(True)
         # self.exc_list_text.sizeHint(custom_sizehint=150)
         # self.exc_list_text.sizeHint(custom_sizehint=150)
         font = QtGui.QFont()
         font = QtGui.QFont()
-        font.setPointSize(12)
+        font.setPointSize(tb_fsize)
         self.exc_list_text.setFont(font)
         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"
         self.exc_list_btn.setToolTip(_("Apply the file associations between\n"
                                        "FlatCAM and the files with above extensions.\n"
                                        "FlatCAM and the files with above extensions.\n"
                                        "They will be active after next logon.\n"
                                        "They will be active after next logon.\n"
                                        "This work only in Windows."))
                                        "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):
 class FAGcoPrefGroupUI(OptionsGroupUI):
@@ -7831,7 +7934,17 @@ class FAGcoPrefGroupUI(OptionsGroupUI):
 
 
         self.setTitle(str(_("GCode File associations")))
         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 = QtWidgets.QLabel("<b>%s:</b>" % _("Extensions list"))
         self.gco_list_label.setToolTip(
         self.gco_list_label.setToolTip(
             _("List of file extensions to be\n"
             _("List of file extensions to be\n"
@@ -7839,15 +7952,41 @@ class FAGcoPrefGroupUI(OptionsGroupUI):
         )
         )
         self.layout.addWidget(self.gco_list_label)
         self.layout.addWidget(self.gco_list_label)
 
 
+        settings = QSettings("Open Source", "FlatCAM")
+        if settings.contains("textbox_font_size"):
+            tb_fsize = settings.value('textbox_font_size', type=int)
+        else:
+            tb_fsize = 10
+
         self.gco_list_text = FCTextArea()
         self.gco_list_text = FCTextArea()
+        self.gco_list_text.setReadOnly(True)
         # self.gco_list_text.sizeHint(custom_sizehint=150)
         # self.gco_list_text.sizeHint(custom_sizehint=150)
         font = QtGui.QFont()
         font = QtGui.QFont()
-        font.setPointSize(12)
+        font.setPointSize(tb_fsize)
         self.gco_list_text.setFont(font)
         self.gco_list_text.setFont(font)
 
 
         self.layout.addWidget(self.gco_list_text)
         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"
         self.gco_list_btn.setToolTip(_("Apply the file associations between\n"
                                        "FlatCAM and the files with above extensions.\n"
                                        "FlatCAM and the files with above extensions.\n"
                                        "They will be active after next logon.\n"
                                        "They will be active after next logon.\n"
@@ -7864,7 +8003,17 @@ class FAGrbPrefGroupUI(OptionsGroupUI):
 
 
         self.setTitle(str(_("Gerber File associations")))
         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 = QtWidgets.QLabel("<b>%s:</b>" % _("Extensions list"))
         self.grb_list_label.setToolTip(
         self.grb_list_label.setToolTip(
             _("List of file extensions to be\n"
             _("List of file extensions to be\n"
@@ -7872,14 +8021,40 @@ class FAGrbPrefGroupUI(OptionsGroupUI):
         )
         )
         self.layout.addWidget(self.grb_list_label)
         self.layout.addWidget(self.grb_list_label)
 
 
+        settings = QSettings("Open Source", "FlatCAM")
+        if settings.contains("textbox_font_size"):
+            tb_fsize = settings.value('textbox_font_size', type=int)
+        else:
+            tb_fsize = 10
+
         self.grb_list_text = FCTextArea()
         self.grb_list_text = FCTextArea()
+        self.grb_list_text.setReadOnly(True)
         # self.grb_list_text.sizeHint(custom_sizehint=150)
         # self.grb_list_text.sizeHint(custom_sizehint=150)
         self.layout.addWidget(self.grb_list_text)
         self.layout.addWidget(self.grb_list_text)
         font = QtGui.QFont()
         font = QtGui.QFont()
-        font.setPointSize(12)
+        font.setPointSize(tb_fsize)
         self.grb_list_text.setFont(font)
         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"
         self.grb_list_btn.setToolTip(_("Apply the file associations between\n"
                                        "FlatCAM and the files with above extensions.\n"
                                        "FlatCAM and the files with above extensions.\n"
                                        "They will be active after next logon.\n"
                                        "They will be active after next logon.\n"
@@ -7890,6 +8065,69 @@ class FAGrbPrefGroupUI(OptionsGroupUI):
         # self.layout.addStretch()
         # self.layout.addStretch()
 
 
 
 
+class AutoCompletePrefGroupUI(OptionsGroupUI):
+    def __init__(self, parent=None):
+        # OptionsGroupUI.__init__(self, "Gerber File associations Preferences", parent=None)
+        super().__init__(self, parent=parent)
+
+        self.setTitle(str(_("Autocompleter Keywords")))
+
+        self.restore_btn = FCButton(_("Restore"))
+        self.restore_btn.setToolTip(_("Restore the autocompleter keywords list to the default state."))
+        self.del_all_btn = FCButton(_("Delete All"))
+        self.del_all_btn.setToolTip(_("Delete all autocompleter keywords 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>" % _("Keywords list"))
+        self.grb_list_label.setToolTip(
+            _("List of keywords used by\n"
+              "the autocompleter in FlatCAM.\n"
+              "The autocompleter is installed\n"
+              "in the Code Editor and for the Tcl Shell.")
+        )
+        self.layout.addWidget(self.grb_list_label)
+
+        settings = QSettings("Open Source", "FlatCAM")
+        if settings.contains("textbox_font_size"):
+            tb_fsize = settings.value('textbox_font_size', type=int)
+        else:
+            tb_fsize = 10
+
+        self.kw_list_text = FCTextArea()
+        self.kw_list_text.setReadOnly(True)
+        # self.grb_list_text.sizeHint(custom_sizehint=150)
+        self.layout.addWidget(self.kw_list_text)
+        font = QtGui.QFont()
+        font.setPointSize(tb_fsize)
+        self.kw_list_text.setFont(font)
+
+        self.kw_label = QtWidgets.QLabel('%s:' % _("Extension"))
+        self.kw_label.setToolTip(_("A keyword to be added or deleted to the list."))
+        self.kw_entry = FCEntry()
+
+        hlay1 = QtWidgets.QHBoxLayout()
+        self.layout.addLayout(hlay1)
+        hlay1.addWidget(self.kw_label)
+        hlay1.addWidget(self.kw_entry)
+
+        self.add_btn = FCButton(_("Add keyword"))
+        self.add_btn.setToolTip(_("Add a keyword to the list"))
+        self.del_btn = FCButton(_("Delete keyword"))
+        self.del_btn.setToolTip(_("Delete a keyword from the list"))
+
+        hlay2 = QtWidgets.QHBoxLayout()
+        self.layout.addLayout(hlay2)
+        hlay2.addWidget(self.add_btn)
+        hlay2.addWidget(self.del_btn)
+
+        # self.layout.addStretch()
+
+
 class FlatCAMActivityView(QtWidgets.QWidget):
 class FlatCAMActivityView(QtWidgets.QWidget):
 
 
     def __init__(self, parent=None):
     def __init__(self, parent=None):
@@ -7970,4 +8208,63 @@ class FlatCAMInfoBar(QtWidgets.QWidget):
 
 
         self.set_text_(text)
         self.set_text_(text)
         self.icon.setPixmap(self.pmap)
         self.icon.setPixmap(self.pmap)
+
+
+class FlatCAMSystemTray(QtWidgets.QSystemTrayIcon):
+
+    def __init__(self, app, icon, headless=None, parent=None):
+        # QtWidgets.QSystemTrayIcon.__init__(self, icon, parent)
+        super().__init__(icon, parent=parent)
+        self.app = app
+
+        menu = QtWidgets.QMenu(parent)
+
+        menu_runscript = QtWidgets.QAction(QtGui.QIcon('share/script16.png'), '%s' % _('Run Script ...'), self)
+        menu_runscript.setToolTip(
+            _("Will run the opened Tcl Script thus\n"
+              "enabling the automation of certain\n"
+              "functions of FlatCAM.")
+        )
+        menu.addAction(menu_runscript)
+
+        menu.addSeparator()
+
+        if headless is None:
+            self.menu_open = menu.addMenu(QtGui.QIcon('share/folder32_bis.png'), _('Open'))
+
+            # Open Project ...
+            menu_openproject = QtWidgets.QAction(QtGui.QIcon('share/folder16.png'), _('Open Project ...'), self)
+            self.menu_open.addAction(menu_openproject)
+            self.menu_open.addSeparator()
+
+            # Open Gerber ...
+            menu_opengerber = QtWidgets.QAction(QtGui.QIcon('share/flatcam_icon24.png'),
+                                                        _('Open &Gerber ...\tCTRL+G'), self)
+            self.menu_open.addAction(menu_opengerber)
+
+            # Open Excellon ...
+            menu_openexcellon = QtWidgets.QAction(QtGui.QIcon('share/open_excellon32.png'),
+                                                          _('Open &Excellon ...\tCTRL+E'), self)
+            self.menu_open.addAction(menu_openexcellon)
+
+            # Open G-Code ...
+            menu_opengcode = QtWidgets.QAction(QtGui.QIcon('share/code.png'), _('Open G-&Code ...'), self)
+            self.menu_open.addAction(menu_opengcode)
+
+            self.menu_open.addSeparator()
+
+            menu_openproject.triggered.connect(self.app.on_file_openproject)
+            menu_opengerber.triggered.connect(self.app.on_fileopengerber)
+            menu_openexcellon.triggered.connect(self.app.on_fileopenexcellon)
+            menu_opengcode.triggered.connect(self.app.on_fileopengcode)
+
+        exitAction = menu.addAction(_("Exit"))
+        exitAction.setIcon(QtGui.QIcon('share/power16.png'))
+        self.setContextMenu(menu)
+
+        menu_runscript.triggered.connect(lambda: self.app.on_filerunscript(
+            silent=True if self.app.cmd_line_headless == 1 else False))
+
+        exitAction.triggered.connect(self.app.final_save)
+
 # end of file
 # end of file

BIN
share/flatcam_icon32_green.png


+ 2 - 2
tclCommands/TclCommandPlotAll.py

@@ -42,5 +42,5 @@ class TclCommandPlotAll(TclCommand):
         :param unnamed_args:
         :param unnamed_args:
         :return:
         :return:
         """
         """
-
-        self.app.plot_all()
+        if self.app.cmd_line_headless != 1:
+            self.app.plot_all()

+ 8 - 7
tclCommands/TclCommandPlotObjects.py

@@ -42,10 +42,11 @@ class TclCommandPlotObjects(TclCommand):
         :param unnamed_args:
         :param unnamed_args:
         :return:
         :return:
         """
         """
-        names = [x.strip() for x in args['names'].split(",")]
-        objs = []
-        for name in names:
-            objs.append(self.app.collection.get_by_name(name))
-
-        for obj in objs:
-            obj.plot()
+        if self.app.cmd_line_headless != 1:
+            names = [x.strip() for x in args['names'].split(",")]
+            objs = []
+            for name in names:
+                objs.append(self.app.collection.get_by_name(name))
+
+            for obj in objs:
+                obj.plot()

+ 47 - 0
tclCommands/TclCommandQuit.py

@@ -0,0 +1,47 @@
+from ObjectCollection import *
+from tclCommands.TclCommand import TclCommand
+
+
+class TclCommandQuit(TclCommand):
+    """
+    Tcl shell command to quit FlatCAM from Tcl shell.
+
+    example:
+
+    """
+
+    # List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
+    aliases = ['quit_flatcam']
+
+    # Dictionary of types from Tcl command, needs to be ordered
+    arg_names = collections.OrderedDict([
+
+    ])
+
+    # Dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
+    option_types = collections.OrderedDict([
+
+    ])
+
+    # array of mandatory options for current Tcl command: required = {'name','outname'}
+    required = []
+
+    # structured help for current command, args needs to be ordered
+    help = {
+        'main': "Tcl shell command to quit FlatCAM from Tcl shell.",
+        'args': collections.OrderedDict([
+
+        ]),
+        'examples': ['quit_flatcam']
+    }
+
+    def execute(self, args, unnamed_args):
+        """
+
+        :param args:
+        :param unnamed_args:
+        :return:
+        """
+
+        self.app.quit_application()
+

+ 1 - 0
tclCommands/__init__.py

@@ -48,6 +48,7 @@ import tclCommands.TclCommandPaint
 import tclCommands.TclCommandPanelize
 import tclCommands.TclCommandPanelize
 import tclCommands.TclCommandPlotAll
 import tclCommands.TclCommandPlotAll
 import tclCommands.TclCommandPlotObjects
 import tclCommands.TclCommandPlotObjects
+import tclCommands.TclCommandQuit
 import tclCommands.TclCommandSaveProject
 import tclCommands.TclCommandSaveProject
 import tclCommands.TclCommandSaveSys
 import tclCommands.TclCommandSaveSys
 import tclCommands.TclCommandScale
 import tclCommands.TclCommandScale

+ 158 - 0
tests/titlebar_custom.py

@@ -0,0 +1,158 @@
+#########################################################
+## customize Title bar
+## dotpy.ir
+## iraj.jelo@gmail.com
+#########################################################
+import sys
+from PyQt5 import QtWidgets, QtGui
+from PyQt5 import QtCore
+from PyQt5.QtCore import Qt
+
+
+class TitleBar(QtWidgets.QDialog):
+    def __init__(self, parent=None):
+        QtWidgets.QWidget.__init__(self, parent)
+        self.setWindowFlags(Qt.FramelessWindowHint)
+        css = """
+        QWidget{
+            Background: #0000FF;
+            color:white;
+            font:12px bold;
+            font-weight:bold;
+            border-radius: 1px;
+            height: 11px;
+        }
+        QDialog{
+            Background-image:url('img/titlebar bg.png');
+            font-size:12px;
+            color: black;
+
+        }
+        QToolButton{
+            Background:#AA00AA;
+            font-size:11px;
+        }
+        QToolButton:hover{
+            Background: #FF00FF;
+            font-size:11px;
+        }
+        """
+        self.setAutoFillBackground(True)
+        self.setBackgroundRole(QtGui.QPalette.Highlight)
+        self.setStyleSheet(css)
+        self.minimize=QtWidgets.QToolButton(self)
+        self.minimize.setIcon(QtGui.QIcon('img/min.png'))
+        self.maximize=QtWidgets.QToolButton(self)
+        self.maximize.setIcon(QtGui.QIcon('img/max.png'))
+        close=QtWidgets.QToolButton(self)
+        close.setIcon(QtGui.QIcon('img/close.png'))
+        self.minimize.setMinimumHeight(10)
+        close.setMinimumHeight(10)
+        self.maximize.setMinimumHeight(10)
+        label=QtWidgets.QLabel(self)
+        label.setText("Window Title")
+        self.setWindowTitle("Window Title")
+        hbox=QtWidgets.QHBoxLayout(self)
+        hbox.addWidget(label)
+        hbox.addWidget(self.minimize)
+        hbox.addWidget(self.maximize)
+        hbox.addWidget(close)
+        hbox.insertStretch(1,500)
+        hbox.setSpacing(0)
+        self.setSizePolicy(QtWidgets.QSizePolicy.Expanding,QtWidgets.QSizePolicy.Fixed)
+        self.maxNormal=False
+        close.clicked.connect(self.close)
+        self.minimize.clicked.connect(self.showSmall)
+        self.maximize.clicked.connect(self.showMaxRestore)
+
+    def showSmall(self):
+        box.showMinimized()
+
+    def showMaxRestore(self):
+        if(self.maxNormal):
+            box.showNormal()
+            self.maxNormal= False
+            self.maximize.setIcon(QtGui.QIcon('img/max.png'))
+        else:
+            box.showMaximized()
+            self.maxNormal = True
+            self.maximize.setIcon(QtGui.QIcon('img/max2.png'))
+
+    def close(self):
+        box.close()
+
+    def mousePressEvent(self,event):
+        if event.button() == Qt.LeftButton:
+            box.moving = True
+            box.offset = event.pos()
+            if event.type() == QtCore.QEvent.MouseButtonDblClick:
+                self.showMaxRestore()
+
+    def mouseMoveEvent(self,event):
+        if box.isMaximized():
+            self.showMaxRestore()
+            box.move(event.globalPos() - box.offset)
+        else:
+            if box.moving:
+                box.move(event.globalPos()-box.offset)
+
+
+class Frame(QtWidgets.QFrame):
+    def __init__(self, parent=None):
+        QtWidgets.QFrame.__init__(self, parent)
+        self.m_mouse_down= False
+        self.setFrameShape(QtWidgets.QFrame.StyledPanel)
+        css = """
+        QFrame{
+            Background:  #FFFFF0;
+            color:white;
+            font:13px ;
+            font-weight:bold;
+            }
+        """
+        self.setStyleSheet(css)
+        self.setWindowFlags(Qt.FramelessWindowHint)
+        self.setMouseTracking(True)
+        self.m_titleBar= TitleBar(self)
+        self.m_content= QtWidgets.QWidget(self)
+        vbox=QtWidgets.QVBoxLayout(self)
+        vbox.addWidget(self.m_titleBar)
+        vbox.setContentsMargins(0, 0, 0, 0)
+        vbox.setSpacing(0)
+        layout=QtWidgets.QVBoxLayout()
+        layout.addWidget(self.m_content)
+        layout.setContentsMargins(5, 5, 5, 5)
+        layout.setSpacing(0)
+        vbox.addLayout(layout)
+        # Allows you to access the content area of the frame
+        # where widgets and layouts can be added
+
+    def contentWidget(self):
+        return self.m_content
+
+    def titleBar(self):
+        return self.m_titleBar
+
+    def mousePressEvent(self,event):
+        self.m_old_pos = event.pos()
+        self.m_mouse_down = event.button()== Qt.LeftButton
+
+    def mouseMoveEvent(self,event):
+        x=event.x()
+        y=event.y()
+
+    def mouseReleaseEvent(self,event):
+        m_mouse_down=False
+
+if __name__ == '__main__':
+    app = QtWidgets.QApplication(sys.argv)
+    box = Frame()
+    box.move(60,60)
+    l=QtWidgets.QVBoxLayout(box.contentWidget())
+    l.setContentsMargins(0, 0, 0, 0)
+    edit=QtWidgets.QLabel("""I would've did anything for you to show you how much I adored you
+But it's over now, it's too late to save our loveJust promise me you'll think of me
+Every time you look up in the sky and see a star 'cuz I'm  your star.""")
+    l.addWidget(edit)
+    box.show()
+    app.exec_()

Некоторые файлы не были показаны из-за большого количества измененных файлов