From bc2f31aa90ea0ed8c14dcb9309319e54d168318c Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Sat, 2 Oct 2021 18:02:27 +0300 Subject: [PATCH] - in Preferences, more Plugins preferences UI is upgraded to the new look - In Paint Plugin fixed the Area select mode to work with Geometry object created by the Geometry Editor - in Paint Plugin some changes in the way the source object is autoloaded - in Paint, NCC and Cutout Plugins when using a mode that require to be terminated (by mouse RMB or ESC key) the notebook UI element is disabled until this is done --- CHANGELOG.md | 4 + .../general/GeneralAPPSetGroupUI.py | 16 +- .../tools/Tools2CThievingPrefGroupUI.py | 7 +- .../tools/Tools2ExtractPrefGroupUI.py | 181 +++++++++++------- .../tools/Tools2FiducialsPrefGroupUI.py | 2 + .../tools/Tools2InvertPrefGroupUI.py | 43 +++-- .../tools/Tools2PunchGerberPrefGroupUI.py | 134 ++++++++----- .../tools/Tools2QRCodePrefGroupUI.py | 55 +++--- appObjects/AppObject.py | 2 +- appPlugins/ToolCutOut.py | 39 ++-- appPlugins/ToolNCC.py | 52 +---- appPlugins/ToolPaint.py | 88 +++++---- camlib.py | 40 ++-- 13 files changed, 380 insertions(+), 283 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b8a17e4..7e64966a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ CHANGELOG for FlatCAM beta - clicking the splash screen will close it; also if an error is triggered, the error message will pop over the splash screen - the Aperture Table in the Gerber Editor is no longer extended to show all apertures at once - in Preferences: Excellon, Geometry and CNCJob tabs, updated the UI to the new design +- in Preferences, more Plugins preferences UI is upgraded to the new look +- In Paint Plugin fixed the Area select mode to work with Geometry object created by the Geometry Editor +- in Paint Plugin some changes in the way the source object is autoloaded +- in Paint, NCC and Cutout Plugins when using a mode that require to be terminated (by mouse RMB or ESC key) the notebook UI element is disabled until this is done 29.09.2021 diff --git a/appGUI/preferences/general/GeneralAPPSetGroupUI.py b/appGUI/preferences/general/GeneralAPPSetGroupUI.py index 6c2baa54..d11ea312 100644 --- a/appGUI/preferences/general/GeneralAPPSetGroupUI.py +++ b/appGUI/preferences/general/GeneralAPPSetGroupUI.py @@ -37,7 +37,7 @@ class GeneralAPPSetGroupUI(OptionsGroupUI): # Grid Settings Frame # ############################################################################################################# # GRID Settings - self.grid_label = FCLabel('%s' % _('Grid Settings')) + self.grid_label = FCLabel('%s' % _('Grid Settings')) self.layout.addWidget(self.grid_label) grids_frame = FCFrame() @@ -90,7 +90,7 @@ class GeneralAPPSetGroupUI(OptionsGroupUI): # Workspace Frame # ############################################################################################################# # Workspace - self.workspace_label = FCLabel('%s' % _('Workspace Settings')) + self.workspace_label = FCLabel('%s' % _('Workspace Settings')) self.layout.addWidget(self.workspace_label) wk_frame = FCFrame() @@ -191,7 +191,7 @@ class GeneralAPPSetGroupUI(OptionsGroupUI): # Font Frame # ############################################################################################################# # Font Size - self.font_size_label = FCLabel('%s' % _('Font Size')) + self.font_size_label = FCLabel('%s' % _('Font Size')) self.layout.addWidget(self.font_size_label) fnt_frame = FCFrame() @@ -283,7 +283,7 @@ class GeneralAPPSetGroupUI(OptionsGroupUI): # Axis Frame # ############################################################################################################# # Axis Size - self.axis_label = FCLabel('%s' % _('Axis')) + self.axis_label = FCLabel('%s' % _('Axis')) self.layout.addWidget(self.axis_label) ax_frame = FCFrame() @@ -305,7 +305,7 @@ class GeneralAPPSetGroupUI(OptionsGroupUI): # ############################################################################################################# # Mouse Frame # ############################################################################################################# - self.mouse_lbl = FCLabel('%s' % _('Mouse Settings')) + self.mouse_lbl = FCLabel('%s' % _('Mouse Settings')) self.layout.addWidget(self.mouse_lbl) m_frame = FCFrame() @@ -408,7 +408,7 @@ class GeneralAPPSetGroupUI(OptionsGroupUI): # ############################################################################################################# # Parameters Frame # ############################################################################################################# - self.par_label = FCLabel('%s:' % _('Parameters')) + self.par_label = FCLabel('%s' % _('Parameters')) self.layout.addWidget(self.par_label) par_frame = FCFrame() @@ -477,6 +477,10 @@ class GeneralAPPSetGroupUI(OptionsGroupUI): par_grid.addWidget(self.activity_label, 10, 0) par_grid.addWidget(self.activity_combo, 10, 1) + FCGridLayout.set_common_column_size( + [grids_grid, m_grid, par_grid, wk_grid, fnt_grid, ax_grid], 0 + ) + self.layout.addStretch() self.mouse_cursor_color_cb.stateChanged.connect(self.on_mouse_cursor_color_enable) diff --git a/appGUI/preferences/tools/Tools2CThievingPrefGroupUI.py b/appGUI/preferences/tools/Tools2CThievingPrefGroupUI.py index 67071ad3..d0c35bf4 100644 --- a/appGUI/preferences/tools/Tools2CThievingPrefGroupUI.py +++ b/appGUI/preferences/tools/Tools2CThievingPrefGroupUI.py @@ -259,7 +259,7 @@ class Tools2CThievingPrefGroupUI(OptionsGroupUI): # ############################################################################################################# # Robber Bar Parameters Frame # ############################################################################################################# - self.robber_bar_label = FCLabel('%s' % _('Robber Bar Parameters')) + self.robber_bar_label = FCLabel('%s' % _('Robber Bar Parameters')) self.robber_bar_label.setToolTip( _("Parameters used for the robber bar.\n" "Robber bar = copper border to help in pattern hole plating.") @@ -302,7 +302,7 @@ class Tools2CThievingPrefGroupUI(OptionsGroupUI): # ############################################################################################################# # RPattern Plating Mask Parameters Frame # ############################################################################################################# - self.patern_mask_label = FCLabel('%s' % _('Pattern Plating Mask')) + self.patern_mask_label = FCLabel('%s' % _('Pattern Plating Mask')) self.patern_mask_label.setToolTip( _("Generate a mask for pattern plating.") ) @@ -346,4 +346,7 @@ class Tools2CThievingPrefGroupUI(OptionsGroupUI): grid_ppm.addWidget(self.ppm_choice_label, 4, 0) grid_ppm.addWidget(self.ppm_choice_combo, 4, 1) + FCGridLayout.set_common_column_size( + [grid_par, grid_ppm, grid_line, grid_dots, grid_robber, grid_square], 0) + self.layout.addStretch() diff --git a/appGUI/preferences/tools/Tools2ExtractPrefGroupUI.py b/appGUI/preferences/tools/Tools2ExtractPrefGroupUI.py index 81c7e21c..62eee520 100644 --- a/appGUI/preferences/tools/Tools2ExtractPrefGroupUI.py +++ b/appGUI/preferences/tools/Tools2ExtractPrefGroupUI.py @@ -1,6 +1,6 @@ from PyQt6 import QtWidgets -from appGUI.GUIElements import FCCheckBox, RadioSet, FCDoubleSpinner, FCLabel, FCGridLayout +from appGUI.GUIElements import FCCheckBox, RadioSet, FCDoubleSpinner, FCLabel, FCGridLayout, FCFrame from appGUI.preferences.OptionsGroupUI import OptionsGroupUI import gettext @@ -21,24 +21,23 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI): self.decimals = decimals self.defaults = defaults - # ## Grid Layout - grid_lay = FCGridLayout(v_spacing=5, h_spacing=3) - self.layout.addLayout(grid_lay) - - self.param_label = FCLabel('%s:' % _('Parameters')) - self.param_label.setToolTip( - _("Parameters used for this tool.") - ) - grid_lay.addWidget(self.param_label, 0, 0, 1, 2) - - self.padt_label = FCLabel("%s:" % _("Processed Pads Type")) + # ############################################################################################################# + # PARAMETERS Frame + # ############################################################################################################# + self.padt_label = FCLabel('%s' % _("Processed Pads Type")) self.padt_label.setToolTip( _("The type of pads shape to be processed.\n" "If the PCB has many SMD pads with rectangular pads,\n" "disable the Rectangular aperture.") ) - grid_lay.addWidget(self.padt_label, 2, 0, 1, 2) + self.layout.addWidget(self.padt_label) + + param_frame = FCFrame() + self.layout.addWidget(param_frame) + + param_grid = FCGridLayout(v_spacing=5, h_spacing=3) + param_frame.setLayout(param_grid) # Circular Aperture Selection self.circular_cb = FCCheckBox('%s' % _("Circular")) @@ -46,7 +45,7 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI): _("Process Circular Pads.") ) - grid_lay.addWidget(self.circular_cb, 3, 0, 1, 2) + param_grid.addWidget(self.circular_cb, 3, 0, 1, 2) # Oblong Aperture Selection self.oblong_cb = FCCheckBox('%s' % _("Oblong")) @@ -54,7 +53,7 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI): _("Process Oblong Pads.") ) - grid_lay.addWidget(self.oblong_cb, 4, 0, 1, 2) + param_grid.addWidget(self.oblong_cb, 4, 0, 1, 2) # Square Aperture Selection self.square_cb = FCCheckBox('%s' % _("Square")) @@ -62,7 +61,7 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI): _("Process Square Pads.") ) - grid_lay.addWidget(self.square_cb, 5, 0, 1, 2) + param_grid.addWidget(self.square_cb, 5, 0, 1, 2) # Rectangular Aperture Selection self.rectangular_cb = FCCheckBox('%s' % _("Rectangular")) @@ -70,7 +69,7 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI): _("Process Rectangular Pads.") ) - grid_lay.addWidget(self.rectangular_cb, 6, 0, 1, 2) + param_grid.addWidget(self.rectangular_cb, 6, 0, 1, 2) # Others type of Apertures Selection self.other_cb = FCCheckBox('%s' % _("Others")) @@ -78,14 +77,22 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI): _("Process pads not in the categories above.") ) - grid_lay.addWidget(self.other_cb, 7, 0, 1, 2) + param_grid.addWidget(self.other_cb, 7, 0, 1, 2) - separator_line = QtWidgets.QFrame() - separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine) - separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) - grid_lay.addWidget(separator_line, 8, 0, 1, 2) + # separator_line = QtWidgets.QFrame() + # separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine) + # separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + # param_grid.addWidget(separator_line, 8, 0, 1, 2) + + # ############################################################################################################# + # Method Frame + # ############################################################################################################# + met_frame = FCFrame() + self.layout.addWidget(met_frame) + + met_grid = FCGridLayout(v_spacing=5, h_spacing=3) + met_frame.setLayout(met_grid) - # Method of extraction self.method_radio = RadioSet( [ {'label': _("Fixed Diameter"), 'value': 'fixed'}, @@ -94,26 +101,32 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI): ], orientation='vertical', compact=True) - self.method_label = FCLabel('%s:' % _("Method")) + self.method_label = FCLabel('%s:' % _("Method")) self.method_label.setToolTip( _("The method for processing pads. Can be:\n" "- Fixed Diameter -> all holes will have a set size\n" "- Fixed Annular Ring -> all holes will have a set annular ring\n" "- Proportional -> each hole size will be a fraction of the pad size")) - grid_lay.addWidget(self.method_label, 9, 0) - grid_lay.addWidget(self.method_radio, 9, 1) + met_grid.addWidget(self.method_label, 0, 0) + met_grid.addWidget(self.method_radio, 0, 1) - # grid_lay1.addWidget(FCLabel('')) + # separator_line = QtWidgets.QFrame() + # separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine) + # separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + # param_grid.addWidget(separator_line, 10, 0, 1, 2) - separator_line = QtWidgets.QFrame() - separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine) - separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) - grid_lay.addWidget(separator_line, 10, 0, 1, 2) + # ############################################################################################################# + # Fixed Diameter Frame + # ############################################################################################################# + self.fixed_label = FCLabel('%s' % _("Fixed Diameter")) + self.layout.addWidget(self.fixed_label) - # Annular Ring - self.fixed_label = FCLabel('%s' % _("Fixed Diameter")) - grid_lay.addWidget(self.fixed_label, 11, 0, 1, 2) + fix_frame = FCFrame() + self.layout.addWidget(fix_frame) + + fix_grid = FCGridLayout(v_spacing=5, h_spacing=3) + fix_frame.setLayout(fix_grid) # Diameter value self.dia_entry = FCDoubleSpinner() @@ -125,17 +138,25 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI): _("Fixed hole diameter.") ) - grid_lay.addWidget(self.dia_label, 12, 0) - grid_lay.addWidget(self.dia_entry, 12, 1) + fix_grid.addWidget(self.dia_label, 0, 0) + fix_grid.addWidget(self.dia_entry, 0, 1) - # Annular Ring value - self.ring_label = FCLabel('%s' % _("Fixed Annular Ring")) + # ############################################################################################################# + # Annular ring Frame + # ############################################################################################################# + self.ring_label = FCLabel('%s' % _("Fixed Annular Ring")) self.ring_label.setToolTip( _("The size of annular ring.\n" "The copper sliver between the hole exterior\n" "and the margin of the copper pad.") ) - grid_lay.addWidget(self.ring_label, 13, 0, 1, 2) + self.layout.addWidget(self.ring_label) + + ring_frame = FCFrame() + self.layout.addWidget(ring_frame) + + ring_grid = FCGridLayout(v_spacing=5, h_spacing=3) + ring_frame.setLayout(ring_grid) # Circular Annular Ring Value self.circular_ring_label = FCLabel('%s:' % _("Circular")) @@ -147,8 +168,8 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI): self.circular_ring_entry.set_precision(self.decimals) self.circular_ring_entry.set_range(0.0000, 10000.0000) - grid_lay.addWidget(self.circular_ring_label, 14, 0) - grid_lay.addWidget(self.circular_ring_entry, 14, 1) + ring_grid.addWidget(self.circular_ring_label, 0, 0) + ring_grid.addWidget(self.circular_ring_entry, 0, 1) # Oblong Annular Ring Value self.oblong_ring_label = FCLabel('%s:' % _("Oblong")) @@ -160,8 +181,8 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI): self.oblong_ring_entry.set_precision(self.decimals) self.oblong_ring_entry.set_range(0.0000, 10000.0000) - grid_lay.addWidget(self.oblong_ring_label, 15, 0) - grid_lay.addWidget(self.oblong_ring_entry, 15, 1) + ring_grid.addWidget(self.oblong_ring_label, 2, 0) + ring_grid.addWidget(self.oblong_ring_entry, 2, 1) # Square Annular Ring Value self.square_ring_label = FCLabel('%s:' % _("Square")) @@ -173,8 +194,8 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI): self.square_ring_entry.set_precision(self.decimals) self.square_ring_entry.set_range(0.0000, 10000.0000) - grid_lay.addWidget(self.square_ring_label, 16, 0) - grid_lay.addWidget(self.square_ring_entry, 16, 1) + ring_grid.addWidget(self.square_ring_label, 4, 0) + ring_grid.addWidget(self.square_ring_entry, 4, 1) # Rectangular Annular Ring Value self.rectangular_ring_label = FCLabel('%s:' % _("Rectangular")) @@ -186,8 +207,8 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI): self.rectangular_ring_entry.set_precision(self.decimals) self.rectangular_ring_entry.set_range(0.0000, 10000.0000) - grid_lay.addWidget(self.rectangular_ring_label, 17, 0) - grid_lay.addWidget(self.rectangular_ring_entry, 17, 1) + ring_grid.addWidget(self.rectangular_ring_label, 6, 0) + ring_grid.addWidget(self.rectangular_ring_entry, 6, 1) # Others Annular Ring Value self.other_ring_label = FCLabel('%s:' % _("Others")) @@ -199,11 +220,20 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI): self.other_ring_entry.set_precision(self.decimals) self.other_ring_entry.set_range(0.0000, 10000.0000) - grid_lay.addWidget(self.other_ring_label, 18, 0) - grid_lay.addWidget(self.other_ring_entry, 18, 1) + ring_grid.addWidget(self.other_ring_label, 8, 0) + ring_grid.addWidget(self.other_ring_entry, 8, 1) - self.prop_label = FCLabel('%s' % _("Proportional Diameter")) - grid_lay.addWidget(self.prop_label, 19, 0, 1, 2) + # ############################################################################################################# + # Proportional Diameter Frame + # ############################################################################################################# + self.prop_label = FCLabel('%s' % _("Proportional Diameter")) + self.layout.addWidget(self.prop_label) + + prop_frame = FCFrame() + self.layout.addWidget(prop_frame) + + prop_grid = FCGridLayout(v_spacing=5, h_spacing=3) + prop_frame.setLayout(prop_grid) # Factor value self.factor_entry = FCDoubleSpinner(suffix='%') @@ -217,14 +247,22 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI): "The hole diameter will be a fraction of the pad size.") ) - grid_lay.addWidget(self.factor_label, 20, 0) - grid_lay.addWidget(self.factor_entry, 20, 1) + prop_grid.addWidget(self.factor_label, 0, 0) + prop_grid.addWidget(self.factor_entry, 0, 1) - # EXTRACT SOLDERMASK - self.extract_sm_label = FCLabel('%s' % _("Extract Soldermask")) + # ############################################################################################################# + # Extract Soldermask Frame + # ############################################################################################################# + self.extract_sm_label = FCLabel('%s' % _("Extract Soldermask")) self.extract_sm_label.setToolTip( _("Extract soldermask from a given Gerber file.")) - grid_lay.addWidget(self.extract_sm_label, 22, 0, 1, 2) + self.layout.addWidget(self.extract_sm_label) + + solder_frame = FCFrame() + self.layout.addWidget(solder_frame) + + solder_grid = FCGridLayout(v_spacing=5, h_spacing=3) + solder_frame.setLayout(solder_grid) # CLEARANCE soldermask extraction self.clearance_label = FCLabel('%s:' % _("Clearance")) @@ -237,14 +275,22 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI): self.clearance_entry.set_precision(self.decimals) self.clearance_entry.setSingleStep(0.1) - grid_lay.addWidget(self.clearance_label, 24, 0) - grid_lay.addWidget(self.clearance_entry, 24, 1) + solder_grid.addWidget(self.clearance_label, 0, 0) + solder_grid.addWidget(self.clearance_entry, 0, 1) - # EXTRACT CUTOUT - self.extract_cut_label = FCLabel('%s' % _("Extract Cutout")) + # ############################################################################################################# + # Extract CutOut Frame + # ############################################################################################################# + self.extract_cut_label = FCLabel('%s' % _("Extract Cutout")) self.extract_cut_label.setToolTip( _("Extract a cutout from a given Gerber file.")) - grid_lay.addWidget(self.extract_cut_label, 26, 0, 1, 2) + self.layout.addWidget(self.extract_cut_label) + + ecut_frame = FCFrame() + self.layout.addWidget(ecut_frame) + + ecut_grid = FCGridLayout(v_spacing=5, h_spacing=3) + ecut_frame.setLayout(ecut_grid) # Margin Cutout self.margin_cut_label = FCLabel('%s:' % _("Margin")) @@ -258,8 +304,8 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI): self.margin_cut_entry.set_precision(self.decimals) self.margin_cut_entry.setSingleStep(0.1) - grid_lay.addWidget(self.margin_cut_label, 28, 0) - grid_lay.addWidget(self.margin_cut_entry, 28, 1) + ecut_grid.addWidget(self.margin_cut_label, 0, 0) + ecut_grid.addWidget(self.margin_cut_entry, 0, 1) # Thickness Cutout self.thick_cut_label = FCLabel('%s:' % _("Thickness")) @@ -271,7 +317,10 @@ class Tools2EDrillsPrefGroupUI(OptionsGroupUI): self.thick_cut_entry.set_precision(self.decimals) self.thick_cut_entry.setSingleStep(0.1) - grid_lay.addWidget(self.thick_cut_label, 30, 0) - grid_lay.addWidget(self.thick_cut_entry, 30, 1) - + ecut_grid.addWidget(self.thick_cut_label, 2, 0) + ecut_grid.addWidget(self.thick_cut_entry, 2, 1) + + FCGridLayout.set_common_column_size( + [param_grid, ring_grid, fix_grid, prop_grid, met_grid, solder_grid, ecut_grid], 0) + self.layout.addStretch() diff --git a/appGUI/preferences/tools/Tools2FiducialsPrefGroupUI.py b/appGUI/preferences/tools/Tools2FiducialsPrefGroupUI.py index b7d53408..76c1fb63 100644 --- a/appGUI/preferences/tools/Tools2FiducialsPrefGroupUI.py +++ b/appGUI/preferences/tools/Tools2FiducialsPrefGroupUI.py @@ -141,4 +141,6 @@ class Tools2FiducialsPrefGroupUI(OptionsGroupUI): grid_sel.addWidget(self.mode_label, 0, 0) grid_sel.addWidget(self.mode_radio, 0, 1) + FCGridLayout.set_common_column_size([grid_par, grid_sel], 0) + self.layout.addStretch(1) diff --git a/appGUI/preferences/tools/Tools2InvertPrefGroupUI.py b/appGUI/preferences/tools/Tools2InvertPrefGroupUI.py index 33614115..bc5246b1 100644 --- a/appGUI/preferences/tools/Tools2InvertPrefGroupUI.py +++ b/appGUI/preferences/tools/Tools2InvertPrefGroupUI.py @@ -1,6 +1,6 @@ from PyQt6 import QtWidgets -from appGUI.GUIElements import FCDoubleSpinner, RadioSet, FCLabel, FCGridLayout +from appGUI.GUIElements import FCDoubleSpinner, RadioSet, FCLabel, FCGridLayout, FCFrame from appGUI.preferences.OptionsGroupUI import OptionsGroupUI import gettext @@ -21,17 +21,21 @@ class Tools2InvertPrefGroupUI(OptionsGroupUI): self.decimals = decimals self.defaults = defaults - # ## Subtractor Tool Parameters - self.sublabel = FCLabel("%s:" % _("Parameters")) + # ############################################################################################################# + # PARAMETERS Frame + # ############################################################################################################# + self.sublabel = FCLabel('%s' % _("Parameters")) self.sublabel.setToolTip( _("A tool to invert Gerber geometry from positive to negative\n" "and in revers.") ) self.layout.addWidget(self.sublabel) - # Grid Layout - grid0 = FCGridLayout(v_spacing=5, h_spacing=3) - self.layout.addLayout(grid0) + param_frame = FCFrame() + self.layout.addWidget(param_frame) + + param_grid = FCGridLayout(v_spacing=5, h_spacing=3) + param_frame.setLayout(param_grid) # Margin self.margin_label = FCLabel('%s:' % _('Margin')) @@ -44,10 +48,13 @@ class Tools2InvertPrefGroupUI(OptionsGroupUI): self.margin_entry.set_range(0.0000, 10000.0000) self.margin_entry.setObjectName(_("Margin")) - grid0.addWidget(self.margin_label, 2, 0, 1, 2) - grid0.addWidget(self.margin_entry, 3, 0, 1, 2) + param_grid.addWidget(self.margin_label, 0, 0) + param_grid.addWidget(self.margin_entry, 0, 1) - self.join_label = FCLabel('%s:' % _("Lines Join Style")) + # ############################################################################################################# + # Line Join Frame + # ############################################################################################################# + self.join_label = FCLabel('%s' % _("Lines Join Style")) self.join_label.setToolTip( _("The way that the lines in the object outline will be joined.\n" "Can be:\n" @@ -55,13 +62,25 @@ class Tools2InvertPrefGroupUI(OptionsGroupUI): "- square -> the lines meet in 90 degrees angle\n" "- bevel -> the lines are joined by a third line") ) + self.layout.addWidget(self.join_label) + + join_frame = FCFrame() + self.layout.addWidget(join_frame) + + join_grid = FCGridLayout(v_spacing=5, h_spacing=3) + join_frame.setLayout(join_grid) + + line_join_lbl = FCLabel('%s:' % _("Value")) + self.join_radio = RadioSet([ {'label': _('Rounded'), 'value': 'r'}, {'label': _('Square'), 'value': 's'}, {'label': _('Bevel'), 'value': 'b'} - ], orientation='vertical', compact=True) + ], orientation='vertical') - grid0.addWidget(self.join_label, 5, 0, 1, 2) - grid0.addWidget(self.join_radio, 7, 0, 1, 2) + join_grid.addWidget(line_join_lbl, 0, 0) + join_grid.addWidget(self.join_radio, 0, 1) + + FCGridLayout.set_common_column_size([param_grid, join_grid], 0) self.layout.addStretch() diff --git a/appGUI/preferences/tools/Tools2PunchGerberPrefGroupUI.py b/appGUI/preferences/tools/Tools2PunchGerberPrefGroupUI.py index a7e88dbc..fff4c1fe 100644 --- a/appGUI/preferences/tools/Tools2PunchGerberPrefGroupUI.py +++ b/appGUI/preferences/tools/Tools2PunchGerberPrefGroupUI.py @@ -1,6 +1,6 @@ from PyQt6 import QtWidgets -from appGUI.GUIElements import FCCheckBox, RadioSet, FCDoubleSpinner, FCLabel, FCGridLayout +from appGUI.GUIElements import FCCheckBox, RadioSet, FCDoubleSpinner, FCLabel, FCGridLayout, FCFrame from appGUI.preferences.OptionsGroupUI import OptionsGroupUI import gettext @@ -21,24 +21,23 @@ class Tools2PunchGerberPrefGroupUI(OptionsGroupUI): self.decimals = decimals self.defaults = defaults - # ## Grid Layout - grid_lay = FCGridLayout(v_spacing=5, h_spacing=3) - self.layout.addLayout(grid_lay) - - self.param_label = FCLabel('%s:' % _('Parameters')) - self.param_label.setToolTip( - _("Parameters used for this tool.") - ) - grid_lay.addWidget(self.param_label, 0, 0, 1, 2) - - self.padt_label = FCLabel("%s:" % _("Processed Pads Type")) + # ############################################################################################################# + # Processed Pads Frame + # ############################################################################################################# + self.padt_label = FCLabel('%s' % _("Processed Pads Type")) self.padt_label.setToolTip( _("The type of pads shape to be processed.\n" "If the PCB has many SMD pads with rectangular pads,\n" "disable the Rectangular aperture.") ) - grid_lay.addWidget(self.padt_label, 2, 0, 1, 2) + self.layout.addWidget(self.padt_label) + + param_frame = FCFrame() + self.layout.addWidget(param_frame) + + param_grid = FCGridLayout(v_spacing=5, h_spacing=3) + param_frame.setLayout(param_grid) # Circular Aperture Selection self.circular_cb = FCCheckBox('%s' % _("Circular")) @@ -46,7 +45,7 @@ class Tools2PunchGerberPrefGroupUI(OptionsGroupUI): _("Process Circular Pads.") ) - grid_lay.addWidget(self.circular_cb, 3, 0, 1, 2) + param_grid.addWidget(self.circular_cb, 3, 0, 1, 2) # Oblong Aperture Selection self.oblong_cb = FCCheckBox('%s' % _("Oblong")) @@ -54,7 +53,7 @@ class Tools2PunchGerberPrefGroupUI(OptionsGroupUI): _("Process Oblong Pads.") ) - grid_lay.addWidget(self.oblong_cb, 4, 0, 1, 2) + param_grid.addWidget(self.oblong_cb, 4, 0, 1, 2) # Square Aperture Selection self.square_cb = FCCheckBox('%s' % _("Square")) @@ -62,7 +61,7 @@ class Tools2PunchGerberPrefGroupUI(OptionsGroupUI): _("Process Square Pads.") ) - grid_lay.addWidget(self.square_cb, 5, 0, 1, 2) + param_grid.addWidget(self.square_cb, 5, 0, 1, 2) # Rectangular Aperture Selection self.rectangular_cb = FCCheckBox('%s' % _("Rectangular")) @@ -70,7 +69,7 @@ class Tools2PunchGerberPrefGroupUI(OptionsGroupUI): _("Process Rectangular Pads.") ) - grid_lay.addWidget(self.rectangular_cb, 6, 0, 1, 2) + param_grid.addWidget(self.rectangular_cb, 6, 0, 1, 2) # Others type of Apertures Selection self.other_cb = FCCheckBox('%s' % _("Others")) @@ -78,14 +77,22 @@ class Tools2PunchGerberPrefGroupUI(OptionsGroupUI): _("Process pads not in the categories above.") ) - grid_lay.addWidget(self.other_cb, 7, 0, 1, 2) + param_grid.addWidget(self.other_cb, 7, 0, 1, 2) - separator_line = QtWidgets.QFrame() - separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine) - separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) - grid_lay.addWidget(separator_line, 8, 0, 1, 2) + # separator_line = QtWidgets.QFrame() + # separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine) + # separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + # param_grid.addWidget(separator_line, 8, 0, 1, 2) + + # ############################################################################################################# + # Method Frame + # ############################################################################################################# + met_frame = FCFrame() + self.layout.addWidget(met_frame) + + met_grid = FCGridLayout(v_spacing=5, h_spacing=3) + met_frame.setLayout(met_grid) - # ## Axis self.hole_size_radio = RadioSet( [ {'label': _("Excellon"), 'value': 'exc'}, @@ -95,7 +102,7 @@ class Tools2PunchGerberPrefGroupUI(OptionsGroupUI): ], orientation='vertical', compact=True) - self.hole_size_label = FCLabel('%s:' % _("Method")) + self.hole_size_label = FCLabel('%s:' % _("Method")) self.hole_size_label.setToolTip( _("The punch hole source can be:\n" "- Excellon Object-> the Excellon object drills center will serve as reference.\n" @@ -103,19 +110,20 @@ class Tools2PunchGerberPrefGroupUI(OptionsGroupUI): "- Fixed Annular Ring -> will try to keep a set annular ring.\n" "- Proportional -> will make a Gerber punch hole having the diameter a percentage of the pad diameter.") ) - grid_lay.addWidget(self.hole_size_label, 9, 0) - grid_lay.addWidget(self.hole_size_radio, 9, 1) + met_grid.addWidget(self.hole_size_label, 9, 0) + met_grid.addWidget(self.hole_size_radio, 9, 1) - # grid_lay1.addWidget(FCLabel('')) + # ############################################################################################################# + # Fixed Diameter Frame + # ############################################################################################################# + self.fixed_label = FCLabel('%s' % _("Fixed Diameter")) + self.layout.addWidget(self.fixed_label) - separator_line = QtWidgets.QFrame() - separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine) - separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) - grid_lay.addWidget(separator_line, 10, 0, 1, 2) + fix_frame = FCFrame() + self.layout.addWidget(fix_frame) - # Annular Ring - self.fixed_label = FCLabel('%s' % _("Fixed Diameter")) - grid_lay.addWidget(self.fixed_label, 11, 0, 1, 2) + fix_grid = FCGridLayout(v_spacing=5, h_spacing=3) + fix_frame.setLayout(fix_grid) # Diameter value self.dia_entry = FCDoubleSpinner() @@ -127,17 +135,25 @@ class Tools2PunchGerberPrefGroupUI(OptionsGroupUI): _("Fixed hole diameter.") ) - grid_lay.addWidget(self.dia_label, 12, 0) - grid_lay.addWidget(self.dia_entry, 12, 1) + fix_grid.addWidget(self.dia_label, 0, 0) + fix_grid.addWidget(self.dia_entry, 0, 1) - # Annular Ring value - self.ring_label = FCLabel('%s' % _("Fixed Annular Ring")) + # ############################################################################################################# + # Annular ring Frame + # ############################################################################################################# + self.ring_label = FCLabel('%s' % _("Fixed Annular Ring")) self.ring_label.setToolTip( _("The size of annular ring.\n" "The copper sliver between the hole exterior\n" "and the margin of the copper pad.") ) - grid_lay.addWidget(self.ring_label, 13, 0, 1, 2) + self.layout.addWidget(self.ring_label) + + ring_frame = FCFrame() + self.layout.addWidget(ring_frame) + + ring_grid = FCGridLayout(v_spacing=5, h_spacing=3) + ring_frame.setLayout(ring_grid) # Circular Annular Ring Value self.circular_ring_label = FCLabel('%s:' % _("Circular")) @@ -149,8 +165,8 @@ class Tools2PunchGerberPrefGroupUI(OptionsGroupUI): self.circular_ring_entry.set_precision(self.decimals) self.circular_ring_entry.set_range(0.0000, 10000.0000) - grid_lay.addWidget(self.circular_ring_label, 14, 0) - grid_lay.addWidget(self.circular_ring_entry, 14, 1) + ring_grid.addWidget(self.circular_ring_label, 0, 0) + ring_grid.addWidget(self.circular_ring_entry, 0, 1) # Oblong Annular Ring Value self.oblong_ring_label = FCLabel('%s:' % _("Oblong")) @@ -162,8 +178,8 @@ class Tools2PunchGerberPrefGroupUI(OptionsGroupUI): self.oblong_ring_entry.set_precision(self.decimals) self.oblong_ring_entry.set_range(0.0000, 10000.0000) - grid_lay.addWidget(self.oblong_ring_label, 15, 0) - grid_lay.addWidget(self.oblong_ring_entry, 15, 1) + ring_grid.addWidget(self.oblong_ring_label, 2, 0) + ring_grid.addWidget(self.oblong_ring_entry, 2, 1) # Square Annular Ring Value self.square_ring_label = FCLabel('%s:' % _("Square")) @@ -175,8 +191,8 @@ class Tools2PunchGerberPrefGroupUI(OptionsGroupUI): self.square_ring_entry.set_precision(self.decimals) self.square_ring_entry.set_range(0.0000, 10000.0000) - grid_lay.addWidget(self.square_ring_label, 16, 0) - grid_lay.addWidget(self.square_ring_entry, 16, 1) + ring_grid.addWidget(self.square_ring_label, 4, 0) + ring_grid.addWidget(self.square_ring_entry, 4, 1) # Rectangular Annular Ring Value self.rectangular_ring_label = FCLabel('%s:' % _("Rectangular")) @@ -188,8 +204,8 @@ class Tools2PunchGerberPrefGroupUI(OptionsGroupUI): self.rectangular_ring_entry.set_precision(self.decimals) self.rectangular_ring_entry.set_range(0.0000, 10000.0000) - grid_lay.addWidget(self.rectangular_ring_label, 17, 0) - grid_lay.addWidget(self.rectangular_ring_entry, 17, 1) + ring_grid.addWidget(self.rectangular_ring_label, 6, 0) + ring_grid.addWidget(self.rectangular_ring_entry, 6, 1) # Others Annular Ring Value self.other_ring_label = FCLabel('%s:' % _("Others")) @@ -201,11 +217,20 @@ class Tools2PunchGerberPrefGroupUI(OptionsGroupUI): self.other_ring_entry.set_precision(self.decimals) self.other_ring_entry.set_range(0.0000, 10000.0000) - grid_lay.addWidget(self.other_ring_label, 18, 0) - grid_lay.addWidget(self.other_ring_entry, 18, 1) + ring_grid.addWidget(self.other_ring_label, 8, 0) + ring_grid.addWidget(self.other_ring_entry, 8, 1) - self.prop_label = FCLabel('%s' % _("Proportional Diameter")) - grid_lay.addWidget(self.prop_label, 19, 0, 1, 2) + # ############################################################################################################# + # Proportional Diameter Frame + # ############################################################################################################# + self.prop_label = FCLabel('%s' % _("Proportional Diameter")) + self.layout.addWidget(self.prop_label) + + prop_frame = FCFrame() + self.layout.addWidget(prop_frame) + + prop_grid = FCGridLayout(v_spacing=5, h_spacing=3) + prop_frame.setLayout(prop_grid) # Factor value self.factor_entry = FCDoubleSpinner(suffix='%') @@ -219,7 +244,10 @@ class Tools2PunchGerberPrefGroupUI(OptionsGroupUI): "The hole diameter will be a fraction of the pad size.") ) - grid_lay.addWidget(self.factor_label, 20, 0) - grid_lay.addWidget(self.factor_entry, 20, 1) + prop_grid.addWidget(self.factor_label, 0, 0) + prop_grid.addWidget(self.factor_entry, 0, 1) + + FCGridLayout.set_common_column_size( + [param_grid, ring_grid, prop_grid, met_grid, fix_grid], 0) self.layout.addStretch() diff --git a/appGUI/preferences/tools/Tools2QRCodePrefGroupUI.py b/appGUI/preferences/tools/Tools2QRCodePrefGroupUI.py index 75d33562..26ccc682 100644 --- a/appGUI/preferences/tools/Tools2QRCodePrefGroupUI.py +++ b/appGUI/preferences/tools/Tools2QRCodePrefGroupUI.py @@ -1,6 +1,6 @@ from PyQt6 import QtWidgets -from appGUI.GUIElements import FCSpinner, RadioSet, FCTextArea, FCLabel, FCColorEntry, FCGridLayout +from appGUI.GUIElements import FCSpinner, RadioSet, FCTextArea, FCLabel, FCColorEntry, FCGridLayout, FCFrame from appGUI.preferences.OptionsGroupUI import OptionsGroupUI import gettext @@ -21,17 +21,22 @@ class Tools2QRCodePrefGroupUI(OptionsGroupUI): self.decimals = decimals self.defaults = defaults - # ## Parameters - self.qrlabel = FCLabel("%s:" % _("Parameters")) + # ############################################################################################################# + # Parameters Frame + # ############################################################################################################# + self.qrlabel = FCLabel('%s' % _("Parameters")) self.qrlabel.setToolTip( _("A tool to create a QRCode that can be inserted\n" "into a selected Gerber file, or it can be exported as a file.") ) self.layout.addWidget(self.qrlabel) + par_frame = FCFrame() + self.layout.addWidget(par_frame) + # ## Grid Layout - grid_lay = FCGridLayout(v_spacing=5, h_spacing=3) - self.layout.addLayout(grid_lay) + param_grid = FCGridLayout(v_spacing=5, h_spacing=3) + par_frame.setLayout(param_grid) # VERSION # self.version_label = FCLabel('%s:' % _("Version")) @@ -43,8 +48,8 @@ class Tools2QRCodePrefGroupUI(OptionsGroupUI): self.version_entry.set_range(1, 40) self.version_entry.setWrapping(True) - grid_lay.addWidget(self.version_label, 1, 0) - grid_lay.addWidget(self.version_entry, 1, 1) + param_grid.addWidget(self.version_label, 0, 0) + param_grid.addWidget(self.version_entry, 0, 1) # ERROR CORRECTION # self.error_label = FCLabel('%s:' % _("Error correction")) @@ -66,8 +71,8 @@ class Tools2QRCodePrefGroupUI(OptionsGroupUI): "Q = maximum 25%% errors can be corrected\n" "H = maximum 30%% errors can be corrected.") ) - grid_lay.addWidget(self.error_label, 2, 0) - grid_lay.addWidget(self.error_radio, 2, 1) + param_grid.addWidget(self.error_label, 2, 0) + param_grid.addWidget(self.error_radio, 2, 1) # BOX SIZE # self.bsize_label = FCLabel('%s:' % _("Box Size")) @@ -79,8 +84,8 @@ class Tools2QRCodePrefGroupUI(OptionsGroupUI): self.bsize_entry.set_range(1, 9999) self.bsize_entry.setWrapping(True) - grid_lay.addWidget(self.bsize_label, 3, 0) - grid_lay.addWidget(self.bsize_entry, 3, 1) + param_grid.addWidget(self.bsize_label, 4, 0) + param_grid.addWidget(self.bsize_entry, 4, 1) # BORDER SIZE # self.border_size_label = FCLabel('%s:' % _("Border Size")) @@ -92,8 +97,8 @@ class Tools2QRCodePrefGroupUI(OptionsGroupUI): self.border_size_entry.set_range(1, 9999) self.border_size_entry.setWrapping(True) - grid_lay.addWidget(self.border_size_label, 4, 0) - grid_lay.addWidget(self.border_size_entry, 4, 1) + param_grid.addWidget(self.border_size_label, 6, 0) + param_grid.addWidget(self.border_size_entry, 6, 1) # Text box self.text_label = FCLabel('%s:' % _("QRCode Data")) @@ -104,8 +109,8 @@ class Tools2QRCodePrefGroupUI(OptionsGroupUI): self.text_data.setPlaceholderText( _("Add here the text to be included in the QRCode...") ) - grid_lay.addWidget(self.text_label, 5, 0) - grid_lay.addWidget(self.text_data, 6, 0, 1, 2) + param_grid.addWidget(self.text_label, 8, 0) + param_grid.addWidget(self.text_data, 10, 0, 1, 2) # POLARITY CHOICE # self.pol_label = FCLabel('%s:' % _("Polarity")) @@ -122,8 +127,8 @@ class Tools2QRCodePrefGroupUI(OptionsGroupUI): "be added as positive. If it is added to a Copper Gerber\n" "file then perhaps the QRCode can be added as negative.") ) - grid_lay.addWidget(self.pol_label, 7, 0) - grid_lay.addWidget(self.pol_radio, 7, 1) + param_grid.addWidget(self.pol_label, 12, 0) + param_grid.addWidget(self.pol_radio, 12, 1) # BOUNDING BOX TYPE # self.bb_label = FCLabel('%s:' % _("Bounding Box")) @@ -137,8 +142,8 @@ class Tools2QRCodePrefGroupUI(OptionsGroupUI): _("The bounding box, meaning the empty space that surrounds\n" "the QRCode geometry, can have a rounded or a square shape.") ) - grid_lay.addWidget(self.bb_label, 8, 0) - grid_lay.addWidget(self.bb_radio, 8, 1) + param_grid.addWidget(self.bb_label, 14, 0) + param_grid.addWidget(self.bb_radio, 14, 1) # FILL COLOR # self.fill_color_label = FCLabel('%s:' % _('Fill Color')) @@ -147,8 +152,8 @@ class Tools2QRCodePrefGroupUI(OptionsGroupUI): ) self.fill_color_entry = FCColorEntry() - grid_lay.addWidget(self.fill_color_label, 9, 0) - grid_lay.addWidget(self.fill_color_entry, 9, 1) + param_grid.addWidget(self.fill_color_label, 16, 0) + param_grid.addWidget(self.fill_color_entry, 16, 1) # BACK COLOR # self.back_color_label = FCLabel('%s:' % _('Back Color')) @@ -157,8 +162,8 @@ class Tools2QRCodePrefGroupUI(OptionsGroupUI): ) self.back_color_entry = FCColorEntry() - grid_lay.addWidget(self.back_color_label, 10, 0) - grid_lay.addWidget(self.back_color_entry, 10, 1) + param_grid.addWidget(self.back_color_label, 18, 0) + param_grid.addWidget(self.back_color_entry, 18, 1) # Selection Limit self.sel_limit_label = FCLabel('%s:' % _("Selection limit")) @@ -172,8 +177,8 @@ class Tools2QRCodePrefGroupUI(OptionsGroupUI): self.sel_limit_entry = FCSpinner() self.sel_limit_entry.set_range(0, 9999) - grid_lay.addWidget(self.sel_limit_label, 11, 0) - grid_lay.addWidget(self.sel_limit_entry, 11, 1) + param_grid.addWidget(self.sel_limit_label, 20, 0) + param_grid.addWidget(self.sel_limit_entry, 20, 1) # self.layout.addStretch() # QRCode Tool diff --git a/appObjects/AppObject.py b/appObjects/AppObject.py index 0ca8f739..efb3d76d 100644 --- a/appObjects/AppObject.py +++ b/appObjects/AppObject.py @@ -455,7 +455,7 @@ class AppObject(QtCore.QObject): } new_obj.tools[1]['data']['name'] = outname - + new_obj.solid_geometry = [] new_obj.source_file = '' self.new_object('geometry', outname, initialize, plot=False) diff --git a/appPlugins/ToolCutOut.py b/appPlugins/ToolCutOut.py index da1402f0..b187b82d 100644 --- a/appPlugins/ToolCutOut.py +++ b/appPlugins/ToolCutOut.py @@ -1512,8 +1512,11 @@ class CutOut(AppTool): int_list = [] for b_geo in buff_man_geo.geoms: int_list += b_geo.interiors - else: + elif isinstance(buff_man_geo, Polygon): int_list = buff_man_geo.interiors + else: + self.app.log.debug("Not supported geometry at the moment: %s" % type(buff_man_geo)) + return self.mb_manual_solid_geo = self.flatten(int_list) self.cutting_gapsize = self.ui.gapsize.get_value() @@ -1547,7 +1550,10 @@ class CutOut(AppTool): if self.ui.big_cursor_cb.get_value(): self.old_cursor_type = self.app.defaults["global_cursor_type"] self.app.on_cursor_type(val="big") + self.app.defaults['global_selection_shape'] = False + # disable the notebook until finished + self.app.ui.notebook.setDisabled(True) def on_manual_cutout(self, click_pos): @@ -1833,6 +1839,7 @@ class CutOut(AppTool): self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]}) + self.app.ui.notebook.setDisabled(False) self.app.inform.emit('[success] %s' % _("Finished manual adding of gaps.")) def on_mouse_move(self, event): @@ -1903,32 +1910,24 @@ class CutOut(AppTool): angle = 0 return angle + r_man_geo = man_geo.geoms if isinstance(man_geo, (MultiPolygon, MultiLineString)) else man_geo try: rot_angle = 0 - for geo_el in man_geo: + for geo_el in r_man_geo: if isinstance(geo_el, Polygon): work_geo = geo_el.exterior - if cut_geo.intersects(work_geo): - rot_angle = get_angle(geo=work_geo) - else: - rot_angle = 0 + rot_angle = get_angle(geo=work_geo) if cut_geo.intersects(work_geo) else 0 else: - rot_angle = 0 - if cut_geo.intersects(geo_el): - rot_angle = get_angle(geo=geo_el) + rot_angle = get_angle(geo=geo_el) if cut_geo.intersects(geo_el) else 0 + if rot_angle != 0: break except TypeError: - if isinstance(man_geo, Polygon): - work_geo = man_geo.exterior - if cut_geo.intersects(work_geo): - rot_angle = get_angle(geo=work_geo) - else: - rot_angle = 0 + if isinstance(r_man_geo, Polygon): + work_geo = r_man_geo.exterior + rot_angle = get_angle(geo=work_geo) if cut_geo.intersects(work_geo) else 0 else: - rot_angle = 0 - if cut_geo.intersects(man_geo): - rot_angle = get_angle(geo=man_geo) + rot_angle = get_angle(geo=r_man_geo) if cut_geo.intersects(r_man_geo) else 0 # rotate only if there is an angle to rotate to if rot_angle != 0: @@ -2008,6 +2007,10 @@ class CutOut(AppTool): self.app.geo_editor.tool_shape.clear(update=True) self.app.geo_editor.tool_shape.enabled = False + # restore the notebook state + self.app.ui.notebook.setDisabled(False) + self.app.inform.emit("[WARNING_NOTCL] %s" % _("Cancelled.")) + # Grid toggle if key == QtCore.Qt.Key.Key_G or key == 'G': self.app.ui.grid_snap_btn.trigger() diff --git a/appPlugins/ToolNCC.py b/appPlugins/ToolNCC.py index ad26c65c..1f3c4ef9 100644 --- a/appPlugins/ToolNCC.py +++ b/appPlugins/ToolNCC.py @@ -366,51 +366,6 @@ class NonCopperClear(AppTool, Gerber): if option.find('tools_') == 0: self.default_data[option] = self.app.options[option] - # self.default_data = { - # "name": '_ncc', - # "plot": self.app.defaults["geometry_plot"], - # "cutz": float(self.app.defaults["geometry_cutz"]), - # "vtipdia": float(self.app.defaults["tools_mill_vtipdia"]), - # "vtipangle": float(self.app.defaults["tools_mill_vtipangle"]), - # "travelz": self.app.defaults["geometry_travelz"], - # "feedrate": self.app.defaults["geometry_feedrate"], - # "feedrate_z": self.app.defaults["geometry_feedrate_z"], - # "feedrate_rapid": self.app.defaults["geometry_feedrate_rapid"], - # "dwell": self.app.defaults["geometry_dwell"], - # "dwelltime": self.app.defaults["geometry_dwelltime"], - # "multidepth": self.app.defaults["geometry_multidepth"], - # "ppname_g": self.app.defaults["geometry_ppname_g"], - # "depthperpass": self.app.defaults["geometry_depthperpass"], - # "extracut": self.app.defaults["geometry_extracut"], - # "extracut_length": self.app.defaults["geometry_extracut_length"], - # "toolchange": self.app.defaults["geometry_toolchange"], - # "toolchangez": self.app.defaults["geometry_toolchangez"], - # "endz": self.app.defaults["geometry_endz"], - # "endxy": self.app.defaults["geometry_endxy"], - # - # "spindlespeed": self.app.defaults["geometry_spindlespeed"], - # "toolchangexy": self.app.defaults["geometry_toolchangexy"], - # "startz": self.app.defaults["geometry_startz"], - # - # "area_exclusion": self.app.defaults["geometry_area_exclusion"], - # "area_shape": self.app.defaults["geometry_area_shape"], - # "area_strategy": self.app.defaults["geometry_area_strategy"], - # "area_overz": float(self.app.defaults["geometry_area_overz"]), - # "optimization_type": self.app.defaults["geometry_optimization_type"], - # - # "tools_ncc_operation": self.app.defaults["tools_ncc_operation"], - # "tools_ncc_margin": self.app.defaults["tools_ncc_margin"], - # "tools_ncc_method": self.app.defaults["tools_ncc_method"], - # "tools_ncc_connect": self.app.defaults["tools_ncc_connect"], - # "tools_ncc_contour": self.app.defaults["tools_ncc_contour"], - # "tools_ncc_overlap": self.app.defaults["tools_ncc_overlap"], - # "tools_ncc_rest": self.app.defaults["tools_ncc_rest"], - # "tools_ncc_ref": self.app.defaults["tools_ncc_ref"], - # "tools_ncc_offset_choice": self.app.defaults["tools_ncc_offset_choice"], - # "tools_ncc_offset_value": self.app.defaults["tools_ncc_offset_value"], - # "tools_ncc_milling_type": self.app.defaults["tools_ncc_milling_type"], - # "tools_ncc_check_valid": self.app.defaults["tools_ncc_check_valid"], - # } try: dias = [float(self.app.defaults["tools_ncc_tools"])] @@ -1643,6 +1598,8 @@ class NonCopperClear(AppTool, Gerber): # disconnect flags self.area_sel_disconnect_flag = True + # disable the "notebook UI" until finished + self.app.ui.notebook.setDisabled(True) elif self.select_method == 2: # Reference Object self.bound_obj_name = self.ui.reference_combo.currentText() @@ -1776,6 +1733,8 @@ class NonCopperClear(AppTool, Gerber): self.clear_copper(ncc_obj=self.ncc_obj, sel_obj=self.bound_obj, ncctooldia=self.ncc_dia_list, isotooldia=self.iso_dia_list, outname=self.o_name) + self.app.ui.notebook.setDisabled(False) + # called on mouse move def on_mouse_move(self, event): shape_type = self.ui.area_shape_radio.get_value() @@ -1908,6 +1867,9 @@ class NonCopperClear(AppTool, Gerber): self.app.on_mouse_move_over_plot) self.app.mr = self.app.plotcanvas.graph_event_connect('mouse_release', self.app.on_mouse_click_release_over_plot) + + self.app.ui.notebook.setDisabled(False) + self.points = [] self.poly_drawn = False diff --git a/appPlugins/ToolPaint.py b/appPlugins/ToolPaint.py index efec0a09..2362deeb 100644 --- a/appPlugins/ToolPaint.py +++ b/appPlugins/ToolPaint.py @@ -16,7 +16,7 @@ from camlib import Geometry, FlatCAMRTreeStorage, grace from appGUI.GUIElements import FCTable, FCDoubleSpinner, FCCheckBox, FCInputDoubleSpinner, RadioSet, \ FCButton, FCComboBox, FCLabel, FCComboBox2, VerticalScrollArea, FCGridLayout, FCFrame -from shapely.geometry import base, Polygon, MultiPolygon, LinearRing, Point +from shapely.geometry import base, Polygon, MultiPolygon, LinearRing, Point, MultiLineString, LineString from shapely.ops import unary_union, linemerge from matplotlib.backend_bases import KeyEvent as mpl_key_event @@ -1223,6 +1223,8 @@ class ToolPaint(AppTool, Gerber): # disconnect flags self.area_sel_disconnect_flag = True + # disable the "notebook" until the process is finished + self.app.ui.notebook.setDisabled(True) elif self.select_method == 3: # _("Reference Object") self.bound_obj_name = self.reference_combo.currentText() @@ -1437,6 +1439,7 @@ class ToolPaint(AppTool, Gerber): # disconnect flags self.area_sel_disconnect_flag = False + self.app.ui.notebook.setDisabled(False) if len(self.sel_rect) == 0: return @@ -1495,7 +1498,7 @@ class ToolPaint(AppTool, Gerber): # "%.4f    " % (self.app.dx, self.app.dy)) self.app.ui.update_location_labels(self.app.dx, self.app.dy, curr_pos[0], curr_pos[1]) - units = self.app.app_units.lower() + # units = self.app.app_units.lower() # self.app.plotcanvas.text_hud.text = \ # 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\n\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format( # self.app.dx, units, self.app.dy, units, curr_pos[0], units, curr_pos[1], units) @@ -1591,6 +1594,8 @@ class ToolPaint(AppTool, Gerber): self.app.on_mouse_click_release_over_plot) self.app.mp = self.app.plotcanvas.graph_event_connect('mouse_press', self.app.on_mouse_click_over_plot) + self.app.ui.notebook.setDisabled(False) + self.points = [] self.poly_drawn = False self.poly_dict.clear() @@ -1767,30 +1772,6 @@ class ToolPaint(AppTool, Gerber): cpoly.insert(lin) except TypeError: cpoly.insert(lines_union) - # # determine the Gerber follow line - # for apid, apval in obj.tools.items(): - # for geo_el in apval['geometry']: - # if 'solid' in geo_el: - # if Point(inside_pt).within(geo_el['solid']): - # if not isinstance(geo_el['follow'], Point): - # line = geo_el['follow'] - # - # if apval['type'] == 'C': - # aperture_size = apval['size'] - # else: - # if apval['width'] > apval['height']: - # aperture_size = apval['height'] - # else: - # aperture_size = apval['width'] - # - # if line: - # cpoly = self.fill_with_lines(line, aperture_size, - # tooldia=tooldiameter, - # steps_per_circle=self.circle_steps, - # overlap=over, - # contour=cont, - # connect=conn, - # prog_plot=prog_plot) except grace: return "fail" except Exception as ee: @@ -1853,7 +1834,8 @@ class ToolPaint(AppTool, Gerber): :param tools_storage: whether to use the current tools_storage self.paints_tools or a different one. Usage of the different one is related to when this function is called from a TcL command. - :param plot: + :param plot: if the geometry is plotted; bool + :param rest: if rest machining apply here; bool :param run_threaded: :return: None """ @@ -2311,9 +2293,9 @@ class ToolPaint(AppTool, Gerber): def job_thread(app_obj): try: if use_rest_strategy: - ret = app_obj.app_obj.new_object("geometry", name, job_rest_clear, plot=plot) + ret = app_obj.app_obj.new_object("geometry", name, job_rest_clear, plot=plot, autoselected=False) else: - ret = app_obj.app_obj.new_object("geometry", name, job_normal_clear, plot=plot) + ret = app_obj.app_obj.new_object("geometry", name, job_normal_clear, plot=plot, autoselected=False) except grace: proc.done() return @@ -2534,10 +2516,10 @@ class ToolPaint(AppTool, Gerber): # ## If iterable, expand recursively. try: - for geo in geometry: + multigeo = geometry.geoms if isinstance(geometry, (MultiPolygon, MultiLineString)) else geometry + for geo in multigeo: if geo and not geo.is_empty and geo.is_valid: recurse(geometry=geo, reset=False) - # ## Not iterable, do the actual indexing and add. except TypeError: if isinstance(geometry, LinearRing): @@ -2549,7 +2531,8 @@ class ToolPaint(AppTool, Gerber): return self.flat_geometry # this is where heavy lifting is done and creating the geometry to be painted - target_geo = MultiPolygon(obj.solid_geometry) + target_geo = unary_union(obj.solid_geometry) + if obj.kind == 'gerber': # I don't do anything here, like buffering when the Gerber is loaded without buffering????!!!! if self.app.defaults["gerber_buffering"] == 'no': @@ -2567,16 +2550,45 @@ class ToolPaint(AppTool, Gerber): self.app.inform.emit('%s %s' % (_("Paint Tool."), _("Painting area task started."))) geo_to_paint = target_geo.intersection(sel_obj) + painted_area = recurse(geo_to_paint, reset=True) + try: + painted_area = linemerge(painted_area) + except Exception: + pass + + if isinstance(painted_area, (MultiPolygon, MultiLineString)): + painted_area = painted_area.geoms + + p_geo_list = [] + try: + for paint_g_elem in painted_area: + if isinstance(paint_g_elem, Polygon): + p_geo_list.append(paint_g_elem) + elif isinstance(paint_g_elem, (LinearRing, LineString)): + if paint_g_elem.is_closed: + p_geo_list.append(Polygon(paint_g_elem.coords)) + else: + coords = list(paint_g_elem.coords) + coords.append(coords[0]) + p_geo_list.append(Polygon(coords)) + except TypeError: + if isinstance(painted_area, Polygon): + p_geo_list.append(painted_area) + elif isinstance(painted_area, (LinearRing, LineString)): + if painted_area.is_closed: + p_geo_list.append(Polygon(painted_area.coords)) + else: + coords = list(painted_area.coords) + coords.append(coords[0]) + p_geo_list.append(Polygon(coords)) # No polygon? - if not geo_to_paint or geo_to_paint.is_empty: - self.app.log.warning('No polygon found.') + if not p_geo_list: + self.app.log.warning('ToolPaint.paint_poly_Area(). No geometry or the found geometry could not be painted.') self.app.inform.emit('[WARNING] %s' % _('No polygon found.')) return - painted_area = recurse(geo_to_paint, reset=True) - - self.paint_geo(obj, painted_area, tooldia=tooldia, order=order, method=method, outname=outname, + self.paint_geo(obj, p_geo_list, tooldia=tooldia, order=order, method=method, outname=outname, tools_storage=tools_storage, plot=plot, run_threaded=run_threaded) def paint_poly_ref(self, obj, sel_obj, tooldia=None, order=None, method=None, outname=None, @@ -2971,7 +2983,7 @@ class PaintUI: self.obj_combo = FCComboBox() self.obj_combo.setModel(self.app.collection) self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex())) - self.obj_combo.is_last = True + self.obj_combo.is_last = False obj_grid.addWidget(self.obj_combo, 2, 0, 1, 2) diff --git a/camlib.py b/camlib.py index 1b1234a4..fea4c83f 100644 --- a/camlib.py +++ b/camlib.py @@ -1613,15 +1613,16 @@ class Geometry(object): # geom_elems.append(path) # geom_elems.insert(path) # path can be a collection of paths. + path_geometry = path.geoms if isinstance(path, MultiLineString) else path try: - for p in path: + for p in path_geometry: geom_elems.insert(p) if prog_plot: self.plot_temp_shapes(p) except TypeError: - geom_elems.insert(path) + geom_elems.insert(path_geometry) if prog_plot: - self.plot_temp_shapes(path) + self.plot_temp_shapes(path_geometry) if prog_plot: self.temp_shapes.redraw() @@ -1730,15 +1731,16 @@ class Geometry(object): line = LineString([(left, y), (right, y)]) line = line.intersection(margin_poly) + lines_geometry = line.geoms if isinstance(line, MultiLineString) else line try: - for ll in line: + for ll in lines_geometry: lines_trimmed.append(ll) if prog_plot: self.plot_temp_shapes(ll) except TypeError: - lines_trimmed.append(line) + lines_trimmed.append(lines_geometry) if prog_plot: - self.plot_temp_shapes(line) + self.plot_temp_shapes(lines_geometry) except Exception as e: log.error('camlib.Geometry.clear_polygon3() Processing poly --> %s' % str(e)) return None @@ -1767,15 +1769,16 @@ class Geometry(object): line = LineString([(x, top), (x, bot)]) line = line.intersection(margin_poly) + lines_geometry = line.geoms if isinstance(line, MultiLineString) else line try: - for ll in line: + for ll in lines_geometry: lines_trimmed.append(ll) if prog_plot: self.plot_temp_shapes(ll) except TypeError: - lines_trimmed.append(line) + lines_trimmed.append(lines_geometry) if prog_plot: - self.plot_temp_shapes(line) + self.plot_temp_shapes(lines_geometry) except Exception as e: log.error('camlib.Geometry.clear_polygon3() Processing poly --> %s' % str(e)) return None @@ -1909,28 +1912,30 @@ class Geometry(object): log.error('camlib.Geometry.fill_with_lines() Processing poly --> %s' % str(e)) return None + lines_geometry = new_line.geoms if isinstance(new_line, MultiLineString) else new_line try: - for ll in new_line: + for ll in lines_geometry: lines_trimmed.append(ll) if prog_plot: self.plot_temp_shapes(ll) except TypeError: - lines_trimmed.append(new_line) + lines_trimmed.append(lines_geometry) if prog_plot: - self.plot_temp_shapes(new_line) + self.plot_temp_shapes(lines_geometry) new_line = line.parallel_offset(distance=delta, side='right', resolution=int(steps_per_circle)) new_line = new_line.intersection(margin_poly) + lines_geometry = new_line.geoms if isinstance(new_line, MultiLineString) else new_line try: - for ll in new_line: + for ll in lines_geometry: lines_trimmed.append(ll) if prog_plot: self.plot_temp_shapes(ll) except TypeError: - lines_trimmed.append(new_line) + lines_trimmed.append(lines_geometry) if prog_plot: - self.plot_temp_shapes(new_line) + self.plot_temp_shapes(lines_geometry) if prog_plot: self.temp_shapes.redraw() @@ -1938,15 +1943,16 @@ class Geometry(object): lines_trimmed = unary_union(lines_trimmed) # Add lines to storage + lines_geometry = lines_trimmed.geoms if isinstance(lines_trimmed, MultiLineString) else lines_trimmed try: - for line in lines_trimmed: + for line in lines_geometry: if isinstance(line, LineString) or isinstance(line, LinearRing): geoms.insert(line) else: log.debug("camlib.Geometry.fill_with_lines(). Not a line: %s" % str(type(line))) except TypeError: # in case lines_trimmed are not iterable (Linestring, LinearRing) - geoms.insert(lines_trimmed) + geoms.insert(lines_geometry) # Add margin (contour) to storage if contour: