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

@@ -24,6 +24,7 @@ namespace OpenRA.Mods.Common.Widgets
readonly WorldRenderer worldRenderer;
readonly World world;
readonly EditorActorLayer editorLayer;
readonly EditorActionManager editorActionManager;
readonly EditorViewportControllerWidget editorWidget;
readonly ActorPreviewWidget preview;
readonly WVec centerOffset;
@@ -38,6 +39,7 @@ namespace OpenRA.Mods.Common.Widgets
worldRenderer = wr;
world = wr.World;
editorLayer = world.WorldActor.Trait<EditorActorLayer>();
editorActionManager = world.WorldActor.Trait<EditorActionManager>();
Actor = actor;
this.owner = owner;
@@ -101,33 +103,8 @@ namespace OpenRA.Mods.Common.Widgets
return true;
// Enforce first entry of ValidOwnerNames as owner if the actor has RequiresSpecificOwners
var ownerName = owner.Name;
var specificOwnerInfo = Actor.TraitInfoOrDefault<RequiresSpecificOwnersInfo>();
if (specificOwnerInfo != null && !specificOwnerInfo.ValidOwnerNames.Contains(ownerName))
ownerName = specificOwnerInfo.ValidOwnerNames.First();
var newActorReference = new ActorReference(Actor.Name);
newActorReference.Add(new OwnerInit(ownerName));
newActorReference.Add(new LocationInit(cell));
var ios = Actor.TraitInfoOrDefault<IOccupySpaceInfo>();
if (ios != null && ios.SharesCell)
{
var subcell = editorLayer.FreeSubCellAt(cell);
if (subcell != SubCell.Invalid)
newActorReference.Add(new SubCellInit(subcell));
}
var initDict = newActorReference.InitDict;
if (Actor.HasTraitInfo<IFacingInfo>())
initDict.Add(new FacingInit(facing));
if (Actor.HasTraitInfo<TurretedInfo>())
initDict.Add(new TurretFacingInit(facing));
editorLayer.Add(newActorReference);
var action = new AddActorAction(editorLayer, Actor, cell, owner, facing);
editorActionManager.Add(action);
}
return true;
@@ -151,4 +128,69 @@ namespace OpenRA.Mods.Common.Widgets
public void Dispose() { }
}
class AddActorAction : IEditorAction
{
public string Text { get; private set; }
readonly EditorActorLayer editorLayer;
readonly ActorInfo actor;
readonly CPos cell;
readonly PlayerReference owner;
readonly int facing;
EditorActorPreview editorActorPreview;
public AddActorAction(EditorActorLayer editorLayer, ActorInfo actor, CPos cell, PlayerReference owner, int facing)
{
this.editorLayer = editorLayer;
this.actor = actor;
this.cell = cell;
this.owner = owner;
this.facing = facing;
}
public void Execute()
{
Do();
}
public void Do()
{
var ownerName = owner.Name;
var specificOwnerInfo = actor.TraitInfoOrDefault<RequiresSpecificOwnersInfo>();
if (specificOwnerInfo != null && !specificOwnerInfo.ValidOwnerNames.Contains(ownerName))
ownerName = specificOwnerInfo.ValidOwnerNames.First();
var newActorReference = new ActorReference(actor.Name);
newActorReference.Add(new OwnerInit(ownerName));
newActorReference.Add(new LocationInit(cell));
var ios = actor.TraitInfoOrDefault<IOccupySpaceInfo>();
if (ios != null && ios.SharesCell)
{
var subcell = editorLayer.FreeSubCellAt(cell);
if (subcell != SubCell.Invalid)
newActorReference.Add(new SubCellInit(subcell));
}
var initDict = newActorReference.InitDict;
if (actor.HasTraitInfo<IFacingInfo>())
initDict.Add(new FacingInit(facing));
if (actor.HasTraitInfo<TurretedInfo>())
initDict.Add(new TurretFacingInit(facing));
editorActorPreview = editorLayer.Add(newActorReference);
Text = "Added {0} ({1})".F(editorActorPreview.Info.Name, editorActorPreview.ID);
}
public void Undo()
{
editorLayer.Remove(editorActorPreview);
}
}
}

View File

