ayon-core/pype/standalonepublish/widgets/widget_component_item.py

522 lines
16 KiB
Python

import os
from . import QtCore, QtGui, QtWidgets
from . import get_resource
from pypeapp import style
class ComponentItem(QtWidgets.QFrame):
signal_remove = QtCore.Signal(object)
signal_thumbnail = QtCore.Signal(object)
signal_preview = QtCore.Signal(object)
signal_repre_change = QtCore.Signal(object, object)
preview_text = "PREVIEW"
thumbnail_text = "THUMBNAIL"
def __init__(self, parent, main_parent):
super().__init__()
self.has_valid_repre = True
self.actions = []
self.resize(290, 70)
self.setMinimumSize(QtCore.QSize(0, 70))
self.parent_list = parent
self.parent_widget = main_parent
# Font
font = QtGui.QFont()
font.setFamily("DejaVu Sans Condensed")
font.setPointSize(9)
font.setBold(True)
font.setWeight(50)
font.setKerning(True)
# Main widgets
frame = QtWidgets.QFrame(self)
frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
frame.setFrameShadow(QtWidgets.QFrame.Raised)
layout_main = QtWidgets.QHBoxLayout(frame)
layout_main.setSpacing(2)
layout_main.setContentsMargins(2, 2, 2, 2)
# Image + Info
frame_image_info = QtWidgets.QFrame(frame)
# Layout image info
layout = QtWidgets.QVBoxLayout(frame_image_info)
layout.setSpacing(2)
layout.setContentsMargins(2, 2, 2, 2)
self.icon = QtWidgets.QLabel(frame)
self.icon.setMinimumSize(QtCore.QSize(22, 22))
self.icon.setMaximumSize(QtCore.QSize(22, 22))
self.icon.setText("")
self.icon.setScaledContents(True)
self.btn_action_menu = PngButton(
name="menu", size=QtCore.QSize(22, 22)
)
self.action_menu = QtWidgets.QMenu()
expanding_sizePolicy = QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding
)
expanding_sizePolicy.setHorizontalStretch(0)
expanding_sizePolicy.setVerticalStretch(0)
layout.addWidget(self.icon, alignment=QtCore.Qt.AlignCenter)
layout.addWidget(self.btn_action_menu, alignment=QtCore.Qt.AlignCenter)
layout_main.addWidget(frame_image_info)
# Name + representation
self.name = QtWidgets.QLabel(frame)
self.file_info = QtWidgets.QLabel(frame)
self.ext = QtWidgets.QLabel(frame)
self.name.setFont(font)
self.file_info.setFont(font)
self.ext.setFont(font)
self.file_info.setStyleSheet('padding-left:3px;')
expanding_sizePolicy.setHeightForWidth(
self.name.sizePolicy().hasHeightForWidth()
)
frame_name_repre = QtWidgets.QFrame(frame)
self.file_info.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
self.ext.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
self.name.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
layout = QtWidgets.QHBoxLayout(frame_name_repre)
layout.setSpacing(0)
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(self.name, alignment=QtCore.Qt.AlignLeft)
layout.addWidget(self.file_info, alignment=QtCore.Qt.AlignLeft)
layout.addWidget(self.ext, alignment=QtCore.Qt.AlignRight)
frame_name_repre.setSizePolicy(
QtWidgets.QSizePolicy.MinimumExpanding,
QtWidgets.QSizePolicy.MinimumExpanding
)
# Repre + icons
frame_repre_icons = QtWidgets.QFrame(frame)
frame_repre = QtWidgets.QFrame(frame_repre_icons)
label_repre = QtWidgets.QLabel()
label_repre.setText('Representation:')
self.input_repre = QtWidgets.QLineEdit()
self.input_repre.setMaximumWidth(50)
layout = QtWidgets.QHBoxLayout(frame_repre)
layout.setSpacing(0)
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(label_repre, alignment=QtCore.Qt.AlignLeft)
layout.addWidget(self.input_repre, alignment=QtCore.Qt.AlignLeft)
frame_icons = QtWidgets.QFrame(frame_repre_icons)
self.preview = LightingButton(self.preview_text)
self.thumbnail = LightingButton(self.thumbnail_text)
layout = QtWidgets.QHBoxLayout(frame_icons)
layout.setSpacing(6)
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(self.thumbnail)
layout.addWidget(self.preview)
layout = QtWidgets.QHBoxLayout(frame_repre_icons)
layout.setSpacing(0)
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(frame_repre, alignment=QtCore.Qt.AlignLeft)
layout.addWidget(frame_icons, alignment=QtCore.Qt.AlignRight)
frame_middle = QtWidgets.QFrame(frame)
layout = QtWidgets.QVBoxLayout(frame_middle)
layout.setSpacing(0)
layout.setContentsMargins(4, 0, 4, 0)
layout.addWidget(frame_name_repre)
layout.addWidget(frame_repre_icons)
layout.setStretchFactor(frame_name_repre, 1)
layout.setStretchFactor(frame_repre_icons, 1)
layout_main.addWidget(frame_middle)
self.remove = PngButton(name="trash", size=QtCore.QSize(22, 22))
layout_main.addWidget(self.remove)
layout = QtWidgets.QVBoxLayout(self)
layout.setSpacing(0)
layout.setContentsMargins(2, 2, 2, 2)
layout.addWidget(frame)
self.preview.setToolTip('Mark component as Preview')
self.thumbnail.setToolTip('Component will be selected as thumbnail')
# self.frame.setStyleSheet("border: 1px solid black;")
def set_context(self, data):
self.btn_action_menu.setVisible(False)
self.in_data = data
self.remove.clicked.connect(self._remove)
self.thumbnail.clicked.connect(self._thumbnail_clicked)
self.preview.clicked.connect(self._preview_clicked)
self.input_repre.textChanged.connect(self._handle_duplicate_repre)
name = data['name']
representation = data['representation']
ext = data['ext']
file_info = data['file_info']
thumb = data['thumb']
prev = data['prev']
icon = data['icon']
resource = None
if icon is not None:
resource = get_resource('{}.png'.format(icon))
if resource is None or not os.path.isfile(resource):
if data['is_sequence']:
resource = get_resource('files.png')
else:
resource = get_resource('file.png')
pixmap = QtGui.QPixmap(resource)
self.icon.setPixmap(pixmap)
self.name.setText(name)
self.input_repre.setText(representation)
self.ext.setText('( {} )'.format(ext))
if file_info is None:
self.file_info.setVisible(False)
else:
self.file_info.setText('[{}]'.format(file_info))
self.thumbnail.setVisible(thumb)
self.preview.setVisible(prev)
def add_action(self, action_name):
if action_name.lower() == 'split':
for action in self.actions:
if action.text() == 'Split to frames':
return
new_action = QtWidgets.QAction('Split to frames', self)
new_action.triggered.connect(self.split_sequence)
elif action_name.lower() == 'merge':
for action in self.actions:
if action.text() == 'Merge components':
return
new_action = QtWidgets.QAction('Merge components', self)
new_action.triggered.connect(self.merge_sequence)
else:
print('unknown action')
return
self.action_menu.addAction(new_action)
self.actions.append(new_action)
if not self.btn_action_menu.isVisible():
self.btn_action_menu.setVisible(True)
self.btn_action_menu.clicked.connect(self.show_actions)
self.action_menu.setStyleSheet(style.load_stylesheet())
def set_repre_name_valid(self, valid):
self.has_valid_repre = valid
if valid:
self.input_repre.setStyleSheet("")
else:
self.input_repre.setStyleSheet("border: 1px solid red;")
def split_sequence(self):
self.parent_widget.split_items(self)
def merge_sequence(self):
self.parent_widget.merge_items(self)
def show_actions(self):
position = QtGui.QCursor().pos()
self.action_menu.popup(position)
def _remove(self):
self.signal_remove.emit(self)
def _thumbnail_clicked(self):
self.signal_thumbnail.emit(self)
def _preview_clicked(self):
self.signal_preview.emit(self)
def _handle_duplicate_repre(self, repre_name):
self.signal_repre_change.emit(self, repre_name)
def is_thumbnail(self):
return self.thumbnail.isChecked()
def change_thumbnail(self, hover=True):
self.thumbnail.setChecked(hover)
def is_preview(self):
return self.preview.isChecked()
def change_preview(self, hover=True):
self.preview.setChecked(hover)
def collect_data(self):
in_files = self.in_data['files']
staging_dir = os.path.dirname(in_files[0])
files = [os.path.basename(file) for file in in_files]
if len(files) == 1:
files = files[0]
data = {
'ext': self.in_data['ext'],
'label': self.name.text(),
'name': self.input_repre.text(),
'stagingDir': staging_dir,
'files': files,
'thumbnail': self.is_thumbnail(),
'preview': self.is_preview()
}
if ("frameStart" in self.in_data and "frameEnd" in self.in_data):
data["frameStart"] = self.in_data["frameStart"]
data["frameEnd"] = self.in_data["frameEnd"]
if 'fps' in self.in_data:
data['fps'] = self.in_data['fps']
return data
class LightingButton(QtWidgets.QPushButton):
lightingbtnstyle = """
QPushButton {
font: %(font_size_pt)spt;
text-align: center;
color: #777777;
background-color: transparent;
border-width: 1px;
border-color: #777777;
border-style: solid;
padding-top: 0px;
padding-bottom: 0px;
padding-left: 3px;
padding-right: 3px;
border-radius: 3px;
}
QPushButton:hover {
border-color: #cccccc;
color: #cccccc;
}
QPushButton:pressed {
border-color: #ffffff;
color: #ffffff;
}
QPushButton:disabled {
border-color: #3A3939;
color: #3A3939;
}
QPushButton:checked {
border-color: #4BB543;
color: #4BB543;
}
QPushButton:checked:hover {
border-color: #4Bd543;
color: #4Bd543;
}
QPushButton:checked:pressed {
border-color: #4BF543;
color: #4BF543;
}
"""
def __init__(self, text, font_size_pt=8, *args, **kwargs):
super(LightingButton, self).__init__(text, *args, **kwargs)
self.setStyleSheet(self.lightingbtnstyle % {
"font_size_pt": font_size_pt
})
self.setCheckable(True)
class PngFactory:
png_names = {
"trash": {
"normal": QtGui.QIcon(get_resource("trash.png")),
"hover": QtGui.QIcon(get_resource("trash_hover.png")),
"pressed": QtGui.QIcon(get_resource("trash_pressed.png")),
"pressed_hover": QtGui.QIcon(
get_resource("trash_pressed_hover.png")
),
"disabled": QtGui.QIcon(get_resource("trash_disabled.png"))
},
"menu": {
"normal": QtGui.QIcon(get_resource("menu.png")),
"hover": QtGui.QIcon(get_resource("menu_hover.png")),
"pressed": QtGui.QIcon(get_resource("menu_pressed.png")),
"pressed_hover": QtGui.QIcon(
get_resource("menu_pressed_hover.png")
),
"disabled": QtGui.QIcon(get_resource("menu_disabled.png"))
}
}
class PngButton(QtWidgets.QPushButton):
png_button_style = """
QPushButton {
border: none;
background-color: transparent;
padding-top: 0px;
padding-bottom: 0px;
padding-left: 0px;
padding-right: 0px;
}
QPushButton:hover {}
QPushButton:pressed {}
QPushButton:disabled {}
QPushButton:checked {}
QPushButton:checked:hover {}
QPushButton:checked:pressed {}
"""
def __init__(
self, name=None, path=None, hover_path=None, pressed_path=None,
hover_pressed_path=None, disabled_path=None,
size=None, *args, **kwargs
):
self._hovered = False
self._pressed = False
super(PngButton, self).__init__(*args, **kwargs)
self.setStyleSheet(self.png_button_style)
png_dict = {}
if name:
png_dict = PngFactory.png_names.get(name) or {}
if not png_dict:
print((
"WARNING: There is not set icon with name \"{}\""
"in PngFactory!"
).format(name))
ico_normal = png_dict.get("normal")
ico_hover = png_dict.get("hover")
ico_pressed = png_dict.get("pressed")
ico_hover_pressed = png_dict.get("pressed_hover")
ico_disabled = png_dict.get("disabled")
if path:
ico_normal = QtGui.QIcon(path)
if hover_path:
ico_hover = QtGui.QIcon(hover_path)
if pressed_path:
ico_pressed = QtGui.QIcon(hover_path)
if hover_pressed_path:
ico_hover_pressed = QtGui.QIcon(hover_pressed_path)
if disabled_path:
ico_disabled = QtGui.QIcon(disabled_path)
self.setIcon(ico_normal)
if size:
self.setIconSize(size)
self.setMaximumSize(size)
self.ico_normal = ico_normal
self.ico_hover = ico_hover
self.ico_pressed = ico_pressed
self.ico_hover_pressed = ico_hover_pressed
self.ico_disabled = ico_disabled
def setDisabled(self, in_bool):
super(PngButton, self).setDisabled(in_bool)
icon = self.ico_normal
if in_bool and self.ico_disabled:
icon = self.ico_disabled
self.setIcon(icon)
def enterEvent(self, event):
self._hovered = True
if not self.isEnabled():
return
icon = self.ico_normal
if self.ico_hover:
icon = self.ico_hover
if self._pressed and self.ico_hover_pressed:
icon = self.ico_hover_pressed
if self.icon() != icon:
self.setIcon(icon)
def mouseMoveEvent(self, event):
super(PngButton, self).mouseMoveEvent(event)
if self._pressed:
mouse_pos = event.pos()
hovering = self.rect().contains(mouse_pos)
if hovering and not self._hovered:
self.enterEvent(event)
elif not hovering and self._hovered:
self.leaveEvent(event)
def leaveEvent(self, event):
self._hovered = False
if not self.isEnabled():
return
icon = self.ico_normal
if self._pressed and self.ico_pressed:
icon = self.ico_pressed
if self.icon() != icon:
self.setIcon(icon)
def mousePressEvent(self, event):
self._pressed = True
if not self.isEnabled():
return
icon = self.ico_hover
if self.ico_pressed:
icon = self.ico_pressed
if self.ico_hover_pressed:
mouse_pos = event.pos()
if self.rect().contains(mouse_pos):
icon = self.ico_hover_pressed
if icon is None:
icon = self.ico_normal
if self.icon() != icon:
self.setIcon(icon)
def mouseReleaseEvent(self, event):
if not self.isEnabled():
return
if self._pressed:
self._pressed = False
mouse_pos = event.pos()
if self.rect().contains(mouse_pos):
self.clicked.emit()
icon = self.ico_normal
if self._hovered and self.ico_hover:
icon = self.ico_hover
if self.icon() != icon:
self.setIcon(icon)