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

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

Beta - improvements
Marius Stanciu 6 лет назад
Родитель
Сommit
00e7519ed4

+ 63 - 6
FlatCAMApp.py

@@ -1940,6 +1940,10 @@ class App(QtCore.QObject):
 
 
         self.ui.popmenu_properties.triggered.connect(self.obj_properties)
         self.ui.popmenu_properties.triggered.connect(self.obj_properties)
 
 
+        # Project Context Menu -> Color Setting
+        for act in self.ui.menuprojectcolor.actions():
+            act.triggered.connect(self.on_set_color_action_triggered)
+
         # Preferences Plot Area TAB
         # Preferences Plot Area TAB
         self.ui.pref_save_button.clicked.connect(lambda: self.on_save_button(save_to_file=True))
         self.ui.pref_save_button.clicked.connect(lambda: self.on_save_button(save_to_file=True))
         self.ui.pref_apply_button.clicked.connect(lambda: self.on_save_button(save_to_file=False))
         self.ui.pref_apply_button.clicked.connect(lambda: self.on_save_button(save_to_file=False))
@@ -2024,7 +2028,7 @@ class App(QtCore.QObject):
         self.ui.general_defaults_form.general_gui_group.proj_color_dis_button.clicked.connect(
         self.ui.general_defaults_form.general_gui_group.proj_color_dis_button.clicked.connect(
             self.on_proj_color_dis_button)
             self.on_proj_color_dis_button)
 
 
-        # ############################# workspace setting signals #####################
+        # ############################# Workspace Setting Signals #####################
         self.ui.general_defaults_form.general_gui_group.wk_cb.currentIndexChanged.connect(self.on_workspace_modified)
         self.ui.general_defaults_form.general_gui_group.wk_cb.currentIndexChanged.connect(self.on_workspace_modified)
         self.ui.general_defaults_form.general_gui_group.wk_orientation_radio.activated_custom.connect(
         self.ui.general_defaults_form.general_gui_group.wk_orientation_radio.activated_custom.connect(
             self.on_workspace_modified
             self.on_workspace_modified
@@ -4731,7 +4735,7 @@ class App(QtCore.QObject):
                 self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % " "), 2, 3)
                 self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % " "), 2, 3)
                 self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "German"), 3, 0)
                 self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "German"), 3, 0)
                 self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Marius Stanciu (Google-Tr)"), 3, 1)
                 self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Marius Stanciu (Google-Tr)"), 3, 1)
-                self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Jens Karstedt, @detlefeckardt"), 3, 2)
+                self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Jens Karstedt, Detlef Eckardt"), 3, 2)
                 self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % " "), 3, 3)
                 self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % " "), 3, 3)
                 self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Romanian"), 4, 0)
                 self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Romanian"), 4, 0)
                 self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Marius Stanciu"), 4, 1)
                 self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Marius Stanciu"), 4, 1)
@@ -8443,16 +8447,16 @@ class App(QtCore.QObject):
     def populate_cmenu_grids(self):
     def populate_cmenu_grids(self):
         units = self.defaults['units'].lower()
         units = self.defaults['units'].lower()
 
 
+        for act in self.ui.cmenu_gridmenu.actions():
+            act.triggered.disconnect()
         self.ui.cmenu_gridmenu.clear()
         self.ui.cmenu_gridmenu.clear()
+
         sorted_list = sorted(self.defaults["global_grid_context_menu"][str(units)])
         sorted_list = sorted(self.defaults["global_grid_context_menu"][str(units)])
 
 
         grid_toggle = self.ui.cmenu_gridmenu.addAction(QtGui.QIcon(self.resource_location + '/grid32_menu.png'),
         grid_toggle = self.ui.cmenu_gridmenu.addAction(QtGui.QIcon(self.resource_location + '/grid32_menu.png'),
                                                        _("Grid On/Off"))
                                                        _("Grid On/Off"))
         grid_toggle.setCheckable(True)
         grid_toggle.setCheckable(True)
-        if self.grid_status() == True:
-            grid_toggle.setChecked(True)
-        else:
-            grid_toggle.setChecked(False)
+        grid_toggle.setChecked(True) if self.grid_status() else grid_toggle.setChecked(False)
 
 
         self.ui.cmenu_gridmenu.addSeparator()
         self.ui.cmenu_gridmenu.addSeparator()
         for grid in sorted_list:
         for grid in sorted_list:
@@ -12356,6 +12360,59 @@ class App(QtCore.QObject):
         # Clear pool to free memory
         # Clear pool to free memory
         self.clear_pool()
         self.clear_pool()
 
 