@@ -36,6 +36,7 @@ namespace OpenRA.Mods.Common.Widgets
readonly EditorSelectionLayer selectionLayer;
readonly EditorActorLayer editorLayer;
readonly Func<MapCopyFilters> getCopyFilters;
readonly EditorActionManager editorActionManager;
State state;
CPos start;
@@ -46,6 +47,8 @@ namespace OpenRA.Mods.Common.Widgets
this.editorWidget = editorWidget;
worldRenderer = wr;
editorActionManager = wr.World.WorldActor.Trait<EditorActionManager>();
selectionLayer = wr.World.WorldActor.Trait<EditorSelectionLayer>();
editorLayer = wr.World.WorldActor.Trait<EditorActorLayer>();
this.getCopyFilters = getCopyFilters;
@@ -143,26 +146,8 @@ namespace OpenRA.Mods.Common.Widgets
}
}
foreach (var kv in tiles)
{
if (copyFilters.HasFlag(MapCopyFilters.Terrain))
mapTiles[kv.Key] = kv.Value.Item1;
if (copyFilters.HasFlag(MapCopyFilters.Resources))
mapResources[kv.Key] = kv.Value.Item2;
mapHeight[kv.Key] = kv.Value.Item3;
}
if (copyFilters.HasFlag(MapCopyFilters.Actors))
{
var removeActors = dest.SelectMany(editorLayer.PreviewsAt).Distinct().ToList();
foreach (var preview in removeActors)
editorLayer.Remove(preview);
}
foreach (var kv in previews)
editorLayer.Add(kv.Value);
var action = new CopyPasteEditorAction(copyFilters, worldRenderer.World.Map, tiles, previews, editorLayer, dest);
editorActionManager.Add(action);
}
public void Tick()
@@ -187,4 +172,114 @@ namespace OpenRA.Mods.Common.Widgets
selectionLayer.Clear();
}
}
class CopyPasteEditorAction : IEditorAction
{
public string Text { get; private set; }
readonly MapCopyFilters copyFilters;
readonly Dictionary<CPos, Tuple<TerrainTile, ResourceTile, byte>> tiles;
readonly Dictionary<string, ActorReference> previews;
readonly EditorActorLayer editorLayer;
readonly CellRegion dest;
readonly CellLayer<TerrainTile> mapTiles;
readonly CellLayer<byte> mapHeight;
readonly CellLayer<ResourceTile> mapResources;
readonly Queue<UndoCopyPaste> undoCopyPastes = new Queue<UndoCopyPaste>();
readonly Queue<EditorActorPreview> removedActors = new Queue<EditorActorPreview>();
readonly Queue<EditorActorPreview> addedActorPreviews = new Queue<EditorActorPreview>();
public CopyPasteEditorAction(MapCopyFilters copyFilters, Map map,
Dictionary<CPos, Tuple<TerrainTile, ResourceTile, byte>> tiles, Dictionary<string, ActorReference> previews,
EditorActorLayer editorLayer, CellRegion dest)
{
this.copyFilters = copyFilters;
this.tiles = tiles;
this.previews = previews;
this.editorLayer = editorLayer;
this.dest = dest;
mapTiles = map.Tiles;
mapHeight = map.Height;
mapResources = map.Resources;
Text = "Copied {0} tiles".F(tiles.Count);
}
public void Execute()
{
Do();
}
public void Do()
{
foreach (var kv in tiles)
{
undoCopyPastes.Enqueue(new UndoCopyPaste(kv.Key, mapTiles[kv.Key], mapResources[kv.Key], mapHeight[kv.Key]));
if (copyFilters.HasFlag(MapCopyFilters.Terrain))
mapTiles[kv.Key] = kv.Value.Item1;
if (copyFilters.HasFlag(MapCopyFilters.Resources))
mapResources[kv.Key] = kv.Value.Item2;
mapHeight[kv.Key] = kv.Value.Item3;
}
if (copyFilters.HasFlag(MapCopyFilters.Actors))
{
var removeActors = dest.SelectMany(editorLayer.PreviewsAt).Distinct().ToList();
foreach (var preview in removeActors)
{
removedActors.Enqueue(preview);
editorLayer.Remove(preview);
}
}
foreach (var kv in previews)
addedActorPreviews.Enqueue(editorLayer.Add(kv.Value));
}
public void Undo()
{
while (undoCopyPastes.Count > 0)
{
var undoCopyPaste = undoCopyPastes.Dequeue();
var cell = undoCopyPaste.Cell;
if (copyFilters.HasFlag(MapCopyFilters.Terrain))
mapTiles[cell] = undoCopyPaste.MapTile;
if (copyFilters.HasFlag(MapCopyFilters.Resources))
mapResources[cell] = undoCopyPaste.ResourceTile;
mapHeight[cell] = undoCopyPaste.Height;
}
while (addedActorPreviews.Count > 0)
editorLayer.Remove(addedActorPreviews.Dequeue());
if (copyFilters.HasFlag(MapCopyFilters.Actors))
while (removedActors.Count > 0)
editorLayer.Add(removedActors.Dequeue());
}
}
internal class UndoCopyPaste
{
public CPos Cell { get; private set; }
public TerrainTile MapTile { get; private set; }
public ResourceTile ResourceTile { get; private set; }
public byte Height { get; private set; }
public UndoCopyPaste(CPos cell, TerrainTile mapTile, ResourceTile resourceTile, byte height)
{
Cell = cell;
MapTile = mapTile;
ResourceTile = resourceTile;
Height = height;
}
}
}

View File

