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

- in Tool Film added the page size and page orientation in case of saving the film as PDF file
- the application workspace has now a lot more options selectable in the Edit -> Preferences -> General -> GUI Preferences

Marius Stanciu 6 лет назад
Родитель
Сommit
58f24cbb37
7 измененных файлов с 456 добавлено и 87 удалено
  1. 13 3
      FlatCAMApp.py
  2. 5 0
      README.md
  3. 117 33
      flatcamGUI/PlotCanvas.py
  4. 159 6
      flatcamGUI/PreferencesUI.py
  5. 149 30
      flatcamTools/ToolFilm.py
  6. 10 12
      flatcamTools/ToolMove.py
  7. 3 3
      flatcamTools/ToolPaint.py

+ 13 - 3
FlatCAMApp.py

@@ -427,7 +427,8 @@ class App(QtCore.QObject):
             "global_gridy": 0.0393701,
             "global_gridy": 0.0393701,
             "global_snap_max": 0.001968504,
             "global_snap_max": 0.001968504,
             "global_workspace": False,
             "global_workspace": False,
-            "global_workspaceT": "A4P",
+            "global_workspaceT": "A4",
+            "global_workspace_orientation": 'p',
 
 
             "global_grid_context_menu": {
             "global_grid_context_menu": {
                 'in': [0.01, 0.02, 0.025, 0.05, 0.1],
                 'in': [0.01, 0.02, 0.025, 0.05, 0.1],
@@ -766,6 +767,8 @@ class App(QtCore.QObject):
             "tools_film_mirror_cb": False,
             "tools_film_mirror_cb": False,
             "tools_film_mirror_axis_radio": 'none',
             "tools_film_mirror_axis_radio": 'none',
             "tools_film_file_type_radio": 'svg',
             "tools_film_file_type_radio": 'svg',
+            "tools_film_orientation": 'p',
+            "tools_film_pagesize": 'A4',
 
 
             # Panel Tool
             # Panel Tool
             "tools_panelize_spacing_columns": 0,
             "tools_panelize_spacing_columns": 0,
@@ -1039,6 +1042,7 @@ class App(QtCore.QObject):
             "global_snap_max": self.ui.general_defaults_form.general_gui_group.snap_max_dist_entry,
             "global_snap_max": self.ui.general_defaults_form.general_gui_group.snap_max_dist_entry,
             "global_workspace": self.ui.general_defaults_form.general_gui_group.workspace_cb,
             "global_workspace": self.ui.general_defaults_form.general_gui_group.workspace_cb,
             "global_workspaceT": self.ui.general_defaults_form.general_gui_group.wk_cb,
             "global_workspaceT": self.ui.general_defaults_form.general_gui_group.wk_cb,
+            "global_workspace_orientation": self.ui.general_defaults_form.general_gui_group.wk_orientation_radio,
 
 
             "global_plot_fill": self.ui.general_defaults_form.general_gui_group.pf_color_entry,
             "global_plot_fill": self.ui.general_defaults_form.general_gui_group.pf_color_entry,
             "global_plot_line": self.ui.general_defaults_form.general_gui_group.pl_color_entry,
             "global_plot_line": self.ui.general_defaults_form.general_gui_group.pl_color_entry,
@@ -1324,6 +1328,8 @@ class App(QtCore.QObject):
             "tools_film_mirror_cb": self.ui.tools_defaults_form.tools_film_group.film_mirror_cb,
             "tools_film_mirror_cb": self.ui.tools_defaults_form.tools_film_group.film_mirror_cb,
             "tools_film_mirror_axis_radio": self.ui.tools_defaults_form.tools_film_group.film_mirror_axis,
             "tools_film_mirror_axis_radio": self.ui.tools_defaults_form.tools_film_group.film_mirror_axis,
             "tools_film_file_type_radio": self.ui.tools_defaults_form.tools_film_group.file_type_radio,
             "tools_film_file_type_radio": self.ui.tools_defaults_form.tools_film_group.file_type_radio,
+            "tools_film_orientation": self.ui.tools_defaults_form.tools_film_group.orientation_radio,
+            "tools_film_pagesize": self.ui.tools_defaults_form.tools_film_group.pagesize_combo,
 
 
             # Panelize Tool
             # Panelize Tool
             "tools_panelize_spacing_columns": self.ui.tools_defaults_form.tools_panelize_group.pspacing_columns,
             "tools_panelize_spacing_columns": self.ui.tools_defaults_form.tools_panelize_group.pspacing_columns,
@@ -1932,6 +1938,10 @@ class App(QtCore.QObject):
 
 
         # ############################# 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.on_workspace_modified
+        )
+
         self.ui.general_defaults_form.general_gui_group.workspace_cb.stateChanged.connect(self.on_workspace)
         self.ui.general_defaults_form.general_gui_group.workspace_cb.stateChanged.connect(self.on_workspace)
 
 
         self.ui.general_defaults_form.general_gui_set_group.layout_combo.activated.connect(self.on_layout)
         self.ui.general_defaults_form.general_gui_set_group.layout_combo.activated.connect(self.on_layout)
@@ -5729,7 +5739,7 @@ class App(QtCore.QObject):
 
 
             # change this only if the workspace is active
             # change this only if the workspace is active
             if self.defaults['global_workspace'] is True:
             if self.defaults['global_workspace'] is True:
-                self.plotcanvas.draw_workspace()
+                self.plotcanvas.draw_workspace(pagesize=self.defaults['global_workspaceT'])
 
 
             # adjust the grid values on the main toolbar
             # adjust the grid values on the main toolbar
             dec = 6 if new_units == 'IN'else 4
             dec = 6 if new_units == 'IN'else 4
@@ -6660,7 +6670,7 @@ class App(QtCore.QObject):
 
 
     def on_workspace_modified(self):
     def on_workspace_modified(self):
         self.save_defaults(silent=True)
         self.save_defaults(silent=True)
-        self.plotcanvas.draw_workspace()
+        self.plotcanvas.draw_workspace(pagesize=self.defaults['global_workspaceT'])
 
 
     def on_workspace(self):
     def on_workspace(self):
         self.report_usage("on_workspace()")
         self.report_usage("on_workspace()")

+ 5 - 0
README.md

@@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing.
 
 
 =================================================
 =================================================
 
 
+27.11.2019
+
+- in Tool Film added the page size and page orientation in case of saving the film as PDF file
+- the application workspace has now a lot more options selectable in the Edit -> Preferences -> General -> GUI Preferences
+
 26.11.2019
 26.11.2019
 
 
 - updated the Film Tool to allow exporting PDF and PNG file (besides the SVG file)
 - updated the Film Tool to allow exporting PDF and PNG file (besides the SVG file)

+ 117 - 33
flatcamGUI/PlotCanvas.py

@@ -76,7 +76,7 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
         # draw a rectangle made out of 4 lines on the canvas to serve as a hint for the work area
         # draw a rectangle made out of 4 lines on the canvas to serve as a hint for the work area
         # all CNC have a limited workspace
         # all CNC have a limited workspace
 
 
-        self.draw_workspace()
+        self.draw_workspace(pagesize=self.fcapp.defaults["global_workspaceT"])
 
 
         self.line_parent = None
         self.line_parent = None
         self.cursor_v_line = InfiniteLine(pos=None, color=self.line_color, vertical=True,
         self.cursor_v_line = InfiniteLine(pos=None, color=self.line_color, vertical=True,
@@ -107,37 +107,122 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
 
 
     # draw a rectangle made out of 4 lines on the canvas to serve as a hint for the work area
     # draw a rectangle made out of 4 lines on the canvas to serve as a hint for the work area
     # all CNC have a limited workspace
     # all CNC have a limited workspace
-    def draw_workspace(self):
-        a = np.empty((0, 0))
-
-        a4p_in = np.array([(0, 0), (8.3, 0), (8.3, 11.7), (0, 11.7)])
-        a4l_in = np.array([(0, 0), (11.7, 0), (11.7, 8.3), (0, 8.3)])
-        a3p_in = np.array([(0, 0), (11.7, 0), (11.7, 16.5), (0, 16.5)])
-        a3l_in = np.array([(0, 0), (16.5, 0), (16.5, 11.7), (0, 11.7)])
-
-        a4p_mm = np.array([(0, 0), (210, 0), (210, 297), (0, 297)])
-        a4l_mm = np.array([(0, 0), (297, 0), (297, 210), (0, 210)])
-        a3p_mm = np.array([(0, 0), (297, 0), (297, 420), (0, 420)])
-        a3l_mm = np.array([(0, 0), (420, 0), (420, 297), (0, 297)])
-
-        if self.fcapp.defaults['units'].upper() == 'MM':
-            if self.fcapp.defaults['global_workspaceT'] == 'A4P':
-                a = a4p_mm
-            elif self.fcapp.defaults['global_workspaceT'] == 'A4L':
-                a = a4l_mm
-            elif self.fcapp.defaults['global_workspaceT'] == 'A3P':
-                a = a3p_mm
-            elif self.fcapp.defaults['global_workspaceT'] == 'A3L':
-                a = a3l_mm
-        else:
-            if self.fcapp.defaults['global_workspaceT'] == 'A4P':
-                a = a4p_in
-            elif self.fcapp.defaults['global_workspaceT'] == 'A4L':
-                a = a4l_in
-            elif self.fcapp.defaults['global_workspaceT'] == 'A3P':
-                a = a3p_in
-            elif self.fcapp.defaults['global_workspaceT'] == 'A3L':
-                a = a3l_in
+    # def draw_workspace(self):
+    #     a = np.empty((0, 0))
+    #
+    #     a4p_in = np.array([(0, 0), (8.3, 0), (8.3, 11.7), (0, 11.7)])
+    #     a4l_in = np.array([(0, 0), (11.7, 0), (11.7, 8.3), (0, 8.3)])
+    #     a3p_in = np.array([(0, 0), (11.7, 0), (11.7, 16.5), (0, 16.5)])
+    #     a3l_in = np.array([(0, 0), (16.5, 0), (16.5, 11.7), (0, 11.7)])
+    #
+    #     a4p_mm = np.array([(0, 0), (210, 0), (210, 297), (0, 297)])
+    #     a4l_mm = np.array([(0, 0), (297, 0), (297, 210), (0, 210)])
+    #     a3p_mm = np.array([(0, 0), (297, 0), (297, 420), (0, 420)])
+    #     a3l_mm = np.array([(0, 0), (420, 0), (420, 297), (0, 297)])
+    #
+    #     if self.fcapp.defaults['units'].upper() == 'MM':
+    #         if self.fcapp.defaults['global_workspaceT'] == 'A4P':
+    #             a = a4p_mm
+    #         elif self.fcapp.defaults['global_workspaceT'] == 'A4L':
+    #             a = a4l_mm
+    #         elif self.fcapp.defaults['global_workspaceT'] == 'A3P':
+    #             a = a3p_mm
+    #         elif self.fcapp.defaults['global_workspaceT'] == 'A3L':
+    #             a = a3l_mm
+    #     else:
+    #         if self.fcapp.defaults['global_workspaceT'] == 'A4P':
+    #             a = a4p_in
+    #         elif self.fcapp.defaults['global_workspaceT'] == 'A4L':
+    #             a = a4l_in
+    #         elif self.fcapp.defaults['global_workspaceT'] == 'A3P':
+    #             a = a3p_in
+    #         elif self.fcapp.defaults['global_workspaceT'] == 'A3L':
+    #             a = a3l_in
+    #
+    #     self.delete_workspace()
+    #
+    #     self.b_line = Line(pos=a[0:2], color=(0.70, 0.3, 0.3, 1.0),
+    #                        antialias=True, method='agg', parent=self.view.scene)
+    #     self.r_line = Line(pos=a[1:3], color=(0.70, 0.3, 0.3, 1.0),
+    #                        antialias=True, method='agg', parent=self.view.scene)
+    #
+    #     self.t_line = Line(pos=a[2:4], color=(0.70, 0.3, 0.3, 1.0),
+    #                        antialias=True, method='agg', parent=self.view.scene)
+    #     self.l_line = Line(pos=np.array((a[0], a[3])), color=(0.70, 0.3, 0.3, 1.0),
+    #                        antialias=True, method='agg', parent=self.view.scene)
+    #
+    #     if self.fcapp.defaults['global_workspace'] is False:
+    #         self.delete_workspace()
+
+    # delete the workspace lines from the plot by removing the parent
+
+    def draw_workspace(self, pagesize):
+        pagesize_dict = dict()
+        pagesize_dict.update(
+            {
+                'A0': (841, 1189),
+                'A1': (594, 841),
+                'A2': (420, 594),
+                'A3': (297, 420),
+                'A4': (210, 297),
+                'A5': (148, 210),
+                'A6': (105, 148),
+                'A7': (74, 105),
+                'A8': (52, 74),
+                'A9': (37, 52),
+                'A10': (26, 37),
+
+                'B0': (1000, 1414),
+                'B1': (707, 1000),
+                'B2': (500, 707),
+                'B3': (353, 500),
+                'B4': (250, 353),
+                'B5': (176, 250),
+                'B6': (125, 176),
+                'B7': (88, 125),
+                'B8': (62, 88),
+                'B9': (44, 62),
+                'B10': (31, 44),
+
+                'C0': (917, 1297),
+                'C1': (648, 917),
+                'C2': (458, 648),
+                'C3': (324, 458),
+                'C4': (229, 324),
+                'C5': (162, 229),
+                'C6': (114, 162),
+                'C7': (81, 114),
+                'C8': (57, 81),
+                'C9': (40, 57),
+                'C10': (28, 40),
+
+                # American paper sizes
+                'LETTER': (8.5*25.4, 11*25.4),
+                'LEGAL': (8.5*25.4, 14*25.4),
+                'ELEVENSEVENTEEN': (11*25.4, 17*25.4),
+
+                # From https://en.wikipedia.org/wiki/Paper_size
+                'JUNIOR_LEGAL': (5*25.4, 8*25.4),
+                'HALF_LETTER': (5.5*25.4, 8*25.4),
+                'GOV_LETTER': (8*25.4, 10.5*25.4),
+                'GOV_LEGAL': (8.5*25.4, 13*25.4),
+                'LEDGER': (17*25.4, 11*25.4),
+            }
+        )
+
+        try:
+            if self.fcapp.defaults['units'].upper() == 'MM':
+                dims = pagesize_dict[pagesize]
+            else:
+                dims = (pagesize_dict[pagesize][0]/25.4, pagesize_dict[pagesize][1]/25.4)
+        except Exception as e:
+            log.debug("PlotCanvas.draw_workspace() --> %s" % str(e))
+            return
+
+        if self.fcapp.defaults['global_workspace_orientation'] == 'l':
+            dims = (dims[1], dims[0])
+
+        a = np.array([(0, 0), (dims[0], 0), (dims[0], dims[1]), (0, dims[1])])
 
 
         self.delete_workspace()
         self.delete_workspace()
 
 
@@ -154,7 +239,6 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
         if self.fcapp.defaults['global_workspace'] is False:
         if self.fcapp.defaults['global_workspace'] is False:
             self.delete_workspace()
             self.delete_workspace()
 
 
-    # delete the workspace lines from the plot by removing the parent
     def delete_workspace(self):
     def delete_workspace(self):
         try:
         try:
             self.b_line.parent = None
             self.b_line.parent = None

+ 159 - 6
flatcamGUI/PreferencesUI.py

@@ -343,19 +343,92 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
            _("Draw a delimiting rectangle on canvas.\n"
            _("Draw a delimiting rectangle on canvas.\n"
              "The purpose is to illustrate the limits for our work.")
              "The purpose is to illustrate the limits for our work.")
         )
         )
-        self.workspace_type_lbl = QtWidgets.QLabel('%s:' % _('Wk. format'))
+        self.workspace_type_lbl = QtWidgets.QLabel('%s:' % _('Wk. size'))
         self.workspace_type_lbl.setToolTip(
         self.workspace_type_lbl.setToolTip(
            _("Select the type of rectangle to be used on canvas,\n"
            _("Select the type of rectangle to be used on canvas,\n"
              "as valid workspace.")
              "as valid workspace.")
         )
         )
         self.workspace_cb = FCCheckBox()
         self.workspace_cb = FCCheckBox()
         self.wk_cb = FCComboBox()
         self.wk_cb = FCComboBox()
-        self.wk_cb.addItem('A4P')
-        self.wk_cb.addItem('A4L')
-        self.wk_cb.addItem('A3P')
-        self.wk_cb.addItem('A3L')
 
 
-        self.wks = OptionalInputSection(self.workspace_cb, [self.workspace_type_lbl, self.wk_cb])
+        self.pagesize = dict()
+        self.pagesize.update(
+            {
+                'A0': (841, 1189),
+                'A1': (594, 841),
+                'A2': (420, 594),
+                'A3': (297, 420),
+                'A4': (210, 297),
+                'A5': (148, 210),
+                'A6': (105, 148),
+                'A7': (74, 105),
+                'A8': (52, 74),
+                'A9': (37, 52),
+                'A10': (26, 37),
+
+                'B0': (1000, 1414),
+                'B1': (707, 1000),
+                'B2': (500, 707),
+                'B3': (353, 500),
+                'B4': (250, 353),
+                'B5': (176, 250),
+                'B6': (125, 176),
+                'B7': (88, 125),
+                'B8': (62, 88),
+                'B9': (44, 62),
+                'B10': (31, 44),
+
+                'C0': (917, 1297),
+                'C1': (648, 917),
+                'C2': (458, 648),
+                'C3': (324, 458),
+                'C4': (229, 324),
+                'C5': (162, 229),
+                'C6': (114, 162),
+                'C7': (81, 114),
+                'C8': (57, 81),
+                'C9': (40, 57),
+                'C10': (28, 40),
+
+                # American paper sizes
+                'LETTER': (8.5, 11),
+                'LEGAL': (8.5, 14),
+                'ELEVENSEVENTEEN': (11, 17),
+
+                # From https://en.wikipedia.org/wiki/Paper_size
+                'JUNIOR_LEGAL': (5, 8),
+                'HALF_LETTER': (5.5, 8),
+                'GOV_LETTER': (8, 10.5),
+                'GOV_LEGAL': (8.5, 13),
+                'LEDGER': (17, 11),
+            }
+        )
+
+        page_size_list = list(self.pagesize.keys())
+
+        self.wk_cb.addItems(page_size_list)
+        # self.wk_cb.addItem('A4P')
+        # self.wk_cb.addItem('A4L')
+        # self.wk_cb.addItem('A3P')
+        # self.wk_cb.addItem('A3L')
+
+        # Page orientation
+        self.wk_orientation_label = QtWidgets.QLabel('%s:' % _("Wk. Orientation"))
+        self.wk_orientation_label.setToolTip(_("Can be:\n"
+                                               "- Portrait\n"
+                                               "- Landscape"))
+
+        self.wk_orientation_radio = RadioSet([{'label': _('Portrait'), 'value': 'p'},
+                                              {'label': _('Landscape'), 'value': 'l'},
+                                              ], stretch=False)
+
+        self.wks = OptionalInputSection(self.workspace_cb,
+                                        [
+                                            self.workspace_type_lbl,
+                                            self.wk_cb,
+                                            self.wk_orientation_label,
+                                            self.wk_orientation_radio
+                                        ])
 
 
         # Plot Fill Color
         # Plot Fill Color
         self.pf_color_label = QtWidgets.QLabel('%s:' % _('Plot Fill'))
         self.pf_color_label = QtWidgets.QLabel('%s:' % _('Plot Fill'))
@@ -579,6 +652,8 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
 
 
         self.form_box.addRow(self.workspace_lbl, self.workspace_cb)
         self.form_box.addRow(self.workspace_lbl, self.workspace_cb)
         self.form_box.addRow(self.workspace_type_lbl, self.wk_cb)
         self.form_box.addRow(self.workspace_type_lbl, self.wk_cb)
+        self.form_box.addRow(self.wk_orientation_label, self.wk_orientation_radio)
+
         self.form_box.addRow(self.spacelabel, self.spacelabel)
         self.form_box.addRow(self.spacelabel, self.spacelabel)
         self.form_box.addRow(self.pf_color_label, self.form_box_child_1)
         self.form_box.addRow(self.pf_color_label, self.form_box_child_1)
         self.form_box.addRow(self.pf_alpha_label, self.form_box_child_2)
         self.form_box.addRow(self.pf_alpha_label, self.form_box_child_2)
@@ -4654,6 +4729,84 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI):
         grid0.addWidget(self.file_type_label, 15, 0)
         grid0.addWidget(self.file_type_label, 15, 0)
         grid0.addWidget(self.file_type_radio, 15, 1)
         grid0.addWidget(self.file_type_radio, 15, 1)
 
 
