diff --git a/CHANGELOG.md b/CHANGELOG.md
index 62c3fdaf..43683609 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ CHANGELOG for FlatCAM beta
- in INFO functionality for Gerber Object made the difference if the Follow geometry is not a Point or a LineString
- In Plugins: Panelize, Cutout, Extract, Copper Thieving disabled the autoload of the last created APP object
- In Plugins: Calculators, Copper Thieving, Corners, Extract, Fiducials and Film activated the harmonizing first column width in the Plugin UI
+- DblSided Plugin - remade the UI
18.09.2021
diff --git a/appGUI/preferences/tools/Tools2sidedPrefGroupUI.py b/appGUI/preferences/tools/Tools2sidedPrefGroupUI.py
index 4a88b627..cee07f6e 100644
--- a/appGUI/preferences/tools/Tools2sidedPrefGroupUI.py
+++ b/appGUI/preferences/tools/Tools2sidedPrefGroupUI.py
@@ -78,7 +78,7 @@ class Tools2sidedPrefGroupUI(OptionsGroupUI):
[
{'label': _('Point'), 'value': 'point'},
{'label': _('Box'), 'value': 'box'},
- {'label': _('Hole Snap'), 'value': 'hole'},
+ {'label': _('Snap'), 'value': 'hole'},
]
)
self.axloc_label = FCLabel('%s:' % _("Axis Ref"))
@@ -88,7 +88,7 @@ class Tools2sidedPrefGroupUI(OptionsGroupUI):
"- Point -> a set of coordinates (x,y) around which the object is mirrored\n"
"- Box -> a set of coordinates (x, y) obtained from the center of the\n"
"bounding box of another object selected below\n"
- "- Hole Snap-> a point defined by the center of a drill hone in a Excellon object")
+ "- Snap-> a point defined by the center of a drill hone in a Excellon object")
)
grid0.addWidget(self.axloc_label, 4, 0)
diff --git a/appPlugins/ToolDblSided.py b/appPlugins/ToolDblSided.py
index 3bf33749..8678b6fb 100644
--- a/appPlugins/ToolDblSided.py
+++ b/appPlugins/ToolDblSided.py
@@ -3,7 +3,7 @@ from PyQt6 import QtWidgets, QtCore, QtGui
from appTool import AppTool
from appGUI.GUIElements import RadioSet, FCDoubleSpinner, FCButton, FCComboBox, NumericalEvalTupleEntry, FCLabel, \
- VerticalScrollArea, FCGridLayout, FCFrame
+ VerticalScrollArea, FCGridLayout, FCComboBox2, FCFrame
from numpy import Inf
from copy import deepcopy
@@ -115,14 +115,14 @@ class DblSidedTool(AppTool):
# #############################################################################
self.ui.level.toggled.connect(self.on_level_changed)
- self.ui.object_type_radio.activated_custom.connect(self.on_object_type)
+ self.ui.object_type_combo.currentIndexChanged.connect(self.on_object_type)
self.ui.add_point_button.clicked.connect(self.on_point_add)
self.ui.add_drill_point_button.clicked.connect(self.on_drill_add)
self.ui.delete_drill_point_button.clicked.connect(self.on_drill_delete_last)
self.ui.box_type_radio.activated_custom.connect(self.on_combo_box_type)
- self.ui.axis_location.group_toggle_fn = self.on_toggle_pointbox
+ self.ui.axis_location.activated_custom.connect(self.on_toggle_pointbox)
self.ui.point_entry.textChanged.connect(lambda val: self.ui.align_ref_label_val.set_value(val))
self.ui.pick_hole_button.clicked.connect(self.on_pick_hole)
@@ -157,6 +157,8 @@ class DblSidedTool(AppTool):
self.ui.mirror_axis.set_value(self.app.defaults["tools_2sided_mirror_axis"])
self.ui.axis_location.set_value(self.app.defaults["tools_2sided_axis_loc"])
+ self.on_toggle_pointbox(self.ui.axis_location.get_value())
+
self.ui.drill_dia.set_value(self.app.defaults["tools_2sided_drilldia"])
self.ui.align_axis_radio.set_value(self.app.defaults["tools_2sided_allign_axis"])
@@ -174,27 +176,27 @@ class DblSidedTool(AppTool):
obj_name = obj.options['name']
if obj.kind == 'gerber':
# run once to make sure that the obj_type attribute is updated in the FCComboBox
- self.ui.object_type_radio.set_value('grb')
- self.on_object_type('grb')
+ self.ui.object_type_combo.set_value(0)
+ self.on_object_type(0) # Gerber
self.ui.box_type_radio.set_value('grb')
self.on_combo_box_type('grb')
elif obj.kind == 'excellon':
# run once to make sure that the obj_type attribute is updated in the FCComboBox
- self.ui.object_type_radio.set_value('exc')
- self.on_object_type('exc')
+ self.ui.object_type_combo.set_value(1)
+ self.on_object_type(1) # Excellon
self.ui.box_type_radio.set_value('exc')
self.on_combo_box_type('exc')
elif obj.kind == 'geometry':
# run once to make sure that the obj_type attribute is updated in the FCComboBox
- self.ui.object_type_radio.set_value('geo')
- self.on_object_type('geo')
+ self.ui.object_type_combo.set_value(2)
+ self.on_object_type(2) # Geometry
self.ui.box_type_radio.set_value('geo')
self.on_combo_box_type('geo')
self.ui.object_combo.set_value(obj_name)
else:
- self.ui.object_type_radio.set_value('grb')
- self.on_object_type('grb')
+ self.ui.object_type_combo.set_value(0)
+ self.on_object_type(0) # Gerber
if self.local_connected is True:
self.disconnect_events()
@@ -252,11 +254,18 @@ class DblSidedTool(AppTool):
self.ui.calculate_bb_button.show()
def on_object_type(self, val):
- obj_type = {'grb': 0, 'exc': 1, 'geo': 2}[val]
- self.ui.object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
+ """
+ Will select the actual type of objects: Gerber, Excellon, Geometry
+
+ :param val: Index in the combobox where 0 = Gerber, 1 = Excellon and 2 = Geometry
+ :type val: int
+ :return: None
+ :rtype: None
+ """
+ self.ui.object_combo.setRootModelIndex(self.app.collection.index(val, 0, QtCore.QModelIndex()))
self.ui.object_combo.setCurrentIndex(0)
self.ui.object_combo.obj_type = {
- "grb": "Gerber", "exc": "Excellon", "geo": "Geometry"}[val]
+ 0: "Gerber", 1: "Excellon", 2: "Geometry"}[val]
def on_combo_box_type(self, val):
obj_type = {'grb': 0, 'exc': 1, 'geo': 2}[val]
@@ -271,13 +280,15 @@ class DblSidedTool(AppTool):
kind = current.indexes()[0].internalPointer().obj.kind
if kind in ['gerber', 'excellon', 'geometry']:
+ index = {'gerber': 0, 'excellon': 1, 'geometry': 2}[kind]
+ self.ui.object_type_combo.set_value(index)
+
obj_type = {'gerber': 'grb', 'excellon': 'exc', 'geometry': 'geo'}[kind]
- self.ui.object_type_radio.set_value(obj_type)
self.ui.box_type_radio.set_value(obj_type)
self.ui.object_combo.set_value(name)
- except Exception:
- pass
+ except Exception as err:
+ self.app.log.error("DblSidedTool.on_object_selection_changed() --> %s" % str(err))
def on_create_alignment_holes(self):
axis = self.ui.align_axis_radio.get_value()
@@ -495,41 +506,49 @@ class DblSidedTool(AppTool):
self.drill_values = drill_values_without_last_tupple
self.ui.alignment_holes.set_value(self.drill_values)
- def on_toggle_pointbox(self):
- val = self.ui.axis_location.get_value()
+ def on_toggle_pointbox(self, val):
if val == "point":
- self.ui.point_entry.show()
- self.ui.add_point_button.show()
- self.ui.box_type_radio.hide()
- self.ui.box_combo.hide()
-
- self.ui.exc_hole_lbl.hide()
- self.ui.exc_combo.hide()
- self.ui.pick_hole_button.hide()
+ # self.ui.point_entry.show()
+ # self.ui.add_point_button.show()
+ # self.ui.box_type_radio.hide()
+ # self.ui.box_combo.hide()
+ #
+ # self.ui.exc_hole_lbl.hide()
+ # self.ui.exc_combo.hide()
+ # self.ui.pick_hole_button.hide()
+ self.ui.pr_frame.show()
+ self.ui.br_frame.hide()
+ self.ui.sr_frame.hide()
self.ui.align_ref_label_val.set_value(self.ui.point_entry.get_value())
elif val == 'box':
- self.ui.point_entry.hide()
- self.ui.add_point_button.hide()
-
- self.ui.box_type_radio.show()
- self.ui.box_combo.show()
-
- self.ui.exc_hole_lbl.hide()
- self.ui.exc_combo.hide()
- self.ui.pick_hole_button.hide()
+ # self.ui.point_entry.hide()
+ # self.ui.add_point_button.hide()
+ #
+ # self.ui.box_type_radio.show()
+ # self.ui.box_combo.show()
+ #
+ # self.ui.exc_hole_lbl.hide()
+ # self.ui.exc_combo.hide()
+ # self.ui.pick_hole_button.hide()
+ self.ui.pr_frame.hide()
+ self.ui.br_frame.show()
+ self.ui.sr_frame.hide()
self.ui.align_ref_label_val.set_value("Box centroid")
elif val == 'hole':
- self.ui.point_entry.show()
- self.ui.add_point_button.hide()
-
- self.ui.box_type_radio.hide()
- self.ui.box_combo.hide()
-
- self.ui.exc_hole_lbl.show()
- self.ui.exc_combo.show()
- self.ui.pick_hole_button.show()
+ # self.ui.point_entry.show()
+ # self.ui.add_point_button.hide()
+ #
+ # self.ui.box_type_radio.hide()
+ # self.ui.box_combo.hide()
+ #
+ # self.ui.exc_hole_lbl.show()
+ # self.ui.exc_combo.show()
+ # self.ui.pick_hole_button.show()
+ self.ui.pr_frame.hide()
+ self.ui.br_frame.hide()
+ self.ui.sr_frame.show()
def on_bbox_coordinates(self):
@@ -684,25 +703,19 @@ class DsidedUI:
self.tools_box.addWidget(source_frame)
# ## Grid Layout
- grid0 = FCGridLayout(v_spacing=5, h_spacing=3)
- grid0.setColumnStretch(0, 1)
- grid0.setColumnStretch(1, 0)
- source_frame.setLayout(grid0)
+ grid_obj = FCGridLayout(v_spacing=5, h_spacing=3)
+ source_frame.setLayout(grid_obj)
# Type of object to be cutout
- self.type_obj_combo_label = FCLabel('%s:' % _("Type"))
+ self.type_obj_combo_label = FCLabel('%s:' % _("Target"))
self.type_obj_combo_label.setToolTip(
_("Select the type of application object to be processed in this tool.")
)
- self.object_type_radio = RadioSet([
- {"label": _("Gerber"), "value": "grb"},
- {"label": _("Excellon"), "value": "exc"},
- {"label": _("Geometry"), "value": "geo"}
- ])
-
- grid0.addWidget(self.type_obj_combo_label, 0, 0)
- grid0.addWidget(self.object_type_radio, 0, 1)
+ self.object_type_combo = FCComboBox2()
+ self.object_type_combo.addItems([_("Gerber"), _("Excellon"), _("Geometry")])
+ grid_obj.addWidget(self.type_obj_combo_label, 0, 0)
+ grid_obj.addWidget(self.object_type_combo, 0, 1)
# ## Gerber Object to mirror
self.object_combo = FCComboBox()
@@ -710,12 +723,7 @@ class DsidedUI:
self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.object_combo.is_last = True
- grid0.addWidget(self.object_combo, 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, 7, 0, 1, 2)
+ grid_obj.addWidget(self.object_combo, 2, 0, 1, 2)
# #############################################################################################################
# ########## BOUNDS OPERATION ###########################################################################
@@ -732,8 +740,8 @@ class DsidedUI:
self.bounds_frame = FCFrame()
self.tools_box.addWidget(self.bounds_frame)
- grid1 = FCGridLayout(v_spacing=5, h_spacing=3)
- self.bounds_frame.setLayout(grid1)
+ grid_bounds = FCGridLayout(v_spacing=5, h_spacing=3)
+ self.bounds_frame.setLayout(grid_bounds)
# Xmin value
self.xmin_entry = FCDoubleSpinner(callback=self.confirmation_message)
@@ -746,8 +754,8 @@ class DsidedUI:
)
self.xmin_entry.setReadOnly(True)
- grid1.addWidget(self.xmin_btn, 0, 0)
- grid1.addWidget(self.xmin_entry, 0, 1)
+ grid_bounds.addWidget(self.xmin_btn, 0, 0)
+ grid_bounds.addWidget(self.xmin_entry, 0, 1)
# Ymin value
self.ymin_entry = FCDoubleSpinner(callback=self.confirmation_message)
@@ -760,8 +768,8 @@ class DsidedUI:
)
self.ymin_entry.setReadOnly(True)
- grid1.addWidget(self.ymin_btn, 2, 0)
- grid1.addWidget(self.ymin_entry, 2, 1)
+ grid_bounds.addWidget(self.ymin_btn, 2, 0)
+ grid_bounds.addWidget(self.ymin_entry, 2, 1)
# Xmax value
self.xmax_entry = FCDoubleSpinner(callback=self.confirmation_message)
@@ -774,8 +782,8 @@ class DsidedUI:
)
self.xmax_entry.setReadOnly(True)
- grid1.addWidget(self.xmax_btn, 4, 0)
- grid1.addWidget(self.xmax_entry, 4, 1)
+ grid_bounds.addWidget(self.xmax_btn, 4, 0)
+ grid_bounds.addWidget(self.xmax_entry, 4, 1)
# Ymax value
self.ymax_entry = FCDoubleSpinner(callback=self.confirmation_message)
@@ -788,8 +796,8 @@ class DsidedUI:
)
self.ymax_entry.setReadOnly(True)
- grid1.addWidget(self.ymax_btn, 6, 0)
- grid1.addWidget(self.ymax_entry, 6, 1)
+ grid_bounds.addWidget(self.ymax_btn, 6, 0)
+ grid_bounds.addWidget(self.ymax_entry, 6, 1)
# Center point value
self.center_entry = NumericalEvalTupleEntry(border_color='#0069A9')
@@ -802,8 +810,8 @@ class DsidedUI:
)
self.center_entry.setReadOnly(True)
- grid1.addWidget(self.center_btn, 8, 0)
- grid1.addWidget(self.center_entry, 8, 1)
+ grid_bounds.addWidget(self.center_btn, 8, 0)
+ grid_bounds.addWidget(self.center_entry, 8, 1)
# Calculate Bounding box
self.calculate_bb_button = FCButton(_("Calculate Bounds Values"))
@@ -830,8 +838,8 @@ class DsidedUI:
mirror_frame = FCFrame()
self.tools_box.addWidget(mirror_frame)
- grid2 = FCGridLayout(v_spacing=5, h_spacing=3)
- mirror_frame.setLayout(grid2)
+ grid_mirror = FCGridLayout(v_spacing=5, h_spacing=3)
+ mirror_frame.setLayout(grid_mirror)
# ## Axis
self.mirax_label = FCLabel('%s:' % _("Axis"))
@@ -841,41 +849,63 @@ class DsidedUI:
{'label': 'X', 'value': 'X'},
{'label': 'Y', 'value': 'Y'}
],
- orientation='vertical',
- stretch=False
+ stretch=True
)
- grid2.addWidget(self.mirax_label, 2, 0)
- grid2.addWidget(self.mirror_axis, 2, 1, 1, 2)
+ grid_mirror.addWidget(self.mirax_label, 2, 0)
+ grid_mirror.addWidget(self.mirror_axis, 2, 1, 1, 2)
- # ## Axis Location
- self.axloc_label = FCLabel('%s:' % _("Reference"))
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
+ grid_mirror.addWidget(separator_line, 3, 0, 1, 3)
+
+ # ## Reference
+ self.axloc_label = FCLabel('%s:' % _("Reference"))
self.axloc_label.setToolTip(
_("The coordinates used as reference for the mirror operation.\n"
"Can be:\n"
"- Point -> a set of coordinates (x,y) around which the object is mirrored\n"
"- Box -> a set of coordinates (x, y) obtained from the center of the\n"
"bounding box of another object selected below\n"
- "- Hole Snap -> a point defined by the center of a drill hole in a Excellon object")
+ "- Snap -> a point defined by the center of a drill hole in a Excellon object")
)
self.axis_location = RadioSet(
[
{'label': _('Point'), 'value': 'point'},
{'label': _('Box'), 'value': 'box'},
- {'label': _('Hole Snap'), 'value': 'hole'},
- ]
+ {'label': _('Snap'), 'value': 'hole'},
+ ],
+ stretch=True
)
- grid2.addWidget(self.axloc_label, 4, 0)
- grid2.addWidget(self.axis_location, 4, 1, 1, 2)
+ grid_mirror.addWidget(self.axloc_label, 4, 0)
+ grid_mirror.addWidget(self.axis_location, 4, 1, 1, 2)
+
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
+ grid_mirror.addWidget(separator_line, 7, 0, 1, 3)
+
+ # #############################################################################################################
+ # ## Point Reference
+ # #############################################################################################################
+ self.pr_frame = QtWidgets.QFrame()
+ self.pr_frame.setContentsMargins(0, 0, 0, 0)
+ grid_mirror.addWidget(self.pr_frame, 9, 0, 1, 3)
- # ## Point/Box
self.point_entry = NumericalEvalTupleEntry(border_color='#0069A9')
self.point_entry.setPlaceholderText(_("Point coordinates"))
+ pr_hlay = QtWidgets.QHBoxLayout()
+ pr_hlay.setContentsMargins(0, 0, 0, 0)
+ self.pr_frame.setLayout(pr_hlay)
+
# Add a reference
- self.add_point_button = FCButton(_("Add"))
+ self.add_point_button = QtWidgets.QToolButton()
+ self.add_point_button.setToolButtonStyle(QtCore.Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
self.add_point_button.setIcon(QtGui.QIcon(self.app.resource_location + '/plus16.png'))
+ self.add_point_button.setText(_("Add"))
self.add_point_button.setToolTip(
_("Add the coordinates in format (x, y) through which the mirroring axis\n "
"selected in 'MIRROR AXIS' pass.\n"
@@ -888,41 +918,21 @@ class DsidedUI:
# font-weight: bold;
# }
# """)
- self.add_point_button.setMinimumWidth(60)
+ # self.add_point_button.setMinimumWidth(60)
- grid2.addWidget(self.point_entry, 7, 0, 1, 2)
- grid2.addWidget(self.add_point_button, 7, 2)
+ pr_hlay.addWidget(self.point_entry, stretch=1)
+ pr_hlay.addWidget(self.add_point_button)
- self.exc_hole_lbl = FCLabel('%s:' % _("Excellon"))
- self.exc_hole_lbl.setToolTip(
- _("Object that holds holes that can be picked as reference for mirroring.")
- )
+ # #############################################################################################################
+ # Box Reference
+ # #############################################################################################################
+ self.br_frame = QtWidgets.QFrame()
+ self.br_frame.setContentsMargins(0, 0, 0, 0)
+ grid_mirror.addWidget(self.br_frame, 11, 0, 1, 3)
- # Excellon Object that holds the holes
- self.exc_combo = FCComboBox()
- self.exc_combo.setModel(self.app.collection)
- self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
- self.exc_combo.is_last = True
-
- self.exc_hole_lbl.hide()
- self.exc_combo.hide()
-
- grid2.addWidget(self.exc_hole_lbl, 10, 0)
- grid2.addWidget(self.exc_combo, 10, 1, 1, 2)
-
- self.pick_hole_button = FCButton(_("Pick hole"))
- self.pick_hole_button.setToolTip(
- _("Click inside a drill hole that belong to the selected Excellon object,\n"
- "and the hole center coordinates will be copied to the Point field.")
- )
-
- self.pick_hole_button.hide()
-
- grid2.addWidget(self.pick_hole_button, 12, 0, 1, 3)
-
- # ## Grid Layout
- grid_lay3 = FCGridLayout(v_spacing=5, h_spacing=3)
- grid2.addLayout(grid_lay3, 14, 0, 1, 3)
+ grid_box_ref = FCGridLayout(v_spacing=5, h_spacing=3)
+ grid_box_ref.setContentsMargins(0, 0, 0, 0)
+ self.br_frame.setLayout(grid_box_ref)
# Type of object used as BOX reference
self.box_type_radio = RadioSet([{'label': _('Gerber'), 'value': 'grb'},
@@ -933,8 +943,7 @@ class DsidedUI:
"The coordinates of the center of the bounding box are used\n"
"as reference for mirror operation.")
)
- self.box_type_radio.hide()
- grid_lay3.addWidget(self.box_type_radio, 1, 0, 1, 2)
+ grid_box_ref.addWidget(self.box_type_radio, 0, 0, 1, 2)
# Object used as BOX reference
self.box_combo = FCComboBox()
@@ -942,11 +951,44 @@ class DsidedUI:
self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.box_combo.is_last = True
- self.box_combo.hide()
+ grid_box_ref.addWidget(self.box_combo, 2, 0, 1, 2)
- grid_lay3.addWidget(self.box_combo, 3, 0, 1, 2)
+ # #############################################################################################################
+ # Snap Hole Reference
+ # #############################################################################################################
+ self.sr_frame = QtWidgets.QFrame()
+ self.sr_frame.setContentsMargins(0, 0, 0, 0)
+ grid_mirror.addWidget(self.sr_frame, 13, 0, 1, 3)
+ grid_snap_ref = FCGridLayout(v_spacing=5, h_spacing=3)
+ grid_snap_ref.setContentsMargins(0, 0, 0, 0)
+ self.sr_frame.setLayout(grid_snap_ref)
+
+ self.exc_hole_lbl = FCLabel('%s:' % _("Excellon"))
+ self.exc_hole_lbl.setToolTip(
+ _("Object that holds holes that can be picked as reference for mirroring.")
+ )
+
+ # Excellon Object that holds the holes
+ self.exc_combo = FCComboBox()
+ self.exc_combo.setModel(self.app.collection)
+ self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
+ self.exc_combo.is_last = True
+
+ grid_snap_ref.addWidget(self.exc_hole_lbl, 0, 0, 1, 2)
+ grid_snap_ref.addWidget(self.exc_combo, 2, 0, 1, 2)
+
+ self.pick_hole_button = FCButton(_("Pick hole"))
+ self.pick_hole_button.setToolTip(
+ _("Click inside a drill hole that belong to the selected Excellon object,\n"
+ "and the hole center coordinates will be copied to the Point field.")
+ )
+
+ grid_snap_ref.addWidget(self.pick_hole_button, 4, 0, 1, 2)
+
+ # #############################################################################################################
# Mirror Button
+ # #############################################################################################################
self.mirror_button = FCButton(_("Mirror"))
self.mirror_button.setIcon(QtGui.QIcon(self.app.resource_location + '/doubleside16.png'))
self.mirror_button.setToolTip(
@@ -1006,8 +1048,7 @@ class DsidedUI:
{'label': 'X', 'value': 'X'},
{'label': 'Y', 'value': 'Y'}
],
- orientation='vertical',
- stretch=False
+ stretch=True
)
grid4.addWidget(self.align_ax_label, 4, 0)
@@ -1078,6 +1119,8 @@ class DsidedUI:
grid4.addLayout(drill_hlay, 10, 0, 1, 2)
+ FCGridLayout.set_common_column_size([grid_obj, grid_bounds, grid_mirror, grid_box_ref, grid4], 0)
+
# ## Buttons
self.create_excellon_button = FCButton(_("Create Excellon Object"))
self.create_excellon_button.setIcon(QtGui.QIcon(self.app.resource_location + '/drill32.png'))