1 #region Copyright & License Information
2 /*
3  * Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
4  * This file is part of OpenRA, which is free software. It is made
5  * available to you under the terms of the GNU General Public License
6  * as published by the Free Software Foundation, either version 3 of
7  * the License, or (at your option) any later version. For more
8  * information, see COPYING.
9  */
10 #endregion
11 
12 using System;
13 using System.Linq;
14 using OpenRA.Graphics;
15 using OpenRA.Mods.Common.Traits;
16 using OpenRA.Widgets;
17 
18 namespace OpenRA.Mods.Common.Widgets.Logic
19 {
20 	public class TileSelectorLogic : CommonSelectorLogic
21 	{
22 		class TileSelectorTemplate
23 		{
24 			public readonly TerrainTemplateInfo Template;
25 			public readonly string[] Categories;
26 			public readonly string[] SearchTerms;
27 			public readonly string Tooltip;
28 
TileSelectorTemplate(TerrainTemplateInfo template)29 			public TileSelectorTemplate(TerrainTemplateInfo template)
30 			{
31 				Template = template;
32 				Categories = template.Categories;
33 				Tooltip = template.Id.ToString();
34 				SearchTerms = new[] { Tooltip };
35 			}
36 		}
37 
38 		readonly TileSet tileset;
39 		readonly TileSelectorTemplate[] allTemplates;
40 		readonly EditorCursorLayer editorCursor;
41 
42 		[ObjectCreator.UseCtor]
TileSelectorLogic(Widget widget, World world, WorldRenderer worldRenderer)43 		public TileSelectorLogic(Widget widget, World world, WorldRenderer worldRenderer)
44 			: base(widget, world, worldRenderer, "TILETEMPLATE_LIST", "TILEPREVIEW_TEMPLATE")
45 		{
46 			tileset = world.Map.Rules.TileSet;
47 			allTemplates = tileset.Templates.Values.Select(t => new TileSelectorTemplate(t)).ToArray();
48 			editorCursor = world.WorldActor.Trait<EditorCursorLayer>();
49 
50 			allCategories = allTemplates.SelectMany(t => t.Categories)
51 				.Distinct()
52 				.OrderBy(CategoryOrder)
53 				.ToArray();
54 
55 			foreach (var c in allCategories)
56 			{
57 				SelectedCategories.Add(c);
58 				FilteredCategories.Add(c);
59 			}
60 
61 			SearchTextField.OnTextEdited = () =>
62 			{
63 				searchFilter = SearchTextField.Text.Trim();
64 				FilteredCategories.Clear();
65 
66 				if (!string.IsNullOrEmpty(searchFilter))
67 					FilteredCategories.AddRange(
68 						allTemplates.Where(t => t.SearchTerms.Any(
69 							s => s.IndexOf(searchFilter, StringComparison.OrdinalIgnoreCase) >= 0))
70 						.SelectMany(t => t.Categories)
71 						.Distinct()
72 						.OrderBy(CategoryOrder));
73 				else
74 					FilteredCategories.AddRange(allCategories);
75 
76 				InitializePreviews();
77 			};
78 
79 			InitializePreviews();
80 		}
81 
CategoryOrder(string category)82 		int CategoryOrder(string category)
83 		{
84 			var i = tileset.EditorTemplateOrder.IndexOf(category);
85 			return i >= 0 ? i : int.MaxValue;
86 		}
87 
InitializePreviews()88 		protected override void InitializePreviews()
89 		{
90 			Panel.RemoveChildren();
91 			if (!SelectedCategories.Any())
92 				return;
93 
94 			foreach (var t in allTemplates)
95 			{
96 				if (!SelectedCategories.Overlaps(t.Categories))
97 					continue;
98 
99 				if (!string.IsNullOrEmpty(searchFilter) && !t.SearchTerms.Any(s => s.IndexOf(searchFilter, StringComparison.OrdinalIgnoreCase) >= 0))
100 					continue;
101 
102 				var tileId = t.Template.Id;
103 				var item = ScrollItemWidget.Setup(ItemTemplate,
104 					() => editorCursor.Type == EditorCursorType.TerrainTemplate && editorCursor.TerrainTemplate.Id == tileId,
105 					() => Editor.SetBrush(new EditorTileBrush(Editor, tileId, WorldRenderer)));
106 
107 				var preview = item.Get<TerrainTemplatePreviewWidget>("TILE_PREVIEW");
108 				var template = tileset.Templates[tileId];
109 				var grid = WorldRenderer.World.Map.Grid;
110 				var bounds = WorldRenderer.Theater.TemplateBounds(template, grid.TileSize, grid.Type);
111 
112 				// Scale templates to fit within the panel
113 				var scale = 1f;
114 				while (scale * bounds.Width > ItemTemplate.Bounds.Width)
115 					scale /= 2;
116 
117 				preview.Template = template;
118 				preview.GetScale = () => scale;
119 				preview.Bounds.Width = (int)(scale * bounds.Width);
120 				preview.Bounds.Height = (int)(scale * bounds.Height);
121 
122 				item.Bounds.Width = preview.Bounds.Width + 2 * preview.Bounds.X;
123 				item.Bounds.Height = preview.Bounds.Height + 2 * preview.Bounds.Y;
124 				item.IsVisible = () => true;
125 				item.GetTooltipText = () => t.Tooltip;
126 
127 				Panel.AddChild(item);
128 			}
129 		}
130 	}
131 }
132