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