def __init__(self, parent: QWidget, parent_layout: QVBoxLayout, line_layout: QHBoxLayout, resource_database: ResourceDatabase, requirement: RequirementArrayBase): self._editors = [] self.resource_database = resource_database self._array_type = type(requirement) # the parent is added to a layout which is added to parent_layout, so we index = parent_layout.indexOf(line_layout) + 1 self.group_box = QGroupBox(parent) self.group_box.setStyleSheet("QGroupBox { margin-top: 2px; }") parent_layout.insertWidget(index, self.group_box) self.item_layout = QVBoxLayout(self.group_box) self.item_layout.setContentsMargins(8, 2, 2, 6) self.item_layout.setAlignment(Qt.AlignTop) self.new_item_button = QPushButton(self.group_box) self.new_item_button.setMaximumWidth(75) self.new_item_button.setText("New Row") self.new_item_button.clicked.connect(self.new_item) self.comment_text_box = QLineEdit(parent) self.comment_text_box.setText(requirement.comment or "") self.comment_text_box.setPlaceholderText("Comment") line_layout.addWidget(self.comment_text_box) for item in requirement.items: self._create_item(item) self.item_layout.addWidget(self.new_item_button)
class OrderableListWidget(QScrollArea): """All available items in this list""" _item_list: list[OrderableListItem] """This lists actual widget""" _widget: QWidget """The widgets layout""" _layout: QLayout """Decides which way this list is ordered; 1 for ascending, -1 for descending""" _order_factor: int def __init__(self, order_asc=True, orientation_horizontal=False): """Init gui :type order_asc: bool :param order_asc: Whether to order the list ascending :type orientation_horizontal: bool :param orientation_horizontal: Should the list orientation be horizontal? """ super().__init__() if order_asc: self._order_factor = 1 else: self._order_factor = -1 self._widget = QWidget() self.setWidget(self._widget) self.setWidgetResizable(True) # Set layout if orientation_horizontal: self._layout = QHBoxLayout() else: self._layout = QVBoxLayout() self._widget.setLayout(self._layout) self._layout.setAlignment(Qt.AlignTop) self._item_list = [] def _get_order(self, list_item_a, list_item_b): """Defines this lists widget order :type list_item_a: OrderableListItem :param list_item_a: The first item to compare :type list_item_b: OrderableListItem :param list_item_b: The second item to compare :returns -1|0|1: list_item_a is: before, same, after list_item_b""" str_a: str = list_item_a.get_order_string() str_b: str = list_item_b.get_order_string() if str_a == str_b: return 0 elif str_a < str_b: return -1 * self._order_factor else: return 1 * self._order_factor def add(self, list_item): """Add a new item to the list :type list_item: OrderableListItem :param list_item: The item to add """ # Subscribe to changes list_item.subscribe(OrderableListItem.DELETED, self._item_deleted) list_item.subscribe(OrderableListItem.UPDATED, self._item_updated) # Make sure to add the item only once if list_item not in self._item_list: list_item_inserted = False self._item_list.append(list_item) # Walk all existing items for i in range(self._layout.count()): existing_item: OrderableListItem = self._layout.itemAt(i).widget() if 1 == self._get_order(existing_item, list_item): self._layout.insertWidget(i, list_item) list_item_inserted = True break if not list_item_inserted: self._layout.addWidget(list_item) def _item_deleted(self, item): """Delete an item from the list :type item: OrderableListItem :param item: The item to delete """ # See if the item exists in this list try: i: int = self._item_list.index(item) except ValueError: return # Delete the item self._item_list.pop(i) def _item_updated(self, item): """Update the list with the items new information :type item: OrderableListItem :param item: The item that was updated """ pass
class ParameterEditor(QWidget): onParametersChanged = Signal() def __init__(self, program: Program): super().__init__() self._program = program parametersLabel = QLabel("Parameters") newParameterButton = QPushButton("Add Parameter") newParameterButton.clicked.connect(self.AddParameter) layout = QVBoxLayout() titleLayout = QHBoxLayout() titleLayout.addWidget(parametersLabel) titleLayout.addWidget(newParameterButton) layout.addLayout(titleLayout) self._listArea = QScrollArea() self._listArea.setWidgetResizable(True) self._listArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self._listArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) layout.addWidget(self._listArea, stretch=1) listWidget = QWidget() self._itemLayout = QVBoxLayout() self._itemLayout.setAlignment(Qt.AlignTop) listWidget.setLayout(self._itemLayout) self.setLayout(layout) self._listArea.setWidget(listWidget) self.items: List[ParameterEditorItem] = [] self._temporaryParameters = program.parameters.copy() self.Populate() def AddParameter(self): newParameter = Parameter() self._temporaryParameters.append(newParameter) self.onParametersChanged.emit() self.AddToList(newParameter) def Populate(self): for parameter in self._temporaryParameters: self.AddToList(parameter) self._listArea.updateGeometry() def AddToList(self, parameter: Parameter): newItem = ParameterEditorItem(parameter) newItem.onRemoveParameter.connect(self.RemoveParameter) newItem.onMoveParameterUp.connect(self.MoveParameterUp) newItem.onMoveParameterDown.connect(self.MoveParameterDown) newItem.onChanged.connect(self.onParametersChanged.emit) self._itemLayout.addWidget(newItem) self.items.append(newItem) def RemoveFromList(self, parameter: Parameter): item = [item for item in self.items if item.parameter is parameter] item[0].deleteLater() self.items.remove(item[0]) def RemoveParameter(self, parameter: Parameter): self._temporaryParameters.remove(parameter) self.onParametersChanged.emit() self.RemoveFromList(parameter) def Reorder(self, parameter: Parameter, newPosition: int): item = [item for item in self.items if item.parameter is parameter][0] self._itemLayout.removeWidget(item) self._itemLayout.insertWidget(newPosition, item) self.items.remove(item) self.items.insert(newPosition, item) self._temporaryParameters.remove(parameter) self._temporaryParameters.insert(newPosition, parameter) self.onParametersChanged.emit() def MoveParameterUp(self, parameter: Parameter): index = self._temporaryParameters.index(parameter) self.Reorder(parameter, index - 1) def MoveParameterDown(self, parameter: Parameter): index = self._temporaryParameters.index(parameter) self.Reorder(parameter, index + 1) def Save(self): self._program.parameters = self._temporaryParameters self._temporaryParameters = self._program.parameters.copy() for item in self.items: item.UpdateParameter()