Fix editor area/actor deselection bugs

This commit is contained in:
David Wilson
2024-01-27 14:58:51 +10:00
committed by Gustas
parent 0c22499534
commit d630a6ef7d
30 changed files with 503 additions and 443 deletions

View File

@@ -1,4 +1,15 @@
using System.Collections.Generic;
#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 OpenRA.Mods.Common.Traits;
namespace OpenRA.Mods.Common.EditorBrushes
@@ -7,10 +18,10 @@ namespace OpenRA.Mods.Common.EditorBrushes
{
public readonly TerrainTile TerrainTile;
public readonly ResourceTile ResourceTile;
public readonly ResourceLayerContents ResourceLayerContents;
public readonly ResourceLayerContents? ResourceLayerContents;
public readonly byte Height;
public ClipboardTile(TerrainTile terrainTile, ResourceTile resourceTile, ResourceLayerContents resourceLayerContents, byte height)
public ClipboardTile(TerrainTile terrainTile, ResourceTile resourceTile, ResourceLayerContents? resourceLayerContents, byte height)
{
TerrainTile = terrainTile;
ResourceTile = resourceTile;

View File

@@ -161,7 +161,7 @@ namespace OpenRA.Mods.Common.Widgets
if (!mapTiles.Contains(cell))
continue;
var resourceLayerContents = resourceLayer.GetResource(cell);
var resourceLayerContents = resourceLayer?.GetResource(cell);
tiles.Add(cell, new ClipboardTile(mapTiles[cell], mapResources[cell], resourceLayerContents, mapHeight[cell]));
if (copyFilters.HasFlag(MapCopyFilters.Actors))
@@ -189,7 +189,7 @@ namespace OpenRA.Mods.Common.Widgets
continue;
// Clear any existing resources.
if (copyFilters.HasFlag(MapCopyFilters.Resources))
if (resourceLayer != null && copyFilters.HasFlag(MapCopyFilters.Resources))
resourceLayer.ClearResources(position);
var tile = tileKeyValuePair.Value;
@@ -201,33 +201,38 @@ namespace OpenRA.Mods.Common.Widgets
map.Height[position] = tile.Height;
}
if (copyFilters.HasFlag(MapCopyFilters.Resources) && !string.IsNullOrWhiteSpace(resourceLayerContents.Type))
resourceLayer.AddResource(resourceLayerContents.Type, position, resourceLayerContents.Density);
if (copyFilters.HasFlag(MapCopyFilters.Resources) &&
resourceLayerContents.HasValue &&
!string.IsNullOrWhiteSpace(resourceLayerContents.Value.Type))
resourceLayer.AddResource(resourceLayerContents.Value.Type, position, resourceLayerContents.Value.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)
if (copyFilters.HasFlag(MapCopyFilters.Actors))
{
var selection = clipboard.CellRegion;
var copy = actorKeyValuePair.Value.Export();
var locationInit = copy.GetOrDefault<LocationInit>();
if (locationInit != null)
// 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 actorPosition = locationInit.Value + new CVec(pastePosition.X - selection.TopLeft.X, pastePosition.Y - selection.TopLeft.Y);
if (!map.Contains(actorPosition))
continue;
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));
copy.RemoveAll<LocationInit>();
copy.Add(new LocationInit(actorPosition));
}
editorActorLayer.Add(copy);
}
editorActorLayer.Add(copy);
}
}
@@ -240,7 +245,7 @@ namespace OpenRA.Mods.Common.Widgets
var resourceLayerContents = tile.ResourceLayerContents;
// Clear any existing resources.
if (copyFilters.HasFlag(MapCopyFilters.Resources))
if (resourceLayer != null && copyFilters.HasFlag(MapCopyFilters.Resources))
resourceLayer.ClearResources(position);
if (copyFilters.HasFlag(MapCopyFilters.Terrain))
@@ -249,18 +254,22 @@ namespace OpenRA.Mods.Common.Widgets
map.Height[position] = tile.Height;
}
if (copyFilters.HasFlag(MapCopyFilters.Resources) && !string.IsNullOrWhiteSpace(resourceLayerContents.Type))
resourceLayer.AddResource(resourceLayerContents.Type, position, resourceLayerContents.Density);
if (copyFilters.HasFlag(MapCopyFilters.Resources) &&
resourceLayerContents.HasValue &&
!string.IsNullOrWhiteSpace(resourceLayerContents.Value.Type))
resourceLayer.AddResource(resourceLayerContents.Value.Type, position, resourceLayerContents.Value.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))
{
// Clear existing actors.
foreach (var regionActor in undoClipboard.CellRegion.SelectMany(editorActorLayer.PreviewsAt).Distinct().ToList())
editorActorLayer.Remove(regionActor);
// Place actors back again.
foreach (var actor in undoClipboard.Actors.Values)
editorActorLayer.Add(actor);
}
}
}
}

View File

