Ejemplo n.º 1
0
    def __init__(self, parent=None):
        super(TreeWidget, self).__init__(parent)

        self._auto_add_sub_items = True
        self._title_text_index = 0
        self._text_edit = True
        self._edit_state = None
        self._current_name = None
        self._old_name = None
        self._current_item = None
        self._last_item = None
        self._drop_indicator_rect = QRect()

        self.setIndentation(25)
        self.setExpandsOnDoubleClick(False)

        if tp.Dcc.get_name() == tp.Dccs.Maya:
            self.setAlternatingRowColors(tp.Dcc.get_version() < 2016)

        self.setSortingEnabled(True)
        self.sortByColumn(0, Qt.AscendingOrder)
        if not tp.is_maya() and not not tp.is_nuke():
            palette = QPalette()
            palette.setColor(palette.Highlight, Qt.gray)
            self.setPalette(palette)

        self.itemCollapsed.connect(self._on_item_collapsed)
        self.itemActivated.connect(self._on_item_activated)
        self.itemChanged.connect(self._on_item_changed)
        self.itemSelectionChanged.connect(self._on_item_selection_changed)
        self.itemClicked.connect(self._on_item_clicked)
        self.itemExpanded.connect(self._on_item_expanded)
Ejemplo n.º 2
0
    def thumbnail_capture(self, show=False):
        """
        Captures a playblast and saves it to the temporal thumbnail path
        :param show: bool
        """

        if not tp.is_maya():
            return

        options = self._options_widget.values()
        start_frame, end_frame = options.get('frameRange', [None, None])
        step = options.get('byFrame', 1)

        if not qtutils.is_control_modifier():
            self.show_by_frame_dialog()

        if not self._temp_path or not os.path.isdir(self._temp_path):
            self._temp_path = tempfile.mkdtemp()
        self._temp_path = os.path.join(self._temp_path, 'thumbnail.jpg')

        try:
            thumbnail.ThumbnailCaptureDialog.thumbnail_capture(
                path=self._temp_path,
                show=show,
                start_frame=start_frame,
                end_frame=end_frame,
                step=step,
                clear_cache=False,
                captured=self._on_thumbnail_captured)
        except Exception as e:
            messagebox.MessageBox.critical(self.library_window(),
                                           'Error while capturing thumbnail',
                                           str(e))
            tpQtLib.logger.error(traceback.format_exc())
Ejemplo n.º 3
0
def run():
    if tp.is_maya():
        win = window.dock_window(project=artellapipe.solstice,
                                 window_class=SolsticeAssetsLibraryWidget)
        return win
    else:
        win = SolsticeAssetsLibrary(project=artellapipe.solstice)
        win.show()
        return win
Ejemplo n.º 4
0
    def set_sub_path_warning(self, flag):
        """
        Updates the style of the sub path QLineEdit depending on the app that uses this widget
        :param flag: bool
        """

        if flag:
            if not tp.is_maya():
                self.sub_path_filter.setStyleSheet('background-color: rgb(255, 150, 150);')
            else:
                self.sub_path_filter.setStyleSheet('background-color: rgb(255, 100, 100);')
        else:
            self.sub_path_filter.setStyleSheet('')
    def import_builder(self):
        """
        Function that imports in the scene the builder file
        """

        if not tp.is_maya():
            tp.logger.warning(
                'Import model functionality is only available in Maya')
            return

        assert self._asset

        track = scene.TrackNodes()
        track.load('transform')
        self._asset.import_builder_file()
        mc.refresh()
        imported_objs = track.get_delta()
        mc.select(imported_objs)
        mc.viewFit(animate=True)
        mc.select(clear=True)
    def import_model(self):
        """
        Function that import latest working file of the asset model
        """
        if not tp.is_maya():
            tp.logger.warning(
                'Import model functionality is only available in Maya')
            return

        assert self._asset

        track = scene.TrackNodes()
        track.load('transform')
        self._asset.import_model_file(status='working')
        mc.refresh()
        imported_objs = track.get_delta()
        self._geo['model'] = imported_objs
        mc.select(imported_objs)
        mc.viewFit(animate=True)
        mc.select(clear=True)
Ejemplo n.º 7
0
    def _paint_drop_indicator(self, painter):
        """
        Internal function used to paint the drop indicator manually
        :param painter: QPainter
        """

        if self.state() == QAbstractItemView.DraggingState:
            opt = QStyleOption()
            opt.initFrom(self)
            opt.rect = self._drop_indicator_rect
            rect = opt.rect

            color = Qt.black
            if tp.is_maya():
                color = Qt.white

            brush = QBrush(QColor(color))
            pen = QPen(brush, 1, Qt.DotLine)
            painter.setPen(pen)
            if rect.height() == 0:
                painter.drawLine(rect.topLeft(), rect.topRight())
            else:
                painter.drawRect(rect)
Ejemplo n.º 8
0
import os
import tempfile
import traceback

from Qt.QtCore import *
from Qt.QtWidgets import *
from Qt.QtGui import *

import tpQtLib
import tpDccLib as tp
from tpQtLib.core import base, qtutils
from tpQtLib.widgets import directory, formwidget, messagebox
from tpQtLib.widgets.library import widgets

if tp.is_maya():
    from tpMayaLib.core import thumbnail


class SaveWidget(base.BaseWidget, object):
    def __init__(self, item, settings, temp_path=None, parent=None):

        self._item = None
        self._script_job = None
        self._options_widget = None
        self._sequence_path = None
        self._icon_path = ''
        self._settings = settings
        self._temp_path = temp_path

        super(SaveWidget, self).__init__(parent=parent)
Ejemplo n.º 9
0
class PythonHighlighter(QSyntaxHighlighter):
    """
    Syntax highlighter for the Python language.
    """

    # Python keywords
    keywords = [
        'and', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif',
        'else', 'except', 'exec', 'finally', 'for', 'from', 'global', 'if',
        'import', 'in', 'is', 'lambda', 'not', 'or', 'pass', 'print', 'raise',
        'return', 'try', 'while', 'yield', 'None', 'True', 'False', 'process',
        'show'
    ]

    if tp.is_maya():
        keywords += ['cmds', 'pm', 'mc', 'pymel']

    # Python operators
    operators = [
        '=',
        # Comparison
        '==',
        '!=',
        '<',
        '<=',
        '>',
        '>=',
        # Arithmetic
        '\+',
        '-',
        '\*',
        '/',
        '//',
        '\%',
        '\*\*',
        # In-place
        '\+=',
        '-=',
        '\*=',
        '/=',
        '\%=',
        # Bitwise
        '\^',
        '\|',
        '\&',
        '\~',
        '>>',
        '<<',
    ]

    # Python braces
    braces = [
        '\{',
        '\}',
        '\(',
        '\)',
        '\[',
        '\]',
    ]

    def __init__(self, document):
        super(PythonHighlighter, self).__init__(document)

        # Multi-line strings (expression, flag, style)
        # FIXME: The triple-quotes in these two lines will mess up the
        # syntax highlighting from this point onward
        self.tri_single = (QRegExp("'''"), 1, syntax_styles('string2'))
        self.tri_double = (QRegExp('"""'), 2, syntax_styles('string2'))

        rules = []

        # Keyword, operator, and brace rules
        rules += [(r'\b%s\b' % w, 0, syntax_styles('keyword'))
                  for w in PythonHighlighter.keywords]
        rules += [(r'%s' % o, 0, syntax_styles('operator'))
                  for o in PythonHighlighter.operators]
        rules += [(r'%s' % b, 0, syntax_styles('brace'))
                  for b in PythonHighlighter.braces]

        # All other rules
        rules += [
            # 'self'
            (r'\bself\b', 0, syntax_styles('self')),

            # Double-quoted string, possibly containing escape sequences
            (r'"[^"\\]*(\\.[^"\\]*)*"', 0, syntax_styles('string')),
            # Single-quoted string, possibly containing escape sequences
            (r"'[^'\\]*(\\.[^'\\]*)*'", 0, syntax_styles('string')),

            # 'def' followed by an identifier
            # (r'\bdef\b\s*(\w+)', 0, syntax_styles('defclass')),
            # 'class' followed by an identifier
            # (r'\bclass\b\s*(\w+)', 0, syntax_styles('defclass')),

            # From '#' until a newline
            (r'#[^\n]*', 0, syntax_styles('comment')),
            # ('\\b\.[a-zA-Z_]+\\b(?=\()', 0, syntax_styles('bold')),
            # Numeric literals
            (r'\b[+-]?[0-9]+[lL]?\b', 0, syntax_styles('numbers')),
            (r'\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b', 0, syntax_styles('numbers')),
            (r'\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b', 0,
             syntax_styles('numbers')),
        ]

        # Build a QRegExp for each pattern
        self.rules = [(QRegExp(pat), index, fmt)
                      for (pat, index, fmt) in rules]

    def highlightBlock(self, text):
        """
        Apply syntax highlighting to the given block of text.
        """

        # Do other syntax formatting
        for expression, nth, format_value in self.rules:
            index = expression.indexIn(text, 0)

            while index >= 0:
                # We actually want the index of the nth match
                index = expression.pos(nth)
                length = len(expression.cap(nth))
                self.setFormat(index, length, format_value)
                index = expression.indexIn(text, index + length)

        self.setCurrentBlockState(0)

        # Do multi-line strings
        in_multiline = self.match_multiline(text, *self.tri_single)
        if not in_multiline:
            in_multiline = self.match_multiline(text, *self.tri_double)

    def match_multiline(self, text, delimiter, in_state, style):
        """
        Do highlighting of multi-line strings. ``delimiter`` should be a
        ``QRegExp`` for triple-single-quotes or triple-double-quotes, and
        ``in_state`` should be a unique integer to represent the corresponding
        state changes when inside those strings. Returns True if we're still
        inside a multi-line string when this function is finished.
        """

        # If inside triple-single quotes, start at 0
        if self.previousBlockState() == in_state:
            start = 0
            add = 0
        # Otherwise, look for the delimiter on this line
        else:
            start = delimiter.indexIn(text)
            # Move past this match
            add = delimiter.matchedLength()

        # As long as there's a delimiter match on this line...
        while start >= 0:
            # Look for the ending delimiter
            end = delimiter.indexIn(text, start + add)
            # Ending delimiter on this line?
            if end >= add:
                length = end - start + add + delimiter.matchedLength()
                self.setCurrentBlockState(0)
            # No; multi-line string
            else:
                self.setCurrentBlockState(in_state)
                length = len(text) - start + add
            # Apply formatting
            self.setFormat(start, length, style)
            # Look for the next match
            start = delimiter.indexIn(text, start + length)

        # Return True if still inside a multi-line string, False otherwise
        if self.currentBlockState() == in_state:
            return True
        else:
            return False