@@ -33,6 +33,8 @@ namespace OpenRA.Mods.Common.Widgets
readonly EditorViewportControllerWidget editorWidget;
readonly EditorActorLayer editorLayer;
readonly Dictionary<int, ResourceType> resources;
readonly EditorActionManager editorActionManager;
public EditorActorPreview SelectedActor;
int2 worldPixel;
@@ -45,6 +47,8 @@ namespace OpenRA.Mods.Common.Widgets
editorLayer = world.WorldActor.Trait<EditorActorLayer>();
resources = world.WorldActor.TraitsImplementing<ResourceType>()
.ToDictionary(r => r.Info.ResourceType, r => r);
editorActionManager = world.WorldActor.Trait<EditorActionManager>();
}
long CalculateActorSelectionPriority(EditorActorPreview actor)
@@ -74,7 +78,7 @@ namespace OpenRA.Mods.Common.Widgets
var underCursor = editorLayer.PreviewsAt(worldPixel).MinByOrDefault(CalculateActorSelectionPriority);
var mapResources = world.Map.Resources;
ResourceType type;
ResourceType type = null;
if (underCursor != null)
editorWidget.SetTooltip(underCursor.Tooltip);
else if (mapResources.Contains(cell) && resources.TryGetValue(mapResources[cell].Type, out type))
@@ -97,10 +101,10 @@ namespace OpenRA.Mods.Common.Widgets
editorWidget.SetTooltip(null);
if (underCursor != null && underCursor != SelectedActor)
editorLayer.Remove(underCursor);
editorActionManager.Add(new RemoveActorAction(editorLayer, underCursor));
if (mapResources.Contains(cell) && mapResources[cell].Type != 0)
mapResources[cell] = default(ResourceTile);
editorActionManager.Add(new RemoveResourceAction(mapResources, cell, type));
}
return true;
@@ -109,4 +113,69 @@ namespace OpenRA.Mods.Common.Widgets
public void Tick() { }
public void Dispose() { }
}
class RemoveActorAction : IEditorAction
{
public string Text { get; private set; }
readonly EditorActorLayer editorActorLayer;
readonly EditorActorPreview actor;
public RemoveActorAction(EditorActorLayer editorActorLayer, EditorActorPreview actor)
{
this.editorActorLayer = editorActorLayer;
this.actor = actor;
Text = "Removed {0} ({1})".F(actor.Info.Name, actor.ID);
}
public void Execute()
{
Do();
}
public void Do()
{
editorActorLayer.Remove(actor);
}
public void Undo()
{
editorActorLayer.Add(actor);
}
}
class RemoveResourceAction : IEditorAction
{
public string Text { get; private set; }
readonly CellLayer<ResourceTile> mapResources;
readonly CPos cell;
ResourceTile resourceTile;
public RemoveResourceAction(CellLayer<ResourceTile> mapResources, CPos cell, ResourceType type)
{
this.mapResources = mapResources;
this.cell = cell;
Text = "Removed {0}".F(type.Info.TerrainType);
}
public void Execute()
{
Do();
}
public void Do()
{
resourceTile = mapResources[cell];
mapResources[cell] = default(ResourceTile);
}
public void Undo()
{
mapResources[cell] = resourceTile;
}
}
}

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits;
@@ -23,6 +24,10 @@ namespace OpenRA.Mods.Common.Widgets
readonly World world;
readonly EditorViewportControllerWidget editorWidget;
readonly SpriteWidget preview;
readonly EditorActionManager editorActionManager;
AddResourcesEditorAction action;
bool resourceAdded;
public EditorResourceBrush(EditorViewportControllerWidget editorWidget, ResourceTypeInfo resource, WorldRenderer wr)
{
@@ -30,6 +35,8 @@ namespace OpenRA.Mods.Common.Widgets
ResourceType = resource;
worldRenderer = wr;
world = wr.World;
editorActionManager = world.WorldActor.Trait<EditorActionManager>();
action = new AddResourcesEditorAction(world.Map, ResourceType);
preview = editorWidget.Get<SpriteWidget>("DRAG_LAYER_PREVIEW");
preview.Palette = resource.Palette;
@@ -65,11 +72,18 @@ namespace OpenRA.Mods.Common.Widgets
var cell = worldRenderer.Viewport.ViewToWorld(mi.Location);
if (mi.Button == MouseButton.Left && AllowResourceAt(cell))
if (mi.Button == MouseButton.Left && mi.Event != MouseInputEvent.Up && AllowResourceAt(cell))
{
var type = (byte)ResourceType.ResourceType;
var index = (byte)ResourceType.MaxDensity;
world.Map.Resources[cell] = new ResourceTile(type, index);
action.Add(new CellResource(cell, world.Map.Resources[cell], new ResourceTile(type, index)));
resourceAdded = true;
}
else if (resourceAdded && mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Up)
{
editorActionManager.Add(action);
action = new AddResourcesEditorAction(world.Map, ResourceType);
resourceAdded = false;
}
return true;
@@ -112,4 +126,63 @@ namespace OpenRA.Mods.Common.Widgets
public void Dispose() { }
}
struct CellResource
{
public readonly CPos Cell;
public readonly ResourceTile ResourceTile;
public readonly ResourceTile NewResourceTile;
public CellResource(CPos cell, ResourceTile resourceTile, ResourceTile newResourceTile)
{
Cell = cell;
ResourceTile = resourceTile;
NewResourceTile = newResourceTile;
}
}
class AddResourcesEditorAction : IEditorAction
{
public string Text { get; private set; }
readonly Map map;
readonly ResourceTypeInfo resourceType;
readonly List<CellResource> cellResources = new List<CellResource>();
public AddResourcesEditorAction(Map map, ResourceTypeInfo resourceType)
{
this.map = map;
this.resourceType = resourceType;
}
public void Execute()
{
}
public void Do()
{
foreach (var resourceCell in cellResources)
SetTile(resourceCell.Cell, resourceCell.NewResourceTile);
}
void SetTile(CPos cell, ResourceTile tile)
{
map.Resources[cell] = tile;
}
public void Undo()
{
foreach (var resourceCell in cellResources)
SetTile(resourceCell.Cell, resourceCell.ResourceTile);
}
public void Add(CellResource cellResource)
{
SetTile(cellResource.Cell, cellResource.NewResourceTile);
cellResources.Add(cellResource);
var cellText = cellResources.Count != 1 ? "cells" : "cell";
Text = "Added {0} {1} of {2}".F(cellResources.Count, cellText, resourceType.TerrainType);
}
}
}

View File

