## Un-Modify ## by Stefan Ihringer , 2012-10-16 ## ## This script removes a modifier from an input but keeps the rest of the modifier chain instead of completely killing the animation. ## In other words: this script is the undo command for the "Insert... (modifier)" menu item. def get_valid_inputs(t, datatype = None): """ This function retrieves info about all (valid) animated inputs from a given tool or modifier as a dictionary. If datatype is a supported data type, the result will be restricted to inputs of that type. If datatype is None, this function will recurse once to follow nested modifiers. """ valid_types = datatype if valid_types is None: valid_types = ["Number", "Point", "Text", "Gradient"] inputlist = t.GetInputList() result = {} n = 1 for inp in inputlist.itervalues(): if inp.GetConnectedOutput() is not None: if inp.GetAttrs()["INPS_DataType"] in valid_types: connectedTo = inp.GetConnectedOutput().GetTool() nestedIDs = {} if datatype is None: # recurse to collect all animated inputs of modifier that match the data type nested = get_valid_inputs(connectedTo, inp.GetAttrs()['INPS_DataType']) i = 1 # turn this into a dict of input IDs for entry in nested.keys(): nestedIDs[i] = entry i += 1 result[inp.ID] = { 'index': n, 'name': inp.Name, 'connectedTo': connectedTo, 'modifier': fusion.GetRegAttrs(connectedTo.ID)['REGS_Name'], 'nestedIDs': nestedIDs } n = n + 1 return result ## main ## try: try: if tool is None: tool = comp.ActiveTool except NameError: tool = comp.ActiveTool if tool is None: raise Exception("This is a tool script, you must select a tool in the flow to run this script.") # get all animated inputs inputs = get_valid_inputs(tool) inputlist = [(v['index'], k) for k,v in inputs.items()] if len(inputs) == 0: raise Exception(tool.Name + " has no modifiers that could be removed.") # build dialog to choose which modifier to remove dialog = {} show_info = 0 n = 1 for i, inpID in sorted(inputlist): # add a small explanation on how each input is animated nestedIDs = inputs[inpID]['nestedIDs'] if len(nestedIDs) == 0: label = "remove animation from " + inputs[inpID]['name'] else: if show_info < 1: show_info = 1 label = "extract " + inputs[inpID]['modifier'] + " from " + inputs[inpID]['name'] # it's important that the ID is saved as number 1 dialog[n] = {1: inpID, 2: "Checkbox", "Name": label} n += 1 # add dropdown if there are multiple options for inheriting animation from a deleted modifier if len(nestedIDs) > 1: dialog[n] = {1: inpID+"_Dropdown", 2: "Dropdown", "Name": " inherit from:", "Options": nestedIDs} show_info = 2 n += 1 if show_info: message = "'extract' means that the input will inherit animation from an input of the deleted modifier." if show_info == 2: message += " There are multiple candidates so you need to make a choice using the dropdown(s)." dialog[n] = {1: 'Info', 2: "Text", "Lines": 4, "ReadOnly": True, "Wrap": True, "Default": message} # show dialog box ret = composition.AskUser("Remove Modifier From " + tool.Name, dialog) if ret is not None: # process all checked items for n, control in dialog.items(): if "Checkbox" in control.values() and ret[control[1.0]] == 1: inpID = control[1.0] nestedIDs = inputs[inpID]['nestedIDs'] composition.StartUndo("Un-Modify " + tool.Name + "." + inpID) if len(nestedIDs) == 0: # remove modifier directly tool[inpID] = None print("removed animation from " + inputs[inpID]['name']) else: # extract modifier and inherit animation from selected input/modifier chosenInput = nestedIDs[1] if len(nestedIDs) > 1: chosenInput = nestedIDs[ ret[inpID+"_Dropdown"] + 1 ] tool[inpID] = inputs[inpID]['connectedTo'][chosenInput].GetConnectedOutput() print("extracted " + inputs[inpID]['modifier'] + " from " + inputs[inpID]['name'] + ", inheriting animation of '" + chosenInput + "'") composition.EndUndo() except Exception as e: composition.GetFrameList()[1].SwitchMainView('ConsoleView') print e # fin