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

- finished adding in Paint Tool the usage of an external object to set the extent of th area painted. For simple shapes (single Polygon) the shape can be anything, for the rest will be a convex hull of the reference object
- modified NCC tool so for simple objects (single Polygon) the external object used as reference can have any shape, for the other types of objects the copper cleared area will be the convex hull of the reference object
- modified the strings of the app wherever they contained the char seq <b> </b> so it is not included in the translated string

Marius Stanciu 6 лет назад
Родитель
Сommit
36586aecce

+ 2 - 2
FlatCAMApp.py

@@ -4027,7 +4027,7 @@ class App(QtCore.QObject):
         msgbox = QtWidgets.QMessageBox()
         msgbox.setWindowTitle(_("Toggle Units"))
         msgbox.setWindowIcon(QtGui.QIcon('share/toggle_units32.png'))
-        msgbox.setText(_("<B>Change project units ...</B>"))
+        msgbox.setText("<B>%s</B>" % _("Change project units ..."))
         msgbox.setInformativeText(_("Changing the units of the project causes all geometrical "
                                     "properties of all objects to be scaled accordingly.\nContinue?"))
         bt_ok = msgbox.addButton(_('Ok'), QtWidgets.QMessageBox.AcceptRole)
@@ -5007,7 +5007,7 @@ class App(QtCore.QObject):
                 msgbox = QtWidgets.QMessageBox()
                 msgbox.setWindowTitle(_("Delete objects"))
                 msgbox.setWindowIcon(QtGui.QIcon('share/deleteshape32.png'))
-                # msgbox.setText(_("<B>Delete FlatCAM objects ...</B>"))
+                # msgbox.setText("<B>%s</B>" % _("Change project units ..."))
                 msgbox.setText(_("Are you sure you want to permanently delete\n"
                                  "the selected objects?"))
                 bt_ok = msgbox.addButton(_('Ok'), QtWidgets.QMessageBox.AcceptRole)

+ 3 - 0
README.md

@@ -17,6 +17,9 @@ CAD program, and create G-Code for Isolation routing.
 - in NCC Tool added a new parameter (radio button) that offer the choice on the order of the tools both in tools table and in execution of engraving; added as a parameter also in Edit -> Preferences -> Tools -> NCC Tool
 - added possibility to drag & drop FlatCAM config files (*.FlatConfig) into the canvas to be opened into the application
 - added GUI in Paint tool in beginning to add Paint by external reference object 
+- finished adding in Paint Tool the usage of an external object to set the extent of th area painted. For simple shapes (single Polygon) the shape can be anything, for the rest will be a convex hull of the reference object
+- modified NCC tool so for simple objects (single Polygon) the external object used as reference can have any shape, for the other types of objects the copper cleared area will be the convex hull of the reference object
+- modified the strings of the app wherever they contained the char seq <b> </b> so it is not included in the translated string
 
 17.08.2019
 

+ 38 - 32
flatcamGUI/FlatCAMGUI.py

@@ -4166,7 +4166,7 @@ class GerberGenPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("Gerber General")))
 
         # ## Plot options
-        self.plot_options_label = QtWidgets.QLabel(_("<b>Plot Options:</b>"))
+        self.plot_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot Options"))
         self.layout.addWidget(self.plot_options_label)
 
         grid0 = QtWidgets.QGridLayout()
@@ -4214,7 +4214,7 @@ class GerberOptPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("Gerber Options")))
 
         # ## Isolation Routing
-        self.isolation_routing_label = QtWidgets.QLabel(_("<b>Isolation Routing:</b>"))
+        self.isolation_routing_label = QtWidgets.QLabel("<b>%s:</b>" % _("Isolation Routing"))
         self.isolation_routing_label.setToolTip(
             _("Create a Geometry object with\n"
               "toolpaths to cut outside polygons.")
@@ -4274,7 +4274,7 @@ class GerberOptPrefGroupUI(OptionsGroupUI):
         grid0.addWidget(self.combine_passes_cb, 4, 0, 1, 2)
 
         # ## Clear non-copper regions
-        self.clearcopper_label = QtWidgets.QLabel(_("<b>Clear non-copper:</b>"))
+        self.clearcopper_label = QtWidgets.QLabel("<b>%s:</b>" % _("Clear non-copper"))
         self.clearcopper_label.setToolTip(
             _("Create a Geometry object with\n"
               "toolpaths to cut all non-copper regions.")
@@ -4339,7 +4339,7 @@ class GerberAdvOptPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("Gerber Adv. Options")))
 
         # ## Advanced Gerber Parameters
