class PreviewWidget(base.BaseWidget, object): def __init__(self, item_view, parent=None): self._item_view = item_view self._sequence_widget = None self._form_widget = None super(PreviewWidget, self).__init__(parent=parent) self._create_sequence_widget() # ============================================================================================================ # OVERRIDES # ============================================================================================================ def get_main_layout(self): main_layout = layouts.VerticalLayout(spacing=2, margins=(0, 0, 0, 0)) main_layout.setAlignment(Qt.AlignTop) return main_layout def ui(self): super(PreviewWidget, self).ui() title_frame = QFrame(self) title_frame_layout = layouts.HorizontalLayout(spacing=0, margins=(0, 0, 0, 0)) title_frame.setLayout(title_frame_layout) title_widget = QWidget(self) title_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) title_widget.setLayout(title_layout) buttons_layout = layouts.HorizontalLayout(spacing=0, margins=(0, 0, 0, 0)) title_layout.addLayout(buttons_layout) self._title_icon = label.BaseLabel(parent=self) self._title_button = label.ElidedLabel(parent=self) self._title_button.setText(self.item().name()) self._menu_button = buttons.BaseButton(parent=self) self._menu_button.setIcon(resources.icon('menu_dots')) buttons_layout.addWidget(self._title_icon) buttons_layout.addStretch() buttons_layout.addWidget(self._title_button) buttons_layout.addStretch() buttons_layout.addWidget(self._menu_button) title_frame_layout.addWidget(title_widget) item_icon_name = self.item().icon() or 'tpDcc' item_icon = resources.icon(item_icon_name) if not item_icon: item_icon = resources.icon('tpDcc') self._title_icon.setPixmap(item_icon.pixmap(QSize(20, 20))) icon_title_frame = QFrame(self) icon_title_frame_layout = layouts.VerticalLayout(spacing=0, margins=(4, 2, 4, 2)) icon_title_frame.setLayout(icon_title_frame_layout) self._icon_group_frame = QFrame(self) icon_group_layout = layouts.HorizontalLayout(spacing=0, margins=(0, 0, 0, 0)) self._icon_group_frame.setLayout(icon_group_layout) self._icon_frame = QFrame(self) icon_frame_layout = layouts.VerticalLayout(spacing=0, margins=(4, 2, 4, 2)) self._icon_frame.setLayout(icon_frame_layout) icon_group_layout.addWidget(self._icon_frame) icon_group_box_widget = group.GroupBoxWidget('Icon', widget=self._icon_group_frame, parent=self) icon_title_frame_layout.addWidget(icon_group_box_widget) form_frame = QFrame(self) form_frame_layout = layouts.VerticalLayout(spacing=0, margins=(4, 2, 4, 2)) form_frame.setLayout(form_frame_layout) buttons_frame = QFrame(self) buttons_frame_layout = layouts.HorizontalLayout(spacing=4, margins=(4, 4, 4, 4)) buttons_frame.setLayout(buttons_frame_layout) self._accept_button = buttons.BaseButton('Load') self._accept_button.setIcon(resources.icon('open')) self._accept_button.setVisible(False) buttons_frame_layout.addWidget(self._accept_button) schema = self._item_view.item.load_schema() if self._item_view else None if schema: self._form_widget = formwidget.FormWidget(self) self._form_widget.setObjectName('{}Form'.format(self._item_view.__class__.__name__)) self._form_widget.set_schema(schema) self._form_widget.set_validator(self.validator) form_frame_layout.addWidget(self._form_widget) self.main_layout.addWidget(title_frame) self.main_layout.addWidget(icon_title_frame) self.main_layout.addWidget(self._icon_group_frame) self.main_layout.addWidget(form_frame) self.main_layout.addStretch() self.main_layout.addWidget(buttons_frame) def setup_signals(self): self._menu_button.clicked.connect(self._on_show_menu) self._accept_button.clicked.connect(self.on_load) def resizeEvent(self, event): """ Overrides base BaseWidget resizeEvent function to make sure the icon image size is updated :param event: QSizeEvent """ self.update_thumbnail_size() def close(self): """ Overrides base BaseWidget close function to save widget persistent data """ # TODO: It is not sure this function it is going to be called when the app is closed # TODO: Find a better approach if self._form_widget: self._form_widget.save_persistent_values() super(PreviewWidget, self).close() # ============================================================================================================ # BASE # ============================================================================================================ def item(self): """ Returns the library item to load :return: LibraryItem """ return self._item_view def validator(self, **kwargs): """ Returns validator used for validating the item loaded arguments :param kwargs: dict """ self._item_view.load_validator(**kwargs) self.update_icon() def update_icon(self): """ Updates item thumbnail icon """ # Updates static icon icon = self._item_view.thumbnail_icon() if icon: self._sequence_widget.setIcon(icon) # Update images sequence (if exist) if self._item_view.image_sequence_path(): self._sequence_widget.set_dirname(self._item_view.image_sequence_path()) def update_thumbnail_size(self): """ Updates the thumbnail button to the size of the widget """ width = self.width() - 5 width = width if width <= 150 else 150 size = QSize(width, width) self._icon_frame.setMaximumSize(size) self._icon_group_frame.setMaximumSize(size) if self._sequence_widget: self._sequence_widget.setIconSize(size) self._sequence_widget.setMinimumSize(size) self._sequence_widget.setMaximumSize(size) # ============================================================================================================ # INTERNAL # ============================================================================================================ def _create_sequence_widget(self): """ Internal function that creates sequence widget for the item """ self._sequence_widget = sequence.ImageSequenceWidget(self._icon_frame) self._icon_frame.layout().insertWidget(0, self._sequence_widget) self.update_icon() # ============================================================================================================ # CALLBACKS # ============================================================================================================ def _on_item_data_changed(self, *args, **kwargs): """ Internal callback function that is called when item data changes :param args: :param kwargs: """ self.update_icon() def _on_show_menu(self): """ Internal callback function triggered when item menu should be opened :return: QAction """ menu = QMenu(self) self.item().context_edit_menu(menu) point = QCursor.pos() point.setX(point.x() + 3) point.setY(point.y() + 3) return menu.exec_(point) def on_load(self): """ Internal callback function that is triggered when load button is pressed by the user """ kwargs = self._form_widget.values() self._item_view.load(**kwargs)
class LoadWidget(BaseLoadWidget, object): HISTORY_WIDGET = history.HistoryFileWidget OPTIONS_WIDGET = None def __init__(self, item, parent=None): self._icon_path = '' self._script_job = None self._options_widget = None super(LoadWidget, self).__init__(item, parent=parent) self.load_settings() self.create_sequence_widget() self.update_thumbnail_size() def ui(self): super(LoadWidget, self).ui() tabs_widget = tabs.BaseTabWidget(parent=self) info_widget = QWidget() info_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) info_widget.setLayout(info_layout) if self.OPTIONS_WIDGET: self._options_widget = self.OPTIONS_WIDGET(parent=self) title_layout = layouts.HorizontalLayout(spacing=1, margins=(1, 1, 0, 0)) self._icon_lbl = label.BaseLabel('', parent=self) self._icon_lbl.setMaximumSize(QSize(14, 14)) self._icon_lbl.setMinimumSize(QSize(14, 14)) self._icon_lbl.setScaledContents(True) self._title_lbl = label.BaseLabel('Title', parent=self) title_layout.addWidget(self._icon_lbl) title_layout.addWidget(self._title_lbl) icon_toggle_box = QFrame() icon_toggle_box.setFrameShape(QFrame.NoFrame) icon_toggle_box.setFrameShadow(QFrame.Plain) icon_toggle_box_lyt = layouts.VerticalLayout(spacing=1, margins=(0, 1, 0, 0)) icon_toggle_box.setLayout(icon_toggle_box_lyt) icon_toggle_box_header = QFrame() icon_toggle_box_header.setFrameShape(QFrame.NoFrame) icon_toggle_box_header.setFrameShadow(QFrame.Plain) icon_toggle_box_header_lyt = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) icon_toggle_box_header.setLayout(icon_toggle_box_header_lyt) self._icon_toggle_box_btn = buttons.BaseButton('ICON', parent=self) self._icon_toggle_box_btn.setObjectName('iconButton') self._icon_toggle_box_btn.setCheckable(True) self._icon_toggle_box_btn.setChecked(True) icon_toggle_box_header_lyt.addWidget(self._icon_toggle_box_btn) self._icon_toggle_box_frame = QFrame() self._icon_toggle_box_frame.setFrameShape(QFrame.NoFrame) self._icon_toggle_box_frame.setFrameShadow(QFrame.Plain) icon_toggle_box_frame_lyt = layouts.VerticalLayout(spacing=1, margins=(0, 1, 0, 0)) self._icon_toggle_box_frame.setLayout(icon_toggle_box_frame_lyt) thumbnail_layout = layouts.HorizontalLayout(spacing=0, margins=(0, 0, 0, 0)) icon_toggle_box_frame_lyt.addLayout(thumbnail_layout) thumbnail_frame_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) self._thumbnail_frame = QFrame() self._thumbnail_frame.setFrameShape(QFrame.NoFrame) self._thumbnail_frame.setFrameShadow(QFrame.Plain) self._thumbnail_frame.setLayout(thumbnail_frame_layout) thumbnail_layout.addWidget(self._thumbnail_frame) self._thumbnail_btn = QToolButton() self._thumbnail_btn.setObjectName('thumbnailButton') self._thumbnail_btn.setMinimumSize(QSize(0, 0)) self._thumbnail_btn.setMaximumSize(QSize(150, 150)) self._thumbnail_btn.setStyleSheet( 'color: rgb(40, 40, 40);\nborder: 1px solid rgb(0, 0, 0, 0);\nbackground-color: rgb(254, 255, 230, 0);' ) self._thumbnail_btn.setLayoutDirection(Qt.LeftToRight) self._thumbnail_btn.setText('Snapshot') self._thumbnail_btn.setIcon(resources.icon('thumbnail')) thumbnail_frame_layout.addWidget(self._thumbnail_btn) icon_toggle_box_lyt.addWidget(icon_toggle_box_header) icon_toggle_box_lyt.addWidget(self._icon_toggle_box_frame) info_toggle_box = QFrame() info_toggle_box.setFrameShape(QFrame.NoFrame) info_toggle_box.setFrameShadow(QFrame.Plain) info_toggle_box_lyt = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) info_toggle_box.setLayout(info_toggle_box_lyt) info_toggle_box_header = QFrame() info_toggle_box_header.setFrameShape(QFrame.NoFrame) info_toggle_box_header.setFrameShadow(QFrame.Plain) info_toggle_box_header_lyt = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) info_toggle_box_header.setLayout(info_toggle_box_header_lyt) self._info_toggle_box_btn = buttons.BaseButton('INFO', parent=self) self._info_toggle_box_btn.setObjectName('infoButton') self._info_toggle_box_btn.setCheckable(True) self._info_toggle_box_btn.setChecked(True) info_toggle_box_header_lyt.addWidget(self._info_toggle_box_btn) self._info_toggle_box_frame = QFrame() self._info_toggle_box_frame.setFrameShape(QFrame.NoFrame) self._info_toggle_box_frame.setFrameShadow(QFrame.Plain) info_toggle_box_frame_lyt = layouts.VerticalLayout(spacing=1, margins=(0, 1, 0, 0)) self._info_toggle_box_frame.setLayout(info_toggle_box_frame_lyt) self._info_frame = QFrame() self._info_frame.setFrameShape(QFrame.NoFrame) self._info_frame.setFrameShadow(QFrame.Plain) info_frame_lyt = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) self._info_frame.setLayout(info_frame_lyt) info_toggle_box_frame_lyt.addWidget(self._info_frame) info_toggle_box_lyt.addWidget(info_toggle_box_header) info_toggle_box_lyt.addWidget(self._info_toggle_box_frame) version_toggle_box = QFrame() version_toggle_box.setFrameShape(QFrame.NoFrame) version_toggle_box.setFrameShadow(QFrame.Plain) version_toggle_box_lyt = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) version_toggle_box.setLayout(version_toggle_box_lyt) version_toggle_box_header = QFrame() version_toggle_box_header.setFrameShape(QFrame.NoFrame) version_toggle_box_header.setFrameShadow(QFrame.Plain) version_toggle_box_header_lyt = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) version_toggle_box_header.setLayout(version_toggle_box_header_lyt) self._version_toggle_box_btn = buttons.BaseButton('VERSION', parent=self) self._version_toggle_box_btn.setObjectName('versionButton') self._version_toggle_box_btn.setCheckable(True) self._version_toggle_box_btn.setChecked(True) version_toggle_box_header_lyt.addWidget(self._version_toggle_box_btn) self._version_toggle_box_frame = QFrame() self._version_toggle_box_frame.setFrameShape(QFrame.NoFrame) self._version_toggle_box_frame.setFrameShadow(QFrame.Plain) version_toggle_box_frame_lyt = layouts.VerticalLayout(spacing=1, margins=(0, 1, 0, 0)) self._version_toggle_box_frame.setLayout(version_toggle_box_frame_lyt) self._version_frame = QFrame() self._version_frame.setFrameShape(QFrame.NoFrame) self._version_frame.setFrameShadow(QFrame.Plain) version_frame_lyt = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) self._version_frame.setLayout(version_frame_lyt) version_toggle_box_frame_lyt.addWidget(self._version_frame) self._history_widget = self.HISTORY_WIDGET() version_frame_lyt.addWidget(self._history_widget) version_toggle_box_lyt.addWidget(version_toggle_box_header) version_toggle_box_lyt.addWidget(self._version_toggle_box_frame) preview_buttons_frame = QFrame() preview_buttons_frame.setObjectName('previewButtons') preview_buttons_frame.setFrameShape(QFrame.NoFrame) preview_buttons_frame.setFrameShadow(QFrame.Plain) self._preview_buttons_frame_lyt = layouts.VerticalLayout(spacing=0, margins=(2, 2, 2, 2)) self._preview_buttons_lyt = layouts.HorizontalLayout(spacing=2, margins=(0, 0, 0, 0)) self._load_btn = buttons.BaseButton('Load', parent=self) self._load_btn.setObjectName('loadButton') self._load_btn.setMinimumSize(QSize(60, 35)) self._load_btn.setMaximumSize(QSize(125, 35)) self._preview_buttons_frame_lyt.addStretch() self._preview_buttons_frame_lyt.addLayout(self._preview_buttons_lyt) self._preview_buttons_frame_lyt.addStretch() self._preview_buttons_lyt.addWidget(self._load_btn) preview_buttons_frame.setLayout(self._preview_buttons_frame_lyt) info_layout.addLayout(title_layout) info_layout.addWidget(icon_toggle_box) info_layout.addWidget(info_toggle_box) info_layout.addWidget(version_toggle_box) tabs_widget.addTab(info_widget, 'Info') if self._options_widget: tabs_widget.addTab(self._options_widget, 'Options') self.main_layout.addWidget(tabs_widget) self.main_layout.addWidget(dividers.Divider()) self.main_layout.addWidget(preview_buttons_frame) self.main_layout.addItem( QSpacerItem(0, 250, QSizePolicy.Preferred, QSizePolicy.Expanding)) def setup_signals(self): self._info_toggle_box_btn.clicked.connect(self.save_settings) self._info_toggle_box_btn.toggled[bool].connect( self._info_toggle_box_frame.setVisible) self._icon_toggle_box_btn.clicked.connect(self.save_settings) self._icon_toggle_box_btn.toggled[bool].connect( self._icon_toggle_box_frame.setVisible) self._version_toggle_box_btn.clicked.connect(self.save_settings) self._version_toggle_box_btn.toggled[bool].connect( self._version_toggle_box_frame.setVisible) self._load_btn.clicked.connect(self.load) def resizeEvent(self, event): """ Function that overrides base.BaseWidget function :param event: QSizeEvent """ self.update_thumbnail_size() def set_item(self, item): """ Sets the library item to load :param item: LibraryItem """ super(LoadWidget, self).set_item(item) self._title_lbl.setText(item.MenuName) self._icon_lbl.setPixmap(QPixmap(item.type_icon_path())) info_widget = formwidget.FormWidget(self) info_widget.set_schema(item.info()) self._info_frame.layout().addWidget(info_widget) self.refresh() def load_btn(self): """ Returns button that loads the data :return: QPushButton """ return self._load_btn def icon_path(self): """ Returns the icon path to be used for the thumbnail :return: str """ return self._icon_path def set_icon_path(self, path): """ Sets the icon path to be used for the thumbnail :param path: str """ self._icon_path = path icon = QIcon(QPixmap(path)) self.set_icon(icon) self.update_thumbnail_size() self.item().update() def set_icon(self, icon): """ Sets the icon to be shown for the preview :param icon: QIcon """ self._thumbnail_btn.setIcon(icon) self._thumbnail_btn.setIconSize(QSize(200, 200)) self._thumbnail_btn.setText('') def refresh(self): """ Refreshes load widgetz """ self.update_history() self.update_options() def update_history(self): """ Updates history version of the current selected item """ if not self._item: return data_object = self._item.data_object() if not data_object: return self._history_widget.set_directory(data_object.directory) self._history_widget.refresh() def update_options(self): """ Updates options widget """ if not self._options_widget: return if not self._item: return data_object = self._item.data_object() if not data_object: return self._options_widget.set_data_object(data_object) def is_editable(self): """ Returns whether the user can edit the item or not :return: bool """ item = self.item() editable = True if item and item.library_window(): editable = not item.library_window().is_locked() return editable def create_sequence_widget(self): """ Creates a sequence widget to replace the static thumbnail widget """ self._sequence_widget = widgets.LibraryImageSequenceWidget(self) self._sequence_widget.setStyleSheet(self._thumbnail_btn.styleSheet()) self._sequence_widget.setToolTip(self._thumbnail_btn.toolTip()) self._thumbnail_frame.layout().insertWidget(0, self._sequence_widget) self._thumbnail_btn.hide() self._thumbnail_btn = self._sequence_widget path = self.item().thumbnail_path() if path and os.path.exists(path): self.set_icon_path(path) if self.item().image_sequence_path(): self._sequence_widget.set_dirname( self.item().image_sequence_path()) def update_thumbnail_size(self): """ Updates the thumbnail button to the size of the widget """ width = self.width() - 10 if width > 250: width = 250 size = QSize(width, width) self._thumbnail_btn.setIconSize(size) self._thumbnail_btn.setMaximumSize(size) self._thumbnail_frame.setMaximumSize(size) def settings(self): """ Returns the current state of the widget :return: dict """ settings = dict() settings['iconToggleBoxChecked'] = self._icon_toggle_box_btn.isChecked( ) settings['infoToggleBoxChecked'] = self._info_toggle_box_btn.isChecked( ) settings[ 'versionToggleBoxChecked'] = self._version_toggle_box_btn.isChecked( ) return settings def save_settings(self): pass def load_settings(self): pass def load(self): """ Loads current item """ if not self.item(): return self.item().load_from_current_options()
class BaseSaveWidget(base.BaseWidget, object): cancelled = Signal() saved = Signal() ENABLE_THUMBNAIL_CAPTURE = True def __init__(self, item_view, client=None, *args, **kwargs): self._item_view = item_view self._client = client self._form_widget = None self._sequence_widget = None super(BaseSaveWidget, self).__init__(*args, **kwargs) self.setObjectName('LibrarySaveWidget') self._create_sequence_widget() self.update_thumbnail_size() self.set_item_view(item_view) # ============================================================================================================ # OVERRIDES # ============================================================================================================ def get_main_layout(self): return layouts.VerticalLayout(spacing=4, margins=(0, 0, 0, 0)) def ui(self): super(BaseSaveWidget, self).ui() self.setWindowTitle('Save Item') title_frame = QFrame(self) title_frame_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) title_frame.setLayout(title_frame_layout) title_widget = QFrame(self) title_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) title_widget.setLayout(title_layout) title_buttons_layout = layouts.HorizontalLayout(spacing=0, margins=(0, 0, 0, 0)) title_layout.addLayout(title_buttons_layout) title_icon = label.BaseLabel(parent=self) title_button = label.BaseLabel(self.item().menu_name(), parent=self) title_button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self._menu_button = buttons.BaseButton(parent=self) self._menu_button.setIcon(resources.icon('menu_dots')) self._menu_button.setVisible(False) # Hide by default title_buttons_layout.addWidget(title_icon) title_buttons_layout.addSpacing(5) title_buttons_layout.addWidget(title_button) title_buttons_layout.addWidget(self._menu_button) title_frame_layout.addWidget(title_widget) item_icon_name = self.item().icon() or 'tpDcc' item_icon = resources.icon(item_icon_name) if not item_icon: item_icon = resources.icon('tpDcc') title_icon.setPixmap(item_icon.pixmap(QSize(20, 20))) thumbnail_layout = layouts.HorizontalLayout(spacing=0, margins=(0, 0, 0, 0)) self._thumbnail_frame = QFrame(self) thumbnail_frame_layout = layouts.VerticalLayout(spacing=0, margins=(0, 2, 0, 2)) self._thumbnail_frame.setLayout(thumbnail_frame_layout) thumbnail_layout.addWidget(self._thumbnail_frame) self._options_frame = QFrame(self) options_frame_layout = layouts.VerticalLayout(spacing=0, margins=(4, 2, 4, 2)) self._options_frame.setLayout(options_frame_layout) preview_buttons_frame = QFrame(self) self._preview_buttons_layout = layouts.HorizontalLayout(spacing=0, margins=(4, 2, 4, 2)) preview_buttons_frame.setLayout(self._preview_buttons_layout) self._save_button = buttons.BaseButton('Save', parent=self) self._save_button.setIcon(resources.icon('save')) self._cancel_button = buttons.BaseButton('Cancel', parent=self) self._cancel_button.setIcon(resources.icon('cancel')) self._preview_buttons_layout.addStretch() self._preview_buttons_layout.addWidget(self._save_button) self._preview_buttons_layout.addStretch() self._preview_buttons_layout.addWidget(self._cancel_button) self._preview_buttons_layout.addStretch() self.main_layout.addWidget(title_frame) self.main_layout.addLayout(thumbnail_layout) self.main_layout.addWidget(self._options_frame) self.main_layout.addWidget(preview_buttons_frame) def setup_signals(self): self._menu_button.clicked.connect(self._on_show_menu) self._save_button.clicked.connect(self._on_save) self._cancel_button.clicked.connect(self._on_cancel) def resizeEvent(self, event): """ Overrides base QWidget resizeEvent function :param event: QResizeEvent """ self.update_thumbnail_size() def close(self): """ Overrides base QWidget close function to disable script job when its is done """ if self._form_widget: self._form_widget.save_persistent_values() super(BaseSaveWidget, self).close() # ============================================================================================================ # BASE # ============================================================================================================ def folder_path(self): """ Returns the folder path :return: str """ return self.form_widget().value('folder') def set_folder_path(self, path): """ Sets the destination folder path :param path: str """ self.form_widget().set_value('folder', path) def set_thumbnail_path(self, path): """ Sets the path to the thumbnail image or the image sequence directory :param path: str """ file_name, extension = os.path.splitext(path) target = utils.temp_path('thumbnail{}'.format(extension)) utils.copy_path(path, target, force=True) self._sequence_widget.set_path(target) def library_window(self): """ Returns library widget window for the item :return: LibraryWindow """ return self.item_view().library_window() def set_library_window(self, library_window): """ Sets the library widget for the item :param library_window: LibraryWindow """ self.item_view().set_library_window(library_window) def form_widget(self): """ Returns the form widget instance :return: FormWidget """ return self._form_widget def item(self): """ Returns current item :return: """ return self.item_view().item def item_view(self): """ Returns the current item view :return: LibraryItem """ return self._item_view def set_item_view(self, item_view): """ Sets the base item to be created :param item_view: LibraryItem """ self._item_view = item_view if os.path.exists(item_view.image_sequence_path()): self.set_thumbnail_path(item_view.image_sequence_path()) elif not item_view.is_default_thumbnail_path(): self.set_thumbnail_path(item_view.thumbnail_path()) schema = self.item().save_schema() if schema: form_widget = formwidget.FormWidget(self) form_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) form_widget.set_schema(schema) form_widget.set_validator(self.item().save_validator) # item_name = os.path.basename(item.path()) # form_widget.set_values({'name': item_name}) self._options_frame.layout().addWidget(form_widget) form_widget.validate() self._form_widget = form_widget else: self._options_frame.setVisible(False) def update_thumbnail_size(self): """ Updates the thumbnail button to teh size of the widget """ width = self.width() - 10 if width > 250: width = 250 size = QSize(width, width) if self._sequence_widget: self._sequence_widget.setIconSize(size) self._sequence_widget.setMaximumSize(size) self._thumbnail_frame.setMaximumSize(size) def show_thumbnail_capture_dialog(self): """ Asks the user if they would like to capture a thumbnail :return: int """ buttons = QDialogButtonBox.Yes | QDialogButtonBox.Ignore | QDialogButtonBox.Cancel parent = self.item_view().library_window() btn = messagebox.MessageBox.question( parent, 'Create a thumbnail', 'Would you like to capture a thumbnail?', buttons=buttons) if btn == QDialogButtonBox.Yes: self.thumbnail_capture() return btn def show_by_frame_dialog(self): """ Show the by frame dialog """ help_text = """ To help speed up the playblast you can set the "by frame" to another greater than 1. For example if the "by frame" is set to 2 it will playblast every second frame """ result = None options = self.form_widget().values() by_frame = options.get('byFrame', 1) start_frame, end_frame = options.get('frameRange', [None, None]) duration = end_frame - start_frame if start_frame is not None and end_frame is not None else 1 if duration > 100 and by_frame == 1: buttons = QDialogButtonBox.Ok | QDialogButtonBox.Cancel result = messagebox.MessageBox.question( self.library_window(), title='Tip', text=help_text, buttons=buttons, enable_dont_show_checkbox=True) return result def thumbnail_capture(self, show=False): """ Captures a playblast and saves it to the temporal thumbnail path :param show: bool """ options = self.form_widget().values() start_frame, end_frame = options.get('frameRange', [None, None]) step = options.get('byFrame', 1) if not qtutils.is_control_modifier(): result = self.show_by_frame_dialog() if result == QDialogButtonBox.Cancel: return path = utils.temp_path('sequence', 'thumbnail.jpg') try: snapshot.SnapshotWindow(path=path, on_save=self._on_thumbnail_captured) # thumbnail.ThumbnailCaptureDialog.thumbnail_capture( # path=self._temp_path, # show=show, # start_frame=start_frame, # end_frame=end_frame, # step=step, # clear_cache=False, # captured=self._on_thumbnail_captured # ) except Exception as e: messagebox.MessageBox.critical(self.library_window(), 'Error while capturing thumbnail', str(e)) LOGGER.error(traceback.format_exc()) def save(self, path, thumbnail): """ Saves the item with the given objects to the given disk location path :param path: str :param thumbnail: str """ kwargs = self.form_widget().values() sequence_path = self._sequence_widget.dirname() item_view = self.item_view() item_view.item_view.path = path library_window = self.library_window() valid_save = item_view.safe_save(thumbnail=thumbnail, sequence_path=sequence_path, **kwargs) if valid_save: if library_window: library_window.refresh() library_window.select_folder_path(path) self.saved.emit() self.close() # ============================================================================================================ # INTERNAL # ============================================================================================================ def _create_sequence_widget(self): """ Internal function that creates a sequence widget to replace the static thumbnail widget """ self._sequence_widget = sequence.ImageSequenceWidget(self) self._sequence_widget.setObjectName('thumbnailButton') self._thumbnail_frame.layout().insertWidget(0, self._sequence_widget) self._sequence_widget.clicked.connect(self._on_thumbnail_capture) self._sequence_widget.setToolTip( 'Click to capture a thumbnail from the current model panel.\n' 'CTRL + Click to show the capture window for better framing.') camera_icon = resources.get('icons', self.theme().style(), 'camera.png') expand_icon = resources.get('icons', self.theme().style(), 'full_screen.png') folder_icon = resources.get('icons', self.theme().style(), 'folder.png') self._sequence_widget.addAction(camera_icon, 'Capture new image', 'Capture new image', self._on_thumbnail_capture) self._sequence_widget.addAction(expand_icon, 'Show Capture window', 'Show Capture window', self._on_show_capture_window) self._sequence_widget.addAction(folder_icon, 'Load image from disk', 'Load image from disk', self._on_show_browse_image_dialog) self._sequence_widget.setIcon(resources.icon('tpdcc')) # ============================================================================================================ # CALLBACKS # ============================================================================================================ def _on_show_menu(self): """ Internal callback function that is called when menu button is clicked byu the user :return: QAction """ pass def _on_save(self): if not self.library_window(): return False library = self.library_window().library() if not library: return False try: self.form_widget().validate() if self.form_widget().has_errors(): raise Exception('\n'.join(self.form_widget().errors())) has_frames = self._sequence_widget.has_frames() if not has_frames and self.ENABLE_THUMBNAIL_CAPTURE: button = self.show_thumbnail_capture_dialog() if button == QDialogButtonBox.Cancel: return False name = self.form_widget().value('name') folder = self.form_widget().value('folder') comment = self.form_widget().value('comment') or '' extension = self.item().extension() if extension and not name.endswith(extension): name = '{}{}'.format(name, extension) path = folder + '/' + name thumbnail = self._sequence_widget.first_frame() save_item = library.get(path, only_extension=True) save_function = save_item.functionality().get('save') if not save_function: LOGGER.warning( 'Item "{}" does not supports save operation'.format( save_item)) return False library_path = self.item().library.identifier if not library_path or not os.path.isfile(library_path): LOGGER.warning( 'Impossible to save data "{}" because its library does not exists: "{}"' .format(self.item(), library_path)) return values = self.form_widget().values() try: if self._client: success, message, dependencies = self._client().save_data( library_path=library_path, data_path=path, values=values) if not success: messagebox.MessageBox.critical(self.library_window(), 'Error while saving', str(message)) LOGGER.error(str(message)) return False else: dependencies = save_function(**values) except Exception as exc: messagebox.MessageBox.critical(self.library_window(), 'Error while saving', str(exc)) LOGGER.error(traceback.format_exc()) return False except Exception as exc: messagebox.MessageBox.critical(self.library_window(), 'Error while saving', str(exc)) LOGGER.error(traceback.format_exc()) raise new_item_path = save_item.format_identifier() if not new_item_path or not os.path.isfile(new_item_path): LOGGER.warning( 'Although saving process for item "{}" was completed, ' 'it seems no new data has been generated!'.format(save_item)) self.saved.emit() return False save_item.library.add(new_item_path) # # TODO: Instead of creating a local version, we will use a git system to upload our data to our project repo # # TODO: Should we save new versions of dependencies too? # valid = save_item.create_version(comment=comment) # if not valid: # LOGGER.warning('Impossible to store new version for data "{}"'.format(save_item)) if thumbnail and os.path.isfile(thumbnail): save_item.store_thumbnail(thumbnail) self.library_window().sync() save_item.update_dependencies(dependencies=dependencies) self.saved.emit() return True def _on_cancel(self): self.cancelled.emit() self.close() def _on_thumbnail_capture(self): """ Internal callback function that is called when a thumbnail capture must be done """ self.thumbnail_capture(show=False) def _on_thumbnail_captured(self, captured_path): """ Internal callback function that is called when thumbnail is captured :param captured_path: str """ thumb_path = os.path.dirname(captured_path) self.set_thumbnail_path(thumb_path) def _on_show_capture_window(self): """ Internal callback function that shows the capture window for framing """ self.thumbnail_capture(show=True) def _on_show_browse_image_dialog(self): """ Internal callback function that shows a file dialog for choosing an image from disk """ file_dialog = QFileDialog(self, caption='Open Image', filter='Image Files (*.png *.jpg)') file_dialog.fileSelected.connect(self.set_thumbnail_path) file_dialog.exec_()
class BaseLoadWidget(base.BaseWidget, object): def __init__(self, item_view, client=None, parent=None): self._item_view = item_view self._client = client self._form_widget = None self._sequence_widget = None super(BaseLoadWidget, self).__init__(parent=parent) self.setObjectName('LoadWidget') try: self.form_widget().validate() except NameError as error: LOGGER.exception(error) self.update_thumbnail_size() item = self.item() if item: self._accept_button.setVisible( bool(item.functionality().get('load', False))) self._update_version_info() # ============================================================================================================ # OVERRIDES # ============================================================================================================ def get_main_layout(self): return layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) def ui(self): super(BaseLoadWidget, self).ui() self.setWindowTitle('Load Item') title_frame = QFrame(self) title_frame_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) title_frame.setLayout(title_frame_layout) title_widget = QFrame(self) title_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) title_widget.setLayout(title_layout) title_buttons_layout = layouts.HorizontalLayout(spacing=0, margins=(0, 0, 0, 0)) title_layout.addLayout(title_buttons_layout) title_icon = label.BaseLabel(parent=self) title_button = label.BaseLabel(self.item().label(), parent=self) title_button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self._menu_button = buttons.BaseButton(parent=self) self._menu_button.setIcon(resources.icon('menu_dots')) title_buttons_layout.addWidget(title_icon) title_buttons_layout.addWidget(title_button) title_buttons_layout.addWidget(self._menu_button) title_frame_layout.addWidget(title_widget) item_icon_name = self.item().icon() or 'tpDcc' item_icon = resources.icon(item_icon_name) if not item_icon: item_icon = resources.icon('tpDcc') title_icon.setPixmap(item_icon.pixmap(QSize(20, 20))) main_frame = QFrame(self) main_frame_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) main_frame.setLayout(main_frame_layout) icon_frame = QFrame(self) icon_frame_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) icon_frame.setLayout(icon_frame_layout) icon_title_frame = QFrame(self) icon_title_frame_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) icon_frame_layout.addWidget(icon_title_frame) icon_title_frame.setLayout(icon_title_frame_layout) icon_frame2 = QFrame(self) icon_frame2_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) icon_frame2.setLayout(icon_frame2_layout) thumbnail_layout = layouts.HorizontalLayout(spacing=0, margins=(0, 0, 0, 0)) self._thumbnail_frame = QFrame(self) thumbnail_frame_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) self._thumbnail_frame.setLayout(thumbnail_frame_layout) icon_frame_layout.addWidget(icon_frame2) icon_frame2_layout.addLayout(thumbnail_layout) thumbnail_layout.addWidget(self._thumbnail_frame) form_frame = QFrame(self) form_frame_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) form_frame.setLayout(form_frame_layout) main_frame_layout.addWidget(icon_frame) main_frame_layout.addWidget(form_frame) version_frame = QFrame(self) version_frame_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) version_frame.setLayout(version_frame_layout) self._versions_widget = version.VersionHistoryWidget(parent=self) version_frame_layout.addWidget(self._versions_widget) self._custom_widget_frame = QFrame(self) custom_widget_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) self._custom_widget_frame.setLayout(custom_widget_layout) self._preview_buttons_frame = QFrame(self) preview_buttons_layout = layouts.HorizontalLayout(spacing=2, margins=(0, 0, 0, 0)) self._preview_buttons_frame.setLayout(preview_buttons_layout) self._accept_button = buttons.BaseButton('Load', parent=self) self._accept_button.setIcon(resources.icon('open')) preview_buttons_layout.addStretch() preview_buttons_layout.addWidget(self._accept_button) preview_buttons_layout.addStretch() self._export_btn = buttons.BaseButton('Export', parent=self) self._export_btn.setIcon(resources.icon('export')) self._import_btn = buttons.BaseButton('Import', parent=self) self._import_btn.setIcon(resources.icon('import')) self._reference_btn = buttons.BaseButton('Reference', parent=self) self._reference_btn.setIcon(resources.icon('reference')) for btn in [self._export_btn, self._import_btn, self._reference_btn]: btn.setToolTip(btn.text()) extra_buttons_frame = QFrame(self) extra_buttons_layout = layouts.HorizontalLayout(spacing=2, margins=(0, 0, 0, 0)) extra_buttons_frame.setLayout(extra_buttons_layout) extra_buttons_layout.addWidget(self._export_btn) extra_buttons_layout.addWidget(self._import_btn) extra_buttons_layout.addWidget(self._reference_btn) group_box = group.GroupBoxWidget('Icon', icon_frame) group_box.set_persistent(True) group_box.set_checked(True) self._version_box = group.GroupBoxWidget('Version', version_frame) self._version_box.set_persistent(True) self._version_box.set_checked(True) self._sequence_widget = sequence.ImageSequenceWidget(self) thumbnail_frame_layout.insertWidget(0, self._sequence_widget) if os.path.exists(self._item_view.image_sequence_path()): self._sequence_widget.set_path( self._item_view.image_sequence_path()) elif os.path.exists(self._item_view.thumbnail_path()): self._sequence_widget.set_path(self._item_view.thumbnail_path()) self._form_widget = formwidget.FormWidget(self) self._form_widget.set_schema(self.item().load_schema()) self._form_widget.set_validator(self.item().load_validator) form_frame_layout.addWidget(self._form_widget) self.main_layout.addWidget(title_frame) self.main_layout.addWidget(group_box) self.main_layout.addWidget(main_frame) self.main_layout.addWidget(self._version_box) self.main_layout.addWidget(version_frame) self.main_layout.addWidget(self._custom_widget_frame) self.main_layout.addStretch() self.main_layout.addWidget(dividers.Divider()) self.main_layout.addWidget(self._preview_buttons_frame) self.main_layout.addWidget(extra_buttons_frame) def setup_signals(self): self._menu_button.clicked.connect(self._on_show_menu) self._accept_button.clicked.connect(self._on_load) self._export_btn.clicked.connect(self._on_export) self._import_btn.clicked.connect(self._on_import) self._reference_btn.clicked.connect(self._on_reference) self._item_view.loadValueChanged.connect(self._on_item_value_changed) def resizeEvent(self, event): """ Overrides base QWidget resizeEvent function :param event: QResizeEvent """ self.update_thumbnail_size() def close(self): """ Overrides base QWidget close function to disable script job when its is done """ if self.form_widget(): self.form_widget().save_persistent_values() super(BaseLoadWidget, self).close() # ============================================================================================================ # BASE # ============================================================================================================ def item(self): """ Returns the library item to load :return: """ return self._item_view.item def item_view(self): """ Returns the library item view to load :return: LibraryItem """ return self._item_view def form_widget(self): """ Returns form widget instance :return: FormWidget """ return self._form_widget def set_custom_widget(self, widget): """ Sets custom widget to use when loading items :param widget: QQWidget """ self._custom_widget_frame.layout().addWidget(widget) def update_thumbnail_size(self): """ Updates the thumbnail button to teh size of the widget """ width = self.width() - 10 if width > 250: width = 250 size = QSize(width, width) self._sequence_widget.setIconSize(size) self._sequence_widget.setMaximumSize(size) self._thumbnail_frame.setMaximumSize(size) # ============================================================================================================ # INTERNAL # ============================================================================================================ def _update_version_info(self): item_view = self.item_view() if not item_view or not item_view.library_window(): return library_window = item_view.library_window() if not library_window: return repository_type = library_window.get_repository_type() repository_path = library_window.get_repository_path() if not repository_type or not repository_path: return try: repository_type = int(repository_type) except Exception: repository_type = 0 if repository_type == 0: repository_type = None elif repository_type == 1: repository_type = data_version.GitVersionControl self._versions_widget.set_version_control_class(repository_type) self._versions_widget.set_repository_path(repository_path) # If not valid version control is defined, we hide version control valid_version_control = self._versions_widget.set_directory( self.item().format_identifier()) self._versions_widget.setVisible(valid_version_control) self._version_box.setVisible(valid_version_control) # ============================================================================================================ # CALLBACKS # ============================================================================================================ def _on_show_menu(self): """ Internal callback function that is called when menu button is clicked byu the user :return: QAction """ menu = QMenu(self) self._item_view.context_edit_menu(menu) point = QCursor.pos() point.setX(point.x() + 3) point.setY(point.y() + 3) return menu.exec_(point) def _on_load(self): """ Internal callback function that is called when Load button is pressed by the user """ load_function = self.item().functionality().get('load') if not load_function: LOGGER.warning( 'Load functionality is not available for data: "{}"'.format( self.item())) return library_path = self.item().library.identifier if not library_path or not os.path.isfile(library_path): LOGGER.warning( 'Impossible to load data "{}" because its library does not exists: "{}"' .format(self.item(), library_path)) return if self._client: self._client().load_data(library_path=library_path, data_path=self.item().format_identifier()) else: load_function() def _on_export(self): """ Internal callback function that is called when export button is pressed by the user """ item = self.item() if not item: return library_window = self.item_view().library_window() if not library_window: return base_data.BaseDataItemView.show_export_widget(item.__class__, item.format_identifier(), library_window) def _on_import(self): """ Internal callback function that is called when import button is pressed by the user """ import_function = self.item().functionality().get('import_data') if not import_function: LOGGER.warning( 'Import functionality is not available for data: "{}"'.format( self.item())) return library_path = self.item().library.identifier if not library_path or not os.path.isfile(library_path): LOGGER.warning( 'Impossible to load data "{}" because its library does not exists: "{}"' .format(self.item(), library_path)) return if self._client: self._client().import_data( library_path=library_path, data_path=self.item().format_identifier()) else: import_function() def _on_reference(self): """ Internal callback function that is called when reference button is pressed by the user """ reference_function = self.item().functionality().get('reference_data') if not reference_function: LOGGER.warning( 'Reference functionality is not available for data: "{}"'. format(self.item())) return library_path = self.item().library.identifier if not library_path or not os.path.isfile(library_path): LOGGER.warning( 'Impossible to load data "{}" because its library does not exists: "{}"' .format(self.item(), library_path)) return if self._client: self._client().reference_data( library_path=library_path, data_path=self.item().format_identifier()) else: reference_function() def _on_item_value_changed(self, field, value): """ Internal callback function that is called each time an item field value changes :param field: str :param value: object """ self._form_widget.set_value(field, value)
class SaveWidget(BaseSaveWidget, object): def __init__(self, item, settings, temp_path=None, parent=None): self._script_job = None self._sequence_path = None self._icon_path = '' super(SaveWidget, self).__init__(item=item, settings=settings, temp_path=temp_path, parent=parent) self.create_sequence_widget() self.update_thumbnail_size() try: self._on_selection_changed() # self.set_script_job_enabled(True) except NameError as e: LOGGER.error('{} | {}'.format(e, traceback.format_exc())) def ui(self): super(SaveWidget, self).ui() model_panel_layout = layouts.HorizontalLayout() model_panel_layout.setContentsMargins(0, 0, 0, 0) model_panel_layout.setSpacing(0) thumbnail_layout = layouts.VerticalLayout() thumbnail_layout.setContentsMargins(0, 0, 0, 0) thumbnail_layout.setSpacing(0) self._thumbnail_frame = QFrame() self._thumbnail_frame.setMinimumSize(QSize(50, 50)) self._thumbnail_frame.setMaximumSize(QSize(150, 150)) self._thumbnail_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self._thumbnail_frame.setFrameShape(QFrame.NoFrame) self._thumbnail_frame.setFrameShadow(QFrame.Plain) self._thumbnail_frame.setLineWidth(0) self._thumbnail_frame.setLayout(thumbnail_layout) model_panel_layout.addWidget(self._thumbnail_frame) self._thumbnail_btn = QPushButton() self._thumbnail_btn.setMinimumSize(QSize(0, 0)) self._thumbnail_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self._thumbnail_btn.setMaximumSize(QSize(150, 150)) self._thumbnail_btn.setToolTip('Take snapshot') self._thumbnail_btn.setStyleSheet( 'color: rgb(40, 40, 40);border: 0px solid rgb(0, 0, 0, 150);background-color: rgb(254, 255, 230, 200);' ) self._thumbnail_btn.setIcon(resources.icon('thumbnail')) self._thumbnail_btn.setToolTip(""" Click to capture a thumbnail from the current viewport.\n CTRL + Click to show the capture window for better framing """) thumbnail_layout.addWidget(self._thumbnail_btn) self._extra_layout.addLayout(model_panel_layout) def setup_signals(self): super(SaveWidget, self).setup_signals() self._thumbnail_btn.clicked.connect(self._on_thumbnail_capture) def resizeEvent(self, event): """ Overrides base QWidget resizeEvent function :param event: QResizeEvent """ self.update_thumbnail_size() def icon_path(self): """ Returns the icon path to be used for the thumbnail :return: str """ return self._icon_path def set_icon(self, icon): """ Sets the icon for the create widget thumbnail :param icon: QIcon """ self._thumbnail_btn.setIcon(icon) self._thumbnail_btn.setIconSize(QSize(200, 200)) self._thumbnail_btn.setText('') def sequence_path(self): """ Returns the playblast path :return: str """ return self._sequence_path def set_sequence_path(self, path): """ Sets the disk location for the image sequence to be saved :param path: str """ self._sequence_path = path self._thumbnail_btn.set_dirname(os.path.dirname(path)) def create_sequence_widget(self): """ Creates a sequence widget to replace the static thumbnail widget """ sequence_widget = widgets.LibraryImageSequenceWidget(self) sequence_widget.setObjectName('thumbnailButton') sequence_widget.setStyleSheet(self._thumbnail_btn.styleSheet()) sequence_widget.setToolTip(self._thumbnail_btn.toolTip()) camera_icon = resources.get('icons', 'camera.svg') expand_icon = resources.get('icons', 'expand.svg') folder_icon = resources.get('icons', 'folder.svg') sequence_widget.addAction(camera_icon, 'Capture new image', 'Capture new image', self._on_thumbnail_capture) sequence_widget.addAction(expand_icon, 'Show Capture window', 'Show Capture window', self._on_show_capture_window) sequence_widget.addAction(folder_icon, 'Load image from disk', 'Load image from disk', self._on_show_browse_image_dialog) sequence_widget.setIcon(resources.icon('thumbnail2')) self._thumbnail_frame.layout().insertWidget(0, sequence_widget) self._thumbnail_btn.hide() self._thumbnail_btn = sequence_widget self._thumbnail_btn.clicked.connect(self._on_thumbnail_capture) def set_sequence(self, source): """ Sets the sequenced path for the thumbnail widget :param source: str """ self.set_thumbnail(source, sequence=True) def set_thumbnail(self, source, sequence=False): """ Sets the thumbnail :param source: str :param sequence: bool """ source = os.path.normpath(source) # TODO: Find a way to remove temp folder afteer saving the file # filename, extension = os.path.splitext(source) # with path_utils.temp_dir() as dir_path: # dir_path = path_utils.temp_dir() # target = os.path.join(dir_path, 'thumbnail{}'.format(extension)) # shutil.copyfile(source, target) # tpQtLib.logger.debug('Source Thumbnail: {}'.format(source)) # tpQtLib.logger.debug('Target Thumbnail: {}'.format(target)) # self._icon_path = target # self._thumbnail_btn.set_path(target) self._icon_path = source self._thumbnail_btn.set_path(source) if sequence: self.set_sequence_path(source) def update_thumbnail_size(self): """ Updates the thumbnail button to teh size of the widget """ width = self.width() - 10 if width > 250: width = 250 size = QSize(width, width) self._thumbnail_btn.setIconSize(size) self._thumbnail_btn.setMaximumSize(size) self._thumbnail_frame.setMaximumSize(size) def show_by_frame_dialog(self): """ Show the by frame dialog """ help_text = """ To help speed up the playblast you can set the "by frame" to another greather than 1. For example if the "by frame" is set to 2 it will playblast every second frame """ options = self._options_widget.values() by_frame = options.get('byFrame', 1) start_frame, end_frame = options.get('frameRange', [None, None]) duration = 1 if start_frame is not None and end_frame is not None: duration = end_frame - start_frame if duration > 100 and by_frame == 1: buttons = QDialogButtonBox.Ok | QDialogButtonBox.Cancel result = messagebox.MessageBox.question( self.library_window(), title='Tip', text=help_text, buttons=buttons, enable_dont_show_checkbox=True) if result != QDialogButtonBox.Ok: raise Exception('Cancelled by user') def show_thumbnail_capture_dialog(self): """ Asks the user if they would like to capture a thumbnail :return: int """ buttons = QDialogButtonBox.Yes | QDialogButtonBox.Ignore | QDialogButtonBox.Cancel parent = self.item().library_window() btn = messagebox.MessageBox.question( None, 'Create a thumbnail', 'Would you like to capture a thumbnail?', buttons=buttons) if btn == QDialogButtonBox.Yes: self.thumbnail_capture() return btn def thumbnail_capture(self, show=False): """ Captures a playblast and saves it to the temporal thumbnail path :param show: bool """ options = self._options_widget.values() start_frame, end_frame = options.get('frameRange', [None, None]) step = options.get('byFrame', 1) if not qtutils.is_control_modifier(): self.show_by_frame_dialog() if not self._temp_path or not os.path.isdir(self._temp_path): self._temp_path = tempfile.mkdtemp() self._temp_path = os.path.join(self._temp_path, 'thumbnail.jpg') try: snapshot.SnapshotWindow(path=self._temp_path, on_save=self._on_thumbnail_captured) # thumbnail.ThumbnailCaptureDialog.thumbnail_capture( # path=self._temp_path, # show=show, # start_frame=start_frame, # end_frame=end_frame, # step=step, # clear_cache=False, # captured=self._on_thumbnail_captured # ) except Exception as e: messagebox.MessageBox.critical(self.library_window(), 'Error while capturing thumbnail', str(e)) LOGGER.error(traceback.format_exc()) def save(self, path, icon_path, objects=None): """ Saves the item with the given objects to the given disk location path :param path: list(str) :param icon_path: str :param objects: str """ item = self.item() options = self._options_widget.values() sequence_path = self.sequence_path() if sequence_path: sequence_path = os.path.dirname(sequence_path) item.save(path=path, objects=objects, icon_path=icon_path, sequence_path=sequence_path, **options) self.close() def _on_selection_changed(self): """ Internal callback functino that is called when DCC selection changes """ if self._options_widget: self._options_widget.validate() def _on_thumbnail_capture(self): self.thumbnail_capture(show=False) def _on_thumbnail_captured(self, captured_path): """ Internal callback function that is called when thumbnail is captured :param captured_path: str """ self.set_sequence(captured_path) def _on_show_capture_window(self): """ Internal callback function that shows the capture window for framing """ self.thumbnail_capture(show=True) def _on_show_browse_image_dialog(self): """ Internal callback function that shows a file dialog for choosing an image from disk """ file_dialog = QFileDialog(self, caption='Open Image', filter='Image Files (*.png *.jpg)') file_dialog.fileSelected.connect(self.set_thumbnail) file_dialog.exec_()