mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-26 05:42:15 +01:00
* initial commitof ayon loader * tweaks in ayon utils * implemented product type filtering * products have icons and proper style * fix refresh of products * added enable grouping checkbox * added icons and sorting of grouped items * fix version delegate * add splitter between context and product type filtering * fix products filtering by name * implemented 'filter_repre_contexts_by_loader' * implemented base of action items * implemented folder underline colors * changed version items to dictionary * use 'product_id' instead of 'subset_id' * base implementation of info widget * require less to trigger action * set selection of version ids in controller * added representation widget and related logic changes * implemented actions in representations widget * handle load error * use versions for subset loader * fix representations widget * implemente "in scene" logic properly * use ayon loader in host tools * fix used function to get tasks * show actions per representation name * center window * add window flag to loader window * added 'ThumbnailPainterWidget' to tool utils * implemented thumbnails model * implement thumbnail widget * fix FolderItem args docstring * bypass bug in ayon_api * fix sorting of folders * added refresh button * added expected selection and go to current context * added information if project item is library project * added more filtering options to projects widget * added missing information abou is library to model items * remove select project item on selection change * filter out non library projects * set current context project to project combobox * change window title * fix hero version queries * move current project to the top * fix reset * change icon for library projects * added libraries separator to project widget * show libraries separator in loader * ise single line expression * library loader tool is loader tool in AYON mode * fixes in grouping model * implemented grouping logic * use loader in tray action * better initial sizes * moved 'ActionItem' to abstract * filter loaders by tool name based on current context project * formatting fixes * separate abstract classes into frontend and backend abstractions * added docstrings to abstractions * implemented 'to_data' and 'from_data' for action item options * added more docstrings * first filter representation contexts and then create action items * implemented 'refresh' method * do not reset controller in '_on_first_show' Method '_on_show_timer' will take about the reset. * 'ThumbnailPainterWidget' have more options of bg painting * do not use checkerboard in loader thumbnail * fix condition Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com> --------- Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com>
366 lines
12 KiB
Python
366 lines
12 KiB
Python
from qtpy import QtWidgets, QtCore, QtGui
|
|
|
|
from openpype.style import get_objected_colors
|
|
|
|
from .lib import paint_image_with_color
|
|
from .images import get_image
|
|
|
|
|
|
class ThumbnailPainterWidget(QtWidgets.QWidget):
|
|
"""Widget for painting of thumbnails.
|
|
|
|
The widget use is to paint thumbnail or multiple thumbnails in a defined
|
|
area. Is not meant to show them in a grid but in overlay.
|
|
|
|
It is expected that there is a logic that will provide thumbnails to
|
|
paint and set them using 'set_current_thumbnails' or
|
|
'set_current_thumbnail_paths'.
|
|
"""
|
|
|
|
width_ratio = 3.0
|
|
height_ratio = 2.0
|
|
border_width = 1
|
|
max_thumbnails = 3
|
|
offset_sep = 4
|
|
checker_boxes_count = 20
|
|
|
|
def __init__(self, parent):
|
|
super(ThumbnailPainterWidget, self).__init__(parent)
|
|
|
|
border_color = get_objected_colors("bg-buttons").get_qcolor()
|
|
thumbnail_bg_color = get_objected_colors("bg-view").get_qcolor()
|
|
|
|
default_image = get_image("thumbnail.png")
|
|
default_pix = paint_image_with_color(default_image, border_color)
|
|
|
|
self._border_color = border_color
|
|
self._thumbnail_bg_color = thumbnail_bg_color
|
|
self._default_pix = default_pix
|
|
|
|
self._cached_pix = None
|
|
self._current_pixes = None
|
|
self._has_pixes = False
|
|
|
|
self._bg_color = QtCore.Qt.transparent
|
|
self._use_checker = True
|
|
self._checker_color_1 = QtGui.QColor(89, 89, 89)
|
|
self._checker_color_2 = QtGui.QColor(188, 187, 187)
|
|
|
|
def set_background_color(self, color):
|
|
self._bg_color = color
|
|
self.repaint()
|
|
|
|
def set_use_checkboard(self, use_checker):
|
|
if self._use_checker is use_checker:
|
|
return
|
|
self._use_checker = use_checker
|
|
self.repaint()
|
|
|
|
def set_checker_colors(self, color_1, color_2):
|
|
self._checker_color_1 = color_1
|
|
self._checker_color_2 = color_2
|
|
self.repaint()
|
|
|
|
def set_border_color(self, color):
|
|
"""Change border color.
|
|
|
|
Args:
|
|
color (QtGui.QColor): Color to set.
|
|
"""
|
|
|
|
self._border_color = color
|
|
self._default_pix = None
|
|
self.clear_cache()
|
|
|
|
def set_thumbnail_bg_color(self, color):
|
|
"""Change background color.
|
|
|
|
Args:
|
|
color (QtGui.QColor): Color to set.
|
|
"""
|
|
|
|
self._thumbnail_bg_color = color
|
|
self.clear_cache()
|
|
|
|
@property
|
|
def has_pixes(self):
|
|
"""Has set thumbnails.
|
|
|
|
Returns:
|
|
bool: True if widget has thumbnails to paint.
|
|
"""
|
|
|
|
return self._has_pixes
|
|
|
|
def clear_cache(self):
|
|
"""Clear cache of resized thumbnails and repaint widget."""
|
|
|
|
self._cached_pix = None
|
|
self.repaint()
|
|
|
|
def set_current_thumbnails(self, pixmaps=None):
|
|
"""Set current thumbnails.
|
|
|
|
Args:
|
|
pixmaps (Optional[List[QtGui.QPixmap]]): List of pixmaps.
|
|
"""
|
|
|
|
self._current_pixes = pixmaps or None
|
|
self._has_pixes = self._current_pixes is not None
|
|
self.clear_cache()
|
|
|
|
def set_current_thumbnail_paths(self, thumbnail_paths=None):
|
|
"""Set current thumbnails.
|
|
|
|
Set current thumbnails using paths to a files.
|
|
|
|
Args:
|
|
thumbnail_paths (Optional[List[str]]): List of paths to thumbnail
|
|
sources.
|
|
"""
|
|
|
|
pixes = []
|
|
if thumbnail_paths:
|
|
for thumbnail_path in thumbnail_paths:
|
|
pixes.append(QtGui.QPixmap(thumbnail_path))
|
|
|
|
self.set_current_thumbnails(pixes)
|
|
|
|
def paintEvent(self, event):
|
|
if self._cached_pix is None:
|
|
self._cache_pix()
|
|
|
|
painter = QtGui.QPainter()
|
|
painter.begin(self)
|
|
painter.setRenderHint(QtGui.QPainter.Antialiasing)
|
|
painter.drawPixmap(0, 0, self._cached_pix)
|
|
painter.end()
|
|
|
|
def resizeEvent(self, event):
|
|
self._cached_pix = None
|
|
super(ThumbnailPainterWidget, self).resizeEvent(event)
|
|
|
|
def _get_default_pix(self):
|
|
if self._default_pix is None:
|
|
default_image = get_image("thumbnail")
|
|
default_pix = paint_image_with_color(
|
|
default_image, self._border_color)
|
|
self._default_pix = default_pix
|
|
return self._default_pix
|
|
|
|
def _paint_tile(self, width, height):
|
|
if not self._use_checker:
|
|
tile_pix = QtGui.QPixmap(width, width)
|
|
tile_pix.fill(self._bg_color)
|
|
return tile_pix
|
|
|
|
checker_size = int(float(width) / self.checker_boxes_count)
|
|
if checker_size < 1:
|
|
checker_size = 1
|
|
|
|
checker_pix = QtGui.QPixmap(checker_size * 2, checker_size * 2)
|
|
checker_pix.fill(QtCore.Qt.transparent)
|
|
checker_painter = QtGui.QPainter()
|
|
checker_painter.begin(checker_pix)
|
|
checker_painter.setPen(QtCore.Qt.NoPen)
|
|
checker_painter.setBrush(self._checker_color_1)
|
|
checker_painter.drawRect(
|
|
0, 0, checker_pix.width(), checker_pix.height()
|
|
)
|
|
checker_painter.setBrush(self._checker_color_2)
|
|
checker_painter.drawRect(
|
|
0, 0, checker_size, checker_size
|
|
)
|
|
checker_painter.drawRect(
|
|
checker_size, checker_size, checker_size, checker_size
|
|
)
|
|
checker_painter.end()
|
|
return checker_pix
|
|
|
|
def _paint_default_pix(self, pix_width, pix_height):
|
|
full_border_width = 2 * self.border_width
|
|
width = pix_width - full_border_width
|
|
height = pix_height - full_border_width
|
|
if width > 100:
|
|
width = int(width * 0.6)
|
|
height = int(height * 0.6)
|
|
|
|
scaled_pix = self._get_default_pix().scaled(
|
|
width,
|
|
height,
|
|
QtCore.Qt.KeepAspectRatio,
|
|
QtCore.Qt.SmoothTransformation
|
|
)
|
|
pos_x = int(
|
|
(pix_width - scaled_pix.width()) / 2
|
|
)
|
|
pos_y = int(
|
|
(pix_height - scaled_pix.height()) / 2
|
|
)
|
|
new_pix = QtGui.QPixmap(pix_width, pix_height)
|
|
new_pix.fill(QtCore.Qt.transparent)
|
|
pix_painter = QtGui.QPainter()
|
|
pix_painter.begin(new_pix)
|
|
render_hints = (
|
|
QtGui.QPainter.Antialiasing
|
|
| QtGui.QPainter.SmoothPixmapTransform
|
|
)
|
|
if hasattr(QtGui.QPainter, "HighQualityAntialiasing"):
|
|
render_hints |= QtGui.QPainter.HighQualityAntialiasing
|
|
|
|
pix_painter.setRenderHints(render_hints)
|
|
pix_painter.drawPixmap(pos_x, pos_y, scaled_pix)
|
|
pix_painter.end()
|
|
return new_pix
|
|
|
|
def _draw_thumbnails(self, thumbnails, pix_width, pix_height):
|
|
full_border_width = 2 * self.border_width
|
|
|
|
checker_pix = self._paint_tile(pix_width, pix_height)
|
|
|
|
backgrounded_images = []
|
|
for src_pix in thumbnails:
|
|
scaled_pix = src_pix.scaled(
|
|
pix_width - full_border_width,
|
|
pix_height - full_border_width,
|
|
QtCore.Qt.KeepAspectRatio,
|
|
QtCore.Qt.SmoothTransformation
|
|
)
|
|
pos_x = int(
|
|
(pix_width - scaled_pix.width()) / 2
|
|
)
|
|
pos_y = int(
|
|
(pix_height - scaled_pix.height()) / 2
|
|
)
|
|
|
|
new_pix = QtGui.QPixmap(pix_width, pix_height)
|
|
new_pix.fill(QtCore.Qt.transparent)
|
|
pix_painter = QtGui.QPainter()
|
|
pix_painter.begin(new_pix)
|
|
render_hints = (
|
|
QtGui.QPainter.Antialiasing
|
|
| QtGui.QPainter.SmoothPixmapTransform
|
|
)
|
|
if hasattr(QtGui.QPainter, "HighQualityAntialiasing"):
|
|
render_hints |= QtGui.QPainter.HighQualityAntialiasing
|
|
pix_painter.setRenderHints(render_hints)
|
|
|
|
tiled_rect = QtCore.QRectF(
|
|
pos_x, pos_y, scaled_pix.width(), scaled_pix.height()
|
|
)
|
|
pix_painter.drawTiledPixmap(
|
|
tiled_rect,
|
|
checker_pix,
|
|
QtCore.QPointF(0.0, 0.0)
|
|
)
|
|
pix_painter.drawPixmap(pos_x, pos_y, scaled_pix)
|
|
pix_painter.end()
|
|
backgrounded_images.append(new_pix)
|
|
return backgrounded_images
|
|
|
|
def _paint_dash_line(self, painter, rect):
|
|
pen = QtGui.QPen()
|
|
pen.setWidth(1)
|
|
pen.setBrush(QtCore.Qt.darkGray)
|
|
pen.setStyle(QtCore.Qt.DashLine)
|
|
|
|
new_rect = rect.adjusted(1, 1, -1, -1)
|
|
painter.setPen(pen)
|
|
painter.setBrush(QtCore.Qt.transparent)
|
|
# painter.drawRect(rect)
|
|
painter.drawRect(new_rect)
|
|
|
|
def _cache_pix(self):
|
|
rect = self.rect()
|
|
rect_width = rect.width()
|
|
rect_height = rect.height()
|
|
|
|
pix_x_offset = 0
|
|
pix_y_offset = 0
|
|
expected_height = int(
|
|
(rect_width / self.width_ratio) * self.height_ratio
|
|
)
|
|
if expected_height > rect_height:
|
|
expected_height = rect_height
|
|
expected_width = int(
|
|
(rect_height / self.height_ratio) * self.width_ratio
|
|
)
|
|
pix_x_offset = (rect_width - expected_width) / 2
|
|
else:
|
|
expected_width = rect_width
|
|
pix_y_offset = (rect_height - expected_height) / 2
|
|
|
|
if self._current_pixes is None:
|
|
used_default_pix = True
|
|
pixes_to_draw = None
|
|
pixes_len = 1
|
|
else:
|
|
used_default_pix = False
|
|
pixes_to_draw = self._current_pixes
|
|
if len(pixes_to_draw) > self.max_thumbnails:
|
|
pixes_to_draw = pixes_to_draw[:-self.max_thumbnails]
|
|
pixes_len = len(pixes_to_draw)
|
|
|
|
width_offset, height_offset = self._get_pix_offset_size(
|
|
expected_width, expected_height, pixes_len
|
|
)
|
|
pix_width = expected_width - width_offset
|
|
pix_height = expected_height - height_offset
|
|
|
|
if used_default_pix:
|
|
thumbnail_images = [self._paint_default_pix(pix_width, pix_height)]
|
|
else:
|
|
thumbnail_images = self._draw_thumbnails(
|
|
pixes_to_draw, pix_width, pix_height
|
|
)
|
|
|
|
if pixes_len == 1:
|
|
width_offset_part = 0
|
|
height_offset_part = 0
|
|
else:
|
|
width_offset_part = int(float(width_offset) / (pixes_len - 1))
|
|
height_offset_part = int(float(height_offset) / (pixes_len - 1))
|
|
full_width_offset = width_offset + pix_x_offset
|
|
|
|
final_pix = QtGui.QPixmap(rect_width, rect_height)
|
|
final_pix.fill(QtCore.Qt.transparent)
|
|
|
|
bg_pen = QtGui.QPen()
|
|
bg_pen.setWidth(self.border_width)
|
|
bg_pen.setColor(self._border_color)
|
|
|
|
final_painter = QtGui.QPainter()
|
|
final_painter.begin(final_pix)
|
|
render_hints = (
|
|
QtGui.QPainter.Antialiasing
|
|
| QtGui.QPainter.SmoothPixmapTransform
|
|
)
|
|
if hasattr(QtGui.QPainter, "HighQualityAntialiasing"):
|
|
render_hints |= QtGui.QPainter.HighQualityAntialiasing
|
|
|
|
final_painter.setRenderHints(render_hints)
|
|
|
|
final_painter.setBrush(QtGui.QBrush(self._thumbnail_bg_color))
|
|
final_painter.setPen(bg_pen)
|
|
final_painter.drawRect(rect)
|
|
|
|
for idx, pix in enumerate(thumbnail_images):
|
|
x_offset = full_width_offset - (width_offset_part * idx)
|
|
y_offset = (height_offset_part * idx) + pix_y_offset
|
|
final_painter.drawPixmap(x_offset, y_offset, pix)
|
|
|
|
# Draw drop enabled dashes
|
|
if used_default_pix:
|
|
self._paint_dash_line(final_painter, rect)
|
|
|
|
final_painter.end()
|
|
|
|
self._cached_pix = final_pix
|
|
|
|
def _get_pix_offset_size(self, width, height, image_count):
|
|
if image_count == 1:
|
|
return 0, 0
|
|
|
|
part_width = width / self.offset_sep
|
|
part_height = height / self.offset_sep
|
|
return part_width, part_height
|