/* * Copyright 2022 Peter Han * Permission is hereby granted, free of charge, to any person obtaining a copy of this software * and associated documentation files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or * substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ using System; using System.Collections.Generic; using UnityEngine; namespace PeterHan.PLib.UI { /// /// A panel which lays out its components using grid-type constraints. /// public class PGridPanel : PContainer, IDynamicSizable { /// /// The number of columns currently defined. /// public int Columns => columns.Count; public bool DynamicSize { get; set; } /// /// The number of rows currently defined. /// public int Rows => rows.Count; /// /// The children of this panel. /// private readonly ICollection> children; /// /// The columns in this panel. /// private readonly IList columns; /// /// The rows in this panel. /// private readonly IList rows; public PGridPanel() : this(null) { } public PGridPanel(string name) : base(name ?? "GridPanel") { children = new List>(16); columns = new List(16); rows = new List(16); DynamicSize = true; Margin = null; } /// /// Adds a child to this panel. /// /// The child to add. /// The location where the child will be placed. /// This panel for call chaining. public PGridPanel AddChild(IUIComponent child, GridComponentSpec spec) { if (child == null) throw new ArgumentNullException(nameof(child)); if (spec == null) throw new ArgumentNullException(nameof(spec)); children.Add(new GridComponent(spec, child)); return this; } /// /// Adds a column to this panel. /// /// The specification for that column. /// This panel for call chaining. public PGridPanel AddColumn(GridColumnSpec column) { if (column == null) throw new ArgumentNullException(nameof(column)); columns.Add(column); return this; } /// /// Adds a handler when this panel is realized. /// /// The handler to invoke on realization. /// This panel for call chaining. public PGridPanel AddOnRealize(PUIDelegates.OnRealize onRealize) { OnRealize += onRealize; return this; } /// /// Adds a row to this panel. /// /// The specification for that row. /// This panel for call chaining. public PGridPanel AddRow(GridRowSpec row) { if (row == null) throw new ArgumentNullException(nameof(row)); rows.Add(row); return this; } public override GameObject Build() { if (Columns < 1) throw new InvalidOperationException("At least one column must be defined"); if (Rows < 1) throw new InvalidOperationException("At least one row must be defined"); var panel = PUIElements.CreateUI(null, Name); SetImage(panel); // Add layout component var layout = panel.AddComponent(); layout.Margin = Margin; foreach (var column in columns) layout.AddColumn(column); foreach (var row in rows) layout.AddRow(row); // Add children foreach (var child in children) layout.AddComponent(child.Item.Build(), child); if (!DynamicSize) layout.LockLayout(); layout.flexibleWidth = FlexSize.x; layout.flexibleHeight = FlexSize.y; InvokeRealize(panel); return panel; } public override string ToString() { return string.Format("PGridPanel[Name={0},Rows={1:D},Columns={2:D}]", Name, Rows, Columns); } } }