class _UnitRangeWidget(_ParameterWidget): def __init__(self, parameter, parent=None): _ParameterWidget.__init__(self, parameter, parent) # Widgets self._txt_lower = MultiNumericalLineEdit() self._txt_upper = MultiNumericalLineEdit() self._cb_unit = UnitComboBox(parameter.unit) # Layouts layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self._txt_lower, 1) layout.addWidget(QLabel("-")) layout.addWidget(self._txt_upper, 1) layout.addWidget(self._cb_unit) self.setLayout(layout) # Signals self.valuesChanged.connect(self._onChanged) self.validationRequested.connect(self._onChanged) self._txt_lower.textChanged.connect(self.valuesChanged) self._txt_upper.textChanged.connect(self.valuesChanged) self._cb_unit.currentIndexChanged.connect(self.valuesChanged) self.validationRequested.emit() def _onChanged(self): if self.hasAcceptableInput(): self._txt_lower.setStyleSheet("background: none") self._txt_upper.setStyleSheet("background: none") else: self._txt_lower.setStyleSheet("background: pink") self._txt_upper.setStyleSheet("background: pink") def values(self): lows = self._txt_lower.values() * self._cb_unit.factor() ups = self._txt_upper.values() * self._cb_unit.factor() return list(product(lows, ups)) def setValues(self, values): values = np.array(values, ndmin=1) self._txt_lower.setValues(list(map(itemgetter(0), values))) self._txt_upper.setValues(list(map(itemgetter(1), values))) self._cb_unit.setUnit(self.parameter().unit) def isReadOnly(self): return self._txt_lower.isReadOnly() and \ self._txt_upper.isReadOnly() and \ not self._cb_unit.isEnabled() def setReadOnly(self, state): self._txt_lower.setReadOnly(state) self._txt_upper.setReadOnly(state) self._cb_unit.setEnabled(not state)
class UnitParameterWidget(_ParameterWidget): def __init__(self, parameter, parent=None): _ParameterWidget.__init__(self, parameter, parent) # Widgets self._cb_unit = UnitComboBox(parameter.unit) self._txt_values = MultiNumericalLineEdit() validator = _FactorParameterValidator(parameter, self._cb_unit) self._txt_values.setValidator(validator) # Layouts layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self._txt_values, 1) layout.addWidget(self._cb_unit) self.setLayout(layout) # Signals self.valuesChanged.connect(self._onChanged) self.validationRequested.connect(self._onChanged) self._txt_values.textChanged.connect(self.valuesChanged) self._cb_unit.currentIndexChanged.connect(self.valuesChanged) self.validationRequested.emit() def _onChanged(self): if self.hasAcceptableInput(): self._txt_values.setStyleSheet("background: none") else: self._txt_values.setStyleSheet("background: pink") def values(self): return self._txt_values.values() * self._cb_unit.factor() def setValues(self, values): self._txt_values.setValues(values) self._cb_unit.setUnit(self.parameter().unit) def isReadOnly(self): return self._txt_values.isReadOnly() and not self._cb_unit.isEnabled() def setReadOnly(self, state): self._txt_values.setReadOnly(state) self._cb_unit.setEnabled(not state) def hasAcceptableInput(self): if not _ParameterWidget.hasAcceptableInput(self): return False return self._txt_values.hasAcceptableInput()
class LayerListWidget(_ParameterWidget): def __init__(self, parameter, parent=None): _ParameterWidget.__init__(self, parameter, parent) # Variables model = _LayerModel() self._material_class = Material # Actions act_add = QAction(getIcon("list-add"), "Add layer", self) act_remove = QAction(getIcon("list-remove"), "Remove layer", self) act_clean = QAction(getIcon('edit-clear'), "Clear", self) # Widgets self._cb_unit = UnitComboBox('m') self._cb_unit.setUnit('um') self._tbl_layers = QTableView() self._tbl_layers.setModel(model) self._tbl_layers.setItemDelegate(_LayerDelegate()) header = self._tbl_layers.horizontalHeader() header.setResizeMode(QHeaderView.Stretch) header.setStyleSheet('color: blue') self._tlb_layers = QToolBar() spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self._tlb_layers.addWidget(spacer) self._tlb_layers.addAction(act_add) self._tlb_layers.addAction(act_remove) self._tlb_layers.addAction(act_clean) # Layouts layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) sublayout = QHBoxLayout() sublayout.addStretch() sublayout.addWidget(QLabel('Thickness unit')) sublayout.addWidget(self._cb_unit) layout.addLayout(sublayout) layout.addWidget(self._tbl_layers) layout.addWidget(self._tlb_layers) self.setLayout(layout) # Signals self.valuesChanged.connect(self._onChanged) self.validationRequested.connect(self._onChanged) act_add.triggered.connect(self._onAdd) act_remove.triggered.connect(self._onRemove) act_clean.triggered.connect(self._onClear) self._tbl_layers.doubleClicked.connect(self._onDoubleClicked) model.dataChanged.connect(self.valuesChanged) model.rowsInserted.connect(self.valuesChanged) model.rowsRemoved.connect(self.valuesChanged) self.validationRequested.emit() def _onChanged(self): if self.hasAcceptableInput(): self._tbl_layers.setStyleSheet("background: none") else: self._tbl_layers.setStyleSheet("background: pink") def _onDoubleClicked(self, index): if index.column() != 0: return model = self._tbl_layers.model() materials = model.materials(index) if len(materials) == 0: dialog = get_material_dialog_class(self._material_class)() elif len(materials) == 1: dialog = get_material_dialog_class(self._material_class)() dialog.setValue(materials[0]) else: dialog = MaterialListDialog() dialog.setMaterialClass(self._material_class) dialog.setValues(materials) dialog.setReadOnly(self.isReadOnly()) if not dialog.exec_(): return model.setData(index, dialog.values()) def _onAdd(self): index = self._tbl_layers.selectionModel().currentIndex() model = self._tbl_layers.model() model.insertRows(index.row() + 1) # Show material dialog right away index = model.createIndex(index.row() + 1, 0) self._onDoubleClicked(index) def _onRemove(self): selection = self._tbl_layers.selectionModel().selection().indexes() if len(selection) == 0: QMessageBox.warning(self, "Layer", "Select a row") return model = self._tbl_layers.model() for row in sorted(map(methodcaller('row'), selection), reverse=True): model.removeRow(row) def _onClear(self): model = self._tbl_layers.model() for row in reversed(range(model.rowCount())): model.removeRow(row) def values(self): factor = self._cb_unit.factor() layers = [] for material, thickness in self._tbl_layers.model().layers(): if not material or not thickness: continue thickness_m = np.array(thickness, ndmin=1) * factor layers.append(_MockLayer(material, thickness_m)) return layers def setValues(self, layers): layers = np.array(layers, ndmin=1) factor = self._cb_unit.factor() model = self._tbl_layers.model() model.removeRows(0, model.rowCount()) model.insertRows(0, len(layers)) for i, layer in enumerate(layers): model.setData(model.index(i, 0), layer.material) model.setData(model.index(i, 1), layer.thickness_m / factor) def isReadOnly(self): return not self._cb_unit.isEnabled() and \ not self._tlb_layers.isVisible() def setReadOnly(self, state): self._cb_unit.setEnabled(not state) self._tlb_layers.setVisible(not state) style = 'color: none' if state else 'color: blue' self._tbl_layers.horizontalHeader().setStyleSheet(style) self._tbl_layers.itemDelegate().setReadOnly(state) def setMaterialClass(self, clasz): self._material_class = clasz
class OriginWidget(_ParameterWidget): def __init__(self, parameter, parent=None): _ParameterWidget.__init__(self, parameter, parent) # Widgets self._lbl_x = QLabel('x') self._lbl_x.setStyleSheet("color: blue") self._txt_x = MultiNumericalLineEdit() self._lbl_y = QLabel('y') self._lbl_y.setStyleSheet("color: blue") self._txt_y = MultiNumericalLineEdit() self._lbl_z = QLabel('z') self._lbl_z.setStyleSheet("color: blue") self._txt_z = MultiNumericalLineEdit() self._cb_unit = UnitComboBox(parameter.unit) # Layouts layout = QFormLayout() layout.setContentsMargins(0, 0, 0, 0) if sys.platform == 'darwin': # Fix for Mac OS layout.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.ExpandingFieldsGrow) layout.addRow(self._lbl_x, self._txt_x) layout.addRow(self._lbl_y, self._txt_y) layout.addRow(self._lbl_z, self._txt_z) layout.addRow('Unit', self._cb_unit) self.setLayout(layout) # Signals self.valuesChanged.connect(self._onChanged) self.validationRequested.connect(self._onChanged) self._txt_x.textChanged.connect(self.valuesChanged) self._txt_y.textChanged.connect(self.valuesChanged) self._txt_z.textChanged.connect(self.valuesChanged) self._cb_unit.currentIndexChanged.connect(self.valuesChanged) self.validationRequested.emit() def _onChanged(self): if self.hasAcceptableInput(): self._txt_x.setStyleSheet("background: none") self._txt_y.setStyleSheet("background: none") self._txt_z.setStyleSheet("background: none") else: self._txt_x.setStyleSheet("background: pink") self._txt_y.setStyleSheet("background: pink") self._txt_z.setStyleSheet("background: pink") def values(self): xs = self._txt_x.values() * self._cb_unit.factor() ys = self._txt_y.values() * self._cb_unit.factor() zs = self._txt_z.values() * self._cb_unit.factor() return list(product(xs, ys, zs)) def setValues(self, values): values = np.array(values, ndmin=1) self._txt_x.setValues(list(map(itemgetter(0), values))) self._txt_y.setValues(list(map(itemgetter(1), values))) self._txt_z.setValues(list(map(itemgetter(2), values))) self._cb_unit.setUnit('m') def isReadOnly(self): return self._txt_x.isReadOnly() and \ self._txt_y.isReadOnly() and \ self._txt_z.isReadOnly() and \ not self._cb_unit.isEnabled() def setReadOnly(self, state): style = 'color: none' if state else 'color: blue' self._lbl_x.setStyleSheet(style) self._txt_x.setReadOnly(state) self._lbl_y.setStyleSheet(style) self._txt_y.setReadOnly(state) self._lbl_z.setStyleSheet(style) self._txt_z.setReadOnly(state) self._cb_unit.setEnabled(not state) def hasAcceptableInput(self): if not _ParameterWidget.hasAcceptableInput(self): return False if not self._txt_x.hasAcceptableInput(): return False if not self._txt_y.hasAcceptableInput(): return False if not self._txt_z.hasAcceptableInput(): return False return True