-        self.adv_param_label = QtWidgets.QLabel(_("<b>Advanced Param.:</b>"))
+        self.adv_param_label = QtWidgets.QLabel("<b>%s:</b>" % _("Advanced Param."))
         self.adv_param_label.setToolTip(
             _("A list of Gerber advanced parameters.\n"
               "Those parameters are available only for\n"
@@ -4404,7 +4404,7 @@ class GerberExpPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("Gerber Export")))
 
         # Plot options
-        self.export_options_label = QtWidgets.QLabel(_("<b>Export Options:</b>"))
+        self.export_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Export Options"))
         self.export_options_label.setToolTip(
             _("The parameters set here are used in the file exported\n"
               "when using the File -> Export -> Export Gerber menu entry.")
@@ -4429,7 +4429,7 @@ class GerberExpPrefGroupUI(OptionsGroupUI):
         form.addRow(self.gerber_units_label, self.gerber_units_radio)
 
         # Gerber format
-        self.digits_label = QtWidgets.QLabel(_("<b>Int/Decimals:</b>"))
+        self.digits_label = QtWidgets.QLabel("<b>%s:</b>" % _("Int/Decimals"))
         self.digits_label.setToolTip(
             _("The number of digits in the whole part of the number\n"
               "and in the fractional part of the number.")
@@ -4498,7 +4498,7 @@ class GerberEditorPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("Gerber Editor")))
 
         # Advanced Gerber Parameters
-        self.param_label = QtWidgets.QLabel(_("<b>Parameters:</b>"))
+        self.param_label = QtWidgets.QLabel("<b>%s:</b>" % _("Parameters"))
         self.param_label.setToolTip(
             _("A list of Gerber Editor parameters.")
         )
@@ -4533,7 +4533,7 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("Excellon General")))
 
         # Plot options
-        self.plot_options_label = QtWidgets.QLabel(_("<b>Plot Options:</b>"))
+        self.plot_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot Options"))
         self.layout.addWidget(self.plot_options_label)
 
         grid1 = QtWidgets.QGridLayout()
@@ -4552,7 +4552,7 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
         grid1.addWidget(self.solid_cb, 0, 1)
 
         # Excellon format
-        self.excellon_format_label = QtWidgets.QLabel(_("<b>Excellon Format:</b>"))
+        self.excellon_format_label = QtWidgets.QLabel("<b>%s:</b>" % _("Excellon Format"))
         self.excellon_format_label.setToolTip(
             _("The NC drill files, usually named Excellon files\n"
               "are files that can be found in different formats.\n"
@@ -4692,7 +4692,7 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
 
         grid2.addWidget(QtWidgets.QLabel(""), 2, 0)
 
-        self.excellon_general_label = QtWidgets.QLabel(_("<b>Excellon Optimization:</b>"))
+        self.excellon_general_label = QtWidgets.QLabel("<b>%s:</b>" % _("Excellon Optimization"))
         grid2.addWidget(self.excellon_general_label, 3, 0, 1, 2)
 
         self.excellon_optimization_label = QtWidgets.QLabel(_('Algorithm:   '))
@@ -5056,7 +5056,7 @@ class ExcellonExpPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("Excellon Export")))
 
         # Plot options
-        self.export_options_label = QtWidgets.QLabel(_("<b>Export Options:</b>"))
+        self.export_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Export Options"))
         self.export_options_label.setToolTip(
             _("The parameters set here are used in the file exported\n"
               "when using the File -> Export -> Export Excellon menu entry.")
@@ -5081,7 +5081,7 @@ class ExcellonExpPrefGroupUI(OptionsGroupUI):
         form.addRow(self.excellon_units_label, self.excellon_units_radio)
 
         # Excellon non-decimal format
-        self.digits_label = QtWidgets.QLabel(_("<b>Int/Decimals:</b>"))
+        self.digits_label = QtWidgets.QLabel("<b>%s:</b>" % _("Int/Decimals"))
         self.digits_label.setToolTip(
             _("The NC drill files, usually named Excellon files\n"
               "are files that can be found in different formats.\n"
@@ -5119,7 +5119,7 @@ class ExcellonExpPrefGroupUI(OptionsGroupUI):
         form.addRow(self.digits_label, hlay1)
 
         # Select the Excellon Format
-        self.format_label = QtWidgets.QLabel(_("<b>Format:</b>"))
+        self.format_label = QtWidgets.QLabel("<b>%s:</b>" % _("Format"))
         self.format_label.setToolTip(
             _("Select the kind of coordinates format used.\n"
               "Coordinates can be saved with decimal point or without.\n"
@@ -5206,7 +5206,7 @@ class ExcellonEditorPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("Excellon Editor")))
 
         # Excellon Editor Parameters
-        self.param_label = QtWidgets.QLabel(_("<b>Parameters:</b>"))
+        self.param_label = QtWidgets.QLabel("<b>%s:</b>" % _("Parameters"))
         self.param_label.setToolTip(
             _("A list of Excellon Editor parameters.")
         )
@@ -5461,7 +5461,7 @@ class GeometryGenPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("Geometry General")))
 
         # ## Plot options
-        self.plot_options_label = QtWidgets.QLabel(_("<b>Plot Options:</b>"))
+        self.plot_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot Options"))
         self.layout.addWidget(self.plot_options_label)
 
         # Plot CB
@@ -5485,7 +5485,7 @@ class GeometryGenPrefGroupUI(OptionsGroupUI):
         grid0.addWidget(self.circle_steps_entry, 1, 1)
 
         # Tools
-        self.tools_label = QtWidgets.QLabel(_("<b>Tools:</b>"))
+        self.tools_label = QtWidgets.QLabel("<b>%s:</b>" % _("Tools"))
         grid0.addWidget(self.tools_label, 2, 0, 1, 2)
 
         # Tooldia
@@ -5796,7 +5796,7 @@ class GeometryEditorPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("Geometry Editor")))
 
         # Advanced Geometry Parameters