Ejemplo n.º 10
0
def syntax_styles(name):
    if name == 'keyword':
        if tp.is_maya():
            return get_syntax_format('green', 'bold')
        if not tp.is_maya():
            return get_syntax_format([0, 150, 150], 'bold')
    if name == 'operator':
        if tp.is_maya():
            return get_syntax_format('gray')
        if not tp.is_maya():
            return get_syntax_format('darkGray')
    if name == 'brace':
        if tp.is_maya():
            return get_syntax_format('lightGray')
        if not tp.is_maya():
            return get_syntax_format('darkGray')
    if name == 'defclass':
        if tp.is_maya():
            return get_syntax_format(None, 'bold')
        if not tp.is_maya():
            return get_syntax_format(None, 'bold')
    if name == 'string':
        if tp.is_maya():
            return get_syntax_format([230, 230, 0])
        if not tp.is_maya():
            return get_syntax_format('blue')
    if name == 'string2':
        if tp.is_maya():
            return get_syntax_format([230, 230, 0])
        if not tp.is_maya():
            return get_syntax_format('lightGreen')
    if name == 'comment':
        if tp.is_maya():
            return get_syntax_format('red')
        if not tp.is_maya():
            return get_syntax_format('red')
    if name == 'self':
        if tp.is_maya():
            return get_syntax_format(None, 'italic')
        if not tp.is_maya():
            return get_syntax_format('black', 'italic')
    if name == 'bold':
        return get_syntax_format(None, 'bold')
    if name == 'numbers':
        if tp.is_maya():
            return get_syntax_format('cyan')
        if not tp.is_maya():
            return get_syntax_format('brown')
