Explorar o código

- some fixes and prepared the activity monitor area to receive updated texts

Marius Stanciu %!s(int64=6) %!d(string=hai) anos
pai
achega
c1ce72e9fb
Modificáronse 7 ficheiros con 254 adicións e 101 borrados
  1. 8 8
      FlatCAMApp.py
  2. 79 76
      FlatCAMObj.py
  3. 22 3
      FlatCAMProcess.py
  4. 2 0
      README.md
  5. 7 9
      flatcamTools/ToolNonCopperClear.py
  6. 132 4
      flatcamTools/ToolPaint.py
  7. 4 1
      flatcamTools/ToolPanelize.py

+ 8 - 8
FlatCAMApp.py

@@ -3459,14 +3459,14 @@ class App(QtCore.QObject):
 
 
         # here it is done the object plotting
         # here it is done the object plotting
         def worker_task(t_obj):
         def worker_task(t_obj):
-            with self.proc_container.new("Plotting"):
-                if isinstance(t_obj, FlatCAMCNCjob):
-                    t_obj.plot(kind=self.defaults["cncjob_plot_kind"])
-                else:
-                    t_obj.plot()
-                t1 = time.time()  # DEBUG
-                self.log.debug("%f seconds adding object and plotting." % (t1 - t0))
-                self.object_plotted.emit(t_obj)
+            # with self.proc_container.new(_("Plotting")):
+            if isinstance(t_obj, FlatCAMCNCjob):
+                t_obj.plot(kind=self.defaults["cncjob_plot_kind"])
+            else:
+                t_obj.plot()
+            t1 = time.time()  # DEBUG
+            self.log.debug("%f seconds adding object and plotting." % (t1 - t0))
+            self.object_plotted.emit(t_obj)
 
 
         # Send to worker
         # Send to worker
         # self.worker.add_task(worker_task, [self])
         # self.worker.add_task(worker_task, [self])

+ 79 - 76
FlatCAMObj.py

@@ -348,16 +348,16 @@ class FlatCAMObj(QtCore.QObject):
         log.debug("FlatCAMObj.visible()")
         log.debug("FlatCAMObj.visible()")
 
 
         def worker_task(app_obj):
         def worker_task(app_obj):
-            app_obj.shapes.visible = value
+            self.shapes.visible = value
 
 
             # Not all object types has annotations
             # Not all object types has annotations
             try:
             try:
-                app_obj.annotation.visible = value
+                self.annotation.visible = value
             except Exception as e:
             except Exception as e:
                 pass
                 pass
 
 
         if threaded is False:
         if threaded is False:
-            worker_task(app_obj=self)
+            worker_task(app_obj=self.app)
         else:
         else:
             self.app.worker_task.emit({'fcn': worker_task, 'params': [self]})
             self.app.worker_task.emit({'fcn': worker_task, 'params': [self]})
 
 
@@ -1179,39 +1179,40 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
             color[3] = 1
             color[3] = 1
             return color
             return color
 
 
-        try:
-            if self.options["solid"]:
-                for g in geometry:
-                    if type(g) == Polygon or type(g) == LineString:
-                        self.add_shape(shape=g, color=color,
-                                       face_color=random_color() if self.options['multicolored']
-                                       else face_color, visible=self.options['plot'])
-                    elif type(g) == Point:
-                        pass
-                    else:
-                        try:
-                            for el in g:
-                                self.add_shape(shape=el, color=color,
-                                               face_color=random_color() if self.options['multicolored']
-                                               else face_color, visible=self.options['plot'])
-                        except TypeError:
+        with self.app.proc_container.new(_("Plotting")):
+            try:
+                if self.options["solid"]:
+                    for g in geometry:
+                        if type(g) == Polygon or type(g) == LineString:
                             self.add_shape(shape=g, color=color,
                             self.add_shape(shape=g, color=color,
                                            face_color=random_color() if self.options['multicolored']
                                            face_color=random_color() if self.options['multicolored']
                                            else face_color, visible=self.options['plot'])
                                            else face_color, visible=self.options['plot'])