@@ -13,6 +13,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
namespace OpenRA.Mods.Common.Widgets
@@ -26,6 +27,7 @@ namespace OpenRA.Mods.Common.Widgets
readonly EditorViewportControllerWidget editorWidget;
readonly TerrainTemplatePreviewWidget preview;
readonly Rectangle bounds;
readonly EditorActionManager editorActionManager;
bool painting;
@@ -36,6 +38,8 @@ namespace OpenRA.Mods.Common.Widgets
worldRenderer = wr;
world = wr.World;
editorActionManager = world.WorldActor.Trait<EditorActionManager>();
preview = editorWidget.Get<TerrainTemplatePreviewWidget>("DRAG_TILE_PREVIEW");
preview.GetScale = () => worldRenderer.Viewport.Zoom;
preview.IsVisible = () => editorWidget.CurrentBrush == this;
@@ -97,33 +101,13 @@ namespace OpenRA.Mods.Common.Widgets
void PaintCell(CPos cell, bool isMoving)
{
var map = world.Map;
var mapTiles = map.Tiles;
var mapHeight = map.Height;
var tileset = map.Rules.TileSet;
var template = tileset.Templates[Template];
var baseHeight = mapHeight.Contains(cell) ? mapHeight[cell] : (byte)0;
if (isMoving && PlacementOverlapsSameTemplate(template, cell))
return;
var i = 0;
for (var y = 0; y < template.Size.Y; y++)
{
for (var x = 0; x < template.Size.X; x++, i++)
{
if (template.Contains(i) && template[i] != null)
{
var index = template.PickAny ? (byte)Game.CosmeticRandom.Next(0, template.TilesCount) : (byte)i;
var c = cell + new CVec(x, y);
if (!mapTiles.Contains(c))
continue;
mapTiles[c] = new TerrainTile(Template, index);
mapHeight[c] = (byte)(baseHeight + template[index].Height).Clamp(0, map.Grid.MaximumTerrainHeight);
}
}
}
editorActionManager.Add(new PaintTileEditorAction(Template, map, cell));
}
void FloodFillWithBrush(CPos cell, bool isMoving)
@@ -239,4 +223,87 @@ namespace OpenRA.Mods.Common.Widgets
public void Dispose() { }
}
class PaintTileEditorAction : IEditorAction
{
public string Text { get; private set; }
readonly ushort template;
readonly Map map;
readonly CPos cell;
readonly Queue<UndoTile> undoTiles = new Queue<UndoTile>();
readonly TerrainTemplateInfo terrainTemplate;
public PaintTileEditorAction(ushort template, Map map, CPos cell)
{
this.template = template;
this.map = map;
this.cell = cell;
var tileset = map.Rules.TileSet;
terrainTemplate = tileset.Templates[template];
Text = "Added tile {0}".F(terrainTemplate.Id);
}
public void Execute()
{
Do();
}
public void Do()
{
var mapTiles = map.Tiles;
var mapHeight = map.Height;
var baseHeight = mapHeight.Contains(cell) ? mapHeight[cell] : (byte)0;
var i = 0;
for (var y = 0; y < terrainTemplate.Size.Y; y++)
{
for (var x = 0; x < terrainTemplate.Size.X; x++, i++)
{
if (terrainTemplate.Contains(i) && terrainTemplate[i] != null)
{
var index = terrainTemplate.PickAny ? (byte)Game.CosmeticRandom.Next(0, terrainTemplate.TilesCount) : (byte)i;
var c = cell + new CVec(x, y);
if (!mapTiles.Contains(c))
continue;
undoTiles.Enqueue(new UndoTile(c, mapTiles[c], mapHeight[c]));
mapTiles[c] = new TerrainTile(template, index);
mapHeight[c] = (byte)(baseHeight + terrainTemplate[index].Height).Clamp(0, map.Grid.MaximumTerrainHeight);
}
}
}
}
public void Undo()
{
var mapTiles = map.Tiles;
var mapHeight = map.Height;
while (undoTiles.Count > 0)
{
var undoTile = undoTiles.Dequeue();
mapTiles[undoTile.Cell] = undoTile.MapTile;
mapHeight[undoTile.Cell] = undoTile.Height;
}
}
}
class UndoTile
{
public CPos Cell { get; private set; }
public TerrainTile MapTile { get; private set; }
public byte Height { get; private set; }
public UndoTile(CPos cell, TerrainTile mapTile, byte height)
{
Cell = cell;
MapTile = mapTile;
Height = height;
}
}
}

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;
}
}
}

View File

@@ -11,6 +11,7 @@
using System;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
@@ -25,6 +26,7 @@ namespace OpenRA.Mods.Common.Widgets
readonly Lazy<TooltipContainerWidget> tooltipContainer;
readonly WorldRenderer worldRenderer;
readonly EditorActionManager editorActionManager;
bool enableTooltips;
@@ -34,6 +36,14 @@ namespace OpenRA.Mods.Common.Widgets
this.worldRenderer = worldRenderer;
tooltipContainer = Exts.Lazy(() => Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
CurrentBrush = DefaultBrush = new EditorDefaultBrush(this, worldRenderer);
editorActionManager = world.WorldActor.Trait<EditorActionManager>();
editorActionManager.OnChange += EditorActionManagerOnChange;
}
void EditorActionManagerOnChange()
{
DefaultBrush.SelectedActor = null;
}
public void ClearBrush() { SetBrush(null); }
@@ -109,5 +119,11 @@ namespace OpenRA.Mods.Common.Widgets
cachedViewportPosition = worldRenderer.Viewport.CenterPosition;
CurrentBrush.Tick();
}
public override void Removed()
{
base.Removed();
editorActionManager.OnChange -= EditorActionManagerOnChange;
}
}
}

View File

