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: