Merge pull request #1108 from ynput/enhancement/add-placeholder-to-enum

Enum attribute definition: Allow placeholder text
This commit is contained in:
Jakub Trllo 2025-02-12 13:09:08 +01:00 committed by GitHub
commit 47ad31b4b9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 112 additions and 41 deletions

View file

@ -550,16 +550,24 @@ class EnumDef(AbstractAttrDef):
passed items or list of values for multiselection.
multiselection (Optional[bool]): If True, multiselection is allowed.
Output is list of selected items.
placeholder (Optional[str]): Placeholder for UI purposes, only for
multiselection enumeration.
"""
type = "enum"
type_attributes = [
"multiselection",
"placeholder",
]
def __init__(
self,
key: str,
items: "EnumItemsInputType",
default: "Union[str, List[Any]]" = None,
multiselection: Optional[bool] = False,
placeholder: Optional[str] = None,
**kwargs
):
if multiselection is None:
@ -588,6 +596,7 @@ class EnumDef(AbstractAttrDef):
self.items: List["EnumItemDict"] = items
self._item_values: Set[Any] = item_values_set
self.multiselection: bool = multiselection
self.placeholder: Optional[str] = placeholder
def convert_value(self, value):
if not self.multiselection:
@ -613,7 +622,6 @@ class EnumDef(AbstractAttrDef):
def serialize(self):
data = super().serialize()
data["items"] = copy.deepcopy(self.items)
data["multiselection"] = self.multiselection
return data
@staticmethod

View file

@ -22,6 +22,8 @@ from ayon_core.tools.utils import (
FocusSpinBox,
FocusDoubleSpinBox,
MultiSelectionComboBox,
PlaceholderLineEdit,
PlaceholderPlainTextEdit,
set_style_property,
)
from ayon_core.tools.utils import NiceCheckbox
@ -502,9 +504,9 @@ class TextAttrWidget(_BaseAttrDefWidget):
self.multiline = self.attr_def.multiline
if self.multiline:
input_widget = QtWidgets.QPlainTextEdit(self)
input_widget = PlaceholderPlainTextEdit(self)
else:
input_widget = QtWidgets.QLineEdit(self)
input_widget = PlaceholderLineEdit(self)
# Override context menu event to add revert to default action
input_widget.contextMenuEvent = self._input_widget_context_event
@ -641,7 +643,9 @@ class EnumAttrWidget(_BaseAttrDefWidget):
def _ui_init(self):
if self.multiselection:
input_widget = MultiSelectionComboBox(self)
input_widget = MultiSelectionComboBox(
self, placeholder=self.attr_def.placeholder
)
else:
input_widget = CustomTextComboBox(self)

View file

@ -5,6 +5,7 @@ from .widgets import (
ComboBox,
CustomTextComboBox,
PlaceholderLineEdit,
PlaceholderPlainTextEdit,
ElideLabel,
HintedLineEdit,
ExpandingTextEdit,
@ -89,6 +90,7 @@ __all__ = (
"ComboBox",
"CustomTextComboBox",
"PlaceholderLineEdit",
"PlaceholderPlainTextEdit",
"ElideLabel",
"HintedLineEdit",
"ExpandingTextEdit",

View file

@ -1,5 +1,7 @@
from qtpy import QtCore, QtGui, QtWidgets
from ayon_core.style import get_objected_colors
from .lib import (
checkstate_int_to_enum,
checkstate_enum_to_int,
@ -45,15 +47,16 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
top_bottom_padding = 2
left_right_padding = 3
left_offset = 4
top_bottom_margins = 2
top_bottom_margins = 1
item_spacing = 5
item_bg_color = QtGui.QColor("#31424e")
_placeholder_color = None
def __init__(
self, parent=None, placeholder="", separator=", ", **kwargs
):
super(MultiSelectionComboBox, self).__init__(parent=parent, **kwargs)
super().__init__(parent=parent, **kwargs)
self.setObjectName("MultiSelectionComboBox")
self.setFocusPolicy(QtCore.Qt.StrongFocus)
@ -61,7 +64,7 @@ class MultiSelectionComboBox(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 or ""
delegate = ComboItemDelegate(self)
self.setItemDelegate(delegate)
@ -74,7 +77,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
return self._placeholder_text
def set_placeholder_text(self, text):
self._placeholder_text = text
self._placeholder_text = text or ""
self._update_size_hint()
def set_custom_text(self, text):
@ -206,19 +209,36 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
combotext = self._placeholder_text
else:
draw_text = False
if draw_text:
option.currentText = combotext
option.palette.setCurrentColorGroup(QtGui.QPalette.Disabled)
painter.drawControl(QtWidgets.QStyle.CE_ComboBoxLabel, option)
return
font_metricts = self.fontMetrics()
if draw_text:
color = self._get_placeholder_color()
pen = painter.pen()
pen.setColor(color)
painter.setPen(pen)
left_x = option.rect.left() + self.left_offset
font = self.font()
# This is hardcoded point size from styles
font.setPointSize(10)
painter.setFont(font)
label_rect = QtCore.QRect(option.rect)
label_rect.moveLeft(left_x)
painter.drawText(
label_rect,
QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter,
combotext
)
return
if self._item_height is None:
self.updateGeometry()
self.update()
return
font_metrics = self.fontMetrics()
for line, items in self._lines.items():
top_y = (
option.rect.top()
@ -227,7 +247,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
)
left_x = option.rect.left() + self.left_offset
for item in items:
label_rect = font_metricts.boundingRect(item)
label_rect = font_metrics.boundingRect(item)
label_height = label_rect.height()
label_rect.moveTop(top_y)
@ -237,22 +257,25 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
label_rect.width() + self.left_right_padding
)
bg_rect = QtCore.QRectF(label_rect)
bg_rect.setWidth(
label_rect.width() + self.left_right_padding
)
left_x = bg_rect.right() + self.item_spacing
if not draw_text:
bg_rect = QtCore.QRectF(label_rect)
bg_rect.setWidth(
label_rect.width() + self.left_right_padding
)
left_x = bg_rect.right() + self.item_spacing
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)
painter.fillPath(path, self.item_bg_color)
label_rect.moveLeft(label_rect.x() + self.left_right_padding)
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)
painter.fillPath(path, self.item_bg_color)
painter.drawText(
label_rect,
QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter,
@ -287,11 +310,11 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
line = 0
self._lines = {line: []}
font_metricts = self.fontMetrics()
font_metrics = self.fontMetrics()
default_left_x = 0 + self.left_offset
left_x = int(default_left_x)
for item in items:
rect = font_metricts.boundingRect(item)
rect = font_metrics.boundingRect(item)
width = rect.width() + (2 * self.left_right_padding)
right_x = left_x + width
if right_x > total_width:
@ -382,3 +405,12 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
return event.ignore()
return super(MultiSelectionComboBox, self).keyPressEvent(event)
@classmethod
def _get_placeholder_color(cls):
if cls._placeholder_color is None:
color_obj = get_objected_colors("font")
color = color_obj.get_qcolor()
color.setAlpha(67)
cls._placeholder_color = color
return cls._placeholder_color

View file

@ -54,7 +54,7 @@ class ComboBox(QtWidgets.QComboBox):
"""
def __init__(self, *args, **kwargs):
super(ComboBox, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
delegate = QtWidgets.QStyledItemDelegate()
self.setItemDelegate(delegate)
self.setFocusPolicy(QtCore.Qt.StrongFocus)
@ -63,7 +63,7 @@ class ComboBox(QtWidgets.QComboBox):
def wheelEvent(self, event):
if self.hasFocus():
return super(ComboBox, self).wheelEvent(event)
return super().wheelEvent(event)
class CustomTextComboBox(ComboBox):
@ -71,7 +71,7 @@ class CustomTextComboBox(ComboBox):
def __init__(self, *args, **kwargs):
self._custom_text = None
super(CustomTextComboBox, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
def set_custom_text(self, text=None):
if self._custom_text != text:
@ -88,23 +88,48 @@ class CustomTextComboBox(ComboBox):
painter.drawControl(QtWidgets.QStyle.CE_ComboBoxLabel, option)
class PlaceholderLineEdit(QtWidgets.QLineEdit):
"""Set placeholder color of QLineEdit in Qt 5.12 and higher."""
def __init__(self, *args, **kwargs):
super(PlaceholderLineEdit, self).__init__(*args, **kwargs)
# Change placeholder palette color
if hasattr(QtGui.QPalette, "PlaceholderText"):
filter_palette = self.palette()
class _Cache:
_placeholder_color = None
@classmethod
def get_placeholder_color(cls):
if cls._placeholder_color is None:
color_obj = get_objected_colors("font")
color = color_obj.get_qcolor()
color.setAlpha(67)
cls._placeholder_color = color
return cls._placeholder_color
class PlaceholderLineEdit(QtWidgets.QLineEdit):
"""Set placeholder color of QLineEdit in Qt 5.12 and higher."""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Change placeholder palette color
if hasattr(QtGui.QPalette, "PlaceholderText"):
filter_palette = self.palette()
filter_palette.setColor(
QtGui.QPalette.PlaceholderText,
color
_Cache.get_placeholder_color()
)
self.setPalette(filter_palette)
class PlaceholderPlainTextEdit(QtWidgets.QPlainTextEdit):
"""Set placeholder color of QPlainTextEdit in Qt 5.12 and higher."""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Change placeholder palette color
if hasattr(QtGui.QPalette, "PlaceholderText"):
viewport = self.viewport()
filter_palette = viewport.palette()
filter_palette.setColor(
QtGui.QPalette.PlaceholderText,
_Cache.get_placeholder_color()
)
viewport.setPalette(filter_palette)
class ElideLabel(QtWidgets.QLabel):
"""Label which elide text.