Files
OpenRA/OpenRA.Mods.Common/Widgets/Logic/Editor/TileSelectorLogic.cs
let5sne.win10 9cf6ebb986
Some checks failed
Continuous Integration / Linux (.NET 8.0) (push) Has been cancelled
Continuous Integration / Windows (.NET 8.0) (push) Has been cancelled
Initial commit: OpenRA game engine
Fork from OpenRA/OpenRA with one-click launch script (start-ra.cmd)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 21:46:54 +08:00

145 lines
4.5 KiB
C#

#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;
using System.Collections.Immutable;
using System.Globalization;
using System.IO;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Terrain;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets.Logic
{
[IncludeStaticFluentReferences(
typeof(PaintTileEditorAction),
typeof(FloodFillEditorAction),
typeof(CommonSelectorLogic))]
public class TileSelectorLogic : CommonSelectorLogic
{
sealed class TileSelectorTemplate
{
public readonly TerrainTemplateInfo Template;
public readonly ImmutableArray<string> Categories;
public readonly string[] SearchTerms;
public readonly string Tooltip;
public TileSelectorTemplate(TerrainTemplateInfo template)
{
Template = template;
Categories = template.Categories;
Tooltip = template.Id.ToString(NumberFormatInfo.CurrentInfo);
SearchTerms = [Tooltip];
}
}
readonly ITemplatedTerrainInfo terrainInfo;
readonly ImmutableArray<TileSelectorTemplate> allTemplates;
[ObjectCreator.UseCtor]
public TileSelectorLogic(Widget widget, ModData modData, World world, WorldRenderer worldRenderer)
: base(widget, modData, world, worldRenderer, "TILETEMPLATE_LIST", "TILEPREVIEW_TEMPLATE")
{
terrainInfo = world.Map.Rules.TerrainInfo as ITemplatedTerrainInfo;
if (terrainInfo == null)
throw new InvalidDataException("TileSelectorLogic requires a template-based tileset.");
allTemplates = terrainInfo.TemplatesInDefinitionOrder.Select(t => new TileSelectorTemplate(t)).ToImmutableArray();
allCategories = allTemplates.SelectMany(t => t.Categories)
.Distinct()
.OrderBy(CategoryOrder)
.ToArray();
foreach (var c in allCategories)
{
SelectedCategories.Add(c);
FilteredCategories.Add(c);
}
SearchTextField.OnTextEdited = () =>
{
searchFilter = SearchTextField.Text.Trim();
FilteredCategories.Clear();
if (!string.IsNullOrEmpty(searchFilter))
FilteredCategories.AddRange(
allTemplates.Where(t => t.SearchTerms.Any(
s => s.Contains(searchFilter, StringComparison.CurrentCultureIgnoreCase)))
.SelectMany(t => t.Categories)
.Distinct()
.OrderBy(CategoryOrder));
else
FilteredCategories.AddRange(allCategories);
InitializePreviews();
};
InitializePreviews();
}
int CategoryOrder(string category)
{
var i = terrainInfo.EditorTemplateOrder.IndexOf(category);
return i >= 0 ? i : int.MaxValue;
}
protected override void InitializePreviews()
{
Panel.RemoveChildren();
if (SelectedCategories.Count == 0)
return;
foreach (var t in allTemplates)
{
if (!SelectedCategories.Overlaps(t.Categories))
continue;
if (!string.IsNullOrEmpty(searchFilter) &&
!t.SearchTerms.Any(s => s.Contains(searchFilter, StringComparison.CurrentCultureIgnoreCase)))
continue;
var tileId = t.Template.Id;
var item = ScrollItemWidget.Setup(ItemTemplate,
() => Editor.CurrentBrush is EditorTileBrush editorCursor && editorCursor.TerrainTemplate.Id == tileId,
() => Editor.SetBrush(new EditorTileBrush(Editor, tileId, WorldRenderer)));
var preview = item.Get<TerrainTemplatePreviewWidget>("TILE_PREVIEW");
preview.SetTemplate(terrainInfo.Templates[tileId]);
// Scale templates to fit within the panel
// Preview position is assumed to be a margin
var maxPreviewWidth = item.Bounds.Width - 2 * preview.Bounds.X;
var maxPreviewHeight = item.Bounds.Height - 2 * preview.Bounds.Y;
var scale = 1f;
if (preview.IdealPreviewSize.X > maxPreviewWidth)
scale = maxPreviewWidth / (float)preview.IdealPreviewSize.X;
if (preview.IdealPreviewSize.Y * scale > maxPreviewHeight)
scale = maxPreviewHeight / (float)preview.IdealPreviewSize.Y;
preview.Scale = scale;
preview.Bounds.Width = (int)(scale * preview.IdealPreviewSize.X);
preview.Bounds.Height = (int)(scale * preview.IdealPreviewSize.Y);
item.Bounds.Width = preview.Bounds.Width + 2 * preview.Bounds.X;
item.Bounds.Height = preview.Bounds.Height + 2 * preview.Bounds.Y;
item.IsVisible = () => true;
item.GetTooltipText = () => t.Tooltip;
Panel.AddChild(item);
}
}
}
}