-            else:
-                for g in geometry:
-                    if type(g) == Polygon or type(g) == LineString:
-                        self.add_shape(shape=g, color=random_color() if self.options['multicolored'] else 'black',
-                                       visible=self.options['plot'])
-                    elif type(g) == Point:
-                        pass
-                    else:
-                        for el in g:
-                            self.add_shape(shape=el, color=random_color() if self.options['multicolored'] else 'black',
+                        elif type(g) == Point:
+                            pass
+                        else:
+                            try:
+                                for el in g:
+                                    self.add_shape(shape=el, color=color,
+                                                   face_color=random_color() if self.options['multicolored']
+                                                   else face_color, visible=self.options['plot'])
+                            except TypeError:
+                                self.add_shape(shape=g, color=color,
+                                               face_color=random_color() if self.options['multicolored']
+                                               else face_color, visible=self.options['plot'])
+                else:
+                    for g in geometry:
+                        if type(g) == Polygon or type(g) == LineString:
+                            self.add_shape(shape=g, color=random_color() if self.options['multicolored'] else 'black',
                                            visible=self.options['plot'])
                                            visible=self.options['plot'])
-            self.shapes.redraw()
-        except (ObjectDeleted, AttributeError):
-            self.shapes.clear(update=True)
+                        elif type(g) == Point:
+                            pass
+                        else:
+                            for el in g:
+                                self.add_shape(shape=el, color=random_color() if self.options['multicolored'] else 'black',
+                                               visible=self.options['plot'])
+                self.shapes.redraw()
+            except (ObjectDeleted, AttributeError):
+                self.shapes.clear(update=True)
 
 
     # experimental plot() when the solid_geometry is stored in the self.apertures
     # experimental plot() when the solid_geometry is stored in the self.apertures
     def plot_aperture(self, **kwargs):
     def plot_aperture(self, **kwargs):
@@ -2928,28 +2929,29 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         # except (ObjectDeleted, AttributeError, KeyError):
         # except (ObjectDeleted, AttributeError, KeyError):
         #     self.shapes.clear(update=True)
         #     self.shapes.clear(update=True)
 
 
-        # this stays for compatibility reasons, in case we try to open old projects
-        try:
-            __ = iter(self.solid_geometry)
-        except TypeError:
-            self.solid_geometry = [self.solid_geometry]
+        with self.app.proc_container.new(_("Plotting")):
+            # this stays for compatibility reasons, in case we try to open old projects
+            try:
+                __ = iter(self.solid_geometry)
+            except TypeError:
+                self.solid_geometry = [self.solid_geometry]
 
 
-        try:
-            # Plot Excellon (All polygons?)
-            if self.options["solid"]:
-                for geo in self.solid_geometry:
-                    self.add_shape(shape=geo, color='#750000BF', face_color='#C40000BF',
-                                   visible=self.options['plot'],
-                                   layer=2)
-            else:
-                for geo in self.solid_geometry:
-                    self.add_shape(shape=geo.exterior, color='red', visible=self.options['plot'])
-                    for ints in geo.interiors:
-                        self.add_shape(shape=ints, color='orange', visible=self.options['plot'])
+            try:
+                # Plot Excellon (All polygons?)
+                if self.options["solid"]:
+                    for geo in self.solid_geometry:
+                        self.add_shape(shape=geo, color='#750000BF', face_color='#C40000BF',
+                                       visible=self.options['plot'],
+                                       layer=2)
+                else:
+                    for geo in self.solid_geometry:
+                        self.add_shape(shape=geo.exterior, color='red', visible=self.options['plot'])
+                        for ints in geo.interiors:
+                            self.add_shape(shape=ints, color='orange', visible=self.options['plot'])
 
 
-            self.shapes.redraw()
-        except (ObjectDeleted, AttributeError):
-            self.shapes.clear(update=True)
+                self.shapes.redraw()
+            except (ObjectDeleted, AttributeError):
+                self.shapes.clear(update=True)
 
 
 
 
 class FlatCAMGeometry(FlatCAMObj, Geometry):
 class FlatCAMGeometry(FlatCAMObj, Geometry):
@@ -6039,32 +6041,33 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
         if not FlatCAMObj.plot(self):
         if not FlatCAMObj.plot(self):
             return
             return
 
 
-        visible = visible if visible else self.options['plot']
+        with self.app.proc_container.new(_("Plotting")):
+            visible = visible if visible else self.options['plot']
 
 
-        if self.ui.annotation_cb.get_value() and self.ui.plot_cb.get_value():
-            self.text_col.enabled = True
-        else:
-            self.text_col.enabled = False
-        self.annotation.redraw()
-
-        try:
-            if self.multitool is False:  # single tool usage
-                try:
-                    dia_plot = float(self.options["tooldia"])
-                except ValueError:
-                    # we may have a tuple with only one element and a comma
-                    dia_plot = [float(el) for el in self.options["tooldia"].split(',') if el != ''][0]
-                self.plot2(dia_plot, obj=self, visible=visible, kind=kind)
+            if self.ui.annotation_cb.get_value() and self.ui.plot_cb.get_value():
+                self.text_col.enabled = True
             else:
             else:
-                # multiple tools usage
-                for tooluid_key in self.cnc_tools:
-                    tooldia = float('%.4f' % float(self.cnc_tools[tooluid_key]['tooldia']))
-                    gcode_parsed = self.cnc_tools[tooluid_key]['gcode_parsed']
-                    self.plot2(tooldia=tooldia, obj=self, visible=visible, gcode_parsed=gcode_parsed, kind=kind)
-            self.shapes.redraw()
-        except (ObjectDeleted, AttributeError):
-            self.shapes.clear(update=True)
-            self.annotation.clear(update=True)
+                self.text_col.enabled = False
+            self.annotation.redraw()
+
+            try:
+                if self.multitool is False:  # single tool usage
+                    try:
+                        dia_plot = float(self.options["tooldia"])
+                    except ValueError:
+                        # we may have a tuple with only one element and a comma
+                        dia_plot = [float(el) for el in self.options["tooldia"].split(',') if el != ''][0]
+                    self.plot2(dia_plot, obj=self, visible=visible, kind=kind)
+                else:
+                    # multiple tools usage
+                    for tooluid_key in self.cnc_tools:
+                        tooldia = float('%.4f' % float(self.cnc_tools[tooluid_key]['tooldia']))
+                        gcode_parsed = self.cnc_tools[tooluid_key]['gcode_parsed']
+                        self.plot2(tooldia=tooldia, obj=self, visible=visible, gcode_parsed=gcode_parsed, kind=kind)
+                self.shapes.redraw()
+            except (ObjectDeleted, AttributeError):
+                self.shapes.clear(update=True)
+                self.annotation.clear(update=True)
 
 
     def on_annotation_change(self):
     def on_annotation_change(self):
         if self.ui.annotation_cb.get_value():
         if self.ui.annotation_cb.get_value():

+ 22 - 3
FlatCAMProcess.py

@@ -10,6 +10,13 @@ from flatcamGUI.FlatCAMGUI import FlatCAMActivityView
 from PyQt5 import QtCore
 from PyQt5 import QtCore
 import weakref
 import weakref
 
 
+import gettext
+import FlatCAMTranslation as fcTranslate
+import builtins
+
+fcTranslate.apply_language('strings')
+if '_' not in builtins.__dict__:
+    _ = gettext.gettext
 
 
 # import logging
 # import logging
 
 
@@ -131,6 +138,9 @@ class FCVisibleProcessContainer(QtCore.QObject, FCProcessContainer):
 
 
         self.view = view
         self.view = view
 
 
