private List <ICommand> SetupSingleAnimation(OperatorPart opPart, double keyframeTime) { var context = new OperatorPartContext() { Time = (float)keyframeTime }; float currentValue = opPart.Eval(context).Value; // this command is needed to restore the original value correctly when undoing this, for doing it it's redundant var setValueCommand = new SetFloatValueCommand(opPart, currentValue); var compOp = opPart.Parent.Parent; var addCurveOpCommand = new AddOperatorCommand(compOp, CurveID, 100, 100, 100, false); var curveOpInstanceId = addCurveOpCommand.AddedInstanceID; var addTimeOpCommand = new AddOperatorCommand(compOp, CurrentTimeID, 100, 100, 100, false); var curveMetaOp = MetaManager.Instance.GetMetaOperator(CurveID); var timeMetaOp = MetaManager.Instance.GetMetaOperator(CurrentTimeID); var timeToCurve = new MetaConnection(addTimeOpCommand.AddedInstanceID, timeMetaOp.Outputs[0].ID, addCurveOpCommand.AddedInstanceID, curveMetaOp.Inputs[0].ID); var connectionTimeToCurveCommand = new InsertConnectionCommand(compOp.Definition, timeToCurve, 0); var curveToCurrent = new MetaConnection(addCurveOpCommand.AddedInstanceID, curveMetaOp.Outputs[0].ID, opPart.Parent.ID, opPart.ID); var connectionCurveToCurrentCommand = new InsertConnectionCommand(compOp.Definition, curveToCurrent, 0); var addKeyframeCommand = new AddOrUpdateKeyframeCommand(keyframeTime, currentValue, compOp, curveOpInstanceId, curveMetaOp.Inputs[0].ID); return(new List <ICommand>() { setValueCommand, addCurveOpCommand, addTimeOpCommand, connectionTimeToCurveCommand, connectionCurveToCurrentCommand, addKeyframeCommand }); }
public AddOperatorAndConnectToInputsCommand(Operator compositionOp, MetaOperator metaOpToAdd, IEnumerable <Operator> inputOps, Point position) { _name = "Add Operator And Connect"; var addOperatorCommand = new AddOperatorCommand(compositionOp, metaOpToAdd.ID); _commands.Add(addOperatorCommand); var addedInstanceID = addOperatorCommand.AddedInstanceID; double maxY = Double.NegativeInfinity; double sumX = 0; var connectedOps = new List <Operator>(); var usedSingleInputs = new List <MetaInput>(); var usedMultiInputsCounter = new Dictionary <MetaInput, int>(); // select usable input ops, the ones with at least one output - for now var usableInputOps = from op in inputOps where op.Outputs.Count > 0 select op; foreach (var inputOp in usableInputOps) { maxY = Math.Max(maxY, inputOp.Position.Y); sumX += inputOp.Position.X; var sourceOpID = inputOp.ID; var sourceOpPartID = inputOp.Outputs[0].ID; var inputOpType = inputOp.Definition.Outputs[0].OpPart.Type; Func <FunctionType, bool> isValidInputType = type => { return(inputOpType == type || type == FunctionType.Generic); }; Func <MetaInput, bool> isInputUsable = input => { return(input.IsMultiInput || !usedSingleInputs.Contains(input)); }; var matchingTargetInput = (from input in metaOpToAdd.Inputs where isValidInputType(input.OpPart.Type) && isInputUsable(input) select input).FirstOrDefault(); if (matchingTargetInput == null) { continue; // try next input op } var prevConnection = (from con in compositionOp.Definition.Connections where con.SourceOpPartID == sourceOpPartID && con.SourceOpID == sourceOpID select con).FirstOrDefault(); // Split existing connections for single selected operators if (prevConnection != null && inputOps.Count() == 1) { var firstOccuranceOfTargetOpID = compositionOp.Definition.Connections.FindIndex(con => (con.TargetOpID == prevConnection.TargetOpID) && (con.TargetOpPartID == prevConnection.TargetOpPartID)); var idxOfPrevConnection = compositionOp.Definition.Connections.FindIndex(con => (con.SourceOpID == prevConnection.SourceOpID) && (con.SourceOpPartID == prevConnection.SourceOpPartID) && (con.TargetOpID == prevConnection.TargetOpID) && (con.TargetOpPartID == prevConnection.TargetOpPartID)); int multiInputIdx = idxOfPrevConnection - firstOccuranceOfTargetOpID; var conNewOpToPrevTarget = new MetaConnection(addedInstanceID, metaOpToAdd.Outputs[0].ID, prevConnection.TargetOpID, prevConnection.TargetOpPartID); _commands.Add(new RemoveConnectionCommand(compositionOp.Definition, prevConnection, multiInputIdx)); _commands.Add(new InsertConnectionCommand(compositionOp.Definition, conNewOpToPrevTarget, multiInputIdx)); } // insert new connection var newConnection = new MetaConnection(sourceOpID, sourceOpPartID, addedInstanceID, matchingTargetInput.ID); int index = 0; if (matchingTargetInput.IsMultiInput) { usedMultiInputsCounter.TryGetValue(matchingTargetInput, out index); usedMultiInputsCounter[matchingTargetInput] = index + 1; } else { usedSingleInputs.Add(matchingTargetInput); } _commands.Add(new InsertConnectionCommand(compositionOp.Definition, newConnection, index)); connectedOps.Add(inputOp); } var posX = position.X; var posY = position.Y; var width = 100.0; // Position above connected inputs operators if (connectedOps.Count == 0) { // find free position in center } else if (connectedOps.Count == 1) { posX = connectedOps[0].Position.X; posY = connectedOps[0].Position.Y - 25; addOperatorCommand.Width = width; } else if (connectedOps.Count > 1) { posX = sumX / inputOps.Count(); posY = maxY - 40; } addOperatorCommand.Position = new Point(posX, posY); }
public DuplicateOperatorsCommand(MetaOperator sourceCompositionOp, MetaOperator targetCompositionOp, IEnumerable <Operator> opsToDuplicate) { _name = "Duplicate Operators"; _commands = new List <ICommand>(); var offset = new Point(100, 100); var originalToCopyMap = new Dictionary <Guid, Guid>(); var toDuplicate = opsToDuplicate as Operator[] ?? opsToDuplicate.ToArray(); foreach (var op in toDuplicate) { var position = new Point(op.Position.X + offset.X, op.Position.Y + offset.Y); // copy op var addOperatorCmd = new AddOperatorCommand(targetCompositionOp, op.Definition.ID, position.X, position.Y, op.Width, op.Visible); foreach (var state in sourceCompositionOp.Operators[op.ID].Item2.OperatorPartStates) { addOperatorCmd.OperatorPartStates.Add(state.Key, state.Value.Clone()); } originalToCopyMap[op.ID] = addOperatorCmd.AddedInstanceID; _commands.Add(addOperatorCmd); // copy op properties var updatePropertiesCmd = new UpdateOperatorPropertiesCommand(op.Definition.ID, addOperatorCmd.AddedInstanceID, new UpdateOperatorPropertiesCommand.Entry(op) { Position = position }); _commands.Add(updatePropertiesCmd); // copy input parameters foreach (var input in op.Inputs) { if (!input.IsDefaultFuncSet) { // if default func is not set update the input value var value = (input.Func as Utilities.ValueFunction).Value; // var setInputValueCmd = new UpdateOperatorPartValueFunctionCommand(op.Definition.ID, addOperatorCmd.AddedInstanceID, input.ID, // true, value); // _commands.Add(setInputValueCmd); } } } // copy connections between duplicated ops // first get the connections between the original ops var internalConnections = from con in sourceCompositionOp.Connections from sourceOp in toDuplicate from targetOp in toDuplicate where con.SourceOpID == sourceOp.ID where con.TargetOpID == targetOp.ID select con; // sort them as stored in parent op in order to preserve multi input order var allConnectionsSorted = new List <MetaConnection>(); // these are later on needed to restore multi input order! foreach (var con in sourceCompositionOp.Connections) { if (internalConnections.Contains(con)) { allConnectionsSorted.Add(con); } } // create a group for each input var groupedConnections = (from con in allConnectionsSorted group con by(con.TargetOpID.ToString() + con.TargetOpPartID.ToString()) into g select g).ToList(); // insert the connections to new op foreach (var conGroup in groupedConnections) { var index = 0; foreach (var con in conGroup) { var conBetweenNewOps = new MetaConnection(originalToCopyMap[con.SourceOpID], con.SourceOpPartID, originalToCopyMap[con.TargetOpID], con.TargetOpPartID); _commands.Add(new InsertConnectionCommand(targetCompositionOp, conBetweenNewOps, index)); index++; } } }