diff --git a/CHANGELOG.md b/CHANGELOG.md index e8c13743..068a8744 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ CHANGELOG for FlatCAM beta - in Film Plugin added new parameters and improvements: now the negative film can have a box that is convex and it is no longer limited to square shapes. Also, if the box object has only one geometric element (an outline) then that one will be the final shape of the negative - in Gerber Editor fixed not being able to delete an aperture - in Gerber Editor fixed the edge case where the user selects apertures in the Tools Table and then uses the Poligonize Tool and not by selecting shapes on canvas +- in Cutout Plugin remade the UI and fixed different issues 21.09.2021 diff --git a/appGUI/preferences/PreferencesUIManager.py b/appGUI/preferences/PreferencesUIManager.py index 76801c57..83c93a1e 100644 --- a/appGUI/preferences/PreferencesUIManager.py +++ b/appGUI/preferences/PreferencesUIManager.py @@ -439,7 +439,7 @@ class PreferencesUIManager: "tools_cutout_convexshape": self.ui.plugin_pref_form.tools_cutout_group.convex_box, "tools_cutout_big_cursor": self.ui.plugin_pref_form.tools_cutout_group.big_cursor_cb, - "tools_cutout_gap_type": self.ui.plugin_pref_form.tools_cutout_group.gaptype_radio, + "tools_cutout_gap_type": self.ui.plugin_pref_form.tools_cutout_group.gaptype_combo, "tools_cutout_gap_depth": self.ui.plugin_pref_form.tools_cutout_group.thin_depth_entry, "tools_cutout_mb_dia": self.ui.plugin_pref_form.tools_cutout_group.mb_dia_entry, "tools_cutout_mb_spacing": self.ui.plugin_pref_form.tools_cutout_group.mb_spacing_entry, diff --git a/appGUI/preferences/tools/ToolsCutoutPrefGroupUI.py b/appGUI/preferences/tools/ToolsCutoutPrefGroupUI.py index 7949a205..b5eca6fb 100644 --- a/appGUI/preferences/tools/ToolsCutoutPrefGroupUI.py +++ b/appGUI/preferences/tools/ToolsCutoutPrefGroupUI.py @@ -1,7 +1,7 @@ from PyQt6 import QtWidgets from appGUI.GUIElements import FCDoubleSpinner, FCCheckBox, RadioSet, FCComboBox, FCLabel, OptionalInputSection, \ - FCGridLayout + FCGridLayout, FCFrame, FCComboBox2 from appGUI.preferences.OptionsGroupUI import OptionsGroupUI import gettext @@ -23,7 +23,7 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI): self.defaults = defaults # ## Board cutout - self.board_cutout_label = FCLabel("%s:" % _("Parameters")) + self.board_cutout_label = FCLabel('%s' % _("Parameters")) self.board_cutout_label.setToolTip( _("Create toolpaths to cut around\n" "the PCB and separate it from\n" @@ -31,10 +31,17 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI): ) self.layout.addWidget(self.board_cutout_label) - grid0 = FCGridLayout(v_spacing=5, h_spacing=3) - self.layout.addLayout(grid0) + # ############################################################################################################# + # Tool Params Frame + # ############################################################################################################# + tool_par_frame = FCFrame() + self.layout.addWidget(tool_par_frame) - tdclabel = FCLabel('%s:' % _('Tool Diameter')) + param_grid = FCGridLayout(v_spacing=5, h_spacing=3) + tool_par_frame.setLayout(param_grid) + + # Tool Diameter + tdclabel = FCLabel('%s:' % _('Tool Dia')) tdclabel.setToolTip( _("Diameter of the tool used to cutout\n" "the PCB shape out of the surrounding material.") @@ -45,8 +52,16 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI): self.cutout_tooldia_entry.set_precision(self.decimals) self.cutout_tooldia_entry.setSingleStep(0.1) - grid0.addWidget(tdclabel, 0, 0) - grid0.addWidget(self.cutout_tooldia_entry, 0, 1) + param_grid.addWidget(tdclabel, 0, 0) + param_grid.addWidget(self.cutout_tooldia_entry, 0, 1) + + # Convex box shape + self.convex_box = FCCheckBox('%s' % _("Convex Shape")) + self.convex_box.setToolTip( + _("Create a convex shape surrounding the entire PCB.\n" + "Used only if the source object type is Gerber.") + ) + param_grid.addWidget(self.convex_box, 2, 0, 1, 2) # Cut Z cutzlabel = FCLabel('%s:' % _('Cut Z')) @@ -62,8 +77,8 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI): self.cutz_entry.setSingleStep(0.1) - grid0.addWidget(cutzlabel, 1, 0) - grid0.addWidget(self.cutz_entry, 1, 1) + param_grid.addWidget(cutzlabel, 4, 0) + param_grid.addWidget(self.cutz_entry, 4, 1) # Multi-pass self.mpass_cb = FCCheckBox('%s:' % _("Multi-Depth")) @@ -83,8 +98,8 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI): self.maxdepth_entry.setToolTip(_("Depth of each pass (positive).")) - grid0.addWidget(self.mpass_cb, 2, 0) - grid0.addWidget(self.maxdepth_entry, 2, 1) + param_grid.addWidget(self.mpass_cb, 6, 0) + param_grid.addWidget(self.maxdepth_entry, 6, 1) self.ois_md = OptionalInputSection(self.mpass_cb, [self.maxdepth_entry]) @@ -101,8 +116,8 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI): {"label": _("Single"), "value": "single"}, {"label": _("Panel"), "value": "panel"}, ]) - grid0.addWidget(kindlabel, 3, 0) - grid0.addWidget(self.obj_kind_combo, 3, 1) + param_grid.addWidget(kindlabel, 8, 0) + param_grid.addWidget(self.obj_kind_combo, 8, 1) marginlabel = FCLabel('%s:' % _('Margin')) marginlabel.setToolTip( @@ -116,11 +131,23 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI): self.cutout_margin_entry.set_precision(self.decimals) self.cutout_margin_entry.setSingleStep(0.1) - grid0.addWidget(marginlabel, 4, 0) - grid0.addWidget(self.cutout_margin_entry, 4, 1) - + param_grid.addWidget(marginlabel, 10, 0) + param_grid.addWidget(self.cutout_margin_entry, 10, 1) + + self.gaps_label = FCLabel('%s' % _("Gaps")) + self.layout.addWidget(self.gaps_label) + # ############################################################################################################# + # Gaps Frame + # ############################################################################################################# + gaps_frame = FCFrame() + self.layout.addWidget(gaps_frame) + + # Grid Layout + gaps_grid = FCGridLayout(v_spacing=5, h_spacing=3) + gaps_frame.setLayout(gaps_grid) + # Gap Size - gaplabel = FCLabel('%s:' % _('Gap size')) + gaplabel = FCLabel('%s:' % _('Size')) gaplabel.setToolTip( _("The size of the bridge gaps in the cutout\n" "used to keep the board connected to\n" @@ -133,11 +160,11 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI): self.cutout_gap_entry.set_precision(self.decimals) self.cutout_gap_entry.setSingleStep(0.1) - grid0.addWidget(gaplabel, 5, 0) - grid0.addWidget(self.cutout_gap_entry, 5, 1) + gaps_grid.addWidget(gaplabel, 0, 0) + gaps_grid.addWidget(self.cutout_gap_entry, 0, 1) # Gap Type - self.gaptype_label = FCLabel('%s:' % _("Gap type")) + self.gaptype_label = FCLabel('%s:' % _("Type")) self.gaptype_label.setToolTip( _("The type of gap:\n" "- Bridge -> the cutout will be interrupted by bridges\n" @@ -145,17 +172,16 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI): "- M-Bites -> 'Mouse Bites' - same as 'bridge' but covered with drill holes") ) - self.gaptype_radio = RadioSet( - [ - {'label': _('Bridge'), 'value': 'b'}, - {'label': _('Thin'), 'value': 'bt'}, - {'label': "M-Bites", 'value': 'mb'} - ], - stretch=True - ) + self.gaptype_combo = FCComboBox2() + self.gaptype_combo.addItems([_('Bridge'), _('Thin'), _("Mouse Bytes")]) - grid0.addWidget(self.gaptype_label, 7, 0) - grid0.addWidget(self.gaptype_radio, 7, 1) + gaps_grid.addWidget(self.gaptype_label, 2, 0) + gaps_grid.addWidget(self.gaptype_combo, 2, 1) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + gaps_grid.addWidget(separator_line, 4, 0, 1, 2) # Thin gaps Depth self.thin_depth_label = FCLabel('%s:' % _("Depth")) @@ -168,8 +194,13 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI): self.thin_depth_entry.setRange(-10000.0000, 10000.0000) self.thin_depth_entry.setSingleStep(0.1) - grid0.addWidget(self.thin_depth_label, 9, 0) - grid0.addWidget(self.thin_depth_entry, 9, 1) + gaps_grid.addWidget(self.thin_depth_label, 6, 0) + gaps_grid.addWidget(self.thin_depth_entry, 6, 1) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + gaps_grid.addWidget(separator_line, 8, 0, 1, 2) # Mouse Bites Tool Diameter self.mb_dia_label = FCLabel('%s:' % _("Tool Diameter")) @@ -180,8 +211,8 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI): self.mb_dia_entry.set_precision(self.decimals) self.mb_dia_entry.setRange(0, 100.0000) - grid0.addWidget(self.mb_dia_label, 11, 0) - grid0.addWidget(self.mb_dia_entry, 11, 1) + gaps_grid.addWidget(self.mb_dia_label, 10, 0) + gaps_grid.addWidget(self.mb_dia_entry, 10, 1) # Mouse Bites Holes Spacing self.mb_spacing_label = FCLabel('%s:' % _("Spacing")) @@ -192,9 +223,14 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI): self.mb_spacing_entry.set_precision(self.decimals) self.mb_spacing_entry.setRange(0, 100.0000) - grid0.addWidget(self.mb_spacing_label, 13, 0) - grid0.addWidget(self.mb_spacing_entry, 13, 1) - + gaps_grid.addWidget(self.mb_spacing_label, 12, 0) + gaps_grid.addWidget(self.mb_spacing_entry, 12, 1) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + gaps_grid.addWidget(separator_line, 14, 0, 1, 2) + gaps_label = FCLabel('%s:' % _('Gaps')) gaps_label.setToolTip( _("Number of gaps used for the cutout.\n" @@ -210,28 +246,34 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI): ) self.gaps_combo = FCComboBox() - grid0.addWidget(gaps_label, 15, 0) - grid0.addWidget(self.gaps_combo, 15, 1) + gaps_grid.addWidget(gaps_label, 16, 0) + gaps_grid.addWidget(self.gaps_combo, 16, 1) gaps_items = ['None', 'LR', 'TB', '4', '2LR', '2TB', '8'] for it in gaps_items: self.gaps_combo.addItem(it) # self.gaps_combo.setStyleSheet('background-color: rgb(255,255,255)') - # Surrounding convex box shape - self.convex_box = FCCheckBox('%s' % _("Convex Shape")) - self.convex_box.setToolTip( - _("Create a convex shape surrounding the entire PCB.\n" - "Used only if the source object type is Gerber.") - ) - grid0.addWidget(self.convex_box, 17, 0, 1, 2) - self.big_cursor_cb = FCCheckBox('%s' % _("Big cursor")) self.big_cursor_cb.setToolTip( _("Use a big cursor when adding manual gaps.")) - grid0.addWidget(self.big_cursor_cb, 19, 0, 1, 2) + gaps_grid.addWidget(self.big_cursor_cb, 18, 0, 1, 2) + + # Cut by Drilling Title + self.title_drillcut_label = FCLabel('%s' % _('Cut by Drilling')) + self.title_drillcut_label.setToolTip(_("Create a series of drill holes following a geometry line.")) + self.layout.addWidget(self.title_drillcut_label) + + # ############################################################################################################# + # Cut by Drilling Frame + # ############################################################################################################# + self.drill_cut_frame = FCFrame() + self.layout.addWidget(self.drill_cut_frame) + + # Grid Layout + drill_cut_grid = FCGridLayout(v_spacing=5, h_spacing=3) + self.drill_cut_frame.setLayout(drill_cut_grid) - # Drill Cut # Drill Tool Diameter self.drill_dia_entry = FCDoubleSpinner() self.drill_dia_entry.set_precision(self.decimals) @@ -242,8 +284,8 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI): _("Diameter of the tool used to cutout\n" "the PCB by drilling.") ) - grid0.addWidget(self.drill_dia_label, 21, 0) - grid0.addWidget(self.drill_dia_entry, 21, 1) + drill_cut_grid.addWidget(self.drill_dia_label, 0, 0) + drill_cut_grid.addWidget(self.drill_dia_entry, 0, 1) # Drill Tool Pitch self.drill_pitch_entry = FCDoubleSpinner() @@ -255,8 +297,8 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI): _("Distance between the center of\n" "two neighboring drill holes.") ) - grid0.addWidget(self.drill_pitch_label, 23, 0) - grid0.addWidget(self.drill_pitch_entry, 23, 1) + drill_cut_grid.addWidget(self.drill_pitch_label, 2, 0) + drill_cut_grid.addWidget(self.drill_pitch_entry, 2, 1) # Drill Tool Margin self.drill_margin_entry = FCDoubleSpinner() @@ -269,7 +311,10 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI): "will make the cutout of the PCB further from\n" "the actual PCB border") ) - grid0.addWidget(self.drill_margin_label, 25, 0) - grid0.addWidget(self.drill_margin_entry, 25, 1) + drill_cut_grid.addWidget(self.drill_margin_label, 4, 0) + drill_cut_grid.addWidget(self.drill_margin_entry, 4, 1) - self.layout.addStretch() + FCGridLayout.set_common_column_size([param_grid, drill_cut_grid, gaps_grid], 0) + + + # self.layout.addStretch() diff --git a/appGUI/preferences/tools/ToolsFilmPrefGroupUI.py b/appGUI/preferences/tools/ToolsFilmPrefGroupUI.py index 2347c10a..f76b5a85 100644 --- a/appGUI/preferences/tools/ToolsFilmPrefGroupUI.py +++ b/appGUI/preferences/tools/ToolsFilmPrefGroupUI.py @@ -35,8 +35,8 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): adj_frame = FCFrame() self.layout.addWidget(adj_frame) - grid0 = FCGridLayout(v_spacing=5, h_spacing=3) - adj_frame.setLayout(grid0) + adj_grid = FCGridLayout(v_spacing=5, h_spacing=3) + adj_frame.setLayout(adj_grid) # Scale Geometry self.film_scale_cb = FCCheckBox('%s' % _("Scale")) @@ -49,11 +49,11 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): QCheckBox {font-weight: bold; color: black} """ ) - grid0.addWidget(self.film_scale_cb, 2, 0, 1, 2) + adj_grid.addWidget(self.film_scale_cb, 2, 0, 1, 2) # SCALE FRAME scale_frame = FCFrame() - grid0.addWidget(scale_frame, 4, 0, 1, 2) + adj_grid.addWidget(scale_frame, 4, 0, 1, 2) grid_scale = FCGridLayout(v_spacing=5, h_spacing=3) scale_frame.setLayout(grid_scale) @@ -102,11 +102,11 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): QCheckBox {font-weight: bold; color: black} """ ) - grid0.addWidget(self.film_skew_cb, 6, 0, 1, 2) + adj_grid.addWidget(self.film_skew_cb, 6, 0, 1, 2) # SKEW FRAME skew_frame = FCFrame() - grid0.addWidget(skew_frame, 8, 0, 1, 2) + adj_grid.addWidget(skew_frame, 8, 0, 1, 2) grid_skew = FCGridLayout(v_spacing=5, h_spacing=3) skew_frame.setLayout(grid_skew) @@ -152,7 +152,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): QCheckBox {font-weight: bold; color: black} """ ) - grid0.addWidget(self.film_mirror_cb, 10, 0, 1, 2) + adj_grid.addWidget(self.film_mirror_cb, 10, 0, 1, 2) self.film_mirror_axis = RadioSet([{'label': _('X'), 'value': 'x'}, {'label': _('Y'), 'value': 'y'}, @@ -160,8 +160,8 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): stretch=False) self.film_mirror_axis_label = FCLabel('%s:' % _("Mirror Axis")) - grid0.addWidget(self.film_mirror_axis_label, 12, 0) - grid0.addWidget(self.film_mirror_axis, 12, 1) + adj_grid.addWidget(self.film_mirror_axis_label, 12, 0) + adj_grid.addWidget(self.film_mirror_axis, 12, 1) # separator_line3 = QtWidgets.QFrame() # separator_line3.setFrameShape(QtWidgets.QFrame.Shape.HLine) @@ -367,7 +367,9 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): grid_par.addWidget(self.png_dpi_label, 18, 0) grid_par.addWidget(self.png_dpi_spinner, 18, 1) - self.layout.addStretch(1) + # self.layout.addStretch(1) + + FCGridLayout.set_common_column_size([adj_grid, grid_par, grid_skew, grid_scale], 0) # Film Tool self.film_color_entry.editingFinished.connect(self.on_film_color_entry) diff --git a/appObjects/FlatCAMGeometry.py b/appObjects/FlatCAMGeometry.py index 413fe32f..b864c5f7 100644 --- a/appObjects/FlatCAMGeometry.py +++ b/appObjects/FlatCAMGeometry.py @@ -1365,9 +1365,12 @@ class GeometryObject(FlatCAMObj, Geometry): visible = visible if visible else self.options['plot'] try: - for sub_el in element: - self.plot_element(sub_el, color=color) - + if isinstance(element, (MultiPolygon, MultiLineString)): + for sub_el in element.geoms: + self.plot_element(sub_el, color=color) + else: + for sub_el in element: + self.plot_element(sub_el, color=color) except TypeError: # Element is not iterable... # if self.app.is_legacy is False: self.add_shape(shape=element, color=color, visible=visible, layer=0) diff --git a/appPlugins/ToolCutOut.py b/appPlugins/ToolCutOut.py index a27c3c40..55e9bb28 100644 --- a/appPlugins/ToolCutOut.py +++ b/appPlugins/ToolCutOut.py @@ -8,7 +8,7 @@ from PyQt6 import QtWidgets, QtGui, QtCore from appTool import AppTool from appGUI.GUIElements import FCDoubleSpinner, FCCheckBox, RadioSet, FCComboBox, OptionalInputSection, FCButton, \ - FCLabel, VerticalScrollArea, FCGridLayout, FCFrame + FCLabel, VerticalScrollArea, FCGridLayout, FCFrame, FCComboBox2 from shapely.geometry import box, MultiPolygon, Polygon, LineString, LinearRing, MultiLineString, Point from shapely.ops import unary_union, linemerge @@ -244,8 +244,6 @@ class CutOut(AppTool): else: self.on_type_obj_changed(val='geo') - self.ui.dia.set_value(float(self.app.defaults["tools_cutout_tooldia"])) - # init the working variables self.default_data.clear() kind = 'geometry' @@ -257,62 +255,19 @@ class CutOut(AppTool): if option.find('tools_') == 0: self.default_data[option] = self.app.options[option] - # self.default_data.update({ - # "plot": True, - # - # "cutz": float(self.app.defaults["geometry_cutz"]), - # "multidepth": self.app.defaults["geometry_multidepth"], - # "depthperpass": float(self.app.defaults["geometry_depthperpass"]), - # - # "vtipdia": float(self.app.defaults["tools_mill_vtipdia"]), - # "vtipangle": float(self.app.defaults["tools_mill_vtipangle"]), - # "travelz": float(self.app.defaults["geometry_travelz"]), - # "feedrate": float(self.app.defaults["geometry_feedrate"]), - # "feedrate_z": float(self.app.defaults["geometry_feedrate_z"]), - # "feedrate_rapid": float(self.app.defaults["geometry_feedrate_rapid"]), - # "spindlespeed": self.app.defaults["geometry_spindlespeed"], - # "dwell": self.app.defaults["geometry_dwell"], - # "dwelltime": float(self.app.defaults["geometry_dwelltime"]), - # "spindledir": self.app.defaults["geometry_spindledir"], - # "ppname_g": self.app.defaults["geometry_ppname_g"], - # "extracut": self.app.defaults["geometry_extracut"], - # "extracut_length": float(self.app.defaults["geometry_extracut_length"]), - # "toolchange": self.app.defaults["geometry_toolchange"], - # "toolchangexy": self.app.defaults["geometry_toolchangexy"], - # "toolchangez": float(self.app.defaults["geometry_toolchangez"]), - # "startz": self.app.defaults["geometry_startz"], - # "endz": float(self.app.defaults["geometry_endz"]), - # "endxy": self.app.defaults["geometry_endxy"], - # "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"], - # - # # Cutout - # "tools_cutout_tooldia": self.app.defaults["tools_cutout_tooldia"], - # "tools_cutout_kind": self.app.defaults["tools_cutout_kind"], - # "tools_cutout_margin": float(self.app.defaults["tools_cutout_margin"]), - # "tools_cutout_z": float(self.app.defaults["tools_cutout_z"]), - # "tools_cutout_depthperpass": float(self.app.defaults["tools_cutout_depthperpass"]), - # "tools_cutout_mdepth": self.app.defaults["tools_cutout_mdepth"], - # "tools_cutout_gapsize": float(self.app.defaults["tools_cutout_gapsize"]), - # "tools_cutout_gaps_ff": self.app.defaults["tools_cutout_gaps_ff"], - # "tools_cutout_convexshape": self.app.defaults["tools_cutout_convexshape"], - # - # "tools_cutout_big_cursor": self.app.defaults["tools_cutout_big_cursor"], - # "tools_cutout_gap_type": self.app.defaults["tools_cutout_gap_type"], - # "tools_cutout_gap_depth": float(self.app.defaults["tools_cutout_gap_depth"]), - # "tools_cutout_mb_dia": float(self.app.defaults["tools_cutout_mb_dia"]), - # "tools_cutout_mb_spacing": float(self.app.defaults["tools_cutout_mb_spacing"]), - # - # }) + self.ui.gaptype_combo.set_value(self.app.defaults["tools_cutout_gap_type"]) + self.ui.on_gap_type_radio(self.ui.gaptype_combo.get_value()) + + # add a default tool + self.ui.dia.set_value(float(self.app.defaults["tools_cutout_tooldia"])) tool_dia = float(self.app.defaults["tools_cutout_tooldia"]) self.on_tool_add(custom_dia=tool_dia) + # set as default the automatic adding of gaps self.ui.cutout_type_radio.set_value('a') self.on_cutout_type(val='a') + # set the Cut By Drilling parameters self.ui.drill_dia_entry.set_value(float(self.app.defaults["tools_cutout_drill_dia"])) self.ui.drill_pitch_entry.set_value(float(self.app.defaults["tools_cutout_drill_pitch"])) self.ui.drill_margin_entry.set_value(float(self.app.defaults["tools_cutout_drill_margin"])) @@ -358,14 +313,16 @@ class CutOut(AppTool): tool_data = self.cut_tool_dict['data'] tool_data['tools_cutout_convexshape'] = False - tool_data['tools_cutout_gap_type'] = "b" + tool_data['tools_cutout_gap_type'] = 0 # "Basic Type of Gap" self.ui.gaptype_label.hide() - self.ui.gaptype_radio.hide() + self.ui.gaptype_combo.hide() self.ui.cutout_type_label.hide() self.ui.cutout_type_radio.hide() self.ui.cutout_type_radio.set_value('a') + self.ui.separator_line.hide() + self.ui.drill_cut_frame.hide() self.ui.title_drillcut_label.hide() self.ui.drillcut_btn.hide() @@ -396,15 +353,21 @@ class CutOut(AppTool): tool_data['tools_cutout_gap_type'] = app_defaults['tools_cutout_gap_type'] self.ui.gaptype_label.show() - self.ui.gaptype_radio.show() + self.ui.gaptype_combo.show() self.ui.cutout_type_label.show() self.ui.cutout_type_radio.show() self.ui.cutout_type_radio.set_value('a') + self.ui.separator_line.show() + self.ui.drill_cut_frame.show() self.ui.title_drillcut_label.show() self.ui.drillcut_btn.show() + if self.cut_tool_dict: + tool_data = self.cut_tool_dict['data'] + self.ui.on_gap_type_radio(tool_data['tools_cutout_gap_type']) + def update_ui(self, tool_dict): self.ui.obj_kind_combo.set_value(self.default_data["tools_cutout_kind"]) self.ui.big_cursor_cb.set_value(self.default_data['tools_cutout_big_cursor']) @@ -412,7 +375,9 @@ class CutOut(AppTool): # Entries that may be updated from database self.ui.margin.set_value(float(tool_dict["tools_cutout_margin"])) self.ui.gapsize.set_value(float(tool_dict["tools_cutout_gapsize"])) - self.ui.gaptype_radio.set_value(tool_dict["tools_cutout_gap_type"]) + self.ui.gaptype_combo.set_value(tool_dict["tools_cutout_gap_type"]) + self.on_cutout_type(self.ui.gaptype_combo.get_value()) + self.ui.thin_depth_entry.set_value(float(tool_dict["tools_cutout_gap_depth"])) self.ui.mb_dia_entry.set_value(float(tool_dict["tools_cutout_mb_dia"])) self.ui.mb_spacing_entry.set_value(float(tool_dict["tools_cutout_mb_spacing"])) @@ -430,24 +395,18 @@ class CutOut(AppTool): self.ui.ff_cutout_object_btn.show() self.ui.rect_cutout_object_btn.show() - self.ui.big_cursor_label.hide() - self.ui.big_cursor_cb.hide() self.ui.man_geo_creation_btn.hide() - self.ui.man_object_combo.hide() - self.ui.man_object_label.hide() self.ui.man_gaps_creation_btn.hide() + self.ui.man_frame.hide() else: self.ui.gaps_label.hide() self.ui.gaps.hide() self.ui.ff_cutout_object_btn.hide() self.ui.rect_cutout_object_btn.hide() - self.ui.big_cursor_label.show() - self.ui.big_cursor_cb.show() self.ui.man_geo_creation_btn.show() - self.ui.man_object_combo.show() - self.ui.man_object_label.show() self.ui.man_gaps_creation_btn.show() + self.ui.man_frame.show() def on_tool_add(self, custom_dia=None): self.blockSignals(True) @@ -543,16 +502,15 @@ class CutOut(AppTool): self.blockSignals(False) return - # FIXME when the Geometry UI milling functionality will be transferred in the Milling Tool this needs changes - new_tools_dict["tools_cutout_z"] = deepcopy(new_tools_dict["cutz"]) - new_tools_dict["tools_cutout_mdepth"] = deepcopy(new_tools_dict["multidepth"]) - new_tools_dict["tools_cutout_depthperpass"] = deepcopy(new_tools_dict["depthperpass"]) + new_tools_dict["tools_cutout_z"] = deepcopy(new_tools_dict["tools_mill_cutz"]) + new_tools_dict["tools_cutout_mdepth"] = deepcopy(new_tools_dict["tools_mill_multidepth"]) + new_tools_dict["tools_cutout_depthperpass"] = deepcopy(new_tools_dict["tools_mill_depthperpass"]) new_tdia = deepcopy(updated_tooldia) if updated_tooldia is not None else deepcopy(truncated_tooldia) self.cut_tool_dict.update({ - 'tooldia': new_tdia, - 'data': deepcopy(new_tools_dict), - 'solid_geometry': [] + 'tooldia': new_tdia, + 'data': deepcopy(new_tools_dict), + 'solid_geometry': [] }) self.update_ui(new_tools_dict) @@ -574,61 +532,11 @@ class CutOut(AppTool): if option.find('tools_') == 0: self.default_data[option] = self.app.options[option] - # self.default_data.update({ - # "plot": True, - # - # "cutz": float(self.app.defaults["geometry_cutz"]), - # "multidepth": self.app.defaults["geometry_multidepth"], - # "depthperpass": float(self.app.defaults["geometry_depthperpass"]), - # - # "vtipdia": float(self.app.defaults["tools_mill_vtipdia"]), - # "vtipangle": float(self.app.defaults["tools_mill_vtipangle"]), - # "travelz": float(self.app.defaults["geometry_travelz"]), - # "feedrate": float(self.app.defaults["geometry_feedrate"]), - # "feedrate_z": float(self.app.defaults["geometry_feedrate_z"]), - # "feedrate_rapid": float(self.app.defaults["geometry_feedrate_rapid"]), - # "spindlespeed": self.app.defaults["geometry_spindlespeed"], - # "dwell": self.app.defaults["geometry_dwell"], - # "dwelltime": float(self.app.defaults["geometry_dwelltime"]), - # "spindledir": self.app.defaults["geometry_spindledir"], - # "ppname_g": self.app.defaults["geometry_ppname_g"], - # "extracut": self.app.defaults["geometry_extracut"], - # "extracut_length": float(self.app.defaults["geometry_extracut_length"]), - # "toolchange": self.app.defaults["geometry_toolchange"], - # "toolchangexy": self.app.defaults["geometry_toolchangexy"], - # "toolchangez": float(self.app.defaults["geometry_toolchangez"]), - # "startz": self.app.defaults["geometry_startz"], - # "endz": float(self.app.defaults["geometry_endz"]), - # "endxy": self.app.defaults["geometry_endxy"], - # "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"], - # - # # Cutout - # "tools_cutout_tooldia": self.app.defaults["tools_cutout_tooldia"], - # "tools_cutout_kind": self.app.defaults["tools_cutout_kind"], - # "tools_cutout_margin": float(self.app.defaults["tools_cutout_margin"]), - # "tools_cutout_z": float(self.app.defaults["tools_cutout_z"]), - # "tools_cutout_depthperpass": float(self.app.defaults["tools_cutout_depthperpass"]), - # "tools_cutout_mdepth": self.app.defaults["tools_cutout_mdepth"], - # "tools_cutout_gapsize": float(self.app.defaults["tools_cutout_gapsize"]), - # "tools_cutout_gaps_ff": self.app.defaults["tools_cutout_gaps_ff"], - # "tools_cutout_convexshape": self.app.defaults["tools_cutout_convexshape"], - # - # "tools_cutout_big_cursor": self.app.defaults["tools_cutout_big_cursor"], - # "tools_cutout_gap_type": self.app.defaults["tools_cutout_gap_type"], - # "tools_cutout_gap_depth": float(self.app.defaults["tools_cutout_gap_depth"]), - # "tools_cutout_mb_dia": float(self.app.defaults["tools_cutout_mb_dia"]), - # "tools_cutout_mb_spacing": float(self.app.defaults["tools_cutout_mb_spacing"]), - # - # }) self.cut_tool_dict.update({ - 'tooldia': dia, - 'data': deepcopy(self.default_data), - 'solid_geometry': [] + 'tooldia': dia, + 'data': deepcopy(self.default_data), + 'solid_geometry': [] }) self.update_ui(self.default_data) @@ -653,7 +561,6 @@ class CutOut(AppTool): tool_from_db = deepcopy(self.default_data) tool_from_db.update(tool) - # FIXME when the Geometry UI milling functionality will be transferred in the Milling Tool this needs changes tool_from_db['data']["tools_cutout_tooldia"] = deepcopy(tool["tooldia"]) tool_from_db['data']["tools_cutout_z"] = deepcopy(tool_from_db['data']["tools_mill_cutz"]) tool_from_db['data']["tools_cutout_mdepth"] = deepcopy(tool_from_db['data']["tools_mill_multidepth"]) @@ -685,9 +592,9 @@ class CutOut(AppTool): truncated_tooldia = self.app.dec_format(tooldia, self.decimals) self.cutout_tools.update({ 1: { - 'tooldia': truncated_tooldia, - 'data': deepcopy(tool['data']), - 'solid_geometry': [] + 'tooldia': truncated_tooldia, + 'data': deepcopy(tool['data']), + 'solid_geometry': [] } }) self.cutout_tools[1]['data']['name'] = '_cutout' @@ -870,7 +777,7 @@ class CutOut(AppTool): outname = "%s_cutout" % formatted_name self.app.collection.promise(outname) - has_mouse_bites = True if self.ui.gaptype_radio.get_value() == 'mb' else False + has_mouse_bites = True if self.ui.gaptype_combo.get_value() == 2 else False # "mouse bytes" outname_exc = "%s_mouse_bites" % formatted_name if has_mouse_bites is True: @@ -887,7 +794,7 @@ class CutOut(AppTool): mb_dia = self.ui.mb_dia_entry.get_value() mb_buff_val = mb_dia / 2.0 mb_spacing = self.ui.mb_spacing_entry.get_value() - gap_type = self.ui.gaptype_radio.get_value() + gap_type = self.ui.gaptype_combo.get_value() thin_entry = self.ui.thin_depth_entry.get_value() if cutout_obj.kind == 'gerber': @@ -935,7 +842,7 @@ class CutOut(AppTool): return 'fail' solid_geo, rest_geo = cutout_handler(geom=geo, gapsize=gapsize) - if gap_type == 'bt' and thin_entry != 0: + if gap_type == 1 and thin_entry != 0: # "Thin gaps" gaps_solid_geo = rest_geo else: object_geo = flatten_shapely_geometry(object_geo) @@ -949,7 +856,7 @@ class CutOut(AppTool): c_geo, r_geo = cutout_handler(geom=geom_struct, gapsize=gapsize) solid_geo += c_geo - if gap_type == 'bt' and thin_entry != 0: + if gap_type == 1 and thin_entry != 0: # "Thin gaps" gaps_solid_geo += r_geo if not solid_geo: @@ -962,6 +869,7 @@ class CutOut(AppTool): # there ar enot lines but polygons pass + # If it has mouse bytes if has_mouse_bites is True: gapsize -= dia / 2 mb_object_geo = deepcopy(object_geo) @@ -1074,7 +982,7 @@ class CutOut(AppTool): exc_obj.options['ymax'] = ymax try: - if self.ui.gaptype_radio.get_value() == 'mb': + if self.ui.gaptype_combo.get_value() == 2: # "mouse bytes" ret = app_obj.app_obj.new_object('excellon', outname_exc, excellon_init, autoselected=False) if ret == 'fail': app_obj.inform.emit('[ERROR_NOTCL] %s' % _("Mouse bites failed.")) @@ -1215,7 +1123,7 @@ class CutOut(AppTool): outname = "%s_cutout" % formatted_name self.app.collection.promise(outname) - has_mouse_bites = True if self.ui.gaptype_radio.get_value() == 'mb' else False + has_mouse_bites = True if self.ui.gaptype_combo.get_value() == 2 else False # "mouse bytes" outname_exc = cutout_obj.options["name"] + "_mouse_bites" if has_mouse_bites is True: @@ -1231,7 +1139,7 @@ class CutOut(AppTool): mb_dia = self.ui.mb_dia_entry.get_value() mb_buff_val = mb_dia / 2.0 mb_spacing = self.ui.mb_spacing_entry.get_value() - gap_type = self.ui.gaptype_radio.get_value() + gap_type = self.ui.gaptype_combo.get_value() thin_entry = self.ui.thin_depth_entry.get_value() if cutout_obj.multigeo is False: @@ -1258,7 +1166,7 @@ class CutOut(AppTool): solid_geo = cutout_rect_handler(geo, gapsize, xmin, ymin, xmax, ymax) - if gap_type == 'bt' and thin_entry != 0: + if gap_type == 1 and thin_entry != 0: # "Thin gaps" gaps_solid_geo = self.subtract_geo(geo, deepcopy(solid_geo)) else: if cutout_obj.kind == 'geometry': @@ -1270,7 +1178,7 @@ class CutOut(AppTool): c_geo = cutout_rect_handler(geom_struct, gapsize, xmin, ymin, xmax, ymax) solid_geo += c_geo - if gap_type == 'bt' and thin_entry != 0: + if gap_type == 1 and thin_entry != 0: # "Thin gaps" try: gaps_solid_geo += self.subtract_geo(geom_struct, c_geo) except TypeError: @@ -1286,7 +1194,7 @@ class CutOut(AppTool): c_geo = cutout_rect_handler(geom_struct, gapsize, xmin, ymin, xmax, ymax) solid_geo += c_geo - if gap_type == 'bt' and thin_entry != 0: + if gap_type == 1 and thin_entry != 0: # "Thin gaps" try: gaps_solid_geo += self.subtract_geo(geom_struct, c_geo) except TypeError: @@ -1436,7 +1344,7 @@ class CutOut(AppTool): exc_obj.options['ymax'] = e_ymax try: - if self.ui.gaptype_radio.get_value() == 'mb': + if self.ui.gaptype_combo.get_value() == 2: # "mouse bytes" ret = app_obj.app_obj.new_object('excellon', outname_exc, excellon_init, autoselected=False) if ret == 'fail': app_obj.inform.emit('[ERROR_NOTCL] %s' % _("Mouse bites failed.")) @@ -1544,7 +1452,7 @@ class CutOut(AppTool): with self.app.proc_container.new('%s...' % _("Working")): try: - ret = self.app.app_obj.new_object("excellon", outname, obj_init) + ret = self.app.app_obj.new_object("excellon", outname, obj_init, autoselected=False) except Exception as e: log.error("Error on Drill Cutting Excellon object creation: %s" % str(e)) return @@ -1579,7 +1487,7 @@ class CutOut(AppTool): _("Tool Diameter is zero value. Change it to a positive real number.")) return - if self.ui.gaptype_radio.get_value() == 'mb': + if self.ui.gaptype_combo.get_value() == 2: # "mouse bytes" mb_dia = self.ui.mb_dia_entry.get_value() b_dia = (self.cutting_dia / 2.0) - (mb_dia / 2.0) # flaten manual geometry @@ -1638,12 +1546,12 @@ class CutOut(AppTool): cut_poly = self.cutting_geo(pos=(snapped_pos[0], snapped_pos[1])) - gap_type = self.ui.gaptype_radio.get_value() + gap_type = self.ui.gaptype_combo.get_value() gaps_solid_geo = None - if gap_type == 'bt' and self.ui.thin_depth_entry.get_value() != 0: + if gap_type == 1 and self.ui.thin_depth_entry.get_value() != 0: # "Thin gaps" gaps_solid_geo = self.intersect_geo(self.manual_solid_geo, cut_poly) - if gap_type == 'mb': + if gap_type == 2: # "Mouse Bytes" rests_geo = self.intersect_geo(self.mb_manual_solid_geo, cut_poly) if isinstance(rests_geo, list): self.mb_manual_cuts += rests_geo @@ -1739,7 +1647,7 @@ class CutOut(AppTool): elif kind == 'single': if isinstance(geo_union, Polygon) or \ (isinstance(geo_union, list) and len(geo_union) == 1) or \ - (isinstance(geo_union, MultiPolygon) and len(geo_union) == 1): + (isinstance(geo_union, MultiPolygon) and len(geo_union.geoms) == 1): geo_obj.solid_geometry = geo_union.buffer(margin + abs(dia / 2)).exterior elif isinstance(geo_union, MultiPolygon): x0, y0, x1, y1 = geo_union.bounds @@ -1779,7 +1687,7 @@ class CutOut(AppTool): geo_obj.tools[1]['data']['tools_mill_depthperpass'] = self.ui.maxdepth_entry.get_value() outname = cutout_obj.options["name"] + "_cutout" - self.app.app_obj.new_object('geometry', outname, geo_init) + self.app.app_obj.new_object('geometry', outname, geo_init, autoselected=False) def cutting_geo(self, pos): self.cutting_dia = float(self.ui.dia.get_value()) @@ -1862,7 +1770,7 @@ class CutOut(AppTool): self.man_cutout_obj.plot() # mouse bytes - if self.ui.gaptype_radio.get_value() == 'mb': + if self.ui.gaptype_combo.get_value() == 2: # "mouse bytes" with self.app.proc_container.new("Generating Excellon ..."): outname_exc = self.man_cutout_obj.options["name"] + "_mouse_bites" self.app.collection.promise(outname_exc) @@ -2305,8 +2213,8 @@ class CutoutUI: self.tools_box.addWidget(obj_frame) # Grid Layout - grid0 = FCGridLayout(v_spacing=5, h_spacing=3) - obj_frame.setLayout(grid0) + obj_grid = FCGridLayout(v_spacing=5, h_spacing=3) + obj_frame.setLayout(obj_grid) # Object kind self.kindlabel = FCLabel('%s:' % _('Kind')) @@ -2320,8 +2228,8 @@ class CutoutUI: {"label": _("Single"), "value": "single"}, {"label": _("Panel"), "value": "panel"}, ]) - grid0.addWidget(self.kindlabel, 2, 0) - grid0.addWidget(self.obj_kind_combo, 2, 1) + obj_grid.addWidget(self.kindlabel, 2, 0) + obj_grid.addWidget(self.obj_kind_combo, 2, 1) # Type of object to be cutout self.type_obj_radio = RadioSet([ @@ -2337,8 +2245,8 @@ class CutoutUI: "of objects that will populate the 'Object' combobox.") ) - grid0.addWidget(self.type_obj_combo_label, 4, 0) - grid0.addWidget(self.type_obj_radio, 4, 1) + obj_grid.addWidget(self.type_obj_combo_label, 4, 0) + obj_grid.addWidget(self.type_obj_radio, 4, 1) # Object to be cutout self.obj_combo = FCComboBox() @@ -2346,7 +2254,7 @@ class CutoutUI: self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex())) self.obj_combo.is_last = False - grid0.addWidget(self.obj_combo, 6, 0, 1, 2) + obj_grid.addWidget(self.obj_combo, 6, 0, 1, 2) self.tool_sel_label = FCLabel('%s' % _('Cutout Tool')) self.tools_box.addWidget(self.tool_sel_label) @@ -2358,8 +2266,8 @@ class CutoutUI: self.tools_box.addWidget(tool_frame) # Grid Layout - grid1 = FCGridLayout(v_spacing=5, h_spacing=3) - tool_frame.setLayout(grid1) + tool_grid = FCGridLayout(v_spacing=5, h_spacing=3) + tool_frame.setLayout(tool_grid) # Tool Diameter self.dia = FCDoubleSpinner(callback=self.confirmation_message) @@ -2371,8 +2279,8 @@ class CutoutUI: _("Diameter of the tool used to cutout\n" "the PCB shape out of the surrounding material.") ) - grid1.addWidget(self.dia_label, 0, 0) - grid1.addWidget(self.dia, 0, 1) + tool_grid.addWidget(self.dia_label, 0, 0) + tool_grid.addWidget(self.dia, 0, 1) hlay = QtWidgets.QHBoxLayout() @@ -2399,12 +2307,12 @@ class CutoutUI: ) hlay.addWidget(self.addtool_from_db_btn) - grid1.addLayout(hlay, 2, 0, 1, 2) + tool_grid.addLayout(hlay, 2, 0, 1, 2) # separator_line = QtWidgets.QFrame() # separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine) # separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) - # grid0.addWidget(separator_line, 18, 0, 1, 2) + # obj_grid.addWidget(separator_line, 18, 0, 1, 2) self.param_label = FCLabel('%s' % _("Tool Parameters")) self.tools_box.addWidget(self.param_label) @@ -2416,8 +2324,8 @@ class CutoutUI: self.tools_box.addWidget(tool_par_frame) # Grid Layout - grid2 = FCGridLayout(v_spacing=5, h_spacing=3) - tool_par_frame.setLayout(grid2) + param_grid = FCGridLayout(v_spacing=5, h_spacing=3) + tool_par_frame.setLayout(param_grid) # Convex Shape # Surrounding convex box shape @@ -2431,8 +2339,8 @@ class CutoutUI: _("Create a convex shape surrounding the entire PCB.\n" "Used only if the source object type is Gerber.") ) - grid2.addWidget(self.convex_box_label, 0, 0) - grid2.addWidget(self.convex_box_cb, 0, 1) + param_grid.addWidget(self.convex_box_label, 0, 0) + param_grid.addWidget(self.convex_box_cb, 0, 1) # Cut Z cutzlabel = FCLabel('%s:' % _('Cut Z')) @@ -2446,8 +2354,8 @@ class CutoutUI: self.cutz_entry.setSingleStep(0.1) - grid2.addWidget(cutzlabel, 2, 0) - grid2.addWidget(self.cutz_entry, 2, 1) + param_grid.addWidget(cutzlabel, 2, 0) + param_grid.addWidget(self.cutz_entry, 2, 1) # Multi-pass self.mpass_cb = FCCheckBox('%s:' % _("Multi-Depth")) @@ -2465,8 +2373,8 @@ class CutoutUI: self.maxdepth_entry.setToolTip(_("Depth of each pass (positive).")) - grid2.addWidget(self.mpass_cb, 4, 0) - grid2.addWidget(self.maxdepth_entry, 4, 1) + param_grid.addWidget(self.mpass_cb, 4, 0) + param_grid.addWidget(self.maxdepth_entry, 4, 1) self.ois_mpass_geo = OptionalInputSection(self.mpass_cb, [self.maxdepth_entry]) @@ -2482,11 +2390,24 @@ class CutoutUI: "will make the cutout of the PCB further from\n" "the actual PCB border") ) - grid2.addWidget(self.margin_label, 6, 0) - grid2.addWidget(self.margin, 6, 1) + param_grid.addWidget(self.margin_label, 6, 0) + param_grid.addWidget(self.margin, 6, 1) + + self.gaps_label = FCLabel('%s' % _("Gaps")) + self.tools_box.addWidget(self.gaps_label) + + # ############################################################################################################# + # Gaps Frame + # ############################################################################################################# + gaps_frame = FCFrame() + self.tools_box.addWidget(gaps_frame) + + # Grid Layout + gaps_grid = FCGridLayout(v_spacing=5, h_spacing=3) + gaps_frame.setLayout(gaps_grid) # Gapsize - self.gapsize_label = FCLabel('%s:' % _("Gap size")) + self.gapsize_label = FCLabel('%s:' % _("Size")) self.gapsize_label.setToolTip( _("The size of the bridge gaps in the cutout\n" "used to keep the board connected to\n" @@ -2498,11 +2419,11 @@ class CutoutUI: self.gapsize.setRange(0.0000, 10000.0000) self.gapsize.set_precision(self.decimals) - grid2.addWidget(self.gapsize_label, 8, 0) - grid2.addWidget(self.gapsize, 8, 1) + gaps_grid.addWidget(self.gapsize_label, 2, 0) + gaps_grid.addWidget(self.gapsize, 2, 1) # Gap Type - self.gaptype_label = FCLabel('%s:' % _("Gap type")) + self.gaptype_label = FCLabel('%s:' % _("Type")) self.gaptype_label.setToolTip( _("The type of gap:\n" "- Bridge -> the cutout will be interrupted by bridges\n" @@ -2510,17 +2431,19 @@ class CutoutUI: "- M-Bites -> 'Mouse Bites' - same as 'bridge' but covered with drill holes") ) - self.gaptype_radio = RadioSet( - [ - {'label': _('Bridge'), 'value': 'b'}, - {'label': _('Thin'), 'value': 'bt'}, - {'label': "M-Bites", 'value': 'mb'} - ], - stretch=True - ) + # self.gaptype_combo = RadioSet( + # [ + # {'label': _('Bridge'), 'value': 'b'}, + # {'label': _('Thin'), 'value': 'bt'}, + # {'label': "M-Bites", 'value': 'mb'} + # ], + # stretch=True + # ) + self.gaptype_combo = FCComboBox2() + self.gaptype_combo.addItems([_('Bridge'), _('Thin'), _("Mouse Bytes")]) - grid2.addWidget(self.gaptype_label, 10, 0) - grid2.addWidget(self.gaptype_radio, 10, 1) + gaps_grid.addWidget(self.gaptype_label, 4, 0) + gaps_grid.addWidget(self.gaptype_combo, 4, 1) # Thin gaps Depth self.thin_depth_label = FCLabel('%s:' % _("Depth")) @@ -2533,11 +2456,11 @@ class CutoutUI: self.thin_depth_entry.setRange(-10000.0000, 10000.0000) self.thin_depth_entry.setSingleStep(0.1) - grid2.addWidget(self.thin_depth_label, 12, 0) - grid2.addWidget(self.thin_depth_entry, 12, 1) + gaps_grid.addWidget(self.thin_depth_label, 6, 0) + gaps_grid.addWidget(self.thin_depth_entry, 6, 1) # Mouse Bites Tool Diameter - self.mb_dia_label = FCLabel('%s:' % _("Tool Diameter")) + self.mb_dia_label = FCLabel('%s:' % _("Tool Dia")) self.mb_dia_label.setToolTip( _("The drill hole diameter when doing mouse bites.") ) @@ -2545,8 +2468,8 @@ class CutoutUI: self.mb_dia_entry.set_precision(self.decimals) self.mb_dia_entry.setRange(0, 10000.0000) - grid2.addWidget(self.mb_dia_label, 14, 0) - grid2.addWidget(self.mb_dia_entry, 14, 1) + gaps_grid.addWidget(self.mb_dia_label, 8, 0) + gaps_grid.addWidget(self.mb_dia_entry, 8, 1) # Mouse Bites Holes Spacing self.mb_spacing_label = FCLabel('%s:' % _("Spacing")) @@ -2557,18 +2480,18 @@ class CutoutUI: self.mb_spacing_entry.set_precision(self.decimals) self.mb_spacing_entry.setRange(0, 10000.0000) - grid2.addWidget(self.mb_spacing_label, 16, 0) - grid2.addWidget(self.mb_spacing_entry, 16, 1) + gaps_grid.addWidget(self.mb_spacing_label, 10, 0) + gaps_grid.addWidget(self.mb_spacing_entry, 10, 1) - separator_line = QtWidgets.QFrame() - separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine) - separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) - grid2.addWidget(separator_line, 18, 0, 1, 2) + self.separator_line = QtWidgets.QFrame() + self.separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine) + self.separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + gaps_grid.addWidget(self.separator_line, 12, 0, 1, 2) # ############################################################################################################## # ######################################## Type of CUTOUT ###################################################### # ############################################################################################################## - self.cutout_type_label = FCLabel('%s:' % _("Bridge Gaps")) + self.cutout_type_label = FCLabel('%s:' % _("Bridge")) self.cutout_type_label.setToolTip( _("Selection of the type of cutout.") ) @@ -2578,8 +2501,8 @@ class CutoutUI: {"label": _("Manual"), "value": "m"}, ]) - grid2.addWidget(self.cutout_type_label, 20, 0) - grid2.addWidget(self.cutout_type_radio, 20, 1) + gaps_grid.addWidget(self.cutout_type_label, 14, 0) + gaps_grid.addWidget(self.cutout_type_radio, 14, 1) # Gaps # How gaps wil be rendered: @@ -2609,8 +2532,24 @@ class CutoutUI: for it in gaps_items: self.gaps.addItem(it) # self.gaps.setStyleSheet('background-color: rgb(255,255,255)') - grid2.addWidget(self.gaps_label, 22, 0) - grid2.addWidget(self.gaps, 22, 1) + gaps_grid.addWidget(self.gaps_label, 16, 0) + gaps_grid.addWidget(self.gaps, 16, 1) + + # ############################################################################################################# + # Manual Gaps Frame + # ############################################################################################################# + self.man_frame = QtWidgets.QFrame() + self.man_frame.setContentsMargins(0, 0, 0, 0) + gaps_grid.addWidget(self.man_frame, 18, 0, 1, 2) + + man_grid = FCGridLayout(v_spacing=5, h_spacing=3) + man_grid.setContentsMargins(0, 0, 0, 0) + self.man_frame.setLayout(man_grid) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + man_grid.addWidget(separator_line, 0, 0, 1, 2) # Big Cursor self.big_cursor_label = FCLabel('%s:' % _("Big cursor")) @@ -2618,8 +2557,8 @@ class CutoutUI: _("Use a big cursor when adding manual gaps.")) self.big_cursor_cb = FCCheckBox() - grid2.addWidget(self.big_cursor_label, 24, 0) - grid2.addWidget(self.big_cursor_cb, 24, 1) + man_grid.addWidget(self.big_cursor_label, 2, 0) + man_grid.addWidget(self.big_cursor_cb, 2, 1) # Manual Geo Object self.man_object_combo = FCComboBox() @@ -2634,13 +2573,41 @@ class CutoutUI: ) # self.man_object_label.setMinimumWidth(60) - grid2.addWidget(self.man_object_label, 26, 0, 1, 2) - grid2.addWidget(self.man_object_combo, 26, 0, 1, 2) + man_grid.addWidget(self.man_object_label, 4, 0, 1, 2) + man_grid.addWidget(self.man_object_combo, 6, 0, 1, 2) # ############################################################################################################# # Buttons # ############################################################################################################# + man_hlay = QtWidgets.QHBoxLayout() + self.tools_box.addLayout(man_hlay) + + # Generate a surrounding Geometry object Button + self.man_geo_creation_btn = FCButton(_("Manual Geometry")) + self.man_geo_creation_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/rectangle32.png')) + self.man_geo_creation_btn.setToolTip( + _("Generate a Geometry to be used as cutout.") + ) + # self.man_geo_creation_btn.setStyleSheet(""" + # QPushButton + # { + # font-weight: bold; + # } + # """) + + # Manual Add of Gaps Button + self.man_gaps_creation_btn = QtWidgets.QToolButton() + self.man_gaps_creation_btn.setToolButtonStyle(QtCore.Qt.ToolButtonStyle.ToolButtonTextBesideIcon) + self.man_gaps_creation_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/plus32.png')) + self.man_gaps_creation_btn.setText(_("Gaps")) + self.man_gaps_creation_btn.setToolTip( + _("Add new gaps on the selected Geometry object\n" + "by clicking mouse left button on the Geometry outline.") + ) + man_hlay.addWidget(self.man_geo_creation_btn) + man_hlay.addWidget(self.man_gaps_creation_btn) + # Freeform Geometry Button self.ff_cutout_object_btn = FCButton(_("Generate Geometry")) self.ff_cutout_object_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/irregular32.png')) @@ -2674,47 +2641,12 @@ class CutoutUI: """) self.tools_box.addWidget(self.rect_cutout_object_btn) - # Generate a surrounding Geometry object Button - self.man_geo_creation_btn = FCButton(_("Generate Manual Geometry")) - self.man_geo_creation_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/rectangle32.png')) - self.man_geo_creation_btn.setToolTip( - _("If the object to be cutout is a Gerber\n" - "first create a Geometry that surrounds it,\n" - "to be used as the cutout, if one doesn't exist yet.\n" - "Select the source Gerber file in the top object combobox.") - ) - # self.man_geo_creation_btn.setStyleSheet(""" - # QPushButton - # { - # font-weight: bold; - # } - # """) - self.tools_box.addWidget(self.man_geo_creation_btn) - - # Manual Add of Gaps Button - self.man_gaps_creation_btn = FCButton(_("Manual Add Bridge Gaps")) - self.man_gaps_creation_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/gaps32.png')) - self.man_gaps_creation_btn.setToolTip( - _("Use the left mouse button (LMB) click\n" - "to create a bridge gap to separate the PCB from\n" - "the surrounding material.\n" - "The LMB click has to be done on the perimeter of\n" - "the Geometry object used as a cutout geometry.") - ) - self.man_gaps_creation_btn.setStyleSheet(""" - QPushButton - { - font-weight: bold; - } - """) - self.tools_box.addWidget(self.man_gaps_creation_btn) - # self.tool_param_separator_line = QtWidgets.QFrame() # self.tool_param_separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine) # self.tool_param_separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) - # grid0.addWidget(self.tool_param_separator_line, 60, 0, 1, 2) + # obj_grid.addWidget(self.tool_param_separator_line, 60, 0, 1, 2) - # grid0.addWidget(FCLabel(""), 62, 0, 1, 2) + # obj_grid.addWidget(FCLabel(""), 62, 0, 1, 2) # Cut by Drilling Title self.title_drillcut_label = FCLabel('%s' % _('Cut by Drilling')) @@ -2728,8 +2660,8 @@ class CutoutUI: self.tools_box.addWidget(self.drill_cut_frame) # Grid Layout - grid3 = FCGridLayout(v_spacing=5, h_spacing=3) - self.drill_cut_frame.setLayout(grid3) + drill_cut_grid = FCGridLayout(v_spacing=5, h_spacing=3) + self.drill_cut_frame.setLayout(drill_cut_grid) # Drilling Geo Object Label self.drillcut_object_lbl = FCLabel('%s:' % _("Geometry")) @@ -2737,16 +2669,16 @@ class CutoutUI: _("Geometry object used to create the manual cutout.") ) - grid3.addWidget(self.drillcut_object_lbl, 0, 0, 1, 2) + drill_cut_grid.addWidget(self.drillcut_object_lbl, 0, 0, 1, 2) # Drilling Geo Object self.drillcut_object_combo = FCComboBox() self.drillcut_object_combo.setModel(self.app.collection) self.drillcut_object_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex())) - self.drillcut_object_combo.is_last = True + self.drillcut_object_combo.is_last = False self.drillcut_object_combo.obj_type = "Geometry" - grid3.addWidget(self.drillcut_object_combo, 2, 0, 1, 2) + drill_cut_grid.addWidget(self.drillcut_object_combo, 2, 0, 1, 2) # Drill Tool Diameter self.drill_dia_entry = FCDoubleSpinner(callback=self.confirmation_message) @@ -2758,8 +2690,8 @@ class CutoutUI: _("Diameter of the tool used to cutout\n" "the PCB by drilling.") ) - grid3.addWidget(self.drill_dia_label, 4, 0) - grid3.addWidget(self.drill_dia_entry, 4, 1) + drill_cut_grid.addWidget(self.drill_dia_label, 4, 0) + drill_cut_grid.addWidget(self.drill_dia_entry, 4, 1) # Drill Tool Pitch self.drill_pitch_entry = FCDoubleSpinner(callback=self.confirmation_message) @@ -2771,8 +2703,8 @@ class CutoutUI: _("Distance between the center of\n" "two neighboring drill holes.") ) - grid3.addWidget(self.drill_pitch_label, 6, 0) - grid3.addWidget(self.drill_pitch_entry, 6, 1) + drill_cut_grid.addWidget(self.drill_pitch_label, 6, 0) + drill_cut_grid.addWidget(self.drill_pitch_entry, 6, 1) # Drill Tool Margin self.drill_margin_entry = FCDoubleSpinner(callback=self.confirmation_message) @@ -2785,8 +2717,10 @@ class CutoutUI: "will make the cutout of the PCB further from\n" "the actual PCB border") ) - grid3.addWidget(self.drill_margin_label, 8, 0) - grid3.addWidget(self.drill_margin_entry, 8, 1) + drill_cut_grid.addWidget(self.drill_margin_label, 8, 0) + drill_cut_grid.addWidget(self.drill_margin_entry, 8, 1) + + FCGridLayout.set_common_column_size([obj_grid, tool_grid, param_grid, man_grid, drill_cut_grid, gaps_grid], 0) # Drill Cut Button self.drillcut_btn = FCButton(_("Cut by Drilling")) @@ -2818,27 +2752,27 @@ class CutoutUI: """) self.layout.addWidget(self.reset_button) - self.gaptype_radio.activated_custom.connect(self.on_gap_type_radio) + self.gaptype_combo.currentIndexChanged.connect(self.on_gap_type_radio) # ############################ FINSIHED GUI ################################### # ############################################################################# - def on_gap_type_radio(self, val): - if val == 'b': + def on_gap_type_radio(self, index): + if index == 0: # Normal gap self.thin_depth_label.hide() self.thin_depth_entry.hide() self.mb_dia_label.hide() self.mb_dia_entry.hide() self.mb_spacing_label.hide() self.mb_spacing_entry.hide() - elif val == 'bt': + elif index == 1: # "Thin gaps" self.thin_depth_label.show() self.thin_depth_entry.show() self.mb_dia_label.hide() self.mb_dia_entry.hide() self.mb_spacing_label.hide() self.mb_spacing_entry.hide() - elif val == 'mb': + elif index == 2: # "Mouse Bytes" self.thin_depth_label.hide() self.thin_depth_entry.hide() self.mb_dia_label.show() diff --git a/defaults.py b/defaults.py index 2908a648..bd16c758 100644 --- a/defaults.py +++ b/defaults.py @@ -510,7 +510,7 @@ class FlatCAMDefaults: "tools_cutout_gaps_ff": "4", "tools_cutout_convexshape": False, "tools_cutout_big_cursor": True, - "tools_cutout_gap_type": 'b', + "tools_cutout_gap_type": 0, # "Basic Gap" "tools_cutout_gap_depth": -1.0, "tools_cutout_mb_dia": 0.6, "tools_cutout_mb_spacing": 0.3,