+        self.text_to_display_in_activity = ''
+        self.new_text = ' '
+
         self.something_changed.connect(self.update_view)
         self.something_changed.connect(self.update_view)
 
 
     def on_done(self, proc):
     def on_done(self, proc):
@@ -143,14 +153,23 @@ class FCVisibleProcessContainer(QtCore.QObject, FCProcessContainer):
         # self.app.log.debug("FCVisibleProcessContainer.on_change()")
         # self.app.log.debug("FCVisibleProcessContainer.on_change()")
         super(FCVisibleProcessContainer, self).on_change(proc)
         super(FCVisibleProcessContainer, self).on_change(proc)
 
 
+        # whenever there is a change update the message on activity
+        self.text_to_display_in_activity = self.procs[0]().status_msg()
+
         self.something_changed.emit()
         self.something_changed.emit()
 
 
     def update_view(self):
     def update_view(self):
         if len(self.procs) == 0:
         if len(self.procs) == 0:
             self.view.set_idle()
             self.view.set_idle()
+            self.new_text = ''
 
 
         elif len(self.procs) == 1:
         elif len(self.procs) == 1:
-            self.view.set_busy(self.procs[0]().status_msg())
-
+            self.view.set_busy(self.text_to_display_in_activity + self.new_text)
         else:
         else:
-            self.view.set_busy("%d processes running." % len(self.procs))
+            self.view.set_busy("%d %s" % (len(self.procs), _("processes running.")))
+
+    def update_view_text(self, new_text):
+        # this has to be called after the method 'new' inherited by this class is called with a string text as param
+        self.new_text = new_text
+        if len(self.procs) == 1:
+            self.view.set_busy(self.text_to_display_in_activity + self.new_text)

+ 2 - 0
README.md

@@ -14,6 +14,8 @@ CAD program, and create G-Code for Isolation routing.
 - remade visibility threaded
 - remade visibility threaded
 - reimplemented the thread listening for new FlatCAM process starting with args so it is no longer subclassed but using the moveToThread function
 - reimplemented the thread listening for new FlatCAM process starting with args so it is no longer subclassed but using the moveToThread function
 - added percentage display for work done in NCC Tool
 - added percentage display for work done in NCC Tool
+- added percentage display for work done in Paint Tool
+- some fixes and prepared the activity monitor area to receive updated texts
 
 
 5.09.2019
 5.09.2019
 
 

+ 7 - 9
flatcamTools/ToolNonCopperClear.py

@@ -1637,11 +1637,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
                     area = MultiPolygon([area])
                     area = MultiPolygon([area])
 
 
                 # variables to display the percentage of work done
                 # variables to display the percentage of work done
-                step = int(len(area.geoms) / 100)
+                geo_len = len(area.geoms)
                 disp_number = 0
                 disp_number = 0
                 old_disp_number = 0
                 old_disp_number = 0
-                log.warning("Total number of polygons to be cleared. %s" % str(len(area.geoms)))
-                log.warning("Step: %d" % step)
+                log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
 
 
                 if area.geoms:
                 if area.geoms:
                     if len(area.geoms) > 0:
                     if len(area.geoms) > 0:
@@ -1687,10 +1686,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
                                     continue
                                     continue
 
 
                                 pol_nr += 1
                                 pol_nr += 1
-                                disp_number = int(pol_nr / step)
+                                disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 99]))
                                 # log.debug("Polygons cleared: %d" % pol_nr)
                                 # log.debug("Polygons cleared: %d" % pol_nr)
 
 
