From 04fd74587804006c7d3df0fede102b9735692dc9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 12:37:38 +0200 Subject: [PATCH 01/27] implemented multiselection combobox --- .../widgets/multiselection_combobox.py | 335 ++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100644 pype/tools/settings/settings/widgets/multiselection_combobox.py diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py new file mode 100644 index 0000000000..d77de9f0e3 --- /dev/null +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -0,0 +1,335 @@ +from Qt import QtCore, QtGui, QtWidgets + + +class ComboItemDelegate(QtWidgets.QStyledItemDelegate): + """ + Helper styled delegate (mostly based on existing private Qt's + delegate used by the QtWidgets.QComboBox). Used to style the popup like a + list view (e.g windows style). + """ + + def paint(self, painter, option, index): + option = QtWidgets.QStyleOptionViewItem(option) + option.showDecorationSelected = True + + # option.state &= ( + # ~QtWidgets.QStyle.State_HasFocus + # & ~QtWidgets.QStyle.State_MouseOver + # ) + super(ComboItemDelegate, self).paint(painter, option, index) + + +class ComboMenuDelegate(QtWidgets.QAbstractItemDelegate): + """ + Helper styled delegate (mostly based on existing private Qt's + delegate used by the QtWidgets.QComboBox). Used to style the popup like a + menu. (e.g osx aqua style). + """ + + def paint(self, painter, option, index): + menuopt = self._menu_style_option(option, index) + if option.widget is not None: + style = option.widget.style() + else: + style = QtWidgets.QApplication.style() + style.drawControl(QtWidgets.QStyle.CE_MenuItem, menuopt, painter, + option.widget) + + def sizeHint(self, option, index): + menuopt = self._menu_style_option(option, index) + if option.widget is not None: + style = option.widget.style() + else: + style = QtWidgets.QApplication.style() + return style.sizeFromContents( + QtWidgets.QStyle.CT_MenuItem, menuopt, menuopt.rect.size(), + option.widget + ) + + def _menu_style_option(self, option, index): + menuoption = QtWidgets.QStyleOptionMenuItem() + if option.widget: + palette_source = option.widget.palette("QMenu") + else: + palette_source = QtWidgets.QApplication.palette("QMenu") + + palette = option.palette.resolve(palette_source) + foreground = index.data(QtCore.Qt.ForegroundRole) + if isinstance(foreground, (QtGui.QBrush, QtGui.QColor, QtGui.QPixmap)): + foreground = QtGui.QBrush(foreground) + palette.setBrush(QtGui.QPalette.Text, foreground) + palette.setBrush(QtGui.QPalette.ButtonText, foreground) + palette.setBrush(QtGui.QPalette.WindowText, foreground) + + background = index.data(QtCore.Qt.BackgroundRole) + if isinstance(background, (QtGui.QBrush, QtGui.QColor, QtGui.QPixmap)): + background = QtGui.QBrush(background) + palette.setBrush(QtGui.QPalette.Background, background) + + menuoption.palette = palette + + decoration = index.data(QtCore.Qt.DecorationRole) + if isinstance(decoration, QtGui.QIcon): + menuoption.icon = decoration + + menuoption.menuItemType = QtWidgets.QStyleOptionMenuItem.Normal + + if index.flags() & QtCore.Qt.ItemIsUserCheckable: + menuoption.checkType = QtWidgets.QStyleOptionMenuItem.NonExclusive + else: + menuoption.checkType = QtWidgets.QStyleOptionMenuItem.NotCheckable + + check = index.data(QtCore.Qt.CheckStateRole) + menuoption.checked = check == QtCore.Qt.Checked + + if option.widget is not None: + menuoption.font = option.widget.font() + else: + menuoption.font = QtWidgets.QApplication.font("QMenu") + + menuoption.maxIconWidth = option.decorationSize.width() + 4 + menuoption.rect = option.rect + menuoption.menuRect = option.rect + + # menuoption.menuHasCheckableItems = True + menuoption.tabWidth = 0 + # TODO: self.displayText(QVariant, QLocale) + # TODO: Why is this not a QtWidgets.QStyledItemDelegate? + menuoption.text = str(index.data(QtCore.Qt.DisplayRole)) + + menuoption.fontMetrics = QtGui.QFontMetrics(menuoption.font) + state = option.state & ( + QtWidgets.QStyle.State_MouseOver + | QtWidgets.QStyle.State_Selected + | QtWidgets.QStyle.State_Active + ) + + if index.flags() & QtCore.Qt.ItemIsEnabled: + state = state | QtWidgets.QStyle.State_Enabled + menuoption.palette.setCurrentColorGroup(QtGui.QPalette.Active) + else: + state = state & ~QtWidgets.QStyle.State_Enabled + menuoption.palette.setCurrentColorGroup(QtGui.QPalette.Disabled) + + if menuoption.checked: + state = state | QtWidgets.QStyle.State_On + else: + state = state | QtWidgets.QStyle.State_Off + + menuoption.state = state + return menuoption + + +class CheckComboBox(QtWidgets.QComboBox): + ignored_keys = { + QtCore.Qt.Key_Up, + QtCore.Qt.Key_Down, + QtCore.Qt.Key_PageDown, + QtCore.Qt.Key_PageUp, + QtCore.Qt.Key_Home, + QtCore.Qt.Key_End + } + + def __init__( + self, parent=None, placeholder_text="", separator=", ", **kwargs + ): + super(CheckComboBox, self).__init__(parent=parent, **kwargs) + self.setFocusPolicy(QtCore.Qt.StrongFocus) + + self._popup_is_shown = False + # self.__supressPopupHide = False + self._block_mouse_release_timer = QtCore.QTimer(self, singleShot=True) + self._initial_mouse_pos = None + self._separator = separator + self._placeholder_text = placeholder_text + self._update_item_delegate() + + def mousePressEvent(self, event): + """Reimplemented.""" + self._popup_is_shown = False + super(CheckComboBox, self).mousePressEvent(event) + if self._popup_is_shown: + self._initial_mouse_pos = self.mapToGlobal(event.pos()) + self._block_mouse_release_timer.start( + QtWidgets.QApplication.doubleClickInterval() + ) + + def changeEvent(self, event): + """Reimplemented.""" + if event.type() == QtCore.QEvent.StyleChange: + self._update_item_delegate() + super(CheckComboBox, self).changeEvent(event) + + def showPopup(self): + """Reimplemented.""" + super(CheckComboBox, self).showPopup() + view = self.view() + view.installEventFilter(self) + view.viewport().installEventFilter(self) + self._popup_is_shown = True + + def hidePopup(self): + """Reimplemented.""" + self.view().removeEventFilter(self) + self.view().viewport().removeEventFilter(self) + self._popup_is_shown = False + self._initial_mouse_pos = None + super(CheckComboBox, self).hidePopup() + self.view().clearFocus() + + def eventFilter(self, obj, event): + """Reimplemented.""" + if ( + self._popup_is_shown + and event.type() == QtCore.QEvent.MouseMove + and self.view().isVisible() + and self._initial_mouse_pos is not None + ): + diff = obj.mapToGlobal(event.pos()) - self._initial_mouse_pos + if ( + diff.manhattanLength() > 9 + and self._block_mouse_release_timer.isActive() + ): + self._block_mouse_release_timer.stop() + + current_index = self.view().currentIndex() + if ( + self._popup_is_shown + and event.type() == QtCore.QEvent.MouseButtonRelease + and self.view().isVisible() + and self.view().rect().contains(event.pos()) + and current_index.isValid() + and current_index.flags() & QtCore.Qt.ItemIsSelectable + and current_index.flags() & QtCore.Qt.ItemIsEnabled + and current_index.flags() & QtCore.Qt.ItemIsUserCheckable + and self.view().visualRect(current_index).contains(event.pos()) + and not self._block_mouse_release_timer.isActive() + ): + model = self.model() + index = self.view().currentIndex() + state = model.data(index, QtCore.Qt.CheckStateRole) + if state == QtCore.Qt.Unchecked: + check_state = QtCore.Qt.Checked + else: + check_state = QtCore.Qt.Unchecked + + model.setData(index, check_state, QtCore.Qt.CheckStateRole) + self.view().update(index) + self.update() + return True + + if self._popup_is_shown and event.type() == QtCore.QEvent.KeyPress: + if event.key() == QtCore.Qt.Key_Space: + # toogle the current items check state + model = self.model() + index = self.view().currentIndex() + flags = model.flags(index) + state = model.data(index, QtCore.Qt.CheckStateRole) + if flags & QtCore.Qt.ItemIsUserCheckable and \ + flags & QtCore.Qt.ItemIsTristate: + state = QtCore.Qt.CheckState((int(state) + 1) % 3) + elif flags & QtCore.Qt.ItemIsUserCheckable: + state = ( + QtCore.Qt.Checked + if state != QtCore.Qt.Checked + else QtCore.Qt.Unchecked + ) + model.setData(index, state, QtCore.Qt.CheckStateRole) + self.view().update(index) + self.update() + return True + # TODO: handle QtCore.Qt.Key_Enter, Key_Return? + + return super(CheckComboBox, self).eventFilter(obj, event) + + def paintEvent(self, event): + """Reimplemented.""" + painter = QtWidgets.QStylePainter(self) + option = QtWidgets.QStyleOptionComboBox() + self.initStyleOption(option) + painter.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, option) + # draw the icon and text + items = self.checked_items_text() + if not items: + option.currentText = self._placeholder_text + option.palette.setCurrentColorGroup(QtGui.QPalette.Disabled) + painter.drawControl(QtWidgets.QStyle.CE_ComboBoxLabel, option) + return + + # body_rect = QtCore.QRectF(option.rect) + + side_padding = 3 + item_spacing = 5 + font_metricts = self.fontMetrics() + left_x = option.rect.left() + 2 + for item in items: + rect = font_metricts.boundingRect(item) + rect.moveTop(option.rect.y()) + + label_height = rect.height() + + rect.moveLeft(left_x) + rect.setHeight(option.rect.height()) + + bg_rect = QtCore.QRect(rect) + bg_rect.setWidth(rect.width() + (2 * side_padding)) + left_x = bg_rect.right() + item_spacing + + rect.moveLeft(rect.x() + side_padding) + + remainder_half = (option.rect.height() - label_height) / 2 + remainder_quarter = int(remainder_half / 2) + 1 + bg_rect.setHeight(label_height + remainder_half) + bg_rect.moveTop(bg_rect.top() + remainder_quarter) + + path = QtGui.QPainterPath() + path.addRoundedRect(bg_rect, 5, 5) + + painter.fillPath(path, QtGui.QColor("#38d39f")) + + painter.drawText( + rect, + QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter, + item + ) + option.currentText = self._separator.join(items) + # option.currentIcon = QtGui.QIcon() + + def setItemCheckState(self, index, state): + self.setItemData(index, state, QtCore.Qt.CheckStateRole) + + def checked_items_text(self): + items = list() + for idx in range(self.count()): + state = self.itemData(idx, role=QtCore.Qt.CheckStateRole) + if state == QtCore.Qt.Checked: + items.append(self.itemText(idx)) + return items + + def wheelEvent(self, event): + event.ignore() + + def keyPressEvent(self, event): + if ( + event.key() == QtCore.Qt.Key_Down + and event.modifiers() & QtCore.Qt.AltModifier + ): + self.showPopup() + return + + if event.key() in self.ignored_keys: + event.ignore() + return + + return super(CheckComboBox, self).keyPressEvent(event) + + def _update_item_delegate(self): + opt = QtWidgets.QStyleOptionComboBox() + opt.initFrom(self) + if self.style().styleHint( + QtWidgets.QStyle.SH_ComboBox_Popup, opt, self + ): + delegate = ComboMenuDelegate(self) + else: + delegate = ComboItemDelegate(self) + self.setItemDelegate(delegate) From 0ce16680044b8f17f6c3229ed95cd6a69e72d979 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 13:10:09 +0200 Subject: [PATCH 02/27] implemented basic combobox with custom modifications --- .../settings/settings/widgets/widgets.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index 2a1f5fe804..616e605a35 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -25,6 +25,28 @@ class NumberSpinBox(QtWidgets.QDoubleSpinBox): return output +class ComboBox(QtWidgets.QComboBox): + value_changed = QtCore.Signal() + + def __init__(self, *args, **kwargs): + super(ComboBox, self).__init__(*args, **kwargs) + + self.currentIndexChanged.connect(self._on_change) + + def _on_change(self, *args, **kwargs): + self.value_changed.emit() + + def set_value(self, value): + for idx in range(self.count()): + _value = self.itemData(idx, role=QtCore.Qt.UserRole) + if _value == value: + self.setCurrentIndex(idx) + break + + def value(self): + return self.itemData(self.currentIndex(), role=QtCore.Qt.UserRole) + + class PathInput(QtWidgets.QLineEdit): def clear_end_path(self): value = self.text().strip() From 8aefe456ae4c97d543d11d77c4680ddacfd0716c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 13:10:30 +0200 Subject: [PATCH 03/27] multiselectio ncheckbox has methods for getting and setting value --- .../widgets/multiselection_combobox.py | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index d77de9f0e3..98e6048cce 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -121,6 +121,7 @@ class ComboMenuDelegate(QtWidgets.QAbstractItemDelegate): class CheckComboBox(QtWidgets.QComboBox): + value_changed = QtCore.Signal() ignored_keys = { QtCore.Qt.Key_Up, QtCore.Qt.Key_Down, @@ -131,7 +132,7 @@ class CheckComboBox(QtWidgets.QComboBox): } def __init__( - self, parent=None, placeholder_text="", separator=", ", **kwargs + self, parent=None, placeholder="", separator=", ", **kwargs ): super(CheckComboBox, self).__init__(parent=parent, **kwargs) self.setFocusPolicy(QtCore.Qt.StrongFocus) @@ -141,7 +142,7 @@ class CheckComboBox(QtWidgets.QComboBox): self._block_mouse_release_timer = QtCore.QTimer(self, singleShot=True) self._initial_mouse_pos = None self._separator = separator - self._placeholder_text = placeholder_text + self._placeholder_text = placeholder self._update_item_delegate() def mousePressEvent(self, event): @@ -216,6 +217,7 @@ class CheckComboBox(QtWidgets.QComboBox): model.setData(index, check_state, QtCore.Qt.CheckStateRole) self.view().update(index) self.update() + self.value_changed.emit() return True if self._popup_is_shown and event.type() == QtCore.QEvent.KeyPress: @@ -298,6 +300,26 @@ class CheckComboBox(QtWidgets.QComboBox): def setItemCheckState(self, index, state): self.setItemData(index, state, QtCore.Qt.CheckStateRole) + def set_value(self, values): + for idx in range(self.count()): + value = self.itemData(idx, role=QtCore.Qt.UserRole) + state = self.itemData(idx, role=QtCore.Qt.CheckStateRole) + if value in values: + check_state = QtCore.Qt.Checked + else: + check_state = QtCore.Qt.Unchecked + self.setItemData(idx, check_state, QtCore.Qt.CheckStateRole) + + def value(self): + items = list() + for idx in range(self.count()): + state = self.itemData(idx, role=QtCore.Qt.CheckStateRole) + if state == QtCore.Qt.Checked: + items.append( + self.itemData(idx, role=QtCore.Qt.UserRole) + ) + return items + def checked_items_text(self): items = list() for idx in range(self.count()): From b700de57ddb5993ae91cc920ff09559b9f776ba3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 13:10:49 +0200 Subject: [PATCH 04/27] implemented enumerator item --- .../settings/settings/widgets/item_types.py | 106 +++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index e589b89c0f..634b14ab0e 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -6,8 +6,10 @@ from .widgets import ( ExpandingWidget, NumberSpinBox, PathInput, - GridLabelWidget + GridLabelWidget, + ComboBox ) +from .multiselection_combobox import CheckComboBox from .lib import NOT_SET, METADATA_KEY, TypeToKlass, CHILD_OFFSET from avalon.vendor import qtawesome @@ -827,6 +829,107 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): return self.checkbox.isChecked() +class EnumeratorWidget(QtWidgets.QWidget, InputObject): + default_input_value = True + value_changed = QtCore.Signal(object) + + def __init__( + self, input_data, parent, + as_widget=False, label_widget=None, parent_widget=None + ): + if parent_widget is None: + parent_widget = parent + super(EnumeratorWidget, self).__init__(parent_widget) + + self.initial_attributes(input_data, parent, as_widget) + self.multiselection = input_data.get("multiselection") + self.enum_items = input_data["enum_items"] + if not self.enum_items: + raise ValueError( + "Attribute `enum_items` is not defined." + ) + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(5) + + if not self._as_widget: + self.key = input_data["key"] + if not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + layout.addWidget(label_widget, 0) + self.label_widget = label_widget + + if self.multiselection: + placeholder = input_data.get("placeholder") + self.input_field = CheckComboBox( + placeholder=placeholder, parent=self + ) + else: + self.input_field = ComboBox(self) + + first_value = None + for enum_item in self.enum_items: + for value, label in enum_item.items(): + if first_value is None: + first_value = value + self.input_field.addItem(label, value) + + self._first_value = first_value + + layout.addWidget(self.input_field, 0) + + self.setFocusProxy(self.input_field) + + self.input_field.value_changed.connect(self._on_value_change) + + @property + def default_input_value(self): + if self.multiselection: + return [] + return self._first_value + + def set_value(self, value): + # Ignore value change because if `self.isChecked()` has same + # value as `value` the `_on_value_change` is not triggered + self.input_field.set_value(value) + + def update_style(self): + if self._as_widget: + if not self.isEnabled(): + state = self.style_state(False, False, False, False) + else: + state = self.style_state( + False, + self._is_invalid, + False, + self._is_modified + ) + else: + state = self.style_state( + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified + ) + if self._state == state: + return + + if self._as_widget: + property_name = "input-state" + else: + property_name = "state" + + self.label_widget.setProperty(property_name, state) + self.label_widget.style().polish(self.label_widget) + self._state = state + + def item_value(self): + return self.input_field.value() + + class NumberWidget(QtWidgets.QWidget, InputObject): default_input_value = 0 value_changed = QtCore.Signal(object) @@ -3494,6 +3597,7 @@ TypeToKlass.types["path-input"] = PathInputWidget TypeToKlass.types["raw-json"] = RawJsonWidget TypeToKlass.types["list"] = ListWidget TypeToKlass.types["list-strict"] = ListStrictWidget +TypeToKlass.types["enum"] = EnumeratorWidget TypeToKlass.types["dict-modifiable"] = ModifiableDict # DEPRECATED - remove when removed from schemas TypeToKlass.types["dict-item"] = DictWidget From 4954a3dba0f9d793f5fb319e84aa39894da6147e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 14:04:15 +0200 Subject: [PATCH 05/27] fix checkables in multiselection --- pype/tools/settings/settings/widgets/item_types.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 634b14ab0e..274aeff86a 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -877,6 +877,11 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): first_value = value self.input_field.addItem(label, value) + if self.multiselection: + model = self.input_field.model() + for idx in range(self.input_field.count()): + model.item(idx).setCheckable(True) + self._first_value = first_value layout.addWidget(self.input_field, 0) From 918ff9eefa91b814d4f0312010738568e7745653 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 14:04:36 +0200 Subject: [PATCH 06/27] changed bg_rect to QRectF --- .../settings/settings/widgets/multiselection_combobox.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 98e6048cce..029f577032 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -273,7 +273,7 @@ class CheckComboBox(QtWidgets.QComboBox): rect.moveLeft(left_x) rect.setHeight(option.rect.height()) - bg_rect = QtCore.QRect(rect) + bg_rect = QtCore.QRectF(rect) bg_rect.setWidth(rect.width() + (2 * side_padding)) left_x = bg_rect.right() + item_spacing @@ -287,7 +287,7 @@ class CheckComboBox(QtWidgets.QComboBox): path = QtGui.QPainterPath() path.addRoundedRect(bg_rect, 5, 5) - painter.fillPath(path, QtGui.QColor("#38d39f")) + painter.fillPath(path, QtGui.QColor("#555555")) painter.drawText( rect, From f6f75c6fb33a6880a5e6b68b171f4d86ad4cf42f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 14:04:49 +0200 Subject: [PATCH 07/27] added enum to examples --- .../gui_schemas/system_schema/1_examples.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json b/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json index 0578968508..00aef304a9 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json @@ -9,6 +9,25 @@ "type": "dict-invisible", "children": [ { + "type": "enum", + "key": "test_enum_singleselection", + "label": "Enum Single Selection", + "enum_items": [ + {"value_1": "Label 1"}, + {"value_2": "Label 2"}, + {"value_3": "Label 3"} + ] + }, { + "type": "enum", + "key": "test_enum_multiselection", + "label": "Enum Multi Selection", + "multiselection": true, + "enum_items": [ + {"value_1": "Label 1"}, + {"value_2": "Label 2"}, + {"value_3": "Label 3"} + ] + }, { "type": "boolean", "key": "bool", "label": "Boolean checkbox" From 6e49beb9c38e5e20d81333c4f8d62339935b2853 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 14:56:44 +0200 Subject: [PATCH 08/27] added style for combobox --- pype/tools/settings/settings/style/style.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pype/tools/settings/settings/style/style.css b/pype/tools/settings/settings/style/style.css index 3f648abef8..c4fce7aa90 100644 --- a/pype/tools/settings/settings/style/style.css +++ b/pype/tools/settings/settings/style/style.css @@ -38,6 +38,14 @@ QLineEdit:disabled, QSpinBox:disabled, QDoubleSpinBox:disabled, QPlainTextEdit:d QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QPlainTextEdit:focus, QTextEdit:focus { border: 1px solid #ffffff; } + +QComboBox { + border: 1px solid #aaaaaa; + border-radius: 3px; + padding: 2px 2px 4px 4px; + background: #1d272f; +} + QToolButton { background: transparent; } From 4b70f708566bc1a06ef6295ced0e3e4783266fff Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 16:35:48 +0200 Subject: [PATCH 09/27] multiselection combobox expand size by its items --- .../widgets/multiselection_combobox.py | 140 +++++++++++++----- 1 file changed, 104 insertions(+), 36 deletions(-) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 029f577032..30b0c89d28 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -131,6 +131,13 @@ class CheckComboBox(QtWidgets.QComboBox): QtCore.Qt.Key_End } + padding = 2 + left_offset = 2 + h_margins = 2 + item_spacing = 5 + + item_bg_color = QtGui.QColor("#555555") + def __init__( self, parent=None, placeholder="", separator=", ", **kwargs ): @@ -142,9 +149,16 @@ class CheckComboBox(QtWidgets.QComboBox): self._block_mouse_release_timer = QtCore.QTimer(self, singleShot=True) self._initial_mouse_pos = None self._separator = separator - self._placeholder_text = placeholder + self.placeholder_text = placeholder self._update_item_delegate() + self.lines = {} + self.item_height = ( + self.fontMetrics().height() + + (2 * self.padding) + + (2 * self.h_margins) + ) + def mousePressEvent(self, event): """Reimplemented.""" self._popup_is_shown = False @@ -216,7 +230,7 @@ class CheckComboBox(QtWidgets.QComboBox): model.setData(index, check_state, QtCore.Qt.CheckStateRole) self.view().update(index) - self.update() + self.update_size_hint() self.value_changed.emit() return True @@ -250,52 +264,106 @@ class CheckComboBox(QtWidgets.QComboBox): option = QtWidgets.QStyleOptionComboBox() self.initStyleOption(option) painter.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, option) + # draw the icon and text items = self.checked_items_text() if not items: - option.currentText = self._placeholder_text + option.currentText = self.placeholder_text option.palette.setCurrentColorGroup(QtGui.QPalette.Disabled) painter.drawControl(QtWidgets.QStyle.CE_ComboBoxLabel, option) return - # body_rect = QtCore.QRectF(option.rect) - - side_padding = 3 - item_spacing = 5 font_metricts = self.fontMetrics() - left_x = option.rect.left() + 2 + for line, items in self.lines.items(): + top_y = option.rect.top() + (line * self.item_height) + left_x = option.rect.left() + self.left_offset + for item in items: + label_rect = font_metricts.boundingRect(item) + label_height = label_rect.height() + + label_rect.moveTop(top_y) + label_rect.moveLeft(left_x) + label_rect.setHeight(self.item_height) + + bg_rect = QtCore.QRectF(label_rect) + bg_rect.setWidth(label_rect.width() + (2 * self.padding)) + left_x = bg_rect.right() + self.item_spacing + + label_rect.moveLeft(label_rect.x() + self.padding) + + bg_rect.setHeight(label_height + (2 * self.padding)) + bg_rect.moveTop(bg_rect.top() + self.h_margins) + + path = QtGui.QPainterPath() + path.addRoundedRect(bg_rect, 5, 5) + + painter.fillPath(path, self.item_bg_color) + + painter.drawText( + label_rect, + QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter, + item + ) + + def resizeEvent(self, *args, **kwargs): + super(CheckComboBox, self).resizeEvent(*args, **kwargs) + self.update_size_hint() + + def update_size_hint(self): + previous_lines = len(self.lines) + + self.lines = {} + + items = self.checked_items_text() + if not items: + self.update() + return + + option = QtWidgets.QStyleOptionComboBox() + self.initStyleOption(option) + btn_rect = self.style().subControlRect( + QtWidgets.QStyle.CC_ComboBox, + option, + QtWidgets.QStyle.SC_ComboBoxArrow + ) + total_width = self.width() - btn_rect.width() + font_metricts = self.fontMetrics() + + line = 0 + self.lines = {line: []} + + font_metricts = self.fontMetrics() + left_x = None for item in items: + if left_x is None: + left_x = 0 + self.left_offset rect = font_metricts.boundingRect(item) - rect.moveTop(option.rect.y()) + width = rect.width() + (2 * self.padding) + right_x = left_x + width + if right_x > total_width: + if self.lines.get(line): + line += 1 + left_x = None + self.lines[line] = [item] + else: + self.lines[line] = [item] + line += 1 + left_x = None + else: + self.lines[line].append(item) + left_x = left_x + width + self.item_spacing - label_height = rect.height() + self.update() + if len(self.lines) != previous_lines: + self.updateGeometry() - rect.moveLeft(left_x) - rect.setHeight(option.rect.height()) - - bg_rect = QtCore.QRectF(rect) - bg_rect.setWidth(rect.width() + (2 * side_padding)) - left_x = bg_rect.right() + item_spacing - - rect.moveLeft(rect.x() + side_padding) - - remainder_half = (option.rect.height() - label_height) / 2 - remainder_quarter = int(remainder_half / 2) + 1 - bg_rect.setHeight(label_height + remainder_half) - bg_rect.moveTop(bg_rect.top() + remainder_quarter) - - path = QtGui.QPainterPath() - path.addRoundedRect(bg_rect, 5, 5) - - painter.fillPath(path, QtGui.QColor("#555555")) - - painter.drawText( - rect, - QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter, - item - ) - option.currentText = self._separator.join(items) - # option.currentIcon = QtGui.QIcon() + def sizeHint(self): + value = super(CheckComboBox, self).sizeHint() + lines = len(self.lines) + if lines == 0: + lines = 1 + value.setHeight(lines * self.item_height) + return value def setItemCheckState(self, index, state): self.setItemData(index, state, QtCore.Qt.CheckStateRole) From e779375b9b3e61d5d9e1810cdb7ca6f67d1d7f8b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 16:55:31 +0200 Subject: [PATCH 10/27] renamed CheckComboBox to MultiSelectionComboBox --- .../settings/settings/widgets/item_types.py | 4 ++-- .../widgets/multiselection_combobox.py | 20 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 274aeff86a..33585773f9 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -9,7 +9,7 @@ from .widgets import ( GridLabelWidget, ComboBox ) -from .multiselection_combobox import CheckComboBox +from .multiselection_combobox import MultiSelectionComboBox from .lib import NOT_SET, METADATA_KEY, TypeToKlass, CHILD_OFFSET from avalon.vendor import qtawesome @@ -864,7 +864,7 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): if self.multiselection: placeholder = input_data.get("placeholder") - self.input_field = CheckComboBox( + self.input_field = MultiSelectionComboBox( placeholder=placeholder, parent=self ) else: diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 30b0c89d28..d49ebeb45a 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -120,7 +120,7 @@ class ComboMenuDelegate(QtWidgets.QAbstractItemDelegate): return menuoption -class CheckComboBox(QtWidgets.QComboBox): +class MultiSelectionComboBox(QtWidgets.QComboBox): value_changed = QtCore.Signal() ignored_keys = { QtCore.Qt.Key_Up, @@ -141,7 +141,7 @@ class CheckComboBox(QtWidgets.QComboBox): def __init__( self, parent=None, placeholder="", separator=", ", **kwargs ): - super(CheckComboBox, self).__init__(parent=parent, **kwargs) + super(MultiSelectionComboBox, self).__init__(parent=parent, **kwargs) self.setFocusPolicy(QtCore.Qt.StrongFocus) self._popup_is_shown = False @@ -162,7 +162,7 @@ class CheckComboBox(QtWidgets.QComboBox): def mousePressEvent(self, event): """Reimplemented.""" self._popup_is_shown = False - super(CheckComboBox, self).mousePressEvent(event) + super(MultiSelectionComboBox, self).mousePressEvent(event) if self._popup_is_shown: self._initial_mouse_pos = self.mapToGlobal(event.pos()) self._block_mouse_release_timer.start( @@ -173,11 +173,11 @@ class CheckComboBox(QtWidgets.QComboBox): """Reimplemented.""" if event.type() == QtCore.QEvent.StyleChange: self._update_item_delegate() - super(CheckComboBox, self).changeEvent(event) + super(MultiSelectionComboBox, self).changeEvent(event) def showPopup(self): """Reimplemented.""" - super(CheckComboBox, self).showPopup() + super(MultiSelectionComboBox, self).showPopup() view = self.view() view.installEventFilter(self) view.viewport().installEventFilter(self) @@ -189,7 +189,7 @@ class CheckComboBox(QtWidgets.QComboBox): self.view().viewport().removeEventFilter(self) self._popup_is_shown = False self._initial_mouse_pos = None - super(CheckComboBox, self).hidePopup() + super(MultiSelectionComboBox, self).hidePopup() self.view().clearFocus() def eventFilter(self, obj, event): @@ -256,7 +256,7 @@ class CheckComboBox(QtWidgets.QComboBox): return True # TODO: handle QtCore.Qt.Key_Enter, Key_Return? - return super(CheckComboBox, self).eventFilter(obj, event) + return super(MultiSelectionComboBox, self).eventFilter(obj, event) def paintEvent(self, event): """Reimplemented.""" @@ -306,7 +306,7 @@ class CheckComboBox(QtWidgets.QComboBox): ) def resizeEvent(self, *args, **kwargs): - super(CheckComboBox, self).resizeEvent(*args, **kwargs) + super(MultiSelectionComboBox, self).resizeEvent(*args, **kwargs) self.update_size_hint() def update_size_hint(self): @@ -358,7 +358,7 @@ class CheckComboBox(QtWidgets.QComboBox): self.updateGeometry() def sizeHint(self): - value = super(CheckComboBox, self).sizeHint() + value = super(MultiSelectionComboBox, self).sizeHint() lines = len(self.lines) if lines == 0: lines = 1 @@ -411,7 +411,7 @@ class CheckComboBox(QtWidgets.QComboBox): event.ignore() return - return super(CheckComboBox, self).keyPressEvent(event) + return super(MultiSelectionComboBox, self).keyPressEvent(event) def _update_item_delegate(self): opt = QtWidgets.QStyleOptionComboBox() From 13576aeedcf07646b72294cb9adcb75d73ca54f5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 16:58:52 +0200 Subject: [PATCH 11/27] added a little bit more atomicity to padding and margins --- .../widgets/multiselection_combobox.py | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index d49ebeb45a..d7179f07f0 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -131,9 +131,10 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): QtCore.Qt.Key_End } - padding = 2 + top_bottom_padding = 2 + left_right_padding = 3 left_offset = 2 - h_margins = 2 + top_bottom_margins = 2 item_spacing = 5 item_bg_color = QtGui.QColor("#555555") @@ -155,8 +156,8 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): self.lines = {} self.item_height = ( self.fontMetrics().height() - + (2 * self.padding) - + (2 * self.h_margins) + + (2 * self.top_bottom_padding) + + (2 * self.top_bottom_margins) ) def mousePressEvent(self, event): @@ -275,7 +276,11 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): font_metricts = self.fontMetrics() for line, items in self.lines.items(): - top_y = option.rect.top() + (line * self.item_height) + top_y = ( + option.rect.top() + + (line * self.item_height) + + self.top_bottom_margins + ) left_x = option.rect.left() + self.left_offset for item in items: label_rect = font_metricts.boundingRect(item) @@ -286,13 +291,16 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): label_rect.setHeight(self.item_height) bg_rect = QtCore.QRectF(label_rect) - bg_rect.setWidth(label_rect.width() + (2 * self.padding)) + bg_rect.setWidth( + label_rect.width() + + (2 * self.left_right_padding) + ) left_x = bg_rect.right() + self.item_spacing - label_rect.moveLeft(label_rect.x() + self.padding) + label_rect.moveLeft(label_rect.x() + self.left_right_padding) - bg_rect.setHeight(label_height + (2 * self.padding)) - bg_rect.moveTop(bg_rect.top() + self.h_margins) + bg_rect.setHeight(label_height + (2 * self.top_bottom_padding)) + bg_rect.moveTop(bg_rect.top() + self.top_bottom_margins) path = QtGui.QPainterPath() path.addRoundedRect(bg_rect, 5, 5) @@ -338,7 +346,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): if left_x is None: left_x = 0 + self.left_offset rect = font_metricts.boundingRect(item) - width = rect.width() + (2 * self.padding) + width = rect.width() + (2 * self.left_right_padding) right_x = left_x + width if right_x > total_width: if self.lines.get(line): @@ -362,7 +370,10 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): lines = len(self.lines) if lines == 0: lines = 1 - value.setHeight(lines * self.item_height) + value.setHeight( + (lines * self.item_height) + + (2 * self.top_bottom_margins) + ) return value def setItemCheckState(self, index, state): From 016ea3146bd55f2809173731371121fd5fc8aa5c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 16:59:08 +0200 Subject: [PATCH 12/27] added style for multiselection combobox --- pype/tools/settings/settings/style/style.css | 4 ++++ .../settings/settings/widgets/multiselection_combobox.py | 1 + 2 files changed, 5 insertions(+) diff --git a/pype/tools/settings/settings/style/style.css b/pype/tools/settings/settings/style/style.css index c4fce7aa90..796efa22a6 100644 --- a/pype/tools/settings/settings/style/style.css +++ b/pype/tools/settings/settings/style/style.css @@ -110,6 +110,10 @@ QPushButton[btn-type="expand-toggle"] { font-weight: bold; } +#MultiSelectionComboBox { + font-size: 12px; +} + #DictKey[state="studio"] {border-color: #bfccd6;} #DictKey[state="modified"] {border-color: #137cbd;} #DictKey[state="overriden"] {border-color: #00f;} diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index d7179f07f0..ddd4f65e65 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -143,6 +143,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): self, parent=None, placeholder="", separator=", ", **kwargs ): super(MultiSelectionComboBox, self).__init__(parent=parent, **kwargs) + self.setObjectName("MultiSelectionComboBox") self.setFocusPolicy(QtCore.Qt.StrongFocus) self._popup_is_shown = False From 1c1676f6f8924dcd826d2832ef0fdb41c446d7a7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 17:06:54 +0200 Subject: [PATCH 13/27] final touches --- .../settings/settings/widgets/multiselection_combobox.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index ddd4f65e65..b02d19f9c4 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -133,11 +133,11 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): top_bottom_padding = 2 left_right_padding = 3 - left_offset = 2 + left_offset = 4 top_bottom_margins = 2 item_spacing = 5 - item_bg_color = QtGui.QColor("#555555") + item_bg_color = QtGui.QColor("#31424e") def __init__( self, parent=None, placeholder="", separator=", ", **kwargs From 49ac226f30a6c99ad8dce87f5ac19190af6695c9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 17:32:21 +0200 Subject: [PATCH 14/27] line width is calculated right --- .../widgets/multiselection_combobox.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index b02d19f9c4..85dd538cd0 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -32,8 +32,9 @@ class ComboMenuDelegate(QtWidgets.QAbstractItemDelegate): style = option.widget.style() else: style = QtWidgets.QApplication.style() - style.drawControl(QtWidgets.QStyle.CE_MenuItem, menuopt, painter, - option.widget) + style.drawControl( + QtWidgets.QStyle.CE_MenuItem, menuopt, painter, option.widget + ) def sizeHint(self, option, index): menuopt = self._menu_style_option(option, index) @@ -335,36 +336,34 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): option, QtWidgets.QStyle.SC_ComboBoxArrow ) - total_width = self.width() - btn_rect.width() + total_width = option.rect.width() - btn_rect.width() font_metricts = self.fontMetrics() line = 0 self.lines = {line: []} font_metricts = self.fontMetrics() - left_x = None + default_left_x = 0 + self.left_offset + left_x = int(default_left_x) for item in items: - if left_x is None: - left_x = 0 + self.left_offset rect = font_metricts.boundingRect(item) width = rect.width() + (2 * self.left_right_padding) right_x = left_x + width if right_x > total_width: + left_x = int(default_left_x) if self.lines.get(line): line += 1 - left_x = None self.lines[line] = [item] + left_x += width else: self.lines[line] = [item] line += 1 - left_x = None else: self.lines[line].append(item) left_x = left_x + width + self.item_spacing self.update() - if len(self.lines) != previous_lines: - self.updateGeometry() + self.updateGeometry() def sizeHint(self): value = super(MultiSelectionComboBox, self).sizeHint() From 85e67b6ce25da02919ebc16b56323489fd6fef1d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 17:35:23 +0200 Subject: [PATCH 15/27] fix stretch --- pype/tools/settings/settings/widgets/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index ee4762de14..404d7b700b 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -266,7 +266,7 @@ class SystemWidget(QtWidgets.QWidget): klass = lib.TypeToKlass.types.get(item_type) item = klass(child_configuration, self) self.input_fields.append(item) - self.content_layout.addWidget(item) + self.content_layout.addWidget(item, 0) # Add spacer to stretch children guis spacer = QtWidgets.QWidget(self.content_widget) @@ -532,7 +532,7 @@ class ProjectWidget(QtWidgets.QWidget): klass = lib.TypeToKlass.types.get(item_type) item = klass(child_configuration, self) self.input_fields.append(item) - self.content_layout.addWidget(item) + self.content_layout.addWidget(item, 0) # Add spacer to stretch children guis spacer = QtWidgets.QWidget(self.content_widget) From 34d16bb0960789b4a3e994e25c490a698f04b8a6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 18:21:26 +0200 Subject: [PATCH 16/27] small cleanup --- pype/tools/settings/settings/style/style.css | 4 ++++ .../settings/settings/widgets/multiselection_combobox.py | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/style/style.css b/pype/tools/settings/settings/style/style.css index 796efa22a6..ebea87203d 100644 --- a/pype/tools/settings/settings/style/style.css +++ b/pype/tools/settings/settings/style/style.css @@ -46,6 +46,10 @@ QComboBox { background: #1d272f; } +QComboBox QAbstractItemView::item { + padding: 3px; +} + QToolButton { background: transparent; } diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 85dd538cd0..0c2d57aed8 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -148,7 +148,6 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): self.setFocusPolicy(QtCore.Qt.StrongFocus) self._popup_is_shown = False - # self.__supressPopupHide = False self._block_mouse_release_timer = QtCore.QTimer(self, singleShot=True) self._initial_mouse_pos = None self._separator = separator From 102a8ead4c0ddf95844cffce37d610d355947ec9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 18:30:55 +0200 Subject: [PATCH 17/27] added enumerator to ExtractReview --- .../projects_schema/1_plugins_gui_schema.json | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json b/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json index f357b51dc5..2fefe8df2d 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json @@ -202,8 +202,15 @@ }, { "key": "tags", "label": "Tags", - "type": "list", - "object_type": "text" + "type": "enum", + "multiselection": true, + "enum_items": [ + {"burnin": "Add burnins"}, + {"ftrackreview": "Add to Ftrack"}, + {"delete": "Delete output"}, + {"slate-frame": "Add slate frame"}, + {"no-hnadles": "Skip handle frames"} + ] }, { "key": "ffmpeg_args", "label": "FFmpeg arguments", From 5410bab315df471f5f68b161b8e3d1f9fcd77bd6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 18:40:32 +0200 Subject: [PATCH 18/27] added readme --- pype/tools/settings/settings/README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/pype/tools/settings/settings/README.md b/pype/tools/settings/settings/README.md index 47bbf28ba5..9492d8bc7b 100644 --- a/pype/tools/settings/settings/README.md +++ b/pype/tools/settings/settings/README.md @@ -168,6 +168,29 @@ } ``` +### enum +- returns value of single on multiple items from predefined values +- multiselection can be allowed with setting key `"multiselection"` to `True` (Default: `False`) +- values are defined under value of key `"enum_items"` as list + - each item in list is simple dictionary where value is label and key is value which will be stored + - should be possible to enter single dictionary if order of items doesn't matter + +``` +{ + "key": "tags", + "label": "Tags", + "type": "enum", + "multiselection": true, + "enum_items": [ + {"burnin": "Add burnins"}, + {"ftrackreview": "Add to Ftrack"}, + {"delete": "Delete output"}, + {"slate-frame": "Add slate frame"}, + {"no-hnadles": "Skip handle frames"} + ] +} +``` + ## Inputs for setting value using Pure inputs - these inputs also have required `"key"` and `"label"` - they use Pure inputs "as widgets" From 9ed5778b51e6df049a9c6d29213576244b695b0f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 18:46:13 +0200 Subject: [PATCH 19/27] removed unused variables --- .../tools/settings/settings/widgets/multiselection_combobox.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 0c2d57aed8..0106051cc4 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -319,8 +319,6 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): self.update_size_hint() def update_size_hint(self): - previous_lines = len(self.lines) - self.lines = {} items = self.checked_items_text() @@ -381,7 +379,6 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): def set_value(self, values): for idx in range(self.count()): value = self.itemData(idx, role=QtCore.Qt.UserRole) - state = self.itemData(idx, role=QtCore.Qt.CheckStateRole) if value in values: check_state = QtCore.Qt.Checked else: From 3aaf4433274fd322aac1656feaec17620443b034 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 10:04:56 +0200 Subject: [PATCH 20/27] moved enumerator --- .../settings/settings/widgets/item_types.py | 212 +++++++++--------- 1 file changed, 106 insertions(+), 106 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 33585773f9..6e169b07b1 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -829,112 +829,6 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): return self.checkbox.isChecked() -class EnumeratorWidget(QtWidgets.QWidget, InputObject): - default_input_value = True - value_changed = QtCore.Signal(object) - - def __init__( - self, input_data, parent, - as_widget=False, label_widget=None, parent_widget=None - ): - if parent_widget is None: - parent_widget = parent - super(EnumeratorWidget, self).__init__(parent_widget) - - self.initial_attributes(input_data, parent, as_widget) - self.multiselection = input_data.get("multiselection") - self.enum_items = input_data["enum_items"] - if not self.enum_items: - raise ValueError( - "Attribute `enum_items` is not defined." - ) - - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - - if not self._as_widget: - self.key = input_data["key"] - if not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) - layout.addWidget(label_widget, 0) - self.label_widget = label_widget - - if self.multiselection: - placeholder = input_data.get("placeholder") - self.input_field = MultiSelectionComboBox( - placeholder=placeholder, parent=self - ) - else: - self.input_field = ComboBox(self) - - first_value = None - for enum_item in self.enum_items: - for value, label in enum_item.items(): - if first_value is None: - first_value = value - self.input_field.addItem(label, value) - - if self.multiselection: - model = self.input_field.model() - for idx in range(self.input_field.count()): - model.item(idx).setCheckable(True) - - self._first_value = first_value - - layout.addWidget(self.input_field, 0) - - self.setFocusProxy(self.input_field) - - self.input_field.value_changed.connect(self._on_value_change) - - @property - def default_input_value(self): - if self.multiselection: - return [] - return self._first_value - - def set_value(self, value): - # Ignore value change because if `self.isChecked()` has same - # value as `value` the `_on_value_change` is not triggered - self.input_field.set_value(value) - - def update_style(self): - if self._as_widget: - if not self.isEnabled(): - state = self.style_state(False, False, False, False) - else: - state = self.style_state( - False, - self._is_invalid, - False, - self._is_modified - ) - else: - state = self.style_state( - self.has_studio_override, - self.is_invalid, - self.is_overriden, - self.is_modified - ) - if self._state == state: - return - - if self._as_widget: - property_name = "input-state" - else: - property_name = "state" - - self.label_widget.setProperty(property_name, state) - self.label_widget.style().polish(self.label_widget) - self._state = state - - def item_value(self): - return self.input_field.value() - - class NumberWidget(QtWidgets.QWidget, InputObject): default_input_value = 0 value_changed = QtCore.Signal(object) @@ -1180,6 +1074,112 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): return self.path_input.text() +class EnumeratorWidget(QtWidgets.QWidget, InputObject): + default_input_value = True + value_changed = QtCore.Signal(object) + + def __init__( + self, input_data, parent, + as_widget=False, label_widget=None, parent_widget=None + ): + if parent_widget is None: + parent_widget = parent + super(EnumeratorWidget, self).__init__(parent_widget) + + self.initial_attributes(input_data, parent, as_widget) + self.multiselection = input_data.get("multiselection") + self.enum_items = input_data["enum_items"] + if not self.enum_items: + raise ValueError( + "Attribute `enum_items` is not defined." + ) + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(5) + + if not self._as_widget: + self.key = input_data["key"] + if not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + layout.addWidget(label_widget, 0) + self.label_widget = label_widget + + if self.multiselection: + placeholder = input_data.get("placeholder") + self.input_field = MultiSelectionComboBox( + placeholder=placeholder, parent=self + ) + else: + self.input_field = ComboBox(self) + + first_value = None + for enum_item in self.enum_items: + for value, label in enum_item.items(): + if first_value is None: + first_value = value + self.input_field.addItem(label, value) + + if self.multiselection: + model = self.input_field.model() + for idx in range(self.input_field.count()): + model.item(idx).setCheckable(True) + + self._first_value = first_value + + layout.addWidget(self.input_field, 0) + + self.setFocusProxy(self.input_field) + + self.input_field.value_changed.connect(self._on_value_change) + + @property + def default_input_value(self): + if self.multiselection: + return [] + return self._first_value + + def set_value(self, value): + # Ignore value change because if `self.isChecked()` has same + # value as `value` the `_on_value_change` is not triggered + self.input_field.set_value(value) + + def update_style(self): + if self._as_widget: + if not self.isEnabled(): + state = self.style_state(False, False, False, False) + else: + state = self.style_state( + False, + self._is_invalid, + False, + self._is_modified + ) + else: + state = self.style_state( + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified + ) + if self._state == state: + return + + if self._as_widget: + property_name = "input-state" + else: + property_name = "state" + + self.label_widget.setProperty(property_name, state) + self.label_widget.style().polish(self.label_widget) + self._state = state + + def item_value(self): + return self.input_field.value() + + class RawJsonInput(QtWidgets.QPlainTextEdit): tab_length = 4 From dfaa62ef952758d51076fec4ff142bf8d9018bd2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 10:19:35 +0200 Subject: [PATCH 21/27] enum has better style changes --- .../settings/settings/widgets/item_types.py | 39 ++++++++----------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 6e169b07b1..647ec96c58 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1090,9 +1090,7 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): self.multiselection = input_data.get("multiselection") self.enum_items = input_data["enum_items"] if not self.enum_items: - raise ValueError( - "Attribute `enum_items` is not defined." - ) + raise ValueError("Attribute `enum_items` is not defined.") layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -1105,7 +1103,7 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): label_widget = QtWidgets.QLabel(label) label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) layout.addWidget(label_widget, 0) - self.label_widget = label_widget + self.label_widget = label_widget if self.multiselection: placeholder = input_data.get("placeholder") @@ -1121,14 +1119,13 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): if first_value is None: first_value = value self.input_field.addItem(label, value) + self._first_value = first_value if self.multiselection: model = self.input_field.model() for idx in range(self.input_field.count()): model.item(idx).setCheckable(True) - self._first_value = first_value - layout.addWidget(self.input_field, 0) self.setFocusProxy(self.input_field) @@ -1147,16 +1144,13 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): self.input_field.set_value(value) def update_style(self): - if self._as_widget: - if not self.isEnabled(): - state = self.style_state(False, False, False, False) - else: - state = self.style_state( - False, - self._is_invalid, - False, - self._is_modified - ) + if self.as_widget: + state = self.style_state( + False, + self._is_invalid, + False, + self._is_modified + ) else: state = self.style_state( self.has_studio_override, @@ -1164,17 +1158,16 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): self.is_overriden, self.is_modified ) + if self._state == state: return - if self._as_widget: - property_name = "input-state" - else: - property_name = "state" - - self.label_widget.setProperty(property_name, state) - self.label_widget.style().polish(self.label_widget) self._state = state + self.input_field.setProperty("input-state", state) + self.input_field.style().polish(self.input_field) + if self.label_widget: + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) def item_value(self): return self.input_field.value() From 83c0010320c63045f5129d34cc6ce871e3786f71 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 10:22:26 +0200 Subject: [PATCH 22/27] removed ComboMenuDelegate as not used --- .../widgets/multiselection_combobox.py | 122 +----------------- 1 file changed, 2 insertions(+), 120 deletions(-) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 0106051cc4..9e5bc815b4 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -19,108 +19,6 @@ class ComboItemDelegate(QtWidgets.QStyledItemDelegate): super(ComboItemDelegate, self).paint(painter, option, index) -class ComboMenuDelegate(QtWidgets.QAbstractItemDelegate): - """ - Helper styled delegate (mostly based on existing private Qt's - delegate used by the QtWidgets.QComboBox). Used to style the popup like a - menu. (e.g osx aqua style). - """ - - def paint(self, painter, option, index): - menuopt = self._menu_style_option(option, index) - if option.widget is not None: - style = option.widget.style() - else: - style = QtWidgets.QApplication.style() - style.drawControl( - QtWidgets.QStyle.CE_MenuItem, menuopt, painter, option.widget - ) - - def sizeHint(self, option, index): - menuopt = self._menu_style_option(option, index) - if option.widget is not None: - style = option.widget.style() - else: - style = QtWidgets.QApplication.style() - return style.sizeFromContents( - QtWidgets.QStyle.CT_MenuItem, menuopt, menuopt.rect.size(), - option.widget - ) - - def _menu_style_option(self, option, index): - menuoption = QtWidgets.QStyleOptionMenuItem() - if option.widget: - palette_source = option.widget.palette("QMenu") - else: - palette_source = QtWidgets.QApplication.palette("QMenu") - - palette = option.palette.resolve(palette_source) - foreground = index.data(QtCore.Qt.ForegroundRole) - if isinstance(foreground, (QtGui.QBrush, QtGui.QColor, QtGui.QPixmap)): - foreground = QtGui.QBrush(foreground) - palette.setBrush(QtGui.QPalette.Text, foreground) - palette.setBrush(QtGui.QPalette.ButtonText, foreground) - palette.setBrush(QtGui.QPalette.WindowText, foreground) - - background = index.data(QtCore.Qt.BackgroundRole) - if isinstance(background, (QtGui.QBrush, QtGui.QColor, QtGui.QPixmap)): - background = QtGui.QBrush(background) - palette.setBrush(QtGui.QPalette.Background, background) - - menuoption.palette = palette - - decoration = index.data(QtCore.Qt.DecorationRole) - if isinstance(decoration, QtGui.QIcon): - menuoption.icon = decoration - - menuoption.menuItemType = QtWidgets.QStyleOptionMenuItem.Normal - - if index.flags() & QtCore.Qt.ItemIsUserCheckable: - menuoption.checkType = QtWidgets.QStyleOptionMenuItem.NonExclusive - else: - menuoption.checkType = QtWidgets.QStyleOptionMenuItem.NotCheckable - - check = index.data(QtCore.Qt.CheckStateRole) - menuoption.checked = check == QtCore.Qt.Checked - - if option.widget is not None: - menuoption.font = option.widget.font() - else: - menuoption.font = QtWidgets.QApplication.font("QMenu") - - menuoption.maxIconWidth = option.decorationSize.width() + 4 - menuoption.rect = option.rect - menuoption.menuRect = option.rect - - # menuoption.menuHasCheckableItems = True - menuoption.tabWidth = 0 - # TODO: self.displayText(QVariant, QLocale) - # TODO: Why is this not a QtWidgets.QStyledItemDelegate? - menuoption.text = str(index.data(QtCore.Qt.DisplayRole)) - - menuoption.fontMetrics = QtGui.QFontMetrics(menuoption.font) - state = option.state & ( - QtWidgets.QStyle.State_MouseOver - | QtWidgets.QStyle.State_Selected - | QtWidgets.QStyle.State_Active - ) - - if index.flags() & QtCore.Qt.ItemIsEnabled: - state = state | QtWidgets.QStyle.State_Enabled - menuoption.palette.setCurrentColorGroup(QtGui.QPalette.Active) - else: - state = state & ~QtWidgets.QStyle.State_Enabled - menuoption.palette.setCurrentColorGroup(QtGui.QPalette.Disabled) - - if menuoption.checked: - state = state | QtWidgets.QStyle.State_On - else: - state = state | QtWidgets.QStyle.State_Off - - menuoption.state = state - return menuoption - - class MultiSelectionComboBox(QtWidgets.QComboBox): value_changed = QtCore.Signal() ignored_keys = { @@ -152,7 +50,8 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): self._initial_mouse_pos = None self._separator = separator self.placeholder_text = placeholder - self._update_item_delegate() + self.delegate = ComboItemDelegate(self) + self.setItemDelegate(self.delegate) self.lines = {} self.item_height = ( @@ -171,12 +70,6 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): QtWidgets.QApplication.doubleClickInterval() ) - def changeEvent(self, event): - """Reimplemented.""" - if event.type() == QtCore.QEvent.StyleChange: - self._update_item_delegate() - super(MultiSelectionComboBox, self).changeEvent(event) - def showPopup(self): """Reimplemented.""" super(MultiSelectionComboBox, self).showPopup() @@ -419,14 +312,3 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): return return super(MultiSelectionComboBox, self).keyPressEvent(event) - - def _update_item_delegate(self): - opt = QtWidgets.QStyleOptionComboBox() - opt.initFrom(self) - if self.style().styleHint( - QtWidgets.QStyle.SH_ComboBox_Popup, opt, self - ): - delegate = ComboMenuDelegate(self) - else: - delegate = ComboItemDelegate(self) - self.setItemDelegate(delegate) From ddd1637bd345f0135b6781a27d0c690b9a65689e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 10:46:35 +0200 Subject: [PATCH 23/27] reorganized eventFilter --- .../widgets/multiselection_combobox.py | 116 +++++++++--------- 1 file changed, 60 insertions(+), 56 deletions(-) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 9e5bc815b4..2c4c910770 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -87,69 +87,73 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): super(MultiSelectionComboBox, self).hidePopup() self.view().clearFocus() - def eventFilter(self, obj, event): - """Reimplemented.""" - if ( - self._popup_is_shown - and event.type() == QtCore.QEvent.MouseMove - and self.view().isVisible() - and self._initial_mouse_pos is not None - ): - diff = obj.mapToGlobal(event.pos()) - self._initial_mouse_pos - if ( - diff.manhattanLength() > 9 - and self._block_mouse_release_timer.isActive() - ): - self._block_mouse_release_timer.stop() + def _event_popup_shown(self, obj, event): + if not self._popup_is_shown: + return current_index = self.view().currentIndex() - if ( - self._popup_is_shown - and event.type() == QtCore.QEvent.MouseButtonRelease - and self.view().isVisible() - and self.view().rect().contains(event.pos()) - and current_index.isValid() - and current_index.flags() & QtCore.Qt.ItemIsSelectable - and current_index.flags() & QtCore.Qt.ItemIsEnabled - and current_index.flags() & QtCore.Qt.ItemIsUserCheckable - and self.view().visualRect(current_index).contains(event.pos()) - and not self._block_mouse_release_timer.isActive() - ): - model = self.model() - index = self.view().currentIndex() - state = model.data(index, QtCore.Qt.CheckStateRole) - if state == QtCore.Qt.Unchecked: - check_state = QtCore.Qt.Checked - else: - check_state = QtCore.Qt.Unchecked + model = self.model() - model.setData(index, check_state, QtCore.Qt.CheckStateRole) - self.view().update(index) + if event.type() == QtCore.QEvent.MouseMove: + if ( + self.view().isVisible() + and self._initial_mouse_pos is not None + and self._block_mouse_release_timer.isActive() + ): + diff = obj.mapToGlobal(event.pos()) - self._initial_mouse_pos + if diff.manhattanLength() > 9: + self._block_mouse_release_timer.stop() + return + + index_flags = current_index.flags() + state = current_index.data(QtCore.Qt.CheckStateRole) + new_state = None + + if event.type() == QtCore.QEvent.MouseButtonRelease: + if ( + self._block_mouse_release_timer.isActive() + or not current_index.isValid() + or not self.view().isVisible() + or not self.view().rect().contains(event.pos()) + or not index_flags & QtCore.Qt.ItemIsSelectable + or not index_flags & QtCore.Qt.ItemIsEnabled + or not index_flags & QtCore.Qt.ItemIsUserCheckable + ): + return + + if state == QtCore.Qt.Unchecked: + new_state = QtCore.Qt.Checked + else: + new_state = QtCore.Qt.Unchecked + + elif event.type() == QtCore.QEvent.KeyPress: + # TODO: handle QtCore.Qt.Key_Enter, Key_Return? + if event.key() == QtCore.Qt.Key_Space: + # toogle the current items check state + if ( + index_flags & QtCore.Qt.ItemIsUserCheckable + and index_flags & QtCore.Qt.ItemIsTristate + ): + new_state = QtCore.Qt.CheckState((int(state) + 1) % 3) + + elif index_flags & QtCore.Qt.ItemIsUserCheckable: + if state != QtCore.Qt.Checked: + new_state = QtCore.Qt.Checked + else: + new_state = QtCore.Qt.Unchecked + + if new_state is not None: + model.setData(current_index, new_state, QtCore.Qt.CheckStateRole) + self.view().update(current_index) self.update_size_hint() self.value_changed.emit() return True - if self._popup_is_shown and event.type() == QtCore.QEvent.KeyPress: - if event.key() == QtCore.Qt.Key_Space: - # toogle the current items check state - model = self.model() - index = self.view().currentIndex() - flags = model.flags(index) - state = model.data(index, QtCore.Qt.CheckStateRole) - if flags & QtCore.Qt.ItemIsUserCheckable and \ - flags & QtCore.Qt.ItemIsTristate: - state = QtCore.Qt.CheckState((int(state) + 1) % 3) - elif flags & QtCore.Qt.ItemIsUserCheckable: - state = ( - QtCore.Qt.Checked - if state != QtCore.Qt.Checked - else QtCore.Qt.Unchecked - ) - model.setData(index, state, QtCore.Qt.CheckStateRole) - self.view().update(index) - self.update() - return True - # TODO: handle QtCore.Qt.Key_Enter, Key_Return? + def eventFilter(self, obj, event): + """Reimplemented.""" + result = self._event_popup_shown(obj, event) + if result is not None: + return result return super(MultiSelectionComboBox, self).eventFilter(obj, event) From 028b754f59bd5c2175153f74a7b6a1427b920e3b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 10:47:49 +0200 Subject: [PATCH 24/27] fixed set_value method for discard changes etc. --- pype/tools/settings/settings/widgets/multiselection_combobox.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 2c4c910770..159b2d16dc 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -281,6 +281,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): else: check_state = QtCore.Qt.Unchecked self.setItemData(idx, check_state, QtCore.Qt.CheckStateRole) + self.update_size_hint() def value(self): items = list() From b2cd99cbcca73fb926983b3f6f333c2cd9bb517e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 10:50:46 +0200 Subject: [PATCH 25/27] skip setting item as checkable for multiselection input --- pype/tools/settings/settings/widgets/item_types.py | 5 ----- .../settings/settings/widgets/multiselection_combobox.py | 7 ++----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 647ec96c58..e495cfc8aa 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1121,11 +1121,6 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): self.input_field.addItem(label, value) self._first_value = first_value - if self.multiselection: - model = self.input_field.model() - for idx in range(self.input_field.count()): - model.item(idx).setCheckable(True) - layout.addWidget(self.input_field, 0) self.setFocusProxy(self.input_field) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 159b2d16dc..17750f909e 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -117,7 +117,6 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): or not self.view().rect().contains(event.pos()) or not index_flags & QtCore.Qt.ItemIsSelectable or not index_flags & QtCore.Qt.ItemIsEnabled - or not index_flags & QtCore.Qt.ItemIsUserCheckable ): return @@ -309,11 +308,9 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): event.key() == QtCore.Qt.Key_Down and event.modifiers() & QtCore.Qt.AltModifier ): - self.showPopup() - return + return self.showPopup() if event.key() in self.ignored_keys: - event.ignore() - return + return event.ignore() return super(MultiSelectionComboBox, self).keyPressEvent(event) From ba785f748bfa580a5cd44343b589e8c3b62bdbde Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 10:53:18 +0200 Subject: [PATCH 26/27] made None as valid value --- pype/tools/settings/settings/widgets/item_types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index e495cfc8aa..9ddfa5acab 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1113,10 +1113,10 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): else: self.input_field = ComboBox(self) - first_value = None + first_value = NOT_SET for enum_item in self.enum_items: for value, label in enum_item.items(): - if first_value is None: + if first_value is NOT_SET: first_value = value self.input_field.addItem(label, value) self._first_value = first_value From c2d9a66b8cff8321a1de68a36e560f2db636d4f0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 12:59:06 +0200 Subject: [PATCH 27/27] fix default checkboxes in multiselection --- pype/tools/settings/settings/widgets/item_types.py | 5 +++++ .../settings/settings/widgets/multiselection_combobox.py | 1 + 2 files changed, 6 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 9ddfa5acab..dc6cde2407 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1121,6 +1121,11 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): self.input_field.addItem(label, value) self._first_value = first_value + if self.multiselection: + model = self.input_field.model() + for idx in range(self.input_field.count()): + model.item(idx).setCheckable(True) + layout.addWidget(self.input_field, 0) self.setFocusProxy(self.input_field) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 17750f909e..9a99561ea8 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -117,6 +117,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): or not self.view().rect().contains(event.pos()) or not index_flags & QtCore.Qt.ItemIsSelectable or not index_flags & QtCore.Qt.ItemIsEnabled + or not index_flags & QtCore.Qt.ItemIsUserCheckable ): return