diff --git a/OpenRA.Game/Map/CellCoordsRegion.cs b/OpenRA.Game/Map/CellCoordsRegion.cs new file mode 100644 index 0000000000..6ec0d928b2 --- /dev/null +++ b/OpenRA.Game/Map/CellCoordsRegion.cs @@ -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 + { + public struct CellCoordsEnumerator : IEnumerator + { + 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 IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public CPos TopLeft { get; } + public CPos BottomRight { get; } + } +} diff --git a/OpenRA.Game/Map/CellRegion.cs b/OpenRA.Game/Map/CellRegion.cs index 8f204cf27a..521eb9aa3d 100644 --- a/OpenRA.Game/Map/CellRegion.cs +++ b/OpenRA.Game/Map/CellRegion.cs @@ -102,6 +102,7 @@ namespace OpenRA } public MapCoordsRegion MapCoords => new(mapTopLeft, mapBottomRight); + public CellCoordsRegion CellCoords => new(TopLeft, BottomRight); public CellRegionEnumerator GetEnumerator() { diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 42dfe37fc5..841ab36bd1 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -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); diff --git a/OpenRA.Mods.Common/EditorBrushes/EditorClipboard.cs b/OpenRA.Mods.Common/EditorBrushes/EditorClipboard.cs new file mode 100644 index 0000000000..e92f39b4fa --- /dev/null +++ b/OpenRA.Mods.Common/EditorBrushes/EditorClipboard.cs @@ -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 Actors; + public readonly Dictionary Tiles; + + public EditorClipboard(CellRegion cellRegion, Dictionary actors, Dictionary tiles) + { + CellRegion = cellRegion; + Actors = actors; + Tiles = tiles; + } + } +} diff --git a/OpenRA.Mods.Common/EditorBrushes/EditorCopyPasteBrush.cs b/OpenRA.Mods.Common/EditorBrushes/EditorCopyPasteBrush.cs index fb40f6c863..acd29aef3f 100644 --- a/OpenRA.Mods.Common/EditorBrushes/EditorCopyPasteBrush.cs +++ b/OpenRA.Mods.Common/EditorBrushes/EditorCopyPasteBrush.cs @@ -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 getCopyFilters; + readonly EditorActorLayer editorActorLayer; readonly EditorActionManager editorActionManager; + readonly EditorClipboard clipboard; + readonly IResourceLayer resourceLayer; + readonly Func getCopyFilters; - State state; - CPos start; - CPos end; + public CPos? PastePreviewPosition { get; private set; } - public EditorCopyPasteBrush(EditorViewportControllerWidget editorWidget, WorldRenderer wr, Func getCopyFilters) + public CellRegion Region => clipboard.CellRegion; + + public EditorCopyPasteBrush( + EditorViewportControllerWidget editorWidget, + WorldRenderer wr, + EditorClipboard clipboard, + IResourceLayer resourceLayer, + Func getCopyFilters) { + this.getCopyFilters = getCopyFilters; this.editorWidget = editorWidget; + this.clipboard = clipboard; + this.resourceLayer = resourceLayer; worldRenderer = wr; editorActionManager = wr.World.WorldActor.Trait(); - - selectionLayer = wr.World.WorldActor.Trait(); - editorLayer = wr.World.WorldActor.Trait(); - this.getCopyFilters = getCopyFilters; + editorActorLayer = wr.World.WorldActor.Trait(); } 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(); - var tiles = new Dictionary(); - 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(); - if (locationInit != null) - { - copy.RemoveAll(); - 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 tiles; - readonly Dictionary previews; - readonly EditorActorLayer editorLayer; - readonly CellRegion dest; - readonly CellLayer mapTiles; - readonly CellLayer mapHeight; - readonly CellLayer mapResources; + readonly IResourceLayer resourceLayer; + readonly EditorActorLayer editorActorLayer; + readonly EditorClipboard clipboard; + readonly EditorClipboard undoClipboard; + readonly CPos pastePosition; + readonly Map map; - readonly Queue undoCopyPastes = new(); - readonly Queue removedActors = new(); - readonly Queue addedActorPreviews = new(); - - public CopyPasteEditorAction(MapCopyFilters copyFilters, Map map, - Dictionary tiles, Dictionary 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)); + } + + /// + /// TODO: This is pretty much repeated in MapEditorSelectionLogic. + /// + /// Clipboard containing map contents for this region. + 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(); + var tiles = new Dictionary(); + + 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; } + + if (copyFilters.HasFlag(MapCopyFilters.Resources) && !string.IsNullOrWhiteSpace(resourceLayerContents.Type)) + resourceLayer.AddResource(resourceLayerContents.Type, position, resourceLayerContents.Density); } - foreach (var kv in previews) - addedActorPreviews.Enqueue(editorLayer.Add(kv.Value)); + // 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(); + 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(); + 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; + { + map.Tiles[position] = tile.TerrainTile; + map.Height[position] = tile.Height; + } - if (copyFilters.HasFlag(MapCopyFilters.Resources)) - mapResources[cell] = undoCopyPaste.ResourceTile; - - mapHeight[cell] = undoCopyPaste.Height; + if (copyFilters.HasFlag(MapCopyFilters.Resources) && !string.IsNullOrWhiteSpace(resourceLayerContents.Type)) + resourceLayer.AddResource(resourceLayerContents.Type, position, resourceLayerContents.Density); } - while (addedActorPreviews.Count > 0) - editorLayer.Remove(addedActorPreviews.Dequeue()); + // 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); } } } diff --git a/OpenRA.Mods.Common/EditorBrushes/EditorDefaultBrush.cs b/OpenRA.Mods.Common/EditorBrushes/EditorDefaultBrush.cs index 8e5d3cb456..34f319c8d2 100644 --- a/OpenRA.Mods.Common/EditorBrushes/EditorDefaultBrush.cs +++ b/OpenRA.Mods.Common/EditorBrushes/EditorDefaultBrush.cs @@ -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,25 +105,114 @@ 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.Button == MouseButton.Left) + if (mi.Event == MouseInputEvent.Down && mi.Button == MouseButton.Left && selectionStartLocation == null) { - editorWidget.SetTooltip(null); - SelectedActor = underCursor; + // Start area drag. + selectionStartLocation = mi.Location; } - if (mi.Button == MouseButton.Right) + if (mi.Event == MouseInputEvent.Up) { - editorWidget.SetTooltip(null); + if (mi.Button == MouseButton.Left) + { + editorWidget.SetTooltip(null); + selectionStartLocation = null; + selectionStartCell = null; - if (underCursor != null && underCursor != SelectedActor) - editorActionManager.Add(new RemoveActorAction(editorLayer, underCursor)); + // If we've released a bounds drag. + if (selectionBounds != null) + { + // Set this as the editor selection. + previousSelection = Selection; + Selection = new EditorSelection + { + Area = selectionBounds + }; - if (resourceUnderCursor != null) - editorActionManager.Add(new RemoveResourceAction(resourceLayer, cell, resourceUnderCursor)); + 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 (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")] diff --git a/OpenRA.Mods.Common/Graphics/EditorSelectionAnnotationRenderable.cs b/OpenRA.Mods.Common/Graphics/EditorSelectionAnnotationRenderable.cs new file mode 100644 index 0000000000..6cf5bc6b55 --- /dev/null +++ b/OpenRA.Mods.Common/Graphics/EditorSelectionAnnotationRenderable.cs @@ -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 +{ + /// + /// Render the current editor area selection or paste region. + /// + 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; } + } +} diff --git a/OpenRA.Mods.Common/Traits/World/EditorSelectionLayer.cs b/OpenRA.Mods.Common/Traits/World/EditorSelectionLayer.cs index bc2325e0e8..5911e1dbb2 100644 --- a/OpenRA.Mods.Common/Traits/World/EditorSelectionLayer.cs +++ b/OpenRA.Mods.Common/Traits/World/EditorSelectionLayer.cs @@ -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, 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("EDITOR_WORLD_ROOT"); + editor = worldRoot.Get("MAP_EDITOR"); } - public void SetCopyRegion(CPos start, CPos end) + IEnumerable IRenderAnnotations.RenderAnnotations(Actor self, WorldRenderer wr) { - CopyRegion = CellRegion.BoundingRegion(map.Grid.Type, new[] { start, end }); + if (editor.CurrentBrush == editor.DefaultBrush && editor.DefaultBrush.CurrentDragBounds != null) + { + yield return new EditorSelectionAnnotationRenderable(editor.DefaultBrush.CurrentDragBounds, info.AltColor, info.AltPixelOffset, null); + yield return new EditorSelectionAnnotationRenderable(editor.DefaultBrush.CurrentDragBounds, info.MainColor, int2.Zero, null); + } + + if (editor.CurrentBrush is EditorCopyPasteBrush pasteBrush && pasteBrush.PastePreviewPosition != 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); + } } - public void SetPasteRegion(CPos start, CPos end) - { - PasteRegion = CellRegion.BoundingRegion(map.Grid.Type, new[] { start, end }); - } - - public void Clear() - { - CopyRegion = PasteRegion = null; - } - - IEnumerable 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; } } diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/20231010/RemoveEditorSelectionLayerProperties.cs b/OpenRA.Mods.Common/UpdateRules/Rules/20231010/RemoveEditorSelectionLayerProperties.cs new file mode 100644 index 0000000000..8eef9be0dc --- /dev/null +++ b/OpenRA.Mods.Common/UpdateRules/Rules/20231010/RemoveEditorSelectionLayerProperties.cs @@ -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 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; + } + } +} diff --git a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs index e032fae753..83aa46131e 100644 --- a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs +++ b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs @@ -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(), diff --git a/OpenRA.Mods.Common/Widgets/EditorViewportControllerWidget.cs b/OpenRA.Mods.Common/Widgets/EditorViewportControllerWidget.cs index c08ad1de86..c25d0774ba 100644 --- a/OpenRA.Mods.Common/Widgets/EditorViewportControllerWidget.cs +++ b/OpenRA.Mods.Common/Widgets/EditorViewportControllerWidget.cs @@ -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 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(TooltipContainer)); CurrentBrush = DefaultBrush = new EditorDefaultBrush(this, worldRenderer); - editorActionManager = world.WorldActor.Trait(); - - 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; - } } } diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/ActorEditLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/ActorEditLogic.cs index 1679768944..c4f94897e2 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Editor/ActorEditLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/ActorEditLogic.cs @@ -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 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(); editorActionManager = world.WorldActor.Trait(); - editor = widget.Parent.Get("MAP_EDITOR"); - actorEditPanel = editor.Get("ACTOR_EDIT_PANEL"); + editor = widget.Parent.Parent.Get("MAP_EDITOR"); + var selectTabContainer = widget.Parent.Parent.Get("SELECT_WIDGETS"); + + actorEditPanel = selectTabContainer.Get("ACTOR_EDIT_PANEL"); typeLabel = actorEditPanel.Get("ACTOR_TYPE_LABEL"); actorIDField = actorEditPanel.Get("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("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; } diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/CommonSelectorLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/CommonSelectorLogic.cs index f0206ea8d0..c1bccd9a3d 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Editor/CommonSelectorLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/CommonSelectorLogic.cs @@ -52,7 +52,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic ModData = modData; World = world; WorldRenderer = worldRenderer; - Editor = widget.Parent.Get("MAP_EDITOR"); + Editor = widget.Parent.Parent.Get("MAP_EDITOR"); Panel = widget.Get(templateListId); ItemTemplate = Panel.Get(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()); diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs index 3d04c3a6f5..6100c04680 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs @@ -28,7 +28,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic public LayerSelectorLogic(Widget widget, WorldRenderer worldRenderer) { this.worldRenderer = worldRenderer; - editor = widget.Parent.Get("MAP_EDITOR"); + editor = widget.Parent.Parent.Get("MAP_EDITOR"); editorCursor = worldRenderer.World.WorldActor.Trait(); layerTemplateList = widget.Get("LAYERTEMPLATE_LIST"); diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorLogic.cs index 3d0f4ce572..03745c74fe 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorLogic.cs @@ -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("MAP_EDITOR"); - var copypasteButton = widget.GetOrNull("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("COPYFILTER_BUTTON"); - copyFilterDropdown.OnMouseDown = _ => - { - copyFilterDropdown.RemovePanel(); - copyFilterDropdown.AttachPanel(CreateCategoriesPanel()); - }; - var coordinateLabel = widget.GetOrNull("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("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; - } } } diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorSelectionLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorSelectionLogic.cs new file mode 100644 index 0000000000..32aebff021 --- /dev/null +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorSelectionLogic.cs @@ -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(); + resourceLayer = world.WorldActor.Trait(); + + editor = widget.Get("MAP_EDITOR"); + + var selectTabContainer = widget.Get("SELECT_WIDGETS"); + actorEditPanel = selectTabContainer.Get("ACTOR_EDIT_PANEL"); + areaEditPanel = selectTabContainer.Get("AREA_EDIT_PANEL"); + + actorEditPanel.IsVisible = () => editor.CurrentBrush == editor.DefaultBrush && editor.DefaultBrush.Selection.Actor != null; + areaEditPanel.IsVisible = () => !actorEditPanel.IsVisible(); + + copyTerrainCheckbox = areaEditPanel.Get("COPY_FILTER_TERRAIN_CHECKBOX"); + copyResourcesCheckbox = areaEditPanel.Get("COPY_FILTER_RESOURCES_CHECKBOX"); + copyActorsCheckbox = areaEditPanel.Get("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("COPY_BUTTON"); + copyButton.OnClick = () => clipboard = CopySelectionContents(); + copyButton.IsDisabled = () => editor.DefaultBrush.Selection.Area == null; + + var pasteButton = widget.Get("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("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(); + var tiles = new Dictionary(); + + 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; + } + } +} diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorTabsLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorTabsLogic.cs index fa042987f9..5c615ac632 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorTabsLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorTabsLogic.cs @@ -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("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) { - var tab = tabContainer.Get(buttonId); - tab.IsHighlighted = () => menuType == tabType; - tab.OnClick = () => menuType = tabType; + if (buttonId != null) + { + var tab = tabContainer.Get(buttonId); + tab.IsHighlighted = () => menuType == tabType; + tab.OnClick = () => menuType = SelectTab(tabType); + } var container = widget.Parent.Get(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; + } } } diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/MapOverlaysLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/MapOverlaysLogic.cs index aa9601b92a..430f9e2f5e 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Editor/MapOverlaysLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/MapOverlaysLogic.cs @@ -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 logicArgs) { + this.widget = widget; + terrainGeometryTrait = world.WorldActor.Trait(); buildableTerrainTrait = world.WorldActor.Trait(); @@ -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("CATEGORY_TEMPLATE"); + var categoriesPanel = widget.Get("TOOLS_WIDGETS"); + var showGridCheckbox = categoriesPanel.Get("SHOW_TILE_GRID"); + var showBuildableAreaCheckbox = categoriesPanel.Get("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; diff --git a/mods/cnc/chrome.yaml b/mods/cnc/chrome.yaml index 8ab74335db..b6339c1f0b 100644 --- a/mods/cnc/chrome.yaml +++ b/mods/cnc/chrome.yaml @@ -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 diff --git a/mods/cnc/chrome/editor.yaml b/mods/cnc/chrome/editor.yaml index fa2f72eb6a..46f2683175 100644 --- a/mods/cnc/chrome/editor.yaml +++ b/mods/cnc/chrome/editor.yaml @@ -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 diff --git a/mods/cnc/languages/chrome/en.ftl b/mods/cnc/languages/chrome/en.ftl index ef1bf87753..f3de0e9b52 100644 --- a/mods/cnc/languages/chrome/en.ftl +++ b/mods/cnc/languages/chrome/en.ftl @@ -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 diff --git a/mods/cnc/uibits/chrome-2x.png b/mods/cnc/uibits/chrome-2x.png index 85b60fdafe..3f096a4f9d 100644 Binary files a/mods/cnc/uibits/chrome-2x.png and b/mods/cnc/uibits/chrome-2x.png differ diff --git a/mods/cnc/uibits/chrome-3x.png b/mods/cnc/uibits/chrome-3x.png index 99a8590a4d..4614d48f78 100644 Binary files a/mods/cnc/uibits/chrome-3x.png and b/mods/cnc/uibits/chrome-3x.png differ diff --git a/mods/cnc/uibits/chrome.png b/mods/cnc/uibits/chrome.png index 64cca2ac91..c226b2813c 100644 Binary files a/mods/cnc/uibits/chrome.png and b/mods/cnc/uibits/chrome.png differ diff --git a/mods/common/chrome/editor.yaml b/mods/common/chrome/editor.yaml index c237ef7904..e6f892b8ef 100644 --- a/mods/common/chrome/editor.yaml +++ b/mods/common/chrome/editor.yaml @@ -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,230 +243,429 @@ Container@EDITOR_WORLD_ROOT: Y: 10 Width: PARENT_RIGHT - 19 Height: PARENT_BOTTOM - 19 + Background@TOOLS_BG: + X: WINDOW_RIGHT - 320 + Y: 330 + Width: 310 + Height: WINDOW_BOTTOM - 422 Container@TILE_WIDGETS: + X: WINDOW_RIGHT - 320 + Y: 354 + Width: 310 + Height: WINDOW_BOTTOM - 458 Logic: TileSelectorLogic Children: - Background@TILES_BG: - X: WINDOW_RIGHT - 320 - Y: 360 - Width: 310 - Height: WINDOW_BOTTOM - 452 + Label@SEARCH_LABEL: + Y: 12 + Width: 55 + Height: 25 + Text: label-tiles-bg-search + Align: Right + Font: TinyBold + TextField@SEARCH_TEXTFIELD: + X: 60 + Y: 10 + Width: PARENT_RIGHT - 70 + Height: 25 + Label@CATEGORIES_LABEL: + Y: 36 + Width: 55 + Height: 25 + Text: label-tiles-bg-categories + Align: Right + Font: TinyBold + DropDownButton@CATEGORIES_DROPDOWN: + X: 60 + Y: 34 + Width: PARENT_RIGHT - 70 + Height: 25 + Font: Bold + ScrollPanel@TILETEMPLATE_LIST: + X: 10 + Y: 58 + Width: PARENT_RIGHT - 20 + Height: PARENT_BOTTOM - 55 + TopBottomSpacing: 4 + ItemSpacing: 4 Children: - Label@SEARCH_LABEL: - Y: 12 - Width: 55 - Height: 25 - Text: label-tiles-bg-search - Align: Right - Font: TinyBold - TextField@SEARCH_TEXTFIELD: - X: 60 - Y: 10 - Width: PARENT_RIGHT - 70 - Height: 25 - Label@CATEGORIES_LABEL: - Y: 36 - Width: 55 - Height: 25 - Text: label-tiles-bg-categories - Align: Right - Font: TinyBold - DropDownButton@CATEGORIES_DROPDOWN: - X: 60 - Y: 34 - Width: PARENT_RIGHT - 70 - Height: 25 - Font: Bold - ScrollPanel@TILETEMPLATE_LIST: - X: 10 - Y: 58 - Width: PARENT_RIGHT - 20 - Height: PARENT_BOTTOM - 68 - TopBottomSpacing: 4 - ItemSpacing: 4 + ScrollItem@TILEPREVIEW_TEMPLATE: + Visible: false + Width: PARENT_RIGHT - 35 + TooltipContainer: TOOLTIP_CONTAINER Children: - ScrollItem@TILEPREVIEW_TEMPLATE: - Visible: false - Width: PARENT_RIGHT - 35 - TooltipContainer: TOOLTIP_CONTAINER - Children: - TerrainTemplatePreview@TILE_PREVIEW: - X: 4 - Y: 4 + TerrainTemplatePreview@TILE_PREVIEW: + 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 + ScrollPanel@LAYERTEMPLATE_LIST: + X: 10 + Y: 10 + Width: PARENT_RIGHT - 20 + Height: PARENT_BOTTOM - 7 + TopBottomSpacing: 4 + ItemSpacing: 4 Children: - ScrollPanel@LAYERTEMPLATE_LIST: - X: 10 - Y: 10 - Width: PARENT_RIGHT - 20 - Height: PARENT_BOTTOM - 20 - TopBottomSpacing: 4 - ItemSpacing: 4 + ScrollItem@LAYERPREVIEW_TEMPLATE: + Visible: false + IgnoreChildMouseOver: true + TooltipContainer: TOOLTIP_CONTAINER Children: - ScrollItem@LAYERPREVIEW_TEMPLATE: + ResourcePreview@LAYER_PREVIEW: + X: 4 + Y: 4 Visible: false - IgnoreChildMouseOver: true - TooltipContainer: TOOLTIP_CONTAINER - Children: - ResourcePreview@LAYER_PREVIEW: - X: 4 - 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 + Label@SEARCH_LABEL: + Y: 12 + Width: 55 + Height: 25 + Text: label-actors-bg-search + Align: Right + Font: TinyBold + TextField@SEARCH_TEXTFIELD: + X: 60 + Y: 10 + Width: PARENT_RIGHT - 70 + Height: 25 + Label@CATEGORIES_LABEL: + Y: 36 + Width: 55 + Height: 25 + Text: label-actors-bg-categories + Align: Right + Font: TinyBold + DropDownButton@CATEGORIES_DROPDOWN: + X: 60 + Y: 34 + Width: PARENT_RIGHT - 70 + Height: 25 + Font: Bold + Label@OWNERS_LABEL: + Y: 60 + Width: 55 + Height: 25 + Text: label-actors-bg-owners + Align: Right + Font: TinyBold + DropDownButton@OWNERS_DROPDOWN: + X: 60 + Y: 58 + Width: PARENT_RIGHT - 70 + Height: 25 + Font: Bold + ScrollPanel@ACTORTEMPLATE_LIST: + X: 10 + Y: 82 + Width: PARENT_RIGHT - 20 + Height: PARENT_BOTTOM - 79 + TopBottomSpacing: 4 + ItemSpacing: 4 Children: - Label@SEARCH_LABEL: - Y: 12 - Width: 55 - Height: 25 - Text: label-actors-bg-search - Align: Right - Font: TinyBold - TextField@SEARCH_TEXTFIELD: - X: 60 - Y: 10 - Width: PARENT_RIGHT - 70 - Height: 25 - Label@CATEGORIES_LABEL: - Y: 36 - Width: 55 - Height: 25 - Text: label-actors-bg-categories - Align: Right - Font: TinyBold - DropDownButton@CATEGORIES_DROPDOWN: - X: 60 - Y: 34 - Width: PARENT_RIGHT - 70 - Height: 25 - Font: Bold - Label@OWNERS_LABEL: - Y: 60 - Width: 55 - Height: 25 - Text: label-actors-bg-owners - Align: Right - Font: TinyBold - DropDownButton@OWNERS_DROPDOWN: - X: 60 - Y: 58 - Width: PARENT_RIGHT - 70 - Height: 25 - Font: Bold - ScrollPanel@ACTORTEMPLATE_LIST: - X: 10 - Y: 82 - Width: PARENT_RIGHT - 20 - Height: PARENT_BOTTOM - 92 - TopBottomSpacing: 4 - ItemSpacing: 4 + ScrollItem@ACTORPREVIEW_TEMPLATE: + Visible: false + Width: PARENT_RIGHT - 35 + TooltipContainer: TOOLTIP_CONTAINER + TooltipTemplate: SIMPLE_TOOLTIP + IgnoreChildMouseOver: true Children: - ScrollItem@ACTORPREVIEW_TEMPLATE: - Visible: false - Width: PARENT_RIGHT - 35 - TooltipContainer: TOOLTIP_CONTAINER - TooltipTemplate: SIMPLE_TOOLTIP - IgnoreChildMouseOver: true - Children: - ActorPreview@ACTOR_PREVIEW: - X: 4 - Y: 4 - Visible: true + ActorPreview@ACTOR_PREVIEW: + X: 4 + Y: 4 + Visible: true + Container@TOOLS_WIDGETS: + X: WINDOW_RIGHT - 320 + Y: 354 + Width: 310 + Height: WINDOW_BOTTOM - 458 + Visible: false + Children: + 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: 354 + Width: 310 + Height: WINDOW_BOTTOM - 458 Logic: HistoryLogLogic Visible: false Children: - Background@HISTORY_BG: - X: WINDOW_RIGHT - 320 - Y: 360 - Width: 310 - Height: WINDOW_BOTTOM - 452 + ScrollPanel@HISTORY_LIST: + X: 10 + Y: 10 + Width: PARENT_RIGHT - 20 + Height: PARENT_BOTTOM - 7 + CollapseHiddenChildren: True + TopBottomSpacing: 4 + ItemSpacing: 4 Children: - ScrollPanel@HISTORY_LIST: - X: 10 - Y: 10 - Width: PARENT_RIGHT - 20 - Height: PARENT_BOTTOM - 20 - CollapseHiddenChildren: True - TopBottomSpacing: 4 - ItemSpacing: 4 + ScrollItem@HISTORY_TEMPLATE: + X: 4 + Visible: false + Width: PARENT_RIGHT - 31 + Height: 25 + IgnoreChildMouseOver: true + TextColor: ffffff + TextColorDisabled: 8f8f8f Children: - ScrollItem@HISTORY_TEMPLATE: - X: 4 - Visible: false - Width: PARENT_RIGHT - 31 + Label@TITLE: + X: 5 + Width: PARENT_RIGHT Height: 25 - IgnoreChildMouseOver: true - TextColor: ffffff - TextColorDisabled: 8f8f8f + 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: - Label@TITLE: - X: 5 - Width: PARENT_RIGHT + 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 - Align: Left + 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 - diff --git a/mods/common/hotkeys/editor.yaml b/mods/common/hotkeys/editor.yaml index fa737a654d..1e5f727ea0 100644 --- a/mods/common/hotkeys/editor.yaml +++ b/mods/common/hotkeys/editor.yaml @@ -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 diff --git a/mods/common/languages/chrome/en.ftl b/mods/common/languages/chrome/en.ftl index 927ff8cd15..8628972562 100644 --- a/mods/common/languages/chrome/en.ftl +++ b/mods/common/languages/chrome/en.ftl @@ -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 diff --git a/mods/common/languages/en.ftl b/mods/common/languages/en.ftl index 94bffa25d1..6608076e3f 100644 --- a/mods/common/languages/en.ftl +++ b/mods/common/languages/en.ftl @@ -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 } diff --git a/mods/d2k/chrome.yaml b/mods/d2k/chrome.yaml index 56e2f6c5ed..34f913fb90 100644 --- a/mods/d2k/chrome.yaml +++ b/mods/d2k/chrome.yaml @@ -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 diff --git a/mods/d2k/uibits/glyphs-2x.png b/mods/d2k/uibits/glyphs-2x.png index e05e5cf1e9..70a95779ef 100644 Binary files a/mods/d2k/uibits/glyphs-2x.png and b/mods/d2k/uibits/glyphs-2x.png differ diff --git a/mods/d2k/uibits/glyphs-3x.png b/mods/d2k/uibits/glyphs-3x.png index d99851bb0c..62eedd9fa2 100644 Binary files a/mods/d2k/uibits/glyphs-3x.png and b/mods/d2k/uibits/glyphs-3x.png differ diff --git a/mods/d2k/uibits/glyphs.png b/mods/d2k/uibits/glyphs.png index 98bd160003..dbbcbf4b91 100644 Binary files a/mods/d2k/uibits/glyphs.png and b/mods/d2k/uibits/glyphs.png differ diff --git a/mods/ra/chrome.yaml b/mods/ra/chrome.yaml index ec6ba73e64..d8e3f13878 100644 --- a/mods/ra/chrome.yaml +++ b/mods/ra/chrome.yaml @@ -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 diff --git a/mods/ra/uibits/glyphs-2x.png b/mods/ra/uibits/glyphs-2x.png index 7061380af6..00dea9ff7c 100644 Binary files a/mods/ra/uibits/glyphs-2x.png and b/mods/ra/uibits/glyphs-2x.png differ diff --git a/mods/ra/uibits/glyphs-3x.png b/mods/ra/uibits/glyphs-3x.png index f6d5ff53c8..ffb635ab79 100644 Binary files a/mods/ra/uibits/glyphs-3x.png and b/mods/ra/uibits/glyphs-3x.png differ diff --git a/mods/ra/uibits/glyphs.png b/mods/ra/uibits/glyphs.png index 9e220bb3e8..62e24f484e 100644 Binary files a/mods/ra/uibits/glyphs.png and b/mods/ra/uibits/glyphs.png differ diff --git a/mods/ts/chrome.yaml b/mods/ts/chrome.yaml index 69df3f85cb..68083a84e5 100644 --- a/mods/ts/chrome.yaml +++ b/mods/ts/chrome.yaml @@ -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 diff --git a/mods/ts/rules/world.yaml b/mods/ts/rules/world.yaml index 91a75ad8b1..c4d2e5c2f7 100644 --- a/mods/ts/rules/world.yaml +++ b/mods/ts/rules/world.yaml @@ -423,8 +423,7 @@ EditorWorld: MaxDensity: 2 VeinholeActors: veinhole EditorSelectionLayer: - Palette: ra - FootprintAlpha: 0.7 + AltPixelOffset: 0,1 LoadWidgetAtGameStart: EditorActionManager: BuildableTerrainOverlay: diff --git a/mods/ts/uibits/glyphs-2x.png b/mods/ts/uibits/glyphs-2x.png index 05184d0fe7..4b58a6908b 100644 Binary files a/mods/ts/uibits/glyphs-2x.png and b/mods/ts/uibits/glyphs-2x.png differ diff --git a/mods/ts/uibits/glyphs-3x.png b/mods/ts/uibits/glyphs-3x.png index d96f0afb4d..42ec614db0 100644 Binary files a/mods/ts/uibits/glyphs-3x.png and b/mods/ts/uibits/glyphs-3x.png differ diff --git a/mods/ts/uibits/glyphs.png b/mods/ts/uibits/glyphs.png index 2a92a8f0bd..fc10af9791 100644 Binary files a/mods/ts/uibits/glyphs.png and b/mods/ts/uibits/glyphs.png differ