-                                if disp_number > old_disp_number and disp_number <= 100:
+                                if old_disp_number < disp_number <= 100:
                                     app_obj.inform.emit(
                                     app_obj.inform.emit(
                                         '[success] %s %s%s %s: %d%%' % (_('Non-Copper Clearing with tool diameter = '),
                                         '[success] %s %s%s %s: %d%%' % (_('Non-Copper Clearing with tool diameter = '),
                                                                       str(tool),
                                                                       str(tool),
@@ -1937,11 +1936,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
                 allparts[:] = []
                 allparts[:] = []
 
 
                 # variables to display the percentage of work done
                 # variables to display the percentage of work done
-                step = int(len(area.geoms) / 100)
+                geo_len = len(area.geoms)
                 disp_number = 0
                 disp_number = 0
                 old_disp_number = 0
                 old_disp_number = 0
-                log.warning("Total number of polygons to be cleared. %s" % str(len(area.geoms)))
-                log.warning("Step: %d" % step)
+                log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
 
 
                 if area.geoms:
                 if area.geoms:
                     if len(area.geoms) > 0:
                     if len(area.geoms) > 0:
@@ -1995,7 +1993,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
                                                 rest_geo.append(poly)
                                                 rest_geo.append(poly)
 
 
                                 pol_nr += 1
                                 pol_nr += 1
-                                disp_number = int(pol_nr / step)
+                                disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 99]))
                                 # log.debug("Polygons cleared: %d" % pol_nr)
                                 # log.debug("Polygons cleared: %d" % pol_nr)
 
 
                                 if disp_number > old_disp_number and disp_number <= 100:
                                 if disp_number > old_disp_number and disp_number <= 100:

+ 132 - 4
flatcamTools/ToolPaint.py

@@ -1497,6 +1497,8 @@ class ToolPaint(FlatCAMTool, Gerber):
             # assert isinstance(geo_obj, FlatCAMGeometry), \
             # assert isinstance(geo_obj, FlatCAMGeometry), \
             #     "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
             #     "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
 
 
+            log.debug("Paint Tool. Normal painting all task started.")
+
             tool_dia = None
             tool_dia = None
             if order == 'fwd':
             if order == 'fwd':
                 sorted_tools.sort(reverse=False)
                 sorted_tools.sort(reverse=False)
@@ -1520,6 +1522,14 @@ class ToolPaint(FlatCAMTool, Gerber):
 
 
             geo_obj.solid_geometry = []
             geo_obj.solid_geometry = []
             for tool_dia in sorted_tools:
             for tool_dia in sorted_tools:
+                log.debug("Starting geometry processing for tool: %s" % str(tool_dia))
+                app_obj.inform.emit(
+                    '[success] %s %s%s %s: %d%%' % (_('Painting with tool diameter = '),
+                                                    str(tool_dia),
+                                                    self.units.lower(),
+                                                    _('started. Progress'),
+                                                    0)
+                )
 
 
                 # find the tooluid associated with the current tool_dia so we know where to add the tool solid_geometry
                 # find the tooluid associated with the current tool_dia so we know where to add the tool solid_geometry
                 for k, v in tools_storage.items():
                 for k, v in tools_storage.items():
@@ -1527,7 +1537,15 @@ class ToolPaint(FlatCAMTool, Gerber):
                         current_uid = int(k)
                         current_uid = int(k)
                         break
                         break
 
 
-                for geo in recurse(obj.solid_geometry):
+                painted_area = recurse(obj.solid_geometry)
+                # variables to display the percentage of work done
+                geo_len = len(painted_area)
+                disp_number = 0
+                old_disp_number = 0
+                log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
+
+                pol_nr = 0
+                for geo in painted_area:
                     try:
                     try:
                         # Polygons are the only really paintable geometries, lines in theory have no area to be painted
                         # Polygons are the only really paintable geometries, lines in theory have no area to be painted
                         if not isinstance(geo, Polygon):
                         if not isinstance(geo, Polygon):
@@ -1570,6 +1588,21 @@ class ToolPaint(FlatCAMTool, Gerber):
                               "Or a different Method of paint\n%s") % str(e))
                               "Or a different Method of paint\n%s") % str(e))
                         return
                         return
 
 
