using UnityEngine;
|
|
namespace Flexalon
|
{
|
/// <summary>
|
/// Base class for all layout componets. See [custom layout](/docs/customLayout) for details
|
/// on how to extend this class. Assigns the Layout method to FlexalonNode and keeps the
|
/// node's children up to date.
|
/// </summary>
|
[DisallowMultipleComponent, RequireComponent(typeof(FlexalonObject))]
|
public abstract class LayoutBase : FlexalonComponent, Layout
|
{
|
/// <inheritdoc />
|
protected override void DoOnEnable()
|
{
|
_node.DetachAllChildren();
|
for (int i = 0; i < transform.childCount; i++)
|
{
|
_node.AddChild(Flexalon.GetOrCreateNode(transform.GetChild(i).gameObject));
|
}
|
|
Flexalon.GetOrCreate().PreUpdate += DetectChanges;
|
_node.SetMethod(this);
|
}
|
|
/// <inheritdoc />
|
protected override void DoOnDisable()
|
{
|
_node.SetMethod(null);
|
var flexalon = Flexalon.Get();
|
if (flexalon)
|
{
|
flexalon.PreUpdate -= DetectChanges;
|
}
|
}
|
|
/// <inheritdoc />
|
protected override void ResetProperties()
|
{
|
_node.DetachAllChildren();
|
}
|
|
// This function is complicated because it's working around two issues.
|
// First, OnTransformChildrenChanged doesn't always run on 2019.4 due to a bug.
|
// See https://issuetracker.unity3d.com/issues/ontransformchildrenchanged-doesnt-get-called-in-the-edit-mode-when-dragging-a-prefab-from-the-project-window-to-the-hierarchy
|
// Second, we need to deal with undo/redo. The strategy here is to do nothing on undo/redo except fix
|
// the node.Children list, since it isn't serialzed. To detect undo/redo, we check if the Parent or SiblingIndex
|
// values change in the serialized FlexalonResult matches the transform children.
|
private void DetectChanges()
|
{
|
// Check if any old children changed parents. They need to be marked dirty
|
// since their size may change after leaving the layout.
|
for (int i = 0; i < _node.Children.Count; i++)
|
{
|
var childNode = _node.Children[i];
|
if (!childNode.GameObject)
|
{
|
Flexalon.RecordFrameChanges = true;
|
childNode.Detach();
|
MarkDirty();
|
}
|
else if (childNode.GameObject.transform.parent != transform || childNode.IsDragging || childNode.SkipLayout || childNode.Constraint != null)
|
{
|
i--;
|
childNode.Detach();
|
if (childNode.Result.Parent == transform)
|
{
|
#if UNITY_EDITOR
|
UnityEditor.Undo.RecordObject(childNode.Result, "Parent change");
|
UnityEditor.PrefabUtility.RecordPrefabInstancePropertyModifications(childNode.Result);
|
Flexalon.RecordFrameChanges = true;
|
#endif
|
childNode.Result.Parent = null;
|
childNode.Result.SiblingIndex = 0;
|
childNode.MarkDirty();
|
MarkDirty();
|
}
|
}
|
}
|
|
// Check if we have any new or out of order children.
|
int index = 0;
|
for (int i = 0; i < transform.childCount; i++)
|
{
|
var child = transform.GetChild(i);
|
var childNode = Flexalon.GetOrCreateNode(child.gameObject);
|
if (childNode.IsDragging || childNode.SkipLayout || childNode.Constraint != null)
|
{
|
continue;
|
}
|
|
_node.InsertChild(childNode, index);
|
if (childNode.Result.Parent != transform || childNode.Result.SiblingIndex != index)
|
{
|
#if UNITY_EDITOR
|
UnityEditor.Undo.RecordObject(childNode.Result, "Parent change");
|
UnityEditor.PrefabUtility.RecordPrefabInstancePropertyModifications(childNode.Result);
|
Flexalon.RecordFrameChanges = true;
|
#endif
|
childNode.Result.Parent = transform;
|
childNode.Result.SiblingIndex = index;
|
|
childNode.MarkDirty();
|
MarkDirty();
|
}
|
|
index++;
|
}
|
}
|
|
protected override void Initialize()
|
{
|
base.Initialize();
|
|
if (!gameObject.TryGetComponent<FlexalonObject>(out var obj))
|
{
|
obj = Flexalon.AddComponent<FlexalonObject>(gameObject);
|
}
|
|
if (!Flexalon.IsRootCanvas(gameObject))
|
{
|
if (obj.WidthType == SizeType.Component)
|
{
|
obj.WidthType = SizeType.Layout;
|
}
|
|
if (obj.HeightType == SizeType.Component)
|
{
|
obj.HeightType = SizeType.Layout;
|
}
|
|
if (obj.DepthType == SizeType.Component)
|
{
|
obj.DepthType = SizeType.Layout;
|
}
|
}
|
}
|
|
/// <inheritdoc />
|
public virtual Bounds Measure(FlexalonNode node, Vector3 size, Vector3 min, Vector3 max)
|
{
|
throw new System.NotImplementedException();
|
}
|
|
/// <summary> Helper to assign the fill and shrink size for all children. </summary>
|
protected void SetChildrenFillShrinkSize(FlexalonNode node, Vector3 childSize, Vector3 layoutSize)
|
{
|
foreach (var child in node.Children)
|
{
|
child.SetShrinkFillSize(childSize, layoutSize);
|
}
|
}
|
|
/// <inheritdoc />
|
public virtual void Arrange(FlexalonNode node, Vector3 layoutSize) {}
|
}
|
}
|