def setIcon(self, column, icon, color=None): """ Overrides base QTreeWidgetItem setIcon function :param column: int or str :param icon: QIcon :param color: QColor or None """ is_app_running = bool(QApplication.instance()) if not is_app_running: return if python.is_string(icon): if not os.path.exists(icon): color = color or QColor(255, 255, 255, 20) icon = resources.icon('image', color=color) else: icon = QIcon(icon) if python.is_string(column): self._icon[column] = icon else: self._pixmap[column] = None super(ItemView, self).setIcon(column, icon) self.update_icon()
def _format_option_value(self, value): """ Internal function used to format object option value :param value: variant :return: variant """ new_value = value option_type = None if type(value) == list: try: option_type = value[1] except Exception: pass value = value[0] if option_type == 'dictionary': new_value = value[0] dict_order = value[1] if type(new_value) == list: new_value = new_value[0] new_value = python.order_dict_by_list_of_keys( new_value, dict_order) return new_value elif option_type == 'list' or option_type == 'file' or option_type == 'vector3f': return value elif option_type == 'combo': try: return value[1] except Exception: return [-1, ''] else: new_value = self._format_custom_option_value( option_type, value) if not option_type == 'script': if python.is_string(value): eval_value = None try: if value: eval_value = eval(value) except Exception: pass if eval_value: if type(eval_value) in [list, tuple, dict]: new_value = eval_value value = eval_value if python.is_string(value): if value.find(',') > -1: new_value = value.split(',') LOGGER.debug('Formatted value: {}'.format(new_value)) return new_value
def confirm_dialog(title, message, button=None, cancel_button=None, default_button=None, dismiss_string=None): """ Shows DCC confirm dialog :param title: :param message: :param button: :param cancel_button: :param default_button: :param dismiss_string: :return: """ from tpDcc.libs.qt.widgets import messagebox from Qt.QtWidgets import QDialogButtonBox new_buttons = None if button: if python.is_string(button): if button == 'Yes': new_buttons = QDialogButtonBox.Yes elif button == 'No': new_buttons = QDialogButtonBox.No elif isinstance(button, (tuple, list)): for i, btn in enumerate(button): if i == 0: if btn == 'Yes': new_buttons = QDialogButtonBox.Yes elif btn == 'No': new_buttons = QDialogButtonBox.No else: if btn == 'Yes': new_buttons = new_buttons | QDialogButtonBox.Yes elif btn == 'No': new_buttons = new_buttons | QDialogButtonBox.No if new_buttons: buttons = new_buttons else: buttons = button or QDialogButtonBox.Yes | QDialogButtonBox.No if cancel_button: if python.is_string(cancel_button): if cancel_button == 'No': buttons = buttons | QDialogButtonBox.No elif cancel_button == 'Cancel': buttons = buttons | QDialogButtonBox.Cancel else: buttons = buttons | QDialogButtonBox.Cancel return messagebox.MessageBox.question(None, title=title, text=message, buttons=buttons)
def get_skin_cluster(dag_path=None): """ Loops through the DAG hierarchy of the given DAG path finding a skin cluster :param dag_path: OpenMaya.MDagPath :return: (OpenMayaAnim.MFnSkinCluster, str), Skin cluster object and skin cluster node name """ if not dag_path: return None, None if not python.is_string(dag_path): dag_path = dag_path.fullPathName() skin_cluster = maya.cmds.ls(maya.cmds.listHistory(dag_path), type='skinCluster') if not skin_cluster: return None, None skin_name = skin_cluster[0] selection_list = api.SelectionList() selection_list.create_by_name(skin_name) skin_node = selection_list.get_depend_node(0) skin_node = maya.api.OpenMayaAnim.MFnSkinCluster(skin_node) return skin_node, skin_name
def convert_2_hex(color): """ Converts given color to hexadecimal value :param color: :return: str """ if python.is_string(color): if string_is_hex(color): return color else: if color.startswith('rgba'): color = [int(value.strip()) for value in color.split('rgba(')[-1].split(')')[0].split(',')] elif color.startswith('rgb'): color = [int(value.strip()) for value in color.split('rgb(')[-1].split(')')[0].split(',')] hex = '#' for var in color: var = format(var, 'x') if len(var) == 1: hex += '0' + str(var) else: hex += str(var) if len(hex) == 9: hex = '#{}{}'.format(hex[-2:], hex[1:-2]) return hex
def set_icon(self, icon=None, highlight=False): """ Sets the icon of the window dragger :param icon: QIcon :param highlight: bool """ icon = icon or self._window.windowIcon() if icon and python.is_string(icon): icon = resources.icon(icon) if not icon or icon.isNull(): icon = resources.icon('tpDcc') size = self.DEFAULT_LOGO_ICON_SIZE if highlight: self._logo_button.set_icon( [icon], colors=[None], tint_composition=QPainter.CompositionMode_Plus, size=size, icon_scaling=[1], color_offset=0, grayscale=True) else: self._logo_button.set_icon([icon], colors=None, size=size, icon_scaling=[1], color_offset=0) self._logo_button.set_icon_idle(icon)
def get(self, setting_name, default_value=None, setting_group=None, begin_group=None): """ Returns the setting stored with the given name :param setting_name: str :param default_value: variant :param default_value: variant :param setting_group: str :return: """ if setting_group: setting_name = '{}/{}'.format(setting_group, setting_name) if begin_group: self.beginGroup(begin_group) val = self.value(setting_name) if not val: if begin_group: self.endGroup() return default_value if python.is_string(val) and val.lower() in ['true', 'false']: if begin_group: self.endGroup() return strings.to_boolean(val) if begin_group: self.endGroup() return val
def set_slot_model(character_node, slot, model): """ Adds a model to a slot in the characterization map :param character_node: FBCharacter :param slot: str, full name of character slot :param model: str or FBModel, model to add to the slot (can be name or model object) :return: """ if python.is_string(model): obj = node.get_model_node_by_name(model) if not obj: logger.warning( 'Object "{}" does not exist. Unable to add it to the character map "{}" under slot "{}"' .format(model, character_node.Name, slot)) return False else: obj = model character_slot = property.list_properties(pattern=slot) if not character_slot: logger.warning('Invalid character slot "{}"'.format(slot)) return False # remove all current models from the slot character_slot[0].removeAll() if obj: character_slot[0].append(obj) return True
def get_mobject(node_name): """ Returns an MObject for the input scene object :param node_name: str, Name of the Maya node to get MObject for :return: """ check_node(node_name) if python.is_string(node_name): selection_list = maya.api.OpenMaya.MSelectionList() selection_list.add(node_name) try: mobj = selection_list.getDependNode(0) except Exception as exc: maya.cmds.warning( 'Impossible to get MObject from name {} : {}'.format( node_name, exc)) return return mobj else: try: if node_name.__module__.startswith('pymel'): return node_name.__apimfn__().object() except AttributeError: if node_name.__class__.__module__.startswith('pymel'): return node_name.__apimfn__().object() return node_name
def find_side(cls, objects, regex_sides): """ Returns the naming convention for the given object names :param objects: list(str) :param regex_sides: str or list(str) :return: str """ if python.is_string(regex_sides): regex_sides = regex_sides.split('|') regex_sides = python.force_list(regex_sides) regex_sides = [re.compile(side) for side in regex_sides] for obj in objects: obj = obj.split('|')[-1].split(':')[-1] for regex_side in regex_sides: match = regex_side.search(obj) if match: side = match.group() if obj.startswith(side): side += '*' if obj.endswith(side): side = '*' + side return side return ''
def _import_submodules(pkg): found_modules = list() if python.is_string(pkg): pkg = import_module(pkg) if not pkg: return found_modules pkg_paths = tuple([os.path.normpath(pkg_path) for pkg_path in pkg.__path__ if pkg is not None]) for pkg_path in list(pkg_paths): for loader, name, is_pkg in pkgutil.walk_packages(pkg_paths): loader_path = os.path.normpath(loader.path) full_name = pkg.__name__ + '.' + name if not loader_path.startswith(pkg_path): # print('Trying to import non valid module: {} | {}'.format(full_name, loader_path)) continue if full_name in skip_modules or full_name.startswith(extra_skip): # print('Skipping .... {}'.format(full_name)) continue found_modules.append(full_name) if recursive and is_pkg: found_modules.extend(_import_submodules(full_name)) return found_modules
def get_skin_weights(skin_cluster, mesh_shape_name): """ Returns the skin weights of the given skin cluster in the given mesh :param skin_cluster: :param mesh_shape_name: :return: """ if python.is_string(skin_cluster): skin_cluster, _ = get_skin_cluster(skin_cluster) if not skin_cluster: return None mesh_path, mesh_components = mesh.get_mesh_path_and_components( mesh_shape_name) if not mesh_path or not mesh_components: return None influences_array = maya.api.OpenMaya.MIntArray() path_array = skin_cluster.influenceObjects() influences_count = len(path_array) for i in range(influences_count): influences_array.append( skin_cluster.indexForInfluenceObject(path_array[i])) weights = skin_cluster.getWeights(mesh_path, mesh_components, influences_array) return weights
def set_skin_weights(skin_cluster, mesh_shape_name, skin_data): if python.is_string(skin_cluster): skin_cluster, _ = get_skin_cluster(skin_cluster) if not skin_cluster: return None skin_data = str(list(skin_data)) mesh_path, mesh_components = mesh.get_mesh_path_and_components( mesh_shape_name) if not mesh_path or not mesh_components: return None influences_array = maya.api.OpenMaya.MIntArray() path_array = skin_cluster.influenceObjects() influences_count = len(path_array) for i in range(influences_count): influences_array.append( skin_cluster.indexForInfluenceObject(path_array[i])) weights_array = maya.api.OpenMaya.MDoubleArray() for i in skin_data[1:-1].split(','): weights_array.append(float(i)) runner = command.CommandRunner() runner.run('tpDcc-dccs-maya-commands-setSkinWeights', skin_cluster=skin_cluster, mesh_path=mesh_path, mesh_components=mesh_components, influences_array=influences_array, weights_array=weights_array)
def _dcc_objects(self, from_selection=False, wildcard='', object_type=None): """ Returns DCC objects from current scene :param from_selection: bool, Whether to return only selected DCC objects or all objects in the scene :param wildcard: str, filter objects by its name :param object_type: int :return: list(variant) """ expression_regex = name_utils.wildcard_to_regex(wildcard) if from_selection: objects = helpers.get_selection_iterator() else: if python.is_string(object_type): objects = maya.cmds.ls(type=object_type, long=True) else: maya_type = dcc.node_types().get( object_type, (maya.api.OpenMaya.MFn.kDagNode, maya.api.OpenMaya.MFn.kCharacter)) objects = list( helpers.get_objects_of_mtype_iterator(maya_type)) if (object_type is not None and object_type != 0) or wildcard: objects_list = list() for obj in objects: if python.is_string(object_type): type_check = True if not object_type else dcc.node_tpdcc_type( obj, as_string=True) == object_type else: type_check = True if not object_type else dcc.node_tpdcc_type( obj) == object_type if wildcard: obj_name = node_utils.get_name(mobj=obj, fullname=False) wildcard_check = expression_regex.match(obj_name) else: wildcard_check = False if type_check and wildcard_check: if python.is_string(obj): obj = node_utils.get_mobject(obj) objects_list.append(obj) objects = objects_list return objects
def generate_color(primary_color, index): """ Generates a new color from the given one and with given index (between 1 and 10) https://github.com/phenom-films/dayu_widgets/blob/master/dayu_widgets/utils.py :param primary_color: base color (RRGGBB) :param index: color step from 1 (light) to 10 (dark) :return: out color Color """ hue_step = 2 saturation_step = 16 saturation_step2 = 5 brightness_step1 = 5 brightness_step2 = 15 light_color_count = 5 dark_color_count = 4 def _get_hue(color, i, is_light): h_comp = color.hue() if 60 <= h_comp <= 240: hue = h_comp - hue_step * i if is_light else h_comp + hue_step * i else: hue = h_comp + hue_step * i if is_light else h_comp - hue_step * i if hue < 0: hue += 359 elif hue >= 359: hue -= 359 return hue / 359.0 def _get_saturation(color, i, is_light): s_comp = color.saturationF() * 100 if is_light: saturation = s_comp - saturation_step * i elif i == dark_color_count: saturation = s_comp + saturation_step else: saturation = s_comp + saturation_step2 * i saturation = min(100.0, saturation) if is_light and i == light_color_count and saturation > 10: saturation = 10 saturation = max(6.0, saturation) return round(saturation * 10) / 1000.0 def _get_value(color, i, is_light): v_comp = color.valueF() if is_light: return min((v_comp * 100 + brightness_step1 * i) / 100, 1.0) return max((v_comp * 100 - brightness_step2 * i) / 100, 0.0) light = index <= 6 hsv_color = Color(primary_color) if python.is_string(primary_color) else primary_color index = light_color_count + 1 - index if light else index - light_color_count - 1 return Color.fromHsvF( _get_hue(hsv_color, index, light), _get_saturation(hsv_color, index, light), _get_value(hsv_color, index, light) ).name()
def insertSeparator(self, before): """ Extends insertSeparator QMenu function :param before: str or QAction :return: QAction """ if python.is_string(before): before = self.find_action(before) return super(Menu, self).insertSeparator(before)
def show_message_box(parent, title, text, width=None, height=None, buttons=None, header_pixmap=None, header_color=None, enable_dont_show_checkbox=False, force=False, theme_to_apply=None): """ Opens a question message box with the given options :param parent: QWidget :param title: str :param text: str :param width: int :param height: int :param buttons: list(QMessageBox.StandardButton) :param header_pixmap: QPixmap :param header_color: str :param enable_dont_show_checkbox: bool :param force: bool :param theme_to_apply: Theme :return: MessageBox """ if python.is_string(enable_dont_show_checkbox): enable_dont_show_checkbox = enable_dont_show_checkbox == 'true' clicked_btn = None if qtutils.is_control_modifier() or qtutils.is_alt_modifier(): force = True if force or not enable_dont_show_checkbox or not enable_dont_show_checkbox: mb = create_message_box( parent=parent, title=title, text=text, width=width, height=height, buttons=buttons, header_pixmap=header_pixmap, header_color=header_color, enable_dont_show_checkbox=enable_dont_show_checkbox, theme_to_apply=theme_to_apply) mb.exec_() mb.close() clicked_btn = mb.clicked_standard_button() dont_show_again = mb.is_dont_show_checkbox_checked() return clicked_btn
def check_node(node_name): """ Returns whether the given node has valid type to work with MaxPlus. If not, raises an Exception :param node_name: variant, str || MaxPlus.INode, node we want to check """ if not python.is_string(node_name) and type( node_name) is not MaxPlus.INode: raise Exception( 'Given node "{}" has not a valid type: "{}" (str or MaxPlus.INode instead)!' .format(node_name, type(node_name)))
def set_default_prim(stage, prim): """ Sets given prim as the default prim in the given stage :param stage: Usd.Stage :param prim: Usd.Prim """ if python.is_string(prim): prim = get_prim_at_path(stage, prim) return stage.SetDefaultPrim(prim)
def get_node_color_data(node): """ Returns the color data in the given Maya node :param node: str or OpenMaya.MObject :return: dict """ if python.is_string(node): node = get_mobject(node) return api_node.get_node_color_data(node)
def get_pymxs_node(node_name): """ Returns 3ds Max pymxs return based on its name or handle :return: """ if python.is_string(node_name): return get_node_by_name(node_name) elif isinstance(node_name, int): return get_node_by_handle(node_name) return node_name
def set_index_color_as_rgb(node, index, linear=True): """ Sets the override RGB color by the given Maya color index :param node: str or list(str) :param index: int or str, Maya index color or Maya nice name color :param linear: bool, Whether or not the RGB should be set in linear space (matches viewport color) """ if python.is_string(index): index = maya_color.convert_maya_color_string_to_index(index) rgb_list = maya_color.convert_maya_color_index_to_rgb(index, linear=linear) set_rgb_color(node, rgb_list=rgb_list)
def insertMenu(self, before, menu): """ Extends insertMenu QMenu function Add supports for finding the before action by the given string :param before: str or QAction :param menu: QMenu :return: QAction """ if python.is_string(before): before = self.find_action(before) return super(Menu, self).insertMenu(before, menu)
def __getattr__(self, item): options = self.options(skip_instance_attrs=True) if not options or item not in options: return super(Theme, self).__getattribute__(item) option_value = options[item] if python.is_string(option_value): if option_value.startswith('^'): return utils.dpi_scale(int(option_value[1:])) if color.string_is_hex(option_value): return color.hex_to_rgb(option_value) else: return option_value
def is_iterator(name): """ Returns true if the passed name is an iterator or False otherwise :param name: str, name to check :return: bool """ if not python.is_string(name): return False if '#' in name or '@' in name: return True return False
def set_icon_hover(self, icon=None): """ Sets the icon hover of the window dragger :param icon: QIcon """ icon = icon or self._window.windowIcon() if icon and python.is_string(icon): icon = resources.icon(icon) if not icon or icon.isNull(): icon = resources.icon('tpDcc') self._logo_button.set_icon_hover(icon)
def get_shape(node, intermediate=False): """ Get the shape node of a transform This is useful if you don't want to have to check if a node is a shape node or transform. You can pass in a shape node or transform and the function will return the shape node If no shape exists, the original name or MObject is returned @param node: str | MObject, Name of the node or MObject @param intermediate: bool, True to get the intermediate shape @return: The name of the shape node """ if type(node) in [list, tuple]: node = node[0] check_node(node) if python.is_string(node): if maya.cmds.nodeType(node) == 'transform': shapes = maya.cmds.listRelatives(node, shapes=True, path=True) if not shapes: shapes = [] for shape in shapes: is_intermediate = maya.cmds.getAttr('%s.intermediateObject' % shape) if intermediate and is_intermediate and maya.cmds.listConnections( shape, source=False): return shape elif not intermediate and not is_intermediate: return shape if shapes: return shapes[0] elif maya.cmds.nodeType(node) in [ 'mesh', 'nurbsCurve', 'nurbsSurface' ]: is_intermediate = maya.cmds.getAttr('%s.intermediateObject' % node) if is_intermediate and not intermediate: node = maya.cmds.listRelatives(node, parent=True, path=True)[0] return get_shape(node) else: return node elif isinstance(node, maya.api.OpenMaya.MObject): if not node.apiType() == maya.api.OpenMaya.MFn.kTransform: return node path = maya.api.OpenMaya.MDagPath.getAPathTo(node) num_shapes = path.numberOfShapesDirectlyBelow() if num_shapes: path.extendToShape(0) return path.node() return node
def setTextColor(self, text_color): """ Sets the foreground color to the given color :param text_color: variant, QColor or str """ if isinstance(text_color, QColor): text_color = color.Color.from_color(text_color) elif python.is_string(text_color): text_color = color.Color.from_string(text_color) self._settings['textColor'] = text_color.to_string() brush = QBrush() brush.setColor(text_color) self.setForeground(0, brush)
def get_curve_data(curve_shape, space=None): """ Returns curve dat from the given shape node :param curve_shape: str, node that represents nurbs curve shape :param space: :return: dict """ space = space or maya.api.OpenMaya.MSpace.kObject if python.is_string(curve_shape): curve_shape = node_utils.get_mobject(curve_shape) return api_curves.get_curve_data(curve_shape, space)
def check_node(node): """ Checks if a node is a valid node and raise and exception if the node is not valid :param node: str | MObject, name of the node to be checked or MObject to be checked :return: bool, True if the given node is valid """ if python.is_string(node): if not maya.cmds.objExists(node): return False elif isinstance(node, maya.api.OpenMaya.MObject): return not node.isNull() return True