-        self.param_label = QtWidgets.QLabel(_("<b>Parameters:</b>"))
+        self.param_label = QtWidgets.QLabel("<b>%s:</b>" % _("Parameters"))
         self.param_label.setToolTip(
             _("A list of Geometry Editor parameters.")
         )
@@ -5830,7 +5830,7 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("CNC Job General")))
 
         # ## Plot options
-        self.plot_options_label = QtWidgets.QLabel(_("<b>Plot Options:</b>"))
+        self.plot_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot Options"))
         self.layout.addWidget(self.plot_options_label)
 
         grid0 = QtWidgets.QGridLayout()
@@ -5963,7 +5963,7 @@ class CNCJobOptPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("CNC Job Options")))
 
         # ## Export G-Code
-        self.export_gcode_label = QtWidgets.QLabel(_("<b>Export G-Code:</b>"))
+        self.export_gcode_label = QtWidgets.QLabel("<b>%s:</b>" % _("Export G-Code"))
         self.export_gcode_label.setToolTip(
             _("Export and save G-Code to\n"
               "make this object to a file.")
@@ -6004,7 +6004,7 @@ class CNCJobAdvOptPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("CNC Job Adv. Options")))
 
         # ## Export G-Code
-        self.export_gcode_label = QtWidgets.QLabel(_("<b>Export G-Code:</b>"))
+        self.export_gcode_label = QtWidgets.QLabel("<b>%s:</b>" % _("Export G-Code"))
         self.export_gcode_label.setToolTip(
             _("Export and save G-Code to\n"
               "make this object to a file.")
@@ -6088,7 +6088,7 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("NCC Tool Options")))
 
         # ## Clear non-copper regions
-        self.clearcopper_label = QtWidgets.QLabel(_("<b>Parameters:</b>"))
+        self.clearcopper_label = QtWidgets.QLabel("<b>%s:</b>" % _("Parameters"))
         self.clearcopper_label.setToolTip(
             _("Create a Geometry object with\n"
               "toolpaths to cut all non-copper regions.")
@@ -6253,7 +6253,7 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("Cutout Tool Options")))
 
         # ## Board cuttout
-        self.board_cutout_label = QtWidgets.QLabel(_("<b>Parameters:</b>"))
+        self.board_cutout_label = QtWidgets.QLabel("<b>%s:</b>" % _("Parameters"))
         self.board_cutout_label.setToolTip(
             _("Create toolpaths to cut around\n"
               "the PCB and separate it from\n"
@@ -6347,7 +6347,7 @@ class Tools2sidedPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("2Sided Tool Options")))
 
         # ## Board cuttout
-        self.dblsided_label = QtWidgets.QLabel(_("<b>Parameters:</b>"))
+        self.dblsided_label = QtWidgets.QLabel("<b>%s:</b>" % _("Parameters"))
         self.dblsided_label.setToolTip(
             _("A tool to help in creating a double sided\n"
               "PCB using alignment holes.")
@@ -6488,13 +6488,19 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
         # Polygon selection
         selectlabel = QtWidgets.QLabel(_('Selection:'))
         selectlabel.setToolTip(
-            _("How to select the polygons to paint.")
+            _("How to select the polygons to paint.<BR>"
+              "Options:<BR>"
+              "- <B>Single</B>: left mouse click on the polygon to be painted.<BR>"
+              "- <B>Area</B>: left mouse click to start selection of the area to be painted.<BR>"
+              "- <B>All</B>: paint all polygons.<BR>"
+              "- <B>Ref</B>: paint an area described by an external reference object.")
         )
         grid0.addWidget(selectlabel, 6, 0)
         self.selectmethod_combo = RadioSet([
             {"label": _("Single"), "value": "single"},
             {"label": _("Area"), "value": "area"},
-            {"label": _("All"), "value": "all"}
+            {"label": _("All"), "value": "all"},
+            {"label": _("Ref."), "value": "ref"}
         ])
         grid0.addWidget(self.selectmethod_combo, 6, 1)
 
@@ -6509,7 +6515,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("Film Tool Options")))
 
         # ## Board cuttout
