// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using FlaxEditor.CustomEditors.Elements;
using FlaxEditor.CustomEditors.GUI;
using FlaxEditor.GUI;
using FlaxEditor.GUI.ContextMenu;
using FlaxEngine;
using FlaxEngine.Assertions;
using FlaxEngine.GUI;
namespace FlaxEditor.CustomEditors
{
///
/// Represents a container control for . Can contain child elements.
///
///
[HideInEditor]
public abstract class LayoutElementsContainer : LayoutElement
{
///
/// Helper flag that is set to true if this container is in root presenter area, otherwise it's one of child groups.
/// It's used to collapse all child groups and open the root ones by auto.
///
internal bool isRootGroup = true;
///
/// The children.
///
public readonly List Children = new List();
///
/// The child custom editors.
///
public readonly List Editors = new List();
///
/// Gets the control represented by this element.
///
public abstract ContainerControl ContainerControl { get; }
///
/// Adds new group element.
///
/// The title.
/// The custom editor to be linked for a group. Used to provide more utility functions for a drop panel UI via context menu.
/// True if use drop down icon and transparent group header, otherwise use normal style.
/// The created element.
public GroupElement Group(string title, CustomEditor linkedEditor, bool useTransparentHeader = false)
{
var element = Group(title, useTransparentHeader);
element.Panel.Tag = linkedEditor;
element.Panel.MouseButtonRightClicked += OnGroupPanelMouseButtonRightClicked;
return element;
}
private void OnGroupPanelMouseButtonRightClicked(DropPanel groupPanel, Float2 location)
{
var linkedEditor = (CustomEditor)groupPanel.Tag;
var menu = new ContextMenu();
var revertToPrefab = menu.AddButton("Revert to Prefab", linkedEditor.RevertToReferenceValue);
revertToPrefab.Enabled = linkedEditor.CanRevertReferenceValue;
var resetToDefault = menu.AddButton("Reset to default", linkedEditor.RevertToDefaultValue);
resetToDefault.Enabled = linkedEditor.CanRevertDefaultValue;
menu.AddSeparator();
menu.AddButton("Copy", linkedEditor.Copy);
var paste = menu.AddButton("Paste", linkedEditor.Paste);
paste.Enabled = linkedEditor.CanPaste;
menu.Show(groupPanel, location);
}
///
/// Adds new group element.
///
/// The title.
/// True if use drop down icon and transparent group header, otherwise use normal style.
/// The created element.
public GroupElement Group(string title, bool useTransparentHeader = false)
{
var element = new GroupElement();
if (!isRootGroup)
{
element.Panel.Close(false);
}
else if (this is CustomEditorPresenter presenter && (presenter.Features & FeatureFlags.CacheExpandedGroups) != 0)
{
if (Editor.Instance.ProjectCache.IsCollapsedGroup(title))
element.Panel.Close(false);
element.Panel.IsClosedChanged += OnPanelIsClosedChanged;
}
element.isRootGroup = false;
element.Panel.HeaderText = title;
if (useTransparentHeader)
{
element.Panel.EnableDropDownIcon = true;
element.Panel.EnableContainmentLines = false;
element.Panel.HeaderColor = element.Panel.HeaderColorMouseOver = Color.Transparent;
}
OnAddElement(element);
return element;
}
private void OnPanelIsClosedChanged(DropPanel panel)
{
Editor.Instance.ProjectCache.SetCollapsedGroup(panel.HeaderText, panel.IsClosed);
}
///
/// Adds new horizontal panel element.
///
/// The created element.
public HorizontalPanelElement HorizontalPanel()
{
var element = new HorizontalPanelElement();
OnAddElement(element);
return element;
}
///
/// Adds new vertical panel element.
///
/// The created element.
public VerticalPanelElement VerticalPanel()
{
var element = new VerticalPanelElement();
OnAddElement(element);
return element;
}
///
/// Adds new button element.
///
/// The text.
/// The tooltip text.
/// The created element.
public ButtonElement Button(string text, string tooltip = null)
{
var element = new ButtonElement();
element.Button.Text = text;
element.Button.TooltipText = tooltip;
OnAddElement(element);
return element;
}
///
/// Adds new button element with custom color.
///
/// The text.
/// The color.
/// The tooltip text.
/// The created element.
public ButtonElement Button(string text, Color color, string tooltip = null)
{
ButtonElement element = new ButtonElement();
element.Button.Text = text;
element.Button.TooltipText = tooltip;
element.Button.SetColors(color);
OnAddElement(element);
return element;
}
///
/// Adds new custom element.
///
/// The custom control.
/// The created element.
public CustomElement Custom()
where T : Control, new()
{
var element = new CustomElement();
OnAddElement(element);
return element;
}
///
/// Adds new custom element with name label.
///
/// The property name.
/// The custom control.
/// The property label tooltip text.
/// The created element.
public CustomElement Custom(string name, string tooltip = null)
where T : Control, new()
{
var property = AddPropertyItem(name, tooltip);
return property.Custom();
}
///
/// Adds new custom elements container.
///
/// The custom control.
/// The created element.
public CustomElementsContainer CustomContainer()
where T : ContainerControl, new()
{
var element = new CustomElementsContainer();
OnAddElement(element);
return element;
}
///
/// Adds new custom elements container with name label.
///
/// The property name.
/// The custom control.
/// The property label tooltip text.
/// The created element.
public CustomElementsContainer CustomContainer(string name, string tooltip = null)
where T : ContainerControl, new()
{
var property = AddPropertyItem(name);
return property.CustomContainer();
}
///
/// Adds new space.
///
/// The space height.
/// The created element.
public SpaceElement Space(float height)
{
var element = new SpaceElement();
element.Init(height);
OnAddElement(element);
return element;
}
///
/// Adds sprite image to the layout.
///
/// The sprite.
/// The created element.
public ImageElement Image(SpriteHandle sprite)
{
var element = new ImageElement();
element.Image.Brush = new SpriteBrush(sprite);
OnAddElement(element);
return element;
}
///
/// Adds texture image to the layout.
///
/// The texture.
/// The created element.
public ImageElement Image(Texture texture)
{
var element = new ImageElement();
element.Image.Brush = new TextureBrush(texture);
OnAddElement(element);
return element;
}
///
/// Adds GPU texture image to the layout.
///
/// The GPU texture.
/// The created element.
public ImageElement Image(GPUTexture texture)
{
var element = new ImageElement();
element.Image.Brush = new GPUTextureBrush(texture);
OnAddElement(element);
return element;
}
///
/// Adds new header control.
///
/// The header text.
/// The created element.
public LabelElement Header(string text)
{
var element = Label(text);
element.Label.Font = new FontReference(Style.Current.FontLarge);
return element;
}
internal LabelElement Header(HeaderAttribute header)
{
var element = Header(header.Text);
if (header.FontSize != -1)
element.Label.Font = new FontReference(element.Label.Font.Font, header.FontSize);
if (header.Color != 0)
element.Label.TextColor = Color.FromRGBA(header.Color);
return element;
}
///
/// Adds new text box element.
///
/// Enable/disable multiline text input support
/// The created element.
public TextBoxElement TextBox(bool isMultiline = false)
{
var element = new TextBoxElement(isMultiline);
OnAddElement(element);
return element;
}
///
/// Adds new check box element.
///
/// The created element.
public CheckBoxElement Checkbox()
{
var element = new CheckBoxElement();
OnAddElement(element);
return element;
}
///
/// Adds new check box element with name label.
///
/// The property name.
/// The property label tooltip text.
/// The created element.
public CheckBoxElement Checkbox(string name, string tooltip = null)
{
var property = AddPropertyItem(name, tooltip);
return property.Checkbox();
}
///
/// Adds new tree element.
///
/// The created element.
public TreeElement Tree()
{
var element = new TreeElement();
OnAddElement(element);
return element;
}
///
/// Adds new label element.
///
/// The label text.
/// The label text horizontal alignment.
/// The created element.
public LabelElement Label(string text, TextAlignment horizontalAlignment = TextAlignment.Near)
{
var element = new LabelElement();
element.Label.Text = text;
element.Label.HorizontalAlignment = horizontalAlignment;
OnAddElement(element);
return element;
}
///
/// Adds new label element with name label.
///
/// The property name.
/// The label text.
/// The property label tooltip text.
/// The created element.
public LabelElement Label(string name, string text, string tooltip = null)
{
var property = AddPropertyItem(name, tooltip);
return property.Label(text);
}
///
/// Adds new label element.
///
/// The label text.
/// The label text horizontal alignment.
/// The created element.
public CustomElement ClickableLabel(string text, TextAlignment horizontalAlignment = TextAlignment.Near)
{
var element = new CustomElement();
element.CustomControl.Height = 18.0f;
element.CustomControl.Text = text;
element.CustomControl.HorizontalAlignment = horizontalAlignment;
OnAddElement(element);
return element;
}
///
/// Adds new label element with name label.
///
/// The property name.
/// The label text.
/// The property label tooltip text.
/// The created element.
public CustomElement ClickableLabel(string name, string text, string tooltip = null)
{
var property = AddPropertyItem(name, tooltip);
return property.ClickableLabel(text);
}
///
/// Adds new float value element.
///
/// The created element.
public FloatValueElement FloatValue()
{
var element = new FloatValueElement();
OnAddElement(element);
return element;
}
///
/// Adds new float value element with name label.
///
/// The property name.
/// The property label tooltip text.
/// The created element.
public FloatValueElement FloatValue(string name, string tooltip = null)
{
var property = AddPropertyItem(name, tooltip);
return property.FloatValue();
}
///
/// Adds new double value element.
///
/// The created element.
public DoubleValueElement DoubleValue()
{
var element = new DoubleValueElement();
OnAddElement(element);
return element;
}
///
/// Adds new double value element with name label.
///
/// The property name.
/// The property label tooltip text.
/// The created element.
public DoubleValueElement DoubleValue(string name, string tooltip = null)
{
var property = AddPropertyItem(name, tooltip);
return property.DoubleValue();
}
///
/// Adds new slider element.
///
/// The created element.
public SliderElement Slider()
{
var element = new SliderElement();
OnAddElement(element);
return element;
}
///
/// Adds new slider element with name label.
///
/// The property name.
/// The property label tooltip text.
/// The created element.
public SliderElement Slider(string name, string tooltip = null)
{
var property = AddPropertyItem(name, tooltip);
return property.Slider();
}
///
/// Adds new signed integer (up to long range) value element.
///
/// The created element.
public SignedIntegerValueElement SignedIntegerValue()
{
var element = new SignedIntegerValueElement();
OnAddElement(element);
return element;
}
///
/// Adds new unsigned signed integer (up to ulong range) value element.
///
/// The created element.
public UnsignedIntegerValueElement UnsignedIntegerValue()
{
var element = new UnsignedIntegerValueElement();
OnAddElement(element);
return element;
}
///
/// Adds new integer value element.
///
/// The created element.
public IntegerValueElement IntegerValue()
{
var element = new IntegerValueElement();
OnAddElement(element);
return element;
}
///
/// Adds new integer value element with name label.
///
/// The property name.
/// The property label tooltip text.
/// The created element.
public IntegerValueElement IntegerValue(string name, string tooltip = null)
{
var property = AddPropertyItem(name, tooltip);
return property.IntegerValue();
}
///
/// Adds new combobox element.
///
/// The created element.
public ComboBoxElement ComboBox()
{
var element = new ComboBoxElement();
OnAddElement(element);
return element;
}
///
/// Adds new combobox element with name label.
///
/// The property name.
/// The property label tooltip text.
/// The created element.
public ComboBoxElement ComboBox(string name, string tooltip = null)
{
var property = AddPropertyItem(name, tooltip);
return property.ComboBox();
}
///
/// Adds new enum value element.
///
/// The enum type.
/// The custom entries layout builder. Allows to hide existing or add different enum values to editor.
/// The formatting mode.
/// The created element.
public EnumElement Enum(Type type, EnumComboBox.BuildEntriesDelegate customBuildEntriesDelegate = null, EnumDisplayAttribute.FormatMode formatMode = EnumDisplayAttribute.FormatMode.Default)
{
var element = new EnumElement(type, customBuildEntriesDelegate, formatMode);
OnAddElement(element);
return element;
}
///
/// Adds new enum value element with name label.
///
/// The property name.
/// The enum type.
/// The custom entries layout builder. Allows to hide existing or add different enum values to editor.
/// The property label tooltip text.
/// The formatting mode.
/// The created element.
public EnumElement Enum(string name, Type type, EnumComboBox.BuildEntriesDelegate customBuildEntriesDelegate = null, string tooltip = null, EnumDisplayAttribute.FormatMode formatMode = EnumDisplayAttribute.FormatMode.Default)
{
var property = AddPropertyItem(name, tooltip);
return property.Enum(type, customBuildEntriesDelegate, formatMode);
}
///
/// Adds object(s) editor. Selects proper based on overrides.
///
/// The values.
/// The custom editor to use. If null will detect it by auto.
/// The created element.
public CustomEditor Object(ValueContainer values, CustomEditor overrideEditor = null)
{
if (values == null)
throw new ArgumentNullException();
var editor = CustomEditorsUtil.CreateEditor(values, overrideEditor);
OnAddEditor(editor);
editor.Initialize(CustomEditor.CurrentCustomEditor.Presenter, this, values);
return editor;
}
///
/// Adds object(s) editor with name label. Selects proper based on overrides.
///
/// The property name.
/// The values.
/// The custom editor to use. If null will detect it by auto.
/// The property label tooltip text.
/// The created element.
public CustomEditor Object(string name, ValueContainer values, CustomEditor overrideEditor = null, string tooltip = null)
{
var property = AddPropertyItem(name, tooltip);
return property.Object(values, overrideEditor);
}
///
/// Adds object(s) editor with name label. Selects proper based on overrides.
///
/// The property label.
/// The values.
/// The custom editor to use. If null will detect it by auto.
/// The property label tooltip text.
/// The created element.
public CustomEditor Object(PropertyNameLabel label, ValueContainer values, CustomEditor overrideEditor = null, string tooltip = null)
{
var property = AddPropertyItem(label, tooltip);
return property.Object(values, overrideEditor);
}
///
/// Adds object property editor. Selects proper based on overrides.
///
/// The property name.
/// The values.
/// The custom editor to use. If null will detect it by auto.
/// The property label tooltip text.
/// The created element.
public CustomEditor Property(string name, ValueContainer values, CustomEditor overrideEditor = null, string tooltip = null)
{
var editor = CustomEditorsUtil.CreateEditor(values, overrideEditor);
var style = editor.Style;
if (style == DisplayStyle.InlineIntoParent || name == EditorDisplayAttribute.InlineStyle)
{
return Object(values, editor);
}
if (style == DisplayStyle.Group)
{
var group = Group(name, editor, true);
group.Panel.Close(false);
group.Panel.TooltipText = tooltip;
return group.Object(values, editor);
}
var property = AddPropertyItem(name, tooltip);
return property.Object(values, editor);
}
///
/// Adds object property editor. Selects proper based on overrides.
///
/// The property label.
/// The values.
/// The custom editor to use. If null will detect it by auto.
/// The property label tooltip text.
/// The created element.
public CustomEditor Property(PropertyNameLabel label, ValueContainer values, CustomEditor overrideEditor = null, string tooltip = null)
{
var editor = CustomEditorsUtil.CreateEditor(values, overrideEditor);
var style = editor.Style;
if (style == DisplayStyle.InlineIntoParent)
{
return Object(values, editor);
}
if (style == DisplayStyle.Group)
{
var group = Group(label.Text, editor, true);
group.Panel.Close(false);
group.Panel.TooltipText = tooltip;
return group.Object(values, editor);
}
var property = AddPropertyItem(label, tooltip);
return property.Object(values, editor);
}
private PropertiesListElement AddPropertyItem()
{
// Try to reuse previous control
PropertiesListElement element;
if (Children.Count > 0 && Children[Children.Count - 1] is PropertiesListElement propertiesListElement)
{
element = propertiesListElement;
}
else
{
element = new PropertiesListElement();
OnAddElement(element);
}
return element;
}
///
/// Adds the to the current layout or reuses the previous one. Used to inject properties.
///
/// The property label name.
/// The property label tooltip text.
/// The element.
public PropertiesListElement AddPropertyItem(string name, string tooltip = null)
{
var element = AddPropertyItem();
element.OnAddProperty(name, tooltip);
return element;
}
///
/// Adds the to the current layout or reuses the previous one. Used to inject properties.
///
/// The property label.
/// The property label tooltip text.
/// The element.
public PropertiesListElement AddPropertyItem(PropertyNameLabel label, string tooltip = null)
{
if (label == null)
throw new ArgumentNullException();
var element = AddPropertyItem();
element.OnAddProperty(label, tooltip);
return element;
}
///
/// Adds custom element to the layout.
///
/// The element.
public void AddElement(LayoutElement element)
{
if (element == null)
throw new ArgumentNullException();
OnAddElement(element);
}
///
/// Called when element is added to the layout.
///
/// The element.
protected virtual void OnAddElement(LayoutElement element)
{
element.Control.Parent = ContainerControl;
Children.Add(element);
}
///
/// Called when editor is added.
///
/// The editor.
protected virtual void OnAddEditor(CustomEditor editor)
{
// This could be passed by the calling code but it's easier to hide it from the user
// Note: we need that custom editor to link generated editor into the parent
var customEditor = CustomEditor.CurrentCustomEditor;
Assert.IsNotNull(customEditor);
customEditor.OnChildCreated(editor);
Editors.Add(editor);
}
///
/// Clears the layout.
///
public virtual void ClearLayout()
{
Children.Clear();
Editors.Clear();
}
///
public override Control Control => ContainerControl;
}
}