def _line_number_paint(self, event): paint = QPainter(self._line_numbers) if not dcc.is_maya(): paint.fillRect(event.rect(), Qt.lightGray) else: paint.fillRect(event.rect(), Qt.black) block = self.firstVisibleBlock() block_number = block.blockNumber() top = int( self.blockBoundingGeometry(block).translated( self.contentOffset()).top()) bottom = int(top + self.blockBoundingGeometry(block).height()) while block.isValid() and top <= event.rect().bottom(): if block.isVisible() and bottom >= event.rect().top(): number = block_number + 1 if dcc.is_maya(): paint.setPen(Qt.lightGray) else: paint.setPen(Qt.black) paint.drawText(0, top, self._line_numbers.width(), self.fontMetrics().height(), Qt.AlignRight, str(number)) block = block.next() top = bottom bottom = top + self.blockBoundingRect(block).height() block_number += 1
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._drop_indicator_position = None self._name_filter = None self.setIndentation(25) self.setExpandsOnDoubleClick(False) self.setSortingEnabled(True) self.sortByColumn(0, Qt.AscendingOrder) if dcc.is_maya(): self.setAlternatingRowColors(dcc.get_version() < 2016) if not dcc.is_maya() and not not dcc.is_nuke(): palette = QPalette() palette.setColor(palette.Highlight, Qt.gray) self.setPalette(palette) 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) self.itemCollapsed.connect(self._on_item_collapsed)
def button_rect(self): r = self.tabBar().tabRect(self.count() - 1) if dcc.is_maya() and dcc.get_version() > 2015: rect = QRect(2, 0, 30, 31) else: rect = QRect(6, 3, 26, 17) if r.isValid(): if dcc.is_maya() and dcc.get_version() > 2015: rect.moveBottomLeft(r.bottomRight() + QPoint(1, 1)) else: rect.moveBottomLeft(r.bottomRight() + QPoint(3, -1)) return rect
def dock_window(window_class, min_width=300): """ Utility function to dock Maya window :param window_class: cls """ if not dcc.is_maya(): return import maya.cmds as cmds import maya.OpenMayaUI as OpenMayaUI try: cmds.deleteUI(window_class.name) except Exception: pass main_control = cmds.workspaceControl( window_class.name, ttc=["AttributeEditor", -1], iw=min_width, mw=True, wp='preferred', label=window_class.title) control_widget = OpenMayaUI.MQtUtil.findControl(window_class.name) control_wrap = qtutils.wrapinstance(int(control_widget), QWidget) control_wrap.setAttribute(Qt.WA_DeleteOnClose) win = window_class(parent=control_wrap) cmds.evalDeferred(lambda *args: cmds.workspaceControl(main_control, e=True, rs=True)) win.show() return win
def add_group(self, name='group', value=True, parent=None): """ Adds new group property to the group box :param name: str :param value: bool, default value :param parent: Option """ if type(name) == bool: name = 'group' name = self._get_unique_name(name, parent) option_object = self.get_option_object() self._option_group_class.FACTORY_CLASS = self.FACTORY_CLASS group = self._option_group_class(name=name, option_object=option_object, parent=self._parent) self._create_group_context_menu(group, group._context_menu) group.set_expanded(value) if self.__class__.__name__.endswith( 'OptionListGroup') or parent.__class__.__name__.endswith( 'OptionListGroup'): if dcc.is_maya(): group.group.set_inset_dark() self._handle_parenting(group, parent) self._write_options(clear=False) self._has_first_group = True return group
def __call__(cls, *args, **kwargs): if dcc.is_maya(): from tpDcc.dccs.maya.ui import dialog as maya_dialog return type.__call__(maya_dialog.MayaSelectFolderDialog, *args, **kwargs) else: return type.__call__(dialog.BaseSaveFileDialog, *args, **kwargs)
def _get_nodes_to_discard(self): """ Internal function that returns list of nodes that should be discarded during renaming process """ discard_nodes = self._default_nodes_to_discard[:] or list() if self._hide_default_scene_nodes_cbx and self._hide_default_scene_nodes_cbx.isChecked( ): discard_nodes.extend(dcc.default_scene_nodes(full_path=False)) # discard_nodes.extend(dcc.list_nodes(node_type='camera')) for btn in self._category_buttons: if not btn.isChecked(): dcc_type = btn.property('dcc_type') if dcc_type: discard_nodes.extend( dcc.list_nodes(node_type=btn.property('dcc_type'))) else: dcc_fn = btn.property('dcc_fn') if dcc_fn: dcc_args = btn.property('dcc_args') if dcc.is_maya(): valid_args = dict() for arg_name, arg_value in dcc_args.items(): valid_args[str(arg_name)] = arg_value nodes = getattr(maya.cmds, dcc_fn)(**valid_args) discard_nodes.extend(nodes) return list(set(discard_nodes))
def open(self, file_path=None): if not dcc.is_maya(): LOGGER.warning('Maya data must be accessed from within Maya!') return open_file = None if file_path: open_file = file_path if not open_file: file_path = self.get_file() if not path.is_file(file_path): LOGGER.warning('Could not open file: {}'.format(file_path)) return open_file = file_path helpers.display_info('Opening: {}'.format(open_file)) try: maya.cmds.file(open_file, f=True, o=True, iv=True, pr=True) except Exception: LOGGER.error('Impossible to open Maya file: {} | {}'.format(open_file, traceback.format_exc())) self._after_open() top_transforms = scene.get_top_dag_nodes(exclude_cameras=True) return top_transforms
def import_data(self, file_path=''): """ Loads data object :param file_path: str, file path of file to load """ if not dcc.is_maya(): LOGGER.warning('Data must be accessed from within Maya!') return if file_path: import_file = file_path else: import_file = self.get_file() if not path.is_file(import_file): LOGGER.warning('Impossible to import invalid data file: {}'.format(file_path)) return track = scene.TrackNodes() track.load('transform') scene.import_scene(import_file, do_save=False) self._after_open() transforms = track.get_delta() top_transforms = scene.get_top_dag_nodes_in_list(transforms) return top_transforms
def export_data(self, comment='-', create_version=True, *args, **kwargs): if not dcc.is_maya(): LOGGER.warning('Maya data must be saved from within Maya!') return file_path = self.get_file() osplatform.get_permission(file_path) self._handle_unknowns() self._clean_scene() if not file_path.endswith('.mb') and not file_path.endswith('.ma'): file_path = maya.cmds.workspace(query=True, rd=True) if self.maya_file_type == self.maya_ascii: file_path = maya.cmds.fileDialog(ds=1, fileFilter='Maya Ascii (*.ma)', dir=file_path) elif self.maya_file_type == self.maya_binary: file_path = maya.cmds.fileDialog(ds=1, fileFilter='Maya Binary (*.mb)', dir=file_path) if file_path: file_path = file_path[0] saved = scene.save_as(file_path) if saved: if create_version: version_file = version.VersionFile(file_path) # if scene.is_batch() or not version_file.has_versions(): version_file.save(comment) helpers.display_info('Saved {} data'.format(self.name)) return True return False
def add_prefix(self, data, reply): prefix_text = data.get('prefix_text', '') if not prefix_text: reply['success'] = False reply['msg'] = 'No prefix to add defined.' return if dcc.is_maya(): if prefix_text[0].isdigit(): reply['success'] = False reply[ 'msg'] = 'Maya does not supports names with digits as first character.' return rename_shape = data.get('rename_shape', True) search_hierarchy = data.get('hierarchy_check', False) selection_only = data.get('only_selection', True) filter_type = data.get('filter_type', None) dcc.add_name_prefix(prefix=prefix_text, filter_type=filter_type, search_hierarchy=search_hierarchy, selection_only=selection_only, rename_shape=rename_shape) reply['success'] = True
def ui(self): super(ManualRenameWidget, self).ui() manual_accordion = accordion.AccordionWidget() self.main_layout.addWidget(manual_accordion) self._renamer_widget = renamerwidget.renamer_widget( client=self._controller.client, parent=self) self._prefix_suffix_widget = prefixsuffixwidget.preffix_suffix_widget( client=self._controller.client, naming_config=self._model.naming_config, parent=self) self._number_side_widget = numbersidewidget.number_side_widget( client=self._controller.client, parent=self) self._namespace_widget = None if dcc.is_maya(): self._namespace_widget = namespacewidget.namespace_widget( client=self._controller.client, parent=self) self._replacer_widget = replacerwidget.replacer_widget( client=self._controller.client, parent=self) self._utils_widget = utilswidget.utils_widget( client=self._controller.client, parent=self) manual_accordion.add_item('Name', self._renamer_widget) manual_accordion.add_item('Prefix/Suffix', self._prefix_suffix_widget) manual_accordion.add_item('Number & Side', self._number_side_widget) if self._namespace_widget: manual_accordion.add_item('Namespace', self._namespace_widget) manual_accordion.add_item('Search & Replace', self._replacer_widget) manual_accordion.add_item('Utils', self._utils_widget) self._rename_btn = buttons.BaseButton('Rename') self._rename_btn.setIcon(resources.icon('rename')) self.main_layout.addLayout(dividers.DividerLayout()) self.main_layout.addWidget(self._rename_btn)
def __init__(self, parent=None, dragger_steps=None, slider_range=None, *args, **kwargs): if dragger_steps is None: dragger_steps = INT_SLIDER_DRAG_STEPS if slider_range is None: slider_range = [-100, 100] super(Slider, self).__init__(parent=parent, **kwargs) self._slider_range = slider_range self._dragger_steps = dragger_steps self._is_float = False self._default_value = 0 self._prev_value = 0 self._delta_value = 0 self._start_drag_pos = QPointF() self._real_start_drag_pos = QPointF() self._draggers = None if dcc.is_maya(): self._left_button = Qt.MidButton self._mid_button = Qt.LeftButton else: self._left_button = Qt.LeftButton self._mid_button = Qt.MidButton self.setFocusPolicy(Qt.StrongFocus) self.setOrientation(Qt.Horizontal) self.setRange(self._slider_range[0], self._slider_range[1])
def rename(self, **kwargs): hierarchy_check = self._model.hierarchy_check selection_type = self._model.selection_type nodes = utils.get_objects_to_rename(hierarchy_check=hierarchy_check, selection_type=selection_type, uuid=True) generated_names = self.generate_names(items=nodes, **kwargs) if not generated_names or len(nodes) != len(generated_names): LOGGER.warning('Impossible to rename because was impossible to generate some of the names ...') return if dcc.is_maya(): import maya.api.OpenMaya for item, new_name in zip(nodes, generated_names): if dcc.is_maya(): mobj = None if hasattr(item, 'handle'): mobj = item.handle.object() elif hasattr(item, 'object'): mobj = item.object() if mobj: try: dag_path = maya.api.OpenMaya.MDagPath.getAPathTo(mobj) full_name = dag_path.fullPathName() except Exception as exc: if hasattr(item, 'full_name'): full_name = item.full_name else: LOGGER.warning('Impossible to retrieve Maya node full path: {}'.format(item)) continue else: full_name = item else: if hasattr(item, 'full_name'): full_name = item.full_name else: full_name = item try: dcc.rename_node(full_name, new_name) if hasattr(item, 'obj') and hasattr(item, 'preview_name'): item.obj = item.preview_name item.preview_name = '' except Exception: LOGGER.error('Impossible to rename: {} to {} | {}'.format(full_name, new_name, traceback.format_exc()))
def __call__(self, *args, **kwargs): if dcc.is_maya(): from tpDcc.dccs.maya.core import sceneobject as maya_sceneobject return type.__call__(maya_sceneobject.MayaSceneObject, *args, **kwargs) else: return type.__call__(sceneobject.AbstractSceneObject, *args, **kwargs)
def setup_signals(self): self._automatic_suffix_btn.clicked.connect(self._controller.automatic_suffix) self._make_unique_name_btn.clicked.connect(self._controller.make_unique_name) self._remove_all_numbers_btn.clicked.connect(self._controller.remove_all_numbers) self._remove_tail_numbers_btn.clicked.connect(self._controller.remove_trail_numbers) if dcc.is_maya(): self._clean_unused_namespaces_btn.clicked.connect(self._controller.clean_unused_namespaces) self._namespace_editor_btn.clicked.connect(self._controller.open_namespace_editor) self._reference_editor_btn.clicked.connect(self._controller.open_reference_editor)
def __init__(self, name, parent=None): super(OptionGroup, self).__init__(parent) if dcc.is_maya(): if dcc.get_version() < 2016: # self.setFrameStyle(self.Panel | self.Raised) palette = self.palette() palette.setColor(self.backgroundRole(), QColor(80, 80, 80)) self.setAutoFillBackground(True) self.setPalette(palette) # else: # self.setFrameStyle(self.NoFrame) if dcc.is_maya(): self._rollout_style = GroupStyles.Maya else: self._rollout_style = GroupStyles.Square self._expanded = True self._clicked = False self._collapsible = True self.close_height = 28 self.setMinimumHeight(self.close_height) self.background_shade = 80 self.main_layout = layouts.VerticalLayout() self.main_layout.setContentsMargins(0, 0, 0, 0) self.main_layout.setSpacing(0) self.setLayout(self.main_layout) self.child_layout = layouts.VerticalLayout() self.child_layout.setContentsMargins(0, 2, 0, 3) self.child_layout.setSpacing(0) self.child_layout.setAlignment(Qt.AlignTop) self.header_layout = layouts.HorizontalLayout() self.main_layout.addSpacing(4) self.main_layout.addLayout(self.child_layout) self.setObjectName(name) self.setTitle(name)
def set_inset_dark(self): value = self.background_shade value -= 15 if dcc.is_maya(): if dcc.get_version() < 2016: self.setFrameStyle(self.Panel | self.Sunken) palette = self.palette() palette.setColor(self.backgroundRole(), QColor(value, value, value)) self.setAutoFillBackground(True) self.setPalette(palette)
def __call__(cls, *args, **kwargs): if cls._instance is None: if dcc.is_maya(): from tpDcc.dccs.maya.core import command cls._instance = type.__call__(command.MayaCommandRunner, *args, **kwargs) else: cls._instance = type.__call__(BaseCommandRunner, *args, **kwargs) return cls._instance
def ui(self): super(UtilsView, self).ui() base_layout = layouts.VerticalLayout(spacing=2, margins=(0, 0, 0, 0)) self.main_layout.addLayout(base_layout) name_utils_layout = layouts.HorizontalLayout(spacing=5, margins=(0, 0, 0, 0)) self._automatic_suffix_btn = buttons.BaseButton('Automatic Suffix', parent=self) self._automatic_suffix_btn.setIcon(resources.icon('suffix')) self._make_unique_name_btn = buttons.BaseButton('Make Unique Name', parent=self) self._make_unique_name_btn.setIcon(resources.icon('name')) name_utils_layout.addWidget(self._automatic_suffix_btn) name_utils_layout.addWidget(self._make_unique_name_btn) if dcc.is_maya(): namespace_utils_layout = layouts.HorizontalLayout(spacing=5, margins=(0, 0, 0, 0)) self._clean_unused_namespaces_btn = buttons.BaseButton('Unused Namespaces', parent=self) self._clean_unused_namespaces_btn.setIcon(resources.icon('clean')) self._namespace_editor_btn = buttons.BaseButton('Namespace Editor', parent=self) self._namespace_editor_btn.setIcon(resources.icon('browse_page')) self._reference_editor_btn = buttons.BaseButton('Reference Editor', parent=self) self._reference_editor_btn.setIcon(resources.icon('connect')) namespace_utils_layout.addWidget(self._clean_unused_namespaces_btn) namespace_utils_layout.addWidget(self._namespace_editor_btn) namespace_utils_layout.addWidget(self._reference_editor_btn) index_utils_layout = layouts.HorizontalLayout(spacing=5, margins=(0, 0, 0, 0)) self._remove_all_numbers_btn = buttons.BaseButton('Remove All Numbers', parent=self) self._remove_all_numbers_btn.setIcon(resources.icon('trash')) self._remove_tail_numbers_btn = buttons.BaseButton('Remove Tail Numbers', parent=self) self._remove_tail_numbers_btn.setIcon(resources.icon('trash')) index_utils_layout.addWidget(self._remove_all_numbers_btn) index_utils_layout.addWidget(self._remove_tail_numbers_btn) base_layout.addLayout(name_utils_layout) base_layout.addLayout(dividers.DividerLayout()) base_layout.addLayout(index_utils_layout) if dcc.is_maya(): base_layout.addLayout(dividers.DividerLayout()) base_layout.addLayout(namespace_utils_layout)
def __call__(self, *args, **kwargs): as_class = kwargs.get('as_class', True) if dcc.is_maya(): from tpDcc.libs.datalibrary.dccs.maya.core import mirrortable if as_class: return mirrortable.MayaMirrorTable else: return type.__call__(mirrortable.MayaMirrorTable, *args, **kwargs) else: if as_class: return BaseMirrorTable else: return type.__call__(BaseMirrorTable, *args, **kwargs)
def __call__(cls, *args, **kwargs): as_class = kwargs.pop('as_class', False) if dcc.is_maya(): from tpDcc.dccs.maya.ui import progress if as_class: return progress.MayaProgressBar else: return type.__call__(progress.MayaProgressBar, *args, **kwargs) else: if as_class: return BaseProgressBar else: return type.__call__(BaseProgressBar, *args, **kwargs)
def __call__(cls, *args, **kwargs): as_class = kwargs.pop('as_class', False) if dcc.is_maya(): from tpDcc.dccs.maya.ui import dialog as maya_dialog if as_class: return maya_dialog.MayaSelectFolderDialog else: return type.__call__(maya_dialog.MayaSelectFolderDialog, *args, **kwargs) else: if as_class: return dialog.BaseSelectFolderDialog else: return type.__call__(dialog.BaseSelectFolderDialog, *args, **kwargs)
def custom_import_load(self, assign_map, module_name): found = list() if module_name == 'cmds': if assign_map: if module_name in assign_map: return [] if dcc.is_maya(): import maya.cmds as cmds functions = dir(cmds) return functions return found
def _fill_background(self, widget): """ Internal function used to paint the background color of the group :param widget: Option """ palette = widget.palette() if not dcc.is_maya(): palette.setColor(widget.backgroundRole(), Qt.gray) else: palette.setColor(widget.backgroundRole(), QColor(35, 150, 245, 255)) widget.setAutoFillBackground(True) widget.setPalette(palette)
def __call__(self, *args, **kwargs): as_class = kwargs.get('as_class', True) if dcc.is_maya(): from tpDcc.libs.datalibrary.dccs.maya.core import transfer if as_class: return transfer.MayaDataTransferObject else: return type.__call__(transfer.MayaDataTransferObject, *args, **kwargs) else: if as_class: return BaseDataTransferObject else: return type.__call__(BaseDataTransferObject, *args, **kwargs)
def _launch(self, *args, **kwargs): """ Internal function for launching the tool :return: """ self._stats.start_time = time.time() exc_type, exc_value, exc_tb = None, None, None try: kwargs['settings'] = self._settings kwargs['config'] = self._config kwargs['dev'] = self._dev tool_data = self.launch(*args, **kwargs) if tool_data and tool_data.get('tool') is not None: tool_data['tool'].ID = self.ID tool_data['tool'].PACKAGE = self.PACKAGE if self._settings.get('dockable', False): uid = None # TODO: Add option in settings to check if a tool can be opened multiple times or not # TODO: Make this piece of code DCC agnostic # if multiple_tools: # uid = "{0} [{1}]".format(self.uiData["label"], str(uuid.uuid4())) ui_label = self._config.get('name', default='') ui_icon = self._config.get('icon', default='tpdcc') if dcc.is_maya(): from tpDcc.dccs.maya.ui import window bootstrap_widget = window.BootStrapWidget( tool_data['tool'], title=ui_label, icon=resources.icon(ui_icon), uid=uid) tool_data['bootstrap'] = bootstrap_widget tool_data['bootstrap'].show( retain=False, dockable=True, tabToControl=('AttributeEditor', -1), floating=False) self._bootstrap.append(bootstrap_widget) except Exception: exc_type, exc_value, exc_tb = sys.exc_info() traceback.print_exception(exc_type, exc_value, exc_tb) raise finally: tb = None if exc_type and exc_value and exc_tb: tb = traceback.format_exception(exc_type, exc_value, exc_tb) self._stats.finish(tb) return tool_data
def set_sub_path_warning(self, flag): """ Sets whether or not sub path filter text should indicate a warning :param flag: bool """ if flag: if dcc.is_maya(): self._sub_path_filter.setStyleSheet( 'background-color: rgb(255, 100, 100);') else: self._sub_path_filter.setStyleSheet( 'background-color: rgb(255, 150, 150);') else: self._sub_path_filter.setStyleSheet('')
def _line_number_highlight(self): extra_selection = QTextEdit.ExtraSelection() selections = [extra_selection] if not self.isReadOnly(): selection = QTextEdit.ExtraSelection() if dcc.is_maya(): line_color = QColor(Qt.black) else: line_color = QColor(Qt.lightGray) selection.format.setBackground(line_color) selection.format.setProperty(QTextFormat.FullWidthSelection, True) selection.cursor = self.textCursor() selection.cursor.clearSelection() selections.append(selection) self.setExtraSelections(selections)
def show_color_editor(self): if dcc.is_maya(): import maya.cmds as cmds cmds.colorEditor(rgbValue=(self._color.redF(), self._color.greenF(), self._color.blueF())) if not cmds.colorEditor(query=True, result=True): return new_color = cmds.colorEditor(query=True, rgbValue=True) self.color = QColor.fromRgbF(new_color[0], new_color[1], new_color[2]) self.colorChanged.emit() else: raise RuntimeError( 'Code Editor is not available for DCC: {}'.format( dcc.get_name()))