@@ -26,6 +26,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
readonly WorldRenderer worldRenderer;
readonly EditorActorLayer editorActorLayer;
readonly EditorActionManager editorActionManager;
readonly EditorViewportControllerWidget editor;
readonly BackgroundWidget actorEditPanel;
readonly LabelWidget typeLabel;
@@ -48,6 +49,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
string initialActorID;
EditorActorPreview currentActorInner;
EditActorPreview editActorPreview;
EditorActorPreview CurrentActor
{
get
@@ -61,7 +64,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
return;
if (currentActorInner != null)
{
Reset();
currentActorInner.Selected = false;
}
currentActorInner = value;
if (currentActorInner != null)
@@ -74,6 +80,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
{
this.worldRenderer = worldRenderer;
editorActorLayer = world.WorldActor.Trait<EditorActorLayer>();
editorActionManager = world.WorldActor.Trait<EditorActionManager>();
editor = widget.Parent.Get<EditorViewportControllerWidget>("MAP_EDITOR");
actorEditPanel = editor.Get<BackgroundWidget>("ACTOR_EDIT_PANEL");
@@ -88,7 +96,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
initContainer.RemoveChildren();
var deleteButton = actorEditPanel.Get<ButtonWidget>("DELETE_BUTTON");
var closeButton = actorEditPanel.Get<ButtonWidget>("CLOSE_BUTTON");
var cancelButton = actorEditPanel.Get<ButtonWidget>("CANCEL_BUTTON");
var okButton = actorEditPanel.Get<ButtonWidget>("OK_BUTTON");
actorIDErrorLabel = actorEditPanel.Get<LabelWidget>("ACTOR_ID_ERROR_LABEL");
actorIDErrorLabel.IsVisible = () => actorIDStatus != ActorIDStatus.Normal;
@@ -99,7 +108,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
if (logicArgs.TryGetValue("EditPanelPadding", out yaml))
editPanelPadding = FieldLoader.GetValue<int>("EditPanelPadding", yaml.Value);
closeButton.OnClick = Close;
okButton.IsDisabled = () => !IsValid() || !editActorPreview.IsDirty;
okButton.OnClick = Save;
cancelButton.OnClick = Cancel;
deleteButton.OnClick = Delete;
actorEditPanel.IsVisible = () => CurrentActor != null
&& editor.CurrentBrush == editor.DefaultBrush
@@ -113,15 +124,15 @@ namespace OpenRA.Mods.Common.Widgets.Logic
actorIDField.OnTextEdited = () =>
{
if (string.IsNullOrWhiteSpace(actorIDField.Text))
var actorId = actorIDField.Text.Trim();
if (string.IsNullOrWhiteSpace(actorId))
{
nextActorIDStatus = ActorIDStatus.Empty;
return;
}
// Check for duplicate actor ID
var actorId = actorIDField.Text.ToLowerInvariant();
if (CurrentActor.ID.ToLowerInvariant() != actorId)
if (CurrentActor.ID.Equals(actorId, StringComparison.OrdinalIgnoreCase))
{
if (editorActorLayer[actorId] != null)
{
@@ -130,23 +141,30 @@ namespace OpenRA.Mods.Common.Widgets.Logic
}
}
SetActorID(world, actorId);
SetActorID(actorId);
nextActorIDStatus = ActorIDStatus.Normal;
};
actorIDField.OnLoseFocus = () =>
{
// Reset invalid IDs back to their starting value
if (actorIDStatus != ActorIDStatus.Normal)
SetActorID(world, initialActorID);
SetActorID(initialActorID);
};
}
void SetActorID(World world, string actorId)
void SetActorID(string actorId)
{
CurrentActor.ID = actorId;
editActorPreview.SetActorID(actorId);
nextActorIDStatus = ActorIDStatus.Normal;
}
bool IsValid()
{
return nextActorIDStatus == ActorIDStatus.Normal;
}
public override void Tick()
{
if (actorIDStatus != nextActorIDStatus)
@@ -183,6 +201,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
lastScrollTime = 0; // Ensure visible
CurrentActor = actor;
editActorPreview = new EditActorPreview(CurrentActor);
initialActorID = actorIDField.Text = actor.ID;
var font = Game.Renderer.Fonts[typeLabel.Font];
@@ -203,13 +223,22 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var ownerDropdown = ownerContainer.Get<DropDownButtonWidget>("OPTION");
var selectedOwner = actor.Owner;
Action<EditorActorPreview, PlayerReference> updateOwner = (preview, reference) =>
{
preview.Owner = reference;
preview.ReplaceInit(new OwnerInit(reference.Name));
};
var ownerHandler = new EditorActorOptionActionHandle<PlayerReference>(updateOwner, actor.Owner);
editActorPreview.Add(ownerHandler);
Func<PlayerReference, ScrollItemWidget, ScrollItemWidget> setupItem = (option, template) =>
{
var item = ScrollItemWidget.Setup(template, () => selectedOwner == option, () =>
{
selectedOwner = option;
CurrentActor.Owner = selectedOwner;
CurrentActor.ReplaceInit(new OwnerInit(selectedOwner.Name));
updateOwner(CurrentActor, selectedOwner);
ownerHandler.OnChange(option);
});
item.Get<LabelWidget>("LABEL").GetText = () => option.Name;
@@ -248,8 +277,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
slider.MaximumValue = so.MaxValue;
slider.Ticks = so.Ticks;
var editorActionHandle = new EditorActorOptionActionHandle<float>(so.OnChange, so.GetValue(actor));
editActorPreview.Add(editorActionHandle);
slider.GetValue = () => so.GetValue(actor);
slider.OnChange += value => so.OnChange(actor, value);
slider.OnChange += value => editorActionHandle.OnChange(value);
initContainer.AddChild(sliderContainer);
}
@@ -261,12 +294,19 @@ namespace OpenRA.Mods.Common.Widgets.Logic
initContainer.Bounds.Height += dropdownContainer.Bounds.Height;
dropdownContainer.Get<LabelWidget>("LABEL").GetText = () => ddo.Name;
var editorActionHandle = new EditorActorOptionActionHandle<string>(ddo.OnChange, ddo.GetValue(actor));
editActorPreview.Add(editorActionHandle);
var dropdown = dropdownContainer.Get<DropDownButtonWidget>("OPTION");
Func<KeyValuePair<string, string>, ScrollItemWidget, ScrollItemWidget> dropdownSetup = (option, template) =>
{
var item = ScrollItemWidget.Setup(template,
() => ddo.GetValue(actor) == option.Key,
() => ddo.OnChange(actor, option.Key));
() =>
{
ddo.OnChange(actor, option.Key);
editorActionHandle.OnChange(option.Key);
});
item.Get<LabelWidget>("LABEL").GetText = () => option.Value;
return item;
@@ -298,16 +338,180 @@ namespace OpenRA.Mods.Common.Widgets.Logic
void Delete()
{
if (CurrentActor != null)
editorActorLayer.Remove(CurrentActor);
editorActionManager.Add(new RemoveActorAction(editorActorLayer, CurrentActor));
Close();
}
void Cancel()
{
Reset();
Close();
}
void Reset()
{
if (editActorPreview != null)
editActorPreview.Reset();
}
void Close()
{
actorIDField.YieldKeyboardFocus();
editor.DefaultBrush.SelectedActor = null;
CurrentActor = null;
}
void Save()
{
editorActionManager.Add(new EditActorEditorAction(editorActorLayer, CurrentActor, editActorPreview.GetDirtyHandles()));
editActorPreview = null;
Close();
}
}
public class EditorActorOptionActionHandle<T> : IEditActorHandle
{
readonly Action<EditorActorPreview, T> change;
T value;
readonly T initialValue;
public EditorActorOptionActionHandle(Action<EditorActorPreview, T> change, T value)
{
this.change = change;
this.value = value;
initialValue = value;
}
public void OnChange(T value)
{
IsDirty = !EqualityComparer<T>.Default.Equals(initialValue, value);
this.value = value;
}
public void Do(EditorActorPreview actor)
{
change(actor, value);
}
public void Undo(EditorActorPreview actor)
{
change(actor, initialValue);
}
public bool IsDirty { get; private set; }
}
public interface IEditActorHandle
{
void Do(EditorActorPreview actor);
void Undo(EditorActorPreview actor);
bool IsDirty { get; }
}
class EditActorEditorAction : IEditorAction
{
public string Text { get; private set; }
readonly IEnumerable<IEditActorHandle> handles;
readonly EditorActorLayer editorActorLayer;
EditorActorPreview actor;
readonly string actorId;
public EditActorEditorAction(EditorActorLayer editorActorLayer, EditorActorPreview actor, IEnumerable<IEditActorHandle> handles)
{
this.editorActorLayer = editorActorLayer;
actorId = actor.ID;
this.actor = actor;
this.handles = handles;
Text = "Edited {0} ({1})".F(actor.Info.Name, actor.ID);
}
public void Execute()
{
}
public void Do()
{
actor = editorActorLayer[actorId.ToLowerInvariant()];
foreach (var editorActionHandle in handles)
editorActionHandle.Do(actor);
}
public void Undo()
{
foreach (var editorActionHandle in handles)
editorActionHandle.Undo(actor);
}
}
class EditActorPreview
{
readonly EditorActorPreview actor;
readonly SetActorIdAction setActorIdAction;
readonly List<IEditActorHandle> handles = new List<IEditActorHandle>();
public EditActorPreview(EditorActorPreview actor)
{
this.actor = actor;
setActorIdAction = new SetActorIdAction(actor.ID);
handles.Add(setActorIdAction);
}
public bool IsDirty
{
get { return handles.Any(h => h.IsDirty); }
}
public void SetActorID(string actorID)
{
setActorIdAction.Set(actorID);
}
public void Add(IEditActorHandle editActor)
{
handles.Add(editActor);
}
public IEnumerable<IEditActorHandle> GetDirtyHandles()
{
return handles.Where(h => h.IsDirty);
}
public void Reset()
{
foreach (var handle in handles.Where(h => h.IsDirty))
handle.Undo(actor);
}
}
public class SetActorIdAction : IEditActorHandle
{
readonly string initial;
string newID;
public void Set(string actorId)
{
IsDirty = initial != actorId;
newID = actorId;
}
public SetActorIdAction(string initial)
{
this.initial = initial;
}
public void Do(EditorActorPreview actor)
{
actor.ID = newID;
}
public void Undo(EditorActorPreview actor)
{
actor.ID = initial;
}
public bool IsDirty { get; private set; }
}
}

View File

@@ -0,0 +1,71 @@
#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.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets.Logic
{
public class HistoryLogLogic : ChromeLogic
{
readonly ScrollPanelWidget panel;
readonly EditorActionManager editorActionManager;
readonly ScrollItemWidget template;
readonly Dictionary<EditorActionContainer, ScrollItemWidget> states = new Dictionary<EditorActionContainer, ScrollItemWidget>();
[ObjectCreator.UseCtor]
public HistoryLogLogic(Widget widget, World world, WorldRenderer worldRenderer, Dictionary<string, MiniYaml> logicArgs)
{
panel = widget.Get<ScrollPanelWidget>("HISTORY_LIST");
template = panel.Get<ScrollItemWidget>("HISTORY_TEMPLATE");
editorActionManager = world.WorldActor.Trait<EditorActionManager>();
editorActionManager.ItemAdded += ItemAdded;
editorActionManager.ItemRemoved += ItemRemoved;
}
void ItemAdded(EditorActionContainer editorAction)
{
var item = ScrollItemWidget.Setup(template, () => false, () =>
{
if (editorAction.Status == EditorActionStatus.History)
editorActionManager.Rewind(editorAction.Id);
else if (editorAction.Status == EditorActionStatus.Future)
editorActionManager.Forward(editorAction.Id);
});
var titleLabel = item.Get<LabelWidget>("TITLE");
var textColor = template.TextColor;
var futureTextColor = template.TextColorDisabled;
titleLabel.GetText = () => editorAction.Action.Text;
titleLabel.GetColor = () => editorAction.Status == EditorActionStatus.Future ? futureTextColor : textColor;
item.IsSelected = () => editorAction.Status == EditorActionStatus.Active;
panel.AddChild(item);
states[editorAction] = item;
}
void ItemRemoved(EditorActionContainer editorAction)
{
var widget = states[editorAction];
panel.RemoveChild(widget);
states.Remove(editorAction);
}
}
}

View File

@@ -128,6 +128,21 @@ namespace OpenRA.Mods.Common.Widgets.Logic
if (reslayer != null)
cashLabel.GetText = () => "$ {0}".F(reslayer.NetWorth);
}
var actionManager = world.WorldActor.Trait<EditorActionManager>();
var undoButton = widget.GetOrNull<ButtonWidget>("UNDO_BUTTON");
if (undoButton != null)
{
undoButton.IsDisabled = () => !actionManager.HasUndos();
undoButton.OnClick = () => actionManager.Undo();
}
var redoButton = widget.GetOrNull<ButtonWidget>("REDO_BUTTON");
if (redoButton != null)
{
redoButton.IsDisabled = () => !actionManager.HasRedos();
redoButton.OnClick = () => actionManager.Redo();
}
}
Widget CreateCategoriesPanel()

View File

@@ -18,7 +18,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
{
readonly Widget widget;
protected enum MenuType { Tiles, Layers, Actors }
protected enum MenuType { Tiles, Layers, Actors, History }
protected MenuType menuType = MenuType.Tiles;
readonly Widget tabContainer;
@@ -31,6 +31,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
SetupTab("TILES_TAB", "TILE_WIDGETS", MenuType.Tiles);
SetupTab("OVERLAYS_TAB", "LAYER_WIDGETS", MenuType.Layers);
SetupTab("ACTORS_TAB", "ACTOR_WIDGETS", MenuType.Actors);
SetupTab("HISTORY_TAB", "HISTORY_WIDGETS", MenuType.History);
}
void SetupTab(string buttonId, string tabId, MenuType tabType)

View File

@@ -292,15 +292,21 @@ Container@EDITOR_WORLD_ROOT:
Children:
Button@DELETE_BUTTON:
X: 4
Width: 85
Width: 75
Height: 25
Text: Delete
Font: Bold
Button@CLOSE_BUTTON:
X: 180
Width: 85
Button@CANCEL_BUTTON:
X: 110
Width: 75
Height: 25
Text: Close
Text: Cancel
Font: Bold
Button@OK_BUTTON:
X: 190
Width: 75
Height: 25
Text: OK
Font: Bold
ViewportController:
Width: WINDOW_RIGHT
@@ -318,10 +324,10 @@ Container@EDITOR_WORLD_ROOT:
BookmarkRestoreKeyPrefix: MapBookmarkRestore
BookmarkKeyCount: 4
Background@RADAR_BG:
X: WINDOW_RIGHT - 255
X: WINDOW_RIGHT - 295
Y: 5
Width: 250
Height: 250
Width: 290
Height: 290
Background: panel-gray
Children:
Radar@INGAME_RADAR:
@@ -332,7 +338,7 @@ Container@EDITOR_WORLD_ROOT:
MenuButton@OPTIONS_BUTTON:
Logic: MenuButtonsChromeLogic
Key: escape
X: WINDOW_RIGHT - 254 - WIDTH
X: WINDOW_RIGHT - 294 - WIDTH
Y: 5
Width: 30
Height: 25
@@ -346,10 +352,10 @@ Container@EDITOR_WORLD_ROOT:
ImageName: options
Container@TILE_WIDGETS:
Logic: TileSelectorLogic
X: WINDOW_RIGHT - 255
Y: 278
Width: 250
Height: WINDOW_BOTTOM - 370
X: WINDOW_RIGHT - 295
Y: 318
Width: 290
Height: WINDOW_BOTTOM - 410
ClickThrough: false
Children:
Container@TILES_BG:
@@ -402,10 +408,10 @@ Container@EDITOR_WORLD_ROOT:
Y: 4
Container@LAYER_WIDGETS:
Logic: LayerSelectorLogic
X: WINDOW_RIGHT - 255
Y: 278
Width: 250
Height: WINDOW_BOTTOM - 370
X: WINDOW_RIGHT - 295
Y: 318
Width: 290
Height: WINDOW_BOTTOM - 410
ClickThrough: false
Children:
Container@LAYERS_BG:
@@ -429,10 +435,10 @@ Container@EDITOR_WORLD_ROOT:
Visible: false
Container@ACTOR_WIDGETS:
Logic: ActorSelectorLogic
X: WINDOW_RIGHT - 255
Y: 278
Width: 250
Height: WINDOW_BOTTOM - 370
X: WINDOW_RIGHT - 295
Y: 318
Width: 290
Height: WINDOW_BOTTOM - 410
ClickThrough: false
Children:
Container@ACTORS_BG:
@@ -499,33 +505,72 @@ Container@EDITOR_WORLD_ROOT:
X: 4
Y: 4
Visible: true
Container@HISTORY_WIDGETS:
Logic: HistoryLogLogic
X: WINDOW_RIGHT - 295
Y: 318
Width: 290
Height: WINDOW_BOTTOM - 410
ClickThrough: false
Children:
Container@HISTORY_BG:
Width: PARENT_RIGHT
Height: PARENT_BOTTOM
Children:
ScrollPanel@HISTORY_LIST:
Width: PARENT_RIGHT
Height: PARENT_BOTTOM
CollapseHiddenChildren: True
TopBottomSpacing: 4
ItemSpacing: 4
Children:
ScrollItem@HISTORY_TEMPLATE:
X: 4
Visible: false
Width: PARENT_RIGHT - 31
Height: 25
IgnoreChildMouseOver: true
TextColor: ffffff
TextColorDisabled: 8f8f8f
Children:
Label@TITLE:
X: 5
Width: PARENT_RIGHT
Height: 25
Align: Left
Container@MAP_EDITOR_TAB_CONTAINER:
Logic: MapEditorTabsLogic
X: WINDOW_RIGHT - 255
Y: 254
Width: 250
X: WINDOW_RIGHT - 295
Y: 294
Width: 290
Height: 25
ClickThrough: false
Children:
Button@TILES_TAB:
Width: 81
Width: 71
Height: 25
Text: Tiles
Font: Bold
Button@OVERLAYS_TAB:
X: 80
Width: 90
X: 70
Width: 80
Height: 25
Text: Overlays
Font: Bold
Button@ACTORS_TAB:
X: 169
Width: 81
X: 149
Width: 71
Height: 25
Text: Actors
Font: Bold
Button@HISTORY_TAB:
X: 219
Width: 71
Height: 25
Text: History
Font: Bold
Button@GRID_BUTTON:
X: WINDOW_RIGHT - 650
X: WINDOW_RIGHT - 690
Y: 5
Width: 100
Height: 25
@@ -536,7 +581,7 @@ Container@EDITOR_WORLD_ROOT:
TooltipText: Toggle the terrain grid
TooltipContainer: TOOLTIP_CONTAINER
Label@ZOOM_LABEL:
X: WINDOW_RIGHT - 730 - 55
X: WINDOW_RIGHT - 770 - 55
Y: 5
Width: 50
Height: 25
@@ -545,7 +590,7 @@ Container@EDITOR_WORLD_ROOT:
Font: Bold
Contrast: true
DropDownButton@ZOOM_BUTTON:
X: WINDOW_RIGHT - 730
X: WINDOW_RIGHT - 770
Y: 5
Width: 70
Height: 25
@@ -555,7 +600,7 @@ Container@EDITOR_WORLD_ROOT:
TooltipText: Zoom
TooltipContainer: TOOLTIP_CONTAINER
Button@COPYPASTE_BUTTON:
X: WINDOW_RIGHT - 540
X: WINDOW_RIGHT - 580
Y: 5
Width: 96
Height: 25
@@ -565,7 +610,7 @@ Container@EDITOR_WORLD_ROOT:
TooltipText: Copy
TooltipContainer: TOOLTIP_CONTAINER
DropDownButton@COPYFILTER_BUTTON:
X: WINDOW_RIGHT - 435
X: WINDOW_RIGHT - 475
Y: 5
Width: 140
Height: 25
@@ -585,6 +630,26 @@ Container@EDITOR_WORLD_ROOT:
Align: Left
Font: Bold
Contrast: true
Button@UNDO_BUTTON:
X: 200
Height: 25
Width: 100
Text: Undo
Font: Bold
Key: z ctrl
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: Undo last step
TooltipContainer: TOOLTIP_CONTAINER
Button@REDO_BUTTON:
X: 305
Height: 25
Width: 100
Text: Redo
Font: Bold
Key: y ctrl
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: Redo last step
TooltipContainer: TOOLTIP_CONTAINER
ScrollPanel@CATEGORY_FILTER_PANEL:
Width: 190

View File

@@ -268,3 +268,4 @@ EditorWorld:
EditorResourceLayer:
EditorSelectionLayer:
LoadWidgetAtGameStart:
EditorActionManager:

View File

@@ -287,15 +287,21 @@ Container@EDITOR_WORLD_ROOT:
Children:
Button@DELETE_BUTTON:
X: 15
Width: 85
Width: 75
Height: 25
Text: Delete
Font: Bold
Button@CLOSE_BUTTON:
X: 195
Width: 85
Button@CANCEL_BUTTON:
X: 125
Width: 75
Height: 25
Text: Close
Text: Cancel
Font: Bold
Button@OK_BUTTON:
X: 205
Width: 75
Height: 25
Text: OK
Font: Bold
ViewportController:
Width: WINDOW_RIGHT
@@ -313,10 +319,10 @@ Container@EDITOR_WORLD_ROOT:
BookmarkRestoreKeyPrefix: MapBookmarkRestore
BookmarkKeyCount: 4
Background@RADAR_BG:
X: WINDOW_RIGHT - 255
X: WINDOW_RIGHT - 325
Y: 5
Width: 250
Height: 250
Width: 320
Height: 320
Children:
Radar@INGAME_RADAR:
X: 10
@@ -327,10 +333,10 @@ Container@EDITOR_WORLD_ROOT:
Logic: TileSelectorLogic
Children:
Background@TILES_BG:
X: WINDOW_RIGHT - 250
Y: 290
Width: 240
Height: WINDOW_BOTTOM - 382
X: WINDOW_RIGHT - 320
Y: 360
Width: 310
Height: WINDOW_BOTTOM - 452
Children:
Label@SEARCH_LABEL:
Y: 12
@@ -378,10 +384,10 @@ Container@EDITOR_WORLD_ROOT:
Logic: LayerSelectorLogic
Children:
Background@LAYERS_BG:
X: WINDOW_RIGHT - 250
Y: 290
Width: 240
Height: WINDOW_BOTTOM - 382
X: WINDOW_RIGHT - 320
Y: 360
Width: 310
Height: WINDOW_BOTTOM - 452
Children:
ScrollPanel@LAYERTEMPLATE_LIST:
X: 10
@@ -405,10 +411,10 @@ Container@EDITOR_WORLD_ROOT:
Logic: ActorSelectorLogic
Children:
Background@ACTORS_BG:
X: WINDOW_RIGHT - 250
Y: 290
Width: 240
Height: WINDOW_BOTTOM - 382
X: WINDOW_RIGHT - 320
Y: 360
Width: 310
Height: WINDOW_BOTTOM - 452
Children:
Label@SEARCH_LABEL:
Y: 12
@@ -467,11 +473,44 @@ Container@EDITOR_WORLD_ROOT:
X: 4
Y: 4
Visible: true
Container@HISTORY_WIDGETS:
Logic: HistoryLogLogic
Visible: false
Children:
Background@HISTORY_BG:
X: WINDOW_RIGHT - 320
Y: 360
Width: 310
Height: WINDOW_BOTTOM - 452
Children:
ScrollPanel@HISTORY_LIST:
X: 10
Y: 10
Width: PARENT_RIGHT - 20
Height: PARENT_BOTTOM - 20
CollapseHiddenChildren: True
TopBottomSpacing: 4
ItemSpacing: 4
Children:
ScrollItem@HISTORY_TEMPLATE:
X: 4
Visible: false
Width: PARENT_RIGHT - 31
Height: 25
IgnoreChildMouseOver: true
TextColor: ffffff
TextColorDisabled: 8f8f8f
Children:
Label@TITLE:
X: 5
Width: PARENT_RIGHT
Height: 25
Align: Left
Container@MAP_EDITOR_TAB_CONTAINER:
Logic: MapEditorTabsLogic
X: WINDOW_RIGHT - 245
Y: 260
Width: 240
X: WINDOW_RIGHT - 315
Y: 330
Width: 310
Height: 25
Children:
Button@TILES_TAB:
@@ -492,6 +531,12 @@ Container@EDITOR_WORLD_ROOT:
Height: 25
Text: Actors
Font: Bold
Button@HISTORY_TAB:
X: 230
Width: 70
Height: 25
Text: History
Font: Bold
MenuButton@OPTIONS_BUTTON:
Logic: MenuButtonsChromeLogic
MenuContainer: INGAME_MENU
@@ -547,15 +592,35 @@ Container@EDITOR_WORLD_ROOT:
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: Zoom
TooltipContainer: TOOLTIP_CONTAINER
Button@UNDO_BUTTON:
X: 630
Height: 25
Width: 90
Text: Undo
Font: Bold
Key: z ctrl
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: Undo last step
TooltipContainer: TOOLTIP_CONTAINER
Button@REDO_BUTTON:
X: 730
Height: 25
Width: 90
Text: Redo
Font: Bold
Key: y ctrl
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: Redo last step
TooltipContainer: TOOLTIP_CONTAINER
Label@COORDINATE_LABEL:
X: 635
X: 835
Width: 50
Height: 25
Align: Left
Font: Bold
Contrast: true
Label@CASH_LABEL:
X: 750
X: 950
Width: 50
Height: 25
Align: Left

View File

@@ -243,3 +243,4 @@ EditorWorld:
D2kEditorResourceLayer:
EditorSelectionLayer:
LoadWidgetAtGameStart:
EditorActionManager:

View File

@@ -284,3 +284,4 @@ EditorWorld:
EditorResourceLayer:
EditorSelectionLayer:
LoadWidgetAtGameStart:
EditorActionManager:

View File

@@ -379,3 +379,4 @@ EditorWorld:
EditorSelectionLayer:
Palette: placefootprint
LoadWidgetAtGameStart:
EditorActionManager: