From 0a31e71bf4e5463b77fe48a86a5c101c976b5699 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 19 Apr 2019 10:45:25 +0200 Subject: [PATCH] added split and merge actions into components --- .../standalonepublish/widgets/__init__.py | 2 + .../widgets/widget_component_item.py | 48 ++++++- .../widgets/widget_components.py | 8 ++ .../widgets/widget_drop_frame.py | 121 ++++++++++-------- 4 files changed, 119 insertions(+), 60 deletions(-) diff --git a/pype/tools/standalonepublish/widgets/__init__.py b/pype/tools/standalonepublish/widgets/__init__.py index 9eb18f4d5d..cd99e15bed 100644 --- a/pype/tools/standalonepublish/widgets/__init__.py +++ b/pype/tools/standalonepublish/widgets/__init__.py @@ -30,3 +30,5 @@ from .widget_components_list import ComponentsList from .widget_drop_frame import DropDataFrame from .widget_components import ComponentsWidget + +from.widget_shadow import ShadowWidget diff --git a/pype/tools/standalonepublish/widgets/widget_component_item.py b/pype/tools/standalonepublish/widgets/widget_component_item.py index db35a2c468..6dec892d91 100644 --- a/pype/tools/standalonepublish/widgets/widget_component_item.py +++ b/pype/tools/standalonepublish/widgets/widget_component_item.py @@ -2,6 +2,7 @@ import os from . import QtCore, QtGui, QtWidgets from . import SvgButton from . import get_resource +from avalon import style class ComponentItem(QtWidgets.QFrame): @@ -13,11 +14,13 @@ class ComponentItem(QtWidgets.QFrame): signal_thumbnail = QtCore.Signal(object) signal_preview = QtCore.Signal(object) - def __init__(self, parent): + def __init__(self, parent, main_parent): super().__init__() + self.actions = [] self.resize(290, 70) self.setMinimumSize(QtCore.QSize(0, 70)) - self.parent_item = parent + self.parent_list = parent + self.parent_widget = main_parent # Font font = QtGui.QFont() font.setFamily("DejaVu Sans Condensed") @@ -49,12 +52,14 @@ class ComponentItem(QtWidgets.QFrame): self.icon.setText("") self.icon.setScaledContents(True) - self.action_menu = SvgButton( + self.btn_action_menu = SvgButton( get_resource('menu.svg'), 22, 22, [self.C_NORMAL, self.C_HOVER], frame_image_info, False ) + self.action_menu = QtWidgets.QMenu() + expanding_sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding ) @@ -62,7 +67,7 @@ class ComponentItem(QtWidgets.QFrame): expanding_sizePolicy.setVerticalStretch(0) layout.addWidget(self.icon, alignment=QtCore.Qt.AlignCenter) - layout.addWidget(self.action_menu, alignment=QtCore.Qt.AlignCenter) + layout.addWidget(self.btn_action_menu, alignment=QtCore.Qt.AlignCenter) layout_main.addWidget(frame_image_info) @@ -173,6 +178,7 @@ class ComponentItem(QtWidgets.QFrame): # 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) @@ -209,6 +215,39 @@ class ComponentItem(QtWidgets.QFrame): 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 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) @@ -233,6 +272,7 @@ class ComponentItem(QtWidgets.QFrame): def collect_data(self): data = { 'ext': self.in_data['ext'], + 'label': self.name.text(), 'representation': self.input_repre.text(), 'files': self.in_data['files'], 'thumbnail': self.is_thumbnail(), diff --git a/pype/tools/standalonepublish/widgets/widget_components.py b/pype/tools/standalonepublish/widgets/widget_components.py index 15222b17d7..61465f2ce5 100644 --- a/pype/tools/standalonepublish/widgets/widget_components.py +++ b/pype/tools/standalonepublish/widgets/widget_components.py @@ -84,6 +84,14 @@ class ComponentsWidget(QtWidgets.QWidget): paths = file_dialog.selectedFiles() self.drop_frame._process_paths(paths) + def working_start(self, msg=None): + if hasattr(self, 'parent_widget'): + self.parent_widget.working_start(msg) + + def working_stop(self): + if hasattr(self, 'parent_widget'): + self.parent_widget.working_stop() + def _publish(self): data = self.parent_widget.collect_data() from pprint import pprint diff --git a/pype/tools/standalonepublish/widgets/widget_drop_frame.py b/pype/tools/standalonepublish/widgets/widget_drop_frame.py index b353b23b41..ec8b07ce34 100644 --- a/pype/tools/standalonepublish/widgets/widget_drop_frame.py +++ b/pype/tools/standalonepublish/widgets/widget_drop_frame.py @@ -56,7 +56,7 @@ class DropDataFrame(QtWidgets.QFrame): except Exception: pass if paths: - self._add_components(paths) + self._process_paths(paths) def _processMimeData(self, mimeData): paths = [] @@ -69,17 +69,10 @@ class DropDataFrame(QtWidgets.QFrame): 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): + def _add_item(self, data, actions=[]): # Assign to self so garbage collector wont remove the component # during initialization - new_component = ComponentItem(self.components_list) + new_component = ComponentItem(self.components_list, self) new_component.set_context(data) self.components_list.add_widget(new_component) @@ -88,6 +81,9 @@ class DropDataFrame(QtWidgets.QFrame): new_component.signal_thumbnail.connect( self._set_thumbnail ) + for action in actions: + new_component.add_action(action) + self.items.append(new_component) self._refresh_view() @@ -131,12 +127,14 @@ class DropDataFrame(QtWidgets.QFrame): self.parent_widget.set_valid_components(not _bool) def _process_paths(self, in_paths): + self.parent_widget.working_start() 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) + self.parent_widget.working_stop() def _get_all_paths(self, paths): output_paths = [] @@ -246,6 +244,9 @@ class DropDataFrame(QtWidgets.QFrame): ) data['prev'] = ext in self.presets['extensions']['video_file'] + actions = [] + new_is_seq = data['is_sequence'] + found = False for item in self.items: if data['ext'] != item.in_data['ext']: @@ -253,7 +254,6 @@ class DropDataFrame(QtWidgets.QFrame): 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 @@ -266,68 +266,77 @@ class DropDataFrame(QtWidgets.QFrame): c, r = clique.assemble(paths) if len(c) == 0: continue + a_name = 'merge' + item.add_action(a_name) + if a_name not in actions: + actions.append(a_name) - found = True - self._remove_item(item) - self._process_collection(c[0]) - 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._remove_item(item) - self._process_collection(collections[0]) - break + + a_name = 'merge' + item.add_action(a_name) + if a_name not in actions: + actions.append(a_name) + continue + # 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']: - paths = [] - for path in item.in_data['files']: - if os.path.exists(path): - paths.append(path) - if len(paths) == 1: - self._remove_item(item) - found = False - break - paths = item.in_data['files'] - paths.append(new_file) - collections, remainders = clique.assemble(paths) - self._remove_item(item) - self._process_collection(collections[0]) + a_name = 'merge' + item.add_action(a_name) + if a_name not in actions: + actions.append(a_name) - 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 data['files'] == item.in_data['files']: + found = True + break + a_name = 'merge' + item.add_action(a_name) + if a_name not in actions: + actions.append(a_name) + + if new_is_seq: + actions.append('split') if found is False: - self._add_item(data) + self._add_item(data, actions) + + def merge_items(self, in_item): + self.parent_widget.working_start() + items = [] + in_paths = in_item.in_data['files'] + paths = in_paths + for item in self.items: + if item.in_data['files'] == in_paths: + items.append(item) + continue + copy_paths = paths.copy() + copy_paths.extend(item.in_data['files']) + collections, remainders = clique.assemble(copy_paths) + if len(collections) == 1 and len(remainders) == 0: + paths.extend(item.in_data['files']) + items.append(item) + for item in items: + self._remove_item(item) + self._process_paths(paths) + self.parent_widget.working_stop() + + def split_items(self, item): + self.parent_widget.working_start() + paths = item.in_data['files'] + self._remove_item(item) + for path in paths: + self._process_remainder(path) + self.parent_widget.working_stop() def collect_data(self): data = {'components' : []}