+    def on_set_color_action_triggered(self):
+        new_color = self.defaults['global_plot_fill']
+        act_name = self.sender().text().lower()
+
+        sel_obj = self.collection.get_active()
+
+        if act_name == 'red':
+            new_color = '#FF0000' + \
+                        str(hex(self.ui.general_defaults_form.general_gui_group.pf_color_alpha_slider.value())[2:])
+        if act_name == 'blue':
+            new_color = '#0000FF' + \
+                        str(hex(self.ui.general_defaults_form.general_gui_group.pf_color_alpha_slider.value())[2:])
+        if act_name == 'yellow':
+            new_color = '#FFDF00' + \
+                        str(hex(self.ui.general_defaults_form.general_gui_group.pf_color_alpha_slider.value())[2:])
+        if act_name == 'green':
+            new_color = '#00FF00' + \
+                        str(hex(self.ui.general_defaults_form.general_gui_group.pf_color_alpha_slider.value())[2:])
+        if act_name == 'violet':
+            new_color = '#FF00FF' + \
+                        str(hex(self.ui.general_defaults_form.general_gui_group.pf_color_alpha_slider.value())[2:])
+        if act_name == 'brown':
+            new_color = '#A52A2A' + \
+                        str(hex(self.ui.general_defaults_form.general_gui_group.pf_color_alpha_slider.value())[2:])
+
+        if act_name == 'custom':
+            new_color = QtGui.QColor(self.defaults['global_plot_fill'][:7])
+            c_dialog = QtWidgets.QColorDialog()
+            plot_fill_color = c_dialog.getColor(initial=new_color)
+
+            if plot_fill_color.isValid() is False:
+                return
+
+            new_color = str(plot_fill_color.name()) + \
+                        str(hex(self.ui.general_defaults_form.general_gui_group.pf_color_alpha_slider.value())[2:])
+
+        if self.is_legacy is False:
+            new_line_color = new_color[:-2]
+            sel_obj.fill_color = new_color
+            sel_obj.outline_color = new_line_color
+
+            sel_obj.shapes.redraw(
+                update_colors=(new_color, new_line_color)
+            )
+        else:
+            new_line_color = new_color
+
+            sel_obj.fill_color = new_color
+            sel_obj.outline_color = new_line_color
+            sel_obj.shapes.redraw(
+                update_colors=(new_color, new_line_color)
+            )
+
     def on_grid_snap_triggered(self, state):
     def on_grid_snap_triggered(self, state):
         if state:
         if state:
             self.ui.snap_infobar_label.setPixmap(QtGui.QPixmap(self.resource_location + '/snap_filled_16.png'))
             self.ui.snap_infobar_label.setPixmap(QtGui.QPixmap(self.resource_location + '/snap_filled_16.png'))

+ 23 - 6
FlatCAMObj.py

@@ -15,7 +15,9 @@ from shapely.geometry import Point, Polygon, MultiPolygon, MultiLineString, Line
 from shapely.ops import cascaded_union
 from shapely.ops import cascaded_union
 import shapely.affinity as affinity
 import shapely.affinity as affinity
 
 
-from copy import deepcopy, copy
+from copy import deepcopy
+from copy import copy
+
 from io import StringIO
 from io import StringIO
 import traceback
 import traceback
 import inspect  # TODO: For debugging only.
 import inspect  # TODO: For debugging only.
@@ -30,6 +32,8 @@ from flatcamParsers.ParseGerber import Gerber
 from camlib import Geometry, CNCjob
 from camlib import Geometry, CNCjob
 import FlatCAMApp
 import FlatCAMApp
 
 
+from flatcamGUI.VisPyVisuals import ShapeCollection
+
 import tkinter as tk
 import tkinter as tk
 import os, sys, itertools
 import os, sys, itertools
 import ezdxf
 import ezdxf
@@ -104,6 +108,7 @@ class FlatCAMObj(QtCore.QObject):
 
 
         if self.app.is_legacy is False:
         if self.app.is_legacy is False:
             self.shapes = self.app.plotcanvas.new_shape_group()
             self.shapes = self.app.plotcanvas.new_shape_group()
+            # self.shapes = ShapeCollection(parent=self.app.plotcanvas.view.scene, pool=self.app.pool, layers=2)
         else:
         else:
             self.shapes = ShapeCollectionLegacy(obj=self, app=self.app, name=name)
             self.shapes = ShapeCollectionLegacy(obj=self, app=self.app, name=name)
 
 
@@ -649,10 +654,13 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
 
 
         self.units_found = self.app.defaults['units']
         self.units_found = self.app.defaults['units']
 
 
+        self.fill_color = self.app.defaults['global_plot_fill']
+        self.outline_color = self.app.defaults['global_plot_line']
+
         # Attributes to be included in serialization
         # Attributes to be included in serialization
         # Always append to it because it carries contents
         # Always append to it because it carries contents
         # from predecessors.
         # from predecessors.
-        self.ser_attrs += ['options', 'kind']
+        self.ser_attrs += ['options', 'kind', 'fill_color', 'outline_color']
 
 
     def set_ui(self, ui):
     def set_ui(self, ui):
         """
         """
@@ -736,6 +744,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
             self.ui.aperture_table_visibility_cb.hide()
             self.ui.aperture_table_visibility_cb.hide()
             self.ui.milling_type_label.hide()
             self.ui.milling_type_label.hide()
             self.ui.milling_type_radio.hide()
             self.ui.milling_type_radio.hide()
+            self.ui.iso_type_label.hide()
             self.ui.iso_type_radio.hide()
             self.ui.iso_type_radio.hide()
 
 
             self.ui.follow_cb.hide()
             self.ui.follow_cb.hide()
@@ -1665,12 +1674,12 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
         if 'color' in kwargs:
         if 'color' in kwargs:
             color = kwargs['color']
             color = kwargs['color']
         else:
         else:
-            color = self.app.defaults['global_plot_line']
+            color = self.outline_color
 
 
         if 'face_color' in kwargs:
         if 'face_color' in kwargs:
             face_color = kwargs['face_color']
             face_color = kwargs['face_color']
         else:
         else:
-            face_color = self.app.defaults['global_plot_fill']
+            face_color = self.fill_color
 
 
         if 'visible' not in kwargs:
         if 'visible' not in kwargs:
             visible = self.options['plot']
             visible = self.options['plot']
@@ -1740,7 +1749,10 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
                         for el in g:
                         for el in g:
                             self.add_shape(shape=el, color=random_color() if self.options['multicolored'] else 'black',
                             self.add_shape(shape=el, color=random_color() if self.options['multicolored'] else 'black',
                                            visible=visible)
                                            visible=visible)
-            self.shapes.redraw()
+            self.shapes.redraw(
+                # update_colors=(self.fill_color, self.outline_color),
+                # indexes=self.app.plotcanvas.shape_collection.data.keys()
+            )
         except (ObjectDeleted, AttributeError):
         except (ObjectDeleted, AttributeError):
             self.shapes.clear(update=True)
             self.shapes.clear(update=True)
         except Exception as e:
         except Exception as e:
@@ -3763,6 +3775,9 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
         self.ui.name_entry.set_value(self.options['name'])
         self.ui.name_entry.set_value(self.options['name'])
         self.ui_connect()
         self.ui_connect()
 
 
+        self.ui.e_cut_entry.setDisabled(False) if self.ui.extracut_cb.get_value() else \
+            self.ui.e_cut_entry.setDisabled(True)
+
     def set_ui(self, ui):
     def set_ui(self, ui):
         FlatCAMObj.set_ui(self, ui)
         FlatCAMObj.set_ui(self, ui)
 
 
@@ -3939,7 +3954,9 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
         else:
         else:
             self.ui.level.setText('<span style="color:red;"><b>%s</b></span>' % _('Advanced'))
             self.ui.level.setText('<span style="color:red;"><b>%s</b></span>' % _('Advanced'))
 
 
-        self.ui.e_cut_entry.setDisabled(True)
+        self.ui.e_cut_entry.setDisabled(False) if self.app.defaults['geometry_extracut'] else \
+            self.ui.e_cut_entry.setDisabled(True)
+        self.ui.extracut_cb.toggled.connect(lambda state: self.ui.e_cut_entry.setDisabled(not state))
 
 
         self.ui.plot_cb.stateChanged.connect(self.on_plot_cb_click)
         self.ui.plot_cb.stateChanged.connect(self.on_plot_cb_click)
         self.ui.generate_cnc_button.clicked.connect(self.on_generatecnc_button_click)
         self.ui.generate_cnc_button.clicked.connect(self.on_generatecnc_button_click)

+ 5 - 0
ObjectCollection.py

@@ -321,6 +321,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
         sel = len(self.view.selectedIndexes()) > 0
         sel = len(self.view.selectedIndexes()) > 0
         self.app.ui.menuprojectenable.setEnabled(sel)
         self.app.ui.menuprojectenable.setEnabled(sel)
         self.app.ui.menuprojectdisable.setEnabled(sel)
         self.app.ui.menuprojectdisable.setEnabled(sel)
+        self.app.ui.menuprojectcolor.setEnabled(sel)
         self.app.ui.menuprojectviewsource.setEnabled(sel)
         self.app.ui.menuprojectviewsource.setEnabled(sel)
 
 
         self.app.ui.menuprojectcopy.setEnabled(sel)
         self.app.ui.menuprojectcopy.setEnabled(sel)
@@ -334,8 +335,12 @@ class ObjectCollection(QtCore.QAbstractItemModel):
             self.app.ui.menuprojectedit.setVisible(True)
             self.app.ui.menuprojectedit.setVisible(True)
             self.app.ui.menuprojectsave.setVisible(True)
             self.app.ui.menuprojectsave.setVisible(True)
             self.app.ui.menuprojectviewsource.setVisible(True)
             self.app.ui.menuprojectviewsource.setVisible(True)
+            self.app.ui.menuprojectcolor.setEnabled(False)
 
 
             for obj in self.get_selected():
             for obj in self.get_selected():
+                if type(obj) == FlatCAMGerber:
+                    self.app.ui.menuprojectcolor.setEnabled(True)
+
                 if type(obj) != FlatCAMGeometry:
                 if type(obj) != FlatCAMGeometry:
                     self.app.ui.menuprojectgeneratecnc.setVisible(False)
                     self.app.ui.menuprojectgeneratecnc.setVisible(False)
                 if type(obj) != FlatCAMGeometry and type(obj) != FlatCAMExcellon and type(obj) != FlatCAMGerber:
                 if type(obj) != FlatCAMGeometry and type(obj) != FlatCAMExcellon and type(obj) != FlatCAMGerber:

+ 13 - 0
README.md

@@ -9,12 +9,25 @@ CAD program, and create G-Code for Isolation routing.
 
 
 =================================================
 =================================================
 
 
+22.12.2019
+
+- added a new option for the Gerber objects: on the project context menu now can be chosen a color for the selected Gerber object
+- fixed issue in Gerber UI where a label was not hidden when in Basic mode
+- added the color parameters of the objects to the serializable attributes
+- fixed Gerber object color set for Legacy(2D) graphic engine; glitch on the OpenGL(3D) graphic engine
+- fixed the above mentioned glitch in the OpenGL(3D) graphic engine when an Gerber object has been set with a color
+
+21.12.2019
+
+- fixed a typo in Distance Tool
+
 20.12.2019
 20.12.2019
 
 
 - fixed a rare issue in the generation of non-copper-region geometry started from the Gerber Object UI (selected tab)
 - fixed a rare issue in the generation of non-copper-region geometry started from the Gerber Object UI (selected tab)
 - Print function is now printing a PDF file for a selection of objects in the colors from canvas 
 - Print function is now printing a PDF file for a selection of objects in the colors from canvas 
 - added an icon in the infobar that will show more clearly the status of the grid snapping
 - added an icon in the infobar that will show more clearly the status of the grid snapping
 - in Geometry Object UI (selected tab) when a tool type is changed from no matter what to V-shape, the cut_z value is saved and when the tool type is changed back to something different than V-shape, this saved cut-z value is restored
 - in Geometry Object UI (selected tab) when a tool type is changed from no matter what to V-shape, the cut_z value is saved and when the tool type is changed back to something different than V-shape, this saved cut-z value is restored
+- fixed re-cut length entry not staying disabled when the re-cut cb is not checked
 
 
 19.12.2019
 19.12.2019
 
 

+ 28 - 0
flatcamGUI/FlatCAMGUI.py

@@ -634,11 +634,39 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         # ########################## Project Tab Context Menu # ##################
         # ########################## Project Tab Context Menu # ##################
         # ########################################################################
         # ########################################################################
         self.menuproject = QtWidgets.QMenu()
         self.menuproject = QtWidgets.QMenu()
+
         self.menuprojectenable = self.menuproject.addAction(
         self.menuprojectenable = self.menuproject.addAction(
             QtGui.QIcon(self.app.resource_location + '/replot32.png'), _('Enable Plot'))
             QtGui.QIcon(self.app.resource_location + '/replot32.png'), _('Enable Plot'))
         self.menuprojectdisable = self.menuproject.addAction(
         self.menuprojectdisable = self.menuproject.addAction(
             QtGui.QIcon(self.app.resource_location + '/clear_plot32.png'), _('Disable Plot'))
             QtGui.QIcon(self.app.resource_location + '/clear_plot32.png'), _('Disable Plot'))
         self.menuproject.addSeparator()
         self.menuproject.addSeparator()
