Added Undo Redo to editor

This commit is contained in:
teinarss
2019-07-13 18:21:01 +02:00
committed by abcdefg30
parent 1f78b3a425
commit 76034c198e
19 changed files with 1155 additions and 164 deletions

View File

@@ -0,0 +1,172 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
public class EditorActionManagerInfo : TraitInfo<EditorActionManager> { }
public class EditorActionManager : IWorldLoaded
{
readonly Stack<EditorActionContainer> undoStack = new Stack<EditorActionContainer>();
readonly Stack<EditorActionContainer> redoStack = new Stack<EditorActionContainer>();
public event Action<EditorActionContainer> ItemAdded;
public event Action<EditorActionContainer> ItemRemoved;
public event Action OnChange;
int nextId;
public void WorldLoaded(World w, WorldRenderer wr)
{
Add(new OpenMapAction());
}
public void Add(IEditorAction editorAction)
{
editorAction.Execute();
if (undoStack.Count > 0)
undoStack.Peek().Status = EditorActionStatus.History;
var actionContainer = new EditorActionContainer(nextId++, editorAction);
ClearRedo();
undoStack.Push(actionContainer);
if (ItemAdded != null)
ItemAdded(actionContainer);
}
public void Undo()
{
if (!HasUndos())
return;
var editorAction = undoStack.Pop();
undoStack.Peek().Status = EditorActionStatus.Active;
editorAction.Action.Undo();
editorAction.Status = EditorActionStatus.Future;
redoStack.Push(editorAction);
if (OnChange != null)
OnChange();
}
void ClearRedo()
{
while (HasRedos())
{
var item = redoStack.Pop();
if (ItemRemoved != null)
ItemRemoved(item);
}
}
public void Redo()
{
if (!HasRedos())
return;
var editorAction = redoStack.Pop();
editorAction.Status = EditorActionStatus.Active;
editorAction.Action.Do();
undoStack.Peek().Status = EditorActionStatus.History;
undoStack.Push(editorAction);
if (OnChange != null)
OnChange();
}
public bool HasUndos()
{
// Preserve the initial OpenMapAction.
return undoStack.Count > 1;
}
public bool HasRedos()
{
return redoStack.Count > 0;
}
public void Rewind(int id)
{
while (undoStack.Peek().Id != id)
Undo();
}
public void Forward(int id)
{
while (undoStack.Peek().Id != id)
Redo();
}
}
public enum EditorActionStatus
{
History,
Active,
Future,
}
public interface IEditorAction
{
void Execute();
void Do();
void Undo();
string Text { get; }
}
class OpenMapAction : IEditorAction
{
public OpenMapAction()
{
Text = "Opened";
}
public void Execute()
{
}
public void Do()
{
}
public void Undo()
{
}
public string Text { get; private set; }
public EditorActionStatus Status { get; set; }
}
public class EditorActionContainer
{
public int Id { get; private set; }
public IEditorAction Action { get; private set; }
public EditorActionStatus Status { get; set; }
public EditorActionContainer(int id, IEditorAction action)
{
Id = id;
Action = action;
Status = EditorActionStatus.Active;
}
}
}

View File