Ejemplo n.º 11
0
    def _on_generate_shot(self):
        """
        Internal callback function that is called when Generate Shot button is pressed
        """

        if not tp.is_maya():
            logger.warning('Shot Generation is only available in Maya!')
            return

        all_hierarchy = self._shot_hierarchy.all_hierarchy()
        if not all_hierarchy:
            logger.warning('No items added to ShotAssembler list!')
            return

        pre_overrides = list()
        post_overrides = list()
        for shot_override in self._shot_overrides.get_loaded_overrides():
            if shot_override.OVERRIDE_STEP == override.OverrideExecutionStep.POST:
                post_overrides.append(shot_override)
            else:
                pre_overrides.append(pre_overrides)

        tp.Dcc.new_file()

        self._progress.set_minimum(0)
        self._progress.set_maximum(
            len(all_hierarchy) + len(pre_overrides) + len(post_overrides) + 3)
        self._progress.set_value(0)
        self._progress.setVisible(True)
        self._progress.set_text('Generating Shot ...')
        self.repaint()

        self._progress.set_value(self._progress.value() + 1)
        self._progress.set_text('Applying Pre Load Overrides ...')
        self.repaint()

        for pre_override in pre_overrides:
            self._progress.set_value(self._progress.value() + 1)
            self._progress.set_text('Applying Pre Load Override: {}'.format(
                pre_override.OVERRIDE_NAME))
            self.repaint()
            pre_override.apply(all_hierarchy)

        for i, node_asset in enumerate(all_hierarchy):
            self._progress.set_value(self._progress.value() + 1)
            self._progress.set_text('Loading Asset: {}'.format(
                node_asset.asset_file))
            self.repaint()
            node_asset.load()

        self._progress.set_value(self._progress.value() + 1)
        self._progress.set_text('Applying Post Load Overrides ...')
        self.repaint()

        for post_override in post_overrides:
            self._progress.set_value(self._progress.value() + 1)
            self._progress.set_text('Applying Post Load Override: {}'.format(
                post_override.OVERRIDE_NAME))
            self.repaint()
            post_override.apply()

        tp.Dcc.clear_selection()

        tp.Dcc.fit_view(animation=True)

        self._progress.set_value(self._progress.value() + 1)
        self._progress.set_text('Loading Shaders ...')
        self.repaint()

        shader.load_all_scene_shaders(project=self._project)

        self._progress.set_value(0)
        self._progress.set_text('')
        self._progress.setVisible(False)
Ejemplo n.º 12
0
    def ui(self):
        super(AlembicImporter, self).ui()

        buttons_layout = QGridLayout()
        self.main_layout.addLayout(buttons_layout)

        shot_name_lbl = QLabel('Shot Name: ')
        self._shot_line = QLineEdit()
        buttons_layout.addWidget(shot_name_lbl, 1, 0, 1, 1, Qt.AlignRight)
        buttons_layout.addWidget(self._shot_line, 1, 1)
        shot_name_lbl.setVisible(False)
        self._shot_line.setVisible(False)

        folder_icon = resource.ResourceManager().icon('folder')
        alembic_path_layout = QHBoxLayout()
        alembic_path_layout.setContentsMargins(2, 2, 2, 2)
        alembic_path_layout.setSpacing(2)
        alembic_path_widget = QWidget()
        alembic_path_widget.setLayout(alembic_path_layout)
        alembic_path_lbl = QLabel('Alembic File: ')
        self._alembic_path_line = QLineEdit()
        self._alembic_path_line.setReadOnly(True)
        self._alembic_path_btn = QPushButton()
        self._alembic_path_btn.setIcon(folder_icon)
        self._alembic_path_btn.setIconSize(QSize(18, 18))
        self._alembic_path_btn.setStyleSheet(
            "background-color: rgba(255, 255, 255, 0); border: 0px solid rgba(255,255,255,0);"
        )
        alembic_path_layout.addWidget(self._alembic_path_line)
        alembic_path_layout.addWidget(self._alembic_path_btn)
        buttons_layout.addWidget(alembic_path_lbl, 2, 0, 1, 1, Qt.AlignRight)
        buttons_layout.addWidget(alembic_path_widget, 2, 1)

        import_mode_layout = QHBoxLayout()
        import_mode_layout.setContentsMargins(2, 2, 2, 2)
        import_mode_layout.setSpacing(2)
        import_mode_widget = QWidget()
        import_mode_widget.setLayout(import_mode_layout)
        import_mode_lbl = QLabel('Import mode: ')
        self._create_radio = QRadioButton('Create')
        self._add_radio = QRadioButton('Add')
        self._merge_radio = QRadioButton('Merge')
        self._create_radio.setChecked(True)
        import_mode_layout.addWidget(self._create_radio)
        import_mode_layout.addWidget(self._add_radio)
        import_mode_layout.addWidget(self._merge_radio)
        buttons_layout.addWidget(import_mode_lbl, 3, 0, 1, 1, Qt.AlignRight)
        buttons_layout.addWidget(import_mode_widget, 3, 1)
        import_mode_lbl.setVisible(False)
        import_mode_widget.setVisible(False)

        self._auto_display_lbl = QLabel('Auto Display Smooth?: ')
        self._auto_smooth_display = QCheckBox()
        self._auto_smooth_display.setChecked(True)
        buttons_layout.addWidget(self._auto_display_lbl, 4, 0, 1, 1,
                                 Qt.AlignRight)
        buttons_layout.addWidget(self._auto_smooth_display, 4, 1)

        if tp.is_maya():
            maya_gpu_cache_lbl = QLabel('Import Alembic as GPU Cache?')
            self._maya_gpu_cache_cbx = QCheckBox()
            self._maya_gpu_cache_cbx.setChecked(True)
            buttons_layout.addWidget(maya_gpu_cache_lbl, 5, 0, 1, 1,
                                     Qt.AlignRight)
            buttons_layout.addWidget(self._maya_gpu_cache_cbx, 5, 1)
        elif tp.is_houdini():
            hou_archive_abc_node_lbl = QLabel('Import Alembic as Archive?')
            self._hou_archive_abc_node_cbx = QCheckBox()
            buttons_layout.addWidget(hou_archive_abc_node_lbl, 5, 0, 1, 1,
                                     Qt.AlignRight)
            buttons_layout.addWidget(self._hou_archive_abc_node_cbx, 5, 1)

        self.main_layout.addLayout(splitters.SplitterLayout())

        buttons_layout = QHBoxLayout()
        buttons_layout.setContentsMargins(2, 2, 2, 2)
        buttons_layout.setSpacing(2)
        self.main_layout.addLayout(buttons_layout)
        self._import_btn = QPushButton('Import')
        self._import_btn.setIcon(resource.ResourceManager().icon('import'))
        self._import_btn.setSizePolicy(QSizePolicy.Expanding,
                                       QSizePolicy.Preferred)
        self._reference_btn = QPushButton('Reference')
        self._reference_btn.setIcon(
            resource.ResourceManager().icon('reference'))
        self._reference_btn.setSizePolicy(QSizePolicy.Expanding,
                                          QSizePolicy.Preferred)
        buttons_layout.addWidget(self._import_btn)
        buttons_layout.addWidget(self._reference_btn)

        if tp.is_houdini():
            self._reference_btn.setEnabled(False)
