Create a framework that would ease the creation of modular interactable UI panels using in-game interactable UI objects
- Layout Elements wrapper classes for game objects to assist with making a layout
- Grid: Contains LayoutElements. Multiple LayoutElements will be presented in a grid format according to the position properties contained within them.
- PageGroup: Contains LayoutElements. Multiple LayoutElements will be presented as individual pages that can be navigated through by navigation buttons
- Control: Contains UI element game objects
- UI Element: UI elements taken from the game. Buttons, sliders, levers. Add helper functions for automatically adjusting relative text position
UIRoot
├── PageGroup
│ ├── GridPanel
│ │ ├── Widget
│ │ │ └── UIElement
public class LayoutElement
{
internal GameObject _layoutObject;
public GameObject GameObject { get { return _layoutObject; } }
public int GridX { get; set; }
public int GridY { get; set; }
public int SpanX { get; set; }
public int SpanY { get; set; }
private float _height;
public float Height { get { return _height; } }
public void Disable()
{
_layoutObject.SetActive(false);
}
public void Enable()
{
_layoutObject.SetActive(true);
}
public LayoutElement(string Name, int GridX, int GridY, int SpanX, int SpanY)
{
_layoutObject = new GameObject(Name);
this.GridX = GridX;
this.GridY = GridY;
this.SpanX = SpanX;
this.SpanY = SpanY;
}
public LayoutElement(string Name) : this(Name, -1, -1, 1, 1) {}
public void MakeChildOf(GameObject Adopter)
{
_layoutObject.transform.SetParent(Adopter.transform, false);
}
}
/// <summary>
/// PageGroup contain nestable elements and present them one at a time as pages.
/// PageGroup will present nav buttons to switch between pages if there is more than one page.
///
/// </summary>
public class PageGroup : LayoutElement
{
public List<LayoutElement> Pages { get { return _contents; } }
private List<LayoutElement> _contents = new List<LayoutElement>();
private int _activeIndex = 0;
public int ActiveIndex { get { return _activeIndex; } }
public PageGroup(List<LayoutElement> Pages, int GridX, int GridY, int SpanX, int SpanY) : base("PageGroup", GridX, GridY, SpanX, SpanY)
{
_contents = Pages;
foreach (LayoutElement page in Pages)
{
page.MakeChildOf(_layoutObject);
}
MakeNavButtons();
}
public PageGroup(List<LayoutElement> Pages)
public void AddPage(LayoutElement page)
{
_contents.Add(page);
}
private void NextPage()
{
if (_contents.Count == 0)
return;
_contents[_activeIndex].Disable();
_activeIndex++;
if (_activeIndex >= _contents.Count)
{
_activeIndex = 0;
}
_contents[_activeIndex].Enable();
}
private void PrevPage()
{
if (_contents.Count == 0)
return;
_contents[_activeIndex].Disable();
_activeIndex--;
if (_activeIndex <= _contents.Count)
{
_activeIndex = _contents.Count - 1;
}
_contents[_activeIndex].Enable();
}
private Widget btnNext;
private Widget btnPrev;
private void MakeNavButtons()
{
btnNext = new Widget(Templates.FromSmallButtonTemplate, string.Empty, "Next");
btnPrev = new Widget(Templates.FromSmallButtonTemplate, string.Empty, "Previous");
btnNext.Enable();
btnPrev.Enable();
btnNext.GameObject.transform.SetParent(_layoutObject.transform, false);
btnPrev.GameObject.transform.SetParent(_layoutObject.transform, false);
btnNext.GameObject.transform.localPosition = new Vector3(0.1f, -0.6f, -0f);
btnPrev.GameObject.transform.localPosition = new Vector3(-0.1f, -0.6f, -0f);
btnNext.GameObject.transform.localRotation = Quaternion.Euler(0, 0, 270);
btnPrev.GameObject.transform.localRotation = Quaternion.Euler(0f, 0f, 90);
System.Action action = () => NextPage();
btnNext.UIElement.GetComponent<InteractionButton>().onPressed.AddListener(action);
action = () => PrevPage();
btnPrev.UIElement.GetComponent<InteractionButton>().onPressed.AddListener(action);
}
}
/// <summary>
/// A GridPanel is a container for nestable elements that arranges them in a grid layout.
/// Will not check for overlaps or out of bounds placements.
/// Not an actual grid. Just a container that uses grid coordinates for placement using coordinates and multipliers
///
/// Constructor will get a list of contents and try to organize them automatically.
/// </summary>
public class GridPanel : LayoutElement
{
public List<LayoutElement> Contents { get { return _contents; } }
private List<LayoutElement> _contents = new List<LayoutElement>();
public int xMult { get; set; }
public int yMult { get; set; }
/// <summary>
///
/// </summary>
/// <param name="Contents">List of Nestable objects contained in the grid</param>
/// <param name="GridX">X position of this element's game object in the parent's grid</param>
/// <param name="GridY">Y position of this element's game object in the parent's grid</param>
/// <param name="SpanX">How many grid cells this element spans in the parent's grid (X direction)</param>
/// <param name="SpanY">How many grid cells this element spans in the parent's grid (Y direction)</param>
/// <remarks>Grid spans and positions refer to this layout element. Not the children</remarks>
public GridPanel(List<LayoutElement> Contents, int GridX, int GridY, int SpanX, int SpanY)
{
_contents = Contents;
foreach (LayoutElement item in Contents)
{
item.MakeChildOf(_layoutObject);
}
}
}
/// <summary>
/// </summary>
public class Widget : LayoutElement
{
private GameObject _uiElement;
public GameObject UIElement { get { return _uiElement; } }
public string Name { get; set; }
public Widget(GameObject UiElement, string Text, string Name)
{
_layoutObject = new GameObject(Name);
_uiElement = UiElement;
_uiElement.SetActive(true);
_uiElement.transform.SetParent(_layoutObject.transform, false);
this.Name = Name;
}
}