+
+        self.menuprojectcolor = self.menuproject.addMenu(
+            QtGui.QIcon(self.app.resource_location + '/set_color32.png'), _('Set Color'))
+
+        self.menuproject_red = self.menuprojectcolor.addAction(
+            QtGui.QIcon(self.app.resource_location + '/red32.png'), _('Red'))
+
+        self.menuproject_blue = self.menuprojectcolor.addAction(
+            QtGui.QIcon(self.app.resource_location + '/blue32.png'), _('Blue'))
+
+        self.menuproject_yellow = self.menuprojectcolor.addAction(
+            QtGui.QIcon(self.app.resource_location + '/yellow32.png'), _('Yellow'))
+
+        self.menuproject_green = self.menuprojectcolor.addAction(
+            QtGui.QIcon(self.app.resource_location + '/green32.png'), _('Green'))
+
+        self.menuproject_violet = self.menuprojectcolor.addAction(
+            QtGui.QIcon(self.app.resource_location + '/violet32.png'), _('Violet'))
+
+        self.menuproject_brown = self.menuprojectcolor.addAction(
+            QtGui.QIcon(self.app.resource_location + '/brown32.png'), _('Brown'))
+
+        self.menuproject_custom = self.menuprojectcolor.addAction(
+            QtGui.QIcon(self.app.resource_location + '/set_color32.png'), _('Custom'))
+
+        self.menuproject.addSeparator()
+
         self.menuprojectgeneratecnc = self.menuproject.addAction(
         self.menuprojectgeneratecnc = self.menuproject.addAction(
             QtGui.QIcon(self.app.resource_location + '/cnc32.png'), _('Generate CNC'))
             QtGui.QIcon(self.app.resource_location + '/cnc32.png'), _('Generate CNC'))
         self.menuprojectviewsource = self.menuproject.addAction(
         self.menuprojectviewsource = self.menuproject.addAction(

+ 1 - 3
flatcamGUI/ObjectUI.py

@@ -1577,7 +1577,7 @@ class GeometryObjectUI(ObjectUI):
         self.cncfeedrate_rapid_entry.hide()
         self.cncfeedrate_rapid_entry.hide()
 
 
         # Cut over 1st point in path
         # Cut over 1st point in path
-        self.extracut_cb = FCCheckBox('%s' % _('Re-cut'))
+        self.extracut_cb = FCCheckBox('%s:' % _('Re-cut'))
         self.extracut_cb.setToolTip(
         self.extracut_cb.setToolTip(
             _("In order to remove possible\n"
             _("In order to remove possible\n"
               "copper leftovers where first cut\n"
               "copper leftovers where first cut\n"
@@ -1599,8 +1599,6 @@ class GeometryObjectUI(ObjectUI):
         self.grid3.addWidget(self.extracut_cb, 13, 0)
         self.grid3.addWidget(self.extracut_cb, 13, 0)
         self.grid3.addWidget(self.e_cut_entry, 13, 1)
         self.grid3.addWidget(self.e_cut_entry, 13, 1)
 
 
-        self.ois_e_cut = OptionalInputSection(self.extracut_cb, [self.e_cut_entry])
-
         # Spindlespeed
         # Spindlespeed
         spdlabel = QtWidgets.QLabel('%s:' % _('Spindle speed'))
         spdlabel = QtWidgets.QLabel('%s:' % _('Spindle speed'))
         spdlabel.setToolTip(
         spdlabel.setToolTip(

+ 12 - 4
flatcamGUI/PlotCanvasLegacy.py

@@ -1033,7 +1033,7 @@ class ShapeCollectionLegacy:
         if update is True:
         if update is True:
             self.redraw()
             self.redraw()
 
 
-    def redraw(self):
+    def redraw(self, update_colors=None):
         """
         """
         This draw the shapes in the shapes collection, on canvas
         This draw the shapes in the shapes collection, on canvas
 
 
@@ -1087,7 +1087,6 @@ class ShapeCollectionLegacy:
                         self.axes.plot(x, y, local_shapes[element]['color'],
                         self.axes.plot(x, y, local_shapes[element]['color'],
                                        linestyle='-',
                                        linestyle='-',
                                        linewidth=local_shapes[element]['linewidth'])
                                        linewidth=local_shapes[element]['linewidth'])
-
                 elif obj_type == 'gerber':
                 elif obj_type == 'gerber':
                     if self.obj.options["multicolored"]:
                     if self.obj.options["multicolored"]:
                         linespec = '-'
                         linespec = '-'
@@ -1095,16 +1094,25 @@ class ShapeCollectionLegacy:
                         linespec = 'k-'
                         linespec = 'k-'
 
 
                     if self.obj.options["solid"]:
                     if self.obj.options["solid"]:
+                        if update_colors:
+                            gerber_fill_color = update_colors[0]
+                            gerber_outline_color = update_colors[1]
+                        else:
+                            gerber_fill_color = local_shapes[element]['face_color']
+                            gerber_outline_color = local_shapes[element]['color']
+
                         try:
                         try:
                             patch = PolygonPatch(local_shapes[element]['shape'],
                             patch = PolygonPatch(local_shapes[element]['shape'],
-                                                 facecolor=local_shapes[element]['face_color'],
-                                                 edgecolor=local_shapes[element]['color'],
+                                                 facecolor=gerber_fill_color,
+                                                 edgecolor=gerber_outline_color,
                                                  alpha=local_shapes[element]['alpha'],
                                                  alpha=local_shapes[element]['alpha'],
                                                  zorder=2)
                                                  zorder=2)
                             self.axes.add_patch(patch)
                             self.axes.add_patch(patch)
                         except AssertionError:
                         except AssertionError:
                             FlatCAMApp.App.log.warning("A geometry component was not a polygon:")
                             FlatCAMApp.App.log.warning("A geometry component was not a polygon:")
                             FlatCAMApp.App.log.warning(str(element))
                             FlatCAMApp.App.log.warning(str(element))
+                        except Exception as e:
+                            FlatCAMApp.App.log.debug("PlotCanvasLegacy.ShepeCollectionLegacy.redraw() --> %s" % str(e))
                     else:
                     else:
                         x, y = local_shapes[element]['shape'].exterior.xy
                         x, y = local_shapes[element]['shape'].exterior.xy
                         self.axes.plot(x, y, linespec)
                         self.axes.plot(x, y, linespec)

+ 170 - 24
flatcamGUI/VisPyVisuals.py

@@ -17,10 +17,9 @@ from flatcamGUI.VisPyTesselators import GLUTess
 
 
 
 
 class FlatCAMLineVisual(LineVisual):
 class FlatCAMLineVisual(LineVisual):
-    def __init__(self, pos=None, color=(0.5, 0.5, 0.5, 1), width=1, connect='strip',
-                            method='gl', antialias=False):
-        LineVisual.__init__(self, pos=None, color=(0.5, 0.5, 0.5, 1), width=1, connect='strip',
-                            method='gl', antialias=True)
+    def __init__(self, pos=None, color=(0.5, 0.5, 0.5, 1), width=1, connect='strip', method='gl', antialias=False):
+        LineVisual.__init__(self, pos=pos, color=color, width=width, connect=connect,
+                            method=method, antialias=True)
 
 
     def clear_data(self):
     def clear_data(self):
         self._bounds = None
         self._bounds = None
@@ -158,11 +157,14 @@ class ShapeGroup(object):
         if update:
         if update:
             self._collection.redraw([])             # Skip waiting results
             self._collection.redraw([])             # Skip waiting results
 
 
-    def redraw(self):
+    def redraw(self, update_colors=None):
         """
         """
         Redraws shape collection
         Redraws shape collection
         """
         """
-        self._collection.redraw(self._indexes)
+        if update_colors:
+            self._collection.redraw(self._indexes, update_colors=update_colors)
+        else:
+            self._collection.redraw(self._indexes)
 
 
     @property
     @property
     def visible(self):
     def visible(self):
@@ -228,9 +230,9 @@ class ShapeCollectionVisual(CompoundVisual):
             pass
             pass
             m.set_gl_state(polygon_offset_fill=True, polygon_offset=(1, 1), cull_face=False)
             m.set_gl_state(polygon_offset_fill=True, polygon_offset=(1, 1), cull_face=False)
 
 
-        for l in self._lines:
+        for lne in self._lines:
             pass
             pass
-            l.set_gl_state(blend=True)
+            lne.set_gl_state(blend=True)
 
 
         self.freeze()
         self.freeze()
 
 
@@ -245,6 +247,8 @@ class ShapeCollectionVisual(CompoundVisual):
             Line/edge color
             Line/edge color
         :param face_color: str, tuple
         :param face_color: str, tuple
             Polygon face color
             Polygon face color
+        :param alpha: str
+            Polygon transparency
         :param visible: bool
         :param visible: bool
             Shape visibility
             Shape visibility
         :param update: bool
         :param update: bool
@@ -271,11 +275,11 @@ class ShapeCollectionVisual(CompoundVisual):
         # Add data to process pool if pool exists
         # Add data to process pool if pool exists
         try:
         try:
             self.results[key] = self.pool.map_async(_update_shape_buffers, [self.data[key]])
             self.results[key] = self.pool.map_async(_update_shape_buffers, [self.data[key]])
-        except Exception as e:
+        except Exception:
             self.data[key] = _update_shape_buffers(self.data[key])
             self.data[key] = _update_shape_buffers(self.data[key])
 
 
         if update:
         if update:
-            self.redraw()                       # redraw() waits for pool process end
+            self.redraw()   # redraw() waits for pool process end
 
 
         return key
         return key
 
 
@@ -309,6 +313,131 @@ class ShapeCollectionVisual(CompoundVisual):
         if update:
         if update:
             self.__update()
             self.__update()
 
 
+    def update_color(self, new_mesh_color=None, new_line_color=None, indexes=None):
+        if (new_mesh_color is None or new_mesh_color == '') and (new_line_color is None or new_line_color == ''):
+            return
+
+        if not self.data:
+            return
+
+        mesh_colors = [[] for _ in range(0, len(self._meshes))]     # Face colors
+        line_colors = [[] for _ in range(0, len(self._meshes))]     # Line colors
+        line_pts = [[] for _ in range(0, len(self._lines))]         # Vertices for line
+
+        # Lock sub-visuals updates
+        self.update_lock.acquire(True)
+        # Merge shapes buffers
+
+        if indexes is None:
+            for k, data in list(self.data.items()):
+                if data['visible'] and 'line_pts' in data:
+                    if new_mesh_color and new_mesh_color != '':
+                        dim_mesh_tris = (len(data['mesh_tris']) // 3)
+                        if dim_mesh_tris != 0:
+                            try:
+                                mesh_colors[data['layer']] += [Color(new_mesh_color).rgba] * dim_mesh_tris
+                                self.data[k]['face_color'] = new_mesh_color
+
+                                new_temp = list()
+                                for i in range(len(data['mesh_colors'])):
+                                    new_temp.append(Color(new_mesh_color).rgba)
+                                data['mesh_colors'] = new_temp
+                            except Exception as e:
+                                print("VisPyVisuals.ShapeCollectionVisual.update_color(). "
+                                      "Create mesh colors --> Data error. %s" % str(e))
+
+                    if new_line_color and new_line_color != '':
+                        dim_line_pts = (len(data['line_pts']))
+                        if dim_line_pts != 0:
+                            try:
+                                line_pts[data['layer']] += data['line_pts']
+                                line_colors[data['layer']] += [Color(new_line_color).rgba] * dim_line_pts
+                                self.data[k]['color'] = new_line_color
+
+                                new_temp = list()
+                                for i in range(len(data['line_colors'])):
+                                    new_temp.append(Color(new_line_color).rgba)
+                                data['line_colors'] = new_temp
+                            except Exception as e:
+                                print("VisPyVisuals.ShapeCollectionVisual.update_color(). "
+                                      "Create line colors --> Data error. %s" % str(e))
+        else:
+            for k, data in list(self.data.items()):
+                if data['visible'] and 'line_pts' in data:
+                    dim_mesh_tris = (len(data['mesh_tris']) // 3)
+                    dim_line_pts = (len(data['line_pts']))
+
+                    if k in indexes:
+                        if new_mesh_color and new_mesh_color != '':
+                            if dim_mesh_tris != 0:
+                                try:
+                                    mesh_colors[data['layer']] += [Color(new_mesh_color).rgba] * dim_mesh_tris
+                                    self.data[k]['face_color'] = new_mesh_color
+
+                                    new_temp = list()
+                                    for i in range(len(data['mesh_colors'])):
+                                        new_temp.append(Color(new_mesh_color).rgba)
+                                    data['mesh_colors'] = new_temp
+                                except Exception as e:
+                                    print("VisPyVisuals.ShapeCollectionVisual.update_color(). "
+                                          "Create mesh colors --> Data error. %s" % str(e))
+                        if new_line_color and new_line_color != '':
+                            if dim_line_pts != 0:
+                                try:
+                                    line_pts[data['layer']] += data['line_pts']
+                                    line_colors[data['layer']] += [Color(new_line_color).rgba] * dim_line_pts
+                                    self.data[k]['color'] = new_line_color
+
+                                    new_temp = list()
+                                    for i in range(len(data['line_colors'])):
+                                        new_temp.append(Color(new_line_color).rgba)
+                                    data['line_colors'] = new_temp
+                                except Exception as e:
+                                    print("VisPyVisuals.ShapeCollectionVisual.update_color(). "
+                                          "Create line colors --> Data error. %s" % str(e))
+                    else:
+                        if dim_mesh_tris != 0:
+                            try:
+                                mesh_colors[data['layer']] += [Color(data['face_color']).rgba] * dim_mesh_tris
+                            except Exception as e:
+                                print("VisPyVisuals.ShapeCollectionVisual.update_color(). "
+                                      "Create mesh colors --> Data error. %s" % str(e))
+
+                        if dim_line_pts != 0:
+                            try:
+                                line_pts[data['layer']] += data['line_pts']
+                                line_colors[data['layer']] += [Color(data['color']).rgba] * dim_line_pts
+                            except Exception as e:
+                                print("VisPyVisuals.ShapeCollectionVisual.update_color(). "
+                                      "Create line colors --> Data error. %s" % str(e))
+
+        # Updating meshes
+        if new_mesh_color and new_mesh_color != '':
+            for i, mesh in enumerate(self._meshes):
+                if mesh_colors[i]:
+                    try:
+                        mesh._meshdata.set_face_colors(colors=np.asarray(mesh_colors[i]))
+                        mesh.mesh_data_changed()
+                    except Exception as e:
+                        print("VisPyVisuals.ShapeCollectionVisual.update_color(). "
+                              "Apply mesh colors --> Data error. %s" % str(e))
+
+        # Updating lines
+        if new_line_color and new_line_color != '':
+            for i, line in enumerate(self._lines):
+                if len(line_pts[i]) > 0:
+                    try:
+                        line._color = np.asarray(line_colors[i])
+                        line._changed['color'] = True
+                        line.update()
+                    except Exception as e:
+                        print("VisPyVisuals.ShapeCollectionVisual.update_color(). "
+                              "Apply line colors --> Data error. %s" % str(e))
+                else:
+                    line.clear_data()
+
+        self.update_lock.release()
+
     def __update(self):
     def __update(self):
         """
         """
         Merges internal buffers, sets data to visuals, redraws collection on scene
         Merges internal buffers, sets data to visuals, redraws collection on scene
@@ -328,20 +457,23 @@ class ShapeCollectionVisual(CompoundVisual):
                 try:
                 try:
                     line_pts[data['layer']] += data['line_pts']
                     line_pts[data['layer']] += data['line_pts']
                     line_colors[data['layer']] += data['line_colors']
                     line_colors[data['layer']] += data['line_colors']
-                    mesh_tris[data['layer']] += [x + len(mesh_vertices[data['layer']])
-                                                 for x in data['mesh_tris']]
 
 
+                    mesh_tris[data['layer']] += [x + len(mesh_vertices[data['layer']]) for x in data['mesh_tris']]
                     mesh_vertices[data['layer']] += data['mesh_vertices']
                     mesh_vertices[data['layer']] += data['mesh_vertices']
                     mesh_colors[data['layer']] += data['mesh_colors']
                     mesh_colors[data['layer']] += data['mesh_colors']
                 except Exception as e:
                 except Exception as e:
-                    print("Data error", e)
+                    print("VisPyVisuals.ShapeCollectionVisual._update() --> Data error. %s" % str(e))
 
 
         # Updating meshes
         # Updating meshes
         for i, mesh in enumerate(self._meshes):
         for i, mesh in enumerate(self._meshes):
             if len(mesh_vertices[i]) > 0:
             if len(mesh_vertices[i]) > 0:
                 set_state(polygon_offset_fill=False)
                 set_state(polygon_offset_fill=False)
-                mesh.set_data(np.asarray(mesh_vertices[i]), np.asarray(mesh_tris[i], dtype=np.uint32)
-                              .reshape((-1, 3)), face_colors=np.asarray(mesh_colors[i]))
+                faces_array = np.asarray(mesh_tris[i], dtype=np.uint32)
+                mesh.set_data(
+                    vertices=np.asarray(mesh_vertices[i]),
+                    faces=faces_array.reshape((-1, 3)),
+                    face_colors=np.asarray(mesh_colors[i])
+                )
             else:
             else:
                 mesh.set_data()
                 mesh.set_data()
 
 
@@ -350,17 +482,20 @@ class ShapeCollectionVisual(CompoundVisual):
         # Updating lines
         # Updating lines
         for i, line in enumerate(self._lines):
         for i, line in enumerate(self._lines):
             if len(line_pts[i]) > 0:
             if len(line_pts[i]) > 0:
-                line.set_data(np.asarray(line_pts[i]), np.asarray(line_colors[i]), self._line_width, 'segments')
+                line.set_data(
+                    pos=np.asarray(line_pts[i]),
+                    color=np.asarray(line_colors[i]),
+                    width=self._line_width,
+                    connect='segments')
             else:
             else:
                 line.clear_data()
                 line.clear_data()
 
 
             line._bounds_changed()
             line._bounds_changed()
 
 
         self._bounds_changed()
         self._bounds_changed()
-
         self.update_lock.release()
         self.update_lock.release()
 
 
-    def redraw(self, indexes=None):
+    def redraw(self, indexes=None, update_colors=None):
         """
         """
         Redraws collection
         Redraws collection
         :param indexes: list
         :param indexes: list
@@ -369,19 +504,30 @@ class ShapeCollectionVisual(CompoundVisual):
         # Only one thread can update data
         # Only one thread can update data
         self.results_lock.acquire(True)
         self.results_lock.acquire(True)
 
 
-        for i in list(self.data.copy().keys()) if not indexes else indexes:
-            if i in list(self.results.copy().keys()):
+        for i in list(self.data.keys()) if not indexes else indexes:
+            if i in list(self.results.keys()):
                 try:
                 try:
                     self.results[i].wait()                                  # Wait for process results
                     self.results[i].wait()                                  # Wait for process results
                     if i in self.data:
                     if i in self.data:
                         self.data[i] = self.results[i].get()[0]             # Store translated data
                         self.data[i] = self.results[i].get()[0]             # Store translated data
                         del self.results[i]
                         del self.results[i]
                 except Exception as e:
                 except Exception as e:
-                    print(e, indexes)
+                    print("VisPyVisuals.ShapeCollectionVisual.redraw() --> Data error = %s. Indexes = %s" %
+                          (str(e), str(indexes)))
 
 
         self.results_lock.release()
         self.results_lock.release()
 
 
-        self.__update()
+        if update_colors is None:
+            self.__update()
+        else:
+            try:
+                self.update_color(
+                    new_mesh_color=update_colors[0],
+                    new_line_color=update_colors[1],
+                    indexes=indexes
+                )
+            except Exception as e:
+                print("VisPyVisuals.ShapeCollectionVisual.redraw() --> Update colors error = %s." % str(e))
 
 
     def lock_updates(self):
     def lock_updates(self):
         self.update_lock.acquire(True)
         self.update_lock.acquire(True)
@@ -489,7 +635,7 @@ class TextCollectionVisual(TextVisual):
         self.lock.release()
         self.lock.release()
 
 
         # Prepare data for translation
         # Prepare data for translation
-        self.data[key] = {'text': text, 'pos': pos, 'visible': visible,'font_size': font_size, 'color': color}
+        self.data[key] = {'text': text, 'pos': pos, 'visible': visible, 'font_size': font_size, 'color': color}
 
 
         if update:
         if update:
             self.redraw()
             self.redraw()
@@ -537,7 +683,7 @@ class TextCollectionVisual(TextVisual):
                     font_s = data['font_size']
                     font_s = data['font_size']
                     color = data['color']
                     color = data['color']
                 except Exception as e:
                 except Exception as e:
-                    print("Data error", e)
+                    print("VisPyVisuals.TextCollectionVisual._update() --> Data error. %s" % str(e))
 
 
         # Updating text
         # Updating text
         if len(labels) > 0:
         if len(labels) > 0:

+ 1 - 1
flatcamTools/ToolDistance.py

@@ -349,7 +349,7 @@ class Distance(FlatCAMTool):
                 d = math.sqrt(dx ** 2 + dy ** 2)
                 d = math.sqrt(dx ** 2 + dy ** 2)
                 self.stop_entry.set_value("(%.*f, %.*f)" % (self.decimals, pos[0], self.decimals, pos[1]))
                 self.stop_entry.set_value("(%.*f, %.*f)" % (self.decimals, pos[0], self.decimals, pos[1]))
 
 
-                self.app.inform.emit("{tx1}: {tx2} D(x) = {d_x} | D(y) = {d_y} | (tx3} = {d_z}".format(
+                self.app.inform.emit("{tx1}: {tx2} D(x) = {d_x} | D(y) = {d_y} | {tx3} = {d_z}".format(
                     tx1=_("MEASURING"),
                     tx1=_("MEASURING"),
                     tx2=_("Result"),
                     tx2=_("Result"),
                     tx3=_("Distance"),
                     tx3=_("Distance"),

BIN
share/blue32.png


BIN
share/brown32.png


BIN
share/green32.png


BIN
share/red32.png


BIN
share/set_color16.png


BIN
share/set_color32.png


BIN
share/violet32.png


BIN
share/yellow32.png