Ejemplo n.º 13
0
    def reference_alembic(project,
                          alembic_path,
                          namespace=None,
                          fix_path=False):
        """
        References alembic file in current DCC scene
        :param project: ArtellaProject
        :param alembic_path: str
        :param namespace: str
        :param fix_path: bool
        """

        if not alembic_path or not os.path.isfile(alembic_path):
            LOGGER.warning(
                'Alembic file {} does not exits!'.format(alembic_path))
            return None

        abc_name = os.path.basename(alembic_path).split('.')[0]
        tag_json_file = os.path.join(
            os.path.dirname(alembic_path),
            os.path.basename(alembic_path).replace('.abc', '_abc.info'))
        if not os.path.isfile(tag_json_file):
            LOGGER.warning('No Alembic Info file found!')
            return

        with open(tag_json_file, 'r') as f:
            tag_info = json.loads(f.read())
        if not tag_info:
            LOGGER.warning('No Alembic Info loaded!')
            return

        root = tp.Dcc.create_empty_group(name=abc_name)
        AlembicImporter._add_tag_info_data(project, tag_info, root)
        sel = [root]
        sel = sel or None

        if not namespace:
            namespace = abc_name

        new_nodes = alembic.reference_alembic(project=project,
                                              alembic_file=alembic_path,
                                              namespace=namespace,
                                              fix_path=fix_path)
        if not new_nodes:
            LOGGER.warning(
                'Error while reference Alembic file: {}'.format(alembic_path))
            return
        for obj in new_nodes:
            if not tp.Dcc.object_exists(obj):
                continue
            if not tp.Dcc.node_type(obj) == 'transform':
                continue
            obj_parent = tp.Dcc.node_parent(obj)
            if obj_parent:
                continue
            tp.Dcc.set_parent(obj, sel[0])
        tp.Dcc.select_object(sel[0])

        new_nodes.insert(0, sel[0])

        # After parenting referenced nodes, full path changes, here we update node paths
        if tp.is_maya():
            new_paths = list()
            for n in new_nodes:
                if tp.Dcc.object_exists(n):
                    new_paths.append(n)
                else:
                    if n.startswith('|'):
                        new_paths.append('{}{}'.format(sel[0], n))
                    else:
                        new_paths.append('{}|{}'.format(sel[0], n))
            return new_paths

        return new_nodes