+        # Page orientation
+        self.orientation_label = QtWidgets.QLabel('%s:' % _("Page Orientation"))
+        self.orientation_label.setToolTip(_("Can be:\n"
+                                            "- Portrait\n"
+                                            "- Lanscape"))
+
+        self.orientation_radio = RadioSet([{'label': _('Portrait'), 'value': 'p'},
+                                           {'label': _('Landscape'), 'value': 'l'},
+                                           ], stretch=False)
+
+        grid0.addWidget(self.orientation_label, 16, 0)
+        grid0.addWidget(self.orientation_radio, 16, 1)
+
+        # Page Size
+        self.pagesize_label = QtWidgets.QLabel('%s:' % _("Page Size"))
+        self.pagesize_label.setToolTip(_("A selection of standard ISO 216 page sizes."))
+
+        self.pagesize_combo = FCComboBox()
+
+        self.pagesize = dict()
+        self.pagesize.update(
+            {
+                'Bounds': None,
+                'A0': (841, 1189),
+                'A1': (594, 841),
+                'A2': (420, 594),
+                'A3': (297, 420),
+                'A4': (210, 297),
+                'A5': (148, 210),
+                'A6': (105, 148),
+                'A7': (74, 105),
+                'A8': (52, 74),
+                'A9': (37, 52),
+                'A10': (26, 37),
+
+                'B0': (1000, 1414),
+                'B1': (707, 1000),
+                'B2': (500, 707),
+                'B3': (353, 500),
+                'B4': (250, 353),
+                'B5': (176, 250),
+                'B6': (125, 176),
+                'B7': (88, 125),
+                'B8': (62, 88),
+                'B9': (44, 62),
+                'B10': (31, 44),
+
+                'C0': (917, 1297),
+                'C1': (648, 917),
+                'C2': (458, 648),
+                'C3': (324, 458),
+                'C4': (229, 324),
+                'C5': (162, 229),
+                'C6': (114, 162),
+                'C7': (81, 114),
+                'C8': (57, 81),
+                'C9': (40, 57),
+                'C10': (28, 40),
+
+                # American paper sizes
+                'LETTER': (8.5, 11),
+                'LEGAL': (8.5, 14),
+                'ELEVENSEVENTEEN': (11, 17),
+
+                # From https://en.wikipedia.org/wiki/Paper_size
+                'JUNIOR_LEGAL': (5, 8),
+                'HALF_LETTER': (5.5, 8),
+                'GOV_LETTER': (8, 10.5),
+                'GOV_LEGAL': (8.5, 13),
+                'LEDGER': (17, 11),
+            }
+        )
+
+        page_size_list = list(self.pagesize.keys())
+        self.pagesize_combo.addItems(page_size_list)
+
+        grid0.addWidget(self.pagesize_label, 17, 0)
+        grid0.addWidget(self.pagesize_combo, 17, 1)
 
 
         self.layout.addStretch()
         self.layout.addStretch()
 
 

