Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collection UI adjustments #2208

Merged
merged 4 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
234 changes: 162 additions & 72 deletions Source/Editor/CustomEditors/Editors/CollectionEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
using System;
using System.Collections;
using System.Linq;
using FlaxEditor.Content;
using FlaxEditor.CustomEditors.Elements;
using FlaxEditor.CustomEditors.GUI;
using FlaxEditor.GUI.Input;
using FlaxEditor.Content;
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.GUI.Drag;
using FlaxEditor.SceneGraph;
Expand Down Expand Up @@ -54,8 +54,13 @@ public CollectionItemLabel(CollectionEditor editor, int index)

private void OnSetupContextMenu(PropertyNameLabel label, ContextMenu menu, CustomEditor linkedEditor)
{
menu.ItemsContainer.RemoveChildren();

menu.AddButton("Copy", linkedEditor.Copy);
var paste = menu.AddButton("Paste", linkedEditor.Paste);
paste.Enabled = linkedEditor.CanPaste;

menu.AddSeparator();

var moveUpButton = menu.AddButton("Move up", OnMoveUpClicked);
moveUpButton.Enabled = Index > 0;

Expand All @@ -65,17 +70,100 @@ private void OnSetupContextMenu(PropertyNameLabel label, ContextMenu menu, Custo
menu.AddButton("Remove", OnRemoveClicked);
}

private void OnMoveUpClicked(ContextMenuButton button)
private void OnMoveUpClicked()
{
Editor.Move(Index, Index - 1);
}

private void OnMoveDownClicked()
{
Editor.Move(Index, Index + 1);
}

private void OnRemoveClicked()
{
Editor.Remove(Index);
}
}

private class CollectionDropPanel : DropPanel
{
/// <summary>
/// The collection editor.
/// </summary>
public CollectionEditor Editor;

/// <summary>
/// The index of the item (zero-based).
/// </summary>
public int Index { get; private set; }

/// <summary>
/// The linked editor.
/// </summary>
public CustomEditor LinkedEditor;

private bool _canReorder = true;

public void Setup(CollectionEditor editor, int index, bool canReorder = true)
{
HeaderHeight = 18;
_canReorder = canReorder;
EnableDropDownIcon = true;
var icons = FlaxEditor.Editor.Instance.Icons;
ArrowImageClosed = new SpriteBrush(icons.ArrowRight12);
ArrowImageOpened = new SpriteBrush(icons.ArrowDown12);
HeaderText = $"Element {index}";
IsClosed = false;
Editor = editor;
Index = index;
Offsets = new Margin(7, 7, 0, 0);

MouseButtonRightClicked += OnMouseButtonRightClicked;
if (_canReorder)
{
// TODO: Drag drop
}
}

private void OnMouseButtonRightClicked(DropPanel panel, Float2 location)
{
if (LinkedEditor == null)
return;
var linkedEditor = LinkedEditor;
var menu = new ContextMenu();

menu.AddButton("Copy", linkedEditor.Copy);
var paste = menu.AddButton("Paste", linkedEditor.Paste);
paste.Enabled = linkedEditor.CanPaste;

if (_canReorder)
{
menu.AddSeparator();

var moveUpButton = menu.AddButton("Move up", OnMoveUpClicked);
moveUpButton.Enabled = Index > 0;

var moveDownButton = menu.AddButton("Move down", OnMoveDownClicked);
moveDownButton.Enabled = Index + 1 < Editor.Count;
}

menu.AddButton("Remove", OnRemoveClicked);

menu.Show(panel, location);
}

private void OnMoveUpClicked()
{
Editor.Move(Index, Index - 1);
}

private void OnMoveDownClicked(ContextMenuButton button)
private void OnMoveDownClicked()
{
Editor.Move(Index, Index + 1);
}

private void OnRemoveClicked(ContextMenuButton button)
private void OnRemoveClicked()
{
Editor.Remove(Index);
}
Expand All @@ -85,13 +173,12 @@ private void OnRemoveClicked(ContextMenuButton button)
/// Determines if value of collection can be null.
/// </summary>
protected bool NotNullItems;

private IntegerValueElement _size;
private PropertyNameLabel _sizeLabel;
private IntValueBox _sizeBox;
private Color _background;
private int _elementsCount;
private bool _readOnly;
private bool _canReorderItems;
private CollectionAttribute.DisplayType _displayType;

/// <summary>
/// Gets the length of the collection.
Expand Down Expand Up @@ -124,12 +211,13 @@ public override void Initialize(LayoutElementsContainer layout)
_readOnly = false;
_canReorderItems = true;
_background = FlaxEngine.GUI.Style.Current.CollectionBackgroundColor;
_displayType = CollectionAttribute.DisplayType.Header;
NotNullItems = false;

// Try get CollectionAttribute for collection editor meta
var attributes = Values.GetAttributes();
Type overrideEditorType = null;
float spacing = 10.0f;
float spacing = 1.0f;
var collection = (CollectionAttribute)attributes?.FirstOrDefault(x => x is CollectionAttribute);
if (collection != null)
{
Expand All @@ -140,6 +228,7 @@ public override void Initialize(LayoutElementsContainer layout)
_background = collection.BackgroundColor.Value;
overrideEditorType = TypeUtils.GetType(collection.OverrideEditorTypeName).Type;
spacing = collection.Spacing;
_displayType = collection.Display;
}

var dragArea = layout.CustomContainer<DragAreaControl>();
Expand Down Expand Up @@ -172,76 +261,77 @@ public override void Initialize(LayoutElementsContainer layout)
}

// Size
if (_readOnly || (NotNullItems && size == 0))
{
dragArea.Label("Size", size.ToString());
}
else
if (layout.ContainerControl is DropPanel dropPanel)
{
var sizeProperty = dragArea.AddPropertyItem("Size");
_sizeLabel = sizeProperty.Labels.Last();
_size = sizeProperty.IntegerValue();
_size.IntValue.MinValue = 0;
_size.IntValue.MaxValue = ushort.MaxValue;
_size.IntValue.Value = size;
_size.IntValue.EditEnd += OnSizeChanged;
var height = dropPanel.HeaderHeight - dropPanel.HeaderTextMargin.Height;
var y = -dropPanel.HeaderHeight + dropPanel.HeaderTextMargin.Top;
_sizeBox = new IntValueBox(size)
{
MinValue = 0,
MaxValue = ushort.MaxValue,
AnchorPreset = AnchorPresets.TopRight,
Bounds = new Rectangle(-40 - dropPanel.ItemsMargin.Right, y, 40, height),
Parent = dropPanel,
};

var label = new Label
{
Text = "Size",
AnchorPreset = AnchorPresets.TopRight,
Bounds = new Rectangle(-_sizeBox.Width - 40 - dropPanel.ItemsMargin.Right - 2, y, 40, height),
Parent = dropPanel
};

if (_readOnly || (NotNullItems && size == 0))
{
_sizeBox.IsReadOnly = true;
_sizeBox.Enabled = false;
}
else
{
_sizeBox.EditEnd += OnSizeChanged;
}
}

