From d2ab30e7a69bfe7efda63ae75812207377917bd3 Mon Sep 17 00:00:00 2001 From: miepzerino <o.skotnik@gmail.com> Date: Sun, 30 Mar 2025 18:50:27 +0000 Subject: [PATCH] Merge branch 'Flexalon-UI-Layouts' into develop --- Assets/Flexalon/Runtime/Core/FlexalonLayoutBase.cs | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 157 insertions(+), 0 deletions(-) diff --git a/Assets/Flexalon/Runtime/Core/FlexalonLayoutBase.cs b/Assets/Flexalon/Runtime/Core/FlexalonLayoutBase.cs new file mode 100644 index 0000000..ef0a63f --- /dev/null +++ b/Assets/Flexalon/Runtime/Core/FlexalonLayoutBase.cs @@ -0,0 +1,157 @@ +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) {} + } +} \ No newline at end of file -- Gitblit v1.9.3