+ 149 - 30
flatcamTools/ToolFilm.py

@@ -9,15 +9,17 @@ from PyQt5 import QtGui, QtCore, QtWidgets
 
 
 from FlatCAMTool import FlatCAMTool
 from FlatCAMTool import FlatCAMTool
 from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, \
 from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, \
-    OptionalHideInputSection, OptionalInputSection
+    OptionalHideInputSection, OptionalInputSection, FCComboBox
 
 
 from copy import deepcopy
 from copy import deepcopy
 import logging
 import logging
 from shapely.geometry import Polygon, MultiPolygon, Point
 from shapely.geometry import Polygon, MultiPolygon, Point
 
 
-from reportlab.graphics import renderPDF, renderPM
+from reportlab.graphics import renderPDF
 from reportlab.pdfgen import canvas
 from reportlab.pdfgen import canvas
-from reportlab.lib.pagesizes import letter, A0, A1, A2, A3, A4, A5
+from reportlab.graphics import renderPM
+from reportlab.lib.units import inch, mm
+from reportlab.lib.pagesizes import landscape, portrait, A4
 
 
 from svglib.svglib import svg2rlg
 from svglib.svglib import svg2rlg
 from xml.dom.minidom import parseString as parse_xml_string
 from xml.dom.minidom import parseString as parse_xml_string
