diff --git a/pype/hosts/maya/lib.py b/pype/hosts/maya/lib.py index dc802b6a37d..c6e0aa955ad 100644 --- a/pype/hosts/maya/lib.py +++ b/pype/hosts/maya/lib.py @@ -2126,15 +2126,13 @@ def _get_attrs(node): return world_space_nodes -def load_capture_preset(path=None, data=None): - import capture_gui +def load_capture_preset(data=None): import capture if data: preset = data else: - path = path - preset = capture_gui.lib.load_json(path) + return {} print(preset) options = dict() @@ -2147,11 +2145,7 @@ def load_capture_preset(path=None, data=None): # GENERIC id = 'Generic' for key in preset[id]: - if key.startswith('isolate'): - pass - # options['isolate'] = preset[id][key] - else: - options[str(key)] = preset[id][key] + options[str(key)] = preset[id][key] # RESOLUTION id = 'Resolution' @@ -2161,9 +2155,9 @@ def load_capture_preset(path=None, data=None): # DISPLAY OPTIONS id = 'Display Options' disp_options = {} - for key in preset['Display Options']: + for key in preset[id]: if key.startswith('background'): - disp_options[key] = preset['Display Options'][key] + disp_options[key] = preset[id][key] else: disp_options['displayGradient'] = True @@ -2231,16 +2225,6 @@ def load_capture_preset(path=None, data=None): # use active sound track scene = capture.parse_active_scene() options['sound'] = scene['sound'] - cam_options = dict() - cam_options['overscan'] = 1.0 - cam_options['displayFieldChart'] = False - cam_options['displayFilmGate'] = False - cam_options['displayFilmOrigin'] = False - cam_options['displayFilmPivot'] = False - cam_options['displayGateMask'] = False - cam_options['displayResolution'] = False - cam_options['displaySafeAction'] = False - cam_options['displaySafeTitle'] = False # options['display_options'] = temp_options diff --git a/pype/plugins/maya/publish/extract_playblast.py b/pype/plugins/maya/publish/extract_playblast.py index 34a9b5897d3..eacf72d6c0c 100644 --- a/pype/plugins/maya/publish/extract_playblast.py +++ b/pype/plugins/maya/publish/extract_playblast.py @@ -43,13 +43,16 @@ def process(self, instance): # get cameras camera = instance.data['review_camera'] - capture_preset = instance.context.data['presets']['maya']['capture'] + capture_preset = instance.context.data.get( + 'presets', {}).get('maya', {}).get('capture') try: preset = lib.load_capture_preset(data=capture_preset) - except Exception: + except Exception as exc: + self.log.error( + 'Error loading capture presets: {}'.format(str(exc))) preset = {} - self.log.info('using viewport preset: {}'.format(preset)) + self.log.info('Using viewport preset: {}'.format(preset)) preset['camera'] = camera preset['format'] = "image" @@ -78,7 +81,7 @@ def process(self, instance): # Isolate view is requested by having objects in the set besides a # camera. - if instance.data.get("isolate"): + if preset.pop("isolate_view", False) or instance.data.get("isolate"): preset["isolate"] = instance.data["setMembers"] # Show/Hide image planes on request. @@ -96,9 +99,6 @@ def process(self, instance): # playblast and viewer preset['viewer'] = False - # Remove panel key since it's internal value to capture_gui - preset.pop("panel", None) - path = capture.capture(**preset) collected_files = os.listdir(stagingdir) diff --git a/pype/plugins/maya/publish/extract_thumbnail.py b/pype/plugins/maya/publish/extract_thumbnail.py index 33604d988e3..d1e10762f28 100644 --- a/pype/plugins/maya/publish/extract_thumbnail.py +++ b/pype/plugins/maya/publish/extract_thumbnail.py @@ -12,10 +12,10 @@ class ExtractThumbnail(pype.api.Extractor): - """Extract a Camera as Alembic. + """Extract viewport thumbnail. - The cameras gets baked to world space by default. Only when the instance's - `bakeToWorldSpace` is set to False it will include its full hierarchy. + Takes review camera and creates a thumbnail based on viewport + capture. """ @@ -28,13 +28,16 @@ def process(self, instance): camera = instance.data['review_camera'] - capture_preset = "" - capture_preset = instance.context.data['presets']['maya']['capture'] + capture_preset = instance.context.data.get( + 'presets', {}).get('maya', {}).get('capture') + try: preset = lib.load_capture_preset(data=capture_preset) - except: + except Exception as exc: + self.log.error( + 'Error loading capture presets: {}'.format(str(exc))) preset = {} - self.log.info('using viewport preset: {}'.format(capture_preset)) + self.log.info('Using viewport preset: {}'.format(preset)) # preset["off_screen"] = False @@ -75,7 +78,7 @@ def process(self, instance): # Isolate view is requested by having objects in the set besides a # camera. - if instance.data.get("isolate"): + if preset.pop("isolate_view", False) or instance.data.get("isolate"): preset["isolate"] = instance.data["setMembers"] with maintained_time(): @@ -86,9 +89,6 @@ def process(self, instance): # playblast and viewer preset['viewer'] = False - # Remove panel key since it's internal value to capture_gui - preset.pop("panel", None) - path = capture.capture(**preset) playblast = self._fix_playblast_output_path(path) diff --git a/pype/vendor/capture_gui/__init__.py b/pype/vendor/capture_gui/__init__.py deleted file mode 100644 index 6c6a8136362..00000000000 --- a/pype/vendor/capture_gui/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ -from .vendor.Qt import QtWidgets -from . import app -from . import lib - - -def main(show=True): - """Convenience method to run the Application inside Maya. - - Args: - show (bool): Whether to directly show the instantiated application. - Defaults to True. Set this to False if you want to manage the - application (like callbacks) prior to showing the interface. - - Returns: - capture_gui.app.App: The pyblish gui application instance. - - """ - # get main maya window to parent widget to - parent = lib.get_maya_main_window() - instance = parent.findChild(QtWidgets.QWidget, app.App.object_name) - if instance: - instance.close() - - # launch app - window = app.App(title="Capture GUI", parent=parent) - if show: - window.show() - - return window diff --git a/pype/vendor/capture_gui/accordion.py b/pype/vendor/capture_gui/accordion.py deleted file mode 100644 index f721837c57c..00000000000 --- a/pype/vendor/capture_gui/accordion.py +++ /dev/null @@ -1,624 +0,0 @@ -from .vendor.Qt import QtCore, QtWidgets, QtGui - - -class AccordionItem(QtWidgets.QGroupBox): - trigger = QtCore.Signal(bool) - - def __init__(self, accordion, title, widget): - QtWidgets.QGroupBox.__init__(self, parent=accordion) - - # create the layout - layout = QtWidgets.QVBoxLayout() - layout.setContentsMargins(6, 12, 6, 6) - layout.setSpacing(0) - layout.addWidget(widget) - - self._accordianWidget = accordion - self._rolloutStyle = 2 - self._dragDropMode = 0 - - self.setAcceptDrops(True) - self.setLayout(layout) - self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) - self.customContextMenuRequested.connect(self.showMenu) - - # create custom properties - self._widget = widget - self._collapsed = False - self._collapsible = True - self._clicked = False - self._customData = {} - - # set common properties - self.setTitle(title) - - def accordionWidget(self): - """ - \remarks grabs the parent item for the accordian widget - \return - """ - return self._accordianWidget - - def customData(self, key, default=None): - """ - \remarks return a custom pointer to information stored with this item - \param key - \param default default value to return if the key was not found - \return data - """ - return self._customData.get(str(key), default) - - def dragEnterEvent(self, event): - if not self._dragDropMode: - return - - source = event.source() - if source != self and source.parent() == self.parent() and isinstance( - source, AccordionItem): - event.acceptProposedAction() - - def dragDropRect(self): - return QtCore.QRect(25, 7, 10, 6) - - def dragDropMode(self): - return self._dragDropMode - - def dragMoveEvent(self, event): - if not self._dragDropMode: - return - - source = event.source() - if source != self and source.parent() == self.parent() and isinstance( - source, AccordionItem): - event.acceptProposedAction() - - def dropEvent(self, event): - widget = event.source() - layout = self.parent().layout() - layout.insertWidget(layout.indexOf(self), widget) - self._accordianWidget.emitItemsReordered() - - def expandCollapseRect(self): - return QtCore.QRect(0, 0, self.width(), 20) - - def enterEvent(self, event): - self.accordionWidget().leaveEvent(event) - event.accept() - - def leaveEvent(self, event): - self.accordionWidget().enterEvent(event) - event.accept() - - def mouseReleaseEvent(self, event): - if self._clicked and self.expandCollapseRect().contains(event.pos()): - self.toggleCollapsed() - event.accept() - else: - event.ignore() - - self._clicked = False - - def mouseMoveEvent(self, event): - event.ignore() - - def mousePressEvent(self, event): - # handle an internal move - - # start a drag event - if event.button() == QtCore.Qt.LeftButton and self.dragDropRect().contains( - event.pos()): - # create the pixmap - pixmap = QtGui.QPixmap.grabWidget(self, self.rect()) - - # create the mimedata - mimeData = QtCore.QMimeData() - mimeData.setText('ItemTitle::%s' % (self.title())) - - # create the drag - drag = QtGui.QDrag(self) - drag.setMimeData(mimeData) - drag.setPixmap(pixmap) - drag.setHotSpot(event.pos()) - - if not drag.exec_(): - self._accordianWidget.emitItemDragFailed(self) - - event.accept() - - # determine if the expand/collapse should occur - elif event.button() == QtCore.Qt.LeftButton and self.expandCollapseRect().contains( - event.pos()): - self._clicked = True - event.accept() - - else: - event.ignore() - - def isCollapsed(self): - return self._collapsed - - def isCollapsible(self): - return self._collapsible - - def __drawTriangle(self, painter, x, y): - - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255, 160), - QtCore.Qt.SolidPattern) - if not self.isCollapsed(): - tl, tr, tp = QtCore.QPoint(x + 9, y + 8), QtCore.QPoint(x + 19, - y + 8), QtCore.QPoint( - x + 14, y + 13.0) - points = [tl, tr, tp] - triangle = QtGui.QPolygon(points) - else: - tl, tr, tp = QtCore.QPoint(x + 11, y + 6), QtCore.QPoint(x + 16, - y + 11), QtCore.QPoint( - x + 11, y + 16.0) - points = [tl, tr, tp] - triangle = QtGui.QPolygon(points) - - currentBrush = painter.brush() - painter.setBrush(brush) - painter.drawPolygon(triangle) - painter.setBrush(currentBrush) - - def paintEvent(self, event): - painter = QtGui.QPainter() - painter.begin(self) - painter.setRenderHint(painter.Antialiasing) - font = painter.font() - font.setBold(True) - painter.setFont(font) - - x = self.rect().x() - y = self.rect().y() - w = self.rect().width() - 1 - h = self.rect().height() - 1 - r = 8 - - # draw a rounded style - if self._rolloutStyle == 2: - # draw the text - painter.drawText(x + 33, y + 3, w, 16, - QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop, - self.title()) - - # draw the triangle - self.__drawTriangle(painter, x, y) - - # draw the borders - pen = QtGui.QPen(self.palette().color(QtGui.QPalette.Light)) - pen.setWidthF(0.6) - painter.setPen(pen) - - painter.drawRoundedRect(x + 1, y + 1, w - 1, h - 1, r, r) - - pen.setColor(self.palette().color(QtGui.QPalette.Shadow)) - painter.setPen(pen) - - painter.drawRoundedRect(x, y, w - 1, h - 1, r, r) - - # draw a square style - if self._rolloutStyle == 3: - # draw the text - painter.drawText(x + 33, y + 3, w, 16, - QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop, - self.title()) - - self.__drawTriangle(painter, x, y) - - # draw the borders - pen = QtGui.QPen(self.palette().color(QtGui.QPalette.Light)) - pen.setWidthF(0.6) - painter.setPen(pen) - - painter.drawRect(x + 1, y + 1, w - 1, h - 1) - - pen.setColor(self.palette().color(QtGui.QPalette.Shadow)) - painter.setPen(pen) - - painter.drawRect(x, y, w - 1, h - 1) - - # draw a Maya style - if self._rolloutStyle == 4: - # draw the text - painter.drawText(x + 33, y + 3, w, 16, - QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop, - self.title()) - - painter.setRenderHint(QtGui.QPainter.Antialiasing, False) - - self.__drawTriangle(painter, x, y) - - # draw the borders - top - headerHeight = 20 - - headerRect = QtCore.QRect(x + 1, y + 1, w - 1, headerHeight) - headerRectShadow = QtCore.QRect(x - 1, y - 1, w + 1, - headerHeight + 2) - - # Highlight - pen = QtGui.QPen(self.palette().color(QtGui.QPalette.Light)) - pen.setWidthF(0.4) - painter.setPen(pen) - - painter.drawRect(headerRect) - painter.fillRect(headerRect, QtGui.QColor(255, 255, 255, 18)) - - # Shadow - pen.setColor(self.palette().color(QtGui.QPalette.Dark)) - painter.setPen(pen) - painter.drawRect(headerRectShadow) - - if not self.isCollapsed(): - # draw the lover border - pen = QtGui.QPen(self.palette().color(QtGui.QPalette.Dark)) - pen.setWidthF(0.8) - painter.setPen(pen) - - offSet = headerHeight + 3 - bodyRect = QtCore.QRect(x, y + offSet, w, h - offSet) - bodyRectShadow = QtCore.QRect(x + 1, y + offSet, w + 1, - h - offSet + 1) - painter.drawRect(bodyRect) - - pen.setColor(self.palette().color(QtGui.QPalette.Light)) - pen.setWidthF(0.4) - painter.setPen(pen) - - painter.drawRect(bodyRectShadow) - - # draw a boxed style - elif self._rolloutStyle == 1: - if self.isCollapsed(): - arect = QtCore.QRect(x + 1, y + 9, w - 1, 4) - brect = QtCore.QRect(x, y + 8, w - 1, 4) - text = '+' - else: - arect = QtCore.QRect(x + 1, y + 9, w - 1, h - 9) - brect = QtCore.QRect(x, y + 8, w - 1, h - 9) - text = '-' - - # draw the borders - pen = QtGui.QPen(self.palette().color(QtGui.QPalette.Light)) - pen.setWidthF(0.6) - painter.setPen(pen) - - painter.drawRect(arect) - - pen.setColor(self.palette().color(QtGui.QPalette.Shadow)) - painter.setPen(pen) - - painter.drawRect(brect) - - painter.setRenderHint(painter.Antialiasing, False) - painter.setBrush( - self.palette().color(QtGui.QPalette.Window).darker(120)) - painter.drawRect(x + 10, y + 1, w - 20, 16) - painter.drawText(x + 16, y + 1, - w - 32, 16, - QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter, - text) - painter.drawText(x + 10, y + 1, - w - 20, 16, - QtCore.Qt.AlignCenter, - self.title()) - - if self.dragDropMode(): - rect = self.dragDropRect() - - # draw the lines - l = rect.left() - r = rect.right() - cy = rect.center().y() - - for y in (cy - 3, cy, cy + 3): - painter.drawLine(l, y, r, y) - - painter.end() - - def setCollapsed(self, state=True): - if self.isCollapsible(): - accord = self.accordionWidget() - accord.setUpdatesEnabled(False) - - self._collapsed = state - - if state: - self.setMinimumHeight(22) - self.setMaximumHeight(22) - self.widget().setVisible(False) - else: - self.setMinimumHeight(0) - self.setMaximumHeight(1000000) - self.widget().setVisible(True) - - self._accordianWidget.emitItemCollapsed(self) - accord.setUpdatesEnabled(True) - - def setCollapsible(self, state=True): - self._collapsible = state - - def setCustomData(self, key, value): - """ - \remarks set a custom pointer to information stored on this item - \param key - \param value - """ - self._customData[str(key)] = value - - def setDragDropMode(self, mode): - self._dragDropMode = mode - - def setRolloutStyle(self, style): - self._rolloutStyle = style - - def showMenu(self): - if QtCore.QRect(0, 0, self.width(), 20).contains( - self.mapFromGlobal(QtGui.QCursor.pos())): - self._accordianWidget.emitItemMenuRequested(self) - - def rolloutStyle(self): - return self._rolloutStyle - - def toggleCollapsed(self): - # enable signaling here - collapse_state = not self.isCollapsed() - self.setCollapsed(collapse_state) - return collapse_state - - def widget(self): - return self._widget - - -class AccordionWidget(QtWidgets.QScrollArea): - """Accordion style widget. - - A collapsible accordion widget like Maya's attribute editor. - - This is a modified version bsed on Blur's Accordion Widget to - include a Maya style. - - """ - itemCollapsed = QtCore.Signal(AccordionItem) - itemMenuRequested = QtCore.Signal(AccordionItem) - itemDragFailed = QtCore.Signal(AccordionItem) - itemsReordered = QtCore.Signal() - - Boxed = 1 - Rounded = 2 - Square = 3 - Maya = 4 - - NoDragDrop = 0 - InternalMove = 1 - - def __init__(self, parent): - - QtWidgets.QScrollArea.__init__(self, parent) - - self.setFrameShape(QtWidgets.QScrollArea.NoFrame) - self.setAutoFillBackground(False) - self.setWidgetResizable(True) - self.setMouseTracking(True) - self.verticalScrollBar().setMaximumWidth(10) - - widget = QtWidgets.QWidget(self) - - # define custom properties - self._rolloutStyle = AccordionWidget.Rounded - self._dragDropMode = AccordionWidget.NoDragDrop - self._scrolling = False - self._scrollInitY = 0 - self._scrollInitVal = 0 - self._itemClass = AccordionItem - - layout = QtWidgets.QVBoxLayout() - layout.setContentsMargins(2, 2, 2, 6) - layout.setSpacing(2) - layout.addStretch(1) - - widget.setLayout(layout) - - self.setWidget(widget) - - def setSpacing(self, spaceInt): - self.widget().layout().setSpacing(spaceInt) - - def addItem(self, title, widget, collapsed=False): - self.setUpdatesEnabled(False) - item = self._itemClass(self, title, widget) - item.setRolloutStyle(self.rolloutStyle()) - item.setDragDropMode(self.dragDropMode()) - layout = self.widget().layout() - layout.insertWidget(layout.count() - 1, item) - layout.setStretchFactor(item, 0) - - if collapsed: - item.setCollapsed(collapsed) - - self.setUpdatesEnabled(True) - - return item - - def clear(self): - self.setUpdatesEnabled(False) - layout = self.widget().layout() - while layout.count() > 1: - item = layout.itemAt(0) - - # remove the item from the layout - w = item.widget() - layout.removeItem(item) - - # close the widget and delete it - w.close() - w.deleteLater() - - self.setUpdatesEnabled(True) - - def eventFilter(self, object, event): - if event.type() == QtCore.QEvent.MouseButtonPress: - self.mousePressEvent(event) - return True - - elif event.type() == QtCore.QEvent.MouseMove: - self.mouseMoveEvent(event) - return True - - elif event.type() == QtCore.QEvent.MouseButtonRelease: - self.mouseReleaseEvent(event) - return True - - return False - - def canScroll(self): - return self.verticalScrollBar().maximum() > 0 - - def count(self): - return self.widget().layout().count() - 1 - - def dragDropMode(self): - return self._dragDropMode - - def indexOf(self, widget): - """ - \remarks Searches for widget(not including child layouts). - Returns the index of widget, or -1 if widget is not found - \return - """ - layout = self.widget().layout() - for index in range(layout.count()): - if layout.itemAt(index).widget().widget() == widget: - return index - return -1 - - def isBoxedMode(self): - return self._rolloutStyle == AccordionWidget.Maya - - def itemClass(self): - return self._itemClass - - def itemAt(self, index): - layout = self.widget().layout() - if 0 <= index and index < layout.count() - 1: - return layout.itemAt(index).widget() - return None - - def emitItemCollapsed(self, item): - if not self.signalsBlocked(): - self.itemCollapsed.emit(item) - - def emitItemDragFailed(self, item): - if not self.signalsBlocked(): - self.itemDragFailed.emit(item) - - def emitItemMenuRequested(self, item): - if not self.signalsBlocked(): - self.itemMenuRequested.emit(item) - - def emitItemsReordered(self): - if not self.signalsBlocked(): - self.itemsReordered.emit() - - def enterEvent(self, event): - if self.canScroll(): - QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.OpenHandCursor) - - def leaveEvent(self, event): - if self.canScroll(): - QtWidgets.QApplication.restoreOverrideCursor() - - def mouseMoveEvent(self, event): - if self._scrolling: - sbar = self.verticalScrollBar() - smax = sbar.maximum() - - # calculate the distance moved for the moust point - dy = event.globalY() - self._scrollInitY - - # calculate the percentage that is of the scroll bar - dval = smax * (dy / float(sbar.height())) - - # calculate the new value - sbar.setValue(self._scrollInitVal - dval) - - event.accept() - - def mousePressEvent(self, event): - # handle a scroll event - if event.button() == QtCore.Qt.LeftButton and self.canScroll(): - self._scrolling = True - self._scrollInitY = event.globalY() - self._scrollInitVal = self.verticalScrollBar().value() - - QtWidgets.QApplication.setOverrideCursor( - QtCore.Qt.ClosedHandCursor) - - event.accept() - - def mouseReleaseEvent(self, event): - if self._scrolling: - QtWidgets.QApplication.restoreOverrideCursor() - - self._scrolling = False - self._scrollInitY = 0 - self._scrollInitVal = 0 - event.accept() - - def moveItemDown(self, index): - layout = self.widget().layout() - if (layout.count() - 1) > (index + 1): - widget = layout.takeAt(index).widget() - layout.insertWidget(index + 1, widget) - - def moveItemUp(self, index): - if index > 0: - layout = self.widget().layout() - widget = layout.takeAt(index).widget() - layout.insertWidget(index - 1, widget) - - def setBoxedMode(self, state): - if state: - self._rolloutStyle = AccordionWidget.Boxed - else: - self._rolloutStyle = AccordionWidget.Rounded - - def setDragDropMode(self, dragDropMode): - self._dragDropMode = dragDropMode - - for item in self.findChildren(AccordionItem): - item.setDragDropMode(self._dragDropMode) - - def setItemClass(self, itemClass): - self._itemClass = itemClass - - def setRolloutStyle(self, rolloutStyle): - self._rolloutStyle = rolloutStyle - - for item in self.findChildren(AccordionItem): - item.setRolloutStyle(self._rolloutStyle) - - def rolloutStyle(self): - return self._rolloutStyle - - def takeAt(self, index): - self.setUpdatesEnabled(False) - layout = self.widget().layout() - widget = None - if 0 <= index and index < layout.count() - 1: - item = layout.itemAt(index) - widget = item.widget() - - layout.removeItem(item) - widget.close() - self.setUpdatesEnabled(True) - return widget - - def widgetAt(self, index): - item = self.itemAt(index) - if item: - return item.widget() - return None - - pyBoxedMode = QtCore.Property('bool', isBoxedMode, setBoxedMode) diff --git a/pype/vendor/capture_gui/app.py b/pype/vendor/capture_gui/app.py deleted file mode 100644 index 1860b084ba3..00000000000 --- a/pype/vendor/capture_gui/app.py +++ /dev/null @@ -1,711 +0,0 @@ -import json -import logging -import os -import tempfile - -import capture -import maya.cmds as cmds - -from .vendor.Qt import QtCore, QtWidgets, QtGui -from . import lib -from . import plugin -from . import presets -from . import version -from . import tokens -from .accordion import AccordionWidget - -log = logging.getLogger("Capture Gui") - - -class ClickLabel(QtWidgets.QLabel): - """A QLabel that emits a clicked signal when clicked upon.""" - clicked = QtCore.Signal() - - def mouseReleaseEvent(self, event): - self.clicked.emit() - return super(ClickLabel, self).mouseReleaseEvent(event) - - -class PreviewWidget(QtWidgets.QWidget): - """The playblast image preview widget. - - Upon refresh it will retrieve the options through the function set as - `options_getter` and make a call to `capture.capture()` for a single - frame (playblasted) snapshot. The result is displayed as image. - """ - - preview_width = 320 - preview_height = 180 - - def __init__(self, options_getter, validator, parent=None): - QtWidgets.QWidget.__init__(self, parent=parent) - - # Add attributes - self.options_getter = options_getter - self.validator = validator - self.preview = ClickLabel() - self.preview.setFixedWidth(self.preview_width) - self.preview.setFixedHeight(self.preview_height) - - tip = "Click to force a refresh" - self.preview.setToolTip(tip) - self.preview.setStatusTip(tip) - - # region Build - self.layout = QtWidgets.QVBoxLayout() - self.layout.setAlignment(QtCore.Qt.AlignHCenter) - self.layout.setContentsMargins(0, 0, 0, 0) - - self.setLayout(self.layout) - self.layout.addWidget(self.preview) - # endregion Build - - # Connect widgets to functions - self.preview.clicked.connect(self.refresh) - - def refresh(self): - """Refresh the playblast preview""" - - frame = cmds.currentTime(query=True) - - # When playblasting outside of an undo queue it seems that undoing - # actually triggers a reset to frame 0. As such we sneak in the current - # time into the undo queue to enforce correct undoing. - cmds.currentTime(frame, update=True) - - # check if plugin outputs are correct - valid = self.validator() - if not valid: - return - - with lib.no_undo(): - options = self.options_getter() - tempdir = tempfile.mkdtemp() - - # override settings that are constants for the preview - options = options.copy() - options['filename'] = None - options['complete_filename'] = os.path.join(tempdir, "temp.jpg") - options['width'] = self.preview_width - options['height'] = self.preview_height - options['viewer'] = False - options['frame'] = frame - options['off_screen'] = True - options['format'] = "image" - options['compression'] = "jpg" - options['sound'] = None - - fname = capture.capture(**options) - if not fname: - log.warning("Preview failed") - return - - image = QtGui.QPixmap(fname) - self.preview.setPixmap(image) - os.remove(fname) - - def showEvent(self, event): - """Initialize when shown""" - self.refresh() - event.accept() - - -class PresetWidget(QtWidgets.QWidget): - """Preset Widget - - Allows the user to set preferences and create presets to load before - capturing. - - """ - - preset_loaded = QtCore.Signal(dict) - config_opened = QtCore.Signal() - - id = "Presets" - label = "Presets" - - def __init__(self, inputs_getter, parent=None): - QtWidgets.QWidget.__init__(self, parent=parent) - - self.inputs_getter = inputs_getter - - layout = QtWidgets.QHBoxLayout(self) - layout.setAlignment(QtCore.Qt.AlignCenter) - layout.setContentsMargins(0, 0, 0, 0) - - presets = QtWidgets.QComboBox() - presets.setFixedWidth(220) - presets.addItem("*") - - # Icons - icon_path = os.path.join(os.path.dirname(__file__), "resources") - save_icon = os.path.join(icon_path, "save.png") - load_icon = os.path.join(icon_path, "import.png") - config_icon = os.path.join(icon_path, "config.png") - - # Create buttons - save = QtWidgets.QPushButton() - save.setIcon(QtGui.QIcon(save_icon)) - save.setFixedWidth(30) - save.setToolTip("Save Preset") - save.setStatusTip("Save Preset") - - load = QtWidgets.QPushButton() - load.setIcon(QtGui.QIcon(load_icon)) - load.setFixedWidth(30) - load.setToolTip("Load Preset") - load.setStatusTip("Load Preset") - - config = QtWidgets.QPushButton() - config.setIcon(QtGui.QIcon(config_icon)) - config.setFixedWidth(30) - config.setToolTip("Preset configuration") - config.setStatusTip("Preset configuration") - - layout.addWidget(presets) - layout.addWidget(save) - layout.addWidget(load) - layout.addWidget(config) - - # Make available for all methods - self.presets = presets - self.config = config - self.load = load - self.save = save - - # Signals - self.save.clicked.connect(self.on_save_preset) - self.load.clicked.connect(self.import_preset) - self.config.clicked.connect(self.config_opened) - self.presets.currentIndexChanged.connect(self.load_active_preset) - - self._process_presets() - - def _process_presets(self): - """Adds all preset files from preset paths to the Preset widget. - - Returns: - None - - """ - for presetfile in presets.discover(): - self.add_preset(presetfile) - - def import_preset(self): - """Load preset files to override output values""" - - path = self._default_browse_path() - filters = "Text file (*.json)" - dialog = QtWidgets.QFileDialog - filename, _ = dialog.getOpenFileName(self, "Open preference file", - path, filters) - if not filename: - return - - # create new entry in combobox - self.add_preset(filename) - - # read file - return self.load_active_preset() - - def load_active_preset(self): - """Load the active preset. - - Returns: - dict: The preset inputs. - - """ - current_index = self.presets.currentIndex() - filename = self.presets.itemData(current_index) - if not filename: - return {} - - preset = lib.load_json(filename) - - # Emit preset load signal - log.debug("Emitting preset_loaded: {0}".format(filename)) - self.preset_loaded.emit(preset) - - # Ensure we preserve the index after loading the changes - # for all the plugin widgets - self.presets.blockSignals(True) - self.presets.setCurrentIndex(current_index) - self.presets.blockSignals(False) - - return preset - - def add_preset(self, filename): - """Add the filename to the preset list. - - This also sets the index to the filename. - - Returns: - None - - """ - - filename = os.path.normpath(filename) - if not os.path.exists(filename): - log.warning("Preset file does not exist: {0}".format(filename)) - return - - label = os.path.splitext(os.path.basename(filename))[0] - item_count = self.presets.count() - - paths = [self.presets.itemData(i) for i in range(item_count)] - if filename in paths: - log.info("Preset is already in the " - "presets list: {0}".format(filename)) - item_index = paths.index(filename) - else: - self.presets.addItem(label, userData=filename) - item_index = item_count - - self.presets.blockSignals(True) - self.presets.setCurrentIndex(item_index) - self.presets.blockSignals(False) - - return item_index - - def _default_browse_path(self): - """Return the current browse path for save/load preset. - - If a preset is currently loaded it will use that specific path - otherwise it will go to the last registered preset path. - - Returns: - str: Path to use as default browse location. - - """ - - current_index = self.presets.currentIndex() - path = self.presets.itemData(current_index) - - if not path: - # Fallback to last registered preset path - paths = presets.preset_paths() - if paths: - path = paths[-1] - - return path - - def save_preset(self, inputs): - """Save inputs to a file""" - - path = self._default_browse_path() - filters = "Text file (*.json)" - filename, _ = QtWidgets.QFileDialog.getSaveFileName(self, - "Save preferences", - path, - filters) - if not filename: - return - - with open(filename, "w") as f: - json.dump(inputs, f, sort_keys=True, - indent=4, separators=(',', ': ')) - - self.add_preset(filename) - - return filename - - def get_presets(self): - """Return all currently listed presets""" - configurations = [self.presets.itemText(i) for - i in range(self.presets.count())] - - return configurations - - def on_save_preset(self): - """Save the inputs of all the plugins in a preset.""" - - inputs = self.inputs_getter(as_preset=True) - self.save_preset(inputs) - - def apply_inputs(self, settings): - - path = settings.get("selected", None) - index = self.presets.findData(path) - if index == -1: - # If the last loaded preset still exists but wasn't on the - # "discovered preset paths" then add it. - if os.path.exists(path): - log.info("Adding previously selected preset explicitly: %s", - path) - self.add_preset(path) - return - else: - log.warning("Previously selected preset is not available: %s", - path) - index = 0 - - self.presets.setCurrentIndex(index) - - def get_inputs(self, as_preset=False): - - if as_preset: - # Don't save the current preset into the preset because - # that would just be recursive and make no sense - return {} - else: - current_index = self.presets.currentIndex() - selected = self.presets.itemData(current_index) - return {"selected": selected} - - -class App(QtWidgets.QWidget): - """The main application in which the widgets are placed""" - - # Signals - options_changed = QtCore.Signal(dict) - playblast_start = QtCore.Signal(dict) - playblast_finished = QtCore.Signal(dict) - viewer_start = QtCore.Signal(dict) - - # Attributes - object_name = "CaptureGUI" - application_sections = ["config", "app"] - - def __init__(self, title, parent=None): - QtWidgets.QWidget.__init__(self, parent=parent) - - # Settings - # Remove pointer for memory when closed - self.setAttribute(QtCore.Qt.WA_DeleteOnClose) - self.settingfile = self._ensure_config_exist() - self.plugins = {"app": list(), - "config": list()} - - self._config_dialog = None - self._build_configuration_dialog() - - # region Set Attributes - title_version = "{} v{}".format(title, version.version) - self.setObjectName(self.object_name) - self.setWindowTitle(title_version) - self.setMinimumWidth(380) - - # Set dialog window flags so the widget can be correctly parented - # to Maya main window - self.setWindowFlags(self.windowFlags() | QtCore.Qt.Dialog) - self.setProperty("saveWindowPref", True) - # endregion Set Attributes - - self.layout = QtWidgets.QVBoxLayout() - self.layout.setContentsMargins(0, 0, 0, 0) - self.setLayout(self.layout) - - # Add accordion widget (Maya attribute editor style) - self.widgetlibrary = AccordionWidget(self) - self.widgetlibrary.setRolloutStyle(AccordionWidget.Maya) - - # Add separate widgets - self.widgetlibrary.addItem("Preview", - PreviewWidget(self.get_outputs, - self.validate, - parent=self), - collapsed=True) - - self.presetwidget = PresetWidget(inputs_getter=self.get_inputs, - parent=self) - self.widgetlibrary.addItem("Presets", self.presetwidget) - - # add plug-in widgets - for widget in plugin.discover(): - self.add_plugin(widget) - - self.layout.addWidget(self.widgetlibrary) - - # add standard buttons - self.apply_button = QtWidgets.QPushButton("Capture") - self.layout.addWidget(self.apply_button) - - # default actions - self.apply_button.clicked.connect(self.apply) - - # signals and slots - self.presetwidget.config_opened.connect(self.show_config) - self.presetwidget.preset_loaded.connect(self.apply_inputs) - - self.apply_inputs(self._read_widget_configuration()) - - def apply(self): - """Run capture action with current settings""" - - valid = self.validate() - if not valid: - return - - options = self.get_outputs() - filename = options.get("filename", None) - - self.playblast_start.emit(options) - - # The filename can be `None` when the - # playblast will *not* be saved. - if filename is not None: - # Format the tokens in the filename - filename = tokens.format_tokens(filename, options) - - # expand environment variables - filename = os.path.expandvars(filename) - - # Make relative paths absolute to the "images" file rule by default - if not os.path.isabs(filename): - root = lib.get_project_rule("images") - filename = os.path.join(root, filename) - - # normalize (to remove double slashes and alike) - filename = os.path.normpath(filename) - - options["filename"] = filename - - # Perform capture and store returned filename with extension - options["filename"] = lib.capture_scene(options) - - self.playblast_finished.emit(options) - filename = options["filename"] # get filename after callbacks - - # Show viewer - viewer = options.get("viewer", False) - if viewer: - if filename and os.path.exists(filename): - self.viewer_start.emit(options) - lib.open_file(filename) - else: - raise RuntimeError("Can't open playblast because file " - "doesn't exist: {0}".format(filename)) - - return filename - - def apply_inputs(self, inputs): - """Apply all the settings of the widgets. - - Arguments: - inputs (dict): input values per plug-in widget - - Returns: - None - - """ - if not inputs: - return - - widgets = self._get_plugin_widgets() - widgets.append(self.presetwidget) - for widget in widgets: - widget_inputs = inputs.get(widget.id, None) - if not widget_inputs: - continue - widget.apply_inputs(widget_inputs) - - def show_config(self): - """Show the advanced configuration""" - # calculate center of main widget - geometry = self.geometry() - self._config_dialog.move(QtCore.QPoint(geometry.x()+30, - geometry.y())) - self._config_dialog.show() - - def add_plugin(self, plugin): - """Add an options widget plug-in to the UI""" - - if plugin.section not in self.application_sections: - log.warning("{}'s section is invalid: " - "{}".format(plugin.label, plugin.section)) - return - - widget = plugin(parent=self) - widget.initialize() - widget.options_changed.connect(self.on_widget_settings_changed) - self.playblast_finished.connect(widget.on_playblast_finished) - - # Add to plug-ins in its section - self.plugins[widget.section].append(widget) - - # Implement additional settings depending on section - if widget.section == "app": - if not widget.hidden: - item = self.widgetlibrary.addItem(widget.label, widget) - # connect label change behaviour - widget.label_changed.connect(item.setTitle) - - # Add the plugin in a QGroupBox to the configuration dialog - if widget.section == "config": - layout = self._config_dialog.layout() - # create group box - group_widget = QtWidgets.QGroupBox(widget.label) - group_layout = QtWidgets.QVBoxLayout(group_widget) - group_layout.addWidget(widget) - - layout.addWidget(group_widget) - - def validate(self): - """Validate whether the outputs of the widgets are good. - - Returns: - bool: Whether it's valid to capture the current settings. - - """ - - errors = list() - for widget in self._get_plugin_widgets(): - widget_errors = widget.validate() - if widget_errors: - errors.extend(widget_errors) - - if errors: - message_title = "%s Validation Error(s)" % len(errors) - message = "\n".join(errors) - QtWidgets.QMessageBox.critical(self, - message_title, - message, - QtWidgets.QMessageBox.Ok) - return False - - return True - - def get_outputs(self): - """Return settings for a capture as currently set in the Application. - - Returns: - dict: Current output settings - - """ - - # Get settings from widgets - outputs = dict() - for widget in self._get_plugin_widgets(): - widget_outputs = widget.get_outputs() - if not widget_outputs: - continue - - for key, value in widget_outputs.items(): - - # We merge dictionaries by updating them so we have - # the "mixed" values of both settings - if isinstance(value, dict) and key in outputs: - outputs[key].update(value) - else: - outputs[key] = value - - return outputs - - def get_inputs(self, as_preset=False): - """Return the inputs per plug-in widgets by `plugin.id`. - - Returns: - dict: The inputs per widget - - """ - - inputs = dict() - # Here we collect all the widgets from which we want to store the - # current inputs. This will be restored in the next session - # The preset widget is added to make sure the user starts with the - # previously selected preset configuration - config_widgets = self._get_plugin_widgets() - config_widgets.append(self.presetwidget) - for widget in config_widgets: - widget_inputs = widget.get_inputs(as_preset=as_preset) - if not isinstance(widget_inputs, dict): - log.debug("Widget inputs are not a dictionary " - "'{}': {}".format(widget.id, widget_inputs)) - return - - if not widget_inputs: - continue - - inputs[widget.id] = widget_inputs - - return inputs - - def on_widget_settings_changed(self): - """Set current preset to '*' on settings change""" - - self.options_changed.emit(self.get_outputs) - self.presetwidget.presets.setCurrentIndex(0) - - def _build_configuration_dialog(self): - """Build a configuration to store configuration widgets in""" - - dialog = QtWidgets.QDialog(self) - dialog.setWindowTitle("Capture - Preset Configuration") - QtWidgets.QVBoxLayout(dialog) - - self._config_dialog = dialog - - def _ensure_config_exist(self): - """Create the configuration file if it does not exist yet. - - Returns: - unicode: filepath of the configuration file - - """ - - userdir = os.path.expanduser("~") - capturegui_dir = os.path.join(userdir, "CaptureGUI") - capturegui_inputs = os.path.join(capturegui_dir, "capturegui.json") - if not os.path.exists(capturegui_dir): - os.makedirs(capturegui_dir) - - if not os.path.isfile(capturegui_inputs): - config = open(capturegui_inputs, "w") - config.close() - - return capturegui_inputs - - def _store_widget_configuration(self): - """Store all used widget settings in the local json file""" - - inputs = self.get_inputs(as_preset=False) - path = self.settingfile - - with open(path, "w") as f: - log.debug("Writing JSON file: {0}".format(path)) - json.dump(inputs, f, sort_keys=True, - indent=4, separators=(',', ': ')) - - def _read_widget_configuration(self): - """Read the stored widget inputs""" - - inputs = {} - path = self.settingfile - - if not os.path.isfile(path) or os.stat(path).st_size == 0: - return inputs - - with open(path, "r") as f: - log.debug("Reading JSON file: {0}".format(path)) - try: - inputs = json.load(f) - except ValueError as error: - log.error(str(error)) - - return inputs - - def _get_plugin_widgets(self): - """List all plug-in widgets. - - Returns: - list: The plug-in widgets in *all* sections - - """ - - widgets = list() - for section in self.plugins.values(): - widgets.extend(section) - - return widgets - - # override close event to ensure the input are stored - - def closeEvent(self, event): - """Store current configuration upon closing the application.""" - - self._store_widget_configuration() - for section_widgets in self.plugins.values(): - for widget in section_widgets: - widget.uninitialize() - - event.accept() diff --git a/pype/vendor/capture_gui/colorpicker.py b/pype/vendor/capture_gui/colorpicker.py deleted file mode 100644 index aa00a7386dd..00000000000 --- a/pype/vendor/capture_gui/colorpicker.py +++ /dev/null @@ -1,55 +0,0 @@ -from capture_gui.vendor.Qt import QtCore, QtWidgets, QtGui - - -class ColorPicker(QtWidgets.QPushButton): - """Custom color pick button to store and retrieve color values""" - - valueChanged = QtCore.Signal() - - def __init__(self): - QtWidgets.QPushButton.__init__(self) - - self.clicked.connect(self.show_color_dialog) - self._color = None - - self.color = [1, 1, 1] - - # region properties - @property - def color(self): - return self._color - - @color.setter - def color(self, values): - """Set the color value and update the stylesheet - - Arguments: - values (list): the color values; red, green, blue - - Returns: - None - - """ - self._color = values - self.valueChanged.emit() - - values = [int(x*255) for x in values] - self.setStyleSheet("background: rgb({},{},{})".format(*values)) - - # endregion properties - - def show_color_dialog(self): - """Display a color picker to change color. - - When a color has been chosen this updates the color of the button - and its current value - - :return: the red, green and blue values - :rtype: list - """ - current = QtGui.QColor() - current.setRgbF(*self._color) - colors = QtWidgets.QColorDialog.getColor(current) - if not colors: - return - self.color = [colors.redF(), colors.greenF(), colors.blueF()] diff --git a/pype/vendor/capture_gui/lib.py b/pype/vendor/capture_gui/lib.py deleted file mode 100644 index 823ca8f7c8d..00000000000 --- a/pype/vendor/capture_gui/lib.py +++ /dev/null @@ -1,396 +0,0 @@ -# TODO: fetch Maya main window without shiboken that also doesn't crash - -import sys -import logging -import json -import os -import glob -import subprocess -import contextlib -from collections import OrderedDict - -import datetime -import maya.cmds as cmds -import maya.mel as mel -import maya.OpenMayaUI as omui -import capture - -from .vendor.Qt import QtWidgets -try: - # PySide1 - import shiboken -except ImportError: - # PySide2 - import shiboken2 as shiboken - -log = logging.getLogger(__name__) - -# region Object types -OBJECT_TYPES = OrderedDict() -OBJECT_TYPES['NURBS Curves'] = 'nurbsCurves' -OBJECT_TYPES['NURBS Surfaces'] = 'nurbsSurfaces' -OBJECT_TYPES['NURBS CVs'] = 'controlVertices' -OBJECT_TYPES['NURBS Hulls'] = 'hulls' -OBJECT_TYPES['Polygons'] = 'polymeshes' -OBJECT_TYPES['Subdiv Surfaces'] = 'subdivSurfaces' -OBJECT_TYPES['Planes'] = 'planes' -OBJECT_TYPES['Lights'] = 'lights' -OBJECT_TYPES['Cameras'] = 'cameras' -OBJECT_TYPES['Image Planes'] = 'imagePlane' -OBJECT_TYPES['Joints'] = 'joints' -OBJECT_TYPES['IK Handles'] = 'ikHandles' -OBJECT_TYPES['Deformers'] = 'deformers' -OBJECT_TYPES['Dynamics'] = 'dynamics' -OBJECT_TYPES['Particle Instancers'] = 'particleInstancers' -OBJECT_TYPES['Fluids'] = 'fluids' -OBJECT_TYPES['Hair Systems'] = 'hairSystems' -OBJECT_TYPES['Follicles'] = 'follicles' -OBJECT_TYPES['nCloths'] = 'nCloths' -OBJECT_TYPES['nParticles'] = 'nParticles' -OBJECT_TYPES['nRigids'] = 'nRigids' -OBJECT_TYPES['Dynamic Constraints'] = 'dynamicConstraints' -OBJECT_TYPES['Locators'] = 'locators' -OBJECT_TYPES['Dimensions'] = 'dimensions' -OBJECT_TYPES['Pivots'] = 'pivots' -OBJECT_TYPES['Handles'] = 'handles' -OBJECT_TYPES['Textures Placements'] = 'textures' -OBJECT_TYPES['Strokes'] = 'strokes' -OBJECT_TYPES['Motion Trails'] = 'motionTrails' -OBJECT_TYPES['Plugin Shapes'] = 'pluginShapes' -OBJECT_TYPES['Clip Ghosts'] = 'clipGhosts' -OBJECT_TYPES['Grease Pencil'] = 'greasePencils' -OBJECT_TYPES['Manipulators'] = 'manipulators' -OBJECT_TYPES['Grid'] = 'grid' -OBJECT_TYPES['HUD'] = 'hud' -# endregion Object types - - -def get_show_object_types(): - - results = OrderedDict() - - # Add the plug-in shapes - plugin_shapes = get_plugin_shapes() - results.update(plugin_shapes) - - # We add default shapes last so plug-in shapes could - # never potentially overwrite any built-ins. - results.update(OBJECT_TYPES) - - return results - - -def get_current_scenename(): - path = cmds.file(query=True, sceneName=True) - if path: - return os.path.splitext(os.path.basename(path))[0] - return None - - -def get_current_camera(): - """Returns the currently active camera. - - Searched in the order of: - 1. Active Panel - 2. Selected Camera Shape - 3. Selected Camera Transform - - Returns: - str: name of active camera transform - - """ - - # Get camera from active modelPanel (if any) - panel = cmds.getPanel(withFocus=True) - if cmds.getPanel(typeOf=panel) == "modelPanel": - cam = cmds.modelEditor(panel, query=True, camera=True) - # In some cases above returns the shape, but most often it returns the - # transform. Still we need to make sure we return the transform. - if cam: - if cmds.nodeType(cam) == "transform": - return cam - # camera shape is a shape type - elif cmds.objectType(cam, isAType="shape"): - parent = cmds.listRelatives(cam, parent=True, fullPath=True) - if parent: - return parent[0] - - # Check if a camShape is selected (if so use that) - cam_shapes = cmds.ls(selection=True, type="camera") - if cam_shapes: - return cmds.listRelatives(cam_shapes, - parent=True, - fullPath=True)[0] - - # Check if a transform of a camShape is selected - # (return cam transform if any) - transforms = cmds.ls(selection=True, type="transform") - if transforms: - cam_shapes = cmds.listRelatives(transforms, shapes=True, type="camera") - if cam_shapes: - return cmds.listRelatives(cam_shapes, - parent=True, - fullPath=True)[0] - - -def get_active_editor(): - """Return the active editor panel to playblast with""" - # fixes `cmds.playblast` undo bug - cmds.currentTime(cmds.currentTime(query=True)) - panel = cmds.playblast(activeEditor=True) - return panel.split("|")[-1] - - -def get_current_frame(): - return cmds.currentTime(query=True) - - -def get_time_slider_range(highlighted=True, - withinHighlighted=True, - highlightedOnly=False): - """Return the time range from Maya's time slider. - - Arguments: - highlighted (bool): When True if will return a selected frame range - (if there's any selection of more than one frame!) otherwise it - will return min and max playback time. - withinHighlighted (bool): By default Maya returns the highlighted range - end as a plus one value. When this is True this will be fixed by - removing one from the last number. - - Returns: - list: List of two floats of start and end frame numbers. - - """ - if highlighted is True: - gPlaybackSlider = mel.eval("global string $gPlayBackSlider; " - "$gPlayBackSlider = $gPlayBackSlider;") - if cmds.timeControl(gPlaybackSlider, query=True, rangeVisible=True): - highlightedRange = cmds.timeControl(gPlaybackSlider, - query=True, - rangeArray=True) - if withinHighlighted: - highlightedRange[-1] -= 1 - return highlightedRange - if not highlightedOnly: - return [cmds.playbackOptions(query=True, minTime=True), - cmds.playbackOptions(query=True, maxTime=True)] - - -def get_current_renderlayer(): - return cmds.editRenderLayerGlobals(query=True, currentRenderLayer=True) - - -def get_plugin_shapes(): - """Get all currently available plugin shapes - - Returns: - dict: plugin shapes by their menu label and script name - - """ - filters = cmds.pluginDisplayFilter(query=True, listFilters=True) - labels = [cmds.pluginDisplayFilter(f, query=True, label=True) for f in - filters] - return OrderedDict(zip(labels, filters)) - - -def open_file(filepath): - """Open file using OS default settings""" - if sys.platform.startswith('darwin'): - subprocess.call(('open', filepath)) - elif os.name == 'nt': - os.startfile(filepath) - elif os.name == 'posix': - subprocess.call(('xdg-open', filepath)) - else: - raise NotImplementedError("OS not supported: {0}".format(os.name)) - - -def load_json(filepath): - """open and read json, return read values""" - with open(filepath, "r") as f: - return json.load(f) - - -def _fix_playblast_output_path(filepath): - """Workaround a bug in maya.cmds.playblast to return correct filepath. - - When the `viewer` argument is set to False and maya.cmds.playblast does not - automatically open the playblasted file the returned filepath does not have - the file's extension added correctly. - - To workaround this we just glob.glob() for any file extensions and assume - the latest modified file is the correct file and return it. - - """ - # Catch cancelled playblast - if filepath is None: - log.warning("Playblast did not result in output path. " - "Playblast is probably interrupted.") - return - - # Fix: playblast not returning correct filename (with extension) - # Lets assume the most recently modified file is the correct one. - if not os.path.exists(filepath): - directory = os.path.dirname(filepath) - filename = os.path.basename(filepath) - # check if the filepath is has frame based filename - # example : capture.####.png - parts = filename.split(".") - if len(parts) == 3: - query = os.path.join(directory, "{}.*.{}".format(parts[0], - parts[-1])) - files = glob.glob(query) - else: - files = glob.glob("{}.*".format(filepath)) - - if not files: - raise RuntimeError("Couldn't find playblast from: " - "{0}".format(filepath)) - filepath = max(files, key=os.path.getmtime) - - return filepath - - -def capture_scene(options): - """Capture using scene settings. - - Uses the view settings from "panel". - - This ensures playblast is done as quicktime H.264 100% quality. - It forces showOrnaments to be off and does not render off screen. - - Arguments: - options (dict): a collection of output options - - Returns: - str: Full path to playblast file. - - """ - - filename = options.get("filename", "%TEMP%") - log.info("Capturing to: {0}".format(filename)) - - options = options.copy() - - # Force viewer to False in call to capture because we have our own - # viewer opening call to allow a signal to trigger between playblast - # and viewer - options['viewer'] = False - - # Remove panel key since it's internal value to capture_gui - options.pop("panel", None) - - path = capture.capture(**options) - path = _fix_playblast_output_path(path) - - return path - - -def browse(path=None): - """Open a pop-up browser for the user""" - - # Acquire path from user input if none defined - if path is None: - - scene_path = cmds.file(query=True, sceneName=True) - - # use scene file name as default name - default_filename = os.path.splitext(os.path.basename(scene_path))[0] - if not default_filename: - # Scene wasn't saved yet so found no valid name for playblast. - default_filename = "playblast" - - # Default to images rule - default_root = os.path.normpath(get_project_rule("images")) - default_path = os.path.join(default_root, default_filename) - path = cmds.fileDialog2(fileMode=0, - dialogStyle=2, - startingDirectory=default_path) - - if not path: - return - - if isinstance(path, (tuple, list)): - path = path[0] - - if path.endswith(".*"): - path = path[:-2] - - # Bug-Fix/Workaround: - # Fix for playblasts that result in nesting of the - # extension (eg. '.mov.mov.mov') which happens if the format - # is defined in the filename used for saving. - extension = os.path.splitext(path)[-1] - if extension: - path = path[:-len(extension)] - - return path - - -def default_output(): - """Return filename based on current scene name. - - Returns: - str: A relative filename - - """ - - scene = get_current_scenename() or "playblast" - - # get current datetime - timestamp = datetime.datetime.today() - str_timestamp = timestamp.strftime("%Y-%m-%d_%H-%M-%S") - filename = "{}_{}".format(scene, str_timestamp) - - return filename - - -def get_project_rule(rule): - """Get the full path of the rule of the project""" - - workspace = cmds.workspace(query=True, rootDirectory=True) - folder = cmds.workspace(fileRuleEntry=rule) - if not folder: - log.warning("File Rule Entry '{}' has no value, please check if the " - "rule name is typed correctly".format(rule)) - - return os.path.join(workspace, folder) - - -def list_formats(): - # Workaround for Maya playblast bug where undo would - # move the currentTime to frame one. - cmds.currentTime(cmds.currentTime(query=True)) - return cmds.playblast(query=True, format=True) - - -def list_compressions(format='avi'): - # Workaround for Maya playblast bug where undo would - # move the currentTime to frame one. - cmds.currentTime(cmds.currentTime(query=True)) - - cmd = 'playblast -format "{0}" -query -compression'.format(format) - return mel.eval(cmd) - - -@contextlib.contextmanager -def no_undo(): - """Disable undo during the context""" - try: - cmds.undoInfo(stateWithoutFlush=False) - yield - finally: - cmds.undoInfo(stateWithoutFlush=True) - - -def get_maya_main_window(): - """Get the main Maya window as a QtGui.QMainWindow instance - - Returns: - QtGui.QMainWindow: instance of the top level Maya windows - - """ - ptr = omui.MQtUtil.mainWindow() - if ptr is not None: - return shiboken.wrapInstance(long(ptr), QtWidgets.QWidget) diff --git a/pype/vendor/capture_gui/plugin.py b/pype/vendor/capture_gui/plugin.py deleted file mode 100644 index 7d087936d70..00000000000 --- a/pype/vendor/capture_gui/plugin.py +++ /dev/null @@ -1,401 +0,0 @@ -"""Plug-in system - -Works similar to how OSs look for executables; i.e. a number of -absolute paths are searched for a given match. The predicate for -executables is whether or not an extension matches a number of -options, such as ".exe" or ".bat". - -In this system, the predicate is whether or not a fname ends with ".py" - -""" - -# Standard library -import os -import sys -import types -import logging -import inspect - -from .vendor.Qt import QtCore, QtWidgets - -log = logging.getLogger(__name__) - -_registered_paths = list() -_registered_plugins = dict() - - -class classproperty(object): - def __init__(self, getter): - self.getter = getter - - def __get__(self, instance, owner): - return self.getter(owner) - - -class Plugin(QtWidgets.QWidget): - """Base class for Option plug-in Widgets. - - This is a regular Qt widget that can be added to the capture interface - as an additional component, like a plugin. - - The plug-ins are sorted in the interface by their `order` attribute and - will be displayed in the main interface when `section` is set to "app" - and displayed in the additional settings pop-up when set to "config". - - When `hidden` is set to True the widget will not be shown in the interface. - This could be useful as a plug-in that supplies solely default values to - the capture GUI command. - - """ - - label = "" - section = "app" # "config" or "app" - hidden = False - options_changed = QtCore.Signal() - label_changed = QtCore.Signal(str) - order = 0 - highlight = "border: 1px solid red;" - validate_state = True - - def on_playblast_finished(self, options): - pass - - def validate(self): - """ - Ensure outputs of the widget are possible, when errors are raised it - will return a message with what has caused the error - :return: - """ - errors = [] - return errors - - def get_outputs(self): - """Return the options as set in this plug-in widget. - - This is used to identify the settings to be used for the playblast. - As such the values should be returned in a way that a call to - `capture.capture()` would understand as arguments. - - Args: - panel (str): The active modelPanel of the user. This is passed so - values could potentially be parsed from the active panel - - Returns: - dict: The options for this plug-in. (formatted `capture` style) - - """ - return dict() - - def get_inputs(self, as_preset): - """Return widget's child settings. - - This should provide a dictionary of input settings of the plug-in - that results in a dictionary that can be supplied to `apply_input()` - This is used to save the settings of the preset to a widget. - - :param as_preset: - :param as_presets: Toggle to mute certain input values of the widget - :type as_presets: bool - - Returns: - dict: The currently set inputs of this widget. - - """ - return dict() - - def apply_inputs(self, settings): - """Apply a dictionary of settings to the widget. - - This should update the widget's inputs to the settings provided in - the dictionary. This is used to apply settings from a preset. - - Returns: - None - - """ - pass - - def initialize(self): - """ - This method is used to register any callbacks - :return: - """ - pass - - def uninitialize(self): - """ - Unregister any callback created when deleting the widget - - A general explation: - - The deletion method is an attribute that lives inside the object to be - deleted, and that is the problem: - Destruction seems not to care about the order of destruction, - and the __dict__ that also holds the onDestroy bound method - gets destructed before it is called. - - Another solution is to use a weakref - - :return: None - """ - pass - - def __str__(self): - return self.label or type(self).__name__ - - def __repr__(self): - return u"%s.%s(%r)" % (__name__, type(self).__name__, self.__str__()) - - id = classproperty(lambda cls: cls.__name__) - - -def register_plugin_path(path): - """Plug-ins are looked up at run-time from directories registered here - - To register a new directory, run this command along with the absolute - path to where you"re plug-ins are located. - - Example: - >>> import os - >>> my_plugins = "/server/plugins" - >>> register_plugin_path(my_plugins) - '/server/plugins' - - Returns: - Actual path added, including any post-processing - - """ - - if path in _registered_paths: - return log.warning("Path already registered: {0}".format(path)) - - _registered_paths.append(path) - - return path - - -def deregister_plugin_path(path): - """Remove a _registered_paths path - - Raises: - KeyError if `path` isn't registered - - """ - - _registered_paths.remove(path) - - -def deregister_all_plugin_paths(): - """Mainly used in tests""" - _registered_paths[:] = [] - - -def registered_plugin_paths(): - """Return paths added via registration - - ..note:: This returns a copy of the registered paths - and can therefore not be modified directly. - - """ - - return list(_registered_paths) - - -def registered_plugins(): - """Return plug-ins added via :func:`register_plugin` - - .. note:: This returns a copy of the registered plug-ins - and can therefore not be modified directly - - """ - - return _registered_plugins.values() - - -def register_plugin(plugin): - """Register a new plug-in - - Arguments: - plugin (Plugin): Plug-in to register - - Raises: - TypeError if `plugin` is not callable - - """ - - if not hasattr(plugin, "__call__"): - raise TypeError("Plug-in must be callable " - "returning an instance of a class") - - if not plugin_is_valid(plugin): - raise TypeError("Plug-in invalid: %s", plugin) - - _registered_plugins[plugin.__name__] = plugin - - -def plugin_paths(): - """Collect paths from all sources. - - This function looks at the three potential sources of paths - and returns a list with all of them together. - - The sources are: - - - Registered paths using :func:`register_plugin_path` - - Returns: - list of paths in which plugins may be locat - - """ - - paths = list() - - for path in registered_plugin_paths(): - if path in paths: - continue - paths.append(path) - - return paths - - -def discover(paths=None): - """Find and return available plug-ins - - This function looks for files within paths registered via - :func:`register_plugin_path`. - - Arguments: - paths (list, optional): Paths to discover plug-ins from. - If no paths are provided, all paths are searched. - - """ - - plugins = dict() - - # Include plug-ins from registered paths - for path in paths or plugin_paths(): - path = os.path.normpath(path) - - if not os.path.isdir(path): - continue - - for fname in os.listdir(path): - if fname.startswith("_"): - continue - - abspath = os.path.join(path, fname) - - if not os.path.isfile(abspath): - continue - - mod_name, mod_ext = os.path.splitext(fname) - - if not mod_ext == ".py": - continue - - module = types.ModuleType(mod_name) - module.__file__ = abspath - - try: - execfile(abspath, module.__dict__) - - # Store reference to original module, to avoid - # garbage collection from collecting it's global - # imports, such as `import os`. - sys.modules[mod_name] = module - - except Exception as err: - log.debug("Skipped: \"%s\" (%s)", mod_name, err) - continue - - for plugin in plugins_from_module(module): - if plugin.id in plugins: - log.debug("Duplicate plug-in found: %s", plugin) - continue - - plugins[plugin.id] = plugin - - # Include plug-ins from registration. - # Directly registered plug-ins take precedence. - for name, plugin in _registered_plugins.items(): - if name in plugins: - log.debug("Duplicate plug-in found: %s", plugin) - continue - plugins[name] = plugin - - plugins = list(plugins.values()) - sort(plugins) # In-place - - return plugins - - -def plugins_from_module(module): - """Return plug-ins from module - - Arguments: - module (types.ModuleType): Imported module from which to - parse valid plug-ins. - - Returns: - List of plug-ins, or empty list if none is found. - - """ - - plugins = list() - - for name in dir(module): - if name.startswith("_"): - continue - - # It could be anything at this point - obj = getattr(module, name) - - if not inspect.isclass(obj): - continue - - if not issubclass(obj, Plugin): - continue - - if not plugin_is_valid(obj): - log.debug("Plug-in invalid: %s", obj) - continue - - plugins.append(obj) - - return plugins - - -def plugin_is_valid(plugin): - """Determine whether or not plug-in `plugin` is valid - - Arguments: - plugin (Plugin): Plug-in to assess - - """ - - if not plugin: - return False - - return True - - -def sort(plugins): - """Sort `plugins` in-place - - Their order is determined by their `order` attribute. - - Arguments: - plugins (list): Plug-ins to sort - - """ - - if not isinstance(plugins, list): - raise TypeError("plugins must be of type list") - - plugins.sort(key=lambda p: p.order) - return plugins - - -# Register default paths -default_plugins_path = os.path.join(os.path.dirname(__file__), "plugins") -register_plugin_path(default_plugins_path) diff --git a/pype/vendor/capture_gui/plugins/cameraplugin.py b/pype/vendor/capture_gui/plugins/cameraplugin.py deleted file mode 100644 index 19023306220..00000000000 --- a/pype/vendor/capture_gui/plugins/cameraplugin.py +++ /dev/null @@ -1,141 +0,0 @@ -import maya.cmds as cmds -from capture_gui.vendor.Qt import QtCore, QtWidgets - -import capture_gui.lib as lib -import capture_gui.plugin - - -class CameraPlugin(capture_gui.plugin.Plugin): - """Camera widget. - - Allows to select a camera. - - """ - id = "Camera" - section = "app" - order = 10 - - def __init__(self, parent=None): - super(CameraPlugin, self).__init__(parent=parent) - - self._layout = QtWidgets.QHBoxLayout() - self._layout.setContentsMargins(5, 0, 5, 0) - self.setLayout(self._layout) - - self.cameras = QtWidgets.QComboBox() - self.cameras.setMinimumWidth(200) - - self.get_active = QtWidgets.QPushButton("Get active") - self.get_active.setToolTip("Set camera from currently active view") - self.refresh = QtWidgets.QPushButton("Refresh") - self.refresh.setToolTip("Refresh the list of cameras") - - self._layout.addWidget(self.cameras) - self._layout.addWidget(self.get_active) - self._layout.addWidget(self.refresh) - - # Signals - self.connections() - - # Force update of the label - self.set_active_cam() - self.on_update_label() - - def connections(self): - self.get_active.clicked.connect(self.set_active_cam) - self.refresh.clicked.connect(self.on_refresh) - - self.cameras.currentIndexChanged.connect(self.on_update_label) - self.cameras.currentIndexChanged.connect(self.validate) - - def set_active_cam(self): - cam = lib.get_current_camera() - self.on_refresh(camera=cam) - - def select_camera(self, cam): - if cam: - # Ensure long name - cameras = cmds.ls(cam, long=True) - if not cameras: - return - cam = cameras[0] - - # Find the index in the list - for i in range(self.cameras.count()): - value = str(self.cameras.itemText(i)) - if value == cam: - self.cameras.setCurrentIndex(i) - return - - def validate(self): - - errors = [] - camera = self.cameras.currentText() - if not cmds.objExists(camera): - errors.append("{} : Selected camera '{}' " - "does not exist!".format(self.id, camera)) - self.cameras.setStyleSheet(self.highlight) - else: - self.cameras.setStyleSheet("") - - return errors - - def get_outputs(self): - """Return currently selected camera from combobox.""" - - idx = self.cameras.currentIndex() - camera = str(self.cameras.itemText(idx)) if idx != -1 else None - - return {"camera": camera} - - def on_refresh(self, camera=None): - """Refresh the camera list with all current cameras in scene. - - A currentIndexChanged signal is only emitted for the cameras combobox - when the camera is different at the end of the refresh. - - Args: - camera (str): When name of camera is passed it will try to select - the camera with this name after the refresh. - - Returns: - None - - """ - - cam = self.get_outputs()['camera'] - - # Get original selection - if camera is None: - index = self.cameras.currentIndex() - if index != -1: - camera = self.cameras.currentText() - - self.cameras.blockSignals(True) - - # Update the list with available cameras - self.cameras.clear() - - cam_shapes = cmds.ls(type="camera") - cam_transforms = cmds.listRelatives(cam_shapes, - parent=True, - fullPath=True) - self.cameras.addItems(cam_transforms) - - # If original selection, try to reselect - self.select_camera(camera) - - self.cameras.blockSignals(False) - - # If camera changed emit signal - if cam != self.get_outputs()['camera']: - idx = self.cameras.currentIndex() - self.cameras.currentIndexChanged.emit(idx) - - def on_update_label(self): - - cam = self.cameras.currentText() - cam = cam.rsplit("|", 1)[-1] # ensure short name - self.label = "Camera ({0})".format(cam) - - self.label_changed.emit(self.label) diff --git a/pype/vendor/capture_gui/plugins/codecplugin.py b/pype/vendor/capture_gui/plugins/codecplugin.py deleted file mode 100644 index 694194aafe3..00000000000 --- a/pype/vendor/capture_gui/plugins/codecplugin.py +++ /dev/null @@ -1,95 +0,0 @@ -from capture_gui.vendor.Qt import QtCore, QtWidgets - -import capture_gui.lib as lib -import capture_gui.plugin - - -class CodecPlugin(capture_gui.plugin.Plugin): - """Codec widget. - - Allows to set format, compression and quality. - - """ - id = "Codec" - label = "Codec" - section = "config" - order = 50 - - def __init__(self, parent=None): - super(CodecPlugin, self).__init__(parent=parent) - - self._layout = QtWidgets.QHBoxLayout() - self._layout.setContentsMargins(0, 0, 0, 0) - self.setLayout(self._layout) - - self.format = QtWidgets.QComboBox() - self.compression = QtWidgets.QComboBox() - self.quality = QtWidgets.QSpinBox() - self.quality.setMinimum(0) - self.quality.setMaximum(100) - self.quality.setValue(100) - self.quality.setToolTip("Compression quality percentage") - - self._layout.addWidget(self.format) - self._layout.addWidget(self.compression) - self._layout.addWidget(self.quality) - - self.format.currentIndexChanged.connect(self.on_format_changed) - - self.refresh() - - # Default to format 'qt' - index = self.format.findText("qt") - if index != -1: - self.format.setCurrentIndex(index) - - # Default to compression 'H.264' - index = self.compression.findText("H.264") - if index != -1: - self.compression.setCurrentIndex(index) - - self.connections() - - def connections(self): - self.compression.currentIndexChanged.connect(self.options_changed) - self.format.currentIndexChanged.connect(self.options_changed) - self.quality.valueChanged.connect(self.options_changed) - - def refresh(self): - formats = sorted(lib.list_formats()) - self.format.clear() - self.format.addItems(formats) - - def on_format_changed(self): - """Refresh the available compressions.""" - - format = self.format.currentText() - compressions = lib.list_compressions(format) - self.compression.clear() - self.compression.addItems(compressions) - - def get_outputs(self): - """Get the plugin outputs that matches `capture.capture` arguments - - Returns: - dict: Plugin outputs - - """ - - return {"format": self.format.currentText(), - "compression": self.compression.currentText(), - "quality": self.quality.value()} - - def get_inputs(self, as_preset): - # a bit redundant but it will work when iterating over widgets - # so we don't have to write an exception - return self.get_outputs() - - def apply_inputs(self, settings): - codec_format = settings.get("format", 0) - compr = settings.get("compression", 4) - quality = settings.get("quality", 100) - - self.format.setCurrentIndex(self.format.findText(codec_format)) - self.compression.setCurrentIndex(self.compression.findText(compr)) - self.quality.setValue(int(quality)) diff --git a/pype/vendor/capture_gui/plugins/defaultoptionsplugin.py b/pype/vendor/capture_gui/plugins/defaultoptionsplugin.py deleted file mode 100644 index f56897e5626..00000000000 --- a/pype/vendor/capture_gui/plugins/defaultoptionsplugin.py +++ /dev/null @@ -1,47 +0,0 @@ -import capture -import capture_gui.plugin - - -class DefaultOptionsPlugin(capture_gui.plugin.Plugin): - """Invisible Plugin that supplies some default values to the gui. - - This enures: - - no HUD is present in playblasts - - no overscan (`overscan` set to 1.0) - - no title safe, action safe, gate mask, etc. - - active sound is included in video playblasts - - """ - order = -1 - hidden = True - - def get_outputs(self): - """Get the plugin outputs that matches `capture.capture` arguments - - Returns: - dict: Plugin outputs - - """ - - outputs = dict() - - # use active sound track - scene = capture.parse_active_scene() - outputs['sound'] = scene['sound'] - - # override default settings - outputs['show_ornaments'] = True # never show HUD or overlays - - # override camera options - outputs['camera_options'] = dict() - outputs['camera_options']['overscan'] = 1.0 - outputs['camera_options']['displayFieldChart'] = False - outputs['camera_options']['displayFilmGate'] = False - outputs['camera_options']['displayFilmOrigin'] = False - outputs['camera_options']['displayFilmPivot'] = False - outputs['camera_options']['displayGateMask'] = False - outputs['camera_options']['displayResolution'] = False - outputs['camera_options']['displaySafeAction'] = False - outputs['camera_options']['displaySafeTitle'] = False - - return outputs diff --git a/pype/vendor/capture_gui/plugins/displayplugin.py b/pype/vendor/capture_gui/plugins/displayplugin.py deleted file mode 100644 index 3dffb986546..00000000000 --- a/pype/vendor/capture_gui/plugins/displayplugin.py +++ /dev/null @@ -1,179 +0,0 @@ -import maya.cmds as cmds - -from capture_gui.vendor.Qt import QtCore, QtWidgets -import capture_gui.plugin -import capture_gui.colorpicker as colorpicker - - -# region GLOBALS - -BACKGROUND_DEFAULT = [0.6309999823570251, - 0.6309999823570251, - 0.6309999823570251] - -TOP_DEFAULT = [0.5350000262260437, - 0.6169999837875366, - 0.7020000219345093] - -BOTTOM_DEFAULT = [0.052000001072883606, - 0.052000001072883606, - 0.052000001072883606] - -COLORS = {"background": BACKGROUND_DEFAULT, - "backgroundTop": TOP_DEFAULT, - "backgroundBottom": BOTTOM_DEFAULT} - -LABELS = {"background": "Background", - "backgroundTop": "Top", - "backgroundBottom": "Bottom"} -# endregion GLOBALS - - -class DisplayPlugin(capture_gui.plugin.Plugin): - """Plugin to apply viewport visibilities and settings""" - - id = "Display Options" - label = "Display Options" - section = "config" - order = 70 - - def __init__(self, parent=None): - super(DisplayPlugin, self).__init__(parent=parent) - - self._colors = dict() - - self._layout = QtWidgets.QVBoxLayout() - self._layout.setContentsMargins(0, 0, 0, 0) - self.setLayout(self._layout) - - self.override = QtWidgets.QCheckBox("Override Display Options") - - self.display_type = QtWidgets.QComboBox() - self.display_type.addItems(["Solid", "Gradient"]) - - # create color columns - self._color_layout = QtWidgets.QHBoxLayout() - for label, default in COLORS.items(): - self.add_color_picker(self._color_layout, label, default) - - # populate layout - self._layout.addWidget(self.override) - self._layout.addWidget(self.display_type) - self._layout.addLayout(self._color_layout) - - # ensure widgets are in the correct enable state - self.on_toggle_override() - - self.connections() - - def connections(self): - self.override.toggled.connect(self.on_toggle_override) - self.override.toggled.connect(self.options_changed) - self.display_type.currentIndexChanged.connect(self.options_changed) - - def add_color_picker(self, layout, label, default): - """Create a column with a label and a button to select a color - - Arguments: - layout (QtWidgets.QLayout): Layout to add color picker to - label (str): system name for the color type, e.g. : backgroundTop - default (list): The default color values to start with - - Returns: - colorpicker.ColorPicker: a color picker instance - - """ - - column = QtWidgets.QVBoxLayout() - label_widget = QtWidgets.QLabel(LABELS[label]) - - color_picker = colorpicker.ColorPicker() - color_picker.color = default - - column.addWidget(label_widget) - column.addWidget(color_picker) - - column.setAlignment(label_widget, QtCore.Qt.AlignCenter) - - layout.addLayout(column) - - # connect signal - color_picker.valueChanged.connect(self.options_changed) - - # store widget - self._colors[label] = color_picker - - return color_picker - - def on_toggle_override(self): - """Callback when override is toggled. - - Enable or disable the color pickers and background type widgets bases - on the current state of the override checkbox - - Returns: - None - - """ - state = self.override.isChecked() - self.display_type.setEnabled(state) - for widget in self._colors.values(): - widget.setEnabled(state) - - def display_gradient(self): - """Return whether the background should be displayed as gradient. - - When True the colors will use the top and bottom color to define the - gradient otherwise the background color will be used as solid color. - - Returns: - bool: Whether background is gradient - - """ - return self.display_type.currentText() == "Gradient" - - def apply_inputs(self, settings): - """Apply the saved inputs from the inputs configuration - - Arguments: - settings (dict): The input settings to apply. - - """ - - for label, widget in self._colors.items(): - default = COLORS.get(label, [0, 0, 0]) # fallback default to black - value = settings.get(label, default) - widget.color = value - - override = settings.get("override_display", False) - self.override.setChecked(override) - - def get_inputs(self, as_preset): - inputs = {"override_display": self.override.isChecked()} - for label, widget in self._colors.items(): - inputs[label] = widget.color - - return inputs - - def get_outputs(self): - """Get the plugin outputs that matches `capture.capture` arguments - - Returns: - dict: Plugin outputs - - """ - - outputs = {} - if self.override.isChecked(): - outputs["displayGradient"] = self.display_gradient() - for label, widget in self._colors.items(): - outputs[label] = widget.color - else: - # Parse active color settings - outputs["displayGradient"] = cmds.displayPref(query=True, - displayGradient=True) - for key in COLORS.keys(): - color = cmds.displayRGBColor(key, query=True) - outputs[key] = color - - return {"display_options": outputs} diff --git a/pype/vendor/capture_gui/plugins/genericplugin.py b/pype/vendor/capture_gui/plugins/genericplugin.py deleted file mode 100644 index a43d43f3cc0..00000000000 --- a/pype/vendor/capture_gui/plugins/genericplugin.py +++ /dev/null @@ -1,95 +0,0 @@ -import maya.cmds as mc -from capture_gui.vendor.Qt import QtCore, QtWidgets - -import capture_gui.plugin -import capture_gui.lib - - -class GenericPlugin(capture_gui.plugin.Plugin): - """Widget for generic options""" - id = "Generic" - label = "Generic" - section = "config" - order = 100 - - def __init__(self, parent=None): - super(GenericPlugin, self).__init__(parent=parent) - - layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - self.setLayout(layout) - - isolate_view = QtWidgets.QCheckBox( - "Use isolate view from active panel") - off_screen = QtWidgets.QCheckBox("Render offscreen") - - layout.addWidget(isolate_view) - layout.addWidget(off_screen) - - isolate_view.stateChanged.connect(self.options_changed) - off_screen.stateChanged.connect(self.options_changed) - - self.widgets = { - "off_screen": off_screen, - "isolate_view": isolate_view - } - - self.apply_inputs(self.get_defaults()) - - def get_defaults(self): - return { - "off_screen": True, - "isolate_view": False - } - - def get_inputs(self, as_preset): - """Return the widget options - - Returns: - dict: The input settings of the widgets. - - """ - - inputs = dict() - for key, widget in self.widgets.items(): - state = widget.isChecked() - inputs[key] = state - - return inputs - - def apply_inputs(self, inputs): - """Apply the saved inputs from the inputs configuration - - Arguments: - inputs (dict): The input settings to apply. - - """ - - for key, widget in self.widgets.items(): - state = inputs.get(key, None) - if state is not None: - widget.setChecked(state) - - return inputs - - def get_outputs(self): - """Returns all the options from the widget - - Returns: dictionary with the settings - - """ - - inputs = self.get_inputs(as_preset=False) - outputs = dict() - outputs['off_screen'] = inputs['off_screen'] - - import capture_gui.lib - - # Get isolate view members of the active panel - if inputs['isolate_view']: - panel = capture_gui.lib.get_active_editor() - filter_set = mc.modelEditor(panel, query=True, viewObjects=True) - isolate = mc.sets(filter_set, query=True) if filter_set else None - outputs['isolate'] = isolate - - return outputs diff --git a/pype/vendor/capture_gui/plugins/ioplugin.py b/pype/vendor/capture_gui/plugins/ioplugin.py deleted file mode 100644 index defdc190df8..00000000000 --- a/pype/vendor/capture_gui/plugins/ioplugin.py +++ /dev/null @@ -1,254 +0,0 @@ -import os -import logging -from functools import partial - -from capture_gui.vendor.Qt import QtCore, QtWidgets -from capture_gui import plugin, lib -from capture_gui import tokens - -log = logging.getLogger("IO") - - -class IoAction(QtWidgets.QAction): - - def __init__(self, parent, filepath): - super(IoAction, self).__init__(parent) - - action_label = os.path.basename(filepath) - - self.setText(action_label) - self.setData(filepath) - - # check if file exists and disable when false - self.setEnabled(os.path.isfile(filepath)) - - # get icon from file - info = QtCore.QFileInfo(filepath) - icon_provider = QtWidgets.QFileIconProvider() - self.setIcon(icon_provider.icon(info)) - - self.triggered.connect(self.open_object_data) - - def open_object_data(self): - lib.open_file(self.data()) - - -class IoPlugin(plugin.Plugin): - """Codec widget. - - Allows to set format, compression and quality. - - """ - id = "IO" - label = "Save" - section = "app" - order = 40 - max_recent_playblasts = 5 - - def __init__(self, parent=None): - super(IoPlugin, self).__init__(parent=parent) - - self.recent_playblasts = list() - - self._layout = QtWidgets.QVBoxLayout() - self._layout.setContentsMargins(0, 0, 0, 0) - self.setLayout(self._layout) - - # region Checkboxes - self.save_file = QtWidgets.QCheckBox(text="Save") - self.open_viewer = QtWidgets.QCheckBox(text="View when finished") - self.raw_frame_numbers = QtWidgets.QCheckBox(text="Raw frame numbers") - - checkbox_hlayout = QtWidgets.QHBoxLayout() - checkbox_hlayout.setContentsMargins(5, 0, 5, 0) - checkbox_hlayout.addWidget(self.save_file) - checkbox_hlayout.addWidget(self.open_viewer) - checkbox_hlayout.addWidget(self.raw_frame_numbers) - checkbox_hlayout.addStretch(True) - # endregion Checkboxes - - # region Path - self.path_widget = QtWidgets.QWidget() - - self.browse = QtWidgets.QPushButton("Browse") - self.file_path = QtWidgets.QLineEdit() - self.file_path.setPlaceholderText("(not set; using scene name)") - tip = "Right click in the text field to insert tokens" - self.file_path.setToolTip(tip) - self.file_path.setStatusTip(tip) - self.file_path.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) - self.file_path.customContextMenuRequested.connect(self.show_token_menu) - - path_hlayout = QtWidgets.QHBoxLayout() - path_hlayout.setContentsMargins(0, 0, 0, 0) - path_label = QtWidgets.QLabel("Path:") - path_label.setFixedWidth(30) - - path_hlayout.addWidget(path_label) - path_hlayout.addWidget(self.file_path) - path_hlayout.addWidget(self.browse) - self.path_widget.setLayout(path_hlayout) - # endregion Path - - # region Recent Playblast - self.play_recent = QtWidgets.QPushButton("Play recent playblast") - self.recent_menu = QtWidgets.QMenu() - self.play_recent.setMenu(self.recent_menu) - # endregion Recent Playblast - - self._layout.addLayout(checkbox_hlayout) - self._layout.addWidget(self.path_widget) - self._layout.addWidget(self.play_recent) - - # Signals / connections - self.browse.clicked.connect(self.show_browse_dialog) - self.file_path.textChanged.connect(self.options_changed) - self.save_file.stateChanged.connect(self.options_changed) - self.raw_frame_numbers.stateChanged.connect(self.options_changed) - self.save_file.stateChanged.connect(self.on_save_changed) - - # Ensure state is up-to-date with current settings - self.on_save_changed() - - def on_save_changed(self): - """Update the visibility of the path field""" - - state = self.save_file.isChecked() - if state: - self.path_widget.show() - else: - self.path_widget.hide() - - def show_browse_dialog(self): - """Set the filepath using a browser dialog. - - :return: None - """ - - path = lib.browse() - if not path: - return - - # Maya's browser return Linux based file paths to ensure Windows is - # supported we use normpath - path = os.path.normpath(path) - - self.file_path.setText(path) - - def add_playblast(self, item): - """ - Add an item to the previous playblast menu - - :param item: full path to a playblast file - :type item: str - - :return: None - """ - - # If item already in the recent playblasts remove it so we are - # sure to add it as the new first most-recent - try: - self.recent_playblasts.remove(item) - except ValueError: - pass - - # Add as first in the recent playblasts - self.recent_playblasts.insert(0, item) - - # Ensure the playblast list is never longer than maximum amount - # by removing the older entries that are at the end of the list - if len(self.recent_playblasts) > self.max_recent_playblasts: - del self.recent_playblasts[self.max_recent_playblasts:] - - # Rebuild the actions menu - self.recent_menu.clear() - for playblast in self.recent_playblasts: - action = IoAction(parent=self, filepath=playblast) - self.recent_menu.addAction(action) - - def on_playblast_finished(self, options): - """Take action after the play blast is done""" - playblast_file = options['filename'] - if not playblast_file: - return - self.add_playblast(playblast_file) - - def get_outputs(self): - """Get the plugin outputs that matches `capture.capture` arguments - - Returns: - dict: Plugin outputs - - """ - - output = {"filename": None, - "raw_frame_numbers": self.raw_frame_numbers.isChecked(), - "viewer": self.open_viewer.isChecked()} - - save = self.save_file.isChecked() - if not save: - return output - - # get path, if nothing is set fall back to default - # project/images/playblast - path = self.file_path.text() - if not path: - path = lib.default_output() - - output["filename"] = path - - return output - - def get_inputs(self, as_preset): - inputs = {"name": self.file_path.text(), - "save_file": self.save_file.isChecked(), - "open_finished": self.open_viewer.isChecked(), - "recent_playblasts": self.recent_playblasts, - "raw_frame_numbers": self.raw_frame_numbers.isChecked()} - - if as_preset: - inputs["recent_playblasts"] = [] - - return inputs - - def apply_inputs(self, settings): - - directory = settings.get("name", None) - save_file = settings.get("save_file", True) - open_finished = settings.get("open_finished", True) - raw_frame_numbers = settings.get("raw_frame_numbers", False) - previous_playblasts = settings.get("recent_playblasts", []) - - self.save_file.setChecked(save_file) - self.open_viewer.setChecked(open_finished) - self.raw_frame_numbers.setChecked(raw_frame_numbers) - - for playblast in reversed(previous_playblasts): - self.add_playblast(playblast) - - self.file_path.setText(directory) - - def token_menu(self): - """ - Build the token menu based on the registered tokens - - :returns: Menu - :rtype: QtWidgets.QMenu - """ - menu = QtWidgets.QMenu(self) - registered_tokens = tokens.list_tokens() - - for token, value in registered_tokens.items(): - label = "{} \t{}".format(token, value['label']) - action = QtWidgets.QAction(label, menu) - fn = partial(self.file_path.insert, token) - action.triggered.connect(fn) - menu.addAction(action) - - return menu - - def show_token_menu(self, pos): - """Show custom manu on position of widget""" - menu = self.token_menu() - globalpos = QtCore.QPoint(self.file_path.mapToGlobal(pos)) - menu.exec_(globalpos) diff --git a/pype/vendor/capture_gui/plugins/panzoomplugin.py b/pype/vendor/capture_gui/plugins/panzoomplugin.py deleted file mode 100644 index 5bf818ff2d1..00000000000 --- a/pype/vendor/capture_gui/plugins/panzoomplugin.py +++ /dev/null @@ -1,48 +0,0 @@ -from capture_gui.vendor.Qt import QtCore, QtWidgets -import capture_gui.plugin - - -class PanZoomPlugin(capture_gui.plugin.Plugin): - """Pan/Zoom widget. - - Allows to toggle whether you want to playblast with the camera's pan/zoom - state or disable it during the playblast. When "Use pan/zoom from camera" - is *not* checked it will force disable pan/zoom. - - """ - id = "PanZoom" - label = "Pan/Zoom" - section = "config" - order = 110 - - def __init__(self, parent=None): - super(PanZoomPlugin, self).__init__(parent=parent) - - self._layout = QtWidgets.QHBoxLayout() - self._layout.setContentsMargins(5, 0, 5, 0) - self.setLayout(self._layout) - - self.pan_zoom = QtWidgets.QCheckBox("Use pan/zoom from camera") - self.pan_zoom.setChecked(True) - - self._layout.addWidget(self.pan_zoom) - - self.pan_zoom.stateChanged.connect(self.options_changed) - - def get_outputs(self): - - if not self.pan_zoom.isChecked(): - return {"camera_options": { - "panZoomEnabled": 1, - "horizontalPan": 0.0, - "verticalPan": 0.0, - "zoom": 1.0} - } - else: - return {} - - def apply_inputs(self, settings): - self.pan_zoom.setChecked(settings.get("pan_zoom", True)) - - def get_inputs(self, as_preset): - return {"pan_zoom": self.pan_zoom.isChecked()} diff --git a/pype/vendor/capture_gui/plugins/rendererplugin.py b/pype/vendor/capture_gui/plugins/rendererplugin.py deleted file mode 100644 index 17932d69d92..00000000000 --- a/pype/vendor/capture_gui/plugins/rendererplugin.py +++ /dev/null @@ -1,104 +0,0 @@ -import maya.cmds as cmds - -from capture_gui.vendor.Qt import QtCore, QtWidgets -import capture_gui.lib as lib -import capture_gui.plugin - - -class RendererPlugin(capture_gui.plugin.Plugin): - """Renderer plugin to control the used playblast renderer for viewport""" - - id = "Renderer" - label = "Renderer" - section = "config" - order = 60 - - def __init__(self, parent=None): - super(RendererPlugin, self).__init__(parent=parent) - - layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - self.setLayout(layout) - - # Get active renderers for viewport - self._renderers = self.get_renderers() - - # Create list of renderers - self.renderers = QtWidgets.QComboBox() - self.renderers.addItems(self._renderers.keys()) - - layout.addWidget(self.renderers) - - self.apply_inputs(self.get_defaults()) - - # Signals - self.renderers.currentIndexChanged.connect(self.options_changed) - - def get_current_renderer(self): - """Get current renderer by internal name (non-UI) - - Returns: - str: Name of renderer. - - """ - renderer_ui = self.renderers.currentText() - renderer = self._renderers.get(renderer_ui, None) - if renderer is None: - raise RuntimeError("No valid renderer: {0}".format(renderer_ui)) - - return renderer - - def get_renderers(self): - """Collect all available renderers for playblast""" - active_editor = lib.get_active_editor() - renderers_ui = cmds.modelEditor(active_editor, - query=True, - rendererListUI=True) - renderers_id = cmds.modelEditor(active_editor, - query=True, - rendererList=True) - - renderers = dict(zip(renderers_ui, renderers_id)) - renderers.pop("Stub Renderer") - - return renderers - - def get_defaults(self): - return {"rendererName": "vp2Renderer"} - - def get_inputs(self, as_preset): - return {"rendererName": self.get_current_renderer()} - - def get_outputs(self): - """Get the plugin outputs that matches `capture.capture` arguments - - Returns: - dict: Plugin outputs - - """ - return { - "viewport_options": { - "rendererName": self.get_current_renderer() - } - } - - def apply_inputs(self, inputs): - """Apply previous settings or settings from a preset - - Args: - inputs (dict): Plugin input settings - - Returns: - None - - """ - - reverse_lookup = {value: key for key, value in self._renderers.items()} - renderer = inputs.get("rendererName", "vp2Renderer") - renderer_ui = reverse_lookup.get(renderer) - - if renderer_ui: - index = self.renderers.findText(renderer_ui) - self.renderers.setCurrentIndex(index) - else: - self.renderers.setCurrentIndex(1) diff --git a/pype/vendor/capture_gui/plugins/resolutionplugin.py b/pype/vendor/capture_gui/plugins/resolutionplugin.py deleted file mode 100644 index 193a95b8ba0..00000000000 --- a/pype/vendor/capture_gui/plugins/resolutionplugin.py +++ /dev/null @@ -1,199 +0,0 @@ -import math -from functools import partial - -import maya.cmds as cmds -from capture_gui.vendor.Qt import QtCore, QtWidgets - -import capture_gui.lib as lib -import capture_gui.plugin - - -class ResolutionPlugin(capture_gui.plugin.Plugin): - """Resolution widget. - - Allows to set scale based on set of options. - - """ - id = "Resolution" - section = "app" - order = 20 - - resolution_changed = QtCore.Signal() - - ScaleWindow = "From Window" - ScaleRenderSettings = "From Render Settings" - ScaleCustom = "Custom" - - def __init__(self, parent=None): - super(ResolutionPlugin, self).__init__(parent=parent) - - self._layout = QtWidgets.QVBoxLayout() - self._layout.setContentsMargins(0, 0, 0, 0) - self.setLayout(self._layout) - - # Scale - self.mode = QtWidgets.QComboBox() - self.mode.addItems([self.ScaleWindow, - self.ScaleRenderSettings, - self.ScaleCustom]) - self.mode.setCurrentIndex(1) # Default: From render settings - - # Custom width/height - self.resolution = QtWidgets.QWidget() - self.resolution.setContentsMargins(0, 0, 0, 0) - resolution_layout = QtWidgets.QHBoxLayout() - resolution_layout.setContentsMargins(0, 0, 0, 0) - resolution_layout.setSpacing(6) - - self.resolution.setLayout(resolution_layout) - width_label = QtWidgets.QLabel("Width") - width_label.setFixedWidth(40) - self.width = QtWidgets.QSpinBox() - self.width.setMinimum(0) - self.width.setMaximum(99999) - self.width.setValue(1920) - heigth_label = QtWidgets.QLabel("Height") - heigth_label.setFixedWidth(40) - self.height = QtWidgets.QSpinBox() - self.height.setMinimum(0) - self.height.setMaximum(99999) - self.height.setValue(1080) - - resolution_layout.addWidget(width_label) - resolution_layout.addWidget(self.width) - resolution_layout.addWidget(heigth_label) - resolution_layout.addWidget(self.height) - - self.scale_result = QtWidgets.QLineEdit() - self.scale_result.setReadOnly(True) - - # Percentage - self.percent_label = QtWidgets.QLabel("Scale") - self.percent = QtWidgets.QDoubleSpinBox() - self.percent.setMinimum(0.01) - self.percent.setValue(1.0) # default value - self.percent.setSingleStep(0.05) - - self.percent_presets = QtWidgets.QHBoxLayout() - self.percent_presets.setSpacing(4) - for value in [0.25, 0.5, 0.75, 1.0, 2.0]: - btn = QtWidgets.QPushButton(str(value)) - self.percent_presets.addWidget(btn) - btn.setFixedWidth(35) - btn.clicked.connect(partial(self.percent.setValue, value)) - - self.percent_layout = QtWidgets.QHBoxLayout() - self.percent_layout.addWidget(self.percent_label) - self.percent_layout.addWidget(self.percent) - self.percent_layout.addLayout(self.percent_presets) - - # Resulting scale display - self._layout.addWidget(self.mode) - self._layout.addWidget(self.resolution) - self._layout.addLayout(self.percent_layout) - self._layout.addWidget(self.scale_result) - - # refresh states - self.on_mode_changed() - self.on_resolution_changed() - - # connect signals - self.mode.currentIndexChanged.connect(self.on_mode_changed) - self.mode.currentIndexChanged.connect(self.on_resolution_changed) - self.percent.valueChanged.connect(self.on_resolution_changed) - self.width.valueChanged.connect(self.on_resolution_changed) - self.height.valueChanged.connect(self.on_resolution_changed) - - # Connect options changed - self.mode.currentIndexChanged.connect(self.options_changed) - self.percent.valueChanged.connect(self.options_changed) - self.width.valueChanged.connect(self.options_changed) - self.height.valueChanged.connect(self.options_changed) - - def on_mode_changed(self): - """Update the width/height enabled state when mode changes""" - - if self.mode.currentText() != self.ScaleCustom: - self.width.setEnabled(False) - self.height.setEnabled(False) - self.resolution.hide() - else: - self.width.setEnabled(True) - self.height.setEnabled(True) - self.resolution.show() - - def _get_output_resolution(self): - - options = self.get_outputs() - return int(options["width"]), int(options["height"]) - - def on_resolution_changed(self): - """Update the resulting resolution label""" - - width, height = self._get_output_resolution() - label = "Result: {0}x{1}".format(width, height) - - self.scale_result.setText(label) - - # Update label - self.label = "Resolution ({0}x{1})".format(width, height) - self.label_changed.emit(self.label) - - def get_outputs(self): - """Return width x height defined by the combination of settings - - Returns: - dict: width and height key values - - """ - mode = self.mode.currentText() - panel = lib.get_active_editor() - - if mode == self.ScaleCustom: - width = self.width.value() - height = self.height.value() - - elif mode == self.ScaleRenderSettings: - # width height from render resolution - width = cmds.getAttr("defaultResolution.width") - height = cmds.getAttr("defaultResolution.height") - - elif mode == self.ScaleWindow: - # width height from active view panel size - if not panel: - # No panel would be passed when updating in the UI as such - # the resulting resolution can't be previewed. But this should - # never happen when starting the capture. - width = 0 - height = 0 - else: - width = cmds.control(panel, query=True, width=True) - height = cmds.control(panel, query=True, height=True) - else: - raise NotImplementedError("Unsupported scale mode: " - "{0}".format(mode)) - - scale = [width, height] - percentage = self.percent.value() - scale = [math.floor(x * percentage) for x in scale] - - return {"width": scale[0], "height": scale[1]} - - def get_inputs(self, as_preset): - return {"mode": self.mode.currentText(), - "width": self.width.value(), - "height": self.height.value(), - "percent": self.percent.value()} - - def apply_inputs(self, settings): - # get value else fall back to default values - mode = settings.get("mode", self.ScaleRenderSettings) - width = int(settings.get("width", 1920)) - height = int(settings.get("height", 1080)) - percent = float(settings.get("percent", 1.0)) - - # set values - self.mode.setCurrentIndex(self.mode.findText(mode)) - self.width.setValue(width) - self.height.setValue(height) - self.percent.setValue(percent) diff --git a/pype/vendor/capture_gui/plugins/timeplugin.py b/pype/vendor/capture_gui/plugins/timeplugin.py deleted file mode 100644 index b4901f9cb41..00000000000 --- a/pype/vendor/capture_gui/plugins/timeplugin.py +++ /dev/null @@ -1,292 +0,0 @@ -import sys -import logging -import re - -import maya.OpenMaya as om -from capture_gui.vendor.Qt import QtCore, QtWidgets - -import capture_gui.lib -import capture_gui.plugin - -log = logging.getLogger("Time Range") - - -def parse_frames(string): - """Parse the resulting frames list from a frame list string. - - Examples - >>> parse_frames("0-3;30") - [0, 1, 2, 3, 30] - >>> parse_frames("0,2,4,-10") - [0, 2, 4, -10] - >>> parse_frames("-10--5,-2") - [-10, -9, -8, -7, -6, -5, -2] - - Args: - string (str): The string to parse for frames. - - Returns: - list: A list of frames - - """ - - result = list() - if not string.strip(): - raise ValueError("Can't parse an empty frame string.") - - if not re.match("^[-0-9,; ]*$", string): - raise ValueError("Invalid symbols in frame string: {}".format(string)) - - for raw in re.split(";|,", string): - - # Skip empty elements - value = raw.strip().replace(" ", "") - if not value: - continue - - # Check for sequences (1-20) including negatives (-10--8) - sequence = re.search("(-?[0-9]+)-(-?[0-9]+)", value) - - # Sequence - if sequence: - start, end = sequence.groups() - frames = range(int(start), int(end) + 1) - result.extend(frames) - - # Single frame - else: - try: - frame = int(value) - except ValueError: - raise ValueError("Invalid frame description: " - "'{0}'".format(value)) - - result.append(frame) - - if not result: - # This happens when only spaces are entered with a separator like `,` or `;` - raise ValueError("Unable to parse any frames from string: {}".format(string)) - - return result - - -class TimePlugin(capture_gui.plugin.Plugin): - """Widget for time based options""" - - id = "Time Range" - section = "app" - order = 30 - - RangeTimeSlider = "Time Slider" - RangeStartEnd = "Start/End" - CurrentFrame = "Current Frame" - CustomFrames = "Custom Frames" - - def __init__(self, parent=None): - super(TimePlugin, self).__init__(parent=parent) - - self._event_callbacks = list() - - self._layout = QtWidgets.QHBoxLayout() - self._layout.setContentsMargins(5, 0, 5, 0) - self.setLayout(self._layout) - - self.mode = QtWidgets.QComboBox() - self.mode.addItems([self.RangeTimeSlider, - self.RangeStartEnd, - self.CurrentFrame, - self.CustomFrames]) - - frame_input_height = 20 - self.start = QtWidgets.QSpinBox() - self.start.setRange(-sys.maxint, sys.maxint) - self.start.setFixedHeight(frame_input_height) - self.end = QtWidgets.QSpinBox() - self.end.setRange(-sys.maxint, sys.maxint) - self.end.setFixedHeight(frame_input_height) - - # unique frames field - self.custom_frames = QtWidgets.QLineEdit() - self.custom_frames.setFixedHeight(frame_input_height) - self.custom_frames.setPlaceholderText("Example: 1-20,25;50;75,100-150") - self.custom_frames.setVisible(False) - - self._layout.addWidget(self.mode) - self._layout.addWidget(self.start) - self._layout.addWidget(self.end) - self._layout.addWidget(self.custom_frames) - - # Connect callbacks to ensure start is never higher then end - # and the end is never lower than start - self.end.valueChanged.connect(self._ensure_start) - self.start.valueChanged.connect(self._ensure_end) - - self.on_mode_changed() # force enabled state refresh - - self.mode.currentIndexChanged.connect(self.on_mode_changed) - self.start.valueChanged.connect(self.on_mode_changed) - self.end.valueChanged.connect(self.on_mode_changed) - self.custom_frames.textChanged.connect(self.on_mode_changed) - - def _ensure_start(self, value): - self.start.setValue(min(self.start.value(), value)) - - def _ensure_end(self, value): - self.end.setValue(max(self.end.value(), value)) - - def on_mode_changed(self, emit=True): - """Update the GUI when the user updated the time range or settings. - - Arguments: - emit (bool): Whether to emit the options changed signal - - Returns: - None - - """ - - mode = self.mode.currentText() - if mode == self.RangeTimeSlider: - start, end = capture_gui.lib.get_time_slider_range() - self.start.setEnabled(False) - self.end.setEnabled(False) - self.start.setVisible(True) - self.end.setVisible(True) - self.custom_frames.setVisible(False) - mode_values = int(start), int(end) - elif mode == self.RangeStartEnd: - self.start.setEnabled(True) - self.end.setEnabled(True) - self.start.setVisible(True) - self.end.setVisible(True) - self.custom_frames.setVisible(False) - mode_values = self.start.value(), self.end.value() - elif mode == self.CustomFrames: - self.start.setVisible(False) - self.end.setVisible(False) - self.custom_frames.setVisible(True) - mode_values = "({})".format(self.custom_frames.text()) - - # ensure validation state for custom frames - self.validate() - - else: - self.start.setEnabled(False) - self.end.setEnabled(False) - self.start.setVisible(True) - self.end.setVisible(True) - self.custom_frames.setVisible(False) - currentframe = int(capture_gui.lib.get_current_frame()) - mode_values = "({})".format(currentframe) - - # Update label - self.label = "Time Range {}".format(mode_values) - self.label_changed.emit(self.label) - - if emit: - self.options_changed.emit() - - def validate(self): - errors = [] - - if self.mode.currentText() == self.CustomFrames: - - # Reset - self.custom_frames.setStyleSheet("") - - try: - parse_frames(self.custom_frames.text()) - except ValueError as exc: - errors.append("{} : Invalid frame description: " - "{}".format(self.id, exc)) - self.custom_frames.setStyleSheet(self.highlight) - - return errors - - def get_outputs(self, panel=""): - """Get the plugin outputs that matches `capture.capture` arguments - - Returns: - dict: Plugin outputs - - """ - - mode = self.mode.currentText() - frames = None - - if mode == self.RangeTimeSlider: - start, end = capture_gui.lib.get_time_slider_range() - - elif mode == self.RangeStartEnd: - start = self.start.value() - end = self.end.value() - - elif mode == self.CurrentFrame: - frame = capture_gui.lib.get_current_frame() - start = frame - end = frame - - elif mode == self.CustomFrames: - frames = parse_frames(self.custom_frames.text()) - start = None - end = None - else: - raise NotImplementedError("Unsupported time range mode: " - "{0}".format(mode)) - - return {"start_frame": start, - "end_frame": end, - "frame": frames} - - def get_inputs(self, as_preset): - return {"time": self.mode.currentText(), - "start_frame": self.start.value(), - "end_frame": self.end.value(), - "frame": self.custom_frames.text()} - - def apply_inputs(self, settings): - # get values - mode = self.mode.findText(settings.get("time", self.RangeTimeSlider)) - startframe = settings.get("start_frame", 1) - endframe = settings.get("end_frame", 120) - custom_frames = settings.get("frame", None) - - # set values - self.mode.setCurrentIndex(mode) - self.start.setValue(int(startframe)) - self.end.setValue(int(endframe)) - if custom_frames is not None: - self.custom_frames.setText(custom_frames) - - def initialize(self): - self._register_callbacks() - - def uninitialize(self): - self._remove_callbacks() - - def _register_callbacks(self): - """Register maya time and playback range change callbacks. - - Register callbacks to ensure Capture GUI reacts to changes in - the Maya GUI in regards to time slider and current frame - - """ - - callback = lambda x: self.on_mode_changed(emit=False) - - # this avoid overriding the ids on re-run - currentframe = om.MEventMessage.addEventCallback("timeChanged", - callback) - timerange = om.MEventMessage.addEventCallback("playbackRangeChanged", - callback) - - self._event_callbacks.append(currentframe) - self._event_callbacks.append(timerange) - - def _remove_callbacks(self): - """Remove callbacks when closing widget""" - for callback in self._event_callbacks: - try: - om.MEventMessage.removeCallback(callback) - except RuntimeError, error: - log.error("Encounter error : {}".format(error)) diff --git a/pype/vendor/capture_gui/plugins/viewportplugin.py b/pype/vendor/capture_gui/plugins/viewportplugin.py deleted file mode 100644 index 96f311fdcf9..00000000000 --- a/pype/vendor/capture_gui/plugins/viewportplugin.py +++ /dev/null @@ -1,292 +0,0 @@ -from capture_gui.vendor.Qt import QtCore, QtWidgets -import capture_gui.plugin -import capture_gui.lib as lib -import capture - - -class ViewportPlugin(capture_gui.plugin.Plugin): - """Plugin to apply viewport visibilities and settings""" - - id = "Viewport Options" - label = "Viewport Options" - section = "config" - order = 70 - - def __init__(self, parent=None): - super(ViewportPlugin, self).__init__(parent=parent) - - # set inherited attributes - self.setObjectName(self.label) - - # custom atttributes - self.show_type_actions = list() - - # get information - self.show_types = lib.get_show_object_types() - - # set main layout for widget - self._layout = QtWidgets.QVBoxLayout() - self._layout.setContentsMargins(0, 0, 0, 0) - self.setLayout(self._layout) - - # build - # region Menus - menus_vlayout = QtWidgets.QHBoxLayout() - - # Display Lights - self.display_light_menu = self._build_light_menu() - self.display_light_menu.setFixedHeight(20) - - # Show - self.show_types_button = QtWidgets.QPushButton("Show") - self.show_types_button.setFixedHeight(20) - self.show_types_menu = self._build_show_menu() - self.show_types_button.setMenu(self.show_types_menu) - - # fill layout - menus_vlayout.addWidget(self.display_light_menu) - menus_vlayout.addWidget(self.show_types_button) - - # endregion Menus - - # region Checkboxes - checkbox_layout = QtWidgets.QGridLayout() - self.high_quality = QtWidgets.QCheckBox() - self.high_quality.setText("Force Viewport 2.0 + AA") - self.override_viewport = QtWidgets.QCheckBox("Override viewport " - "settings") - self.override_viewport.setChecked(True) - - # two sided lighting - self.two_sided_ligthing = QtWidgets.QCheckBox("Two Sided Ligthing") - self.two_sided_ligthing.setChecked(False) - - # show - self.shadows = QtWidgets.QCheckBox("Shadows") - self.shadows.setChecked(False) - - checkbox_layout.addWidget(self.override_viewport, 0, 0) - checkbox_layout.addWidget(self.high_quality, 0, 1) - checkbox_layout.addWidget(self.two_sided_ligthing, 1, 0) - checkbox_layout.addWidget(self.shadows, 1, 1) - # endregion Checkboxes - - self._layout.addLayout(checkbox_layout) - self._layout.addLayout(menus_vlayout) - - self.connections() - - def connections(self): - - self.high_quality.stateChanged.connect(self.options_changed) - self.override_viewport.stateChanged.connect(self.options_changed) - self.override_viewport.stateChanged.connect(self.on_toggle_override) - - self.two_sided_ligthing.stateChanged.connect(self.options_changed) - self.shadows.stateChanged.connect(self.options_changed) - - self.display_light_menu.currentIndexChanged.connect( - self.options_changed - ) - - def _build_show_menu(self): - """Build the menu to select which object types are shown in the output. - - Returns: - QtGui.QMenu: The visibilities "show" menu. - - """ - - menu = QtWidgets.QMenu(self) - menu.setObjectName("ShowShapesMenu") - menu.setWindowTitle("Show") - menu.setFixedWidth(180) - menu.setTearOffEnabled(True) - - # Show all check - toggle_all = QtWidgets.QAction(menu, text="All") - toggle_none = QtWidgets.QAction(menu, text="None") - menu.addAction(toggle_all) - menu.addAction(toggle_none) - menu.addSeparator() - - # add plugin shapes if any - for shape in self.show_types: - action = QtWidgets.QAction(menu, text=shape) - action.setCheckable(True) - # emit signal when the state is changed of the checkbox - action.toggled.connect(self.options_changed) - menu.addAction(action) - self.show_type_actions.append(action) - - # connect signals - toggle_all.triggered.connect(self.toggle_all_visbile) - toggle_none.triggered.connect(self.toggle_all_hide) - - return menu - - def _build_light_menu(self): - """Build lighting menu. - - Create the menu items for the different types of lighting for - in the viewport - - Returns: - None - - """ - - menu = QtWidgets.QComboBox(self) - - # names cane be found in - display_lights = (("Use Default Lighting", "default"), - ("Use All Lights", "all"), - ("Use Selected Lights", "active"), - ("Use Flat Lighting", "flat"), - ("Use No Lights", "none")) - - for label, name in display_lights: - menu.addItem(label, userData=name) - - return menu - - def on_toggle_override(self): - """Enable or disable show menu when override is checked""" - state = self.override_viewport.isChecked() - self.show_types_button.setEnabled(state) - self.high_quality.setEnabled(state) - self.display_light_menu.setEnabled(state) - self.shadows.setEnabled(state) - self.two_sided_ligthing.setEnabled(state) - - def toggle_all_visbile(self): - """Set all object types off or on depending on the state""" - for action in self.show_type_actions: - action.setChecked(True) - - def toggle_all_hide(self): - """Set all object types off or on depending on the state""" - for action in self.show_type_actions: - action.setChecked(False) - - def get_show_inputs(self): - """Return checked state of show menu items - - Returns: - dict: The checked show states in the widget. - - """ - - show_inputs = {} - # get all checked objects - for action in self.show_type_actions: - label = action.text() - name = self.show_types.get(label, None) - if name is None: - continue - show_inputs[name] = action.isChecked() - - return show_inputs - - def get_displaylights(self): - """Get and parse the currently selected displayLights options. - - Returns: - dict: The display light options - - """ - indx = self.display_light_menu.currentIndex() - return {"displayLights": self.display_light_menu.itemData(indx), - "shadows": self.shadows.isChecked(), - "twoSidedLighting": self.two_sided_ligthing.isChecked()} - - def get_inputs(self, as_preset): - """Return the widget options - - Returns: - dict: The input settings of the widgets. - - """ - inputs = {"high_quality": self.high_quality.isChecked(), - "override_viewport_options": self.override_viewport.isChecked(), - "displayLights": self.display_light_menu.currentIndex(), - "shadows": self.shadows.isChecked(), - "twoSidedLighting": self.two_sided_ligthing.isChecked()} - - inputs.update(self.get_show_inputs()) - - return inputs - - def apply_inputs(self, inputs): - """Apply the saved inputs from the inputs configuration - - Arguments: - settings (dict): The input settings to apply. - - """ - - # get input values directly from input given - override_viewport = inputs.get("override_viewport_options", True) - high_quality = inputs.get("high_quality", True) - displaylight = inputs.get("displayLights", 0) # default lighting - two_sided_ligthing = inputs.get("twoSidedLighting", False) - shadows = inputs.get("shadows", False) - - self.high_quality.setChecked(high_quality) - self.override_viewport.setChecked(override_viewport) - self.show_types_button.setEnabled(override_viewport) - - # display light menu - self.display_light_menu.setCurrentIndex(displaylight) - self.shadows.setChecked(shadows) - self.two_sided_ligthing.setChecked(two_sided_ligthing) - - for action in self.show_type_actions: - system_name = self.show_types[action.text()] - state = inputs.get(system_name, True) - action.setChecked(state) - - def get_outputs(self): - """Get the plugin outputs that matches `capture.capture` arguments - - Returns: - dict: Plugin outputs - - """ - outputs = dict() - - high_quality = self.high_quality.isChecked() - override_viewport_options = self.override_viewport.isChecked() - - if override_viewport_options: - outputs['viewport2_options'] = dict() - outputs['viewport_options'] = dict() - - if high_quality: - # force viewport 2.0 and AA - outputs['viewport_options']['rendererName'] = 'vp2Renderer' - outputs['viewport2_options']['multiSampleEnable'] = True - outputs['viewport2_options']['multiSampleCount'] = 8 - - show_per_type = self.get_show_inputs() - display_lights = self.get_displaylights() - outputs['viewport_options'].update(show_per_type) - outputs['viewport_options'].update(display_lights) - else: - # TODO: When this fails we should give the user a warning - # Use settings from the active viewport - outputs = capture.parse_active_view() - - # Remove the display options and camera attributes - outputs.pop("display_options", None) - outputs.pop("camera", None) - - # Remove the current renderer because there's already - # renderer plug-in handling that - outputs["viewport_options"].pop("rendererName", None) - - # Remove all camera options except depth of field - dof = outputs["camera_options"]["depthOfField"] - outputs["camera_options"] = {"depthOfField": dof} - - return outputs diff --git a/pype/vendor/capture_gui/presets.py b/pype/vendor/capture_gui/presets.py deleted file mode 100644 index 634e8264ecb..00000000000 --- a/pype/vendor/capture_gui/presets.py +++ /dev/null @@ -1,105 +0,0 @@ -import glob -import os -import logging - -_registered_paths = [] -log = logging.getLogger("Presets") - - -def discover(paths=None): - """Get the full list of files found in the registered folders - - Args: - paths (list, Optional): directories which host preset files or None. - When None (default) it will list from the registered preset paths. - - Returns: - list: valid .json preset file paths. - - """ - - presets = [] - for path in paths or preset_paths(): - path = os.path.normpath(path) - if not os.path.isdir(path): - continue - - # check for json files - glob_query = os.path.abspath(os.path.join(path, "*.json")) - filenames = glob.glob(glob_query) - for filename in filenames: - # skip private files - if filename.startswith("_"): - continue - - # check for file size - if not check_file_size(filename): - log.warning("Filesize is smaller than 1 byte for file '%s'", - filename) - continue - - if filename not in presets: - presets.append(filename) - - return presets - - -def check_file_size(filepath): - """Check if filesize of the given file is bigger than 1.0 byte - - Args: - filepath (str): full filepath of the file to check - - Returns: - bool: Whether bigger than 1 byte. - - """ - - file_stats = os.stat(filepath) - if file_stats.st_size < 1: - return False - return True - - -def preset_paths(): - """Return existing registered preset paths - - Returns: - list: List of full paths. - - """ - - paths = list() - for path in _registered_paths: - # filter duplicates - if path in paths: - continue - - if not os.path.exists(path): - continue - - paths.append(path) - - return paths - - -def register_preset_path(path): - """Add filepath to registered presets - - :param path: the directory of the preset file(s) - :type path: str - - :return: - """ - if path in _registered_paths: - return log.warning("Path already registered: %s", path) - - _registered_paths.append(path) - - return path - - -# Register default user folder -user_folder = os.path.expanduser("~") -capture_gui_presets = os.path.join(user_folder, "CaptureGUI", "presets") -register_preset_path(capture_gui_presets) diff --git a/pype/vendor/capture_gui/resources/config.png b/pype/vendor/capture_gui/resources/config.png deleted file mode 100644 index 634a1da65aa..00000000000 Binary files a/pype/vendor/capture_gui/resources/config.png and /dev/null differ diff --git a/pype/vendor/capture_gui/resources/import.png b/pype/vendor/capture_gui/resources/import.png deleted file mode 100644 index 785747191af..00000000000 Binary files a/pype/vendor/capture_gui/resources/import.png and /dev/null differ diff --git a/pype/vendor/capture_gui/resources/reset.png b/pype/vendor/capture_gui/resources/reset.png deleted file mode 100644 index 629822cd44b..00000000000 Binary files a/pype/vendor/capture_gui/resources/reset.png and /dev/null differ diff --git a/pype/vendor/capture_gui/resources/save.png b/pype/vendor/capture_gui/resources/save.png deleted file mode 100644 index 817af19e9f1..00000000000 Binary files a/pype/vendor/capture_gui/resources/save.png and /dev/null differ diff --git a/pype/vendor/capture_gui/tokens.py b/pype/vendor/capture_gui/tokens.py deleted file mode 100644 index d34167b53d7..00000000000 --- a/pype/vendor/capture_gui/tokens.py +++ /dev/null @@ -1,68 +0,0 @@ -"""Token system - -The capture gui application will format tokens in the filename. -The tokens can be registered using `register_token` - -""" -from . import lib - -_registered_tokens = dict() - - -def format_tokens(string, options): - """Replace the tokens with the correlated strings - - Arguments: - string (str): filename of the playblast with tokens. - options (dict): The parsed capture options. - - Returns: - str: The formatted filename with all tokens resolved - - """ - - if not string: - return string - - for token, value in _registered_tokens.items(): - if token in string: - func = value['func'] - string = string.replace(token, func(options)) - - return string - - -def register_token(token, func, label=""): - assert token.startswith("<") and token.endswith(">") - assert callable(func) - _registered_tokens[token] = {"func": func, "label": label} - - -def list_tokens(): - return _registered_tokens.copy() - - -# register default tokens -# scene based tokens -def _camera_token(options): - """Return short name of camera from capture options""" - camera = options['camera'] - camera = camera.rsplit("|", 1)[-1] # use short name - camera = camera.replace(":", "_") # namespace `:` to `_` - return camera - - -register_token("", _camera_token, - label="Insert camera name") -register_token("", lambda options: lib.get_current_scenename() or "playblast", - label="Insert current scene name") -register_token("", lambda options: lib.get_current_renderlayer(), - label="Insert active render layer name") - -# project based tokens -register_token("", - lambda options: lib.get_project_rule("images"), - label="Insert image directory of set project") -register_token("", - lambda options: lib.get_project_rule("movie"), - label="Insert movies directory of set project") diff --git a/pype/vendor/capture_gui/vendor/Qt.py b/pype/vendor/capture_gui/vendor/Qt.py deleted file mode 100644 index 3a97da872d9..00000000000 --- a/pype/vendor/capture_gui/vendor/Qt.py +++ /dev/null @@ -1,1030 +0,0 @@ -"""The MIT License (MIT) - -Copyright (c) 2016-2017 Marcus Ottosson - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -Documentation - - Map all bindings to PySide2 - - Project goals: - Qt.py was born in the film and visual effects industry to address - the growing need for the development of software capable of running - with more than one flavour of the Qt bindings for Python - PySide, - PySide2, PyQt4 and PyQt5. - - 1. Build for one, run with all - 2. Explicit is better than implicit - 3. Support co-existence - - Default resolution order: - - PySide2 - - PyQt5 - - PySide - - PyQt4 - - Usage: - >> import sys - >> from Qt import QtWidgets - >> app = QtWidgets.QApplication(sys.argv) - >> button = QtWidgets.QPushButton("Hello World") - >> button.show() - >> app.exec_() - - All members of PySide2 are mapped from other bindings, should they exist. - If no equivalent member exist, it is excluded from Qt.py and inaccessible. - The idea is to highlight members that exist across all supported binding, - and guarantee that code that runs on one binding runs on all others. - - For more details, visit https://github.com/mottosso/Qt.py - -""" - -import os -import sys -import types -import shutil -import importlib - -__version__ = "1.0.0.b3" - -# Enable support for `from Qt import *` -__all__ = [] - -# Flags from environment variables -QT_VERBOSE = bool(os.getenv("QT_VERBOSE")) -QT_PREFERRED_BINDING = os.getenv("QT_PREFERRED_BINDING", "") -QT_SIP_API_HINT = os.getenv("QT_SIP_API_HINT") - -# Reference to Qt.py -Qt = sys.modules[__name__] -Qt.QtCompat = types.ModuleType("QtCompat") - -"""Common members of all bindings - -This is where each member of Qt.py is explicitly defined. -It is based on a "lowest commond denominator" of all bindings; -including members found in each of the 4 bindings. - -Find or add excluded members in build_membership.py - -""" - -_common_members = { - "QtGui": [ - "QAbstractTextDocumentLayout", - "QActionEvent", - "QBitmap", - "QBrush", - "QClipboard", - "QCloseEvent", - "QColor", - "QConicalGradient", - "QContextMenuEvent", - "QCursor", - "QDoubleValidator", - "QDrag", - "QDragEnterEvent", - "QDragLeaveEvent", - "QDragMoveEvent", - "QDropEvent", - "QFileOpenEvent", - "QFocusEvent", - "QFont", - "QFontDatabase", - "QFontInfo", - "QFontMetrics", - "QFontMetricsF", - "QGradient", - "QHelpEvent", - "QHideEvent", - "QHoverEvent", - "QIcon", - "QIconDragEvent", - "QIconEngine", - "QImage", - "QImageIOHandler", - "QImageReader", - "QImageWriter", - "QInputEvent", - "QInputMethodEvent", - "QIntValidator", - "QKeyEvent", - "QKeySequence", - "QLinearGradient", - "QMatrix2x2", - "QMatrix2x3", - "QMatrix2x4", - "QMatrix3x2", - "QMatrix3x3", - "QMatrix3x4", - "QMatrix4x2", - "QMatrix4x3", - "QMatrix4x4", - "QMouseEvent", - "QMoveEvent", - "QMovie", - "QPaintDevice", - "QPaintEngine", - "QPaintEngineState", - "QPaintEvent", - "QPainter", - "QPainterPath", - "QPainterPathStroker", - "QPalette", - "QPen", - "QPicture", - "QPictureIO", - "QPixmap", - "QPixmapCache", - "QPolygon", - "QPolygonF", - "QQuaternion", - "QRadialGradient", - "QRegExpValidator", - "QRegion", - "QResizeEvent", - "QSessionManager", - "QShortcutEvent", - "QShowEvent", - "QStandardItem", - "QStandardItemModel", - "QStatusTipEvent", - "QSyntaxHighlighter", - "QTabletEvent", - "QTextBlock", - "QTextBlockFormat", - "QTextBlockGroup", - "QTextBlockUserData", - "QTextCharFormat", - "QTextCursor", - "QTextDocument", - "QTextDocumentFragment", - "QTextFormat", - "QTextFragment", - "QTextFrame", - "QTextFrameFormat", - "QTextImageFormat", - "QTextInlineObject", - "QTextItem", - "QTextLayout", - "QTextLength", - "QTextLine", - "QTextList", - "QTextListFormat", - "QTextObject", - "QTextObjectInterface", - "QTextOption", - "QTextTable", - "QTextTableCell", - "QTextTableCellFormat", - "QTextTableFormat", - "QTransform", - "QValidator", - "QVector2D", - "QVector3D", - "QVector4D", - "QWhatsThisClickedEvent", - "QWheelEvent", - "QWindowStateChangeEvent", - "qAlpha", - "qBlue", - "qGray", - "qGreen", - "qIsGray", - "qRed", - "qRgb", - "qRgb", - ], - "QtWidgets": [ - "QAbstractButton", - "QAbstractGraphicsShapeItem", - "QAbstractItemDelegate", - "QAbstractItemView", - "QAbstractScrollArea", - "QAbstractSlider", - "QAbstractSpinBox", - "QAction", - "QActionGroup", - "QApplication", - "QBoxLayout", - "QButtonGroup", - "QCalendarWidget", - "QCheckBox", - "QColorDialog", - "QColumnView", - "QComboBox", - "QCommandLinkButton", - "QCommonStyle", - "QCompleter", - "QDataWidgetMapper", - "QDateEdit", - "QDateTimeEdit", - "QDesktopWidget", - "QDial", - "QDialog", - "QDialogButtonBox", - "QDirModel", - "QDockWidget", - "QDoubleSpinBox", - "QErrorMessage", - "QFileDialog", - "QFileIconProvider", - "QFileSystemModel", - "QFocusFrame", - "QFontComboBox", - "QFontDialog", - "QFormLayout", - "QFrame", - "QGesture", - "QGestureEvent", - "QGestureRecognizer", - "QGraphicsAnchor", - "QGraphicsAnchorLayout", - "QGraphicsBlurEffect", - "QGraphicsColorizeEffect", - "QGraphicsDropShadowEffect", - "QGraphicsEffect", - "QGraphicsEllipseItem", - "QGraphicsGridLayout", - "QGraphicsItem", - "QGraphicsItemGroup", - "QGraphicsLayout", - "QGraphicsLayoutItem", - "QGraphicsLineItem", - "QGraphicsLinearLayout", - "QGraphicsObject", - "QGraphicsOpacityEffect", - "QGraphicsPathItem", - "QGraphicsPixmapItem", - "QGraphicsPolygonItem", - "QGraphicsProxyWidget", - "QGraphicsRectItem", - "QGraphicsRotation", - "QGraphicsScale", - "QGraphicsScene", - "QGraphicsSceneContextMenuEvent", - "QGraphicsSceneDragDropEvent", - "QGraphicsSceneEvent", - "QGraphicsSceneHelpEvent", - "QGraphicsSceneHoverEvent", - "QGraphicsSceneMouseEvent", - "QGraphicsSceneMoveEvent", - "QGraphicsSceneResizeEvent", - "QGraphicsSceneWheelEvent", - "QGraphicsSimpleTextItem", - "QGraphicsTextItem", - "QGraphicsTransform", - "QGraphicsView", - "QGraphicsWidget", - "QGridLayout", - "QGroupBox", - "QHBoxLayout", - "QHeaderView", - "QInputDialog", - "QItemDelegate", - "QItemEditorCreatorBase", - "QItemEditorFactory", - "QKeyEventTransition", - "QLCDNumber", - "QLabel", - "QLayout", - "QLayoutItem", - "QLineEdit", - "QListView", - "QListWidget", - "QListWidgetItem", - "QMainWindow", - "QMdiArea", - "QMdiSubWindow", - "QMenu", - "QMenuBar", - "QMessageBox", - "QMouseEventTransition", - "QPanGesture", - "QPinchGesture", - "QPlainTextDocumentLayout", - "QPlainTextEdit", - "QProgressBar", - "QProgressDialog", - "QPushButton", - "QRadioButton", - "QRubberBand", - "QScrollArea", - "QScrollBar", - "QShortcut", - "QSizeGrip", - "QSizePolicy", - "QSlider", - "QSpacerItem", - "QSpinBox", - "QSplashScreen", - "QSplitter", - "QSplitterHandle", - "QStackedLayout", - "QStackedWidget", - "QStatusBar", - "QStyle", - "QStyleFactory", - "QStyleHintReturn", - "QStyleHintReturnMask", - "QStyleHintReturnVariant", - "QStyleOption", - "QStyleOptionButton", - "QStyleOptionComboBox", - "QStyleOptionComplex", - "QStyleOptionDockWidget", - "QStyleOptionFocusRect", - "QStyleOptionFrame", - "QStyleOptionGraphicsItem", - "QStyleOptionGroupBox", - "QStyleOptionHeader", - "QStyleOptionMenuItem", - "QStyleOptionProgressBar", - "QStyleOptionRubberBand", - "QStyleOptionSizeGrip", - "QStyleOptionSlider", - "QStyleOptionSpinBox", - "QStyleOptionTab", - "QStyleOptionTabBarBase", - "QStyleOptionTabWidgetFrame", - "QStyleOptionTitleBar", - "QStyleOptionToolBar", - "QStyleOptionToolBox", - "QStyleOptionToolButton", - "QStyleOptionViewItem", - "QStylePainter", - "QStyledItemDelegate", - "QSwipeGesture", - "QSystemTrayIcon", - "QTabBar", - "QTabWidget", - "QTableView", - "QTableWidget", - "QTableWidgetItem", - "QTableWidgetSelectionRange", - "QTapAndHoldGesture", - "QTapGesture", - "QTextBrowser", - "QTextEdit", - "QTimeEdit", - "QToolBar", - "QToolBox", - "QToolButton", - "QToolTip", - "QTreeView", - "QTreeWidget", - "QTreeWidgetItem", - "QTreeWidgetItemIterator", - "QUndoCommand", - "QUndoGroup", - "QUndoStack", - "QUndoView", - "QVBoxLayout", - "QWhatsThis", - "QWidget", - "QWidgetAction", - "QWidgetItem", - "QWizard", - "QWizardPage", - ], - "QtCore": [ - "QAbstractAnimation", - "QAbstractEventDispatcher", - "QAbstractItemModel", - "QAbstractListModel", - "QAbstractState", - "QAbstractTableModel", - "QAbstractTransition", - "QAnimationGroup", - "QBasicTimer", - "QBitArray", - "QBuffer", - "QByteArray", - "QByteArrayMatcher", - "QChildEvent", - "QCoreApplication", - "QCryptographicHash", - "QDataStream", - "QDate", - "QDateTime", - "QDir", - "QDirIterator", - "QDynamicPropertyChangeEvent", - "QEasingCurve", - "QElapsedTimer", - "QEvent", - "QEventLoop", - "QEventTransition", - "QFile", - "QFileInfo", - "QFileSystemWatcher", - "QFinalState", - "QGenericArgument", - "QGenericReturnArgument", - "QHistoryState", - "QIODevice", - "QLibraryInfo", - "QLine", - "QLineF", - "QLocale", - "QMargins", - "QMetaClassInfo", - "QMetaEnum", - "QMetaMethod", - "QMetaObject", - "QMetaProperty", - "QMimeData", - "QModelIndex", - "QMutex", - "QMutexLocker", - "QObject", - "QParallelAnimationGroup", - "QPauseAnimation", - "QPersistentModelIndex", - "QPluginLoader", - "QPoint", - "QPointF", - "QProcess", - "QProcessEnvironment", - "QPropertyAnimation", - "QReadLocker", - "QReadWriteLock", - "QRect", - "QRectF", - "QRegExp", - "QResource", - "QRunnable", - "QSemaphore", - "QSequentialAnimationGroup", - "QSettings", - "QSignalMapper", - "QSignalTransition", - "QSize", - "QSizeF", - "QSocketNotifier", - "QState", - "QStateMachine", - "QSysInfo", - "QSystemSemaphore", - "QTemporaryFile", - "QTextBoundaryFinder", - "QTextCodec", - "QTextDecoder", - "QTextEncoder", - "QTextStream", - "QTextStreamManipulator", - "QThread", - "QThreadPool", - "QTime", - "QTimeLine", - "QTimer", - "QTimerEvent", - "QTranslator", - "QUrl", - "QVariantAnimation", - "QWaitCondition", - "QWriteLocker", - "QXmlStreamAttribute", - "QXmlStreamAttributes", - "QXmlStreamEntityDeclaration", - "QXmlStreamEntityResolver", - "QXmlStreamNamespaceDeclaration", - "QXmlStreamNotationDeclaration", - "QXmlStreamReader", - "QXmlStreamWriter", - "Qt", - "QtCriticalMsg", - "QtDebugMsg", - "QtFatalMsg", - "QtMsgType", - "QtSystemMsg", - "QtWarningMsg", - "qAbs", - "qAddPostRoutine", - "qChecksum", - "qCritical", - "qDebug", - "qFatal", - "qFuzzyCompare", - "qIsFinite", - "qIsInf", - "qIsNaN", - "qIsNull", - "qRegisterResourceData", - "qUnregisterResourceData", - "qVersion", - "qWarning", - "qrand", - "qsrand", - ], - "QtXml": [ - "QDomAttr", - "QDomCDATASection", - "QDomCharacterData", - "QDomComment", - "QDomDocument", - "QDomDocumentFragment", - "QDomDocumentType", - "QDomElement", - "QDomEntity", - "QDomEntityReference", - "QDomImplementation", - "QDomNamedNodeMap", - "QDomNode", - "QDomNodeList", - "QDomNotation", - "QDomProcessingInstruction", - "QDomText", - "QXmlAttributes", - "QXmlContentHandler", - "QXmlDTDHandler", - "QXmlDeclHandler", - "QXmlDefaultHandler", - "QXmlEntityResolver", - "QXmlErrorHandler", - "QXmlInputSource", - "QXmlLexicalHandler", - "QXmlLocator", - "QXmlNamespaceSupport", - "QXmlParseException", - "QXmlReader", - "QXmlSimpleReader" - ], - "QtHelp": [ - "QHelpContentItem", - "QHelpContentModel", - "QHelpContentWidget", - "QHelpEngine", - "QHelpEngineCore", - "QHelpIndexModel", - "QHelpIndexWidget", - "QHelpSearchEngine", - "QHelpSearchQuery", - "QHelpSearchQueryWidget", - "QHelpSearchResultWidget" - ], - "QtNetwork": [ - "QAbstractNetworkCache", - "QAbstractSocket", - "QAuthenticator", - "QHostAddress", - "QHostInfo", - "QLocalServer", - "QLocalSocket", - "QNetworkAccessManager", - "QNetworkAddressEntry", - "QNetworkCacheMetaData", - "QNetworkConfiguration", - "QNetworkConfigurationManager", - "QNetworkCookie", - "QNetworkCookieJar", - "QNetworkDiskCache", - "QNetworkInterface", - "QNetworkProxy", - "QNetworkProxyFactory", - "QNetworkProxyQuery", - "QNetworkReply", - "QNetworkRequest", - "QNetworkSession", - "QSsl", - "QTcpServer", - "QTcpSocket", - "QUdpSocket" - ], - "QtOpenGL": [ - "QGL", - "QGLContext", - "QGLFormat", - "QGLWidget" - ] -} - - -def _new_module(name): - return types.ModuleType(__name__ + "." + name) - - -def _setup(module, extras): - """Install common submodules""" - - Qt.__binding__ = module.__name__ - - for name in list(_common_members) + extras: - try: - # print("Trying %s" % name) - submodule = importlib.import_module( - module.__name__ + "." + name) - except ImportError: - # print("Failed %s" % name) - continue - - setattr(Qt, "_" + name, submodule) - - if name not in extras: - # Store reference to original binding, - # but don't store speciality modules - # such as uic or QtUiTools - setattr(Qt, name, _new_module(name)) - - -def _pyside2(): - """Initialise PySide2 - - These functions serve to test the existence of a binding - along with set it up in such a way that it aligns with - the final step; adding members from the original binding - to Qt.py - - """ - - import PySide2 as module - _setup(module, ["QtUiTools"]) - - Qt.__binding_version__ = module.__version__ - - if hasattr(Qt, "_QtUiTools"): - Qt.QtCompat.loadUi = lambda fname: \ - Qt._QtUiTools.QUiLoader().load(fname) - - if hasattr(Qt, "_QtGui") and hasattr(Qt, "_QtCore"): - Qt.QtCore.QStringListModel = Qt._QtGui.QStringListModel - - if hasattr(Qt, "_QtWidgets"): - Qt.QtCompat.setSectionResizeMode = \ - Qt._QtWidgets.QHeaderView.setSectionResizeMode - - if hasattr(Qt, "_QtCore"): - Qt.__qt_version__ = Qt._QtCore.qVersion() - Qt.QtCompat.translate = Qt._QtCore.QCoreApplication.translate - - Qt.QtCore.Property = Qt._QtCore.Property - Qt.QtCore.Signal = Qt._QtCore.Signal - Qt.QtCore.Slot = Qt._QtCore.Slot - - Qt.QtCore.QAbstractProxyModel = Qt._QtCore.QAbstractProxyModel - Qt.QtCore.QSortFilterProxyModel = Qt._QtCore.QSortFilterProxyModel - Qt.QtCore.QItemSelection = Qt._QtCore.QItemSelection - Qt.QtCore.QItemSelectionRange = Qt._QtCore.QItemSelectionRange - Qt.QtCore.QItemSelectionModel = Qt._QtCore.QItemSelectionModel - - -def _pyside(): - """Initialise PySide""" - - import PySide as module - _setup(module, ["QtUiTools"]) - - Qt.__binding_version__ = module.__version__ - - if hasattr(Qt, "_QtUiTools"): - Qt.QtCompat.loadUi = lambda fname: \ - Qt._QtUiTools.QUiLoader().load(fname) - - if hasattr(Qt, "_QtGui"): - setattr(Qt, "QtWidgets", _new_module("QtWidgets")) - setattr(Qt, "_QtWidgets", Qt._QtGui) - - Qt.QtCompat.setSectionResizeMode = Qt._QtGui.QHeaderView.setResizeMode - - if hasattr(Qt, "_QtCore"): - Qt.QtCore.QAbstractProxyModel = Qt._QtGui.QAbstractProxyModel - Qt.QtCore.QSortFilterProxyModel = Qt._QtGui.QSortFilterProxyModel - Qt.QtCore.QStringListModel = Qt._QtGui.QStringListModel - Qt.QtCore.QItemSelection = Qt._QtGui.QItemSelection - Qt.QtCore.QItemSelectionRange = Qt._QtGui.QItemSelectionRange - Qt.QtCore.QItemSelectionModel = Qt._QtGui.QItemSelectionModel - - if hasattr(Qt, "_QtCore"): - Qt.__qt_version__ = Qt._QtCore.qVersion() - - Qt.QtCore.Property = Qt._QtCore.Property - Qt.QtCore.Signal = Qt._QtCore.Signal - Qt.QtCore.Slot = Qt._QtCore.Slot - - QCoreApplication = Qt._QtCore.QCoreApplication - Qt.QtCompat.translate = ( - lambda context, sourceText, disambiguation, n: - QCoreApplication.translate( - context, - sourceText, - disambiguation, - QCoreApplication.CodecForTr, - n - ) - ) - - -def _pyqt5(): - """Initialise PyQt5""" - - import PyQt5 as module - _setup(module, ["uic"]) - - if hasattr(Qt, "_uic"): - Qt.QtCompat.loadUi = lambda fname: Qt._uic.loadUi(fname) - - if hasattr(Qt, "_QtWidgets"): - Qt.QtCompat.setSectionResizeMode = \ - Qt._QtWidgets.QHeaderView.setSectionResizeMode - - if hasattr(Qt, "_QtCore"): - Qt.QtCompat.translate = Qt._QtCore.QCoreApplication.translate - - Qt.QtCore.Property = Qt._QtCore.pyqtProperty - Qt.QtCore.Signal = Qt._QtCore.pyqtSignal - Qt.QtCore.Slot = Qt._QtCore.pyqtSlot - - Qt.QtCore.QAbstractProxyModel = Qt._QtCore.QAbstractProxyModel - Qt.QtCore.QSortFilterProxyModel = Qt._QtCore.QSortFilterProxyModel - Qt.QtCore.QStringListModel = Qt._QtCore.QStringListModel - Qt.QtCore.QItemSelection = Qt._QtCore.QItemSelection - Qt.QtCore.QItemSelectionModel = Qt._QtCore.QItemSelectionModel - Qt.QtCore.QItemSelectionRange = Qt._QtCore.QItemSelectionRange - - Qt.__qt_version__ = Qt._QtCore.QT_VERSION_STR - Qt.__binding_version__ = Qt._QtCore.PYQT_VERSION_STR - - -def _pyqt4(): - """Initialise PyQt4""" - - import sip - - # Validation of envivornment variable. Prevents an error if - # the variable is invalid since it's just a hint. - try: - hint = int(QT_SIP_API_HINT) - except TypeError: - hint = None # Variable was None, i.e. not set. - except ValueError: - raise ImportError("QT_SIP_API_HINT=%s must be a 1 or 2") - - for api in ("QString", - "QVariant", - "QDate", - "QDateTime", - "QTextStream", - "QTime", - "QUrl"): - try: - sip.setapi(api, hint or 2) - except AttributeError: - raise ImportError("PyQt4 < 4.6 isn't supported by Qt.py") - except ValueError: - actual = sip.getapi(api) - if not hint: - raise ImportError("API version already set to %d" % actual) - else: - # Having provided a hint indicates a soft constraint, one - # that doesn't throw an exception. - sys.stderr.write( - "Warning: API '%s' has already been set to %d.\n" - % (api, actual) - ) - - import PyQt4 as module - _setup(module, ["uic"]) - - if hasattr(Qt, "_uic"): - Qt.QtCompat.loadUi = lambda fname: Qt._uic.loadUi(fname) - - if hasattr(Qt, "_QtGui"): - setattr(Qt, "QtWidgets", _new_module("QtWidgets")) - setattr(Qt, "_QtWidgets", Qt._QtGui) - - Qt.QtCompat.setSectionResizeMode = \ - Qt._QtGui.QHeaderView.setResizeMode - - if hasattr(Qt, "_QtCore"): - Qt.QtCore.QAbstractProxyModel = Qt._QtGui.QAbstractProxyModel - Qt.QtCore.QSortFilterProxyModel = Qt._QtGui.QSortFilterProxyModel - Qt.QtCore.QItemSelection = Qt._QtGui.QItemSelection - Qt.QtCore.QStringListModel = Qt._QtGui.QStringListModel - Qt.QtCore.QItemSelectionModel = Qt._QtGui.QItemSelectionModel - Qt.QtCore.QItemSelectionRange = Qt._QtGui.QItemSelectionRange - - if hasattr(Qt, "_QtCore"): - Qt.__qt_version__ = Qt._QtCore.QT_VERSION_STR - Qt.__binding_version__ = Qt._QtCore.PYQT_VERSION_STR - - Qt.QtCore.Property = Qt._QtCore.pyqtProperty - Qt.QtCore.Signal = Qt._QtCore.pyqtSignal - Qt.QtCore.Slot = Qt._QtCore.pyqtSlot - - QCoreApplication = Qt._QtCore.QCoreApplication - Qt.QtCompat.translate = ( - lambda context, sourceText, disambiguation, n: - QCoreApplication.translate( - context, - sourceText, - disambiguation, - QCoreApplication.CodecForTr, - n) - ) - - -def _none(): - """Internal option (used in installer)""" - - Mock = type("Mock", (), {"__getattr__": lambda Qt, attr: None}) - - Qt.__binding__ = "None" - Qt.__qt_version__ = "0.0.0" - Qt.__binding_version__ = "0.0.0" - Qt.QtCompat.loadUi = lambda fname: None - Qt.QtCompat.setSectionResizeMode = lambda *args, **kwargs: None - - for submodule in _common_members.keys(): - setattr(Qt, submodule, Mock()) - setattr(Qt, "_" + submodule, Mock()) - - -def _log(text): - if QT_VERBOSE: - sys.stdout.write(text + "\n") - - -def _convert(lines): - """Convert compiled .ui file from PySide2 to Qt.py - - Arguments: - lines (list): Each line of of .ui file - - Usage: - >> with open("myui.py") as f: - .. lines = _convert(f.readlines()) - - """ - - def parse(line): - line = line.replace("from PySide2 import", "from Qt import") - line = line.replace("QtWidgets.QApplication.translate", - "Qt.QtCompat.translate") - return line - - parsed = list() - for line in lines: - line = parse(line) - parsed.append(line) - - return parsed - - -def _cli(args): - """Qt.py command-line interface""" - import argparse - - parser = argparse.ArgumentParser() - parser.add_argument("--convert", - help="Path to compiled Python module, e.g. my_ui.py") - parser.add_argument("--compile", - help="Accept raw .ui file and compile with native " - "PySide2 compiler.") - parser.add_argument("--stdout", - help="Write to stdout instead of file", - action="store_true") - parser.add_argument("--stdin", - help="Read from stdin instead of file", - action="store_true") - - args = parser.parse_args(args) - - if args.stdout: - raise NotImplementedError("--stdout") - - if args.stdin: - raise NotImplementedError("--stdin") - - if args.compile: - raise NotImplementedError("--compile") - - if args.convert: - sys.stdout.write("#\n" - "# WARNING: --convert is an ALPHA feature.\n#\n" - "# See https://github.com/mottosso/Qt.py/pull/132\n" - "# for details.\n" - "#\n") - - # - # ------> Read - # - with open(args.convert) as f: - lines = _convert(f.readlines()) - - backup = "%s_backup%s" % os.path.splitext(args.convert) - sys.stdout.write("Creating \"%s\"..\n" % backup) - shutil.copy(args.convert, backup) - - # - # <------ Write - # - with open(args.convert, "w") as f: - f.write("".join(lines)) - - sys.stdout.write("Successfully converted \"%s\"\n" % args.convert) - - -def _install(): - # Default order (customise order and content via QT_PREFERRED_BINDING) - default_order = ("PySide2", "PyQt5", "PySide", "PyQt4") - preferred_order = list( - b for b in QT_PREFERRED_BINDING.split(os.pathsep) if b - ) - - order = preferred_order or default_order - - available = { - "PySide2": _pyside2, - "PyQt5": _pyqt5, - "PySide": _pyside, - "PyQt4": _pyqt4, - "None": _none - } - - _log("Order: '%s'" % "', '".join(order)) - - found_binding = False - for name in order: - _log("Trying %s" % name) - - try: - available[name]() - found_binding = True - break - - except ImportError as e: - _log("ImportError: %s" % e) - - except KeyError: - _log("ImportError: Preferred binding '%s' not found." % name) - - if not found_binding: - # If not binding were found, throw this error - raise ImportError("No Qt binding were found.") - - # Install individual members - for name, members in _common_members.items(): - try: - their_submodule = getattr(Qt, "_%s" % name) - except AttributeError: - continue - - our_submodule = getattr(Qt, name) - - # Enable import * - __all__.append(name) - - # Enable direct import of submodule, - # e.g. import Qt.QtCore - sys.modules[__name__ + "." + name] = our_submodule - - for member in members: - # Accept that a submodule may miss certain members. - try: - their_member = getattr(their_submodule, member) - except AttributeError: - _log("'%s.%s' was missing." % (name, member)) - continue - - setattr(our_submodule, member, their_member) - - # Backwards compatibility - Qt.QtCompat.load_ui = Qt.QtCompat.loadUi - - -_install() - - -"""Augment QtCompat - -QtCompat contains wrappers and added functionality -to the original bindings, such as the CLI interface -and otherwise incompatible members between bindings, -such as `QHeaderView.setSectionResizeMode`. - -""" - -Qt.QtCompat._cli = _cli -Qt.QtCompat._convert = _convert - -# Enable command-line interface -if __name__ == "__main__": - _cli(sys.argv[1:]) diff --git a/pype/vendor/capture_gui/vendor/__init__.py b/pype/vendor/capture_gui/vendor/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/pype/vendor/capture_gui/version.py b/pype/vendor/capture_gui/version.py deleted file mode 100644 index badefb16598..00000000000 --- a/pype/vendor/capture_gui/version.py +++ /dev/null @@ -1,9 +0,0 @@ -VERSION_MAJOR = 1 -VERSION_MINOR = 5 -VERSION_PATCH = 0 - - -version = '{}.{}.{}'.format(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH) -__version__ = version - -__all__ = ['version', 'version_info', '__version__']