using System.Numerics; using Content.Client.UserInterface.Controls; using Content.Shared.Construction.Prototypes; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Prototypes; namespace Content.Client.Construction.UI { /// /// This is the interface for a UI View of the construction window. The point of it is to abstract away the actual /// UI controls and just provide higher level operations on the entire window. This View is completely passive and /// just raises events to the outside world. This class is controlled by the . /// public interface IConstructionMenuView : IDisposable { // It isn't optimal to expose UI controls like this, but the UI control design is // questionable so it can't be helped. string[] Categories { get; set; } OptionButton OptionCategories { get; } bool EraseButtonPressed { get; set; } bool GridViewButtonPressed { get; set; } bool BuildButtonPressed { get; set; } ListContainer Recipes { get; } ItemList RecipeStepList { get; } ScrollContainer RecipesGridScrollContainer { get; } GridContainer RecipesGrid { get; } event EventHandler<(string search, string catagory)> PopulateRecipes; event EventHandler RecipeSelected; event EventHandler RecipeFavorited; event EventHandler BuildButtonToggled; event EventHandler EraseButtonToggled; event EventHandler ClearAllGhosts; void ClearRecipeInfo(); void SetRecipeInfo(string name, string description, EntityPrototype? targetPrototype, bool isItem, bool isFavorite); void ResetPlacement(); #region Window Control event Action? OnClose; bool IsOpen { get; } void OpenCentered(); void MoveToFront(); bool IsAtFront(); void Close(); #endregion } [GenerateTypedNameReferences] public sealed partial class ConstructionMenu : DefaultWindow, IConstructionMenuView { public bool BuildButtonPressed { get => BuildButton.Pressed; set => BuildButton.Pressed = value; } public string[] Categories { get; set; } = Array.Empty(); public bool EraseButtonPressed { get => EraseButton.Pressed; set => EraseButton.Pressed = value; } public bool GridViewButtonPressed { get => MenuGridViewButton.Pressed; set => MenuGridViewButton.Pressed = value; } public ConstructionMenu() { SetSize = new Vector2(560, 450); MinSize = new Vector2(560, 320); IoCManager.InjectDependencies(this); RobustXamlLoader.Load(this); Title = Loc.GetString("construction-menu-title"); BuildButton.Text = Loc.GetString("construction-menu-place-ghost"); Recipes.ItemPressed += (_, data) => RecipeSelected?.Invoke(this, data as ConstructionMenuListData); Recipes.NoItemSelected += () => RecipeSelected?.Invoke(this, null); Recipes.GenerateItem += (data, button) => { if (data is not ConstructionMenuListData (var prototype, var targetPrototype)) return; var entProtoView = new EntityPrototypeView() { SetSize = new(32f), Stretch = SpriteView.StretchMode.Fill, Scale = new(2), Margin = new(0, 2), }; entProtoView.SetPrototype(targetPrototype); var label = new Label() { Text = prototype.Name, Margin = new(5, 0), }; var box = new BoxContainer(); box.AddChild(entProtoView); box.AddChild(label); button.AddChild(box); button.ToolTip = prototype.Description; button.AddStyleClass(ListContainer.StyleClassListContainerButton); }; SearchBar.OnTextChanged += _ => PopulateRecipes?.Invoke(this, (SearchBar.Text, Categories[OptionCategories.SelectedId])); OptionCategories.OnItemSelected += obj => { OptionCategories.SelectId(obj.Id); SearchBar.SetText(string.Empty); PopulateRecipes?.Invoke(this, (SearchBar.Text, Categories[obj.Id])); }; BuildButton.Text = Loc.GetString("construction-menu-place-ghost"); BuildButton.OnToggled += args => BuildButtonToggled?.Invoke(this, args.Pressed); ClearButton.Text = Loc.GetString("construction-menu-clear-all"); ClearButton.OnPressed += _ => ClearAllGhosts?.Invoke(this, EventArgs.Empty); EraseButton.Text = Loc.GetString("construction-menu-eraser-mode"); EraseButton.OnToggled += args => EraseButtonToggled?.Invoke(this, args.Pressed); FavoriteButton.OnPressed += args => RecipeFavorited?.Invoke(this, EventArgs.Empty); MenuGridViewButton.OnPressed += _ => PopulateRecipes?.Invoke(this, (SearchBar.Text, Categories[OptionCategories.SelectedId])); } public event EventHandler? ClearAllGhosts; public event EventHandler<(string search, string catagory)>? PopulateRecipes; public event EventHandler? RecipeSelected; public event EventHandler? RecipeFavorited; public event EventHandler? BuildButtonToggled; public event EventHandler? EraseButtonToggled; public void ResetPlacement() { BuildButton.Pressed = false; EraseButton.Pressed = false; } public void SetRecipeInfo( string name, string description, EntityPrototype? targetPrototype, bool isItem, bool isFavorite) { BuildButton.Disabled = false; BuildButton.Text = Loc.GetString(isItem ? "construction-menu-place-ghost" : "construction-menu-craft"); TargetName.SetMessage(name); TargetDesc.SetMessage(description); TargetTexture.SetPrototype(targetPrototype?.ID); FavoriteButton.Visible = true; FavoriteButton.Text = Loc.GetString( isFavorite ? "construction-add-favorite-button" : "construction-remove-from-favorite-button"); } public void ClearRecipeInfo() { BuildButton.Disabled = true; TargetName.SetMessage(string.Empty); TargetDesc.SetMessage(string.Empty); TargetTexture.SetPrototype(null); FavoriteButton.Visible = false; RecipeStepList.Clear(); } public sealed record ConstructionMenuListData(ConstructionPrototype Prototype, EntityPrototype TargetPrototype) : ListData; } }