@@ -110,8 +110,15 @@ namespace OpenRA.Mods.Common.Traits
var owner = Players.Players[reference.InitDict.Get<OwnerInit>().PlayerName];
var preview = new EditorActorPreview(worldRenderer, id, reference, owner);
previews.Add(preview);
Add(preview, initialSetup);
return preview;
}
public void Add(EditorActorPreview preview, bool initialSetup = false)
{
previews.Add(preview);
if (!preview.Bounds.IsEmpty)
screenMap.Add(preview, preview.Bounds);
@@ -126,11 +133,9 @@ namespace OpenRA.Mods.Common.Traits
{
UpdateNeighbours(preview.Footprint);
if (reference.Type == "mpspawn")
if (preview.Actor.Type == "mpspawn")
SyncMultiplayerCount();
}
return preview;
}
public void Remove(EditorActorPreview preview)
@@ -262,7 +267,7 @@ namespace OpenRA.Mods.Common.Traits
string NextActorName()
{
var id = previews.Count();
var id = previews.Count;
var possibleName = "Actor" + id.ToString();
while (previews.Any(p => p.ID == possibleName))

View File

@@ -20,7 +20,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
public class EditorActorPreview
public class EditorActorPreview : IEquatable<EditorActorPreview>
{
public readonly string DescriptiveName;
public readonly ActorInfo Info;
@@ -28,6 +28,7 @@ namespace OpenRA.Mods.Common.Traits
public readonly IReadOnlyDictionary<CPos, SubCell> Footprint;
public readonly Rectangle Bounds;
public readonly SelectionBoxRenderable SelectionBox;
public readonly ActorReference Actor;
public string Tooltip
{
@@ -43,7 +44,6 @@ namespace OpenRA.Mods.Common.Traits
public SubCell SubCell { get; private set; }
public bool Selected { get; set; }
readonly ActorReference actor;
readonly WorldRenderer worldRenderer;
readonly TooltipInfoBase tooltip;
IActorPreview[] previews;
@@ -51,7 +51,7 @@ namespace OpenRA.Mods.Common.Traits
public EditorActorPreview(WorldRenderer worldRenderer, string id, ActorReference actor, PlayerReference owner)
{
ID = id;
this.actor = actor;
Actor = actor;
Owner = owner;
this.worldRenderer = worldRenderer;
@@ -120,25 +120,25 @@ namespace OpenRA.Mods.Common.Traits
public void ReplaceInit<T>(T init)
{
var original = actor.InitDict.GetOrDefault<T>();
var original = Actor.InitDict.GetOrDefault<T>();
if (original != null)
actor.InitDict.Remove(original);
Actor.InitDict.Remove(original);
actor.InitDict.Add(init);
Actor.InitDict.Add(init);
GeneratePreviews();
}
public void RemoveInit<T>()
{
var original = actor.InitDict.GetOrDefault<T>();
var original = Actor.InitDict.GetOrDefault<T>();
if (original != null)
actor.InitDict.Remove(original);
Actor.InitDict.Remove(original);
GeneratePreviews();
}
public T Init<T>()
{
return actor.InitDict.GetOrDefault<T>();
return Actor.InitDict.GetOrDefault<T>();
}
public MiniYaml Save()
@@ -154,7 +154,7 @@ namespace OpenRA.Mods.Common.Traits
return true;
};
return actor.Save(saveInit);
return Actor.Save(saveInit);
}
WPos PreviewPosition(World world, TypeDictionary init)
@@ -167,7 +167,7 @@ namespace OpenRA.Mods.Common.Traits
var cell = init.Get<LocationInit>().Value(world);
var offset = WVec.Zero;
var subCellInit = actor.InitDict.GetOrDefault<SubCellInit>();
var subCellInit = Actor.InitDict.GetOrDefault<SubCellInit>();
var subCell = subCellInit != null ? subCellInit.Value(worldRenderer.World) : SubCell.Any;
var buildingInfo = Info.TraitInfoOrDefault<BuildingInfo>();
@@ -182,7 +182,7 @@ namespace OpenRA.Mods.Common.Traits
void GeneratePreviews()
{
var init = new ActorPreviewInitializer(Info, worldRenderer, actor.InitDict);
var init = new ActorPreviewInitializer(Info, worldRenderer, Actor.InitDict);
previews = Info.TraitInfos<IRenderActorPreviewInfo>()
.SelectMany(rpi => rpi.RenderPreview(init))
.ToArray();
@@ -190,12 +190,39 @@ namespace OpenRA.Mods.Common.Traits
public ActorReference Export()
{
return new ActorReference(actor.Type, actor.Save().ToDictionary());
return new ActorReference(Actor.Type, Actor.Save().ToDictionary());
}
public override string ToString()
{
return "{0} {1}".F(Info.Name, ID);
}
public bool Equals(EditorActorPreview other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
return string.Equals(ID, other.ID, StringComparison.OrdinalIgnoreCase);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
return false;
if (ReferenceEquals(this, obj))
return true;
if (obj.GetType() != GetType())
return false;
return Equals((EditorActorPreview)obj);
}
public override int GetHashCode()
{
return ID != null ? StringComparer.OrdinalIgnoreCase.GetHashCode(ID) : 0;
}
}
}