|
@@ -22,7 +22,7 @@ if '_' not in builtins.__dict__:
|
|
|
|
|
|
|
|
class RulesCheck(FlatCAMTool):
|
|
class RulesCheck(FlatCAMTool):
|
|
|
|
|
|
|
|
- toolName = _("Check Rules PCB")
|
|
|
|
|
|
|
+ toolName = _("Check Rules")
|
|
|
|
|
|
|
|
def __init__(self, app):
|
|
def __init__(self, app):
|
|
|
super(RulesCheck, self).__init__(self)
|
|
super(RulesCheck, self).__init__(self)
|
|
@@ -40,205 +40,307 @@ class RulesCheck(FlatCAMTool):
|
|
|
self.layout.addWidget(title_label)
|
|
self.layout.addWidget(title_label)
|
|
|
|
|
|
|
|
# Form Layout
|
|
# Form Layout
|
|
|
- form_layout_0 = QtWidgets.QFormLayout()
|
|
|
|
|
- self.layout.addLayout(form_layout_0)
|
|
|
|
|
-
|
|
|
|
|
- # Type of object to be panelized
|
|
|
|
|
- self.type_obj_combo = QtWidgets.QComboBox()
|
|
|
|
|
- self.type_obj_combo.addItem("Gerber")
|
|
|
|
|
- self.type_obj_combo.addItem("Excellon")
|
|
|
|
|
- self.type_obj_combo.addItem("Geometry")
|
|
|
|
|
-
|
|
|
|
|
- self.type_obj_combo.setItemIcon(0, QtGui.QIcon("share/flatcam_icon16.png"))
|
|
|
|
|
- self.type_obj_combo.setItemIcon(1, QtGui.QIcon("share/drill16.png"))
|
|
|
|
|
- self.type_obj_combo.setItemIcon(2, QtGui.QIcon("share/geometry16.png"))
|
|
|
|
|
-
|
|
|
|
|
- self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
|
|
|
|
|
- self.type_obj_combo_label.setToolTip(
|
|
|
|
|
- _("Specify the type of object to be panelized\n"
|
|
|
|
|
- "It can be of type: Gerber, Excellon or Geometry.\n"
|
|
|
|
|
- "The selection here decide the type of objects that will be\n"
|
|
|
|
|
- "in the Object combobox.")
|
|
|
|
|
|
|
+ form_layout = QtWidgets.QFormLayout()
|
|
|
|
|
+ self.layout.addLayout(form_layout)
|
|
|
|
|
+
|
|
|
|
|
+ self.gerber_title_lbl = QtWidgets.QLabel('<b>%s</b>:' % _("Gerber Files"))
|
|
|
|
|
+ self.gerber_title_lbl.setToolTip(
|
|
|
|
|
+ _("Gerber files for which to check rules.")
|
|
|
)
|
|
)
|
|
|
- form_layout_0.addRow(self.type_obj_combo_label, self.type_obj_combo)
|
|
|
|
|
|
|
|
|
|
- # Object to be panelized
|
|
|
|
|
- self.object_combo = QtWidgets.QComboBox()
|
|
|
|
|
- self.object_combo.setModel(self.app.collection)
|
|
|
|
|
- self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
|
|
|
|
- self.object_combo.setCurrentIndex(1)
|
|
|
|
|
|
|
+ # Copper object
|
|
|
|
|
+ self.copper_object = QtWidgets.QComboBox()
|
|
|
|
|
+ self.copper_object.setModel(self.app.collection)
|
|
|
|
|
+ self.copper_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
|
|
|
|
+ self.copper_object.setCurrentIndex(1)
|
|
|
|
|
|
|
|
- self.object_label = QtWidgets.QLabel('%s:' % _("Object"))
|
|
|
|
|
- self.object_label.setToolTip(
|
|
|
|
|
|
|
+ self.copper_object_lbl = QtWidgets.QLabel('%s:' % _("Copper"))
|
|
|
|
|
+ self.copper_object_lbl.setToolTip(
|
|
|
_("Object to be panelized. This means that it will\n"
|
|
_("Object to be panelized. This means that it will\n"
|
|
|
"be duplicated in an array of rows and columns.")
|
|
"be duplicated in an array of rows and columns.")
|
|
|
)
|
|
)
|
|
|
- form_layout_0.addRow(self.object_label, self.object_combo)
|
|
|
|
|
- form_layout_0.addRow(QtWidgets.QLabel(""))
|
|
|
|
|
|
|
|
|
|
- # Form Layout
|
|
|
|
|
- form_layout = QtWidgets.QFormLayout()
|
|
|
|
|
- self.layout.addLayout(form_layout)
|
|
|
|
|
|
|
+ # SolderMask object
|
|
|
|
|
+ self.sm_object = QtWidgets.QComboBox()
|
|
|
|
|
+ self.sm_object.setModel(self.app.collection)
|
|
|
|
|
+ self.sm_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
|
|
|
|
+ self.sm_object.setCurrentIndex(1)
|
|
|
|
|
|
|
|
- # Type of box Panel object
|
|
|
|
|
- self.reference_radio = RadioSet([{'label': _('Object'), 'value': 'object'},
|
|
|
|
|
- {'label': _('Bounding Box'), 'value': 'bbox'}])
|
|
|
|
|
- self.box_label = QtWidgets.QLabel("<b>%s:</b>" % _("Penelization Reference"))
|
|
|
|
|
- self.box_label.setToolTip(
|
|
|
|
|
- _("Choose the reference for panelization:\n"
|
|
|
|
|
- "- Object = the bounding box of a different object\n"
|
|
|
|
|
- "- Bounding Box = the bounding box of the object to be panelized\n"
|
|
|
|
|
- "\n"
|
|
|
|
|
- "The reference is useful when doing panelization for more than one\n"
|
|
|
|
|
- "object. The spacings (really offsets) will be applied in reference\n"
|
|
|
|
|
- "to this reference object therefore maintaining the panelized\n"
|
|
|
|
|
- "objects in sync.")
|
|
|
|
|
|
|
+ self.sm_object_lbl = QtWidgets.QLabel('%s:' % _("SolderMask"))
|
|
|
|
|
+ self.sm_object_lbl.setToolTip(
|
|
|
|
|
+ _("Object to be panelized. This means that it will\n"
|
|
|
|
|
+ "be duplicated in an array of rows and columns.")
|
|
|
)
|
|
)
|
|
|
- form_layout.addRow(self.box_label)
|
|
|
|
|
- form_layout.addRow(self.reference_radio)
|
|
|
|
|
-
|
|
|
|
|
- # Type of Box Object to be used as an envelope for panelization
|
|
|
|
|
- self.type_box_combo = QtWidgets.QComboBox()
|
|
|
|
|
- self.type_box_combo.addItem("Gerber")
|
|
|
|
|
- self.type_box_combo.addItem("Excellon")
|
|
|
|
|
- self.type_box_combo.addItem("Geometry")
|
|
|
|
|
-
|
|
|
|
|
- # we get rid of item1 ("Excellon") as it is not suitable for use as a "box" for panelizing
|
|
|
|
|
- self.type_box_combo.view().setRowHidden(1, True)
|
|
|
|
|
- self.type_box_combo.setItemIcon(0, QtGui.QIcon("share/flatcam_icon16.png"))
|
|
|
|
|
- self.type_box_combo.setItemIcon(2, QtGui.QIcon("share/geometry16.png"))
|
|
|
|
|
-
|
|
|
|
|
- self.type_box_combo_label = QtWidgets.QLabel('%s:' % _("Box Type"))
|
|
|
|
|
- self.type_box_combo_label.setToolTip(
|
|
|
|
|
- _("Specify the type of object to be used as an container for\n"
|
|
|
|
|
- "panelization. It can be: Gerber or Geometry type.\n"
|
|
|
|
|
- "The selection here decide the type of objects that will be\n"
|
|
|
|
|
- "in the Box Object combobox.")
|
|
|
|
|
|
|
+
|
|
|
|
|
+ # SilkScreen object
|
|
|
|
|
+ self.ss_object = QtWidgets.QComboBox()
|
|
|
|
|
+ self.ss_object.setModel(self.app.collection)
|
|
|
|
|
+ self.ss_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
|
|
|
|
+ self.ss_object.setCurrentIndex(1)
|
|
|
|
|
+
|
|
|
|
|
+ self.ss_object_lbl = QtWidgets.QLabel('%s:' % _("Silkscreen"))
|
|
|
|
|
+ self.ss_object_lbl.setToolTip(
|
|
|
|
|
+ _("Object to be panelized. This means that it will\n"
|
|
|
|
|
+ "be duplicated in an array of rows and columns.")
|
|
|
)
|
|
)
|
|
|
- form_layout.addRow(self.type_box_combo_label, self.type_box_combo)
|
|
|
|
|
-
|
|
|
|
|
- # Box
|
|
|
|
|
- self.box_combo = QtWidgets.QComboBox()
|
|
|
|
|
- self.box_combo.setModel(self.app.collection)
|
|
|
|
|
- self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
|
|
|
|
- self.box_combo.setCurrentIndex(1)
|
|
|
|
|
-
|
|
|
|
|
- self.box_combo_label = QtWidgets.QLabel('%s:' % _("Box Object"))
|
|
|
|
|
- self.box_combo_label.setToolTip(
|
|
|
|
|
- _("The actual object that is used a container for the\n "
|
|
|
|
|
- "selected object that is to be panelized.")
|
|
|
|
|
|
|
+
|
|
|
|
|
+ # Outline object
|
|
|
|
|
+ self.outline_object = QtWidgets.QComboBox()
|
|
|
|
|
+ self.outline_object.setModel(self.app.collection)
|
|
|
|
|
+ self.outline_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
|
|
|
|
+ self.outline_object.setCurrentIndex(1)
|
|
|
|
|
+
|
|
|
|
|
+ self.outline_object_lbl = QtWidgets.QLabel('%s:' % _("Outline"))
|
|
|
|
|
+ self.outline_object_lbl.setToolTip(
|
|
|
|
|
+ _("Object to be panelized. This means that it will\n"
|
|
|
|
|
+ "be duplicated in an array of rows and columns.")
|
|
|
)
|
|
)
|
|
|
- form_layout.addRow(self.box_combo_label, self.box_combo)
|
|
|
|
|
|
|
+ form_layout.addRow(self.gerber_title_lbl)
|
|
|
|
|
+ form_layout.addRow(self.copper_object_lbl, self.copper_object)
|
|
|
|
|
+ form_layout.addRow(self.sm_object_lbl, self.sm_object)
|
|
|
|
|
+ form_layout.addRow(self.ss_object_lbl, self.ss_object)
|
|
|
|
|
+ form_layout.addRow(self.outline_object_lbl, self.outline_object)
|
|
|
form_layout.addRow(QtWidgets.QLabel(""))
|
|
form_layout.addRow(QtWidgets.QLabel(""))
|
|
|
|
|
|
|
|
- panel_data_label = QtWidgets.QLabel("<b>%s:</b>" % _("Panel Data"))
|
|
|
|
|
- panel_data_label.setToolTip(
|
|
|
|
|
- _("This informations will shape the resulting panel.\n"
|
|
|
|
|
- "The number of rows and columns will set how many\n"
|
|
|
|
|
- "duplicates of the original geometry will be generated.\n"
|
|
|
|
|
- "\n"
|
|
|
|
|
- "The spacings will set the distance between any two\n"
|
|
|
|
|
- "elements of the panel array.")
|
|
|
|
|
|
|
+ self.excellon_title_lbl = QtWidgets.QLabel('<b>%s</b>:' % _("Excellon Files"))
|
|
|
|
|
+ self.excellon_title_lbl.setToolTip(
|
|
|
|
|
+ _("Excellon files for which to check rules.")
|
|
|
)
|
|
)
|
|
|
- form_layout.addRow(panel_data_label)
|
|
|
|
|
-
|
|
|
|
|
- # Spacing Columns
|
|
|
|
|
- self.spacing_columns = FCEntry()
|
|
|
|
|
- self.spacing_columns_label = QtWidgets.QLabel('%s:' % _("Spacing cols"))
|
|
|
|
|
- self.spacing_columns_label.setToolTip(
|
|
|
|
|
- _("Spacing between columns of the desired panel.\n"
|
|
|
|
|
- "In current units.")
|
|
|
|
|
|
|
+
|
|
|
|
|
+ # Excellon 1 object
|
|
|
|
|
+ self.e1_object = QtWidgets.QComboBox()
|
|
|
|
|
+ self.e1_object.setModel(self.app.collection)
|
|
|
|
|
+ self.e1_object.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
|
|
|
|
|
+ self.e1_object.setCurrentIndex(1)
|
|
|
|
|
+
|
|
|
|
|
+ self.e1_object_lbl = QtWidgets.QLabel('%s:' % _("Excellon 1"))
|
|
|
|
|
+ self.e1_object_lbl.setToolTip(
|
|
|
|
|
+ _("Object to be panelized. This means that it will\n"
|
|
|
|
|
+ "be duplicated in an array of rows and columns.")
|
|
|
)
|
|
)
|
|
|
- form_layout.addRow(self.spacing_columns_label, self.spacing_columns)
|
|
|
|
|
-
|
|
|
|
|
- # Spacing Rows
|
|
|
|
|
- self.spacing_rows = FCEntry()
|
|
|
|
|
- self.spacing_rows_label = QtWidgets.QLabel('%s:' % _("Spacing rows"))
|
|
|
|
|
- self.spacing_rows_label.setToolTip(
|
|
|
|
|
- _("Spacing between rows of the desired panel.\n"
|
|
|
|
|
- "In current units.")
|
|
|
|
|
|
|
+
|
|
|
|
|
+ # Excellon 2 object
|
|
|
|
|
+ self.e2_object = QtWidgets.QComboBox()
|
|
|
|
|
+ self.e2_object.setModel(self.app.collection)
|
|
|
|
|
+ self.e2_object.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
|
|
|
|
|
+ self.e2_object.setCurrentIndex(1)
|
|
|
|
|
+
|
|
|
|
|
+ self.e2_object_lbl = QtWidgets.QLabel('%s:' % _("Excellon 2"))
|
|
|
|
|
+ self.e2_object_lbl.setToolTip(
|
|
|
|
|
+ _("Object to be panelized. This means that it will\n"
|
|
|
|
|
+ "be duplicated in an array of rows and columns.")
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ form_layout.addRow(self.excellon_title_lbl)
|
|
|
|
|
+ form_layout.addRow(self.e1_object_lbl, self.e1_object)
|
|
|
|
|
+ form_layout.addRow(self.e2_object_lbl, self.e2_object)
|
|
|
|
|
+ form_layout.addRow(QtWidgets.QLabel(""))
|
|
|
|
|
+
|
|
|
|
|
+ # Form Layout
|
|
|
|
|
+ form_layout_1 = QtWidgets.QFormLayout()
|
|
|
|
|
+ self.layout.addLayout(form_layout_1)
|
|
|
|
|
+
|
|
|
|
|
+ # Copper2copper clearance
|
|
|
|
|
+ self.clearance_copper2copper_cb = FCCheckBox('%s:' % _("Copper to copper clearance"))
|
|
|
|
|
+ self.clearance_copper2copper_cb.setToolTip(
|
|
|
|
|
+ _("This checks if the minimum clearance between copper\n"
|
|
|
|
|
+ "features is met.")
|
|
|
)
|
|
)
|
|
|
- form_layout.addRow(self.spacing_rows_label, self.spacing_rows)
|
|
|
|
|
|
|
+ form_layout_1.addRow(self.clearance_copper2copper_cb)
|
|
|
|
|
|
|
|
- # Columns
|
|
|
|
|
- self.columns = FCEntry()
|
|
|
|
|
- self.columns_label = QtWidgets.QLabel('%s:' % _("Columns"))
|
|
|
|
|
- self.columns_label.setToolTip(
|
|
|
|
|
- _("Number of columns of the desired panel")
|
|
|
|
|
|
|
+ # Copper2copper clearance value
|
|
|
|
|
+ self.clearance_copper2copper_entry = FCEntry()
|
|
|
|
|
+ self.clearance_copper2copper_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
|
|
|
|
|
+ self.clearance_copper2copper_lbl.setToolTip(
|
|
|
|
|
+ _("Minimum acceptable clearance value.")
|
|
|
)
|
|
)
|
|
|
- form_layout.addRow(self.columns_label, self.columns)
|
|
|
|
|
|
|
+ form_layout_1.addRow(self.clearance_copper2copper_lbl, self.clearance_copper2copper_entry)
|
|
|
|
|
|
|
|
- # Rows
|
|
|
|
|
- self.rows = FCEntry()
|
|
|
|
|
- self.rows_label = QtWidgets.QLabel('%s:' % _("Rows"))
|
|
|
|
|
- self.rows_label.setToolTip(
|
|
|
|
|
- _("Number of rows of the desired panel")
|
|
|
|
|
|
|
+ self.c2c = OptionalInputSection(
|
|
|
|
|
+ self.clearance_copper2copper_cb, [self.clearance_copper2copper_lbl, self.clearance_copper2copper_entry])
|
|
|
|
|
+
|
|
|
|
|
+ # Copper2soldermask clearance
|
|
|
|
|
+ self.clearance_copper2sm_cb = FCCheckBox('%s:' % _("Copper to soldermask clearance"))
|
|
|
|
|
+ self.clearance_copper2sm_cb.setToolTip(
|
|
|
|
|
+ _("This checks if the minimum clearance between copper\n"
|
|
|
|
|
+ "features and soldermask features is met.")
|
|
|
)
|
|
)
|
|
|
- form_layout.addRow(self.rows_label, self.rows)
|
|
|
|
|
- form_layout.addRow(QtWidgets.QLabel(""))
|
|
|
|
|
|
|
+ form_layout_1.addRow(self.clearance_copper2sm_cb)
|
|
|
|
|
|
|
|
- # Type of resulting Panel object
|
|
|
|
|
- self.panel_type_radio = RadioSet([{'label': _('Gerber'), 'value': 'gerber'},
|
|
|
|
|
- {'label': _('Geo'), 'value': 'geometry'}])
|
|
|
|
|
- self.panel_type_label = QtWidgets.QLabel("<b>%s:</b>" % _("Panel Type"))
|
|
|
|
|
- self.panel_type_label.setToolTip(
|
|
|
|
|
- _("Choose the type of object for the panel object:\n"
|
|
|
|
|
- "- Geometry\n"
|
|
|
|
|
- "- Gerber")
|
|
|
|
|
|
|
+ # Copper2soldermask clearance value
|
|
|
|
|
+ self.clearance_copper2sm_entry = FCEntry()
|
|
|
|
|
+ self.clearance_copper2sm_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
|
|
|
|
|
+ self.clearance_copper2sm_lbl.setToolTip(
|
|
|
|
|
+ _("Minimum acceptable clearance value.")
|
|
|
)
|
|
)
|
|
|
- form_layout.addRow(self.panel_type_label)
|
|
|
|
|
- form_layout.addRow(self.panel_type_radio)
|
|
|
|
|
-
|
|
|
|
|
- # Constrains
|
|
|
|
|
- self.constrain_cb = FCCheckBox('%s:' % _("Constrain panel within"))
|
|
|
|
|
- self.constrain_cb.setToolTip(
|
|
|
|
|
- _("Area define by DX and DY within to constrain the panel.\n"
|
|
|
|
|
- "DX and DY values are in current units.\n"
|
|
|
|
|
- "Regardless of how many columns and rows are desired,\n"
|
|
|
|
|
- "the final panel will have as many columns and rows as\n"
|
|
|
|
|
- "they fit completely within selected area.")
|
|
|
|
|
|
|
+ form_layout_1.addRow(self.clearance_copper2sm_lbl, self.clearance_copper2sm_entry)
|
|
|
|
|
+
|
|
|
|
|
+ self.c2sm = OptionalInputSection(
|
|
|
|
|
+ self.clearance_copper2sm_cb, [self.clearance_copper2sm_lbl, self.clearance_copper2sm_entry])
|
|
|
|
|
+
|
|
|
|
|
+ # Copper2silkscreen clearance
|
|
|
|
|
+ self.clearance_copper2sk_cb = FCCheckBox('%s:' % _("Copper to silkscreen clearance"))
|
|
|
|
|
+ self.clearance_copper2sk_cb.setToolTip(
|
|
|
|
|
+ _("This checks if the minimum clearance between copper\n"
|
|
|
|
|
+ "features and silkscreen features is met.")
|
|
|
|
|
+ )
|
|
|
|
|
+ form_layout_1.addRow(self.clearance_copper2sk_cb)
|
|
|
|
|
+
|
|
|
|
|
+ # Copper2silkscreen clearance value
|
|
|
|
|
+ self.clearance_copper2sk_entry = FCEntry()
|
|
|
|
|
+ self.clearance_copper2sk_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
|
|
|
|
|
+ self.clearance_copper2sk_lbl.setToolTip(
|
|
|
|
|
+ _("Minimum acceptable clearance value.")
|
|
|
|
|
+ )
|
|
|
|
|
+ form_layout_1.addRow(self.clearance_copper2sk_lbl, self.clearance_copper2sk_entry)
|
|
|
|
|
+
|
|
|
|
|
+ self.c2sk = OptionalInputSection(
|
|
|
|
|
+ self.clearance_copper2sk_cb, [self.clearance_copper2sk_lbl, self.clearance_copper2sk_entry])
|
|
|
|
|
+
|
|
|
|
|
+ # Copper2outline clearance
|
|
|
|
|
+ self.clearance_copper2ol_cb = FCCheckBox('%s:' % _("Copper to outline clearance"))
|
|
|
|
|
+ self.clearance_copper2ol_cb.setToolTip(
|
|
|
|
|
+ _("This checks if the minimum clearance between copper\n"
|
|
|
|
|
+ "features and the outline is met.")
|
|
|
)
|
|
)
|
|
|
- form_layout.addRow(self.constrain_cb)
|
|
|
|
|
|
|
+ form_layout_1.addRow(self.clearance_copper2ol_cb)
|
|
|
|
|
+
|
|
|
|
|
+ # Copper2outline clearance value
|
|
|
|
|
+ self.clearance_copper2ol_entry = FCEntry()
|
|
|
|
|
+ self.clearance_copper2ol_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
|
|
|
|
|
+ self.clearance_copper2ol_lbl.setToolTip(
|
|
|
|
|
+ _("Minimum acceptable clearance value.")
|
|
|
|
|
+ )
|
|
|
|
|
+ form_layout_1.addRow(self.clearance_copper2ol_lbl, self.clearance_copper2ol_entry)
|
|
|
|
|
+
|
|
|
|
|
+ self.c2ol = OptionalInputSection(
|
|
|
|
|
+ self.clearance_copper2ol_cb, [self.clearance_copper2ol_lbl, self.clearance_copper2ol_entry])
|
|
|
|
|
|
|
|
- self.x_width_entry = FCEntry()
|
|
|
|
|
- self.x_width_lbl = QtWidgets.QLabel('%s:' % _("Width (DX)"))
|
|
|
|
|
- self.x_width_lbl.setToolTip(
|
|
|
|
|
- _("The width (DX) within which the panel must fit.\n"
|
|
|
|
|
- "In current units.")
|
|
|
|
|
|
|
+ # Silkscreen2silkscreen clearance
|
|
|
|
|
+ self.clearance_silk2silk_cb = FCCheckBox('%s:' % _("Silkscreen to silkscreen clearance"))
|
|
|
|
|
+ self.clearance_silk2silk_cb.setToolTip(
|
|
|
|
|
+ _("This checks if the minimum clearance between silkscreen\n"
|
|
|
|
|
+ "features and silkscreen features is met.")
|
|
|
)
|
|
)
|
|
|
- form_layout.addRow(self.x_width_lbl, self.x_width_entry)
|
|
|
|
|
|
|
+ form_layout_1.addRow(self.clearance_silk2silk_cb)
|
|
|
|
|
|
|
|
- self.y_height_entry = FCEntry()
|
|
|
|
|
- self.y_height_lbl = QtWidgets.QLabel('%s:' % _("Height (DY)"))
|
|
|
|
|
- self.y_height_lbl.setToolTip(
|
|
|
|
|
- _("The height (DY)within which the panel must fit.\n"
|
|
|
|
|
- "In current units.")
|
|
|
|
|
|
|
+ # Copper2silkscreen clearance value
|
|
|
|
|
+ self.clearance_silk2silk_entry = FCEntry()
|
|
|
|
|
+ self.clearance_silk2silk_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
|
|
|
|
|
+ self.clearance_silk2silk_lbl.setToolTip(
|
|
|
|
|
+ _("Minimum acceptable clearance value.")
|
|
|
)
|
|
)
|
|
|
- form_layout.addRow(self.y_height_lbl, self.y_height_entry)
|
|
|
|
|
|
|
+ form_layout_1.addRow(self.clearance_silk2silk_lbl, self.clearance_silk2silk_entry)
|
|
|
|
|
|
|
|
- self.constrain_sel = OptionalInputSection(
|
|
|
|
|
- self.constrain_cb, [self.x_width_lbl, self.x_width_entry, self.y_height_lbl, self.y_height_entry])
|
|
|
|
|
|
|
+ self.s2s = OptionalInputSection(
|
|
|
|
|
+ self.clearance_silk2silk_cb, [self.clearance_silk2silk_lbl, self.clearance_silk2silk_entry])
|
|
|
|
|
+
|
|
|
|
|
+ # Silkscreen2soldermask clearance
|
|
|
|
|
+ self.clearance_silk2sm_cb = FCCheckBox('%s:' % _("Silkscreen to soldermask clearance"))
|
|
|
|
|
+ self.clearance_silk2sm_cb.setToolTip(
|
|
|
|
|
+ _("This checks if the minimum clearance between silkscreen\n"
|
|
|
|
|
+ "features and soldermask features is met.")
|
|
|
|
|
+ )
|
|
|
|
|
+ form_layout_1.addRow(self.clearance_silk2sm_cb)
|
|
|
|
|
+
|
|
|
|
|
+ # Silkscreen2soldermask clearance value
|
|
|
|
|
+ self.clearance_silk2sm_entry = FCEntry()
|
|
|
|
|
+ self.clearance_silk2sm_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
|
|
|
|
|
+ self.clearance_silk2sm_lbl.setToolTip(
|
|
|
|
|
+ _("Minimum acceptable clearance value.")
|
|
|
|
|
+ )
|
|
|
|
|
+ form_layout_1.addRow(self.clearance_silk2sm_lbl, self.clearance_silk2sm_entry)
|
|
|
|
|
+
|
|
|
|
|
+ self.s2sm = OptionalInputSection(
|
|
|
|
|
+ self.clearance_silk2sm_cb, [self.clearance_silk2sm_lbl, self.clearance_silk2sm_entry])
|
|
|
|
|
+
|
|
|
|
|
+ # Soldermask2soldermask clearance
|
|
|
|
|
+ self.clearance_sm2sm_cb = FCCheckBox('%s:' % _("Soldermask to soldermask clearance"))
|
|
|
|
|
+ self.clearance_sm2sm_cb.setToolTip(
|
|
|
|
|
+ _("This checks if the minimum clearance between soldermask\n"
|
|
|
|
|
+ "features and soldermask features is met.")
|
|
|
|
|
+ )
|
|
|
|
|
+ form_layout_1.addRow(self.clearance_sm2sm_cb)
|
|
|
|
|
+
|
|
|
|
|
+ # Soldermask2soldermask clearance value
|
|
|
|
|
+ self.clearance_sm2sm_entry = FCEntry()
|
|
|
|
|
+ self.clearance_sm2sm_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
|
|
|
|
|
+ self.clearance_sm2sm_lbl.setToolTip(
|
|
|
|
|
+ _("Minimum acceptable clearance value.")
|
|
|
|
|
+ )
|
|
|
|
|
+ form_layout_1.addRow(self.clearance_sm2sm_lbl, self.clearance_sm2sm_entry)
|
|
|
|
|
+
|
|
|
|
|
+ self.sm2sm = OptionalInputSection(
|
|
|
|
|
+ self.clearance_sm2sm_cb, [self.clearance_sm2sm_lbl, self.clearance_sm2sm_entry])
|
|
|
|
|
+
|
|
|
|
|
+ form_layout_1.addRow(QtWidgets.QLabel(""))
|
|
|
|
|
+
|
|
|
|
|
+ # Drill2Drill clearance
|
|
|
|
|
+ self.clearance_d2d_cb = FCCheckBox('%s:' % _("Drill hole to drill hole clearance"))
|
|
|
|
|
+ self.clearance_d2d_cb.setToolTip(
|
|
|
|
|
+ _("This checks if the minimum clearance between a drill hole\n"
|
|
|
|
|
+ "and another drill hole is met.")
|
|
|
|
|
+ )
|
|
|
|
|
+ form_layout_1.addRow(self.clearance_d2d_cb)
|
|
|
|
|
+
|
|
|
|
|
+ # Drill2Drill clearance value
|
|
|
|
|
+ self.clearance_d2d_entry = FCEntry()
|
|
|
|
|
+ self.clearance_d2d_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
|
|
|
|
|
+ self.clearance_d2d_lbl.setToolTip(
|
|
|
|
|
+ _("Minimum acceptable clearance value.")
|
|
|
|
|
+ )
|
|
|
|
|
+ form_layout_1.addRow(self.clearance_d2d_lbl, self.clearance_d2d_entry)
|
|
|
|
|
+
|
|
|
|
|
+ self.d2d = OptionalInputSection(
|
|
|
|
|
+ self.clearance_d2d_cb, [self.clearance_d2d_lbl, self.clearance_d2d_entry])
|
|
|
|
|
+
|
|
|
|
|
+ # Ring integrity check
|
|
|
|
|
+ self.ring_integrity_cb = FCCheckBox('%s:' % _("Ring integrity check"))
|
|
|
|
|
+ self.ring_integrity_cb.setToolTip(
|
|
|
|
|
+ _("This checks if the minimum copper ring left by drilling\n"
|
|
|
|
|
+ "a hole into a pad is met.")
|
|
|
|
|
+ )
|
|
|
|
|
+ form_layout_1.addRow(self.ring_integrity_cb)
|
|
|
|
|
+
|
|
|
|
|
+ # Ring integrity value
|
|
|
|
|
+ self.ring_integrity_entry = FCEntry()
|
|
|
|
|
+ self.ring_integrity_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
|
|
|
|
|
+ self.ring_integrity_lbl.setToolTip(
|
|
|
|
|
+ _("Minimum acceptable ring value.")
|
|
|
|
|
+ )
|
|
|
|
|
+ form_layout_1.addRow(self.ring_integrity_lbl, self.ring_integrity_entry)
|
|
|
|
|
+
|
|
|
|
|
+ self.d2d = OptionalInputSection(
|
|
|
|
|
+ self.ring_integrity_cb, [self.ring_integrity_lbl, self.ring_integrity_entry])
|
|
|
|
|
+
|
|
|
|
|
+ # Drill holes overlap check
|
|
|
|
|
+ self.drill_overlap_cb = FCCheckBox('%s:' % _("Drill hole overlap check"))
|
|
|
|
|
+ self.drill_overlap_cb.setToolTip(
|
|
|
|
|
+ _("This checks if drill holes are overlapping\n"
|
|
|
|
|
+ "one over another.")
|
|
|
|
|
+ )
|
|
|
|
|
+ form_layout_1.addRow(self.drill_overlap_cb)
|
|
|
|
|
|
|
|
# Buttons
|
|
# Buttons
|
|
|
hlay_2 = QtWidgets.QHBoxLayout()
|
|
hlay_2 = QtWidgets.QHBoxLayout()
|
|
|
self.layout.addLayout(hlay_2)
|
|
self.layout.addLayout(hlay_2)
|
|
|
|
|
|
|
|
- hlay_2.addStretch()
|
|
|
|
|
- self.panelize_object_button = QtWidgets.QPushButton(_("Panelize Object"))
|
|
|
|
|
- self.panelize_object_button.setToolTip(
|
|
|
|
|
|
|
+ # hlay_2.addStretch()
|
|
|
|
|
+ self.run_button = QtWidgets.QPushButton(_("Run Rules Check"))
|
|
|
|
|
+ self.run_button.setToolTip(
|
|
|
_("Panelize the specified object around the specified box.\n"
|
|
_("Panelize the specified object around the specified box.\n"
|
|
|
"In other words it creates multiple copies of the source object,\n"
|
|
"In other words it creates multiple copies of the source object,\n"
|
|
|
"arranged in a 2D array of rows and columns.")
|
|
"arranged in a 2D array of rows and columns.")
|
|
|
)
|
|
)
|
|
|
- hlay_2.addWidget(self.panelize_object_button)
|
|
|
|
|
|
|
+ hlay_2.addWidget(self.run_button)
|
|
|
|
|
|
|
|
self.layout.addStretch()
|
|
self.layout.addStretch()
|
|
|
|
|
|
|
|
- # Signals
|
|
|
|
|
- self.reference_radio.activated_custom.connect(self.on_reference_radio_changed)
|
|
|
|
|
- self.panelize_object_button.clicked.connect(self.on_panelize)
|
|
|
|
|
- self.type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
|
|
|
|
|
- self.type_box_combo.currentIndexChanged.connect(self.on_type_box_index_changed)
|
|
|
|
|
|
|
+ # #######################################################
|
|
|
|
|
+ # ################ SIGNALS ##############################
|
|
|
|
|
+ # #######################################################
|
|
|
|
|
+
|
|
|
|
|
+ # self.app.collection.rowsInserted.connect(self.on_object_loaded)
|
|
|
|
|
|
|
|
# list to hold the temporary objects
|
|
# list to hold the temporary objects
|
|
|
self.objs = []
|
|
self.objs = []
|
|
@@ -249,8 +351,11 @@ class RulesCheck(FlatCAMTool):
|
|
|
# flag to signal the constrain was activated
|
|
# flag to signal the constrain was activated
|
|
|
self.constrain_flag = False
|
|
self.constrain_flag = False
|
|
|
|
|
|
|
|
|
|
+ # def on_object_loaded(self, index, row):
|
|
|
|
|
+ # print(index.internalPointer().child_items[row].obj.options['name'], index.data())
|
|
|
|
|
+
|
|
|
def run(self, toggle=True):
|
|
def run(self, toggle=True):
|
|
|
- self.app.report_usage("ToolPanelize()")
|
|
|
|
|
|
|
+ self.app.report_usage("ToolRulesCheck()")
|
|
|
|
|
|
|
|
if toggle:
|
|
if toggle:
|
|
|
# if the splitter is hidden, display it, else hide it but only if the current widget is the same
|
|
# if the splitter is hidden, display it, else hide it but only if the current widget is the same
|
|
@@ -274,549 +379,485 @@ class RulesCheck(FlatCAMTool):
|
|
|
FlatCAMTool.run(self)
|
|
FlatCAMTool.run(self)
|
|
|
self.set_tool_ui()
|
|
self.set_tool_ui()
|
|
|
|
|
|
|
|
- self.app.ui.notebook.setTabText(2, _("Panel. Tool"))
|
|
|
|
|
|
|
+ self.app.ui.notebook.setTabText(2, _("Rules Tool"))
|
|
|
|
|
|
|
|
def install(self, icon=None, separator=None, **kwargs):
|
|
def install(self, icon=None, separator=None, **kwargs):
|
|
|
- FlatCAMTool.install(self, icon, separator, shortcut='ALT+Z', **kwargs)
|
|
|
|
|
|
|
+ FlatCAMTool.install(self, icon, separator, shortcut='ALT+R', **kwargs)
|
|
|
|
|
|
|
|
def set_tool_ui(self):
|
|
def set_tool_ui(self):
|
|
|
self.reset_fields()
|
|
self.reset_fields()
|
|
|
|
|
|
|
|
- self.reference_radio.set_value('bbox')
|
|
|
|
|
-
|
|
|
|
|
- sp_c = self.app.defaults["tools_panelize_spacing_columns"] if \
|
|
|
|
|
- self.app.defaults["tools_panelize_spacing_columns"] else 0.0
|
|
|
|
|
- self.spacing_columns.set_value(float(sp_c))
|
|
|
|
|
-
|
|
|
|
|
- sp_r = self.app.defaults["tools_panelize_spacing_rows"] if \
|
|
|
|
|
- self.app.defaults["tools_panelize_spacing_rows"] else 0.0
|
|
|
|
|
- self.spacing_rows.set_value(float(sp_r))
|
|
|
|
|
-
|
|
|
|
|
- rr = self.app.defaults["tools_panelize_rows"] if \
|
|
|
|
|
- self.app.defaults["tools_panelize_rows"] else 0.0
|
|
|
|
|
- self.rows.set_value(int(rr))
|
|
|
|
|
-
|
|
|
|
|
- cc = self.app.defaults["tools_panelize_columns"] if \
|
|
|
|
|
- self.app.defaults["tools_panelize_columns"] else 0.0
|
|
|
|
|
- self.columns.set_value(int(cc))
|
|
|
|
|
-
|
|
|
|
|
- c_cb = self.app.defaults["tools_panelize_constrain"] if \
|
|
|
|
|
- self.app.defaults["tools_panelize_constrain"] else False
|
|
|
|
|
- self.constrain_cb.set_value(c_cb)
|
|
|
|
|
-
|
|
|
|
|
- x_w = self.app.defaults["tools_panelize_constrainx"] if \
|
|
|
|
|
- self.app.defaults["tools_panelize_constrainx"] else 0.0
|
|
|
|
|
- self.x_width_entry.set_value(float(x_w))
|
|
|
|
|
-
|
|
|
|
|
- y_w = self.app.defaults["tools_panelize_constrainy"] if \
|
|
|
|
|
- self.app.defaults["tools_panelize_constrainy"] else 0.0
|
|
|
|
|
- self.y_height_entry.set_value(float(y_w))
|
|
|
|
|
-
|
|
|
|
|
- panel_type = self.app.defaults["tools_panelize_panel_type"] if \
|
|
|
|
|
- self.app.defaults["tools_panelize_panel_type"] else 'gerber'
|
|
|
|
|
- self.panel_type_radio.set_value(panel_type)
|
|
|
|
|
-
|
|
|
|
|
- def on_type_obj_index_changed(self):
|
|
|
|
|
- obj_type = self.type_obj_combo.currentIndex()
|
|
|
|
|
- self.object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
|
|
|
|
|
- self.object_combo.setCurrentIndex(0)
|
|
|
|
|
-
|
|
|
|
|
- # hide the panel type for Excellons, the panel can be only of type Geometry
|
|
|
|
|
- if self.type_obj_combo.currentText() != 'Excellon':
|
|
|
|
|
- self.panel_type_label.setDisabled(False)
|
|
|
|
|
- self.panel_type_radio.setDisabled(False)
|
|
|
|
|
- else:
|
|
|
|
|
- self.panel_type_label.setDisabled(True)
|
|
|
|
|
- self.panel_type_radio.setDisabled(True)
|
|
|
|
|
- self.panel_type_radio.set_value('geometry')
|
|
|
|
|
-
|
|
|
|
|
- def on_type_box_index_changed(self):
|
|
|
|
|
- obj_type = self.type_box_combo.currentIndex()
|
|
|
|
|
- self.box_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
|
|
|
|
|
- self.box_combo.setCurrentIndex(0)
|
|
|
|
|
-
|
|
|
|
|
- def on_reference_radio_changed(self, current_val):
|
|
|
|
|
- if current_val == 'object':
|
|
|
|
|
- self.type_box_combo.setDisabled(False)
|
|
|
|
|
- self.type_box_combo_label.setDisabled(False)
|
|
|
|
|
- self.box_combo.setDisabled(False)
|
|
|
|
|
- self.box_combo_label.setDisabled(False)
|
|
|
|
|
- else:
|
|
|
|
|
- self.type_box_combo.setDisabled(True)
|
|
|
|
|
- self.type_box_combo_label.setDisabled(True)
|
|
|
|
|
- self.box_combo.setDisabled(True)
|
|
|
|
|
- self.box_combo_label.setDisabled(True)
|
|
|
|
|
-
|
|
|
|
|
- def on_panelize(self):
|
|
|
|
|
- name = self.object_combo.currentText()
|
|
|
|
|
-
|
|
|
|
|
- # Get source object.
|
|
|
|
|
- try:
|
|
|
|
|
- obj = self.app.collection.get_by_name(str(name))
|
|
|
|
|
- except Exception as e:
|
|
|
|
|
- log.debug("Panelize.on_panelize() --> %s" % str(e))
|
|
|
|
|
- self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
|
|
|
|
|
- (_("Could not retrieve object"), name))
|
|
|
|
|
- return "Could not retrieve object: %s" % name
|
|
|
|
|
-
|
|
|
|
|
- panel_obj = obj
|
|
|
|
|
-
|
|
|
|
|
- if panel_obj is None:
|
|
|
|
|
- self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
|
|
|
|
|
- (_("Object not found"), panel_obj))
|
|
|
|
|
- return "Object not found: %s" % panel_obj
|
|
|
|
|
-
|
|
|
|
|
- boxname = self.box_combo.currentText()
|
|
|
|
|
-
|
|
|
|
|
- try:
|
|
|
|
|
- box = self.app.collection.get_by_name(boxname)
|
|
|
|
|
- except Exception as e:
|
|
|
|
|
- log.debug("Panelize.on_panelize() --> %s" % str(e))
|
|
|
|
|
- self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
|
|
|
|
|
- (_("Could not retrieve object"), boxname))
|
|
|
|
|
- return "Could not retrieve object: %s" % boxname
|
|
|
|
|
-
|
|
|
|
|
- if box is None:
|
|
|
|
|
- self.app.inform.emit('[WARNING_NOTCL]%s: %s' %
|
|
|
|
|
- (_("No object Box. Using instead"), panel_obj))
|
|
|
|
|
- self.reference_radio.set_value('bbox')
|
|
|
|
|
-
|
|
|
|
|
- if self.reference_radio.get_value() == 'bbox':
|
|
|
|
|
- box = panel_obj
|
|
|
|
|
-
|
|
|
|
|
- self.outname = name + '_panelized'
|
|
|
|
|
-
|
|
|
|
|
- try:
|
|
|
|
|
- spacing_columns = float(self.spacing_columns.get_value())
|
|
|
|
|
- except ValueError:
|
|
|
|
|
- # try to convert comma to decimal point. if it's still not working error message and return
|
|
|
|
|
- try:
|
|
|
|
|
- spacing_columns = float(self.spacing_columns.get_value().replace(',', '.'))
|
|
|
|
|
- except ValueError:
|
|
|
|
|
- self.app.inform.emit('[ERROR_NOTCL] %s' %
|
|
|
|
|
- _("Wrong value format entered, use a number."))
|
|
|
|
|
- return
|
|
|
|
|
- spacing_columns = spacing_columns if spacing_columns is not None else 0
|
|
|
|
|
-
|
|
|
|
|
- try:
|
|
|
|
|
- spacing_rows = float(self.spacing_rows.get_value())
|
|
|
|
|
- except ValueError:
|
|
|
|
|
- # try to convert comma to decimal point. if it's still not working error message and return
|
|
|
|
|
- try:
|
|
|
|
|
- spacing_rows = float(self.spacing_rows.get_value().replace(',', '.'))
|
|
|
|
|
- except ValueError:
|
|
|
|
|
- self.app.inform.emit('[ERROR_NOTCL] %s' %
|
|
|
|
|
- _("Wrong value format entered, use a number."))
|
|
|
|
|
- return
|
|
|
|
|
- spacing_rows = spacing_rows if spacing_rows is not None else 0
|
|
|
|
|
-
|
|
|
|
|
- try:
|
|
|
|
|
- rows = int(self.rows.get_value())
|
|
|
|
|
- except ValueError:
|
|
|
|
|
- # try to convert comma to decimal point. if it's still not working error message and return
|
|
|
|
|
- try:
|
|
|
|
|
- rows = float(self.rows.get_value().replace(',', '.'))
|
|
|
|
|
- rows = int(rows)
|
|
|
|
|
- except ValueError:
|
|
|
|
|
- self.app.inform.emit('[ERROR_NOTCL] %s' %
|
|
|
|
|
- _("Wrong value format entered, use a number."))
|
|
|
|
|
- return
|
|
|
|
|
- rows = rows if rows is not None else 1
|
|
|
|
|
-
|
|
|
|
|
- try:
|
|
|
|
|
- columns = int(self.columns.get_value())
|
|
|
|
|
- except ValueError:
|
|
|
|
|
- # try to convert comma to decimal point. if it's still not working error message and return
|
|
|
|
|
- try:
|
|
|
|
|
- columns = float(self.columns.get_value().replace(',', '.'))
|
|
|
|
|
- columns = int(columns)
|
|
|
|
|
- except ValueError:
|
|
|
|
|
- self.app.inform.emit('[ERROR_NOTCL] %s' %
|
|
|
|
|
- _("Wrong value format entered, use a number."))
|
|
|
|
|
- return
|
|
|
|
|
- columns = columns if columns is not None else 1
|
|
|
|
|
-
|
|
|
|
|
- try:
|
|
|
|
|
- constrain_dx = float(self.x_width_entry.get_value())
|
|
|
|
|
- except ValueError:
|
|
|
|
|
- # try to convert comma to decimal point. if it's still not working error message and return
|
|
|
|
|
- try:
|
|
|
|
|
- constrain_dx = float(self.x_width_entry.get_value().replace(',', '.'))
|
|
|
|
|
- except ValueError:
|
|
|
|
|
- self.app.inform.emit('[ERROR_NOTCL] %s' %
|
|
|
|
|
- _("Wrong value format entered, use a number."))
|
|
|
|
|
- return
|
|
|
|
|
-
|
|
|
|
|
- try:
|
|
|
|
|
- constrain_dy = float(self.y_height_entry.get_value())
|
|
|
|
|
- except ValueError:
|
|
|
|
|
- # try to convert comma to decimal point. if it's still not working error message and return
|
|
|
|
|
- try:
|
|
|
|
|
- constrain_dy = float(self.y_height_entry.get_value().replace(',', '.'))
|
|
|
|
|
- except ValueError:
|
|
|
|
|
- self.app.inform.emit('[ERROR_NOTCL] %s' %
|
|
|
|
|
- _("Wrong value format entered, use a number."))
|
|
|
|
|
- return
|
|
|
|
|
-
|
|
|
|
|
- panel_type = str(self.panel_type_radio.get_value())
|
|
|
|
|
-
|
|
|
|
|
- if 0 in {columns, rows}:
|
|
|
|
|
- self.app.inform.emit('[ERROR_NOTCL] %s' %
|
|
|
|
|
- _("Columns or Rows are zero value. Change them to a positive integer."))
|
|
|
|
|
- return "Columns or Rows are zero value. Change them to a positive integer."
|
|
|
|
|
-
|
|
|
|
|
- xmin, ymin, xmax, ymax = box.bounds()
|
|
|
|
|
- lenghtx = xmax - xmin + spacing_columns
|
|
|
|
|
- lenghty = ymax - ymin + spacing_rows
|
|
|
|
|
-
|
|
|
|
|
- # check if constrain within an area is desired
|
|
|
|
|
- if self.constrain_cb.isChecked():
|
|
|
|
|
- panel_lengthx = ((xmax - xmin) * columns) + (spacing_columns * (columns - 1))
|
|
|
|
|
- panel_lengthy = ((ymax - ymin) * rows) + (spacing_rows * (rows - 1))
|
|
|
|
|
-
|
|
|
|
|
- # adjust the number of columns and/or rows so the panel will fit within the panel constraint area
|
|
|
|
|
- if (panel_lengthx > constrain_dx) or (panel_lengthy > constrain_dy):
|
|
|
|
|
- self.constrain_flag = True
|
|
|
|
|
-
|
|
|
|
|
- while panel_lengthx > constrain_dx:
|
|
|
|
|
- columns -= 1
|
|
|
|
|
- panel_lengthx = ((xmax - xmin) * columns) + (spacing_columns * (columns - 1))
|
|
|
|
|
- while panel_lengthy > constrain_dy:
|
|
|
|
|
- rows -= 1
|
|
|
|
|
- panel_lengthy = ((ymax - ymin) * rows) + (spacing_rows * (rows - 1))
|
|
|
|
|
-
|
|
|
|
|
- def panelize_2():
|
|
|
|
|
- if panel_obj is not None:
|
|
|
|
|
- self.app.inform.emit(_("Generating panel ... "))
|
|
|
|
|
-
|
|
|
|
|
- self.app.progress.emit(0)
|
|
|
|
|
-
|
|
|
|
|
- def job_init_excellon(obj_fin, app_obj):
|
|
|
|
|
- currenty = 0.0
|
|
|
|
|
- self.app.progress.emit(10)
|
|
|
|
|
- obj_fin.tools = panel_obj.tools.copy()
|
|
|
|
|
- obj_fin.drills = []
|
|
|
|
|
- obj_fin.slots = []
|
|
|
|
|
- obj_fin.solid_geometry = []
|
|
|
|
|
-
|
|
|
|
|
- for option in panel_obj.options:
|
|
|
|
|
- if option is not 'name':
|
|
|
|
|
- try:
|
|
|
|
|
- obj_fin.options[option] = panel_obj.options[option]
|
|
|
|
|
- except KeyError:
|
|
|
|
|
- log.warning("Failed to copy option. %s" % str(option))
|
|
|
|
|
-
|
|
|
|
|
- geo_len_drills = len(panel_obj.drills) if panel_obj.drills else 0
|
|
|
|
|
- geo_len_slots = len(panel_obj.slots) if panel_obj.slots else 0
|
|
|
|
|
-
|
|
|
|
|
- element = 0
|
|
|
|
|
- for row in range(rows):
|
|
|
|
|
- currentx = 0.0
|
|
|
|
|
- for col in range(columns):
|
|
|
|
|
- element += 1
|
|
|
|
|
- disp_number = 0
|
|
|
|
|
- old_disp_number = 0
|
|
|
|
|
-
|
|
|
|
|
- if panel_obj.drills:
|
|
|
|
|
- drill_nr = 0
|
|
|
|
|
- for tool_dict in panel_obj.drills:
|
|
|
|
|
- if self.app.abort_flag:
|
|
|
|
|
- # graceful abort requested by the user
|
|
|
|
|
- raise FlatCAMApp.GracefulException
|
|
|
|
|
-
|
|
|
|
|
- point_offseted = affinity.translate(tool_dict['point'], currentx, currenty)
|
|
|
|
|
- obj_fin.drills.append(
|
|
|
|
|
- {
|
|
|
|
|
- "point": point_offseted,
|
|
|
|
|
- "tool": tool_dict['tool']
|
|
|
|
|
- }
|
|
|
|
|
- )
|
|
|
|
|
-
|
|
|
|
|
- drill_nr += 1
|
|
|
|
|
- disp_number = int(np.interp(drill_nr, [0, geo_len_drills], [0, 100]))
|
|
|
|
|
-
|
|
|
|
|
- if disp_number > old_disp_number and disp_number <= 100:
|
|
|
|
|
- self.app.proc_container.update_view_text(' %s: %d D:%d%%' %
|
|
|
|
|
- (_("Copy"),
|
|
|
|
|
- int(element),
|
|
|
|
|
- disp_number))
|
|
|
|
|
- old_disp_number = disp_number
|
|
|
|
|
-
|
|
|
|
|
- if panel_obj.slots:
|
|
|
|
|
- slot_nr = 0
|
|
|
|
|
- for tool_dict in panel_obj.slots:
|
|
|
|
|
- if self.app.abort_flag:
|
|
|
|
|
- # graceful abort requested by the user
|
|
|
|
|
- raise FlatCAMApp.GracefulException
|
|
|
|
|
-
|
|
|
|
|
- start_offseted = affinity.translate(tool_dict['start'], currentx, currenty)
|
|
|
|
|
- stop_offseted = affinity.translate(tool_dict['stop'], currentx, currenty)
|
|
|
|
|
- obj_fin.slots.append(
|
|
|
|
|
- {
|
|
|
|
|
- "start": start_offseted,
|
|
|
|
|
- "stop": stop_offseted,
|
|
|
|
|
- "tool": tool_dict['tool']
|
|
|
|
|
- }
|
|
|
|
|
- )
|
|
|
|
|
-
|
|
|
|
|
- slot_nr += 1
|
|
|
|
|
- disp_number = int(np.interp(slot_nr, [0, geo_len_slots], [0, 100]))
|
|
|
|
|
-
|
|
|
|
|
- if disp_number > old_disp_number and disp_number <= 100:
|
|
|
|
|
- self.app.proc_container.update_view_text(' %s: %d S:%d%%' %
|
|
|
|
|
- (_("Copy"),
|
|
|
|
|
- int(element),
|
|
|
|
|
- disp_number))
|
|
|
|
|
- old_disp_number = disp_number
|
|
|
|
|
-
|
|
|
|
|
- currentx += lenghtx
|
|
|
|
|
- currenty += lenghty
|
|
|
|
|
-
|
|
|
|
|
- obj_fin.create_geometry()
|
|
|
|
|
- obj_fin.zeros = panel_obj.zeros
|
|
|
|
|
- obj_fin.units = panel_obj.units
|
|
|
|
|
- self.app.proc_container.update_view_text('')
|
|
|
|
|
-
|
|
|
|
|
- def job_init_geometry(obj_fin, app_obj):
|
|
|
|
|
- currentx = 0.0
|
|
|
|
|
- currenty = 0.0
|
|
|
|
|
-
|
|
|
|
|
- def translate_recursion(geom):
|
|
|
|
|
- if type(geom) == list:
|
|
|
|
|
- geoms = list()
|
|
|
|
|
- for local_geom in geom:
|
|
|
|
|
- res_geo = translate_recursion(local_geom)
|
|
|
|
|
- try:
|
|
|
|
|
- geoms += res_geo
|
|
|
|
|
- except TypeError:
|
|
|
|
|
- geoms.append(res_geo)
|
|
|
|
|
- return geoms
|
|
|
|
|
- else:
|
|
|
|
|
- return affinity.translate(geom, xoff=currentx, yoff=currenty)
|
|
|
|
|
-
|
|
|
|
|
- obj_fin.solid_geometry = []
|
|
|
|
|
-
|
|
|
|
|
- # create the initial structure on which to create the panel
|
|
|
|
|
- if isinstance(panel_obj, FlatCAMGeometry):
|
|
|
|
|
- obj_fin.multigeo = panel_obj.multigeo
|
|
|
|
|
- obj_fin.tools = deepcopy(panel_obj.tools)
|
|
|
|
|
- if panel_obj.multigeo is True:
|
|
|
|
|
- for tool in panel_obj.tools:
|
|
|
|
|
- obj_fin.tools[tool]['solid_geometry'][:] = []
|
|
|
|
|
- elif isinstance(panel_obj, FlatCAMGerber):
|
|
|
|
|
- obj_fin.apertures = deepcopy(panel_obj.apertures)
|
|
|
|
|
- for ap in obj_fin.apertures:
|
|
|
|
|
- obj_fin.apertures[ap]['geometry'] = list()
|
|
|
|
|
-
|
|
|
|
|
- # find the number of polygons in the source solid_geometry
|
|
|
|
|
- geo_len = 0
|
|
|
|
|
- if isinstance(panel_obj, FlatCAMGeometry):
|
|
|
|
|
- if panel_obj.multigeo is True:
|
|
|
|
|
- for tool in panel_obj.tools:
|
|
|
|
|
- try:
|
|
|
|
|
- for pol in panel_obj.tools[tool]['solid_geometry']:
|
|
|
|
|
- geo_len += 1
|
|
|
|
|
- except TypeError:
|
|
|
|
|
- geo_len = 1
|
|
|
|
|
- else:
|
|
|
|
|
- try:
|
|
|
|
|
- for pol in panel_obj.solid_geometry:
|
|
|
|
|
- geo_len += 1
|
|
|
|
|
- except TypeError:
|
|
|
|
|
- geo_len = 1
|
|
|
|
|
- elif isinstance(panel_obj, FlatCAMGerber):
|
|
|
|
|
- for ap in panel_obj.apertures:
|
|
|
|
|
- for elem in panel_obj.apertures[ap]['geometry']:
|
|
|
|
|
- geo_len += 1
|
|
|
|
|
-
|
|
|
|
|
- self.app.progress.emit(0)
|
|
|
|
|
- element = 0
|
|
|
|
|
- for row in range(rows):
|
|
|
|
|
- currentx = 0.0
|
|
|
|
|
-
|
|
|
|
|
- for col in range(columns):
|
|
|
|
|
- element += 1
|
|
|
|
|
- disp_number = 0
|
|
|
|
|
- old_disp_number = 0
|
|
|
|
|
-
|
|
|
|
|
- if isinstance(panel_obj, FlatCAMGeometry):
|
|
|
|
|
- if panel_obj.multigeo is True:
|
|
|
|
|
- for tool in panel_obj.tools:
|
|
|
|
|
- if self.app.abort_flag:
|
|
|
|
|
- # graceful abort requested by the user
|
|
|
|
|
- raise FlatCAMApp.GracefulException
|
|
|
|
|
-
|
|
|
|
|
- # geo = translate_recursion(panel_obj.tools[tool]['solid_geometry'])
|
|
|
|
|
- # if isinstance(geo, list):
|
|
|
|
|
- # obj_fin.tools[tool]['solid_geometry'] += geo
|
|
|
|
|
- # else:
|
|
|
|
|
- # obj_fin.tools[tool]['solid_geometry'].append(geo)
|
|
|
|
|
-
|
|
|
|
|
- # calculate the number of polygons
|
|
|
|
|
- geo_len = len(panel_obj.tools[tool]['solid_geometry'])
|
|
|
|
|
- pol_nr = 0
|
|
|
|
|
- for geo_el in panel_obj.tools[tool]['solid_geometry']:
|
|
|
|
|
- trans_geo = translate_recursion(geo_el)
|
|
|
|
|
- obj_fin.tools[tool]['solid_geometry'].append(trans_geo)
|
|
|
|
|
-
|
|
|
|
|
- pol_nr += 1
|
|
|
|
|
- disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
|
|
|
|
|
-
|
|
|
|
|
- if old_disp_number < disp_number <= 100:
|
|
|
|
|
- self.app.proc_container.update_view_text(' %s: %d %d%%' %
|
|
|
|
|
- (_("Copy"),
|
|
|
|
|
- int(element),
|
|
|
|
|
- disp_number))
|
|
|
|
|
- old_disp_number = disp_number
|
|
|
|
|
- else:
|
|
|
|
|
- # geo = translate_recursion(panel_obj.solid_geometry)
|
|
|
|
|
- # if isinstance(geo, list):
|
|
|
|
|
- # obj_fin.solid_geometry += geo
|
|
|
|
|
- # else:
|
|
|
|
|
- # obj_fin.solid_geometry.append(geo)
|
|
|
|
|
- if self.app.abort_flag:
|
|
|
|
|
- # graceful abort requested by the user
|
|
|
|
|
- raise FlatCAMApp.GracefulException
|
|
|
|
|
-
|
|
|
|
|
- try:
|
|
|
|
|
- # calculate the number of polygons
|
|
|
|
|
- geo_len = len(panel_obj.solid_geometry)
|
|
|
|
|
- except TypeError:
|
|
|
|
|
- geo_len = 1
|
|
|
|
|
- pol_nr = 0
|
|
|
|
|
- try:
|
|
|
|
|
- for geo_el in panel_obj.solid_geometry:
|
|
|
|
|
- if self.app.abort_flag:
|
|
|
|
|
- # graceful abort requested by the user
|
|
|
|
|
- raise FlatCAMApp.GracefulException
|
|
|
|
|
-
|
|
|
|
|
- trans_geo = translate_recursion(geo_el)
|
|
|
|
|
- obj_fin.solid_geometry.append(trans_geo)
|
|
|
|
|
-
|
|
|
|
|
- pol_nr += 1
|
|
|
|
|
- disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
|
|
|
|
|
-
|
|
|
|
|
- if old_disp_number < disp_number <= 100:
|
|
|
|
|
- self.app.proc_container.update_view_text(' %s: %d %d%%' %
|
|
|
|
|
- (_("Copy"),
|
|
|
|
|
- int(element),
|
|
|
|
|
- disp_number))
|
|
|
|
|
- old_disp_number = disp_number
|
|
|
|
|
- except TypeError:
|
|
|
|
|
- trans_geo = translate_recursion(panel_obj.solid_geometry)
|
|
|
|
|
- obj_fin.solid_geometry.append(trans_geo)
|
|
|
|
|
- else:
|
|
|
|
|
- # geo = translate_recursion(panel_obj.solid_geometry)
|
|
|
|
|
- # if isinstance(geo, list):
|
|
|
|
|
- # obj_fin.solid_geometry += geo
|
|
|
|
|
- # else:
|
|
|
|
|
- # obj_fin.solid_geometry.append(geo)
|
|
|
|
|
- if self.app.abort_flag:
|
|
|
|
|
- # graceful abort requested by the user
|
|
|
|
|
- raise FlatCAMApp.GracefulException
|
|
|
|
|
-
|
|
|
|
|
- try:
|
|
|
|
|
- for geo_el in panel_obj.solid_geometry:
|
|
|
|
|
- if self.app.abort_flag:
|
|
|
|
|
- # graceful abort requested by the user
|
|
|
|
|
- raise FlatCAMApp.GracefulException
|
|
|
|
|
-
|
|
|
|
|
- trans_geo = translate_recursion(geo_el)
|
|
|
|
|
- obj_fin.solid_geometry.append(trans_geo)
|
|
|
|
|
- except TypeError:
|
|
|
|
|
- trans_geo = translate_recursion(panel_obj.solid_geometry)
|
|
|
|
|
- obj_fin.solid_geometry.append(trans_geo)
|
|
|
|
|
-
|
|
|
|
|
- for apid in panel_obj.apertures:
|
|
|
|
|
- if self.app.abort_flag:
|
|
|
|
|
- # graceful abort requested by the user
|
|
|
|
|
- raise FlatCAMApp.GracefulException
|
|
|
|
|
-
|
|
|
|
|
- try:
|
|
|
|
|
- # calculate the number of polygons
|
|
|
|
|
- geo_len = len(panel_obj.apertures[apid]['geometry'])
|
|
|
|
|
- except TypeError:
|
|
|
|
|
- geo_len = 1
|
|
|
|
|
- pol_nr = 0
|
|
|
|
|
- for el in panel_obj.apertures[apid]['geometry']:
|
|
|
|
|
- if self.app.abort_flag:
|
|
|
|
|
- # graceful abort requested by the user
|
|
|
|
|
- raise FlatCAMApp.GracefulException
|
|
|
|
|
-
|
|
|
|
|
- new_el = dict()
|
|
|
|
|
- if 'solid' in el:
|
|
|
|
|
- geo_aper = translate_recursion(el['solid'])
|
|
|
|
|
- new_el['solid'] = geo_aper
|
|
|
|
|
-
|
|
|
|
|
- if 'clear' in el:
|
|
|
|
|
- geo_aper = translate_recursion(el['clear'])
|
|
|
|
|
- new_el['clear'] = geo_aper
|
|
|
|
|
-
|
|
|
|
|
- if 'follow' in el:
|
|
|
|
|
- geo_aper = translate_recursion(el['follow'])
|
|
|
|
|
- new_el['follow'] = geo_aper
|
|
|
|
|
-
|
|
|
|
|
- obj_fin.apertures[apid]['geometry'].append(deepcopy(new_el))
|
|
|
|
|
-
|
|
|
|
|
- pol_nr += 1
|
|
|
|
|
- disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
|
|
|
|
|
-
|
|
|
|
|
- if old_disp_number < disp_number <= 100:
|
|
|
|
|
- self.app.proc_container.update_view_text(' %s: %d %d%%' %
|
|
|
|
|
- (_("Copy"),
|
|
|
|
|
- int(element),
|
|
|
|
|
- disp_number))
|
|
|
|
|
- old_disp_number = disp_number
|
|
|
|
|
-
|
|
|
|
|
- currentx += lenghtx
|
|
|
|
|
- currenty += lenghty
|
|
|
|
|
-
|
|
|
|
|
- if panel_type == 'gerber':
|
|
|
|
|
- self.app.inform.emit('%s' %
|
|
|
|
|
- _("Generating panel ... Adding the Gerber code."))
|
|
|
|
|
- obj_fin.source_file = self.app.export_gerber(obj_name=self.outname, filename=None,
|
|
|
|
|
- local_use=obj_fin, use_thread=False)
|
|
|
|
|
-
|
|
|
|
|
- # app_obj.log.debug("Found %s geometries. Creating a panel geometry cascaded union ..." %
|
|
|
|
|
- # len(obj_fin.solid_geometry))
|
|
|
|
|
-
|
|
|
|
|
- # obj_fin.solid_geometry = cascaded_union(obj_fin.solid_geometry)
|
|
|
|
|
- # app_obj.log.debug("Finished creating a cascaded union for the panel.")
|
|
|
|
|
- self.app.proc_container.update_view_text('')
|
|
|
|
|
-
|
|
|
|
|
- self.app.inform.emit('%s: %d' %
|
|
|
|
|
- (_("Generating panel... Spawning copies"), (int(rows * columns))))
|
|
|
|
|
- if isinstance(panel_obj, FlatCAMExcellon):
|
|
|
|
|
- self.app.progress.emit(50)
|
|
|
|
|
- self.app.new_object("excellon", self.outname, job_init_excellon, plot=True, autoselected=True)
|
|
|
|
|
- else:
|
|
|
|
|
- self.app.progress.emit(50)
|
|
|
|
|
- self.app.new_object(panel_type, self.outname, job_init_geometry,
|
|
|
|
|
- plot=True, autoselected=True)
|
|
|
|
|
-
|
|
|
|
|
- if self.constrain_flag is False:
|
|
|
|
|
- self.app.inform.emit('[success] %s' % _("Panel done..."))
|
|
|
|
|
- else:
|
|
|
|
|
- self.constrain_flag = False
|
|
|
|
|
- self.app.inform.emit(_("{text} Too big for the constrain area. "
|
|
|
|
|
- "Final panel has {col} columns and {row} rows").format(
|
|
|
|
|
- text='[WARNING] ', col=columns, row=rows))
|
|
|
|
|
-
|
|
|
|
|
- proc = self.app.proc_container.new(_("Working..."))
|
|
|
|
|
-
|
|
|
|
|
- def job_thread(app_obj):
|
|
|
|
|
- try:
|
|
|
|
|
- panelize_2()
|
|
|
|
|
- self.app.inform.emit('[success] %s' % _("Panel created successfully."))
|
|
|
|
|
- except Exception as ee:
|
|
|
|
|
- proc.done()
|
|
|
|
|
- log.debug(str(ee))
|
|
|
|
|
- return
|
|
|
|
|
- proc.done()
|
|
|
|
|
-
|
|
|
|
|
- self.app.collection.promise(self.outname)
|
|
|
|
|
- self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
|
|
|
|
|
|
|
+ # def on_panelize(self):
|
|
|
|
|
+ # name = self.object_combo.currentText()
|
|
|
|
|
+ #
|
|
|
|
|
+ # # Get source object.
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # obj = self.app.collection.get_by_name(str(name))
|
|
|
|
|
+ # except Exception as e:
|
|
|
|
|
+ # log.debug("Panelize.on_panelize() --> %s" % str(e))
|
|
|
|
|
+ # self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
|
|
|
|
|
+ # (_("Could not retrieve object"), name))
|
|
|
|
|
+ # return "Could not retrieve object: %s" % name
|
|
|
|
|
+ #
|
|
|
|
|
+ # panel_obj = obj
|
|
|
|
|
+ #
|
|
|
|
|
+ # if panel_obj is None:
|
|
|
|
|
+ # self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
|
|
|
|
|
+ # (_("Object not found"), panel_obj))
|
|
|
|
|
+ # return "Object not found: %s" % panel_obj
|
|
|
|
|
+ #
|
|
|
|
|
+ # boxname = self.box_combo.currentText()
|
|
|
|
|
+ #
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # box = self.app.collection.get_by_name(boxname)
|
|
|
|
|
+ # except Exception as e:
|
|
|
|
|
+ # log.debug("Panelize.on_panelize() --> %s" % str(e))
|
|
|
|
|
+ # self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
|
|
|
|
|
+ # (_("Could not retrieve object"), boxname))
|
|
|
|
|
+ # return "Could not retrieve object: %s" % boxname
|
|
|
|
|
+ #
|
|
|
|
|
+ # if box is None:
|
|
|
|
|
+ # self.app.inform.emit('[WARNING_NOTCL]%s: %s' %
|
|
|
|
|
+ # (_("No object Box. Using instead"), panel_obj))
|
|
|
|
|
+ # self.reference_radio.set_value('bbox')
|
|
|
|
|
+ #
|
|
|
|
|
+ # if self.reference_radio.get_value() == 'bbox':
|
|
|
|
|
+ # box = panel_obj
|
|
|
|
|
+ #
|
|
|
|
|
+ # self.outname = name + '_panelized'
|
|
|
|
|
+ #
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # spacing_columns = float(self.spacing_columns.get_value())
|
|
|
|
|
+ # except ValueError:
|
|
|
|
|
+ # # try to convert comma to decimal point. if it's still not working error message and return
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # spacing_columns = float(self.spacing_columns.get_value().replace(',', '.'))
|
|
|
|
|
+ # except ValueError:
|
|
|
|
|
+ # self.app.inform.emit('[ERROR_NOTCL] %s' %
|
|
|
|
|
+ # _("Wrong value format entered, use a number."))
|
|
|
|
|
+ # return
|
|
|
|
|
+ # spacing_columns = spacing_columns if spacing_columns is not None else 0
|
|
|
|
|
+ #
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # spacing_rows = float(self.spacing_rows.get_value())
|
|
|
|
|
+ # except ValueError:
|
|
|
|
|
+ # # try to convert comma to decimal point. if it's still not working error message and return
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # spacing_rows = float(self.spacing_rows.get_value().replace(',', '.'))
|
|
|
|
|
+ # except ValueError:
|
|
|
|
|
+ # self.app.inform.emit('[ERROR_NOTCL] %s' %
|
|
|
|
|
+ # _("Wrong value format entered, use a number."))
|
|
|
|
|
+ # return
|
|
|
|
|
+ # spacing_rows = spacing_rows if spacing_rows is not None else 0
|
|
|
|
|
+ #
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # rows = int(self.rows.get_value())
|
|
|
|
|
+ # except ValueError:
|
|
|
|
|
+ # # try to convert comma to decimal point. if it's still not working error message and return
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # rows = float(self.rows.get_value().replace(',', '.'))
|
|
|
|
|
+ # rows = int(rows)
|
|
|
|
|
+ # except ValueError:
|
|
|
|
|
+ # self.app.inform.emit('[ERROR_NOTCL] %s' %
|
|
|
|
|
+ # _("Wrong value format entered, use a number."))
|
|
|
|
|
+ # return
|
|
|
|
|
+ # rows = rows if rows is not None else 1
|
|
|
|
|
+ #
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # columns = int(self.columns.get_value())
|
|
|
|
|
+ # except ValueError:
|
|
|
|
|
+ # # try to convert comma to decimal point. if it's still not working error message and return
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # columns = float(self.columns.get_value().replace(',', '.'))
|
|
|
|
|
+ # columns = int(columns)
|
|
|
|
|
+ # except ValueError:
|
|
|
|
|
+ # self.app.inform.emit('[ERROR_NOTCL] %s' %
|
|
|
|
|
+ # _("Wrong value format entered, use a number."))
|
|
|
|
|
+ # return
|
|
|
|
|
+ # columns = columns if columns is not None else 1
|
|
|
|
|
+ #
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # constrain_dx = float(self.x_width_entry.get_value())
|
|
|
|
|
+ # except ValueError:
|
|
|
|
|
+ # # try to convert comma to decimal point. if it's still not working error message and return
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # constrain_dx = float(self.x_width_entry.get_value().replace(',', '.'))
|
|
|
|
|
+ # except ValueError:
|
|
|
|
|
+ # self.app.inform.emit('[ERROR_NOTCL] %s' %
|
|
|
|
|
+ # _("Wrong value format entered, use a number."))
|
|
|
|
|
+ # return
|
|
|
|
|
+ #
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # constrain_dy = float(self.y_height_entry.get_value())
|
|
|
|
|
+ # except ValueError:
|
|
|
|
|
+ # # try to convert comma to decimal point. if it's still not working error message and return
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # constrain_dy = float(self.y_height_entry.get_value().replace(',', '.'))
|
|
|
|
|
+ # except ValueError:
|
|
|
|
|
+ # self.app.inform.emit('[ERROR_NOTCL] %s' %
|
|
|
|
|
+ # _("Wrong value format entered, use a number."))
|
|
|
|
|
+ # return
|
|
|
|
|
+ #
|
|
|
|
|
+ # panel_type = str(self.panel_type_radio.get_value())
|
|
|
|
|
+ #
|
|
|
|
|
+ # if 0 in {columns, rows}:
|
|
|
|
|
+ # self.app.inform.emit('[ERROR_NOTCL] %s' %
|
|
|
|
|
+ # _("Columns or Rows are zero value. Change them to a positive integer."))
|
|
|
|
|
+ # return "Columns or Rows are zero value. Change them to a positive integer."
|
|
|
|
|
+ #
|
|
|
|
|
+ # xmin, ymin, xmax, ymax = box.bounds()
|
|
|
|
|
+ # lenghtx = xmax - xmin + spacing_columns
|
|
|
|
|
+ # lenghty = ymax - ymin + spacing_rows
|
|
|
|
|
+ #
|
|
|
|
|
+ # # check if constrain within an area is desired
|
|
|
|
|
+ # if self.constrain_cb.isChecked():
|
|
|
|
|
+ # panel_lengthx = ((xmax - xmin) * columns) + (spacing_columns * (columns - 1))
|
|
|
|
|
+ # panel_lengthy = ((ymax - ymin) * rows) + (spacing_rows * (rows - 1))
|
|
|
|
|
+ #
|
|
|
|
|
+ # # adjust the number of columns and/or rows so the panel will fit within the panel constraint area
|
|
|
|
|
+ # if (panel_lengthx > constrain_dx) or (panel_lengthy > constrain_dy):
|
|
|
|
|
+ # self.constrain_flag = True
|
|
|
|
|
+ #
|
|
|
|
|
+ # while panel_lengthx > constrain_dx:
|
|
|
|
|
+ # columns -= 1
|
|
|
|
|
+ # panel_lengthx = ((xmax - xmin) * columns) + (spacing_columns * (columns - 1))
|
|
|
|
|
+ # while panel_lengthy > constrain_dy:
|
|
|
|
|
+ # rows -= 1
|
|
|
|
|
+ # panel_lengthy = ((ymax - ymin) * rows) + (spacing_rows * (rows - 1))
|
|
|
|
|
+ #
|
|
|
|
|
+ # def panelize_2():
|
|
|
|
|
+ # if panel_obj is not None:
|
|
|
|
|
+ # self.app.inform.emit(_("Generating panel ... "))
|
|
|
|
|
+ #
|
|
|
|
|
+ # self.app.progress.emit(0)
|
|
|
|
|
+ #
|
|
|
|
|
+ # def job_init_excellon(obj_fin, app_obj):
|
|
|
|
|
+ # currenty = 0.0
|
|
|
|
|
+ # self.app.progress.emit(10)
|
|
|
|
|
+ # obj_fin.tools = panel_obj.tools.copy()
|
|
|
|
|
+ # obj_fin.drills = []
|
|
|
|
|
+ # obj_fin.slots = []
|
|
|
|
|
+ # obj_fin.solid_geometry = []
|
|
|
|
|
+ #
|
|
|
|
|
+ # for option in panel_obj.options:
|
|
|
|
|
+ # if option is not 'name':
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # obj_fin.options[option] = panel_obj.options[option]
|
|
|
|
|
+ # except KeyError:
|
|
|
|
|
+ # log.warning("Failed to copy option. %s" % str(option))
|
|
|
|
|
+ #
|
|
|
|
|
+ # geo_len_drills = len(panel_obj.drills) if panel_obj.drills else 0
|
|
|
|
|
+ # geo_len_slots = len(panel_obj.slots) if panel_obj.slots else 0
|
|
|
|
|
+ #
|
|
|
|
|
+ # element = 0
|
|
|
|
|
+ # for row in range(rows):
|
|
|
|
|
+ # currentx = 0.0
|
|
|
|
|
+ # for col in range(columns):
|
|
|
|
|
+ # element += 1
|
|
|
|
|
+ # disp_number = 0
|
|
|
|
|
+ # old_disp_number = 0
|
|
|
|
|
+ #
|
|
|
|
|
+ # if panel_obj.drills:
|
|
|
|
|
+ # drill_nr = 0
|
|
|
|
|
+ # for tool_dict in panel_obj.drills:
|
|
|
|
|
+ # if self.app.abort_flag:
|
|
|
|
|
+ # # graceful abort requested by the user
|
|
|
|
|
+ # raise FlatCAMApp.GracefulException
|
|
|
|
|
+ #
|
|
|
|
|
+ # point_offseted = affinity.translate(tool_dict['point'], currentx, currenty)
|
|
|
|
|
+ # obj_fin.drills.append(
|
|
|
|
|
+ # {
|
|
|
|
|
+ # "point": point_offseted,
|
|
|
|
|
+ # "tool": tool_dict['tool']
|
|
|
|
|
+ # }
|
|
|
|
|
+ # )
|
|
|
|
|
+ #
|
|
|
|
|
+ # drill_nr += 1
|
|
|
|
|
+ # disp_number = int(np.interp(drill_nr, [0, geo_len_drills], [0, 100]))
|
|
|
|
|
+ #
|
|
|
|
|
+ # if disp_number > old_disp_number and disp_number <= 100:
|
|
|
|
|
+ # self.app.proc_container.update_view_text(' %s: %d D:%d%%' %
|
|
|
|
|
+ # (_("Copy"),
|
|
|
|
|
+ # int(element),
|
|
|
|
|
+ # disp_number))
|
|
|
|
|
+ # old_disp_number = disp_number
|
|
|
|
|
+ #
|
|
|
|
|
+ # if panel_obj.slots:
|
|
|
|
|
+ # slot_nr = 0
|
|
|
|
|
+ # for tool_dict in panel_obj.slots:
|
|
|
|
|
+ # if self.app.abort_flag:
|
|
|
|
|
+ # # graceful abort requested by the user
|
|
|
|
|
+ # raise FlatCAMApp.GracefulException
|
|
|
|
|
+ #
|
|
|
|
|
+ # start_offseted = affinity.translate(tool_dict['start'], currentx, currenty)
|
|
|
|
|
+ # stop_offseted = affinity.translate(tool_dict['stop'], currentx, currenty)
|
|
|
|
|
+ # obj_fin.slots.append(
|
|
|
|
|
+ # {
|
|
|
|
|
+ # "start": start_offseted,
|
|
|
|
|
+ # "stop": stop_offseted,
|
|
|
|
|
+ # "tool": tool_dict['tool']
|
|
|
|
|
+ # }
|
|
|
|
|
+ # )
|
|
|
|
|
+ #
|
|
|
|
|
+ # slot_nr += 1
|
|
|
|
|
+ # disp_number = int(np.interp(slot_nr, [0, geo_len_slots], [0, 100]))
|
|
|
|
|
+ #
|
|
|
|
|
+ # if disp_number > old_disp_number and disp_number <= 100:
|
|
|
|
|
+ # self.app.proc_container.update_view_text(' %s: %d S:%d%%' %
|
|
|
|
|
+ # (_("Copy"),
|
|
|
|
|
+ # int(element),
|
|
|
|
|
+ # disp_number))
|
|
|
|
|
+ # old_disp_number = disp_number
|
|
|
|
|
+ #
|
|
|
|
|
+ # currentx += lenghtx
|
|
|
|
|
+ # currenty += lenghty
|
|
|
|
|
+ #
|
|
|
|
|
+ # obj_fin.create_geometry()
|
|
|
|
|
+ # obj_fin.zeros = panel_obj.zeros
|
|
|
|
|
+ # obj_fin.units = panel_obj.units
|
|
|
|
|
+ # self.app.proc_container.update_view_text('')
|
|
|
|
|
+ #
|
|
|
|
|
+ # def job_init_geometry(obj_fin, app_obj):
|
|
|
|
|
+ # currentx = 0.0
|
|
|
|
|
+ # currenty = 0.0
|
|
|
|
|
+ #
|
|
|
|
|
+ # def translate_recursion(geom):
|
|
|
|
|
+ # if type(geom) == list:
|
|
|
|
|
+ # geoms = list()
|
|
|
|
|
+ # for local_geom in geom:
|
|
|
|
|
+ # res_geo = translate_recursion(local_geom)
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # geoms += res_geo
|
|
|
|
|
+ # except TypeError:
|
|
|
|
|
+ # geoms.append(res_geo)
|
|
|
|
|
+ # return geoms
|
|
|
|
|
+ # else:
|
|
|
|
|
+ # return affinity.translate(geom, xoff=currentx, yoff=currenty)
|
|
|
|
|
+ #
|
|
|
|
|
+ # obj_fin.solid_geometry = []
|
|
|
|
|
+ #
|
|
|
|
|
+ # # create the initial structure on which to create the panel
|
|
|
|
|
+ # if isinstance(panel_obj, FlatCAMGeometry):
|
|
|
|
|
+ # obj_fin.multigeo = panel_obj.multigeo
|
|
|
|
|
+ # obj_fin.tools = deepcopy(panel_obj.tools)
|
|
|
|
|
+ # if panel_obj.multigeo is True:
|
|
|
|
|
+ # for tool in panel_obj.tools:
|
|
|
|
|
+ # obj_fin.tools[tool]['solid_geometry'][:] = []
|
|
|
|
|
+ # elif isinstance(panel_obj, FlatCAMGerber):
|
|
|
|
|
+ # obj_fin.apertures = deepcopy(panel_obj.apertures)
|
|
|
|
|
+ # for ap in obj_fin.apertures:
|
|
|
|
|
+ # obj_fin.apertures[ap]['geometry'] = list()
|
|
|
|
|
+ #
|
|
|
|
|
+ # # find the number of polygons in the source solid_geometry
|
|
|
|
|
+ # geo_len = 0
|
|
|
|
|
+ # if isinstance(panel_obj, FlatCAMGeometry):
|
|
|
|
|
+ # if panel_obj.multigeo is True:
|
|
|
|
|
+ # for tool in panel_obj.tools:
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # for pol in panel_obj.tools[tool]['solid_geometry']:
|
|
|
|
|
+ # geo_len += 1
|
|
|
|
|
+ # except TypeError:
|
|
|
|
|
+ # geo_len = 1
|
|
|
|
|
+ # else:
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # for pol in panel_obj.solid_geometry:
|
|
|
|
|
+ # geo_len += 1
|
|
|
|
|
+ # except TypeError:
|
|
|
|
|
+ # geo_len = 1
|
|
|
|
|
+ # elif isinstance(panel_obj, FlatCAMGerber):
|
|
|
|
|
+ # for ap in panel_obj.apertures:
|
|
|
|
|
+ # for elem in panel_obj.apertures[ap]['geometry']:
|
|
|
|
|
+ # geo_len += 1
|
|
|
|
|
+ #
|
|
|
|
|
+ # self.app.progress.emit(0)
|
|
|
|
|
+ # element = 0
|
|
|
|
|
+ # for row in range(rows):
|
|
|
|
|
+ # currentx = 0.0
|
|
|
|
|
+ #
|
|
|
|
|
+ # for col in range(columns):
|
|
|
|
|
+ # element += 1
|
|
|
|
|
+ # disp_number = 0
|
|
|
|
|
+ # old_disp_number = 0
|
|
|
|
|
+ #
|
|
|
|
|
+ # if isinstance(panel_obj, FlatCAMGeometry):
|
|
|
|
|
+ # if panel_obj.multigeo is True:
|
|
|
|
|
+ # for tool in panel_obj.tools:
|
|
|
|
|
+ # if self.app.abort_flag:
|
|
|
|
|
+ # # graceful abort requested by the user
|
|
|
|
|
+ # raise FlatCAMApp.GracefulException
|
|
|
|
|
+ #
|
|
|
|
|
+ # # geo = translate_recursion(panel_obj.tools[tool]['solid_geometry'])
|
|
|
|
|
+ # # if isinstance(geo, list):
|
|
|
|
|
+ # # obj_fin.tools[tool]['solid_geometry'] += geo
|
|
|
|
|
+ # # else:
|
|
|
|
|
+ # # obj_fin.tools[tool]['solid_geometry'].append(geo)
|
|
|
|
|
+ #
|
|
|
|
|
+ # # calculate the number of polygons
|
|
|
|
|
+ # geo_len = len(panel_obj.tools[tool]['solid_geometry'])
|
|
|
|
|
+ # pol_nr = 0
|
|
|
|
|
+ # for geo_el in panel_obj.tools[tool]['solid_geometry']:
|
|
|
|
|
+ # trans_geo = translate_recursion(geo_el)
|
|
|
|
|
+ # obj_fin.tools[tool]['solid_geometry'].append(trans_geo)
|
|
|
|
|
+ #
|
|
|
|
|
+ # pol_nr += 1
|
|
|
|
|
+ # disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
|
|
|
|
|
+ #
|
|
|
|
|
+ # if old_disp_number < disp_number <= 100:
|
|
|
|
|
+ # self.app.proc_container.update_view_text(' %s: %d %d%%' %
|
|
|
|
|
+ # (_("Copy"),
|
|
|
|
|
+ # int(element),
|
|
|
|
|
+ # disp_number))
|
|
|
|
|
+ # old_disp_number = disp_number
|
|
|
|
|
+ # else:
|
|
|
|
|
+ # # geo = translate_recursion(panel_obj.solid_geometry)
|
|
|
|
|
+ # # if isinstance(geo, list):
|
|
|
|
|
+ # # obj_fin.solid_geometry += geo
|
|
|
|
|
+ # # else:
|
|
|
|
|
+ # # obj_fin.solid_geometry.append(geo)
|
|
|
|
|
+ # if self.app.abort_flag:
|
|
|
|
|
+ # # graceful abort requested by the user
|
|
|
|
|
+ # raise FlatCAMApp.GracefulException
|
|
|
|
|
+ #
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # # calculate the number of polygons
|
|
|
|
|
+ # geo_len = len(panel_obj.solid_geometry)
|
|
|
|
|
+ # except TypeError:
|
|
|
|
|
+ # geo_len = 1
|
|
|
|
|
+ # pol_nr = 0
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # for geo_el in panel_obj.solid_geometry:
|
|
|
|
|
+ # if self.app.abort_flag:
|
|
|
|
|
+ # # graceful abort requested by the user
|
|
|
|
|
+ # raise FlatCAMApp.GracefulException
|
|
|
|
|
+ #
|
|
|
|
|
+ # trans_geo = translate_recursion(geo_el)
|
|
|
|
|
+ # obj_fin.solid_geometry.append(trans_geo)
|
|
|
|
|
+ #
|
|
|
|
|
+ # pol_nr += 1
|
|
|
|
|
+ # disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
|
|
|
|
|
+ #
|
|
|
|
|
+ # if old_disp_number < disp_number <= 100:
|
|
|
|
|
+ # self.app.proc_container.update_view_text(' %s: %d %d%%' %
|
|
|
|
|
+ # (_("Copy"),
|
|
|
|
|
+ # int(element),
|
|
|
|
|
+ # disp_number))
|
|
|
|
|
+ # old_disp_number = disp_number
|
|
|
|
|
+ # except TypeError:
|
|
|
|
|
+ # trans_geo = translate_recursion(panel_obj.solid_geometry)
|
|
|
|
|
+ # obj_fin.solid_geometry.append(trans_geo)
|
|
|
|
|
+ # else:
|
|
|
|
|
+ # # geo = translate_recursion(panel_obj.solid_geometry)
|
|
|
|
|
+ # # if isinstance(geo, list):
|
|
|
|
|
+ # # obj_fin.solid_geometry += geo
|
|
|
|
|
+ # # else:
|
|
|
|
|
+ # # obj_fin.solid_geometry.append(geo)
|
|
|
|
|
+ # if self.app.abort_flag:
|
|
|
|
|
+ # # graceful abort requested by the user
|
|
|
|
|
+ # raise FlatCAMApp.GracefulException
|
|
|
|
|
+ #
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # for geo_el in panel_obj.solid_geometry:
|
|
|
|
|
+ # if self.app.abort_flag:
|
|
|
|
|
+ # # graceful abort requested by the user
|
|
|
|
|
+ # raise FlatCAMApp.GracefulException
|
|
|
|
|
+ #
|
|
|
|
|
+ # trans_geo = translate_recursion(geo_el)
|
|
|
|
|
+ # obj_fin.solid_geometry.append(trans_geo)
|
|
|
|
|
+ # except TypeError:
|
|
|
|
|
+ # trans_geo = translate_recursion(panel_obj.solid_geometry)
|
|
|
|
|
+ # obj_fin.solid_geometry.append(trans_geo)
|
|
|
|
|
+ #
|
|
|
|
|
+ # for apid in panel_obj.apertures:
|
|
|
|
|
+ # if self.app.abort_flag:
|
|
|
|
|
+ # # graceful abort requested by the user
|
|
|
|
|
+ # raise FlatCAMApp.GracefulException
|
|
|
|
|
+ #
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # # calculate the number of polygons
|
|
|
|
|
+ # geo_len = len(panel_obj.apertures[apid]['geometry'])
|
|
|
|
|
+ # except TypeError:
|
|
|
|
|
+ # geo_len = 1
|
|
|
|
|
+ # pol_nr = 0
|
|
|
|
|
+ # for el in panel_obj.apertures[apid]['geometry']:
|
|
|
|
|
+ # if self.app.abort_flag:
|
|
|
|
|
+ # # graceful abort requested by the user
|
|
|
|
|
+ # raise FlatCAMApp.GracefulException
|
|
|
|
|
+ #
|
|
|
|
|
+ # new_el = dict()
|
|
|
|
|
+ # if 'solid' in el:
|
|
|
|
|
+ # geo_aper = translate_recursion(el['solid'])
|
|
|
|
|
+ # new_el['solid'] = geo_aper
|
|
|
|
|
+ #
|
|
|
|
|
+ # if 'clear' in el:
|
|
|
|
|
+ # geo_aper = translate_recursion(el['clear'])
|
|
|
|
|
+ # new_el['clear'] = geo_aper
|
|
|
|
|
+ #
|
|
|
|
|
+ # if 'follow' in el:
|
|
|
|
|
+ # geo_aper = translate_recursion(el['follow'])
|
|
|
|
|
+ # new_el['follow'] = geo_aper
|
|
|
|
|
+ #
|
|
|
|
|
+ # obj_fin.apertures[apid]['geometry'].append(deepcopy(new_el))
|
|
|
|
|
+ #
|
|
|
|
|
+ # pol_nr += 1
|
|
|
|
|
+ # disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
|
|
|
|
|
+ #
|
|
|
|
|
+ # if old_disp_number < disp_number <= 100:
|
|
|
|
|
+ # self.app.proc_container.update_view_text(' %s: %d %d%%' %
|
|
|
|
|
+ # (_("Copy"),
|
|
|
|
|
+ # int(element),
|
|
|
|
|
+ # disp_number))
|
|
|
|
|
+ # old_disp_number = disp_number
|
|
|
|
|
+ #
|
|
|
|
|
+ # currentx += lenghtx
|
|
|
|
|
+ # currenty += lenghty
|
|
|
|
|
+ #
|
|
|
|
|
+ # if panel_type == 'gerber':
|
|
|
|
|
+ # self.app.inform.emit('%s' %
|
|
|
|
|
+ # _("Generating panel ... Adding the Gerber code."))
|
|
|
|
|
+ # obj_fin.source_file = self.app.export_gerber(obj_name=self.outname, filename=None,
|
|
|
|
|
+ # local_use=obj_fin, use_thread=False)
|
|
|
|
|
+ #
|
|
|
|
|
+ # # app_obj.log.debug("Found %s geometries. Creating a panel geometry cascaded union ..." %
|
|
|
|
|
+ # # len(obj_fin.solid_geometry))
|
|
|
|
|
+ #
|
|
|
|
|
+ # # obj_fin.solid_geometry = cascaded_union(obj_fin.solid_geometry)
|
|
|
|
|
+ # # app_obj.log.debug("Finished creating a cascaded union for the panel.")
|
|
|
|
|
+ # self.app.proc_container.update_view_text('')
|
|
|
|
|
+ #
|
|
|
|
|
+ # self.app.inform.emit('%s: %d' %
|
|
|
|
|
+ # (_("Generating panel... Spawning copies"), (int(rows * columns))))
|
|
|
|
|
+ # if isinstance(panel_obj, FlatCAMExcellon):
|
|
|
|
|
+ # self.app.progress.emit(50)
|
|
|
|
|
+ # self.app.new_object("excellon", self.outname, job_init_excellon, plot=True, autoselected=True)
|
|
|
|
|
+ # else:
|
|
|
|
|
+ # self.app.progress.emit(50)
|
|
|
|
|
+ # self.app.new_object(panel_type, self.outname, job_init_geometry,
|
|
|
|
|
+ # plot=True, autoselected=True)
|
|
|
|
|
+ #
|
|
|
|
|
+ # if self.constrain_flag is False:
|
|
|
|
|
+ # self.app.inform.emit('[success] %s' % _("Panel done..."))
|
|
|
|
|
+ # else:
|
|
|
|
|
+ # self.constrain_flag = False
|
|
|
|
|
+ # self.app.inform.emit(_("{text} Too big for the constrain area. "
|
|
|
|
|
+ # "Final panel has {col} columns and {row} rows").format(
|
|
|
|
|
+ # text='[WARNING] ', col=columns, row=rows))
|
|
|
|
|
+ #
|
|
|
|
|
+ # proc = self.app.proc_container.new(_("Working..."))
|
|
|
|
|
+ #
|
|
|
|
|
+ # def job_thread(app_obj):
|
|
|
|
|
+ # try:
|
|
|
|
|
+ # panelize_2()
|
|
|
|
|
+ # self.app.inform.emit('[success] %s' % _("Panel created successfully."))
|
|
|
|
|
+ # except Exception as ee:
|
|
|
|
|
+ # proc.done()
|
|
|
|
|
+ # log.debug(str(ee))
|
|
|
|
|
+ # return
|
|
|
|
|
+ # proc.done()
|
|
|
|
|
+ #
|
|
|
|
|
+ # self.app.collection.promise(self.outname)
|
|
|
|
|
+ # self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
|
|
|
|
|
|
|
|
def reset_fields(self):
|
|
def reset_fields(self):
|
|
|
- self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
|
|
|
|
- self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
|
|
|
|
|
|
+ # self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
|
|
|
|
+ # self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
|
|
|
|
+ pass
|