// Elements
if (size > 0)
{
var panel = dragArea.VerticalPanel();
panel.Panel.Offsets = new Margin(7, 7, 0, 0);
panel.Panel.BackgroundColor = _background;
var elementType = ElementType;

// Use separate layout cells for each collection items to improve layout updates for them in separation
var useSharedLayout = elementType.IsPrimitive || elementType.IsEnum;

if (_canReorderItems)
bool single = elementType.IsPrimitive ||
elementType.Equals(new ScriptType(typeof(string))) ||
elementType.IsEnum ||
(elementType.GetFields().Length == 1 && elementType.GetProperties().Length == 0) ||
(elementType.GetProperties().Length == 1 && elementType.GetFields().Length == 0) ||
elementType.Equals(new ScriptType(typeof(JsonAsset))) ||
elementType.Equals(new ScriptType(typeof(SettingsBase)));

for (int i = 0; i < size; i++)
{
for (int i = 0; i < size; i++)
{
if (i != 0 && spacing > 0f)
{
if (panel.Children.Count > 0 && panel.Children[panel.Children.Count - 1] is PropertiesListElement propertiesListElement)
{
if (propertiesListElement.Labels.Count > 0)
{
var label = propertiesListElement.Labels[propertiesListElement.Labels.Count - 1];
var margin = label.Margin;
margin.Bottom += spacing;
label.Margin = margin;
}
propertiesListElement.Space(spacing);
}
else
{
panel.Space(spacing);
}
}
// Apply spacing
if (i > 0 && i < size && spacing > 0 && !single)
panel.Space(spacing);

var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;
var property = panel.AddPropertyItem(new CollectionItemLabel(this, i));
var itemLayout = useSharedLayout ? (LayoutElementsContainer)property : property.VerticalPanel();
itemLayout.Object(new ListValueContainer(elementType, i, Values, attributes), overrideEditor);
var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;
if (_displayType == CollectionAttribute.DisplayType.Inline || (collection == null && single) || (_displayType == CollectionAttribute.DisplayType.Default && single))
{
PropertyNameLabel itemLabel;
if (_canReorderItems)
itemLabel = new CollectionItemLabel(this, i);
else
itemLabel = new PropertyNameLabel("Element " + i);
var property = panel.AddPropertyItem(itemLabel);
var itemLayout = (LayoutElementsContainer)property;
itemLabel.LinkedEditor = itemLayout.Object(new ListValueContainer(elementType, i, Values, attributes), overrideEditor);
}
}
else
{
for (int i = 0; i < size; i++)
else if (_displayType == CollectionAttribute.DisplayType.Header || (_displayType == CollectionAttribute.DisplayType.Default && !single))
{
if (i != 0 && spacing > 0f)
{
if (panel.Children.Count > 0 && panel.Children[panel.Children.Count - 1] is PropertiesListElement propertiesListElement)
propertiesListElement.Space(spacing);
else
panel.Space(spacing);
}

var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;
var property = panel.AddPropertyItem("Element " + i);
var itemLayout = useSharedLayout ? (LayoutElementsContainer)property : property.VerticalPanel();
itemLayout.Object(new ListValueContainer(elementType, i, Values, attributes), overrideEditor);
var cdp = panel.CustomContainer<CollectionDropPanel>();
cdp.CustomControl.Setup(this, i, _canReorderItems);
var itemLayout = cdp.VerticalPanel();
cdp.CustomControl.LinkedEditor = itemLayout.Object(new ListValueContainer(elementType, i, Values, attributes), overrideEditor);
}
}
}
Expand Down Expand Up @@ -283,8 +373,7 @@ public override void Initialize(LayoutElementsContainer layout)
/// <inheritdoc />
protected override void Deinitialize()
{
_size = null;
_sizeLabel = null;
_sizeBox = null;

base.Deinitialize();
}
Expand All @@ -311,7 +400,8 @@ private void OnSizeChanged()
{
if (IsSetBlocked)
return;
Resize(_size.IntValue.Value);

Resize(_sizeBox.Value);
}

/// <summary>
Expand Down Expand Up @@ -384,14 +474,14 @@ public override void Refresh()
return;

// Update reference/default value indicator
if (_sizeLabel != null)
if (_sizeBox != null)
{
var color = Color.Transparent;
if (Values.HasReferenceValue && Values.ReferenceValue is IList referenceValue && referenceValue.Count != Count)
color = FlaxEngine.GUI.Style.Current.BackgroundSelected;
else if (Values.HasDefaultValue && Values.DefaultValue is IList defaultValue && defaultValue.Count != Count)
color = Color.Yellow * 0.8f;
_sizeLabel.HighlightStripColor = color;
_sizeBox.BorderColor = color;
}

// Check if collection has been resized (by UI or from external source)
Expand Down