+                    pol_nr += 1
+                    disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 99]))
+                    # log.debug("Polygons cleared: %d" % pol_nr)
+
+                    if old_disp_number < disp_number <= 100:
+                        app_obj.inform.emit(
+                            '[success] %s %s%s %s: %d%%' % (_('Painting with tool diameter = '),
+                                                            str(tool_dia),
+                                                            self.units.lower(),
+                                                            _('started. Progress'),
+                                                            disp_number)
+                        )
+                        old_disp_number = disp_number
+                        # log.debug("Polygons cleared: %d. Percentage done: %d%%" % (pol_nr, disp_number))
+
                 # add the solid_geometry to the current too in self.paint_tools (tools_storage)
                 # add the solid_geometry to the current too in self.paint_tools (tools_storage)
                 # dictionary and then reset the temporary list that stored that solid_geometry
                 # dictionary and then reset the temporary list that stored that solid_geometry
                 tools_storage[current_uid]['solid_geometry'] = deepcopy(total_geometry)
                 tools_storage[current_uid]['solid_geometry'] = deepcopy(total_geometry)
@@ -1618,6 +1651,8 @@ class ToolPaint(FlatCAMTool, Gerber):
             assert isinstance(geo_obj, FlatCAMGeometry), \
             assert isinstance(geo_obj, FlatCAMGeometry), \
                 "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
                 "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
 
 
+            log.debug("Paint Tool. Rest machining painting all task started.")
+
             tool_dia = None
             tool_dia = None
             sorted_tools.sort(reverse=True)
             sorted_tools.sort(reverse=True)
 
 
@@ -1636,7 +1671,17 @@ class ToolPaint(FlatCAMTool, Gerber):
                 return
                 return
 
 
             for tool_dia in sorted_tools:
             for tool_dia in sorted_tools:
-                for geo in recurse(obj.solid_geometry):
+                log.debug("Starting geometry processing for tool: %s" % str(tool_dia))
+
+                painted_area = recurse(obj.solid_geometry)
+                # variables to display the percentage of work done
+                geo_len = int(len(painted_area) / 100)
+                disp_number = 0
+                old_disp_number = 0
+                log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
+
+                pol_nr = 0
+                for geo in painted_area:
                     try:
                     try:
                         geo = Polygon(geo) if not isinstance(geo, Polygon) else geo
                         geo = Polygon(geo) if not isinstance(geo, Polygon) else geo
                         poly_buf = geo.buffer(-paint_margin)
                         poly_buf = geo.buffer(-paint_margin)
@@ -1670,6 +1715,21 @@ class ToolPaint(FlatCAMTool, Gerber):
                               "Or a different Method of paint\n%s") % str(e))
                               "Or a different Method of paint\n%s") % str(e))
                         return
                         return
 
 
+                    pol_nr += 1
+                    disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 99]))
+                    # log.debug("Polygons cleared: %d" % pol_nr)
+
+                    if old_disp_number < disp_number <= 100:
+                        app_obj.inform.emit(
+                            '[success] %s %s%s %s: %d%%' % (_('Painting with tool diameter = '),
+                                                            str(tool_dia),
+                                                            self.units.lower(),
+                                                            _('started. Progress'),
+                                                            disp_number)
+                        )
+                        old_disp_number = disp_number
+                        # log.debug("Polygons cleared: %d. Percentage done: %d%%" % (pol_nr, disp_number))
+
                 # find the tooluid associated with the current tool_dia so we know where to add the tool solid_geometry
                 # find the tooluid associated with the current tool_dia so we know where to add the tool solid_geometry
                 for k, v in tools_storage.items():
                 for k, v in tools_storage.items():
                     if float('%.4f' % v['tooldia']) == float('%.4f' % tool_dia):
                     if float('%.4f' % v['tooldia']) == float('%.4f' % tool_dia):
@@ -1833,6 +1893,9 @@ class ToolPaint(FlatCAMTool, Gerber):
         def gen_paintarea(geo_obj, app_obj):
         def gen_paintarea(geo_obj, app_obj):
             # assert isinstance(geo_obj, FlatCAMGeometry), \
             # assert isinstance(geo_obj, FlatCAMGeometry), \
             #     "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
             #     "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
+
+            log.debug("Paint Tool. Normal painting area task started.")
+
             tool_dia = None
             tool_dia = None
             if order == 'fwd':
             if order == 'fwd':
                 sorted_tools.sort(reverse=False)
                 sorted_tools.sort(reverse=False)
@@ -1867,6 +1930,14 @@ class ToolPaint(FlatCAMTool, Gerber):
 
 
             geo_obj.solid_geometry = []
             geo_obj.solid_geometry = []
             for tool_dia in sorted_tools:
             for tool_dia in sorted_tools:
+                log.debug("Starting geometry processing for tool: %s" % str(tool_dia))
+                app_obj.inform.emit(
+                    '[success] %s %s%s %s: %d%%' % (_('Painting with tool diameter = '),
+                                                    str(tool_dia),
+                                                    self.units.lower(),
+                                                    _('started. Progress'),
+                                                    0)
+                )
 
 
                 # find the tooluid associated with the current tool_dia so we know where to add the tool solid_geometry
                 # find the tooluid associated with the current tool_dia so we know where to add the tool solid_geometry
                 for k, v in tools_storage.items():
                 for k, v in tools_storage.items():
@@ -1874,7 +1945,15 @@ class ToolPaint(FlatCAMTool, Gerber):
                         current_uid = int(k)
                         current_uid = int(k)
                         break
                         break
 
 
-                for geo in recurse(geo_to_paint):
+                painted_area = recurse(geo_to_paint)
+                # variables to display the percentage of work done
+                geo_len = len(painted_area)
+                disp_number = 0
+                old_disp_number = 0
+                log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
+
+                pol_nr = 0
+                for geo in painted_area:
                     try:
                     try:
                         # Polygons are the only really paintable geometries, lines in theory have no area to be painted
                         # Polygons are the only really paintable geometries, lines in theory have no area to be painted
                         if not isinstance(geo, Polygon):
                         if not isinstance(geo, Polygon):
@@ -1917,6 +1996,21 @@ class ToolPaint(FlatCAMTool, Gerber):
                               "Or a different Method of paint\n%s") % str(e))
                               "Or a different Method of paint\n%s") % str(e))
                         return
                         return
 
 
+                    pol_nr += 1
+                    disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 99]))
+                    # log.debug("Polygons cleared: %d" % pol_nr)
+
+                    if disp_number > old_disp_number and disp_number <= 100:
+                        app_obj.inform.emit(
+                            '[success] %s %s%s %s: %d%%' % (_('Painting with tool diameter = '),
+                                                            str(tool_dia),
+                                                            self.units.lower(),
+                                                            _('started. Progress'),
+                                                            disp_number)
+                        )
+                        old_disp_number = disp_number
+                        # log.debug("Polygons cleared: %d. Percentage done: %d%%" % (pol_nr, disp_number))
+
                 # add the solid_geometry to the current too in self.paint_tools (tools_storage)
                 # add the solid_geometry to the current too in self.paint_tools (tools_storage)
                 # dictionary and then reset the temporary list that stored that solid_geometry
                 # dictionary and then reset the temporary list that stored that solid_geometry
                 tools_storage[current_uid]['solid_geometry'] = deepcopy(total_geometry)
                 tools_storage[current_uid]['solid_geometry'] = deepcopy(total_geometry)
@@ -1965,6 +2059,8 @@ class ToolPaint(FlatCAMTool, Gerber):
             assert isinstance(geo_obj, FlatCAMGeometry), \
             assert isinstance(geo_obj, FlatCAMGeometry), \
                 "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
                 "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
 
 
+            log.debug("Paint Tool. Rest machining painting area task started.")
+
             tool_dia = None
             tool_dia = None
             sorted_tools.sort(reverse=True)
             sorted_tools.sort(reverse=True)
 
 
