Editor selection refactor pt1

This commit is contained in:
David Wilson
2023-12-14 18:23:04 +10:00
committed by Gustas
parent b58c1ea5bc
commit 2ced4abc24
41 changed files with 1560 additions and 854 deletions

View File

@@ -0,0 +1,90 @@
#region Copyright & License Information
/*
* Copyright (c) The OpenRA Developers and Contributors
* 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;
using System.Collections.Generic;
namespace OpenRA
{
public readonly struct CellCoordsRegion : IEnumerable<CPos>
{
public struct CellCoordsEnumerator : IEnumerator<CPos>
{
readonly CellCoordsRegion r;
public CellCoordsEnumerator(CellCoordsRegion region)
: this()
{
r = region;
Reset();
}
public bool MoveNext()
{
var x = Current.X + 1;
var y = Current.Y;
// Check for column overflow.
if (x > r.BottomRight.X)
{
y++;
x = r.TopLeft.X;
// Check for row overflow.
if (y > r.BottomRight.Y)
return false;
}
Current = new CPos(x, y);
return true;
}
public void Reset()
{
Current = new CPos(r.TopLeft.X - 1, r.TopLeft.Y);
}
public CPos Current { get; private set; }
readonly object IEnumerator.Current => Current;
public readonly void Dispose() { }
}
public CellCoordsRegion(CPos topLeft, CPos bottomRight)
{
TopLeft = topLeft;
BottomRight = bottomRight;
}
public override string ToString()
{
return $"{TopLeft}->{BottomRight}";
}
public CellCoordsEnumerator GetEnumerator()
{
return new CellCoordsEnumerator(this);
}
IEnumerator<CPos> IEnumerable<CPos>.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public CPos TopLeft { get; }
public CPos BottomRight { get; }
}
}

View File

@@ -102,6 +102,7 @@ namespace OpenRA
}
public MapCoordsRegion MapCoords => new(mapTopLeft, mapBottomRight);
public CellCoordsRegion CellCoords => new(TopLeft, BottomRight);
public CellRegionEnumerator GetEnumerator()
{

View File

@@ -296,6 +296,9 @@ namespace OpenRA.Traits
int2 GetDecorationOrigin(Actor self, WorldRenderer wr, string pos, int2 margin);
}
public interface IEditorSelectionLayer : ITraitInfoInterface { }
public interface IEditorPasteLayer : ITraitInfoInterface { }
public interface IMapPreviewSignatureInfo : ITraitInfoInterface
{
void PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List<(MPos Uv, Color Color)> destinationBuffer);

View File

@@ -0,0 +1,35 @@
using System.Collections.Generic;
using OpenRA.Mods.Common.Traits;
namespace OpenRA.Mods.Common.EditorBrushes
{
public readonly struct ClipboardTile
{
public readonly TerrainTile TerrainTile;
public readonly ResourceTile ResourceTile;
public readonly ResourceLayerContents ResourceLayerContents;
public readonly byte Height;
public ClipboardTile(TerrainTile terrainTile, ResourceTile resourceTile, ResourceLayerContents resourceLayerContents, byte height)
{
TerrainTile = terrainTile;
ResourceTile = resourceTile;
ResourceLayerContents = resourceLayerContents;
Height = height;
}
}
public readonly struct EditorClipboard
{
public readonly CellRegion CellRegion;
public readonly Dictionary<string, EditorActorPreview> Actors;
public readonly Dictionary<CPos, ClipboardTile> Tiles;
public EditorClipboard(CellRegion cellRegion, Dictionary<string, EditorActorPreview> actors, Dictionary<CPos, ClipboardTile> tiles)
{
CellRegion = cellRegion;
Actors = actors;
Tiles = tiles;
}
}
}

View File

@@ -13,6 +13,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.EditorBrushes;
using OpenRA.Mods.Common.Traits;
namespace OpenRA.Mods.Common.Widgets
@@ -29,29 +30,33 @@ namespace OpenRA.Mods.Common.Widgets
public sealed class EditorCopyPasteBrush : IEditorBrush
{
enum State { SelectFirst, SelectSecond, Paste }
readonly WorldRenderer worldRenderer;
readonly EditorViewportControllerWidget editorWidget;
readonly EditorSelectionLayer selectionLayer;
readonly EditorActorLayer editorLayer;
readonly Func<MapCopyFilters> getCopyFilters;
readonly EditorActorLayer editorActorLayer;
readonly EditorActionManager editorActionManager;
readonly EditorClipboard clipboard;
readonly IResourceLayer resourceLayer;
readonly Func<MapCopyFilters> getCopyFilters;
State state;
CPos start;
CPos end;
public CPos? PastePreviewPosition { get; private set; }
public EditorCopyPasteBrush(EditorViewportControllerWidget editorWidget, WorldRenderer wr, Func<MapCopyFilters> getCopyFilters)
public CellRegion Region => clipboard.CellRegion;
public EditorCopyPasteBrush(
EditorViewportControllerWidget editorWidget,
WorldRenderer wr,
EditorClipboard clipboard,
IResourceLayer resourceLayer,
Func<MapCopyFilters> getCopyFilters)
{
this.getCopyFilters = getCopyFilters;
this.editorWidget = editorWidget;
this.clipboard = clipboard;
this.resourceLayer = resourceLayer;
worldRenderer = wr;
editorActionManager = wr.World.WorldActor.Trait<EditorActionManager>();
selectionLayer = wr.World.WorldActor.Trait<EditorSelectionLayer>();
editorLayer = wr.World.WorldActor.Trait<EditorActorLayer>();
this.getCopyFilters = getCopyFilters;
editorActorLayer = wr.World.WorldActor.Trait<EditorActorLayer>();
}
public bool HandleMouseInput(MouseInput mi)
@@ -71,106 +76,31 @@ namespace OpenRA.Mods.Common.Widgets
return false;
}
if (mi.Button == MouseButton.Left && (mi.Event == MouseInputEvent.Up || mi.Event == MouseInputEvent.Down))
if (mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Down)
{
var cell = worldRenderer.Viewport.ViewToWorld(mi.Location);
switch (state)
{
case State.SelectFirst:
if (mi.Event != MouseInputEvent.Down)
break;
start = cell;
selectionLayer.SetCopyRegion(start, end);
state = State.SelectSecond;
break;
case State.SelectSecond:
if (mi.Event != MouseInputEvent.Up)
break;
end = cell;
selectionLayer.SetCopyRegion(start, end);
state = State.Paste;
break;
case State.Paste:
{
if (mi.Event != MouseInputEvent.Down)
break;
var gridType = worldRenderer.World.Map.Grid.Type;
var source = CellRegion.BoundingRegion(gridType, new[] { start, end });
Copy(source, cell - end);
break;
}
}
var pastePosition = worldRenderer.Viewport.ViewToWorld(Viewport.LastMousePos);
var action = new CopyPasteEditorAction(
getCopyFilters(),
resourceLayer,
pastePosition,
worldRenderer.World.Map,
clipboard,
editorActorLayer);
editorActionManager.Add(action);
return true;
}
return false;
}
void Copy(CellRegion source, CVec offset)
{
var gridType = worldRenderer.World.Map.Grid.Type;
var mapTiles = worldRenderer.World.Map.Tiles;
var mapHeight = worldRenderer.World.Map.Height;
var mapResources = worldRenderer.World.Map.Resources;
var dest = new CellRegion(gridType, source.TopLeft + offset, source.BottomRight + offset);
var previews = new Dictionary<string, ActorReference>();
var tiles = new Dictionary<CPos, (TerrainTile, ResourceTile, byte)>();
var copyFilters = getCopyFilters();
foreach (var cell in source)
{
if (!mapTiles.Contains(cell) || !mapTiles.Contains(cell + offset))
continue;
tiles.Add(cell + offset, (mapTiles[cell], mapResources[cell], mapHeight[cell]));
if (copyFilters.HasFlag(MapCopyFilters.Actors))
{
foreach (var preview in editorLayer.PreviewsAt(cell))
{
if (previews.ContainsKey(preview.ID))
continue;
var copy = preview.Export();
var locationInit = copy.GetOrDefault<LocationInit>();
if (locationInit != null)
{
copy.RemoveAll<LocationInit>();
copy.Add(new LocationInit(locationInit.Value + offset));
}
previews.Add(preview.ID, copy);
}
}
}
var action = new CopyPasteEditorAction(copyFilters, worldRenderer.World.Map, tiles, previews, editorLayer, dest);
editorActionManager.Add(action);
}
public void Tick()
{
var cell = worldRenderer.Viewport.ViewToWorld(Viewport.LastMousePos);
if (state == State.Paste)
{
selectionLayer.SetPasteRegion(cell + (start - end), cell);
return;
}
if (state == State.SelectFirst)
start = end = cell;
else if (state == State.SelectSecond)
end = cell;
selectionLayer.SetCopyRegion(start, end);
PastePreviewPosition = worldRenderer.Viewport.ViewToWorld(Viewport.LastMousePos);
}
public void Dispose()
{
selectionLayer.Clear();
}
}
@@ -182,33 +112,64 @@ namespace OpenRA.Mods.Common.Widgets
public string Text { get; }
readonly MapCopyFilters copyFilters;
readonly Dictionary<CPos, (TerrainTile Tile, ResourceTile Resource, byte Height)> 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 IResourceLayer resourceLayer;
readonly EditorActorLayer editorActorLayer;
readonly EditorClipboard clipboard;
readonly EditorClipboard undoClipboard;
readonly CPos pastePosition;
readonly Map map;
readonly Queue<UndoCopyPaste> undoCopyPastes = new();
readonly Queue<EditorActorPreview> removedActors = new();
readonly Queue<EditorActorPreview> addedActorPreviews = new();
public CopyPasteEditorAction(MapCopyFilters copyFilters, Map map,
Dictionary<CPos, (TerrainTile Tile, ResourceTile Resource, byte Height)> tiles, Dictionary<string, ActorReference> previews,
EditorActorLayer editorLayer, CellRegion dest)
public CopyPasteEditorAction(
MapCopyFilters copyFilters,
IResourceLayer resourceLayer,
CPos pastePosition,
Map map,
EditorClipboard clipboard,
EditorActorLayer editorActorLayer)
{
this.copyFilters = copyFilters;
this.tiles = tiles;
this.previews = previews;
this.editorLayer = editorLayer;
this.dest = dest;
this.resourceLayer = resourceLayer;
this.clipboard = clipboard;
this.pastePosition = pastePosition;
this.editorActorLayer = editorActorLayer;
this.map = map;
mapTiles = map.Tiles;
mapHeight = map.Height;
mapResources = map.Resources;
undoClipboard = CopySelectionContents();
Text = TranslationProvider.GetString(CopiedTiles, Translation.Arguments("amount", tiles.Count));
Text = TranslationProvider.GetString(CopiedTiles, Translation.Arguments("amount", clipboard.Tiles.Count));
}
/// <summary>
/// TODO: This is pretty much repeated in MapEditorSelectionLogic.
/// </summary>
/// <returns>Clipboard containing map contents for this region.</returns>
EditorClipboard CopySelectionContents()
{
var selectionSize = clipboard.CellRegion.BottomRight - clipboard.CellRegion.TopLeft;
var source = new CellCoordsRegion(pastePosition, pastePosition + selectionSize);
var selection = new CellRegion(map.Grid.Type, pastePosition, pastePosition + selectionSize);
var mapTiles = map.Tiles;
var mapHeight = map.Height;
var mapResources = map.Resources;
var previews = new Dictionary<string, EditorActorPreview>();
var tiles = new Dictionary<CPos, ClipboardTile>();
foreach (var cell in source)
{
if (!mapTiles.Contains(cell))
continue;
var resourceLayerContents = resourceLayer.GetResource(cell);
tiles.Add(cell, new ClipboardTile(mapTiles[cell], mapResources[cell], resourceLayerContents, mapHeight[cell]));
if (copyFilters.HasFlag(MapCopyFilters.Actors))
foreach (var preview in selection.SelectMany(editorActorLayer.PreviewsAt).Distinct())
previews.TryAdd(preview.ID, preview);
}
return new EditorClipboard(selection, previews, tiles);
}
public void Execute()
@@ -218,72 +179,88 @@ namespace OpenRA.Mods.Common.Widgets
public void Do()
{
foreach (var kv in tiles)
var sourcePos = clipboard.CellRegion.TopLeft;
var pasteVec = new CVec(pastePosition.X - sourcePos.X, pastePosition.Y - sourcePos.Y);
foreach (var tileKeyValuePair in clipboard.Tiles)
{
undoCopyPastes.Enqueue(new UndoCopyPaste(kv.Key, mapTiles[kv.Key], mapResources[kv.Key], mapHeight[kv.Key]));
var position = tileKeyValuePair.Key + pasteVec;
if (!map.Contains(position))
continue;
// Clear any existing resources.
if (copyFilters.HasFlag(MapCopyFilters.Resources))
resourceLayer.ClearResources(position);
var tile = tileKeyValuePair.Value;
var resourceLayerContents = tile.ResourceLayerContents;
if (copyFilters.HasFlag(MapCopyFilters.Terrain))
mapTiles[kv.Key] = kv.Value.Tile;
if (copyFilters.HasFlag(MapCopyFilters.Resources))
mapResources[kv.Key] = kv.Value.Resource;
mapHeight[kv.Key] = kv.Value.Height;
}
if (copyFilters.HasFlag(MapCopyFilters.Actors))
{
var removeActors = dest.SelectMany(editorLayer.PreviewsAt).Distinct().ToList();
foreach (var preview in removeActors)
{
removedActors.Enqueue(preview);
editorLayer.Remove(preview);
}
map.Tiles[position] = tile.TerrainTile;
map.Height[position] = tile.Height;
}
foreach (var kv in previews)
addedActorPreviews.Enqueue(editorLayer.Add(kv.Value));
if (copyFilters.HasFlag(MapCopyFilters.Resources) && !string.IsNullOrWhiteSpace(resourceLayerContents.Type))
resourceLayer.AddResource(resourceLayerContents.Type, position, resourceLayerContents.Density);
}
// Clear any existing actors in the paste cells.
var selectionSize = clipboard.CellRegion.BottomRight - clipboard.CellRegion.TopLeft;
var pasteRegion = new CellRegion(map.Grid.Type, pastePosition, pastePosition + selectionSize);
foreach (var regionActor in pasteRegion.SelectMany(editorActorLayer.PreviewsAt).ToHashSet())
editorActorLayer.Remove(regionActor);
// Now place actors.
foreach (var actorKeyValuePair in clipboard.Actors)
{
var selection = clipboard.CellRegion;
var copy = actorKeyValuePair.Value.Export();
var locationInit = copy.GetOrDefault<LocationInit>();
if (locationInit != null)
{
var actorPosition = locationInit.Value + new CVec(pastePosition.X - selection.TopLeft.X, pastePosition.Y - selection.TopLeft.Y);
if (!map.Contains(actorPosition))
continue;
copy.RemoveAll<LocationInit>();
copy.Add(new LocationInit(actorPosition));
}
editorActorLayer.Add(copy);
}
}
public void Undo()
{
while (undoCopyPastes.Count > 0)
foreach (var tileKeyValuePair in undoClipboard.Tiles)
{
var undoCopyPaste = undoCopyPastes.Dequeue();
var position = tileKeyValuePair.Key;
var tile = tileKeyValuePair.Value;
var resourceLayerContents = tile.ResourceLayerContents;
var cell = undoCopyPaste.Cell;
// Clear any existing resources.
if (copyFilters.HasFlag(MapCopyFilters.Resources))
resourceLayer.ClearResources(position);
if (copyFilters.HasFlag(MapCopyFilters.Terrain))
mapTiles[cell] = undoCopyPaste.MapTile;
if (copyFilters.HasFlag(MapCopyFilters.Resources))
mapResources[cell] = undoCopyPaste.ResourceTile;
mapHeight[cell] = undoCopyPaste.Height;
{
map.Tiles[position] = tile.TerrainTile;
map.Height[position] = tile.Height;
}
while (addedActorPreviews.Count > 0)
editorLayer.Remove(addedActorPreviews.Dequeue());
if (copyFilters.HasFlag(MapCopyFilters.Resources) && !string.IsNullOrWhiteSpace(resourceLayerContents.Type))
resourceLayer.AddResource(resourceLayerContents.Type, position, resourceLayerContents.Density);
}
// Clear existing actors.
foreach (var regionActor in undoClipboard.CellRegion.SelectMany(editorActorLayer.PreviewsAt).Distinct().ToList())
editorActorLayer.Remove(regionActor);
// Place actors back again.
if (copyFilters.HasFlag(MapCopyFilters.Actors))
while (removedActors.Count > 0)
editorLayer.Add(removedActors.Dequeue());
}
}
sealed class UndoCopyPaste
{
public CPos Cell { get; }
public TerrainTile MapTile { get; }
public ResourceTile ResourceTile { get; }
public byte Height { get; }
public UndoCopyPaste(CPos cell, TerrainTile mapTile, ResourceTile resourceTile, byte height)
{
Cell = cell;
MapTile = mapTile;
ResourceTile = resourceTile;
Height = height;
foreach (var actor in undoClipboard.Actors.Values)
editorActorLayer.Add(actor);
}
}
}

View File

@@ -12,6 +12,7 @@
using System;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
@@ -21,9 +22,17 @@ namespace OpenRA.Mods.Common.Widgets
void Tick();
}
public class EditorSelection
{
public CellRegion Area;
public EditorActorPreview Actor;
}
public sealed class EditorDefaultBrush : IEditorBrush
{
public readonly ActorInfo Actor;
const int MinMouseMoveBeforeDrag = 32;
public event Action SelectionChanged;
readonly WorldRenderer worldRenderer;
readonly World world;
@@ -32,7 +41,13 @@ namespace OpenRA.Mods.Common.Widgets
readonly EditorActionManager editorActionManager;
readonly IResourceLayer resourceLayer;
public EditorActorPreview SelectedActor;
public CellRegion CurrentDragBounds => selectionBounds ?? Selection.Area;
public EditorSelection Selection = new();
EditorSelection previousSelection;
CellRegion selectionBounds;
int2? selectionStartLocation;
CPos? selectionStartCell;
int2 worldPixel;
public EditorDefaultBrush(EditorViewportControllerWidget editorWidget, WorldRenderer wr)
@@ -58,13 +73,23 @@ namespace OpenRA.Mods.Common.Widgets
return ((long)pixelDistance << 32) + worldZPosition;
}
public void ClearSelection()
{
if (Selection.Area != null || Selection.Actor != null)
{
previousSelection = Selection;
Selection = new EditorSelection();
editorActionManager.Add(new ChangeSelectionAction(this, Selection, previousSelection));
SelectionChanged?.Invoke();
}
}
public bool HandleMouseInput(MouseInput mi)
{
// Exclusively uses mouse wheel and both mouse buttons, but nothing else
// Mouse move events are important for tooltips, so we always allow these through
if ((mi.Button != MouseButton.Left && mi.Button != MouseButton.Right
&& mi.Event != MouseInputEvent.Move && mi.Event != MouseInputEvent.Scroll) ||
mi.Event == MouseInputEvent.Down)
// Exclusively uses mouse wheel and both mouse buttons, but nothing else.
// Mouse move events are important for tooltips, so we always allow these through.
if (mi.Button != MouseButton.Left && mi.Button != MouseButton.Right
&& mi.Event != MouseInputEvent.Move && mi.Event != MouseInputEvent.Scroll)
return false;
worldPixel = worldRenderer.Viewport.ViewToWorldPx(mi.Location);
@@ -80,26 +105,115 @@ namespace OpenRA.Mods.Common.Widgets
else
editorWidget.SetTooltip(null);
// Finished with mouse move events, so let them bubble up the widget tree
// Selection box drag.
if (selectionStartLocation != null &&
(selectionBounds != null || (mi.Location - selectionStartLocation.Value).LengthSquared > MinMouseMoveBeforeDrag))
{
selectionStartCell ??= worldRenderer.Viewport.ViewToWorld(selectionStartLocation.Value);
var topLeft = new CPos(Math.Min(selectionStartCell.Value.X, cell.X), Math.Min(selectionStartCell.Value.Y, cell.Y));
var bottomRight = new CPos(Math.Max(selectionStartCell.Value.X, cell.X), Math.Max(selectionStartCell.Value.Y, cell.Y));
var width = bottomRight.X - topLeft.X;
var height = bottomRight.Y - topLeft.Y;
var gridType = worldRenderer.World.Map.Grid.Type;
// We've dragged enough to capture more than one cell, make a selection box.
if (selectionBounds == null)
{
selectionBounds = new CellRegion(gridType, topLeft, bottomRight);
// Lose focus on any search boxes so we can always copy/paste.
Ui.KeyboardFocusWidget = null;
}
else
{
// We already have a drag box; resize it
selectionBounds = new CellRegion(gridType, topLeft, bottomRight);
}
}
// Finished with mouse move events, so let them bubble up the widget tree.
if (mi.Event == MouseInputEvent.Move)
return false;
if (mi.Event == MouseInputEvent.Down && mi.Button == MouseButton.Left && selectionStartLocation == null)
{
// Start area drag.
selectionStartLocation = mi.Location;
}
if (mi.Event == MouseInputEvent.Up)
{
if (mi.Button == MouseButton.Left)
{
editorWidget.SetTooltip(null);
SelectedActor = underCursor;
selectionStartLocation = null;
selectionStartCell = null;
// If we've released a bounds drag.
if (selectionBounds != null)
{
// Set this as the editor selection.
previousSelection = Selection;
Selection = new EditorSelection
{
Area = selectionBounds
};
editorActionManager.Add(new ChangeSelectionAction(this, Selection, previousSelection));
selectionBounds = null;
SelectionChanged?.Invoke();
}
else if (underCursor != null)
{
// We've clicked on an actor.
if (Selection.Actor != underCursor)
{
previousSelection = Selection;
Selection = new EditorSelection
{
Actor = underCursor,
};
editorActionManager.Add(new ChangeSelectionAction(this, Selection, previousSelection));
SelectionChanged?.Invoke();
}
}
else if (Selection.Area != null || Selection.Actor != null)
{
// Released left mouse without dragging or selecting an actor - deselect current.
previousSelection = Selection;
Selection = new EditorSelection();
editorActionManager.Add(new ChangeSelectionAction(this, Selection, previousSelection));
SelectionChanged?.Invoke();
}
}
if (mi.Button == MouseButton.Right)
{
editorWidget.SetTooltip(null);
if (underCursor != null && underCursor != SelectedActor)
if (Selection.Area != null)
{
// Release right mouse button with a selection - clear selection.
previousSelection = Selection;
Selection = new EditorSelection();
editorActionManager.Add(new ChangeSelectionAction(this, Selection, previousSelection));
}
else
{
// Release right mouse button with no selection and over an actor - delete actor.
if (underCursor != null && underCursor != Selection.Actor)
editorActionManager.Add(new RemoveActorAction(editorLayer, underCursor));
// Or delete resource if found under cursor.
if (resourceUnderCursor != null)
editorActionManager.Add(new RemoveResourceAction(resourceLayer, cell, resourceUnderCursor));
}
}
}
return true;
}
@@ -108,6 +222,64 @@ namespace OpenRA.Mods.Common.Widgets
public void Dispose() { }
}
sealed class ChangeSelectionAction : IEditorAction
{
[TranslationReference("x", "y", "width", "height")]
const string SelectedArea = "notification-selected-area";
[TranslationReference("id")]
const string SelectedActor = "notification-selected-actor";
[TranslationReference]
const string ClearedSelection = "notification-cleared-selection";
public string Text { get; }
readonly EditorSelection selection;
readonly EditorSelection previousSelection;
readonly EditorDefaultBrush defaultBrush;
public ChangeSelectionAction(
EditorDefaultBrush defaultBrush,
EditorSelection selection,
EditorSelection previousSelection)
{
this.defaultBrush = defaultBrush;
this.selection = selection;
this.previousSelection = new EditorSelection
{
Actor = previousSelection.Actor,
Area = previousSelection.Area
};
if (selection.Area != null)
Text = TranslationProvider.GetString(SelectedArea, Translation.Arguments(
"x", selection.Area.TopLeft.X,
"y", selection.Area.TopLeft.Y,
"width", selection.Area.BottomRight.X - selection.Area.TopLeft.X,
"height", selection.Area.BottomRight.Y - selection.Area.TopLeft.Y));
else if (selection.Actor != null)
Text = TranslationProvider.GetString(SelectedActor, Translation.Arguments("id", selection.Actor.ID));
else
Text = TranslationProvider.GetString(ClearedSelection);
}
public void Execute()
{
Do();
}
public void Do()
{
defaultBrush.Selection = selection;
}
public void Undo()
{
defaultBrush.Selection = previousSelection;
}
}
sealed class RemoveActorAction : IEditorAction
{
[TranslationReference("name", "id")]

View File

@@ -0,0 +1,84 @@
#region Copyright & License Information
/*
* Copyright (c) The OpenRA Developers and Contributors
* 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 OpenRA.Graphics;
using OpenRA.Primitives;
namespace OpenRA.Mods.Common.Graphics
{
/// <summary>
/// Render the current editor area selection or paste region.
/// </summary>
public class EditorSelectionAnnotationRenderable : IRenderable, IFinalizedRenderable
{
readonly Color color;
readonly CellRegion bounds;
readonly int2 altPixelOffset;
readonly CPos? offset;
public EditorSelectionAnnotationRenderable(CellRegion bounds, Color color, int2 altPixelOffset, CPos? offset)
{
this.bounds = bounds;
this.color = color;
this.altPixelOffset = altPixelOffset;
this.offset = offset;
}
public WPos Pos => WPos.Zero;
public int ZOffset => 0;
public bool IsDecoration => true;
public IRenderable WithZOffset(int newOffset) { return this; }
public IRenderable OffsetBy(in WVec vec) { return new EditorSelectionAnnotationRenderable(bounds, color, new int2(vec.X, vec.Y), offset); }
public IRenderable AsDecoration() { return this; }
public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; }
public void Render(WorldRenderer wr)
{
if (bounds == null)
return;
const int Width = 1;
var map = wr.World.Map;
var originalWPos = map.CenterOfCell(bounds.TopLeft);
var wposOffset = offset.HasValue ? map.CenterOfCell(offset.Value) - originalWPos : WVec.Zero;
foreach (var cellPos in bounds.CellCoords)
{
var uv = cellPos.ToMPos(map);
if (!map.Height.Contains(uv))
continue;
var ramp = map.Grid.Ramps[map.Ramp[uv]];
var pos = map.CenterOfCell(cellPos) - new WVec(0, 0, ramp.CenterHeightOffset);
foreach (var p in ramp.Polygons)
{
for (var i = 0; i < p.Length; i++)
{
var j = (i + 1) % p.Length;
var start = pos + p[i];
var end = pos + p[j];
Game.Renderer.RgbaColorRenderer.DrawLine(
wr.Viewport.WorldToViewPx(wr.ScreenPosition(start + wposOffset)) + altPixelOffset,
wr.Viewport.WorldToViewPx(wr.Screen3DPosition(end + wposOffset)) + altPixelOffset,
Width, color, color);
}
}
}
}
public void RenderDebugGeometry(WorldRenderer wr) { }
public Rectangle ScreenBounds(WorldRenderer wr) { return Rectangle.Empty; }
}
}

View File

@@ -11,102 +11,67 @@
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Graphics;
using OpenRA.Mods.Common.Widgets;
using OpenRA.Traits;
using OpenRA.Widgets;
using Color = OpenRA.Primitives.Color;
namespace OpenRA.Mods.Common.Traits
{
[TraitLocation(SystemActors.EditorWorld)]
[Desc("Required for the map editor to work. Attach this to the world actor.")]
public class EditorSelectionLayerInfo : TraitInfo
[Desc("Renders the selection grid in the editor.")]
public class EditorSelectionLayerInfo : TraitInfo, Requires<LoadWidgetAtGameStartInfo>, IEditorSelectionLayer
{
[PaletteReference]
[Desc("Palette to use for rendering the placement sprite.")]
public readonly string Palette = TileSet.TerrainPaletteInternalName;
[Desc("Main color of the selection grid.")]
public readonly Color MainColor = Color.White;
[Desc("Custom opacity to apply to the placement sprite.")]
public readonly float FootprintAlpha = 1f;
[Desc("Alternate color of the selection grid.")]
public readonly Color AltColor = Color.Black;
[Desc("Sequence image where the selection overlay types are defined.")]
public readonly string Image = "editor-overlay";
[Desc("Main color of the paste grid.")]
public readonly Color PasteColor = Color.FromArgb(0xFF4CFF00);
[SequenceReference(nameof(Image))]
[Desc("Sequence to use for the copy overlay.")]
public readonly string CopySequence = "copy";
[Desc("Thickness of the selection grid lines.")]
public readonly int LineThickness = 1;
[SequenceReference(nameof(Image))]
[Desc("Sequence to use for the paste overlay.")]
public readonly string PasteSequence = "paste";
[Desc("Render offset of the secondary grid lines.")]
public readonly int2 AltPixelOffset = new(1, 1);
public override object Create(ActorInitializer init) { return new EditorSelectionLayer(init.Self, this); }
public override object Create(ActorInitializer init) { return new EditorSelectionLayer(this); }
}
public class EditorSelectionLayer : IWorldLoaded, IRenderAboveShroud
public class EditorSelectionLayer : IRenderAnnotations, IWorldLoaded
{
readonly EditorSelectionLayerInfo info;
readonly Map map;
readonly Sprite copyTile, pasteTile;
readonly float copyAlpha, pasteAlpha;
PaletteReference palette;
EditorViewportControllerWidget editor;
public CellRegion CopyRegion { get; private set; }
public CellRegion PasteRegion { get; private set; }
public EditorSelectionLayer(Actor self, EditorSelectionLayerInfo info)
public EditorSelectionLayer(EditorSelectionLayerInfo info)
{
if (self.World.Type != WorldType.Editor)
return;
this.info = info;
map = self.World.Map;
var copySequence = map.Sequences.GetSequence(info.Image, info.CopySequence);
copyTile = copySequence.GetSprite(0);
copyAlpha = copySequence.GetAlpha(0);
var pasteSequence = map.Sequences.GetSequence(info.Image, info.PasteSequence);
pasteTile = pasteSequence.GetSprite(0);
pasteAlpha = pasteSequence.GetAlpha(0);
}
void IWorldLoaded.WorldLoaded(World w, WorldRenderer wr)
{
if (w.Type != WorldType.Editor)
return;
palette = wr.Palette(info.Palette);
var worldRoot = Ui.Root.Get<ContainerWidget>("EDITOR_WORLD_ROOT");
editor = worldRoot.Get<EditorViewportControllerWidget>("MAP_EDITOR");
}
public void SetCopyRegion(CPos start, CPos end)
IEnumerable<IRenderable> IRenderAnnotations.RenderAnnotations(Actor self, WorldRenderer wr)
{
CopyRegion = CellRegion.BoundingRegion(map.Grid.Type, new[] { start, end });
}
public void SetPasteRegion(CPos start, CPos end)
if (editor.CurrentBrush == editor.DefaultBrush && editor.DefaultBrush.CurrentDragBounds != null)
{
PasteRegion = CellRegion.BoundingRegion(map.Grid.Type, new[] { start, end });
yield return new EditorSelectionAnnotationRenderable(editor.DefaultBrush.CurrentDragBounds, info.AltColor, info.AltPixelOffset, null);
yield return new EditorSelectionAnnotationRenderable(editor.DefaultBrush.CurrentDragBounds, info.MainColor, int2.Zero, null);
}
public void Clear()
if (editor.CurrentBrush is EditorCopyPasteBrush pasteBrush && pasteBrush.PastePreviewPosition != null)
{
CopyRegion = PasteRegion = null;
yield return new EditorSelectionAnnotationRenderable(pasteBrush.Region, info.AltColor, info.AltPixelOffset, pasteBrush.PastePreviewPosition);
yield return new EditorSelectionAnnotationRenderable(pasteBrush.Region, info.PasteColor, int2.Zero, pasteBrush.PastePreviewPosition);
}
}
IEnumerable<IRenderable> IRenderAboveShroud.RenderAboveShroud(Actor self, WorldRenderer wr)
{
if (wr.World.Type != WorldType.Editor)
yield break;
if (CopyRegion != null)
foreach (var c in CopyRegion)
yield return new SpriteRenderable(copyTile, wr.World.Map.CenterOfCell(c),
WVec.Zero, -511, palette, 1f, copyAlpha * info.FootprintAlpha, float3.Ones, TintModifiers.IgnoreWorldTint, true);
if (PasteRegion != null)
foreach (var c in PasteRegion)
yield return new SpriteRenderable(pasteTile, wr.World.Map.CenterOfCell(c),
WVec.Zero, -511, palette, 1f, pasteAlpha * info.FootprintAlpha, float3.Ones, TintModifiers.IgnoreWorldTint, true);
}
bool IRenderAboveShroud.SpatiallyPartitionable => false;
bool IRenderAnnotations.SpatiallyPartitionable => false;
}
}

View File

@@ -0,0 +1,37 @@
#region Copyright & License Information
/*
* Copyright (c) The OpenRA Developers and Contributors
* 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;
namespace OpenRA.Mods.Common.UpdateRules.Rules
{
public class RemoveEditorSelectionLayerProperties : UpdateRule
{
public override string Name => "Remove defunct properties from EditorSelectionLayer.";
public override string Description =>
"Map editor was refactored and many of EditorSelectionLayer properties were removed.";
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNodeBuilder actorNode)
{
foreach (var editorSelectionLayer in actorNode.ChildrenMatching("EditorSelectionLayer"))
{
editorSelectionLayer.RemoveNodes("Palette");
editorSelectionLayer.RemoveNodes("FootprintAlpha");
editorSelectionLayer.RemoveNodes("Image");
editorSelectionLayer.RemoveNodes("CopySequence");
editorSelectionLayer.RemoveNodes("PasteSequence");
}
yield break;
}
}
}

View File

@@ -85,6 +85,7 @@ namespace OpenRA.Mods.Common.UpdateRules
new ExtractResourceStorageFromHarvester(),
new ReplacePaletteModifiers(),
new RemoveConyardChronoReturnAnimation(),
new RemoveEditorSelectionLayerProperties(),
// Execute these rules last to avoid premature yaml merge crashes.
new ReplaceCloakPalette(),

View File

@@ -11,7 +11,6 @@
using System;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
@@ -26,29 +25,20 @@ namespace OpenRA.Mods.Common.Widgets
readonly Lazy<TooltipContainerWidget> tooltipContainer;
readonly WorldRenderer worldRenderer;
readonly EditorActionManager editorActionManager;
bool enableTooltips;
[ObjectCreator.UseCtor]
public EditorViewportControllerWidget(World world, WorldRenderer worldRenderer)
public EditorViewportControllerWidget(WorldRenderer worldRenderer)
{
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;
// Allow zooming out to full map size
worldRenderer.Viewport.UnlockMinimumZoom(0.25f);
}
void EditorActionManagerOnChange()
{
DefaultBrush.SelectedActor = null;
}
public void ClearBrush() { SetBrush(null); }
public void SetBrush(IEditorBrush brush)
{
@@ -106,11 +96,5 @@ namespace OpenRA.Mods.Common.Widgets
cachedViewportPosition = worldRenderer.Viewport.CenterPosition;
CurrentBrush.Tick();
}
public override void Removed()
{
base.Removed();
editorActionManager.OnChange -= EditorActionManagerOnChange;
}
}
}

View File

@@ -38,7 +38,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
readonly EditorActorLayer editorActorLayer;
readonly EditorActionManager editorActionManager;
readonly EditorViewportControllerWidget editor;
readonly BackgroundWidget actorEditPanel;
readonly ContainerWidget actorEditPanel;
readonly LabelWidget typeLabel;
readonly TextFieldWidget actorIDField;
readonly HashSet<TextFieldWidget> typableFields = new();
@@ -51,12 +51,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic
readonly Widget sliderOptionTemplate;
readonly Widget dropdownOptionTemplate;
readonly int editPanelPadding; // Padding between right edge of actor and the edit panel.
readonly long scrollVisibleTimeout = 100; // Delay after scrolling map before edit widget becomes visible again.
long lastScrollTime = 0;
int2 lastScrollPosition = int2.Zero;
ActorIDStatus actorIDStatus = ActorIDStatus.Normal;
ActorIDStatus nextActorIDStatus = ActorIDStatus.Normal;
string initialActorID;
@@ -93,8 +87,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
editorActorLayer = world.WorldActor.Trait<EditorActorLayer>();
editorActionManager = world.WorldActor.Trait<EditorActionManager>();
editor = widget.Parent.Get<EditorViewportControllerWidget>("MAP_EDITOR");
actorEditPanel = editor.Get<BackgroundWidget>("ACTOR_EDIT_PANEL");
editor = widget.Parent.Parent.Get<EditorViewportControllerWidget>("MAP_EDITOR");
var selectTabContainer = widget.Parent.Parent.Get<ContainerWidget>("SELECT_WIDGETS");
actorEditPanel = selectTabContainer.Get<ContainerWidget>("ACTOR_EDIT_PANEL");
typeLabel = actorEditPanel.Get<LabelWidget>("ACTOR_TYPE_LABEL");
actorIDField = actorEditPanel.Get<TextFieldWidget>("ACTOR_ID");
@@ -118,16 +114,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
? TranslationProvider.GetString(DuplicateActorId)
: TranslationProvider.GetString(EnterActorId);
if (logicArgs.TryGetValue("EditPanelPadding", out var yaml))
editPanelPadding = FieldLoader.GetValue<int>("EditPanelPadding", yaml.Value);
okButton.IsDisabled = () => !IsValid() || !editActorPreview.IsDirty;
okButton.IsDisabled = () => !IsValid() || editActorPreview == null || !editActorPreview.IsDirty;
okButton.OnClick = Save;
cancelButton.OnClick = Cancel;
deleteButton.OnClick = Delete;
actorEditPanel.IsVisible = () => CurrentActor != null
&& editor.CurrentBrush == editor.DefaultBrush
&& Game.RunTime > lastScrollTime + scrollVisibleTimeout;
&& editor.CurrentBrush == editor.DefaultBrush;
actorIDField.OnEscKey = _ => actorIDField.YieldKeyboardFocus();
@@ -182,7 +174,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic
if (nextActorIDStatus == ActorIDStatus.Normal)
offset *= -1;
actorEditPanel.Bounds.Height += offset;
initContainer.Bounds.Y += offset;
buttonContainer.Bounds.Y += offset;
}
@@ -190,22 +181,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
actorIDStatus = nextActorIDStatus;
}
var actor = editor.DefaultBrush.SelectedActor;
var actor = editor.DefaultBrush.Selection.Actor;
if (actor != null)
{
var origin = worldRenderer.Viewport.WorldToViewPx(new int2(actor.Bounds.Right, actor.Bounds.Top));
// If we scrolled, hide the edit box for a moment
if (lastScrollPosition.X != origin.X || lastScrollPosition.Y != origin.Y)
{
lastScrollTime = Game.RunTime;
lastScrollPosition = origin;
}
// If we changed actor, move widgets
// If we changed actor, update details
if (CurrentActor != actor)
{
lastScrollTime = 0; // Ensure visible
CurrentActor = actor;
editActorPreview = new EditActorPreview(CurrentActor);
@@ -365,13 +346,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
}
}
actorEditPanel.Bounds.Height += initContainer.Bounds.Height - oldInitHeight;
buttonContainer.Bounds.Y += initContainer.Bounds.Height - oldInitHeight;
}
// Set the edit panel to the right of the selection border.
actorEditPanel.Bounds.X = origin.X + editPanelPadding;
actorEditPanel.Bounds.Y = origin.Y;
}
else if (CurrentActor != null)
{
@@ -405,7 +381,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
foreach (var f in typableFields)
f.YieldKeyboardFocus();
editor.DefaultBrush.SelectedActor = null;
editor.DefaultBrush.Selection.Actor = null;
CurrentActor = null;
}

View File

@@ -52,7 +52,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
ModData = modData;
World = world;
WorldRenderer = worldRenderer;
Editor = widget.Parent.Get<EditorViewportControllerWidget>("MAP_EDITOR");
Editor = widget.Parent.Parent.Get<EditorViewportControllerWidget>("MAP_EDITOR");
Panel = widget.Get<ScrollPanelWidget>(templateListId);
ItemTemplate = Panel.Get<ScrollItemWidget>(previewTemplateId);
Panel.Layout = new GridLayout(Panel);
@@ -71,6 +71,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
return true;
};
Editor.DefaultBrush.SelectionChanged += HandleSelectionChanged;
var none = TranslationProvider.GetString(None);
var searchResults = TranslationProvider.GetString(SearchResults);
var all = TranslationProvider.GetString(All);
@@ -103,6 +105,18 @@ namespace OpenRA.Mods.Common.Widgets.Logic
};
}
protected override void Dispose(bool disposing)
{
Editor.DefaultBrush.SelectionChanged -= HandleSelectionChanged;
base.Dispose(disposing);
}
void HandleSelectionChanged()
{
SearchTextField.YieldKeyboardFocus();
}
protected Widget CreateCategoriesPanel(ScrollPanelWidget panel)
{
var categoriesPanel = Ui.LoadWidget("CATEGORY_FILTER_PANEL", null, new WidgetArgs());

View File

@@ -28,7 +28,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
public LayerSelectorLogic(Widget widget, WorldRenderer worldRenderer)
{
this.worldRenderer = worldRenderer;
editor = widget.Parent.Get<EditorViewportControllerWidget>("MAP_EDITOR");
editor = widget.Parent.Parent.Get<EditorViewportControllerWidget>("MAP_EDITOR");
editorCursor = worldRenderer.World.WorldActor.Trait<EditorCursorLayer>();
layerTemplateList = widget.Get<ScrollPanelWidget>("LAYERTEMPLATE_LIST");

View File

@@ -18,29 +18,11 @@ namespace OpenRA.Mods.Common.Widgets.Logic
{
public class MapEditorLogic : ChromeLogic
{
MapCopyFilters copyFilters = MapCopyFilters.All;
[ObjectCreator.UseCtor]
public MapEditorLogic(Widget widget, World world, WorldRenderer worldRenderer)
{
var editorViewport = widget.Get<EditorViewportControllerWidget>("MAP_EDITOR");
var copypasteButton = widget.GetOrNull<ButtonWidget>("COPYPASTE_BUTTON");
if (copypasteButton != null)
{
var copyPasteKey = copypasteButton.Key.GetValue();
copypasteButton.OnClick = () => editorViewport.SetBrush(new EditorCopyPasteBrush(editorViewport, worldRenderer, () => copyFilters));
copypasteButton.IsHighlighted = () => editorViewport.CurrentBrush is EditorCopyPasteBrush;
}
var copyFilterDropdown = widget.Get<DropDownButtonWidget>("COPYFILTER_BUTTON");
copyFilterDropdown.OnMouseDown = _ =>
{
copyFilterDropdown.RemovePanel();
copyFilterDropdown.AttachPanel(CreateCategoriesPanel());
};
var coordinateLabel = widget.GetOrNull<LabelWidget>("COORDINATE_LABEL");
if (coordinateLabel != null)
{
@@ -71,25 +53,5 @@ namespace OpenRA.Mods.Common.Widgets.Logic
redoButton.OnClick = () => actionManager.Redo();
}
}
Widget CreateCategoriesPanel()
{
var categoriesPanel = Ui.LoadWidget("COPY_FILTER_PANEL", null, new WidgetArgs());
var categoryTemplate = categoriesPanel.Get<CheckboxWidget>("CATEGORY_TEMPLATE");
MapCopyFilters[] allCategories = { MapCopyFilters.Terrain, MapCopyFilters.Resources, MapCopyFilters.Actors };
foreach (var cat in allCategories)
{
var category = (CheckboxWidget)categoryTemplate.Clone();
category.GetText = () => cat.ToString();
category.IsChecked = () => copyFilters.HasFlag(cat);
category.IsVisible = () => true;
category.OnClick = () => copyFilters ^= cat;
categoriesPanel.AddChild(category);
}
return categoriesPanel;
}
}
}

View File

@@ -0,0 +1,128 @@
#region Copyright & License Information
/*
* Copyright (c) The OpenRA Developers and Contributors
* 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 System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.EditorBrushes;
using OpenRA.Mods.Common.Traits;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets.Logic
{
public class MapEditorSelectionLogic : ChromeLogic
{
readonly EditorViewportControllerWidget editor;
readonly WorldRenderer worldRenderer;
readonly ContainerWidget actorEditPanel;
readonly ContainerWidget areaEditPanel;
readonly CheckboxWidget copyTerrainCheckbox;
readonly CheckboxWidget copyResourcesCheckbox;
readonly CheckboxWidget copyActorsCheckbox;
readonly EditorActorLayer editorActorLayer;
MapCopyFilters copyFilters = MapCopyFilters.All;
EditorClipboard? clipboard;
readonly IResourceLayer resourceLayer;
[ObjectCreator.UseCtor]
public MapEditorSelectionLogic(Widget widget, World world, WorldRenderer worldRenderer)
{
this.worldRenderer = worldRenderer;
editorActorLayer = world.WorldActor.Trait<EditorActorLayer>();
resourceLayer = world.WorldActor.Trait<IResourceLayer>();
editor = widget.Get<EditorViewportControllerWidget>("MAP_EDITOR");
var selectTabContainer = widget.Get("SELECT_WIDGETS");
actorEditPanel = selectTabContainer.Get<ContainerWidget>("ACTOR_EDIT_PANEL");
areaEditPanel = selectTabContainer.Get<ContainerWidget>("AREA_EDIT_PANEL");
actorEditPanel.IsVisible = () => editor.CurrentBrush == editor.DefaultBrush && editor.DefaultBrush.Selection.Actor != null;
areaEditPanel.IsVisible = () => !actorEditPanel.IsVisible();
copyTerrainCheckbox = areaEditPanel.Get<CheckboxWidget>("COPY_FILTER_TERRAIN_CHECKBOX");
copyResourcesCheckbox = areaEditPanel.Get<CheckboxWidget>("COPY_FILTER_RESOURCES_CHECKBOX");
copyActorsCheckbox = areaEditPanel.Get<CheckboxWidget>("COPY_FILTER_ACTORS_CHECKBOX");
copyTerrainCheckbox.IsDisabled = () => editor.CurrentBrush is EditorCopyPasteBrush;
copyResourcesCheckbox.IsDisabled = () => editor.CurrentBrush is EditorCopyPasteBrush;
copyActorsCheckbox.IsDisabled = () => editor.CurrentBrush is EditorCopyPasteBrush;
var copyButton = widget.Get<ButtonWidget>("COPY_BUTTON");
copyButton.OnClick = () => clipboard = CopySelectionContents();
copyButton.IsDisabled = () => editor.DefaultBrush.Selection.Area == null;
var pasteButton = widget.Get<ButtonWidget>("PASTE_BUTTON");
pasteButton.OnClick = () =>
{
if (clipboard == null)
return;
editor.SetBrush(new EditorCopyPasteBrush(
editor,
worldRenderer,
clipboard.Value,
resourceLayer,
() => copyFilters));
};
pasteButton.IsDisabled = () => clipboard == null;
pasteButton.IsHighlighted = () => editor.CurrentBrush is EditorCopyPasteBrush;
var closeAreaSelectionButton = areaEditPanel.Get<ButtonWidget>("SELECTION_CANCEL_BUTTON");
closeAreaSelectionButton.OnClick = () => editor.DefaultBrush.ClearSelection();
CreateCategoryPanel(MapCopyFilters.Terrain, copyTerrainCheckbox);
CreateCategoryPanel(MapCopyFilters.Resources, copyResourcesCheckbox);
CreateCategoryPanel(MapCopyFilters.Actors, copyActorsCheckbox);
}
EditorClipboard CopySelectionContents()
{
var selection = editor.DefaultBrush.Selection.Area;
var source = new CellCoordsRegion(selection.TopLeft, selection.BottomRight);
var mapTiles = worldRenderer.World.Map.Tiles;
var mapHeight = worldRenderer.World.Map.Height;
var mapResources = worldRenderer.World.Map.Resources;
var previews = new Dictionary<string, EditorActorPreview>();
var tiles = new Dictionary<CPos, ClipboardTile>();
foreach (var cell in source)
{
if (!mapTiles.Contains(cell))
continue;
tiles.Add(cell, new ClipboardTile(mapTiles[cell], mapResources[cell], resourceLayer.GetResource(cell), mapHeight[cell]));
if (copyFilters.HasFlag(MapCopyFilters.Actors))
foreach (var preview in selection.SelectMany(editorActorLayer.PreviewsAt).Distinct())
previews.TryAdd(preview.ID, preview);
}
return new EditorClipboard(selection, previews, tiles);
}
void CreateCategoryPanel(MapCopyFilters copyFilter, CheckboxWidget checkbox)
{
checkbox.GetText = () => copyFilter.ToString();
checkbox.IsChecked = () => copyFilters.HasFlag(copyFilter);
checkbox.IsVisible = () => true;
checkbox.OnClick = () => copyFilters ^= copyFilter;
}
}
}

View File

@@ -16,31 +16,74 @@ namespace OpenRA.Mods.Common.Widgets.Logic
public class MapEditorTabsLogic : ChromeLogic
{
readonly Widget widget;
readonly EditorViewportControllerWidget editor;
protected enum MenuType { Tiles, Layers, Actors, History }
protected enum MenuType { Select, Tiles, Layers, Actors, Tools, History }
protected MenuType menuType = MenuType.Tiles;
readonly Widget tabContainer;
MenuType lastSelectedTab = MenuType.Tiles;
[ObjectCreator.UseCtor]
public MapEditorTabsLogic(Widget widget)
{
this.widget = widget;
editor = widget.Parent.Parent.Get<EditorViewportControllerWidget>("MAP_EDITOR");
editor.DefaultBrush.SelectionChanged += HandleSelectionChanged;
tabContainer = widget.Get("MAP_EDITOR_TAB_CONTAINER");
SetupTab(null, "SELECT_WIDGETS", MenuType.Select);
SetupTab("TILES_TAB", "TILE_WIDGETS", MenuType.Tiles);
SetupTab("OVERLAYS_TAB", "LAYER_WIDGETS", MenuType.Layers);
SetupTab("ACTORS_TAB", "ACTOR_WIDGETS", MenuType.Actors);
SetupTab("TOOLS_TAB", "TOOLS_WIDGETS", MenuType.Tools);
SetupTab("HISTORY_TAB", "HISTORY_WIDGETS", MenuType.History);
}
protected override void Dispose(bool disposing)
{
editor.DefaultBrush.SelectionChanged -= HandleSelectionChanged;
base.Dispose(disposing);
}
void SetupTab(string buttonId, string tabId, MenuType tabType)
{
if (buttonId != null)
{
var tab = tabContainer.Get<ButtonWidget>(buttonId);
tab.IsHighlighted = () => menuType == tabType;
tab.OnClick = () => menuType = tabType;
tab.OnClick = () => menuType = SelectTab(tabType);
}
var container = widget.Parent.Get<ContainerWidget>(tabId);
container.IsVisible = () => menuType == tabType;
}
MenuType SelectTab(MenuType newMenuType)
{
if (menuType == MenuType.Select)
{
editor.SetBrush(editor.DefaultBrush);
editor.DefaultBrush.ClearSelection();
}
if (newMenuType != MenuType.Select)
lastSelectedTab = newMenuType;
return newMenuType;
}
void HandleSelectionChanged()
{
var actor = editor.DefaultBrush.Selection.Actor;
var area = editor.DefaultBrush.Selection.Area;
if (menuType != MenuType.Select && (actor != null || area != null))
menuType = MenuType.Select;
else if (menuType == MenuType.Select && actor == null && area == null)
menuType = lastSelectedTab;
}
}
}

View File

@@ -30,10 +30,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic
readonly TerrainGeometryOverlay terrainGeometryTrait;
readonly BuildableTerrainOverlay buildableTerrainTrait;
readonly Widget widget;
[ObjectCreator.UseCtor]
public MapOverlaysLogic(Widget widget, World world, ModData modData, Dictionary<string, MiniYaml> logicArgs)
{
this.widget = widget;
terrainGeometryTrait = world.WorldActor.Trait<TerrainGeometryOverlay>();
buildableTerrainTrait = world.WorldActor.Trait<BuildableTerrainOverlay>();
@@ -81,28 +84,23 @@ namespace OpenRA.Mods.Common.Widgets.Logic
Widget CreateOverlaysPanel()
{
var categoriesPanel = Ui.LoadWidget("OVERLAY_PANEL", null, new WidgetArgs());
var categoryTemplate = categoriesPanel.Get<CheckboxWidget>("CATEGORY_TEMPLATE");
var categoriesPanel = widget.Get<Widget>("TOOLS_WIDGETS");
var showGridCheckbox = categoriesPanel.Get<CheckboxWidget>("SHOW_TILE_GRID");
var showBuildableAreaCheckbox = categoriesPanel.Get<CheckboxWidget>("SHOW_BUILDABLE_AREA");
MapOverlays[] allCategories = { MapOverlays.Grid, MapOverlays.Buildable };
foreach (var cat in allCategories)
{
var category = (CheckboxWidget)categoryTemplate.Clone();
category.GetText = () => cat.ToString();
category.IsVisible = () => true;
if (cat.HasFlag(MapOverlays.Grid))
{
category.IsChecked = () => terrainGeometryTrait.Enabled;
category.OnClick = () => terrainGeometryTrait.Enabled ^= true;
showGridCheckbox.IsChecked = () => terrainGeometryTrait.Enabled;
showGridCheckbox.OnClick = () => terrainGeometryTrait.Enabled ^= true;
}
else if (cat.HasFlag(MapOverlays.Buildable))
{
category.IsChecked = () => buildableTerrainTrait.Enabled;
category.OnClick = () => buildableTerrainTrait.Enabled ^= true;
showBuildableAreaCheckbox.IsChecked = () => buildableTerrainTrait.Enabled;
showBuildableAreaCheckbox.OnClick = () => buildableTerrainTrait.Enabled ^= true;
}
categoriesPanel.AddChild(category);
}
return categoriesPanel;

View File

@@ -749,3 +749,10 @@ chrome-radar-gdi:
Inherits: ^Chrome
Regions:
logo: 644, 320, 132, 132
editor:
Inherits: ^Chrome
Regions:
tiles: 768, 170, 16, 16
overlays: 785, 170, 16, 16
tools: 904, 68, 16, 16

View File

@@ -215,7 +215,7 @@ Container@EDITOR_ROOT:
TooltipContainer@TOOLTIP_CONTAINER:
Container@EDITOR_WORLD_ROOT:
Logic: LoadIngamePerfLogic, MapEditorLogic, ActorEditLogic, MapOverlaysLogic
Logic: LoadIngamePerfLogic, MapEditorLogic, ActorEditLogic, MapOverlaysLogic, MapEditorSelectionLogic
ToggleGridOverlayKey: EditorToggleGridOverlay
ToggleBuildableOverlayKey: EditorToggleBuildableOverlay
Children:
@@ -226,106 +226,6 @@ Container@EDITOR_WORLD_ROOT:
Height: WINDOW_BOTTOM
TooltipContainer: TOOLTIP_CONTAINER
TooltipTemplate: SIMPLE_TOOLTIP
Children:
Background@ACTOR_EDIT_PANEL:
Background: panel-black
Width: 269
Height: 89
Children:
Label@ACTOR_TYPE_LABEL:
X: 2
Y: 2
Width: 265
Height: 24
Align: Center
Font: Bold
Label@ACTOR_ID_LABEL:
Y: 30
Width: 55
Height: 24
Text: label-actor-edit-panel-id
Align: Right
TextField@ACTOR_ID:
X: 67
Y: 29
Width: 189
Height: 25
Label@ACTOR_ID_ERROR_LABEL:
X: 67
Y: 55
Width: 189
Height: 15
Font: TinyBold
TextColor: FF0000
Container@ACTOR_INIT_CONTAINER:
Y: 57
Width: PARENT_RIGHT
Children:
Container@CHECKBOX_OPTION_TEMPLATE:
Width: PARENT_RIGHT
Height: 22
Children:
Checkbox@OPTION:
X: 67
Y: 1
Width: PARENT_RIGHT - 67
Height: 20
Container@SLIDER_OPTION_TEMPLATE:
Width: PARENT_RIGHT
Height: 22
Children:
Label@LABEL:
Y: 1
Width: 55
Height: 16
Align: Right
Slider@OPTION:
X: 58
Y: 1
Width: 146
Height: 20
TextField@VALUE:
X: 206
Y: 1
Width: 50
Height: 20
Type: Integer
Container@DROPDOWN_OPTION_TEMPLATE:
Width: PARENT_RIGHT
Height: 27
Children:
Label@LABEL:
Y: 2
Width: 55
Height: 24
Align: Right
DropDownButton@OPTION:
X: 67
Y: 1
Width: 189
Height: 25
Font: Bold
Container@BUTTON_CONTAINER:
Y: 60
Children:
Button@DELETE_BUTTON:
X: 4
Width: 75
Height: 25
Text: button-container-delete
Font: Bold
Button@CANCEL_BUTTON:
X: 110
Width: 75
Height: 25
Text: button-container-cancel
Font: Bold
Button@OK_BUTTON:
X: 190
Width: 75
Height: 25
Text: button-container-ok
Font: Bold
ViewportController:
Width: WINDOW_RIGHT
Height: WINDOW_BOTTOM
@@ -525,6 +425,31 @@ Container@EDITOR_WORLD_ROOT:
X: 4
Y: 4
Visible: true
Container@TOOLS_WIDGETS:
X: WINDOW_RIGHT - 295
Y: 318
Width: 290
Height: WINDOW_BOTTOM - 410
ClickThrough: false
Children:
Background@TOOLS_EDIT_PANEL:
X: 0
Y: 0
Width: PARENT_RIGHT
Height: PARENT_BOTTOM
Background: scrollpanel-bg
Checkbox@SHOW_TILE_GRID:
X: 6
Y: 7
Width: PARENT_RIGHT - 29
Height: 20
Text: label-show-tile-grid
Checkbox@SHOW_BUILDABLE_AREA:
X: 6
Y: 32
Width: PARENT_RIGHT - 29
Height: 20
Text: label-show-buildable-area
Container@HISTORY_WIDGETS:
Logic: HistoryLogLogic
X: WINDOW_RIGHT - 295
@@ -558,6 +483,171 @@ Container@EDITOR_WORLD_ROOT:
Width: PARENT_RIGHT
Height: 25
Align: Left
Container@SELECT_WIDGETS:
Visible: false
X: WINDOW_RIGHT - 295
Y: 318
Width: 290
Height: WINDOW_BOTTOM - 410
Children:
Background@SELECT_BG:
X: 0
Y: 0
Width: PARENT_RIGHT
Height: PARENT_BOTTOM
Background: scrollpanel-bg
Container@AREA_EDIT_PANEL:
X: 0
Y: 0
Width: PARENT_RIGHT
Height: PARENT_BOTTOM
#Background: scrollpanel-bg
Children:
Label@AREA_EDIT_TITLE:
X: 6
Y: 7
Width: 265
Height: 24
Align: Center
Font: Bold
Text: label-area-selection
Label@AREA_FILTERS_LABEL:
X: 6
Y: 36
Width: 55
Height: 25
Font: Bold
Align: Left
Text: label-copy-filters
Checkbox@COPY_FILTER_TERRAIN_CHECKBOX:
X: 6
Y: 61
Width: PARENT_RIGHT - 29
Height: 20
Text: label-filter-terrain
Checkbox@COPY_FILTER_RESOURCES_CHECKBOX:
X: 6
Y: 86
Width: PARENT_RIGHT - 29
Height: 20
Text: label-filter-resources
Checkbox@COPY_FILTER_ACTORS_CHECKBOX:
X: 6
Y: 111
Width: PARENT_RIGHT - 29
Height: 20
Text: label-filter-actors
Button@SELECTION_CANCEL_BUTTON:
X: 209
Y: 136
Width: 75
Height: 25
Text: button-selection-cancel
Font: Bold
Container@ACTOR_EDIT_PANEL:
X: 0
Y: 0
Width: PARENT_RIGHT
Height: PARENT_BOTTOM
#Background: scrollpanel-bg
Children:
Label@ACTOR_TYPE_LABEL:
X: 6
Y: 2
Width: 265
Height: 24
Align: Center
Font: Bold
Label@ACTOR_ID_LABEL:
X: 0
Y: 29
Width: 55
Height: 25
Text: label-actor-edit-panel-id
Align: Right
TextField@ACTOR_ID:
X: 67
Y: 29
Width: 210
Height: 25
Label@ACTOR_ID_ERROR_LABEL:
X: 67
Y: 45
Width: 210
Height: 15
Font: TinyBold
TextColor: FF0000
Container@ACTOR_INIT_CONTAINER:
Y: 57
Width: PARENT_RIGHT
Children:
Container@CHECKBOX_OPTION_TEMPLATE:
Width: PARENT_RIGHT
Height: 22
Children:
Checkbox@OPTION:
X: 84
Y: 1
Width: PARENT_RIGHT - 100
Height: 20
Container@SLIDER_OPTION_TEMPLATE:
Width: PARENT_RIGHT
Height: 22
Children:
Label@LABEL:
X: 0
Y: 1
Width: 55
Height: 16
Align: Right
Slider@OPTION:
X: 58
Y: 1
Width: 167
Height: 20
TextField@VALUE:
X: 227
Y: 1
Width: 50
Height: 20
Type: Integer
Container@DROPDOWN_OPTION_TEMPLATE:
Width: PARENT_RIGHT
Height: 27
Children:
Label@LABEL:
X: 0
Y: 2
Width: 55
Height: 24
Align: Right
DropDownButton@OPTION:
X: 67
Y: 1
Width: 210
Height: 25
Font: Bold
Container@BUTTON_CONTAINER:
Y: 60
Children:
Button@DELETE_BUTTON:
X: 4
Width: 75
Height: 25
Text: button-container-delete
Font: Bold
Button@CANCEL_BUTTON:
X: 131
Width: 75
Height: 25
Text: button-container-cancel
Font: Bold
Button@OK_BUTTON:
X: 211
Width: 75
Height: 25
Text: button-container-ok
Font: Bold
Container@MAP_EDITOR_TAB_CONTAINER:
Logic: MapEditorTabsLogic
X: WINDOW_RIGHT - 295
@@ -567,46 +657,76 @@ Container@EDITOR_WORLD_ROOT:
ClickThrough: false
Children:
Button@TILES_TAB:
Width: 71
Width: 59
Height: 25
Text: button-map-editor-tab-container-tiles.label
Font: Bold
Key: EditorTilesTab
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: button-map-editor-tab-container-tiles.tooltip
TooltipContainer: TOOLTIP_CONTAINER
Children:
Image@ICON:
X: 21
Y: 5
ImageCollection: editor
ImageName: tiles
Button@OVERLAYS_TAB:
X: 70
Width: 80
X: 58
Width: 59
Height: 25
Text: button-map-editor-tab-container-overlays.label
Font: Bold
Key: EditorOverlaysTab
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: button-map-editor-tab-container-overlays.tooltip
TooltipContainer: TOOLTIP_CONTAINER
Children:
Image@ICON:
X: 21
Y: 5
ImageCollection: editor
ImageName: overlays
Button@ACTORS_TAB:
X: 149
Width: 71
X: 116
Width: 58
Height: 25
Text: button-map-editor-tab-container-actors.label
Font: Bold
Key: EditorActorsTab
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: button-map-editor-tab-container-actors.tooltip
TooltipContainer: TOOLTIP_CONTAINER
Button@HISTORY_TAB:
X: 219
Width: 71
Children:
Image@ICON:
X: 21
Y: 5
ImageCollection: production-icons
ImageName: infantry
Button@TOOLS_TAB:
X: 173
Width: 59
Height: 25
Key: EditorToolsTab
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: button-map-editor-tab-container-tools.tooltip
TooltipContainer: TOOLTIP_CONTAINER
Children:
Image@ICON:
X: 21
Y: 5
ImageCollection: editor
ImageName: tools
Button@HISTORY_TAB:
X: 231
Width: 59
Height: 25
Text: button-map-editor-tab-container-history.label
Font: Bold
Key: EditorHistoryTab
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: button-map-editor-tab-container-history.tooltip
TooltipContainer: TOOLTIP_CONTAINER
Children:
Image@ICON:
X: 21
Y: 5
ImageCollection: sidebar-bits
ImageName: production-tooltip-time
Button@UNDO_BUTTON:
X: WINDOW_RIGHT - 800
X: WINDOW_RIGHT - 764
Y: 5
Height: 25
Width: 100
@@ -617,7 +737,7 @@ Container@EDITOR_WORLD_ROOT:
TooltipText: button-editor-world-root-undo.tooltip
TooltipContainer: TOOLTIP_CONTAINER
Button@REDO_BUTTON:
X: WINDOW_RIGHT - 690
X: WINDOW_RIGHT - 654
Y: 5
Height: 25
Width: 100
@@ -627,30 +747,28 @@ Container@EDITOR_WORLD_ROOT:
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: button-editor-world-root-redo.tooltip
TooltipContainer: TOOLTIP_CONTAINER
Button@COPYPASTE_BUTTON:
X: WINDOW_RIGHT - 580
Button@COPY_BUTTON:
X: WINDOW_RIGHT - 544
Y: 5
Width: 96
Height: 25
Text: button-editor-world-root-copypaste.label
Width: 100
Text: button-editor-world-root-copy.label
Font: Bold
Key: EditorCopy
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: button-editor-world-root-copypaste.tooltip
TooltipText: button-editor-world-root-copy.tooltip
TooltipContainer: TOOLTIP_CONTAINER
DropDownButton@COPYFILTER_BUTTON:
X: WINDOW_RIGHT - 475
Button@PASTE_BUTTON:
X: WINDOW_RIGHT - 434
Y: 5
Width: 140
Height: 25
Text: dropdownbutton-editor-world-root-copyfilter-button
Font: Bold
DropDownButton@OVERLAY_BUTTON:
X: WINDOW_RIGHT - 950
Y: 5
Width: 140
Height: 25
Text: dropdownbutton-editor-world-root-overlay-button
Width: 100
Text: button-editor-world-root-paste.label
Font: Bold
Key: EditorPaste
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: button-editor-world-root-paste.tooltip
TooltipContainer: TOOLTIP_CONTAINER
Label@COORDINATE_LABEL:
X: 10
Width: 50
@@ -693,19 +811,6 @@ ScrollPanel@CATEGORY_FILTER_PANEL:
Height: 20
Visible: false
ScrollPanel@COPY_FILTER_PANEL:
Width: 140
Height: 80
ItemSpacing: 5
TopBottomSpacing: 0
Children:
Checkbox@CATEGORY_TEMPLATE:
X: 5
Y: 5
Width: PARENT_RIGHT - 29
Height: 20
Visible: false
ScrollPanel@OVERLAY_PANEL:
Width: 140
Height: 55

View File

@@ -72,23 +72,38 @@ label-tiles-bg-categories = Filter:
label-actors-bg-search = Search:
label-actors-bg-categories = Filter:
label-actors-bg-owners = Owner:
label-area-selection = Area Selection
label-copy-filters = Copy Filters
label-filter-terrain = Terrain
label-filter-resources = Resources
label-filter-actors = Actors
button-selection-cancel = Cancel
label-show-tile-grid = Show Tile Grid
label-show-buildable-area = Show Buildable Area
button-map-editor-tab-container-tiles =
.label = Tiles
.tooltip = Tiles
button-map-editor-tab-container-overlays =
.label = Overlays
.tooltip = Overlays
button-map-editor-tab-container-actors =
.label = Actors
.tooltip = Actors
button-map-editor-tab-container-tools =
.tooltip = Tools
button-map-editor-tab-container-history =
.label = History
.tooltip = History
button-editor-world-root-copy =
.label = Copy
.tooltip = Copy
button-editor-world-root-paste =
.label = Paste
.tooltip = Paste
button-editor-world-root-undo =
.label = Undo
.tooltip = Undo last step
@@ -97,12 +112,6 @@ button-editor-world-root-redo =
.label = Redo
.tooltip = Redo last step
button-editor-world-root-copypaste =
.label = Copy/Paste
.tooltip = Copy
dropdownbutton-editor-world-root-copyfilter-button = Copy Filters
dropdownbutton-editor-world-root-overlay-button = Overlays
button-select-categories-buttons-all = All
button-select-categories-buttons-none = None

Binary file not shown.

Before

Width:  |  Height:  |  Size: 356 KiB

After

Width:  |  Height:  |  Size: 464 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 652 KiB

After

Width:  |  Height:  |  Size: 853 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 178 KiB

View File

@@ -204,7 +204,7 @@ Container@EDITOR_ROOT:
TooltipContainer@TOOLTIP_CONTAINER:
Container@EDITOR_WORLD_ROOT:
Logic: LoadIngamePerfLogic, MapEditorLogic, ActorEditLogic, MapOverlaysLogic
Logic: LoadIngamePerfLogic, MapEditorLogic, ActorEditLogic, MapOverlaysLogic, MapEditorSelectionLogic
ToggleGridOverlayKey: EditorToggleGridOverlay
ToggleBuildableOverlayKey: EditorToggleBuildableOverlay
Children:
@@ -215,110 +215,6 @@ Container@EDITOR_WORLD_ROOT:
Height: WINDOW_BOTTOM
TooltipContainer: TOOLTIP_CONTAINER
TooltipTemplate: SIMPLE_TOOLTIP
Children:
Background@ACTOR_EDIT_PANEL:
X: 32
Y: 32
Width: 294
Height: 114
Children:
Label@ACTOR_TYPE_LABEL:
X: 15
Y: 16
Width: 265
Height: 24
Align: Center
Font: Bold
Label@ACTOR_ID_LABEL:
X: 15
Y: 45
Width: 55
Height: 25
Text: label-actor-edit-panel-id
Align: Right
TextField@ACTOR_ID:
X: 84
Y: 45
Width: 192
Height: 25
Label@ACTOR_ID_ERROR_LABEL:
X: 84
Y: 71
Width: 192
Height: 15
Font: TinyBold
TextColor: FF0000
Container@ACTOR_INIT_CONTAINER:
Y: 73
Width: PARENT_RIGHT
Children:
Container@CHECKBOX_OPTION_TEMPLATE:
Width: PARENT_RIGHT
Height: 22
Children:
Checkbox@OPTION:
X: 84
Y: 1
Width: PARENT_RIGHT - 84
Height: 20
Container@SLIDER_OPTION_TEMPLATE:
Width: PARENT_RIGHT
Height: 22
Children:
Label@LABEL:
X: 15
Y: 1
Width: 55
Height: 16
Align: Right
Slider@OPTION:
X: 75
Y: 1
Width: 149
Height: 20
TextField@VALUE:
X: 226
Y: 1
Width: 50
Height: 20
Type: Integer
Container@DROPDOWN_OPTION_TEMPLATE:
Width: PARENT_RIGHT
Height: 27
Children:
Label@LABEL:
X: 15
Y: 2
Width: 55
Height: 24
Align: Right
DropDownButton@OPTION:
X: 84
Y: 1
Width: 192
Height: 25
Font: Bold
Container@BUTTON_CONTAINER:
Y: 75
Children:
Button@DELETE_BUTTON:
X: 15
Width: 75
Height: 25
Text: button-container-delete
Font: Bold
Button@CANCEL_BUTTON:
X: 125
Width: 75
Height: 25
Text: button-container-cancel
Font: Bold
Button@OK_BUTTON:
X: 205
Width: 75
Height: 25
Text: button-container-ok
Font: Bold
ViewportController:
Width: WINDOW_RIGHT
Height: WINDOW_BOTTOM
@@ -347,14 +243,17 @@ Container@EDITOR_WORLD_ROOT:
Y: 10
Width: PARENT_RIGHT - 19
Height: PARENT_BOTTOM - 19
Container@TILE_WIDGETS:
Logic: TileSelectorLogic
Children:
Background@TILES_BG:
Background@TOOLS_BG:
X: WINDOW_RIGHT - 320
Y: 360
Y: 330
Width: 310
Height: WINDOW_BOTTOM - 452
Height: WINDOW_BOTTOM - 422
Container@TILE_WIDGETS:
X: WINDOW_RIGHT - 320
Y: 354
Width: 310
Height: WINDOW_BOTTOM - 458
Logic: TileSelectorLogic
Children:
Label@SEARCH_LABEL:
Y: 12
@@ -385,7 +284,7 @@ Container@EDITOR_WORLD_ROOT:
X: 10
Y: 58
Width: PARENT_RIGHT - 20
Height: PARENT_BOTTOM - 68
Height: PARENT_BOTTOM - 55
TopBottomSpacing: 4
ItemSpacing: 4
Children:
@@ -398,20 +297,18 @@ Container@EDITOR_WORLD_ROOT:
X: 4
Y: 4
Container@LAYER_WIDGETS:
X: WINDOW_RIGHT - 320
Y: 354
Width: 310
Height: WINDOW_BOTTOM - 458
Visible: false
Logic: LayerSelectorLogic
Children:
Background@LAYERS_BG:
X: WINDOW_RIGHT - 320
Y: 360
Width: 310
Height: WINDOW_BOTTOM - 452
Children:
ScrollPanel@LAYERTEMPLATE_LIST:
X: 10
Y: 10
Width: PARENT_RIGHT - 20
Height: PARENT_BOTTOM - 20
Height: PARENT_BOTTOM - 7
TopBottomSpacing: 4
ItemSpacing: 4
Children:
@@ -425,14 +322,12 @@ Container@EDITOR_WORLD_ROOT:
Y: 4
Visible: false
Container@ACTOR_WIDGETS:
X: WINDOW_RIGHT - 320
Y: 354
Width: 310
Height: WINDOW_BOTTOM - 458
Visible: false
Logic: ActorSelectorLogic
Children:
Background@ACTORS_BG:
X: WINDOW_RIGHT - 320
Y: 360
Width: 310
Height: WINDOW_BOTTOM - 452
Children:
Label@SEARCH_LABEL:
Y: 12
@@ -476,7 +371,7 @@ Container@EDITOR_WORLD_ROOT:
X: 10
Y: 82
Width: PARENT_RIGHT - 20
Height: PARENT_BOTTOM - 92
Height: PARENT_BOTTOM - 79
TopBottomSpacing: 4
ItemSpacing: 4
Children:
@@ -491,21 +386,38 @@ Container@EDITOR_WORLD_ROOT:
X: 4
Y: 4
Visible: true
Container@HISTORY_WIDGETS:
Logic: HistoryLogLogic
Container@TOOLS_WIDGETS:
X: WINDOW_RIGHT - 320
Y: 354
Width: 310
Height: WINDOW_BOTTOM - 458
Visible: false
Children:
Background@HISTORY_BG:
Checkbox@SHOW_TILE_GRID:
X: 15
Y: 15
Width: PARENT_RIGHT - 15
Height: 20
Text: label-show-tile-grid
Checkbox@SHOW_BUILDABLE_AREA:
X: 15
Y: 40
Width: PARENT_RIGHT - 15
Height: 20
Text: label-show-buildable-area
Container@HISTORY_WIDGETS:
X: WINDOW_RIGHT - 320
Y: 360
Y: 354
Width: 310
Height: WINDOW_BOTTOM - 452
Height: WINDOW_BOTTOM - 458
Logic: HistoryLogLogic
Visible: false
Children:
ScrollPanel@HISTORY_LIST:
X: 10
Y: 10
Width: PARENT_RIGHT - 20
Height: PARENT_BOTTOM - 20
Height: PARENT_BOTTOM - 7
CollapseHiddenChildren: True
TopBottomSpacing: 4
ItemSpacing: 4
@@ -524,53 +436,236 @@ Container@EDITOR_WORLD_ROOT:
Width: PARENT_RIGHT
Height: 25
Align: Left
Container@SELECT_WIDGETS:
X: WINDOW_RIGHT - 320
Y: 354
Width: 310
Height: WINDOW_BOTTOM - 458
Visible: false
Children:
Container@AREA_EDIT_PANEL:
Width: 310
Height: WINDOW_BOTTOM - 458
Children:
Label@AREA_EDIT_TITLE:
X: 15
Y: 16
Width: 281
Height: 24
Align: Center
Font: Bold
Text: label-area-selection
Label@AREA_FILTERS_LABEL:
X: 15
Y: 45
Width: 55
Height: 25
Font: Bold
Align: Left
Text: label-copy-filters
Checkbox@COPY_FILTER_TERRAIN_CHECKBOX:
X: 15
Y: 70
Width: PARENT_RIGHT - 29
Height: 20
Text: label-filter-terrain
Checkbox@COPY_FILTER_RESOURCES_CHECKBOX:
X: 15
Y: 95
Width: PARENT_RIGHT - 29
Height: 20
Text: label-filter-resources
Checkbox@COPY_FILTER_ACTORS_CHECKBOX:
X: 15
Y: 120
Width: PARENT_RIGHT - 29
Height: 20
Text: label-filter-actors
Button@SELECTION_CANCEL_BUTTON:
X: 222
Y: 145
Width: 75
Height: 25
Text: button-selection-cancel
Font: Bold
Container@ACTOR_EDIT_PANEL:
Width: 310
Height: WINDOW_BOTTOM - 458
Children:
Label@ACTOR_TYPE_LABEL:
X: 15
Y: 16
Width: 281
Height: 24
Align: Center
Font: Bold
Label@ACTOR_ID_LABEL:
X: 15
Y: 45
Width: 55
Height: 25
Text: label-actor-edit-panel-id
Align: Right
TextField@ACTOR_ID:
X: 84
Y: 45
Width: 208
Height: 25
Label@ACTOR_ID_ERROR_LABEL:
X: 84
Y: 71
Width: 208
Height: 15
Font: TinyBold
TextColor: FF0000
Container@ACTOR_INIT_CONTAINER:
Y: 73
Width: PARENT_RIGHT
Children:
Container@CHECKBOX_OPTION_TEMPLATE:
Width: PARENT_RIGHT
Height: 22
Children:
Checkbox@OPTION:
X: 84
Y: 1
Width: PARENT_RIGHT - 100
Height: 20
Container@SLIDER_OPTION_TEMPLATE:
Width: PARENT_RIGHT
Height: 22
Children:
Label@LABEL:
X: 15
Y: 1
Width: 55
Height: 16
Align: Right
Slider@OPTION:
X: 75
Y: 1
Width: 165
Height: 20
TextField@VALUE:
X: 242
Y: 1
Width: 50
Height: 20
Type: Integer
Container@DROPDOWN_OPTION_TEMPLATE:
Width: PARENT_RIGHT
Height: 27
Children:
Label@LABEL:
X: 15
Y: 2
Width: 55
Height: 24
Align: Right
DropDownButton@OPTION:
X: 84
Y: 1
Width: 208
Height: 25
Font: Bold
Container@BUTTON_CONTAINER:
Y: 75
Children:
Button@DELETE_BUTTON:
X: 15
Width: 75
Height: 25
Text: button-container-delete
Font: Bold
Button@CANCEL_BUTTON:
X: 142
Width: 75
Height: 25
Text: button-container-cancel
Font: Bold
Button@OK_BUTTON:
X: 222
Width: 75
Height: 25
Text: button-container-ok
Font: Bold
Container@MAP_EDITOR_TAB_CONTAINER:
Logic: MapEditorTabsLogic
X: WINDOW_RIGHT - 315
Y: 330
Width: 310
X: WINDOW_RIGHT - 311
Y: 339
Width: 292
Height: 25
Children:
Button@TILES_TAB:
X: 0
Width: 70
Width: 58
Height: 25
Text: button-map-editor-tab-container-tiles.label
Font: Bold
Key: EditorTilesTab
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: button-map-editor-tab-container-tiles.tooltip
TooltipContainer: TOOLTIP_CONTAINER
Children:
Image@ICON:
X: 21
Y: 5
ImageCollection: editor
ImageName: tiles
Button@OVERLAYS_TAB:
X: 70
Width: 90
X: 58
Width: 58
Height: 25
Text: button-map-editor-tab-container-overlays.label
Font: Bold
Key: EditorOverlaysTab
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: button-map-editor-tab-container-overlays.tooltip
TooltipContainer: TOOLTIP_CONTAINER
Children:
Image@ICON:
X: 21
Y: 5
ImageCollection: editor
ImageName: overlays
Button@ACTORS_TAB:
X: 160
Width: 70
X: 116
Width: 59
Height: 25
Text: button-map-editor-tab-container-actors.label
Font: Bold
Key: EditorActorsTab
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: button-map-editor-tab-container-actors.tooltip
TooltipContainer: TOOLTIP_CONTAINER
Button@HISTORY_TAB:
X: 230
Width: 70
Children:
Image@ICON:
X: 21
Y: 5
ImageCollection: production-icons
ImageName: infantry
Button@TOOLS_TAB:
X: 175
Width: 58
Height: 25
Key: EditorToolsTab
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: button-map-editor-tab-container-tools.tooltip
TooltipContainer: TOOLTIP_CONTAINER
Children:
Image@ICON:
X: 21
Y: 5
ImageCollection: editor
ImageName: tools
Button@HISTORY_TAB:
X: 233
Width: 58
Height: 25
Text: button-map-editor-tab-container-history.label
Font: Bold
Key: EditorHistoryTab
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: button-map-editor-tab-container-history.tooltip
TooltipContainer: TOOLTIP_CONTAINER
Children:
Image@ICON:
X: 21
Y: 5
ImageCollection: sidebar-bits
ImageName: production-tooltip-time
MenuButton@OPTIONS_BUTTON:
Logic: MenuButtonsChromeLogic
MenuContainer: INGAME_MENU
@@ -583,24 +678,8 @@ Container@EDITOR_WORLD_ROOT:
TooltipContainer: TOOLTIP_CONTAINER
Font: Bold
Key: escape
Button@COPYPASTE_BUTTON:
X: 70
Width: 90
Height: 25
Text: button-editor-world-root-copypaste.label
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: button-editor-world-root-copypaste.tooltip
TooltipContainer: TOOLTIP_CONTAINER
Font: Bold
Key: EditorCopy
DropDownButton@COPYFILTER_BUTTON:
X: 170
Width: 140
Height: 25
Text: dropdownbutton-editor-world-root-copyfilter-button
Font: Bold
Button@UNDO_BUTTON:
X: 320
X: 70
Height: 25
Width: 70
Text: button-editor-world-root-undo.label
@@ -610,7 +689,7 @@ Container@EDITOR_WORLD_ROOT:
TooltipText: button-editor-world-root-undo.tooltip
TooltipContainer: TOOLTIP_CONTAINER
Button@REDO_BUTTON:
X: 400
X: 150
Height: 25
Width: 70
Text: button-editor-world-root-redo.label
@@ -619,21 +698,35 @@ Container@EDITOR_WORLD_ROOT:
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: button-editor-world-root-redo.tooltip
TooltipContainer: TOOLTIP_CONTAINER
DropDownButton@OVERLAY_BUTTON:
X: 480
Width: 140
Button@COPY_BUTTON:
X: 230
Height: 25
Text: dropdownbutton-editor-world-root-overlay-button
Text: button-editor-world-root-copy.label
Width: 70
Font: Bold
Key: EditorCopy
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: button-editor-world-root-copy.tooltip
TooltipContainer: TOOLTIP_CONTAINER
Button@PASTE_BUTTON:
X: 310
Width: 70
Height: 25
Text: button-editor-world-root-paste.label
Font: Bold
Key: EditorPaste
TooltipTemplate: BUTTON_TOOLTIP
TooltipText: button-editor-world-root-paste.tooltip
TooltipContainer: TOOLTIP_CONTAINER
Label@COORDINATE_LABEL:
X: 630
X: 470
Width: 50
Height: 25
Align: Left
Font: Bold
Contrast: true
Label@CASH_LABEL:
X: 745
X: 595
Width: 50
Height: 25
Align: Left
@@ -669,29 +762,3 @@ ScrollPanel@CATEGORY_FILTER_PANEL:
Height: 20
Visible: false
ScrollPanel@COPY_FILTER_PANEL:
Width: 140
Height: 80
ItemSpacing: 5
TopBottomSpacing: 0
Children:
Checkbox@CATEGORY_TEMPLATE:
X: 5
Y: 5
Width: PARENT_RIGHT - 29
Height: 20
Visible: false
ScrollPanel@OVERLAY_PANEL:
Width: 140
Height: 55
ItemSpacing: 5
TopBottomSpacing: 0
Children:
Checkbox@CATEGORY_TEMPLATE:
X: 5
Y: 5
Width: PARENT_RIGHT - 29
Height: 20
Visible: false

View File

@@ -27,6 +27,13 @@ EditorQuickSave: S Ctrl
Platform:
OSX: S Meta
EditorPaste: V Ctrl
Description: Paste
Types: Editor
Contexts: Editor
Platform:
OSX: V Meta
EditorTilesTab: E
Description: Tiles Tab
Types: Editor
@@ -42,11 +49,21 @@ EditorActorsTab: T
Types: Editor
Contexts: Editor
EditorHistoryTab: Y
EditorToolsTab: Y
Description: Tools Tab
Types: Editor
Contexts: Editor
EditorHistoryTab: U
Description: History Tab
Types: Editor
Contexts: Editor
EditorSettingsTab: I
Description: Settings Tab
Types: Editor
Contexts: Editor
EditorToggleGridOverlay: F1
Description: Grid Overlay
Types: Editor

View File

@@ -72,32 +72,41 @@ label-tiles-bg-categories = Filter:
label-actors-bg-search = Search:
label-actors-bg-categories = Filter:
label-actors-bg-owners = Owner:
label-area-selection = Area Selection
label-copy-filters = Copy Filters
label-filter-terrain = Terrain
label-filter-resources = Resources
label-filter-actors = Actors
button-selection-cancel = Cancel
label-show-tile-grid = Show Tile Grid
label-show-buildable-area = Show Buildable Area
button-map-editor-tab-container-tiles =
.label = Tiles
.tooltip = Tiles
button-map-editor-tab-container-overlays =
.label = Overlays
.tooltip = Overlays
button-map-editor-tab-container-actors =
.label = Actors
.tooltip = Actors
button-map-editor-tab-container-tools =
.tooltip = Tools
button-map-editor-tab-container-history =
.label = History
.tooltip = History
button-editor-world-root-options =
.label = Menu
.tooltip = Menu
button-editor-world-root-copypaste =
.label = Copy/Paste
button-editor-world-root-copy =
.label = Copy
.tooltip = Copy
dropdownbutton-editor-world-root-copyfilter-button = Copy Filters
button-editor-world-root-paste =
.label = Paste
.tooltip = Paste
button-editor-world-root-undo =
.label = Undo
@@ -107,7 +116,6 @@ button-editor-world-root-redo =
.label = Redo
.tooltip = Redo last step
dropdownbutton-editor-world-root-overlay-button = Overlays
button-select-categories-buttons-all = All
button-select-categories-buttons-none = None

View File

@@ -805,6 +805,9 @@ notification-copied-tiles =
}
## EditorDefaultBrush
notification-selected-area = Selected area { $x },{ $y } ({ $width },{ $height })
notification-selected-actor = Selected actor { $id }
notification-cleared-selection = Cleared selection
notification-removed-actor = Removed { $name } ({ $id })
notification-removed-resource = Removed { $type }

View File

@@ -511,3 +511,10 @@ loadscreen-stripe:
Inherits: ^LoadScreen
PanelRegion: 258, 0, 0, 0, 253, 256, 0, 0
PanelSides: Center
editor:
Inherits: ^Glyphs
Regions:
tiles: 0, 144, 16, 16
overlays: 17, 144, 16, 16
tools: 34, 144, 16, 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -655,3 +655,10 @@ dropdown-separators:
separator:
Inherits: button
editor:
Inherits: ^Glyphs
Regions:
tiles: 0, 187, 16, 16
overlays: 17, 187, 16, 16
tools: 136, 68, 16, 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

@@ -786,3 +786,10 @@ loadscreen-stripe:
Inherits: ^LoadScreen
PanelRegion: 258, 0, 0, 0, 253, 256, 0, 0
PanelSides: Center
editor:
Inherits: ^Glyphs
Regions:
tiles: 0, 144, 16, 16
overlays: 17, 144, 16, 16
tools: 34, 144, 16, 16

View File

@@ -423,8 +423,7 @@ EditorWorld:
MaxDensity: 2
VeinholeActors: veinhole
EditorSelectionLayer:
Palette: ra
FootprintAlpha: 0.7
AltPixelOffset: 0,1
LoadWidgetAtGameStart:
EditorActionManager:
BuildableTerrainOverlay:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 17 KiB