mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 08:24:53 +01:00
Publisher: Show instances in report page (#4915)
* renamed 'validations_widget.py' to 'report_page.py' * Implemented base logic and widgets for logs * make one report page * added missing imports * added missing constants * move and rename 'VerticallScrollArea' to 'VerticalScrollArea' * Validation erro item have id * use 'ReportPageWidget' in window * change 'bg-button-hover' key to 'bg-buttons-hover' in style colors * move publish actions widgets * Refactored how validation error title is showed * remove item id from validation error item but add id to group items * remove margins from actions widget * shrink publish frame on finished publishing * fix dash line draw * add missing styles * fix dash line in thumbnail widget * added crash widget and changed layout a little * added infor overlay message * export and copy report happens in main window * fix docstrings * added per plugin filtering for validation errors * added implementation of 'FlowLayout' * actions buttons are in flow layout * fix actions order * implemented expanding text edit widget * expand button has some signals and properties * description and details are separated widgets * fix typo * added constans to '__all__' * parse icon def is a function * change layout of widgets * fix log filtering * added state icon to instances * fix pyside6 issues * implemented 'ClassicExpandBtnLabel' with arrow images * modified details separator * added some spacing to layouts * fix syle of description inputs and progress color * removed unused import * add 'is_validation_error' to errored result * validation error has different icon in logs view * added plugin name to ValueError if happens * spacer before detail inputs moved out of detals widget * fix actions visible in craash report * ignore pyblish base classes * filter base plugins in discovery * use 'is' comparison instead of '__eq__' * fix action error handling * Fix handling of 'None' values in comparison * formatting fix * Report instance card have same margins as in create mode * publish instances are grouped by family * log messages are rstripped
This commit is contained in:
parent
d55211c337
commit
a73d19b612
21 changed files with 2373 additions and 834 deletions
|
|
@ -1,13 +1,16 @@
|
|||
from .layouts import FlowLayout
|
||||
from .widgets import (
|
||||
FocusSpinBox,
|
||||
FocusDoubleSpinBox,
|
||||
ComboBox,
|
||||
CustomTextComboBox,
|
||||
PlaceholderLineEdit,
|
||||
ExpandingTextEdit,
|
||||
BaseClickableFrame,
|
||||
ClickableFrame,
|
||||
ClickableLabel,
|
||||
ExpandBtn,
|
||||
ClassicExpandBtn,
|
||||
PixmapLabel,
|
||||
IconButton,
|
||||
PixmapButton,
|
||||
|
|
@ -37,15 +40,19 @@ from .overlay_messages import (
|
|||
|
||||
|
||||
__all__ = (
|
||||
"FlowLayout",
|
||||
|
||||
"FocusSpinBox",
|
||||
"FocusDoubleSpinBox",
|
||||
"ComboBox",
|
||||
"CustomTextComboBox",
|
||||
"PlaceholderLineEdit",
|
||||
"ExpandingTextEdit",
|
||||
"BaseClickableFrame",
|
||||
"ClickableFrame",
|
||||
"ClickableLabel",
|
||||
"ExpandBtn",
|
||||
"ClassicExpandBtn",
|
||||
"PixmapLabel",
|
||||
"IconButton",
|
||||
"PixmapButton",
|
||||
|
|
|
|||
150
openpype/tools/utils/layouts.py
Normal file
150
openpype/tools/utils/layouts.py
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
from qtpy import QtWidgets, QtCore
|
||||
|
||||
|
||||
class FlowLayout(QtWidgets.QLayout):
|
||||
"""Layout that organize widgets by minimum size into a flow layout.
|
||||
|
||||
Layout is putting widget from left to right and top to bottom. When widget
|
||||
can't fit a row it is added to next line. Minimum size matches widget with
|
||||
biggest 'sizeHint' width and height using calculated geometry.
|
||||
|
||||
Content margins are part of calculations. It is possible to define
|
||||
horizontal and vertical spacing.
|
||||
|
||||
Layout does not support stretch and spacing items.
|
||||
|
||||
Todos:
|
||||
Unified width concept -> use width of largest item so all of them are
|
||||
same. This could allow to have minimum columns option too.
|
||||
"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(FlowLayout, self).__init__(parent)
|
||||
|
||||
# spaces between each item
|
||||
self._horizontal_spacing = 5
|
||||
self._vertical_spacing = 5
|
||||
|
||||
self._items = []
|
||||
|
||||
def __del__(self):
|
||||
while self.count():
|
||||
self.takeAt(0, False)
|
||||
|
||||
def isEmpty(self):
|
||||
for item in self._items:
|
||||
if not item.isEmpty():
|
||||
return False
|
||||
return True
|
||||
|
||||
def setSpacing(self, spacing):
|
||||
self._horizontal_spacing = spacing
|
||||
self._vertical_spacing = spacing
|
||||
self.invalidate()
|
||||
|
||||
def setHorizontalSpacing(self, spacing):
|
||||
self._horizontal_spacing = spacing
|
||||
self.invalidate()
|
||||
|
||||
def setVerticalSpacing(self, spacing):
|
||||
self._vertical_spacing = spacing
|
||||
self.invalidate()
|
||||
|
||||
def addItem(self, item):
|
||||
self._items.append(item)
|
||||
self.invalidate()
|
||||
|
||||
def count(self):
|
||||
return len(self._items)
|
||||
|
||||
def itemAt(self, index):
|
||||
if 0 <= index < len(self._items):
|
||||
return self._items[index]
|
||||
return None
|
||||
|
||||
def takeAt(self, index, invalidate=True):
|
||||
if 0 <= index < len(self._items):
|
||||
item = self._items.pop(index)
|
||||
if invalidate:
|
||||
self.invalidate()
|
||||
return item
|
||||
return None
|
||||
|
||||
def expandingDirections(self):
|
||||
return QtCore.Qt.Orientations(QtCore.Qt.Vertical)
|
||||
|
||||
def hasHeightForWidth(self):
|
||||
return True
|
||||
|
||||
def heightForWidth(self, width):
|
||||
return self._setup_geometry(QtCore.QRect(0, 0, width, 0), True)
|
||||
|
||||
def setGeometry(self, rect):
|
||||
super(FlowLayout, self).setGeometry(rect)
|
||||
self._setup_geometry(rect)
|
||||
|
||||
def sizeHint(self):
|
||||
return self.minimumSize()
|
||||
|
||||
def minimumSize(self):
|
||||
size = QtCore.QSize(0, 0)
|
||||
for item in self._items:
|
||||
widget = item.widget()
|
||||
if widget is not None:
|
||||
parent = widget.parent()
|
||||
if not widget.isVisibleTo(parent):
|
||||
continue
|
||||
size = size.expandedTo(item.minimumSize())
|
||||
|
||||
if size.width() < 1 or size.height() < 1:
|
||||
return size
|
||||
l_margin, t_margin, r_margin, b_margin = self.getContentsMargins()
|
||||
size += QtCore.QSize(l_margin + r_margin, t_margin + b_margin)
|
||||
return size
|
||||
|
||||
def _setup_geometry(self, rect, only_calculate=False):
|
||||
h_spacing = self._horizontal_spacing
|
||||
v_spacing = self._vertical_spacing
|
||||
l_margin, t_margin, r_margin, b_margin = self.getContentsMargins()
|
||||
|
||||
left_x = rect.x() + l_margin
|
||||
top_y = rect.y() + t_margin
|
||||
pos_x = left_x
|
||||
pos_y = top_y
|
||||
row_height = 0
|
||||
for item in self._items:
|
||||
item_hint = item.sizeHint()
|
||||
item_width = item_hint.width()
|
||||
item_height = item_hint.height()
|
||||
if item_width < 1 or item_height < 1:
|
||||
continue
|
||||
|
||||
end_x = pos_x + item_width
|
||||
|
||||
wrap = (
|
||||
row_height > 0
|
||||
and (
|
||||
end_x > rect.right()
|
||||
or (end_x + r_margin) > rect.right()
|
||||
)
|
||||
)
|
||||
if not wrap:
|
||||
next_pos_x = end_x + h_spacing
|
||||
else:
|
||||
pos_x = left_x
|
||||
pos_y += row_height + v_spacing
|
||||
next_pos_x = pos_x + item_width + h_spacing
|
||||
row_height = 0
|
||||
|
||||
if not only_calculate:
|
||||
item.setGeometry(
|
||||
QtCore.QRect(pos_x, pos_y, item_width, item_height)
|
||||
)
|
||||
|
||||
pos_x = next_pos_x
|
||||
row_height = max(row_height, item_height)
|
||||
|
||||
height = (pos_y - top_y) + row_height
|
||||
if height > 0:
|
||||
height += b_margin
|
||||
return height
|
||||
|
|
@ -101,6 +101,46 @@ class PlaceholderLineEdit(QtWidgets.QLineEdit):
|
|||
self.setPalette(filter_palette)
|
||||
|
||||
|
||||
class ExpandingTextEdit(QtWidgets.QTextEdit):
|
||||
"""QTextEdit which does not have sroll area but expands height."""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(ExpandingTextEdit, self).__init__(parent)
|
||||
|
||||
size_policy = self.sizePolicy()
|
||||
size_policy.setHeightForWidth(True)
|
||||
size_policy.setVerticalPolicy(QtWidgets.QSizePolicy.Preferred)
|
||||
self.setSizePolicy(size_policy)
|
||||
|
||||
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
||||
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
||||
|
||||
doc = self.document()
|
||||
doc.contentsChanged.connect(self._on_doc_change)
|
||||
|
||||
def _on_doc_change(self):
|
||||
self.updateGeometry()
|
||||
|
||||
def hasHeightForWidth(self):
|
||||
return True
|
||||
|
||||
def heightForWidth(self, width):
|
||||
margins = self.contentsMargins()
|
||||
|
||||
document_width = 0
|
||||
if width >= margins.left() + margins.right():
|
||||
document_width = width - margins.left() - margins.right()
|
||||
|
||||
document = self.document().clone()
|
||||
document.setTextWidth(document_width)
|
||||
|
||||
return margins.top() + document.size().height() + margins.bottom()
|
||||
|
||||
def sizeHint(self):
|
||||
width = super(ExpandingTextEdit, self).sizeHint().width()
|
||||
return QtCore.QSize(width, self.heightForWidth(width))
|
||||
|
||||
|
||||
class BaseClickableFrame(QtWidgets.QFrame):
|
||||
"""Widget that catch left mouse click and can trigger a callback.
|
||||
|
||||
|
|
@ -161,19 +201,34 @@ class ClickableLabel(QtWidgets.QLabel):
|
|||
|
||||
class ExpandBtnLabel(QtWidgets.QLabel):
|
||||
"""Label showing expand icon meant for ExpandBtn."""
|
||||
state_changed = QtCore.Signal()
|
||||
|
||||
|
||||
def __init__(self, parent):
|
||||
super(ExpandBtnLabel, self).__init__(parent)
|
||||
self._source_collapsed_pix = QtGui.QPixmap(
|
||||
get_style_image_path("branch_closed")
|
||||
)
|
||||
self._source_expanded_pix = QtGui.QPixmap(
|
||||
get_style_image_path("branch_open")
|
||||
)
|
||||
self._source_collapsed_pix = self._create_collapsed_pixmap()
|
||||
self._source_expanded_pix = self._create_expanded_pixmap()
|
||||
|
||||
self._current_image = self._source_collapsed_pix
|
||||
self._collapsed = True
|
||||
|
||||
def set_collapsed(self, collapsed):
|
||||
def _create_collapsed_pixmap(self):
|
||||
return QtGui.QPixmap(
|
||||
get_style_image_path("branch_closed")
|
||||
)
|
||||
|
||||
def _create_expanded_pixmap(self):
|
||||
return QtGui.QPixmap(
|
||||
get_style_image_path("branch_open")
|
||||
)
|
||||
|
||||
@property
|
||||
def collapsed(self):
|
||||
return self._collapsed
|
||||
|
||||
def set_collapsed(self, collapsed=None):
|
||||
if collapsed is None:
|
||||
collapsed = not self._collapsed
|
||||
if self._collapsed == collapsed:
|
||||
return
|
||||
self._collapsed = collapsed
|
||||
|
|
@ -182,6 +237,7 @@ class ExpandBtnLabel(QtWidgets.QLabel):
|
|||
else:
|
||||
self._current_image = self._source_expanded_pix
|
||||
self._set_resized_pix()
|
||||
self.state_changed.emit()
|
||||
|
||||
def resizeEvent(self, event):
|
||||
self._set_resized_pix()
|
||||
|
|
@ -203,21 +259,55 @@ class ExpandBtnLabel(QtWidgets.QLabel):
|
|||
|
||||
|
||||
class ExpandBtn(ClickableFrame):
|
||||
state_changed = QtCore.Signal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(ExpandBtn, self).__init__(parent)
|
||||
|
||||
pixmap_label = ExpandBtnLabel(self)
|
||||
pixmap_label = self._create_pix_widget(self)
|
||||
|
||||
layout = QtWidgets.QHBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(pixmap_label)
|
||||
|
||||
pixmap_label.state_changed.connect(self.state_changed)
|
||||
|
||||
self._pixmap_label = pixmap_label
|
||||
|
||||
def set_collapsed(self, collapsed):
|
||||
def _create_pix_widget(self, parent=None):
|
||||
if parent is None:
|
||||
parent = self
|
||||
return ExpandBtnLabel(parent)
|
||||
|
||||
@property
|
||||
def collapsed(self):
|
||||
return self._pixmap_label.collapsed
|
||||
|
||||
def set_collapsed(self, collapsed=None):
|
||||
self._pixmap_label.set_collapsed(collapsed)
|
||||
|
||||
|
||||
class ClassicExpandBtnLabel(ExpandBtnLabel):
|
||||
def _create_collapsed_pixmap(self):
|
||||
return QtGui.QPixmap(
|
||||
get_style_image_path("right_arrow")
|
||||
)
|
||||
|
||||
def _create_expanded_pixmap(self):
|
||||
return QtGui.QPixmap(
|
||||
get_style_image_path("down_arrow")
|
||||
)
|
||||
|
||||
|
||||
class ClassicExpandBtn(ExpandBtn):
|
||||
"""Same as 'ExpandBtn' but with arrow images."""
|
||||
|
||||
def _create_pix_widget(self, parent=None):
|
||||
if parent is None:
|
||||
parent = self
|
||||
return ClassicExpandBtnLabel(parent)
|
||||
|
||||
|
||||
class ImageButton(QtWidgets.QPushButton):
|
||||
"""PushButton with icon and size of font.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue