From 361157ed06ae9cbc1d2700bf8db357f346aa3495 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 27 Jan 2021 16:41:47 +0100 Subject: [PATCH] adde base widget for list --- .../settings/settings/widgets/item_widgets.py | 321 +++++++++++++++++- 1 file changed, 320 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_widgets.py b/pype/tools/settings/settings/widgets/item_widgets.py index b1ed24760d..b59bbc13c6 100644 --- a/pype/tools/settings/settings/widgets/item_widgets.py +++ b/pype/tools/settings/settings/widgets/item_widgets.py @@ -1,6 +1,7 @@ import json from Qt import QtWidgets, QtCore, QtGui +from avalon.vendor import qtawesome from pype.settings.entities import ( GUIEntity, DictImmutableKeysEntity, @@ -27,6 +28,8 @@ from .widgets import ( from .multiselection_combobox import MultiSelectionComboBox from .lib import CHILD_OFFSET +BTN_FIXED_SIZE = 20 + class BaseWidget(QtWidgets.QWidget): def __init__(self, entity, entity_widget): @@ -501,6 +504,320 @@ class PathInputWidget(InputWidget): print("_on_entity_change", self.__class__.__name__, self.entity.path) +class EmptyListItem(QtWidgets.QWidget): + add_clicked = QtCore.Signal() + + def __init__(self, parent): + super(EmptyListItem, self).__init__(parent) + + add_btn = QtWidgets.QPushButton("+", self) + remove_btn = QtWidgets.QPushButton("-", self) + spacer_widget = QtWidgets.QWidget(self) + spacer_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + + add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + remove_btn.setEnabled(False) + + add_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) + remove_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) + + add_btn.setProperty("btn-type", "tool-item") + remove_btn.setProperty("btn-type", "tool-item") + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(3) + layout.addWidget(add_btn, 0) + layout.addWidget(remove_btn, 0) + layout.addWidget(spacer_widget, 1) + + add_btn.clicked.connect(self.add_clicked) + + self.add_btn = add_btn + self.remove_btn = remove_btn + self.spacer_widget = spacer_widget + + +class ListItem(QtWidgets.QWidget): + def __init__(self, entity, entity_widget): + super(ListItem, self).__init__(entity_widget.content_widget) + self.entity_widget = entity_widget + self.entity = entity + + char_up = qtawesome.charmap("fa.angle-up") + char_down = qtawesome.charmap("fa.angle-down") + + add_btn = QtWidgets.QPushButton("+") + remove_btn = QtWidgets.QPushButton("-") + up_btn = QtWidgets.QPushButton(char_up) + down_btn = QtWidgets.QPushButton(char_down) + + font_up_down = qtawesome.font("fa", 13) + up_btn.setFont(font_up_down) + down_btn.setFont(font_up_down) + + add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + up_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + down_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + + add_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) + remove_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) + up_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) + down_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) + + add_btn.setProperty("btn-type", "tool-item") + remove_btn.setProperty("btn-type", "tool-item") + up_btn.setProperty("btn-type", "tool-item") + down_btn.setProperty("btn-type", "tool-item") + + add_btn.clicked.connect(self._on_add_clicked) + remove_btn.clicked.connect(self._on_remove_clicked) + up_btn.clicked.connect(self._on_up_clicked) + down_btn.clicked.connect(self._on_down_clicked) + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(3) + + layout.addWidget(add_btn, 0) + layout.addWidget(remove_btn, 0) + + self.content_widget = self + self.content_layout = layout + + self.input_field = create_ui_for_entity(self.entity, self) + + spacer_widget = QtWidgets.QWidget(self) + spacer_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + spacer_widget.setVisible(False) + + layout.addWidget(spacer_widget, 1) + + layout.addWidget(up_btn, 0) + layout.addWidget(down_btn, 0) + + self.add_btn = add_btn + self.remove_btn = remove_btn + self.up_btn = up_btn + self.down_btn = down_btn + + self.spacer_widget = spacer_widget + + def add_widget_to_layout(self, widget, label=None): + self.content_layout.addWidget(widget, 1) + + def row(self): + return self.entity_widget.input_fields.index(self) + + def parent_rows_count(self): + return len(self.entity_widget.input_fields) + + def _on_add_clicked(self): + self.entity_widget.add_row(row=self.row() + 1) + + def _on_remove_clicked(self): + self.entity_widget.remove_row(self) + + def _on_up_clicked(self): + row = self.row() + self.entity_widget.swap_rows(row - 1, row) + + def _on_down_clicked(self): + row = self.row() + self.entity_widget.swap_rows(row, row + 1) + + def order_changed(self): + row = self.row() + parent_row_count = self.parent_rows_count() + if parent_row_count == 1: + self.up_btn.setVisible(False) + self.down_btn.setVisible(False) + return + + if not self.up_btn.isVisible(): + self.up_btn.setVisible(True) + self.down_btn.setVisible(True) + + if row == 0: + self.up_btn.setEnabled(False) + self.down_btn.setEnabled(True) + + elif row == parent_row_count - 1: + self.up_btn.setEnabled(True) + self.down_btn.setEnabled(False) + + else: + self.up_btn.setEnabled(True) + self.down_btn.setEnabled(True) + + +class ListWidget(InputWidget): + def create_ui(self): + self.input_fields = [] + + main_layout = QtWidgets.QHBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.setSpacing(0) + + body_widget = None + entity_label = self.entity.label + if self.entity.use_label_wrap: + body_widget = ExpandingWidget(entity_label, self) + entity_label = None + main_layout.addWidget(body_widget) + self.label_widget = body_widget.label_widget + + self.body_widget = body_widget + + if body_widget is None: + content_parent_widget = self + else: + content_parent_widget = body_widget + + content_state = "" + + content_widget = QtWidgets.QWidget(content_parent_widget) + content_widget.setObjectName("ContentWidget") + content_widget.setProperty("content_state", content_state) + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 5) + + if body_widget is None: + main_layout.addWidget(content_widget) + else: + body_widget.set_content_widget(content_widget) + + self.body_widget = body_widget + self.content_widget = content_widget + self.content_layout = content_layout + + if body_widget: + if not self.entity.collapsible: + body_widget.hide_toolbox(hide_content=False) + + elif self.entity.collapsed: + body_widget.toggle_content() + + self.setAttribute(QtCore.Qt.WA_TranslucentBackground) + + self.empty_row = EmptyListItem(self.content_widget) + self.content_layout.addWidget(self.empty_row) + + self.entity_widget.add_widget_to_layout(self, entity_label) + + self.update_value() + + def _on_value_change(self): + print("_on_value_change", self.__class__.__name__, self.entity.path) + + def _on_entity_change(self): + print("_on_entity_change", self.__class__.__name__, self.entity.path) + + def count(self): + return len(self.input_fields) + + def update_value(self): + for input_field in tuple(self.input_fields): + self.remove_row(input_field) + + for entity in self.entity.children: + self.add_row(entity) + + self.empty_row.setVisible(self.count() == 0) + + def swap_rows(self, row_1, row_2): + if row_1 == row_2: + return + + if row_1 > row_2: + row_1, row_2 = row_2, row_1 + + field_1 = self.input_fields[row_1] + field_2 = self.input_fields[row_2] + + self.input_fields[row_1] = field_2 + self.input_fields[row_2] = field_1 + + layout_index = self.inputs_layout.indexOf(field_1) + self.inputs_layout.insertWidget(layout_index + 1, field_1) + + field_1.order_changed() + field_2.order_changed() + + def add_new_item(self, row=None): + child_entity = self.entity.add_new_item() + self.add_row(child_entity) + + def add_row(self, child_entity, row=None): + # Create new item + item_widget = ListItem(child_entity, self) + + previous_field = None + next_field = None + + if row is None: + if self.input_fields: + previous_field = self.input_fields[-1] + self.inputs_layout.addWidget(item_widget) + self.input_fields.append(item_widget) + else: + if row > 0: + previous_field = self.input_fields[row - 1] + + max_index = self.count() + if row < max_index: + next_field = self.input_fields[row] + + self.inputs_layout.insertWidget(row, item_widget) + self.input_fields.insert(row, item_widget) + + if previous_field: + previous_field.order_changed() + + if next_field: + next_field.order_changed() + + item_widget.value_changed.connect(self._on_value_change) + + item_widget.order_changed() + + previous_input = None + for input_field in self.input_fields: + if previous_input is not None: + self.setTabOrder( + previous_input, input_field.value_input.focusProxy() + ) + previous_input = input_field.value_input.focusProxy() + + self.updateGeometry() + + def remove_row(self, item_widget): + row = self.input_fields.index(item_widget) + previous_field = None + next_field = None + if row > 0: + previous_field = self.input_fields[row - 1] + + if row != len(self.input_fields) - 1: + next_field = self.input_fields[row + 1] + + self.inputs_layout.removeWidget(item_widget) + self.input_fields.pop(row) + item_widget.setParent(None) + item_widget.deleteLater() + + if previous_field: + previous_field.order_changed() + + if next_field: + next_field.order_changed() + + self.empty_row.setVisible(self.count() == 0) + + self.updateGeometry() + + def create_ui_for_entity(entity, entity_widget): if isinstance(entity, GUIEntity): return GUIWidget(entity, entity_widget) @@ -529,8 +846,10 @@ def create_ui_for_entity(entity, entity_widget): elif isinstance(entity, PathInput): return PathInputWidget(entity, entity_widget) + elif isinstance(entity, ListEntity): + return ListWidget(entity, entity_widget) + # DictMutableKeysEntity, - # ListEntity, # ListStrictEntity, label = "<{}>: {} ({})".format( entity.__class__.__name__, entity.path, entity.value