-        self.film_label = QtWidgets.QLabel(_("<b>Parameters:</b>"))
+        self.film_label = QtWidgets.QLabel("<b>%s:</b>" % _("Parameters"))
         self.film_label.setToolTip(
             _("Create a PCB film from a Gerber or Geometry\n"
               "FlatCAM object.\n"
@@ -6570,7 +6576,7 @@ class ToolsPanelizePrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("Panelize Tool Options")))
 
         # ## Board cuttout
-        self.panelize_label = QtWidgets.QLabel(_("<b>Parameters:</b>"))
+        self.panelize_label = QtWidgets.QLabel("<b>%s:</b>" % _("Parameters"))
         self.panelize_label.setToolTip(
             _("Create an object that contains an array of (x, y) elements,\n"
               "each element is a copy of the source object spaced\n"
@@ -6672,7 +6678,7 @@ class ToolsCalculatorsPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("Calculators Tool Options")))
 
         # ## V-shape Calculator Tool
-        self.vshape_tool_label = QtWidgets.QLabel(_("<b>V-Shape Tool Calculator:</b>"))
+        self.vshape_tool_label = QtWidgets.QLabel("<b>%s:</b>" % _("V-Shape Tool Calculator"))
         self.vshape_tool_label.setToolTip(
             _("Calculate the tool diameter for a given V-shape tool,\n"
               "having the tip diameter, tip angle and\n"
@@ -6714,7 +6720,7 @@ class ToolsCalculatorsPrefGroupUI(OptionsGroupUI):
         grid0.addWidget(self.cut_z_entry, 2, 1)
 
         # ## Electroplating Calculator Tool
-        self.plate_title_label = QtWidgets.QLabel(_("<b>ElectroPlating Calculator:</b>"))
+        self.plate_title_label = QtWidgets.QLabel("<b>%s:</b>" % _("ElectroPlating Calculator"))
         self.plate_title_label.setToolTip(
             _("This calculator is useful for those who plate the via/pad/drill holes,\n"
               "using a method like grahite ink or calcium hypophosphite ink or palladium chloride.")
@@ -6769,7 +6775,7 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("Transform Tool Options")))
 
         # ## Transformations
-        self.transform_label = QtWidgets.QLabel(_("<b>Parameters:</b>"))
+        self.transform_label = QtWidgets.QLabel("<b>%s:</b>" % _("Parameters"))
         self.transform_label.setToolTip(
             _("Various transformations that can be applied\n"
               "on a FlatCAM object.")
@@ -6896,7 +6902,7 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("SolderPaste Tool Options")))
 
         # ## Solder Paste Dispensing
-        self.solderpastelabel = QtWidgets.QLabel(_("<b>Parameters:</b>"))
+        self.solderpastelabel = QtWidgets.QLabel("<b>%s:</b>" % _("Parameters"))
         self.solderpastelabel.setToolTip(
             _("A tool to create GCode for dispensing\n"
               "solder paste onto a PCB.")
@@ -7069,7 +7075,7 @@ class ToolsSubPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("Substractor Tool Options")))
 
         # ## Solder Paste Dispensing
-        self.sublabel = QtWidgets.QLabel(_("<b>Parameters:</b>"))
+        self.sublabel = QtWidgets.QLabel("<b>%s:</b>" % _("Parameters"))
         self.sublabel.setToolTip(
             _("A tool to substract one Gerber or Geometry object\n"
               "from another of the same type.")

+ 21 - 22
flatcamGUI/ObjectUI.py

@@ -147,7 +147,7 @@ class GerberObjectUI(ObjectUI):
         grid0.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
         self.custom_box.addLayout(grid0)
 
-        self.plot_options_label = QtWidgets.QLabel(_("<b>Plot Options:</b>"))
+        self.plot_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot Options"))
         self.plot_options_label.setMinimumWidth(90)
 
         grid0.addWidget(self.plot_options_label, 0, 0)
@@ -179,7 +179,7 @@ class GerberObjectUI(ObjectUI):
         # ## Object name
         self.name_hlay = QtWidgets.QHBoxLayout()
         self.custom_box.addLayout(self.name_hlay)
-        name_label = QtWidgets.QLabel(_("<b>Name:</b>"))
+        name_label = QtWidgets.QLabel("<b>%s:</b>" % _("Name"))
         self.name_entry = FCEntry()
         self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus)
         self.name_hlay.addWidget(name_label)
@@ -247,7 +247,7 @@ class GerberObjectUI(ObjectUI):
         self.apertures_table.setVisible(False)
 
         # Isolation Routing
