public void Add(IEnumerable <ConversationNode> nodes, IEnumerable <NodeGroup> groups, ILocalizationEngine localization) { nodes = nodes.Evaluate(); groups = groups.ToList(); SimpleUndoPair addActions = InnerAddNodes(nodes, groups, localization); bool addedNodes = nodes.Any(); bool addedGroups = groups.Any(); if (addedNodes && addedGroups) { UndoableFile.Change(new GenericUndoAction(addActions.Undo, addActions.Redo, "Added nodes and groups")); } else if (addedNodes) { UndoableFile.Change(new GenericUndoAction(addActions.Undo, addActions.Redo, "Added nodes")); } else if (addedGroups) { UndoableFile.Change(new GenericUndoAction(addActions.Undo, addActions.Redo, "Added groups")); } else { throw new InternalLogicException("why would you do this?"); } }
public void Change(SimpleUndoPair actions, string description) { var action = new GenericUndoAction(new SimpleUndoPair { Redo = () => { actions.Redo(); Modified.Execute(); }, Undo = () => { actions.Undo(); Modified.Execute(); } }, description); action.Redo(); m_undoQueue.Queue(action); }
public Tuple <IEnumerable <ConversationNode>, IEnumerable <NodeGroup> > InsertInto(IEnumerable <GraphAndUI <NodeUIData> > nodeData, IEnumerable <NodeGroup> groups, PointF location, ILocalizationEngine localization) { var nodes = nodeData.Select(gnu => MakeNode(gnu.GraphData, gnu.UIData)).Evaluate(); var area = NodeSet.GetArea(nodes.Concat <IRenderable <IGui> >(groups)); PointF offset = location.Take(area.Center()); foreach (var node in nodes) { node.Renderer.Offset(offset); } foreach (var group in groups) { group.Renderer.Offset(offset); } SimpleUndoPair addActions = InnerAddNodes(nodes, groups, localization); UndoableFile.Change(new GenericUndoAction(addActions, "Pasted")); return(Tuple.Create(nodes, groups)); }
private IEnumerable <ReplaceAction> FindAll() { IEnumerable <TData> search = chkCurrentConversationOnly.Checked ? m_currentDocument().Only <TData>() : m_search; Regex find = GenerateRegex(txtFind.Text); if (find == null) { MessageBox.Show("Invalid regular expression"); yield break; } foreach (var file in search) { foreach (var node in file.Nodes.Evaluate()) { if (chkStrings.Checked) { foreach (var parameter in node.Data.Parameters.OfType <IStringParameter>()) { string original = parameter.Value; if (Replace(original, find, txtReplace.Text, out string output)) { //Treat replace actions as true actions even if they don't actually alter the value of the parameter yield return(new ReplaceAction(parameter.SetValueAction(output) ?? new SimpleUndoPair() { Redo = () => { }, Undo = () => { } }, file, node, parameter)); } ; } } if (chkLocalizedStrings.Checked) { foreach (var parameter in node.Data.Parameters.OfType <ILocalizedStringParameter>()) { var original = m_localizer.Localize(Id <LocalizedStringType> .FromGuid(parameter.TypeId.Guid), parameter.Value); if (original != null) { if (Replace(original, find, txtReplace.Text, out string output)) { SimpleUndoPair redoUndo = m_localizer.SetLocalizationAction(Id <LocalizedStringType> .ConvertFrom(parameter.TypeId), parameter.Value, output); Action redo = () => { redoUndo.Redo(); UpdateDisplay.Execute(); }; Action undo = () => { redoUndo.Undo(); UpdateDisplay.Execute(); }; yield return(new ReplaceAction(undo, redo, file, node, parameter)); } } } } if (chkDynamicEnumerations.Checked) { foreach (var parameter in node.Data.Parameters.OfType <IDynamicEnumParameter>().Where(x => !x.Corrupted)) { string original = parameter.Value; if (original != null) //DynamicEnumParameters shouldn't have a value of null typically but DomainDomain.EnumDefaultParameter can { if (Replace(original, find, txtReplace.Text, out string output)) { //Treat replace actions as true actions even if they don't actually alter the value of the parameter yield return(new ReplaceAction(parameter.SetValueAction(output) ?? new SimpleUndoPair() { Redo = () => { }, Undo = () => { } }, file, node, parameter)); } ; } } } } } }
public ReplaceAction(SimpleUndoPair undoredo, IConversationEditorControlData <ConversationNode, TransitionNoduleUIInfo> file, ConversationNode node, IParameter parameter) : this(undoredo.Undo, undoredo.Redo, file, node, parameter) { }
internal static UnknownParameterEditor Make(IColorScheme scheme, ParameterEditorSetupData data, SimpleUndoPair removeParameter, Action remove) { UnknownParameterEditor x = null; try { x = new UnknownParameterEditor(); x.Scheme = scheme; x.Setup(data); x.m_removeParameter = removeParameter; x.Remove += remove; var result = x; x = null; return(result); } finally { if (x != null) { x.Dispose(); } } }
public bool Remove(IEnumerable <ConversationNode> nodes, IEnumerable <NodeGroup> groups, ILocalizationEngine localization) { nodes = nodes.ToList(); groups = groups.ToList(); bool removeNodes = nodes.Any(); bool removeGroups = groups.Any(); List <Action> undoActions = new List <Action>(); List <Action> redoActions = new List <Action>(); if (nodes.Any(n => !CanRemoveFromData(n, () => false))) { if (!PromptNodeDeletion()) { return(false); } } if (removeNodes) { //Make sure all the nodes are added before trying to link them foreach (var node in nodes) { var n = node; undoActions.Add(() => { m_nodes.Add(n); }); } foreach (var node in nodes) { var n = node; var actions = n.GetNodeRemoveActions(); //Ensure that the localization engine is up to date in terms of usage of localized data foreach (var parameter in n.Data.Parameters.OfType <ILocalizedStringParameter>()) { SimpleUndoPair clearLocalization = localization.ClearLocalizationAction(Id <LocalizedStringType> .ConvertFrom(parameter.TypeId), parameter.Value); undoActions.Add(clearLocalization.Undo); redoActions.Add(clearLocalization.Redo); } var containingGroups = m_groups.Where(g => g.Contents.Contains(n.Data.NodeId)).Evaluate(); undoActions.Add(() => { actions.Undo(); //Connect after adding the node foreach (var group in containingGroups) { group.Contents.Add(n.Data.NodeId); } m_audioProvider.UpdateUsage(n); }); redoActions.Add(() => { actions.Redo(); //Disconnect before removing the node m_nodes.Remove(n); foreach (var group in containingGroups) { group.Contents.Remove(n.Data.NodeId); } NodesDeleted.Execute(); }); } } if (removeGroups) { List <NodeGroup> toAdd = new List <NodeGroup>(groups); undoActions.Add(() => { m_groups.AddRange(toAdd); }); redoActions.Add(() => { m_groups.RemoveRange(toAdd); }); } Action undo = () => { using (m_audioProvider.SuppressUpdates()) foreach (Action action in undoActions) { action(); } }; Action redo = () => { using (m_audioProvider.SuppressUpdates()) foreach (Action action in redoActions) { action(); } }; string message; if (removeNodes && removeGroups) { message = "Deleted elements"; } else if (removeNodes) { message = "Deleted nodes"; } else if (removeGroups) { message = "Removed groupings"; } else { throw new InternalLogicException("Something went wrong :("); } UndoableFile.Change(new GenericUndoAction(undo, redo, message)); return(true); }
private SimpleUndoPair InnerAddNodes(IEnumerable <ConversationNode> nodes, IEnumerable <NodeGroup> groups, ILocalizationEngine localization) { List <Action> undoActions = new List <Action>(); List <Action> redoActions = new List <Action>(); //Set up actions for adding/removing the nodes foreach (var node in nodes) { var n = node; SimpleUndoPair actions = n.GetNodeRemoveActions(); //Ensure that the localization engine is up to date in terms of usage of localized data foreach (var parameter in n.Data.Parameters.OfType <ILocalizedStringParameter>()) { if (parameter.Value != null) { SimpleUndoPair clearLocalization = localization.ClearLocalizationAction(Id <LocalizedStringType> .ConvertFrom(parameter.TypeId), parameter.Value); undoActions.Add(clearLocalization.Redo); redoActions.Add(clearLocalization.Undo); } } var containingGroups = m_groups.Where(g => g.Contents.Contains(n.Data.NodeId)).Evaluate(); redoActions.Add(() => { m_nodes.Add(n); m_audioProvider.UpdateUsage(n); foreach (var group in containingGroups) { group.Contents.Add(n.Data.NodeId); } actions.Undo(); //Undo the node removal }); undoActions.Add(() => { if (CanRemoveFromData(n, PromptNodeDeletion)) { m_nodes.Remove(n); } foreach (var group in containingGroups) { group.Contents.Remove(n.Data.NodeId); } actions.Redo(); //Redo the node removal NodesDeleted.Execute(); }); } //Set up actions for adding/removing nodes from other groups that are gaining/losing their grouping due to removing/adding new groups foreach (var group in groups) { foreach (var node in group.Contents) { var n = node; var old = m_groups.SingleOrDefault(g => g.Contents.Contains(n)); if (old != null) { undoActions.Add(() => old.Contents.Add(n)); redoActions.Add(() => old.Contents.Remove(n)); } } } //Set up actions for adding/removing the groups undoActions.Add(() => { foreach (var group in groups.Reverse()) { m_groups.Remove(group); } }); redoActions.Add(() => { m_groups.AddRange(groups); }); return(new SimpleUndoPair { Undo = () => { using (m_audioProvider.SuppressUpdates()) foreach (Action action in undoActions) { action(); } }, Redo = () => { using (m_audioProvider.SuppressUpdates()) foreach (Action action in redoActions) { action(); } }, }); }
//TODO: Duplicate the IEditable with a new ID (must be deep copy of parameters) public Tuple <IEnumerable <ConversationNode>, IEnumerable <NodeGroup> > DuplicateInto(IEnumerable <GraphAndUI <NodeUIData> > nodeData, IEnumerable <NodeGroup> groups, PointF location, ILocalizationEngine localization) { var nodes = nodeData.Select(gnu => MakeNode(gnu.GraphData, gnu.UIData)).Evaluate(); IEnumerable <IDynamicEnumParameter> localDynamicEnumerationParameters = nodes.SelectMany(n => n.Data.Parameters.OfType <IDynamicEnumParameter>().Where(p => p.Local)); foreach (var ldep in localDynamicEnumerationParameters) { ldep.MergeInto(m_getDocumentSource(ldep)); } if (nodes.Any() || groups.Any()) { List <Action> undoActions = new List <Action>(); List <Action> redoActions = new List <Action>(); //Changes to these nodes don't need to be undoable as they're new nodes foreach (var node in nodes) { //Duplicate the id of any localized string parameters to avoid the new node using the same id(s) as the old one foreach (var p in node.Data.Parameters.OfType <LocalizedStringParameter>()) { var result = localization.DuplicateActions(p.Value); var action = p.SetValueAction(result.Item1); if (action != null) { //Don't this node is a duplicate of another. The old node's localization data is irrelevant. We should never return to it. //undoActions.Add(action.Value.Undo); redoActions.Add(action.Value.Redo); action.Value.Redo(); //Change the value immediately. The old value is irrelevant and we should never return to it. } result.Item2.Redo(); //Add the localization immediately. Otherwise when adding the node we won't know how to undo deletion of the node's localization data. undoActions.Add(result.Item2.Undo); redoActions.Add(result.Item2.Redo); } //TODO: AUDIO: Do we want to treat audio parameters like strings in that they have a meaningful value // or like localized strings in that they are a key into another system? //foreach (var p in node.Data.Parameters.OfType<IAudioParameter>()) //{ // //No need to update audio usage as this will occur when the node is added/removed // var audio = m_generateAudio(this); // var actions = p.SetValueAction(audio); //TODO: AUDIO: Investigate what happens to Audio parameter usage if you duplicate a node and then undo // undoActions.Add(actions.Value.Undo); // redoActions.Add(actions.Value.Redo); //} //foreach (var p in node.Data.Parameters.OfType<IAudioParameter>()) //{ // var action = p.SetValueAction(new Audio(Guid.NewGuid().ToString())); // if (action != null) // action.Value.Redo(); //If we undo the whole operation the parameter wont exist so no need to ever undo this value change. //} var oldID = node.Data.NodeId; node.Data.ChangeId(Id <NodeTemp> .New()); foreach (var group in groups) { if (group.Contents.Contains(oldID)) { group.Contents.Remove(oldID); group.Contents.Add(node.Data.NodeId); } } } var area = NodeSet.GetArea(nodes.Concat <IRenderable <IGui> >(groups)); PointF offset = location.Take(area.Center()); foreach (var node in nodes) { node.Renderer.Offset(offset); } foreach (var group in groups) { group.Renderer.Offset(offset); } SimpleUndoPair addActions = InnerAddNodes(nodes, groups, localization); Action undo = () => { undoActions.ForEach(a => a()); addActions.Undo(); }; Action redo = () => { redoActions.ForEach(a => a()); addActions.Redo(); }; UndoableFile.Change(new GenericUndoAction(undo, redo, "Pasted")); } return(Tuple.Create(nodes, groups)); }