@@ -26,6 +26,8 @@ namespace OpenRA.Mods.Common.Widgets
{
public CellRegion Area;
public EditorActorPreview Actor;
public bool HasSelection => Area != null || Actor != null;
}
public sealed class EditorDefaultBrush : IEditorBrush
@@ -33,6 +35,7 @@ namespace OpenRA.Mods.Common.Widgets
const int MinMouseMoveBeforeDrag = 32;
public event Action SelectionChanged;
public event Action UpdateSelectedTab;
readonly WorldRenderer worldRenderer;
readonly World world;
@@ -43,7 +46,8 @@ namespace OpenRA.Mods.Common.Widgets
public CellRegion CurrentDragBounds => selectionBounds ?? Selection.Area;
public EditorSelection Selection = new();
public EditorSelection Selection { get; private set; } = new();
EditorSelection previousSelection;
CellRegion selectionBounds;
int2? selectionStartLocation;
@@ -73,17 +77,34 @@ namespace OpenRA.Mods.Common.Widgets
return ((long)pixelDistance << 32) + worldZPosition;
}
public void ClearSelection()
public void ClearSelection(bool updateSelectedTab = false)
{
if (Selection.Area != null || Selection.Actor != null)
if (Selection.HasSelection)
{
previousSelection = Selection;
Selection = new EditorSelection();
SetSelection(new EditorSelection());
editorActionManager.Add(new ChangeSelectionAction(this, Selection, previousSelection));
SelectionChanged?.Invoke();
if (updateSelectedTab)
UpdateSelectedTab?.Invoke();
}
}
public void SetSelection(EditorSelection selection)
{
if (Selection == selection)
return;
if (Selection.Actor != null)
Selection.Actor.Selected = false;
Selection = selection;
if (Selection.Actor != null)
Selection.Actor.Selected = true;
SelectionChanged?.Invoke();
}
public bool HandleMouseInput(MouseInput mi)
{
// Exclusively uses mouse wheel and both mouse buttons, but nothing else.
@@ -155,14 +176,14 @@ namespace OpenRA.Mods.Common.Widgets
{
// Set this as the editor selection.
previousSelection = Selection;
Selection = new EditorSelection
SetSelection(new EditorSelection
{
Area = selectionBounds
};
});
editorActionManager.Add(new ChangeSelectionAction(this, Selection, previousSelection));
selectionBounds = null;
SelectionChanged?.Invoke();
editorActionManager.Add(new ChangeSelectionAction(this, Selection, previousSelection));
UpdateSelectedTab?.Invoke();
}
else if (underCursor != null)
{
@@ -170,48 +191,32 @@ namespace OpenRA.Mods.Common.Widgets
if (Selection.Actor != underCursor)
{
previousSelection = Selection;
Selection = new EditorSelection
SetSelection(new EditorSelection
{
Actor = underCursor,
};
});
editorActionManager.Add(new ChangeSelectionAction(this, Selection, previousSelection));
SelectionChanged?.Invoke();
UpdateSelectedTab?.Invoke();
}
}
else if (Selection.Area != null || Selection.Actor != null)
else if (Selection.HasSelection)
{
// 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();
ClearSelection(updateSelectedTab: true);
}
}
if (mi.Button == MouseButton.Right)
else 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();
// Delete actor.
if (underCursor != null && underCursor != Selection.Actor)
editorActionManager.Add(new RemoveActorAction(editorLayer, underCursor));
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));
}
// Or delete resource if found under cursor.
if (resourceUnderCursor != null)
editorActionManager.Add(new RemoveResourceAction(resourceLayer, cell, resourceUnderCursor));
}
}
@@ -219,6 +224,7 @@ namespace OpenRA.Mods.Common.Widgets
}
public void Tick() { }
public void Dispose() { }
}
@@ -271,12 +277,59 @@ namespace OpenRA.Mods.Common.Widgets
public void Do()
{
defaultBrush.Selection = selection;
defaultBrush.SetSelection(selection);
}
public void Undo()
{
defaultBrush.Selection = previousSelection;
defaultBrush.SetSelection(previousSelection);
}
}
sealed class RemoveSelectedActorAction : IEditorAction
{
[TranslationReference("name", "id")]
const string RemovedActor = "notification-removed-actor";
public string Text { get; }
readonly EditorSelection selection;
readonly EditorDefaultBrush defaultBrush;
readonly EditorActorLayer editorActorLayer;
readonly EditorActorPreview actor;
public RemoveSelectedActorAction(
EditorDefaultBrush defaultBrush,
EditorActorLayer editorActorLayer,
EditorActorPreview actor)
{
this.defaultBrush = defaultBrush;
this.editorActorLayer = editorActorLayer;
this.actor = actor;
selection = new EditorSelection
{
Actor = defaultBrush.Selection.Actor
};
Text = TranslationProvider.GetString(RemovedActor,
Translation.Arguments("name", actor.Info.Name, "id", actor.ID));
}
public void Execute()
{
Do();
}
public void Do()
{
defaultBrush.SetSelection(new EditorSelection());
editorActorLayer.Remove(actor);
}
public void Undo()
{
editorActorLayer.Add(actor);
defaultBrush.SetSelection(selection);
}
}