@@ -1983,7 +2079,24 @@ class ToolPaint(FlatCAMTool, Gerber):
                 return
                 return
 
 
             for tool_dia in sorted_tools:
             for tool_dia in sorted_tools:
-                for geo in recurse(obj.solid_geometry):
+                log.debug("Starting geometry processing for tool: %s" % str(tool_dia))
+                app_obj.inform.emit(
+                    '[success] %s %s%s %s: %d%%' % (_('Painting with tool diameter = '),
+                                                    str(tool_dia),
+                                                    self.units.lower(),
+                                                    _('started. Progress'),
+                                                    0)
+                )
+
+                painted_area = recurse(obj.solid_geometry)
+                # variables to display the percentage of work done
+                geo_len = len(painted_area)
+                disp_number = 0
+                old_disp_number = 0
+                log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
+
+                pol_nr = 0
+                for geo in painted_area:
                     try:
                     try:
                         geo = Polygon(geo) if not isinstance(geo, Polygon) else geo
                         geo = Polygon(geo) if not isinstance(geo, Polygon) else geo
                         poly_buf = geo.buffer(-paint_margin)
                         poly_buf = geo.buffer(-paint_margin)
@@ -2017,6 +2130,21 @@ class ToolPaint(FlatCAMTool, Gerber):
                               "Or a different Method of paint\n%s") % str(e))
                               "Or a different Method of paint\n%s") % str(e))
                         return
                         return
 
 
+                    pol_nr += 1
+                    disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 99]))
+                    # log.debug("Polygons cleared: %d" % pol_nr)
+
+                    if disp_number > old_disp_number and disp_number <= 100:
+                        app_obj.inform.emit(
+                            '[success] %s %s%s %s: %d%%' % (_('Painting with tool diameter = '),
+                                                            str(tool_dia),
+                                                            self.units.lower(),
+                                                            _('started. Progress'),
+                                                            disp_number)
+                        )
+                        old_disp_number = disp_number
+                        # log.debug("Polygons cleared: %d. Percentage done: %d%%" % (pol_nr, disp_number))
+
                 # find the tooluid associated with the current tool_dia so we know where to add the tool solid_geometry
                 # find the tooluid associated with the current tool_dia so we know where to add the tool solid_geometry
                 for k, v in tools_storage.items():
                 for k, v in tools_storage.items():
                     if float('%.4f' % v['tooldia']) == float('%.4f' % tool_dia):
                     if float('%.4f' % v['tooldia']) == float('%.4f' % tool_dia):

+ 4 - 1
flatcamTools/ToolPanelize.py

@@ -620,6 +620,9 @@ class Panelize(FlatCAMTool):
 
 
                     app_obj.log.debug("Found %s geometries. Creating a panel geometry cascaded union ..." %
                     app_obj.log.debug("Found %s geometries. Creating a panel geometry cascaded union ..." %
                                       len(obj_fin.solid_geometry))
                                       len(obj_fin.solid_geometry))
+                    self.app.inform.emit(_("Found %s geometries. Creating a final panel geometry ...") %
+                                         len(obj_fin.solid_geometry))
+
                     obj_fin.solid_geometry = cascaded_union(obj_fin.solid_geometry)
                     obj_fin.solid_geometry = cascaded_union(obj_fin.solid_geometry)
                     app_obj.log.debug("Finished creating a cascaded union for the panel.")
                     app_obj.log.debug("Finished creating a cascaded union for the panel.")
 
 
@@ -639,7 +642,7 @@ class Panelize(FlatCAMTool):
                                    "Final panel has {col} columns and {row} rows").format(
                                    "Final panel has {col} columns and {row} rows").format(
                 col=columns, row=rows))
                 col=columns, row=rows))
 
 
-        proc = self.app.proc_container.new(_("Generating panel ... Please wait."))
+        proc = self.app.proc_container.new(_("Generating panel ..."))
 
 
         def job_thread(app_obj):
         def job_thread(app_obj):
             try:
             try: