def remove_selected_transforms_from_curve(self): if not self.current_node: return with maya_helpers.undo(): selected_rows = set( idx.row() for idx in self.ui.transformList.selectedIndexes()) if not selected_rows: return # Remember the first selection, so we can reselect it below. first_selected_dropdown_idx = min(selected_rows) curve = CreateCurve(self.current_node) transforms = curve.get_transforms() new_transforms = [] for idx, transform in enumerate(transforms): if idx not in selected_rows: new_transforms.append(transform) curve.set_transforms(new_transforms) # Refresh the list, and select the first index that was selected. This way, if you delete # the first entry, we leave the new first entry selected instead of deselecting. self.refresh_all() self.select_transform_rows([first_selected_dropdown_idx])
def create_and_select_node(self): """ Create a new zCreateCurve node and an output curve. Select the curve. If transforms are selected in the scene, add them to it. """ with maya_helpers.undo(): nodes = pm.ls(sl=True) attrs = self.get_matrix_from_nodes(nodes) # Create the curve. curve = CreateCurve.create() self.refresh_all() self.current_node = curve.node # Create a curve node. output_curve = curve.add_curve_output() # Add the transforms to it. curve = CreateCurve(self.current_node) curve.set_transforms(attrs) # Refresh and select the new curve. self.refresh_all() pm.select(output_curve.getTransform())
def create_controller_for_selected_object(self): nodes = pm.ls(sl=True, type='transform') if not nodes: log.info('Select one or more objects to create a controller for') return with maya_helpers.undo(): self.create_controller_for_objects(nodes)
def frame_name_edited(self, widget): # How do you find out which item was edited? QT's documentation is useless. items = self._ui.frameList.selectedItems() if not items: return item = items[0] with maya_helpers.undo(): set_name_at_frame(item.frame, item.text())
def set_keyframe_with_time_editor(attr, inTangentType=None, outTangentType=None): """ Set a keyframe, working around problems with the time editor. """ def set_to_time_editor(): keying_target = pm.timeEditorPanel('timeEditorPanel1TimeEd', q=True, keyingTarget=True) if not keying_target: return False # The time editor has weird native hooks for applying keyframes, which calls # teSetKeyFrameOnActiveLayerOrClip in teKeyingFunctions.mel. It's very broken: # it looks at the channel box to see what to key, which causes it to key the wrong # attributes. We can't just set what's shown in the channel box: that requires # changing the selection (which will screw with the graph editor), and we can't change # the selection and the channel box at the same time since the CB update is async. # # Instead, bypass all of that and set the key on the time editor layer directly. # # This means we can't control tangents on time editor clips, which sucks. keying_target = pm.ls(keying_target)[0] clip_id = keying_target.node().attr('clip[0].clipid').get() layer_id = keying_target.attr('layerId').get() is_layer = isinstance(keying_target.node(), pm.nodetypes.TimeEditorClip) and keying_target.attr('layerName').get() != '' if not is_layer: return False # timeEditorClipLayer doesn't take tangentType arguments like pm.setKeyframe, so we have # to work around this the long way by temporarily changing the default. old_in_tangent_type = pm.keyTangent(q=True, g=True, inTangentType=True)[0] old_out_tangent_type = pm.keyTangent(q=True, g=True, outTangentType=True)[0] if inTangentType is not None: pm.keyTangent(g=True, inTangentType=inTangentType) if outTangentType is not None: pm.keyTangent(g=True, outTangentType=outTangentType) try: # Set the key. pm.timeEditorClipLayer(e=True, clipId=clip_id, layerId=layer_id, setKeyframe=True, attribute=attr) finally: # Restore the tangent type. pm.keyTangent(g=True, inTangentType=old_in_tangent_type) pm.keyTangent(g=True, outTangentType=old_out_tangent_type) return True with maya_helpers.undo(): if set_to_time_editor(): return kwargs = {} if inTangentType is not None: kwargs['inTangentType'] = inTangentType if outTangentType is not None: kwargs['outTangentType'] = outTangentType pm.setKeyframe(attr, **kwargs)
def delete_selected_frame(self): """ Delete the frame that's selected in the list, if any. """ item = self.get_selected_frame_item() if item is None: return self.cancel_rename() with maya_helpers.undo(): delete_key_at_frame(item.frame)
def dragged_from_maya(self, nodes, target, indicator_position): with maya_helpers.undo(): # Create controllers for the nodes if they don't exist. self.create_controller_for_objects(nodes) for node in nodes: # See if there's a controller for this node. controller = get_controller_for_object(node) if not controller: continue self.dragged_controller(controller, target, indicator_position)
def dragged_internally(self, target, event, indicator_position): # We shouldn't get an internal drag with no selection (there's nothing to drag). if not self.current_node: return with maya_helpers.undo(): # The position we're moving the selection to: pos = self.get_drag_target_idx(target, indicator_position) curve = CreateCurve(self.current_node) orig_transforms = curve.get_transforms() # The selected rows, and associated transforms: selected_rows = [ idx.row() for idx in self.ui.transformList.selectedIndexes() ] selected_transforms = [ orig_transforms[row] for row in selected_rows ] new_transforms = [] output_idx = None for idx, transform in enumerate(orig_transforms): # If this is the position we're moving the selection to, add them. if idx == pos: output_idx = len(new_transforms) new_transforms.extend(selected_transforms) # If this transform isn't one of the ones we're moving, add it. if idx not in selected_rows: new_transforms.append(transform) # If pos is at the end, we didn't add selected_transforms above, so do it now. if pos == len(orig_transforms): output_idx = len(new_transforms) new_transforms.extend(selected_transforms) curve.set_transforms(new_transforms) # Update the list so we can update the selection. self.populate_transform_list() # Reselect the items that we added. self.select_transform_rows( range(output_idx, output_idx + len(selected_transforms)))
def add_transforms_to_curve(self, nodes, pos=0): """ Insert nodes into the transform list at the given position. If pos is None, add at the end. """ with maya_helpers.undo(): curve = CreateCurve(self.current_node) attrs = self.get_matrix_from_nodes(nodes) # Add the attributes to the transform list. We don't prevent adding duplicates. transforms = curve.get_transforms() if pos is None: pos = len(transforms) transforms[pos:pos] = attrs curve.set_transforms(transforms) # Refresh now, so we can select the new items. self.refresh_all() # Select the items that we added. self.select_transform_rows(range(pos, pos + len(nodes)))
def add_new_frame(self): """ Create a key if one doesn't exist already, and begin editing its name. """ with maya_helpers.undo(): # If we're editing, cancel editing before adding the new frame, or the # new frame won't be visible. This can happen if you select a frame, # click Add, then select another frame and click Add without first # pressing enter for the first rename. This usually only happens if # the window is docked into the main Maya window. self.cancel_rename() if not key_exists_at_frame(pm.currentTime(q=True)): frame = pm.currentTime(q=True) create_key_at_time(frame) set_name_at_frame(frame, 'Frame %i' % frame) # Our listeners will refresh automatically, but that won't happen until later. Refresh # immediately, so we can initiate editing on the new item. self.refresh() # Find the new item and edit it to let the user set its name. self.rename_selected_frame()
def create_controller_group(self): with maya_helpers.undo(): self.create_controller_for_objects([None])
def set_controller_parent(controller, parent, after=None): """ Set controller's parent to parent. If after is None, the node becomes the first child. Otherwise, the node is placed after the given node. If after is at_end, the node is placed at the end. controller -p should do this, but the docs don't really describe how it works and there doesn't seem to be any way to change the parent of a controller to be a root. """ assert controller != parent if after is at_end: if parent is None: raise Exception('parent must be specified if after is at_end') # If there are any children, place controller after the last one. children = get_controller_children(parent) if children: after = children[-1] else: after = None with maya_helpers.undo(): old_parent_plug = get_controller_parent(controller, get_plug=True) if old_parent_plug is None and parent is None: return if old_parent_plug is not None: # Unparent the controller from its old parent. if old_parent_plug.node().prepopulate.isConnectedTo( controller.prepopulate): old_parent_plug.node().prepopulate.disconnect( controller.prepopulate) # We need to reconnect all children and not just disconnect the child, since the # child list needs to remain contiguous. all_children = get_controller_children(old_parent_plug.node(), disconnect_from_parent=True) all_children.remove(controller.node()) assign_controller_children(old_parent_plug.node(), all_children) # If we're unparenting, we're done. if parent is None: return # Connect prepopulate. parent.prepopulate.connect(controller.prepopulate) # Get a list of all children of the parent, and disconnect them. all_children = get_controller_children(parent, disconnect_from_parent=True) # Insert our new child. If we've been given a position to add it, use it. Otherwise, # add to the beginning. if after is None or after not in all_children: all_children = [controller] + all_children else: idx = all_children.index(after) + 1 all_children[idx:idx] = [controller] # Reconnect the children. assign_controller_children(parent, all_children)