@@ -268,6 +270,10 @@ class Film(FlatCAMTool):
         separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
         separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
         grid0.addWidget(separator_line2, 17, 0, 1, 2)
         grid0.addWidget(separator_line2, 17, 0, 1, 2)
 
 
+        self.film_param_label = QtWidgets.QLabel('<b>%s</b>' % _("Film Parameters"))
+
+        grid0.addWidget(self.film_param_label, 18, 0, 1, 2)
+
         # Scale Stroke size
         # Scale Stroke size
         self.film_scale_stroke_entry = FCDoubleSpinner()
         self.film_scale_stroke_entry = FCDoubleSpinner()
         self.film_scale_stroke_entry.set_range(-999.9999, 999.9999)
         self.film_scale_stroke_entry.set_range(-999.9999, 999.9999)
@@ -280,10 +286,10 @@ class Film(FlatCAMTool):
               "It means that the line that envelope each SVG feature will be thicker or thinner,\n"
               "It means that the line that envelope each SVG feature will be thicker or thinner,\n"
               "therefore the fine features may be more affected by this parameter.")
               "therefore the fine features may be more affected by this parameter.")
         )
         )
-        grid0.addWidget(self.film_scale_stroke_label, 18, 0)
-        grid0.addWidget(self.film_scale_stroke_entry, 18, 1)
+        grid0.addWidget(self.film_scale_stroke_label, 19, 0)
+        grid0.addWidget(self.film_scale_stroke_entry, 19, 1)
 
 
-        grid0.addWidget(QtWidgets.QLabel(''), 19, 0)
+        grid0.addWidget(QtWidgets.QLabel(''), 20, 0)
 
 
         # Film Type
         # Film Type
         self.film_type = RadioSet([{'label': _('Positive'), 'value': 'pos'},
         self.film_type = RadioSet([{'label': _('Positive'), 'value': 'pos'},
@@ -298,8 +304,8 @@ class Film(FlatCAMTool):
               "with white on a black canvas.\n"
               "with white on a black canvas.\n"
               "The Film format is SVG.")
               "The Film format is SVG.")
         )
         )
-        grid0.addWidget(self.film_type_label, 20, 0)
-        grid0.addWidget(self.film_type, 20, 1)
+        grid0.addWidget(self.film_type_label, 21, 0)
+        grid0.addWidget(self.film_type, 21, 1)
 
 
         # Boundary for negative film generation
         # Boundary for negative film generation
         self.boundary_entry = FCDoubleSpinner()
         self.boundary_entry = FCDoubleSpinner()
@@ -318,8 +324,8 @@ class Film(FlatCAMTool):
               "white color like the rest and which may confound with the\n"
               "white color like the rest and which may confound with the\n"
               "surroundings if not for this border.")
               "surroundings if not for this border.")
         )
         )
-        grid0.addWidget(self.boundary_label, 21, 0)
-        grid0.addWidget(self.boundary_entry, 21, 1)
+        grid0.addWidget(self.boundary_label, 22, 0)
+        grid0.addWidget(self.boundary_entry, 22, 1)
 
 
         self.boundary_label.hide()
         self.boundary_label.hide()
         self.boundary_entry.hide()
         self.boundary_entry.hide()
@@ -329,7 +335,7 @@ class Film(FlatCAMTool):
         self.punch_cb.setToolTip(_("When checked the generated film will have holes in pads when\n"
         self.punch_cb.setToolTip(_("When checked the generated film will have holes in pads when\n"
                                    "the generated film is positive. This is done to help drilling,\n"
                                    "the generated film is positive. This is done to help drilling,\n"
                                    "when done manually."))
                                    "when done manually."))
-        grid0.addWidget(self.punch_cb, 22, 0, 1, 2)
+        grid0.addWidget(self.punch_cb, 23, 0, 1, 2)
 
 
         # this way I can hide/show the frame
         # this way I can hide/show the frame
         self.punch_frame = QtWidgets.QFrame()
         self.punch_frame = QtWidgets.QFrame()
@@ -393,6 +399,7 @@ class Film(FlatCAMTool):
         separator_line3.setFrameShadow(QtWidgets.QFrame.Sunken)
         separator_line3.setFrameShadow(QtWidgets.QFrame.Sunken)
         grid1.addWidget(separator_line3, 0, 0, 1, 2)
         grid1.addWidget(separator_line3, 0, 0, 1, 2)
 
 
+        # File type
         self.file_type_radio = RadioSet([{'label': _('SVG'), 'value': 'svg'},
         self.file_type_radio = RadioSet([{'label': _('SVG'), 'value': 'svg'},
                                          {'label': _('PNG'), 'value': 'png'},
                                          {'label': _('PNG'), 'value': 'png'},
                                          {'label': _('PDF'), 'value': 'pdf'}
                                          {'label': _('PDF'), 'value': 'pdf'}
@@ -408,15 +415,96 @@ class Film(FlatCAMTool):
         grid1.addWidget(self.file_type_label, 1, 0)
         grid1.addWidget(self.file_type_label, 1, 0)
         grid1.addWidget(self.file_type_radio, 1, 1)
         grid1.addWidget(self.file_type_radio, 1, 1)
 
 
+        # Page orientation
+        self.orientation_label = QtWidgets.QLabel('%s:' % _("Page Orientation"))
+        self.orientation_label.setToolTip(_("Can be:\n"
+                                            "- Portrait\n"
+                                            "- Landscape"))
+
+        self.orientation_radio = RadioSet([{'label': _('Portrait'), 'value': 'p'},
+                                           {'label': _('Landscape'), 'value': 'l'},
+                                           ], stretch=False)
+
+        grid1.addWidget(self.orientation_label, 2, 0)
+        grid1.addWidget(self.orientation_radio, 2, 1)
+
+        # Page Size
+        self.pagesize_label = QtWidgets.QLabel('%s:' % _("Page Size"))
+        self.pagesize_label.setToolTip(_("A selection of standard ISO 216 page sizes."))
+
+        self.pagesize_combo = FCComboBox()
+
+        self.pagesize = dict()
+        self.pagesize.update(
+            {
+                'Bounds': None,
+                'A0': (841*mm, 1189*mm),
+                'A1': (594*mm, 841*mm),
+                'A2': (420*mm, 594*mm),
+                'A3': (297*mm, 420*mm),
+                'A4': (210*mm, 297*mm),
+                'A5': (148*mm, 210*mm),
+                'A6': (105*mm, 148*mm),
+                'A7': (74*mm, 105*mm),
+                'A8': (52*mm, 74*mm),
+                'A9': (37*mm, 52*mm),
+                'A10': (26*mm, 37*mm),
+
+                'B0': (1000*mm, 1414*mm),
+                'B1': (707*mm, 1000*mm),
+                'B2': (500*mm, 707*mm),
+                'B3': (353*mm, 500*mm),
+                'B4': (250*mm, 353*mm),
+                'B5': (176*mm, 250*mm),
+                'B6': (125*mm, 176*mm),
+                'B7': (88*mm, 125*mm),
+                'B8': (62*mm, 88*mm),
+                'B9': (44*mm, 62*mm),
+                'B10': (31*mm, 44*mm),
+
+                'C0': (917*mm, 1297*mm),
+                'C1': (648*mm, 917*mm),
+                'C2': (458*mm, 648*mm),
+                'C3': (324*mm, 458*mm),
+                'C4': (229*mm, 324*mm),
+                'C5': (162*mm, 229*mm),
+                'C6': (114*mm, 162*mm),
+                'C7': (81*mm, 114*mm),
+                'C8': (57*mm, 81*mm),
+                'C9': (40*mm, 57*mm),
+                'C10': (28*mm, 40*mm),
+
+                # American paper sizes
+                'LETTER': (8.5*inch, 11*inch),
+                'LEGAL': (8.5*inch, 14*inch),
+                'ELEVENSEVENTEEN': (11*inch, 17*inch),
+
+                # From https://en.wikipedia.org/wiki/Paper_size
+                'JUNIOR_LEGAL': (5*inch, 8*inch),
+                'HALF_LETTER': (5.5*inch, 8*inch),
+                'GOV_LETTER': (8*inch, 10.5*inch),
+                'GOV_LEGAL': (8.5*inch, 13*inch),
+                'LEDGER': (17*inch, 11*inch),
+            }
+        )
+
+        page_size_list = list(self.pagesize.keys())
+        self.pagesize_combo.addItems(page_size_list)
+
+        grid1.addWidget(self.pagesize_label, 3, 0)
+        grid1.addWidget(self.pagesize_combo, 3, 1)
+
+        self.on_film_type(val='hide')
+
         # Buttons
         # Buttons
         self.film_object_button = QtWidgets.QPushButton(_("Save Film"))
         self.film_object_button = QtWidgets.QPushButton(_("Save Film"))
         self.film_object_button.setToolTip(
         self.film_object_button.setToolTip(
             _("Create a Film for the selected object, within\n"
             _("Create a Film for the selected object, within\n"
               "the specified box. Does not create a new \n "
               "the specified box. Does not create a new \n "
-              "FlatCAM object, but directly save it in SVG format\n"
-              "which can be opened with Inkscape.")
+              "FlatCAM object, but directly save it in the\n"
+              "selected format.")
         )
         )
-        grid1.addWidget(self.film_object_button, 2, 0, 1, 2)
+        grid1.addWidget(self.film_object_button, 4, 0, 1, 2)
 
 
         self.layout.addStretch()
         self.layout.addStretch()
 
 
@@ -429,6 +517,7 @@ class Film(FlatCAMTool):
 
 
         self.film_type.activated_custom.connect(self.on_film_type)
         self.film_type.activated_custom.connect(self.on_film_type)
         self.source_punch.activated_custom.connect(self.on_punch_source)
         self.source_punch.activated_custom.connect(self.on_punch_source)
+        self.file_type_radio.activated_custom.connect(self.on_file_type)
 
 
     def on_type_obj_index_changed(self, index):
     def on_type_obj_index_changed(self, index):
         obj_type = self.tf_type_obj_combo.currentIndex()
         obj_type = self.tf_type_obj_combo.currentIndex()
@@ -498,6 +587,8 @@ class Film(FlatCAMTool):
         self.film_mirror_cb.set_value(self.app.defaults["tools_film_mirror_cb"])
         self.film_mirror_cb.set_value(self.app.defaults["tools_film_mirror_cb"])
         self.film_mirror_axis.set_value(self.app.defaults["tools_film_mirror_axis_radio"])
         self.film_mirror_axis.set_value(self.app.defaults["tools_film_mirror_axis_radio"])
         self.file_type_radio.set_value(self.app.defaults["tools_film_file_type_radio"])
         self.file_type_radio.set_value(self.app.defaults["tools_film_file_type_radio"])
+        self.orientation_radio.set_value(self.app.defaults["tools_film_orientation"])
+        self.pagesize_combo.set_value(self.app.defaults["tools_film_pagesize"])
 
 
     def on_film_type(self, val):
     def on_film_type(self, val):
         type_of_film = val
         type_of_film = val
@@ -512,6 +603,18 @@ class Film(FlatCAMTool):
             self.boundary_entry.hide()
             self.boundary_entry.hide()
             self.punch_cb.show()
             self.punch_cb.show()
 
 
+    def on_file_type(self, val):
+        if val == 'pdf':
+            self.orientation_label.show()
+            self.orientation_radio.show()
+            self.pagesize_label.show()
+            self.pagesize_combo.show()
+        else:
+            self.orientation_label.hide()
+            self.orientation_radio.hide()
+            self.pagesize_label.hide()
+            self.pagesize_combo.hide()
+
     def on_punch_source(self, val):
     def on_punch_source(self, val):
         if val == 'pad' and self.punch_cb.get_value():
         if val == 'pad' and self.punch_cb.get_value():
             self.punch_size_label.show()
             self.punch_size_label.show()
@@ -604,7 +707,7 @@ class Film(FlatCAMTool):
         try:
         try:
             filename, _f = QtWidgets.QFileDialog.getSaveFileName(
             filename, _f = QtWidgets.QFileDialog.getSaveFileName(
                 caption=_("Export positive film"),
                 caption=_("Export positive film"),
-                directory=self.app.get_last_save_folder() + '/' + name,
+                directory=self.app.get_last_save_folder() + '/' + name + '_film',
                 filter=filter_ext)
                 filter=filter_ext)
         except TypeError:
         except TypeError:
             filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export positive film"))
             filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export positive film"))
@@ -647,7 +750,7 @@ class Film(FlatCAMTool):
             outname = name + "_punched"
             outname = name + "_punched"
             self.app.new_object('gerber', outname, init_func)
             self.app.new_object('gerber', outname, init_func)
 
 
-            self.generate_positive_normal_film(outname, boxname, factor=factor)
+            self.generate_positive_normal_film(outname, boxname, factor=factor, ftype=ftype)
         else:
         else:
             log.debug("ToolFilm.Film.generate_positive_punched_film() with Pad center source started ...")
             log.debug("ToolFilm.Film.generate_positive_punched_film() with Pad center source started ...")
 
 
@@ -698,7 +801,7 @@ class Film(FlatCAMTool):
             outname = name + "_punched"
             outname = name + "_punched"
             self.app.new_object('gerber', outname, init_func)
             self.app.new_object('gerber', outname, init_func)
 
 
-            self.generate_positive_normal_film(outname, boxname, factor=factor)
+            self.generate_positive_normal_film(outname, boxname, factor=factor, ftype=ftype)
 
 
     def generate_negative_film(self, name, boxname, factor, ftype='svg'):
     def generate_negative_film(self, name, boxname, factor, ftype='svg'):
         log.debug("ToolFilm.Film.generate_negative_film() started ...")
         log.debug("ToolFilm.Film.generate_negative_film() started ...")
@@ -744,7 +847,7 @@ class Film(FlatCAMTool):
         try:
         try:
             filename, _f = QtWidgets.QFileDialog.getSaveFileName(
             filename, _f = QtWidgets.QFileDialog.getSaveFileName(
                 caption=_("Export negative film"),
                 caption=_("Export negative film"),
-                directory=self.app.get_last_save_folder() + '/' + name,
+                directory=self.app.get_last_save_folder() + '/' + name + '_film',
                 filter=filter_ext)
                 filter=filter_ext)
         except TypeError:
         except TypeError:
             filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export negative film"))
             filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export negative film"))
@@ -785,6 +888,7 @@ class Film(FlatCAMTool):
         those are the 4 points of the bounding box of the geometry to be skewed.
         those are the 4 points of the bounding box of the geometry to be skewed.
         :param mirror: can be 'x' or 'y' or 'both'. Axis on which to mirror the svg geometry
         :param mirror: can be 'x' or 'y' or 'both'. Axis on which to mirror the svg geometry
         :param use_thread: if to be run in a separate thread; boolean
         :param use_thread: if to be run in a separate thread; boolean
+        :param ftype: the type of file for saving the film: 'svg', 'png' or 'pdf'
         :return:
         :return:
         """
         """
         self.app.report_usage("export_negative()")
         self.app.report_usage("export_negative()")
@@ -896,19 +1000,26 @@ class Film(FlatCAMTool):
             else:
             else:
                 try:
                 try:
                     if self.units == 'INCH':
                     if self.units == 'INCH':
-                        from reportlab.lib.units import inch
                         unit = inch
                         unit = inch
                     else:
                     else:
-                        from reportlab.lib.units import mm
                         unit = mm
                         unit = mm
 
 
                     doc_final = StringIO(doc_final)
                     doc_final = StringIO(doc_final)
-                    my_canvas = canvas.Canvas(filename, pagesize=A4)
                     drawing = svg2rlg(doc_final)
                     drawing = svg2rlg(doc_final)
-                    my_canvas.translate(bounds[0] * unit, bounds[1] * unit)
 
 
-                    renderPDF.draw(drawing, my_canvas, 0, 0)
-                    my_canvas.save()
+                    p_size = self.pagesize_combo.get_value()
+                    if p_size == 'Bounds':
+                        renderPDF.drawToFile(drawing, filename)
+                    else:
+                        if self.orientation_radio.get_value() == 'p':
+                            page_size = portrait(self.pagesize[p_size])
+                        else:
+                            page_size = landscape(self.pagesize[p_size])
+
+                        my_canvas = canvas.Canvas(filename, pagesize=page_size)
+                        my_canvas.translate(bounds[0] * unit, bounds[1] * unit)
+                        renderPDF.draw(drawing, my_canvas, 0, 0)
+                        my_canvas.save()
                 except Exception as e:
                 except Exception as e:
                     log.debug("FilmTool.export_negative() --> PDF output --> %s" % str(e))
                     log.debug("FilmTool.export_negative() --> PDF output --> %s" % str(e))
                     return 'fail'
                     return 'fail'
@@ -955,6 +1066,7 @@ class Film(FlatCAMTool):
         :param mirror: can be 'x' or 'y' or 'both'. Axis on which to mirror the svg geometry
         :param mirror: can be 'x' or 'y' or 'both'. Axis on which to mirror the svg geometry
 
 
         :param use_thread: if to be run in a separate thread; boolean
         :param use_thread: if to be run in a separate thread; boolean
+        :param ftype: the type of file for saving the film: 'svg', 'png' or 'pdf'
         :return:
         :return:
         """
         """
         self.app.report_usage("export_positive()")
         self.app.report_usage("export_positive()")
@@ -1059,19 +1171,26 @@ class Film(FlatCAMTool):
             else:
             else:
                 try:
                 try:
                     if self.units == 'INCH':
                     if self.units == 'INCH':
-                        from reportlab.lib.units import inch
                         unit = inch
                         unit = inch
                     else:
                     else:
-                        from reportlab.lib.units import mm
                         unit = mm
                         unit = mm
 
 
                     doc_final = StringIO(doc_final)
                     doc_final = StringIO(doc_final)
-                    my_canvas = canvas.Canvas(filename, pagesize=A4)
                     drawing = svg2rlg(doc_final)
                     drawing = svg2rlg(doc_final)
-                    my_canvas.translate(bounds[0]*unit, bounds[1]*unit)
 
 
-                    renderPDF.draw(drawing, my_canvas, 0, 0)
-                    my_canvas.save()
+                    p_size = self.pagesize_combo.get_value()
+                    if p_size == 'Bounds':
+                        renderPDF.drawToFile(drawing, filename)
+                    else:
+                        if self.orientation_radio.get_value() == 'p':
+                            page_size = portrait(self.pagesize[p_size])
+                        else:
+                            page_size = landscape(self.pagesize[p_size])
+
+                        my_canvas = canvas.Canvas(filename, pagesize=page_size)
+                        my_canvas.translate(bounds[0] * unit, bounds[1] * unit)
+                        renderPDF.draw(drawing, my_canvas, 0, 0)
+                        my_canvas.save()
                 except Exception as e:
                 except Exception as e:
                     log.debug("FilmTool.export_positive() --> PDF output --> %s" % str(e))
                     log.debug("FilmTool.export_positive() --> PDF output --> %s" % str(e))
                     return 'fail'
                     return 'fail'

+ 10 - 12
flatcamTools/ToolMove.py

@@ -160,11 +160,12 @@ class ToolMove(FlatCAMTool):
 
 
                     def job_move(app_obj):
                     def job_move(app_obj):
                         with self.app.proc_container.new(_("Moving...")) as proc:
                         with self.app.proc_container.new(_("Moving...")) as proc:
-                            try:
-                                if not obj_list:
-                                    self.app.inform.emit('[WARNING_NOTCL] %s' % _("No object(s) selected."))
-                                    return "fail"
 
 
+                            if not obj_list:
+                                app_obj.app.inform.emit('[WARNING_NOTCL] %s' % _("No object(s) selected."))
+                                return "fail"
+
+                            try:
                                 # remove any mark aperture shape that may be displayed
                                 # remove any mark aperture shape that may be displayed
                                 for sel_obj in obj_list:
                                 for sel_obj in obj_list:
                                     # if the Gerber mark shapes are enabled they need to be disabled before move
                                     # if the Gerber mark shapes are enabled they need to be disabled before move
@@ -173,10 +174,9 @@ class ToolMove(FlatCAMTool):
 
 
                                     try:
                                     try:
                                         sel_obj.replotApertures.emit()
                                         sel_obj.replotApertures.emit()
-                                    except Exception as e:
+                                    except Exception:
                                         pass
                                         pass
 
 
-                                for sel_obj in obj_list:
                                     # offset solid_geometry
                                     # offset solid_geometry
                                     sel_obj.offset((dx, dy))
                                     sel_obj.offset((dx, dy))
 
 
@@ -186,15 +186,13 @@ class ToolMove(FlatCAMTool):
                                     sel_obj.options['ymin'] = b
                                     sel_obj.options['ymin'] = b
                                     sel_obj.options['xmax'] = c
                                     sel_obj.options['xmax'] = c
                                     sel_obj.options['ymax'] = d
                                     sel_obj.options['ymax'] = d
-
-                                # time to plot the moved objects
-                                self.replot_signal.emit(obj_list)
                             except Exception as e:
                             except Exception as e:
-                                proc.done()
-                                self.app.inform.emit('[ERROR_NOTCL] %s --> %s' % ('ToolMove.on_left_click()', str(e)))
+                                log.debug('[ERROR_NOTCL] %s --> %s' % ('ToolMove.on_left_click()', str(e)))
                                 return "fail"
                                 return "fail"
 
 
-                        proc.done()
+                            # time to plot the moved objects
+                            app_obj.replot_signal.emit(obj_list)
+
                         # delete the selection bounding box
                         # delete the selection bounding box
                         self.delete_shape()
                         self.delete_shape()
                         self.app.inform.emit('[success] %s %s' %
                         self.app.inform.emit('[success] %s %s' %

+ 3 - 3
flatcamTools/ToolPaint.py

@@ -381,6 +381,7 @@ class ToolPaint(FlatCAMTool, Gerber):
         self.overlap = None
         self.overlap = None
         self.connect = None
         self.connect = None
         self.contour = None
         self.contour = None
+        self.select_method = None
 
 
         self.units = ''
         self.units = ''
         self.paint_tools = {}
         self.paint_tools = {}
@@ -966,7 +967,6 @@ class ToolPaint(FlatCAMTool, Gerber):
         self.connect = self.pathconnect_cb.get_value()
         self.connect = self.pathconnect_cb.get_value()
         self.contour = self.paintcontour_cb.get_value()
         self.contour = self.paintcontour_cb.get_value()
         self.select_method = self.selectmethod_combo.get_value()
         self.select_method = self.selectmethod_combo.get_value()
-
         self.obj_name = self.obj_combo.currentText()
         self.obj_name = self.obj_combo.currentText()
 
 
         # Get source object.
         # Get source object.
@@ -2018,7 +2018,7 @@ class ToolPaint(FlatCAMTool, Gerber):
             except FlatCAMApp.GracefulException:
             except FlatCAMApp.GracefulException:
                 proc.done()
                 proc.done()
                 return
                 return
-            except Exception as e:
+            except Exception:
                 proc.done()
                 proc.done()
                 traceback.print_stack()
                 traceback.print_stack()
                 return
                 return
@@ -2493,7 +2493,7 @@ class ToolPaint(FlatCAMTool, Gerber):
             except FlatCAMApp.GracefulException:
             except FlatCAMApp.GracefulException:
                 proc.done()
                 proc.done()
                 return
                 return
-            except Exception as e:
+            except Exception:
                 proc.done()
                 proc.done()
                 traceback.print_stack()
                 traceback.print_stack()
                 return
                 return