added widgets for component inserting

This commit is contained in:
Jakub Trllo 2019-04-16 14:25:19 +02:00
parent 09cc2e9e59
commit a09c90aeb3
6 changed files with 539 additions and 0 deletions

View file

@ -21,3 +21,10 @@ from .widget_asset_view import AssetView
from .widget_asset import AssetWidget
from .widget_family_desc import FamilyDescriptionWidget
from .widget_family import FamilyWidget
from .widget_drop_data import DropDataWidget
from .widget_component import ComponentWidget
from .widget_tree_components import TreeComponents
from .widget_component_item import ComponentItem
from .widget_drop_files import DropDataFrame

View file

@ -0,0 +1,189 @@
from . import QtCore, QtGui, QtWidgets
from . import SvgButton
from . import get_resource
class ComponentWidget(QtWidgets.QFrame):
C_NORMAL = '#777777'
C_HOVER = '#ffffff'
C_ACTIVE = '#4BB543'
C_ACTIVE_HOVER = '#4BF543'
signal_remove = QtCore.Signal(object)
def __init__(self, parent):
super().__init__()
self.resize(290, 70)
self.setMinimumSize(QtCore.QSize(0, 70))
self.parent_item = 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)
image = QtWidgets.QLabel(frame)
image.setMinimumSize(QtCore.QSize(22, 22))
image.setMaximumSize(QtCore.QSize(22, 22))
image.setText("")
image.setScaledContents(True)
pixmap = QtGui.QPixmap(get_resource('image_sequence.png'))
image.setPixmap(pixmap)
self.info = SvgButton(
get_resource('information.svg'), 22, 22,
[self.C_NORMAL, self.C_HOVER],
frame_image_info, False
)
expanding_sizePolicy = QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding
)
expanding_sizePolicy.setHorizontalStretch(0)
expanding_sizePolicy.setVerticalStretch(0)
layout.addWidget(image, alignment=QtCore.Qt.AlignCenter)
layout.addWidget(self.info, alignment=QtCore.Qt.AlignCenter)
layout_main.addWidget(frame_image_info)
# Name + representation
self.name = QtWidgets.QLabel(frame)
self.frames = QtWidgets.QLabel(frame)
self.ext = QtWidgets.QLabel(frame)
self.name.setFont(font)
self.frames.setFont(font)
self.ext.setFont(font)
self.frames.setStyleSheet('padding-left:3px;')
expanding_sizePolicy.setHeightForWidth(self.name.sizePolicy().hasHeightForWidth())
frame_name_repre = QtWidgets.QFrame(frame)
self.frames.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.frames, alignment=QtCore.Qt.AlignLeft)
layout.addWidget(self.ext, alignment=QtCore.Qt.AlignRight)
frame_name_repre.setSizePolicy(
QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding
)
# Frames + icons
frame_repre_icons = QtWidgets.QFrame(frame)
label_repre = QtWidgets.QLabel()
label_repre.setText('Representation:')
self.input_repre = QtWidgets.QLineEdit()
self.input_repre.setMaximumWidth(50)
frame_icons = QtWidgets.QFrame(frame_repre_icons)
self.preview = SvgButton(
get_resource('preview.svg'), 64, 18,
[self.C_NORMAL, self.C_HOVER, self.C_ACTIVE, self.C_ACTIVE_HOVER],
frame_icons
)
self.thumbnail = SvgButton(
get_resource('thumbnail.svg'), 84, 18,
[self.C_NORMAL, self.C_HOVER, self.C_ACTIVE, self.C_ACTIVE_HOVER],
frame_icons
)
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(label_repre, alignment=QtCore.Qt.AlignLeft)
layout.addWidget(self.input_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 = SvgButton(
get_resource('trash.svg'), 22, 22,
[self.C_NORMAL, self.C_HOVER],
frame, False
)
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.remove.clicked.connect(self._remove)
name = data['name']
representation = data['representation']
ext = data['ext']
file_info = data['file_info']
thumb = data['thumb']
prev = data['prev']
info = data['info']
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 _remove(self):
self.signal_remove.emit(self.parent_item)

View file

@ -0,0 +1,15 @@
from . import QtWidgets
from . import ComponentWidget
class ComponentItem(QtWidgets.QTreeWidgetItem):
def __init__(self, parent, data):
super().__init__(parent)
self.in_data = data
self._widget = ComponentWidget(self)
self._widget.set_context(data)
self.treeWidget().setItemWidget(self, 0, self._widget)
def double_clicked(*args):
pass

View file

@ -0,0 +1,41 @@
import os
import logging
import clique
from . import QtWidgets, QtCore, QtGui
class DropDataWidget(QtWidgets.QWidget):
def __init__(self, parent):
'''Initialise DataDropZone widget.'''
super().__init__(parent)
layout = QtWidgets.QVBoxLayout(self)
bottomCenterAlignment = QtCore.Qt.AlignBottom | QtCore.Qt.AlignHCenter
topCenterAlignment = QtCore.Qt.AlignTop | QtCore.Qt.AlignHCenter
self._label = QtWidgets.QLabel('Drop files here')
layout.addWidget(
self._label,
alignment=bottomCenterAlignment
)
self._browseButton = QtWidgets.QPushButton('Browse')
self._browseButton.setToolTip('Browse for file(s).')
layout.addWidget(
self._browseButton, alignment=topCenterAlignment
)
def paintEvent(self, event):
super().paintEvent(event)
painter = QtGui.QPainter(self)
pen = QtGui.QPen()
pen.setWidth(1);
pen.setBrush(QtCore.Qt.darkGray);
pen.setStyle(QtCore.Qt.DashLine);
painter.setPen(pen)
painter.drawRect(
10, 10,
self.rect().width()-15, self.rect().height()-15
)

View file

@ -0,0 +1,273 @@
import os
import clique
from . import QtWidgets, QtCore
from . import ComponentItem, TreeComponents, DropDataWidget
class DropDataFrame(QtWidgets.QFrame):
# signal_dropped = QtCore.Signal(object)
def __init__(self, parent):
super().__init__()
self.items = []
self.setAcceptDrops(True)
layout = QtWidgets.QVBoxLayout(self)
self.tree_widget = TreeComponents(self)
layout.addWidget(self.tree_widget)
self.drop_widget = DropDataWidget(self)
layout.addWidget(self.drop_widget)
self._refresh_view()
def dragEnterEvent(self, event):
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
def dragLeaveEvent(self, event):
event.accept()
def dropEvent(self, event):
paths = self._processMimeData(event.mimeData())
if paths:
self._add_components(paths)
event.accept()
def _processMimeData(self, mimeData):
paths = []
if not mimeData.hasUrls():
print('Dropped invalid file/folder')
return paths
for path in mimeData.urls():
local_path = path.toLocalFile()
if os.path.isfile(local_path) or os.path.isdir(local_path):
paths.append(local_path)
else:
print('Invalid input: "{}"'.format(local_path))
return paths
def _add_components(self, paths):
components = self._process_paths(paths)
if not components:
return
for component in components:
self._add_item(component)
def _add_item(self, data):
# Assign to self so garbage collector wont remove the component
# during initialization
self.new_component = ComponentItem(self.tree_widget, data)
self.new_component._widget.signal_remove.connect(self._remove_item)
self.tree_widget.addTopLevelItem(self.new_component)
self.items.append(self.new_component)
self.new_component = None
self._refresh_view()
def _remove_item(self, item):
root = self.tree_widget.invisibleRootItem()
(item.parent() or root).removeChild(item)
self.items.remove(item)
self._refresh_view()
def _refresh_view(self):
_bool = len(self.items) == 0
self.tree_widget.setVisible(not _bool)
self.drop_widget.setVisible(_bool)
def _process_paths(self, in_paths):
paths = self._get_all_paths(in_paths)
collections, remainders = clique.assemble(paths)
for collection in collections:
self._process_collection(collection)
for remainder in remainders:
self._process_remainder(remainder)
def _get_all_paths(self, paths):
output_paths = []
for path in paths:
path = os.path.normpath(path)
if os.path.isfile(path):
output_paths.append(path)
elif os.path.isdir(path):
s_paths = []
for s_item in os.listdir(path):
s_path = os.path.sep.join([path, s_item])
s_paths.append(s_path)
output_paths.extend(self._get_all_paths(s_paths))
else:
print('Invalid path: "{}"'.format(path))
return output_paths
def _process_collection(self, collection):
file_base = os.path.basename(collection.head)
folder_path = os.path.dirname(collection.head)
if file_base[-1] in ['.']:
file_base = file_base[:-1]
file_ext = collection.tail
repr_name = file_ext.replace('.', '')
range = self._get_ranges(collection.indexes)
thumb = False
if file_ext in ['.jpeg']:
thumb = True
prev = False
if file_ext in ['.jpeg']:
prev = True
files = []
for file in os.listdir(folder_path):
if file.startswith(file_base) and file.endswith(file_ext):
files.append(os.path.sep.join([folder_path, file]))
info = {}
data = {
'files': files,
'name': file_base,
'ext': file_ext,
'file_info': range,
'representation': repr_name,
'folder_path': folder_path,
'icon': 'sequence',
'thumb': thumb,
'prev': prev,
'is_sequence': True,
'info': info
}
self._process_data(data)
def _get_ranges(self, indexes):
if len(indexes) == 1:
return str(indexes[0])
ranges = []
first = None
last = None
for index in indexes:
if first is None:
first = index
last = index
elif (last+1) == index:
last = index
else:
if first == last:
range = str(first)
else:
range = '{}-{}'.format(first, last)
ranges.append(range)
first = index
last = index
if first == last:
range = str(first)
else:
range = '{}-{}'.format(first, last)
ranges.append(range)
return ', '.join(ranges)
def _process_remainder(self, remainder):
filename = os.path.basename(remainder)
folder_path = os.path.dirname(remainder)
file_base, file_ext = os.path.splitext(filename)
repr_name = file_ext.replace('.', '')
file_info = None
thumb = False
if file_ext in ['.jpeg']:
thumb = True
prev = False
if file_ext in ['.jpeg']:
prev = True
files = []
files.append(remainder)
info = {}
data = {
'files': files,
'name': file_base,
'ext': file_ext,
'file_info': file_info,
'representation': repr_name,
'folder_path': folder_path,
'icon': 'sequence',
'thumb': thumb,
'prev': prev,
'is_sequence': False,
'info': info
}
self._process_data(data)
def _process_data(self, data):
found = False
for item in self.items:
if data['ext'] != item.in_data['ext']:
continue
if data['folder_path'] != item.in_data['folder_path']:
continue
new_is_seq = data['is_sequence']
ex_is_seq = item.in_data['is_sequence']
# If both are single files
if not new_is_seq and not ex_is_seq:
if data['name'] != item.in_data['name']:
continue
found = True
break
# If new is sequence and ex is single file
elif new_is_seq and not ex_is_seq:
if data['name'] not in item.in_data['name']:
continue
ex_file = item.in_data['files'][0]
found = True
# If file is one of inserted sequence
if ex_file in data['files']:
self._remove_item(item)
self._add_item(data)
break
# if file is missing in inserted sequence
paths = data['files']
paths.append(ex_file)
collections, remainders = clique.assemble(paths)
self._process_collection(collections[0])
break
# If new is single file existing is sequence
elif not new_is_seq and ex_is_seq:
if item.in_data['name'] not in data['name']:
continue
new_file = data['files'][0]
found = True
if new_file in item.in_data['files']:
break
paths = item.in_data['files']
paths.append(new_file)
collections, remainders = clique.assemble(paths)
self._remove_item(item)
self._process_collection(collections[0])
break
# If both are sequence
else:
if data['name'] != item.in_data['name']:
continue
found = True
ex_files = item.in_data['files']
for file in data['files']:
if file not in ex_files:
ex_files.append(file)
paths = list(set(ex_files))
collections, remainders = clique.assemble(paths)
self._remove_item(item)
self._process_collection(collections[0])
break
if found is False:
self._add_item(data)

View file

@ -0,0 +1,14 @@
from . import QtCore, QtGui, QtWidgets
class TreeComponents(QtWidgets.QTreeWidget):
def __init__(self, parent):
super().__init__(parent)
self.invisibleRootItem().setFlags(QtCore.Qt.ItemIsEnabled)
self.setIndentation(28)
self.headerItem().setText(0, 'Components')
self.setRootIsDecorated(False)
self.itemDoubleClicked.connect(lambda i, c: i.double_clicked(c))