From ac7c7e7dd204cb56f1655243b21cf109b524bd2e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 31 Aug 2021 15:34:19 +0200 Subject: [PATCH] better item drawing --- .../publish_log_viewer/constants.py | 6 +- .../publish_log_viewer/delegates.py | 133 +++++++++++++++--- .../new_publisher/publish_log_viewer/model.py | 5 +- .../publish_log_viewer/widgets.py | 7 + 4 files changed, 129 insertions(+), 22 deletions(-) diff --git a/openpype/tools/new_publisher/publish_log_viewer/constants.py b/openpype/tools/new_publisher/publish_log_viewer/constants.py index 42a4d7be74..f1e13534d0 100644 --- a/openpype/tools/new_publisher/publish_log_viewer/constants.py +++ b/openpype/tools/new_publisher/publish_log_viewer/constants.py @@ -4,8 +4,8 @@ from Qt import QtCore ITEM_ID_ROLE = QtCore.Qt.UserRole + 1 ITEM_IS_GROUP_ROLE = QtCore.Qt.UserRole + 2 ITEM_LABEL_ROLE = QtCore.Qt.UserRole + 3 -PLUGIN_SKIPPED_ROLE = QtCore.Qt.UserRole + 4 -PLUGIN_ERRORED_ROLE = QtCore.Qt.UserRole + 5 +ITEM_ERRORED_ROLE = QtCore.Qt.UserRole + 4 +PLUGIN_SKIPPED_ROLE = QtCore.Qt.UserRole + 5 INSTANCE_REMOVED_ROLE = QtCore.Qt.UserRole + 6 @@ -13,7 +13,7 @@ __all__ = ( "ITEM_ID_ROLE", "ITEM_IS_GROUP_ROLE", "ITEM_LABEL_ROLE", + "ITEM_ERRORED_ROLE", "PLUGIN_SKIPPED_ROLE", - "PLUGIN_ERRORED_ROLE", "INSTANCE_REMOVED_ROLE" ) diff --git a/openpype/tools/new_publisher/publish_log_viewer/delegates.py b/openpype/tools/new_publisher/publish_log_viewer/delegates.py index e959c7c50a..f6077a496d 100644 --- a/openpype/tools/new_publisher/publish_log_viewer/delegates.py +++ b/openpype/tools/new_publisher/publish_log_viewer/delegates.py @@ -1,11 +1,12 @@ import platform +import collections from Qt import QtWidgets, QtCore, QtGui -from constants import ( +from .constants import ( ITEM_ID_ROLE, ITEM_IS_GROUP_ROLE, + ITEM_ERRORED_ROLE, ITEM_LABEL_ROLE, PLUGIN_SKIPPED_ROLE, - PLUGIN_ERRORED_ROLE, INSTANCE_REMOVED_ROLE ) @@ -25,22 +26,19 @@ colors = { } -class ItemDelegate(QtWidgets.QStyledItemDelegate): - pass - - class GroupItemDelegate(QtWidgets.QStyledItemDelegate): """Generic delegate for instance header""" + + _item_icons_by_name_and_size = collections.defaultdict(dict) + _minus_pixmaps = {} _plus_pixmaps = {} _path_stroker = None - _pix_offset_ratio = 1 / 3 - _pix_stroke_size_ratio = 1 / 7 - - def __init__(self, parent): - super(GroupItemDelegate, self).__init__(parent) - self.item_delegate = ItemDelegate(parent) + _item_pix_offset_ratio = 1 / 5 + _item_border_size = 1 / 7 + _group_pix_offset_ratio = 1 / 3 + _group_pix_stroke_size_ratio = 1 / 7 @classmethod def _get_path_stroker(cls): @@ -61,7 +59,7 @@ class GroupItemDelegate(QtWidgets.QStyledItemDelegate): pix = QtGui.QPixmap(size, size) pix.fill(QtCore.Qt.transparent) - offset = int(size * cls._pix_offset_ratio) + offset = int(size * cls._group_pix_offset_ratio) pnt_1 = QtCore.QPoint(offset, int(size / 2)) pnt_2 = QtCore.QPoint(size - offset, int(size / 2)) pnt_3 = QtCore.QPoint(int(size / 2), offset) @@ -72,7 +70,7 @@ class GroupItemDelegate(QtWidgets.QStyledItemDelegate): path_2.lineTo(pnt_4) path_stroker = cls._get_path_stroker() - path_stroker.setWidth(size * cls._pix_stroke_size_ratio) + path_stroker.setWidth(size * cls._group_pix_stroke_size_ratio) stroked_path_1 = path_stroker.createStroke(path_1) stroked_path_2 = path_stroker.createStroke(path_2) @@ -97,13 +95,13 @@ class GroupItemDelegate(QtWidgets.QStyledItemDelegate): if pix is not None: return pix - offset = int(size * cls._pix_offset_ratio) + offset = int(size * cls._group_pix_offset_ratio) pnt_1 = QtCore.QPoint(offset, int(size / 2)) pnt_2 = QtCore.QPoint(size - offset, int(size / 2)) path = QtGui.QPainterPath(pnt_1) path.lineTo(pnt_2) path_stroker = cls._get_path_stroker() - path_stroker.setWidth(size * cls._pix_stroke_size_ratio) + path_stroker.setWidth(size * cls._group_pix_stroke_size_ratio) stroked_path = path_stroker.createStroke(path) pix = QtGui.QPixmap(size, size) @@ -120,11 +118,112 @@ class GroupItemDelegate(QtWidgets.QStyledItemDelegate): return pix + @classmethod + def _get_icon_color(cls, name): + if name == "error": + return QtGui.QColor(colors["error"]) + return QtGui.QColor(QtCore.Qt.white) + + @classmethod + def _get_icon(cls, name, size): + icons_by_size = cls._item_icons_by_name_and_size[name] + if icons_by_size and size in icons_by_size: + return icons_by_size[size] + + pix = QtGui.QPixmap(size, size) + pix.fill(QtCore.Qt.transparent) + + painter = QtGui.QPainter(pix) + painter.setRenderHint(QtGui.QPainter.Antialiasing) + + if name == "error": + color = QtGui.QColor(colors["error"]) + painter.setPen(QtCore.Qt.NoPen) + painter.setBrush(color) + elif name == "skipped": + color = QtGui.QColor(QtCore.Qt.white) + pen = QtGui.QPen(color) + pen.setWidth(int(size * cls._item_border_size)) + painter.setPen(pen) + painter.setBrush(QtCore.Qt.transparent) + else: + color = QtGui.QColor(QtCore.Qt.white) + painter.setPen(QtCore.Qt.NoPen) + painter.setBrush(color) + + offset = int(size * cls._item_pix_offset_ratio) + painter.drawEllipse( + offset, offset, + size - (2 * offset), size - (2 * offset) + ) + painter.end() + + cls._item_icons_by_name_and_size[name][size] = pix + + return pix + def paint(self, painter, option, index): if index.data(ITEM_IS_GROUP_ROLE): self.group_item_paint(painter, option, index) else: - self.item_delegate.paint(painter, option, index) + self.item_paint(painter, option, index) + + def item_paint(self, painter, option, index): + self.initStyleOption(option, index) + + widget = option.widget + if widget: + style = widget.style() + else: + style = QtWidgets.QApplicaion.style() + + style.proxy().drawPrimitive( + style.PE_PanelItemViewItem, option, painter, widget + ) + _rect = style.proxy().subElementRect( + style.SE_ItemViewItemText, option, widget + ) + bg_rect = QtCore.QRectF(option.rect) + bg_rect.setY(_rect.y()) + bg_rect.setHeight(_rect.height()) + + expander_rect = QtCore.QRectF(bg_rect) + expander_rect.setWidth(expander_rect.height() + 5) + + label_rect = QtCore.QRectF( + expander_rect.x() + expander_rect.width(), + expander_rect.y(), + bg_rect.width() - expander_rect.width(), + expander_rect.height() + ) + + icon_size = expander_rect.height() + if index.data(ITEM_ERRORED_ROLE): + expander_icon = self._get_icon("error", icon_size) + elif index.data(PLUGIN_SKIPPED_ROLE): + expander_icon = self._get_icon("skipped", icon_size) + else: + expander_icon = self._get_icon("", icon_size) + + label = index.data(QtCore.Qt.DisplayRole) + label = option.fontMetrics.elidedText( + label, QtCore.Qt.ElideRight, label_rect.width() + ) + + painter.save() + # Draw icon + pix_point = QtCore.QPoint( + expander_rect.center().x() - int(expander_icon.width() / 2), + expander_rect.top() + ) + painter.drawPixmap(pix_point, expander_icon) + + # Draw label + painter.setFont(option.font) + painter.drawText(label_rect, QtCore.Qt.AlignVCenter, label) + + # Ok, we're done, tidy up. + painter.restore() def group_item_paint(self, painter, option, index): """Paint text diff --git a/openpype/tools/new_publisher/publish_log_viewer/model.py b/openpype/tools/new_publisher/publish_log_viewer/model.py index ccc6cb4946..3e115ff61e 100644 --- a/openpype/tools/new_publisher/publish_log_viewer/model.py +++ b/openpype/tools/new_publisher/publish_log_viewer/model.py @@ -7,8 +7,8 @@ from .constants import ( ITEM_ID_ROLE, ITEM_IS_GROUP_ROLE, ITEM_LABEL_ROLE, + ITEM_ERRORED_ROLE, PLUGIN_SKIPPED_ROLE, - PLUGIN_ERRORED_ROLE, INSTANCE_REMOVED_ROLE ) @@ -42,6 +42,7 @@ class InstancesModel(QtGui.QStandardItemModel): for instance_item in instance_items: item = QtGui.QStandardItem(instance_item.label) item.setData(instance_item.label, ITEM_LABEL_ROLE) + item.setData(instance_item.errored, ITEM_ERRORED_ROLE) item.setData(instance_item.id, ITEM_ID_ROLE) item.setData(instance_item.removed, INSTANCE_REMOVED_ROLE) item.setData(False, ITEM_IS_GROUP_ROLE) @@ -159,7 +160,7 @@ class PluginsModel(QtGui.QStandardItemModel): item.setData(plugin_item.label, ITEM_LABEL_ROLE) item.setData(plugin_item.id, ITEM_ID_ROLE) item.setData(plugin_item.skipped, PLUGIN_SKIPPED_ROLE) - item.setData(plugin_item.errored, PLUGIN_ERRORED_ROLE) + item.setData(plugin_item.errored, ITEM_ERRORED_ROLE) items.append(item) self._items_by_id[plugin_item.id] = item self._plugin_items_by_id[plugin_item.id] = item diff --git a/openpype/tools/new_publisher/publish_log_viewer/widgets.py b/openpype/tools/new_publisher/publish_log_viewer/widgets.py index d45f88dfb6..ce92d63f26 100644 --- a/openpype/tools/new_publisher/publish_log_viewer/widgets.py +++ b/openpype/tools/new_publisher/publish_log_viewer/widgets.py @@ -55,6 +55,13 @@ class InstanceItem: if instance_data_item["id"] == self._id: logs.extend(copy.deepcopy(instance_data_item["logs"])) + errored = False + for log in logs: + if log["type"] == "error": + errored = True + break + + self.errored = errored self.logs = logs @property