-        self.isolation_routing_label = QtWidgets.QLabel(_("<b>Isolation Routing:</b>"))
+        self.isolation_routing_label = QtWidgets.QLabel("<b>%s:</b>" % _("Isolation Routing"))
         self.isolation_routing_label.setToolTip(
             _("Create a Geometry object with\n"
               "toolpaths to cut outside polygons.")
@@ -320,7 +320,7 @@ class GerberObjectUI(ObjectUI):
         )
         grid1.addWidget(self.follow_cb, 4, 1)
 
-        self.gen_iso_label = QtWidgets.QLabel(_("<b>Generate Isolation Geometry:</b>"))
+        self.gen_iso_label = QtWidgets.QLabel("<b>%s:</b>" % _("Generate Isolation Geometry"))
         self.gen_iso_label.setToolTip(
             _("Create a Geometry object with toolpaths to cut \n"
               "isolation outside, inside or on both sides of the\n"
@@ -379,7 +379,7 @@ class GerberObjectUI(ObjectUI):
         self.custom_box.addLayout(grid2)
 
         # ## Clear non-copper regions
-        self.clearcopper_label = QtWidgets.QLabel(_("<b>Clear N-copper:</b>"))
+        self.clearcopper_label = QtWidgets.QLabel("<b>%s:</b>" % _("Clear N-copper"))
         self.clearcopper_label.setToolTip(
             _("Create a Geometry object with\n"
               "toolpaths to cut all non-copper regions.")
@@ -395,7 +395,7 @@ class GerberObjectUI(ObjectUI):
         grid2.addWidget(self.generate_ncc_button, 0, 1)
 
         # ## Board cutout
-        self.board_cutout_label = QtWidgets.QLabel(_("<b>Board cutout:</b>"))
+        self.board_cutout_label = QtWidgets.QLabel("<b>%s:</b>" % _("Board cutout"))
         self.board_cutout_label.setToolTip(
             _("Create toolpaths to cut around\n"
               "the PCB and separate it from\n"
@@ -411,7 +411,7 @@ class GerberObjectUI(ObjectUI):
         grid2.addWidget(self.generate_cutout_button, 1, 1)
 
         # ## Non-copper regions
-        self.noncopper_label = QtWidgets.QLabel(_("<b>Non-copper regions:</b>"))
+        self.noncopper_label = QtWidgets.QLabel("<b>%s:</b>" % _("Non-copper regions"))
         self.noncopper_label.setToolTip(
             _("Create polygons covering the\n"
               "areas without copper on the PCB.\n"
@@ -500,7 +500,7 @@ class ExcellonObjectUI(ObjectUI):
         hlay_plot = QtWidgets.QHBoxLayout()
         self.custom_box.addLayout(hlay_plot)
 
-        self.plot_options_label = QtWidgets.QLabel(_("<b>Plot Options:</b>"))
+        self.plot_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot Options"))
         self.solid_cb = FCCheckBox(label=_('Solid'))
         self.solid_cb.setToolTip(
             _("Solid circles.")
@@ -512,7 +512,7 @@ class ExcellonObjectUI(ObjectUI):
         # ## Object name
         self.name_hlay = QtWidgets.QHBoxLayout()
         self.custom_box.addLayout(self.name_hlay)
-        name_label = QtWidgets.QLabel(_("<b>Name:</b>"))
+        name_label = QtWidgets.QLabel("<b>%s:</b>" % _("Name"))
         self.name_entry = FCEntry()
         self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus)
         self.name_hlay.addWidget(name_label)
@@ -828,13 +828,13 @@ class GeometryObjectUI(ObjectUI):
                                                icon_file='share/geometry32.png', parent=parent)
 
         # Plot options
-        self.plot_options_label = QtWidgets.QLabel(_("<b>Plot Options:</b>"))
+        self.plot_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot Options"))
         self.custom_box.addWidget(self.plot_options_label)
 
         # ## Object name
         self.name_hlay = QtWidgets.QHBoxLayout()
         self.custom_box.addLayout(self.name_hlay)
-        name_label = QtWidgets.QLabel(_("<b>Name:</b>"))
+        name_label = QtWidgets.QLabel("<b>%s:</b>" % _("Name"))
         self.name_entry = FCEntry()
         self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus)
         self.name_hlay.addWidget(name_label)
@@ -1353,10 +1353,10 @@ class CNCObjectUI(ObjectUI):
         self.offset_button.hide()
 
         # ## Plot options
-        self.plot_options_label = QtWidgets.QLabel(_("<b>Plot Options:</b>"))
+        self.plot_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot Options"))
         self.custom_box.addWidget(self.plot_options_label)
 
-        self.cncplot_method_label = QtWidgets.QLabel(_("<b>Plot kind:</b>"))
+        self.cncplot_method_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot kind"))
         self.cncplot_method_label.setToolTip(
             _(
                 "This selects the kind of geometries on the canvas to plot.\n"
@@ -1372,12 +1372,11 @@ class CNCObjectUI(ObjectUI):
             {"label": _("Cut"), "value": "cut"}
         ], stretch=False)
 
-        self.annotation_label = QtWidgets.QLabel(_("<b>Display Annotation:</b>"))
+        self.annotation_label = QtWidgets.QLabel("<b>%s:</b>" % _("Display Annotation"))
         self.annotation_label.setToolTip(
-            _(
-                "This selects if to display text annotation on the plot.\n"
-                "When checked it will display numbers in order for each end\n"
-                "of a travel line."
+            _("This selects if to display text annotation on the plot.\n"
+              "When checked it will display numbers in order for each end\n"
+              "of a travel line."
             )
         )
         self.annotation_cb = FCCheckBox()
@@ -1385,13 +1384,13 @@ class CNCObjectUI(ObjectUI):
         # ## Object name
         self.name_hlay = QtWidgets.QHBoxLayout()
         self.custom_box.addLayout(self.name_hlay)
-        name_label = QtWidgets.QLabel(_("<b>Name:</b>"))
+        name_label = QtWidgets.QLabel("<b>%s:</b>" % _("Name"))
         self.name_entry = FCEntry()
         self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus)
         self.name_hlay.addWidget(name_label)
         self.name_hlay.addWidget(self.name_entry)
 
-        self.t_distance_label = QtWidgets.QLabel(_("<b>Travelled dist.:</b>"))
+        self.t_distance_label = QtWidgets.QLabel("<b>%s:</b>" % _("Travelled dist."))
         self.t_distance_label.setToolTip(
             _("This is the total travelled distance on X-Y plane.\n"
               "In current units.")
@@ -1403,7 +1402,7 @@ class CNCObjectUI(ObjectUI):
         )
         self.units_label = QtWidgets.QLabel()
 
-        self.t_time_label = QtWidgets.QLabel(_("<b>Estimated time:</b>"))
+        self.t_time_label = QtWidgets.QLabel("<b>%s:</b>" % _("Estimated time"))
         self.t_time_label.setToolTip(
             _("This is the estimated time to do the routing/drilling,\n"
               "without the time spent in ToolChange events.")
@@ -1497,7 +1496,7 @@ class CNCObjectUI(ObjectUI):
         # ####################
         # ## Export G-Code ##
         # ####################
-        self.export_gcode_label = QtWidgets.QLabel(_("<b>Export CNC Code:</b>"))
+        self.export_gcode_label = QtWidgets.QLabel("<b>%s:</b>" % _("Export CNC Code"))
         self.export_gcode_label.setToolTip(
             _("Export and save G-Code to\n"
             "make this object to a file.")

+ 3 - 3
flatcamTools/ToolDblSided.py

@@ -44,7 +44,7 @@ class DblSidedTool(FlatCAMTool):
         self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
         self.gerber_object_combo.setCurrentIndex(1)
 
-        self.botlay_label = QtWidgets.QLabel(_("<b>GERBER:</b>"))
+        self.botlay_label = QtWidgets.QLabel("<b>%s:</b>" % _("GERBER"))
         self.botlay_label.setToolTip(
             "Gerber  to be mirrored."
         )
@@ -68,7 +68,7 @@ class DblSidedTool(FlatCAMTool):
         self.exc_object_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
         self.exc_object_combo.setCurrentIndex(1)
 
-        self.excobj_label = QtWidgets.QLabel(_("<b>EXCELLON:</b>"))
+        self.excobj_label = QtWidgets.QLabel("<b>%s:</b>" % _("EXCELLON"))
         self.excobj_label.setToolTip(
             _("Excellon Object to be mirrored.")
         )
@@ -92,7 +92,7 @@ class DblSidedTool(FlatCAMTool):
         self.geo_object_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
         self.geo_object_combo.setCurrentIndex(1)
 
-        self.geoobj_label = QtWidgets.QLabel(_("<b>GEOMETRY</b>:"))
+        self.geoobj_label = QtWidgets.QLabel("<b>%s</b>:" % _("GEOMETRY"))
         self.geoobj_label.setToolTip(
             _("Geometry Obj to be mirrored.")
         )

+ 8 - 4
flatcamTools/ToolNonCopperClear.py

@@ -10,10 +10,10 @@ from FlatCAMTool import FlatCAMTool
 from copy import copy, deepcopy
 from ObjectCollection import *
 import time
+from shapely.geometry import base
 
 import gettext
 import FlatCAMTranslation as fcTranslate
-from shapely.geometry import base
 import builtins
 
 fcTranslate.apply_language('strings')
@@ -860,12 +860,16 @@ class NonCopperClear(FlatCAMTool, Gerber):
             return "Could not retrieve object: %s" % self.obj_name
 
         # Prepare non-copper polygons
+        geo_n = self.bound_obj.solid_geometry
         try:
-            if not isinstance(self.bound_obj.solid_geometry, MultiPolygon):
+            if isinstance(geo_n, MultiPolygon):
+                env_obj = geo_n.convex_hull
+            elif (isinstance(geo_n, MultiPolygon) and len(geo_n) == 1) or \
+                    (isinstance(geo_n, list) and len(geo_n) == 1) and isinstance(geo_n[0], Polygon):
                 env_obj = cascaded_union(self.bound_obj.solid_geometry)
-                env_obj = env_obj.convex_hull
             else:
-                env_obj = self.bound_obj.solid_geometry.convex_hull
+                env_obj = cascaded_union(self.bound_obj.solid_geometry)
+                env_obj = env_obj.convex_hull
             bounding_box = env_obj.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre)
         except Exception as e:
             log.debug("NonCopperClear.on_ncc() --> %s" % str(e))

+ 50 - 9
flatcamTools/ToolPaint.py

@@ -9,6 +9,7 @@
 from FlatCAMTool import FlatCAMTool
 from copy import copy, deepcopy
 from ObjectCollection import *
+from shapely.geometry import base
 
 import gettext
 import FlatCAMTranslation as fcTranslate
@@ -238,19 +239,27 @@ class ToolPaint(FlatCAMTool, Gerber):
         selectlabel.setToolTip(
             _("How to select the polygons to paint.<BR>"
               "Options:<BR>"
-              "- <B>Single</B>: left mouse click on the polygon to be painted.<BR>"
-              "- <B>Area</B>: left mouse click to start selection of the area to be painted.<BR>"
-              "- <B>All</B>: paint all polygons.<BR>"
-              "- <B>Ref</B>: paint an area described by an external reference object.")
+              "- <B>Single Polygons</B>: left mouse click on the polygon to be painted.<BR>"
+              "- <B>Area Selection</B>: left mouse click to start selection of the area to be painted.<BR>"
+              "- <B>All Polygons</B>: paint all polygons.<BR>"
+              "- <B>Reference Object</B>: paint an area described by an external reference object.")
         )
         grid3.addWidget(selectlabel, 7, 0)
         # grid3 = QtWidgets.QGridLayout()
         self.selectmethod_combo = RadioSet([
-            {"label": _("Single"), "value": "single"},
-            {"label": _("Area"), "value": "area"},
-            {"label": _("All"), "value": "all"},
-            {"label": _("Ref."), "value": "ref"}
-        ])
+            {"label": _("Single Polygon"), "value": "single"},
+            {"label": _("Area Selection"), "value": "area"},
+            {"label": _("All Polygons"), "value": "all"},
+            {"label": _("Reference Object"), "value": "ref"}
+        ], orientation='vertical', stretch=False)
+        self.selectmethod_combo.setToolTip(
+            _("How to select the polygons to paint.<BR>"
+              "Options:<BR>"
+              "- <B>Single Polygons</B>: left mouse click on the polygon to be painted.<BR>"
+              "- <B>Area Selection</B>: left mouse click to start selection of the area to be painted.<BR>"
+              "- <B>All Polygons</B>: paint all polygons.<BR>"
+              "- <B>Reference Object</B>: paint an area described by an external reference object.")
+        )
         grid3.addWidget(self.selectmethod_combo, 7, 1)
 
         grid4 = QtWidgets.QGridLayout()
@@ -950,6 +959,38 @@ class ToolPaint(FlatCAMTool, Gerber):
             self.app.plotcanvas.vis_connect('mouse_press', on_mouse_press)
             self.app.plotcanvas.vis_connect('mouse_move', on_mouse_move)
 
+        elif select_method == 'ref':
+            self.bound_obj_name = self.box_combo.currentText()
+            # Get source object.
+            try:
+                self.bound_obj = self.app.collection.get_by_name(self.bound_obj_name)
+            except Exception as e:
+                self.app.inform.emit(_("[ERROR_NOTCL] Could not retrieve object: %s") % self.obj_name)
+                return "Could not retrieve object: %s" % self.obj_name
+
+            geo = self.bound_obj.solid_geometry
+            try:
+                if isinstance(geo, MultiPolygon):
+                    env_obj = geo.convex_hull
+                elif (isinstance(geo, MultiPolygon) and len(geo) == 1) or \
+                    (isinstance(geo, list) and len(geo) == 1) and isinstance(geo[0], Polygon):
+                    env_obj = cascaded_union(self.bound_obj.solid_geometry)
+                else:
+                    env_obj = cascaded_union(self.bound_obj.solid_geometry)
+                    env_obj = env_obj.convex_hull
+                sel_rect = env_obj.buffer(distance=0.0000001, join_style=base.JOIN_STYLE.mitre)
+            except Exception as e:
+                log.debug("ToolPaint.on_paint_button_click() --> %s" % str(e))
+                self.app.inform.emit(_("[ERROR_NOTCL] No object available."))
+                return
+
+            self.paint_poly_area(obj=self.paint_obj,
+                                 sel_obj=sel_rect,
+                                 outname=o_name,
+                                 overlap=overlap,
+                                 connect=connect,
+                                 contour=contour)
+
     def paint_poly(self, obj, inside_pt, tooldia, overlap, outname=None, connect=True, contour=True):
         """
         Paints a polygon selected by clicking on its interior.

+ 3 - 3
flatcamTools/ToolPanelize.py

@@ -83,7 +83,7 @@ class Panelize(FlatCAMTool):
         # Type of box Panel object
         self.reference_radio = RadioSet([{'label': _('Object'), 'value': 'object'},
                                          {'label': _('Bounding Box'), 'value': 'bbox'}])
-        self.box_label = QtWidgets.QLabel(_("<b>Penelization Reference:</b>"))
+        self.box_label = QtWidgets.QLabel("<b>%s:</b>" % _("Penelization Reference"))
         self.box_label.setToolTip(
             _("Choose the reference for panelization:\n"
               "- Object = the bounding box of a different object\n"
@@ -131,7 +131,7 @@ class Panelize(FlatCAMTool):
         form_layout.addRow(self.box_combo_label, self.box_combo)
         form_layout.addRow(QtWidgets.QLabel(""))
 
-        panel_data_label = QtWidgets.QLabel(_("<b>Panel Data:</b>"))
+        panel_data_label = QtWidgets.QLabel("<b>%s:</b>" % _("Panel Data"))
         panel_data_label.setToolTip(
             _("This informations will shape the resulting panel.\n"
               "The number of rows and columns will set how many\n"
@@ -180,7 +180,7 @@ class Panelize(FlatCAMTool):
         # Type of resulting Panel object
         self.panel_type_radio = RadioSet([{'label': _('Gerber'), 'value': 'gerber'},
                                           {'label': _('Geo'), 'value': 'geometry'}])
-        self.panel_type_label = QtWidgets.QLabel(_("<b>Panel Type:</b>"))
+        self.panel_type_label = QtWidgets.QLabel("<b>%s:</b>" % _("Panel Type"))
         self.panel_type_label.setToolTip(
             _("Choose the type of object for the panel object:\n"
               "- Geometry\n"

+ 2 - 2
flatcamTools/ToolPcbWizard.py

@@ -48,7 +48,7 @@ class PcbWizard(FlatCAMTool):
         self.layout.addWidget(title_label)
 
         self.layout.addWidget(QtWidgets.QLabel(""))
-        self.layout.addWidget(QtWidgets.QLabel(_("<b>Load files:</b>")))
+        self.layout.addWidget(QtWidgets.QLabel("<b>%s:</b>" % _("Load files")))
 
         # Form Layout
         form_layout = QtWidgets.QFormLayout()
@@ -84,7 +84,7 @@ class PcbWizard(FlatCAMTool):
         self.tools_table.setVisible(False)
 
         self.layout.addWidget(QtWidgets.QLabel(""))
-        self.layout.addWidget(QtWidgets.QLabel(_("<b>Excellon format:</b>")))
+        self.layout.addWidget(QtWidgets.QLabel("<b>%s:</b>" % _("Excellon format")))
         # Form Layout
         form_layout1 = QtWidgets.QFormLayout()
         self.layout.addLayout(form_layout1)

+ 2 - 2
flatcamTools/ToolSub.py

@@ -52,7 +52,7 @@ class ToolSub(FlatCAMTool):
         form_layout = QtWidgets.QFormLayout()
         self.tools_box.addLayout(form_layout)
 
-        self.gerber_title = QtWidgets.QLabel(_("<b>Gerber Objects</b>"))
+        self.gerber_title = QtWidgets.QLabel("<b>%s</b>" % _("Gerber Objects"))
         form_layout.addRow(self.gerber_title)
 
         # Target Gerber Object
@@ -98,7 +98,7 @@ class ToolSub(FlatCAMTool):
         form_geo_layout = QtWidgets.QFormLayout()
         self.tools_box.addLayout(form_geo_layout)
 
-        self.geo_title = QtWidgets.QLabel(_("<b>Geometry Objects</b>"))
+        self.geo_title = QtWidgets.QLabel("<b>%s</b>" % _("Geometry Objects"))
         form_geo_layout.addRow(self.geo_title)
 
         # Target Geometry Object