diff --git a/OpenRA.Mods.Common/Traits/EditorTilesetFilter.cs b/OpenRA.Mods.Common/Traits/EditorTilesetFilter.cs index 18e1c3626e..6a41433cb0 100644 --- a/OpenRA.Mods.Common/Traits/EditorTilesetFilter.cs +++ b/OpenRA.Mods.Common/Traits/EditorTilesetFilter.cs @@ -18,6 +18,7 @@ namespace OpenRA.Mods.Common.Traits { public readonly HashSet RequireTilesets = null; public readonly HashSet ExcludeTilesets = null; + public readonly string[] Categories; } public class EditorTilesetFilter { } diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/ActorSelectorLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/ActorSelectorLogic.cs index f488a21411..85a69fb0a2 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Editor/ActorSelectorLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/ActorSelectorLogic.cs @@ -10,11 +10,11 @@ #endregion using System; +using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; using OpenRA.Primitives; -using OpenRA.Traits; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets.Logic @@ -28,6 +28,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic readonly Ruleset mapRules; readonly World world; readonly WorldRenderer worldRenderer; + readonly List allCategories; + readonly List selectedCategories = new List(); PlayerReference selectedOwner; @@ -57,7 +59,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic ownersDropDown.Text = selectedOwner.Name; ownersDropDown.TextColor = selectedOwner.Color.RGB; - IntializeActorPreviews(); + InitializeActorPreviews(); }); item.Get("LABEL").GetText = () => option.Name; @@ -75,15 +77,70 @@ namespace OpenRA.Mods.Common.Widgets.Logic ownersDropDown.Text = selectedOwner.Name; ownersDropDown.TextColor = selectedOwner.Color.RGB; - IntializeActorPreviews(); + var actorCategorySelector = widget.Get("ACTOR_CATEGORY"); + var filtersPanel = Ui.LoadWidget("ACTOR_CATEGORY_FILTER_PANEL", null, new WidgetArgs()); + var categoryTemplate = filtersPanel.Get("CATEGORY_TEMPLATE"); + var tileSetId = world.Map.Rules.TileSet.Id; + allCategories = mapRules.Actors.Where(a => !a.Value.Name.Contains('^')).Select(a => a.Value.TraitInfoOrDefault()) + .Where(i => i != null && i.Categories != null && + !(i.ExcludeTilesets != null && i.ExcludeTilesets.Contains(tileSetId)) && !(i.RequireTilesets != null && !i.RequireTilesets.Contains(tileSetId))) + .SelectMany(i => i.Categories).Distinct().OrderBy(i => i).ToList(); + selectedCategories.AddRange(allCategories); + + var selectButtons = filtersPanel.Get("SELECT_CATEGORIES_BUTTONS"); + filtersPanel.AddChild(selectButtons); + filtersPanel.Bounds.Height = Math.Min(allCategories.Count * categoryTemplate.Bounds.Height + 5 + selectButtons.Bounds.Height, panel.Bounds.Height); + + var selectAll = selectButtons.Get("SELECT_ALL"); + selectAll.OnClick = () => + { + selectedCategories.Clear(); + selectedCategories.AddRange(allCategories); + InitializeActorPreviews(); + }; + + var selectNone = selectButtons.Get("SELECT_NONE"); + selectNone.OnClick = () => + { + selectedCategories.Clear(); + InitializeActorPreviews(); + }; + + actorCategorySelector.OnMouseDown = _ => + { + actorCategorySelector.RemovePanel(); + actorCategorySelector.AttachPanel(filtersPanel); + }; + + foreach (var cat in allCategories) + { + var category = (CheckboxWidget)categoryTemplate.Clone(); + category.GetText = () => cat; + category.IsChecked = () => selectedCategories.Contains(cat); + category.IsVisible = () => true; + category.OnClick = () => + { + if (selectedCategories.Contains(cat)) + selectedCategories.Remove(cat); + else + selectedCategories.Add(cat); + + InitializeActorPreviews(); + }; + + filtersPanel.AddChild(category); + } + + InitializeActorPreviews(); } - void IntializeActorPreviews() + void InitializeActorPreviews() { panel.RemoveChildren(); var actors = mapRules.Actors.Where(a => !a.Value.Name.Contains('^')) .Select(a => a.Value); + var tileSetId = world.Map.Rules.TileSet.Id; foreach (var a in actors) { @@ -95,13 +152,14 @@ namespace OpenRA.Mods.Common.Widgets.Logic continue; var filter = actor.TraitInfoOrDefault(); - if (filter != null) - { - if (filter.ExcludeTilesets != null && filter.ExcludeTilesets.Contains(world.Map.Rules.TileSet.Id)) - continue; - if (filter.RequireTilesets != null && !filter.RequireTilesets.Contains(world.Map.Rules.TileSet.Id)) - continue; - } + if (filter == null || filter.Categories == null || !filter.Categories.Intersect(selectedCategories).Any()) + continue; + + if (filter.ExcludeTilesets != null && filter.ExcludeTilesets.Contains(tileSetId)) + continue; + + if (filter.RequireTilesets != null && !filter.RequireTilesets.Contains(tileSetId)) + continue; var td = new TypeDictionary(); td.Add(new OwnerInit(selectedOwner.Name)); diff --git a/mods/cnc/chrome/editor.yaml b/mods/cnc/chrome/editor.yaml index ba6d04acf6..630f472acd 100644 --- a/mods/cnc/chrome/editor.yaml +++ b/mods/cnc/chrome/editor.yaml @@ -320,10 +320,16 @@ Container@EDITOR_WORLD_ROOT: Width: PARENT_RIGHT Height: 25 Font: Bold - ScrollPanel@ACTORTEMPLATE_LIST: - Y: 24 + DropDownButton@ACTOR_CATEGORY: + Y: 25 Width: PARENT_RIGHT - Height: PARENT_BOTTOM - 24 + Height: 25 + Text: Categories + Font: Bold + ScrollPanel@ACTORTEMPLATE_LIST: + Y: 50 + Width: PARENT_RIGHT + Height: PARENT_BOTTOM - 50 TopBottomSpacing: 4 ItemSpacing: 4 Children: @@ -409,3 +415,29 @@ Container@EDITOR_WORLD_ROOT: Align: Left Font: Bold Contrast: true + +ScrollPanel@ACTOR_CATEGORY_FILTER_PANEL: + Width: 250 + Children: + Container@SELECT_CATEGORIES_BUTTONS + Width: PARENT_RIGHT + Height: 30 + Children: + Button@SELECT_ALL: + X: 10 + Y: 2 + Width: 100 + Height: 25 + Text: Select all + Button@SELECT_NONE: + X: 120 + Y: 2 + Width: 100 + Height: 25 + Text: Select none + Checkbox@CATEGORY_TEMPLATE: + X: 5 + Y: 5 + Width: PARENT_RIGHT - 29 + Height: 22 + Visible: false diff --git a/mods/common/chrome/editor.yaml b/mods/common/chrome/editor.yaml index cae75599b0..19f95c1fd7 100644 --- a/mods/common/chrome/editor.yaml +++ b/mods/common/chrome/editor.yaml @@ -295,11 +295,18 @@ Container@EDITOR_WORLD_ROOT: Width: 220 Height: 25 Font: Bold - ScrollPanel@ACTORTEMPLATE_LIST: + DropDownButton@ACTOR_CATEGORY: X: 10 Y: 35 - Width: PARENT_RIGHT - 20 - Height: PARENT_BOTTOM - 45 + Width: 220 + Height: 25 + Text: Categories + Font: Bold + ScrollPanel@ACTORTEMPLATE_LIST: + X: 10 + Y: 60 + Width: 220 + Height: PARENT_BOTTOM - 70 TopBottomSpacing: 4 ItemSpacing: 4 Children: @@ -394,3 +401,31 @@ Container@EDITOR_WORLD_ROOT: Align: Left Font: Bold Contrast: true + +ScrollPanel@ACTOR_CATEGORY_FILTER_PANEL: + Width: 220 + Children: + Container@SELECT_CATEGORIES_BUTTONS + Width: 220 + Height: 29 + Children: + Button@SELECT_ALL: + X: 5 + Y: 2 + Width: 90 + Height: 25 + Text: Select all + Font: Bold + Button@SELECT_NONE: + X: 100 + Y: 2 + Width: 90 + Height: 25 + Text: Select none + Font: Bold + Checkbox@CATEGORY_TEMPLATE: + X: 5 + Y: 5 + Width: PARENT_RIGHT - 29 + Height: 20 + Visible: false