[NUI] Bind Constraint with custom function
authorEunki, Hong <eunkiki.hong@samsung.com>
Wed, 26 Mar 2025 04:07:36 +0000 (13:07 +0900)
committerSangHyeon Jade Lee <dltkdgus1764@gmail.com>
Thu, 17 Apr 2025 07:55:55 +0000 (16:55 +0900)
Let we bind custom constraints generate API.

Relative dali patch :

https://review.tizen.org/gerrit/c/platform/core/uifw/dali-toolkit/+/322672 (To make CornerRadius as constraint input)
https://review.tizen.org/gerrit/c/platform/core/uifw/dali-csharp-binder/+/322068

Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
13 files changed:
src/Tizen.NUI/src/internal/Animation/Constraint.cs
src/Tizen.NUI/src/internal/Animation/ConstraintApplyActionType.cs [new file with mode: 0755]
src/Tizen.NUI/src/internal/Animation/ConstraintFunction.cs [new file with mode: 0755]
src/Tizen.NUI/src/internal/Animation/ConstraintTagRanges.cs [new file with mode: 0755]
src/Tizen.NUI/src/internal/Animation/EqualConstraintWithParentFloat.cs
src/Tizen.NUI/src/internal/Animation/PropertyInputContainer.cs [new file with mode: 0755]
src/Tizen.NUI/src/internal/Animation/RelativeConstraintWithParentFloat.cs
src/Tizen.NUI/src/internal/Interop/Interop.Constraint.cs
src/Tizen.NUI/src/internal/Interop/Interop.ConstraintFunction.cs [new file with mode: 0755]
src/Tizen.NUI/src/internal/Interop/Interop.Handle.cs
src/Tizen.NUI/src/internal/Interop/Interop.PropertyInputContainer.cs [new file with mode: 0755]
src/Tizen.NUI/src/public/Animation/Animatable.cs
test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/ConstraintWithCustomShaderTest.cs [new file with mode: 0644]

index d6bc437211f1a3f99a51d50e344202bad6b7f067..4ffd6b65d529b86f851281a9423680f2c0cc30d5 100755 (executable)
  *
  */
 
-using System.ComponentModel;
+using global::System;
+using global::System.ComponentModel;
+using global::System.Runtime.InteropServices;
 namespace Tizen.NUI
 {
-    using global::System;
-    using global::System.Runtime.InteropServices;
-
     /// <summary>
     /// An abstract base class for Constraints.
+    /// Callback invoked every frame after Apply(), and stop to Remove().
     /// This class only use for inhouse currently.
-    /// 
+    /// </summary>
+    /// <remarks>
     /// This can be used to constrain a property of an object, after animations have been applied.
     /// Constraints are applied in the following order:
     ///  - Constraints are applied to on-stage views in a depth-first traversal.
     ///  - For each view, the constraints are applied in the same order as the calls to Apply().
-    ///  - Constraints are not applied to off-stage views.
-    /// 
+    ///
+    /// Use GenerateConstraint() to create new constraints.
+    /// We need three parameter to create constraints : Animatable, Property (string or int), and callback.
+    ///
+    /// Property type and callback type not matched. For example,
+    /// "SizeWidth" only allow to use Constraint.ConstraintFloatFunctionCallbackType.
+    /// "Position" only allow to use Constraint.ConstraintVector3FunctionCallbackType.
+    ///
+    /// Vector4 type property is special. We can use both ConstraintVector4FunctionCallbackType and ConstraintColorFunctionCallbackType.
+    /// "Color" allow to use Constraint.ConstraintVector4FunctionCallbackType and ConstraintColorFunctionCallbackType.
+    ///
+    /// You can register constraint callback at generate time, and cannot unregister or remove.
+    ///
+    /// AddSource used for get input inside of constraint callback.
+    /// AddLocalSource is special API s.t. will use target's property.
+    /// In the callback, you can get additional values ordered by AddSource API.
+    ///
+    /// Constraints are not applied to off-stage views.
+    /// Constraints be invalidate if the target object, or any of source input objects be disposed.
+    ///
     /// Create a constraint using one of the New method depending on the type of callback functions used.
-    /// 
+    ///
+    /// Note : Callback could be called even after target object or Constraint itself disposed.
     /// Note : This function will called every frame. Maybe reduce performance if you applyed too many constraints.
-    /// 
-    /// TODO : AddSource(ConstraintSource); API need to be implemented.
-    ///   To implement this, we have to bind ConstraintSource.
-    /// TODO : Currently We don't support custom functions.
-    ///   To implement this, we have to bind PropertyInputContainer
-    /// </summary>
+    /// </remarks>
+    /// <example><code>
+    /// Constraint constraint = Constraint.GenerateConstraint(view, "SizeWidth", new Constraint.ConstraintFloatFunctionCallbackType(YourCallback));
+    /// constraint.AddSource(otherView, "SizeWidth");
+    /// constraint.AddLocalSource("Position");
+    /// constraint.ApplyAction = ConstraintApplyActionType.Discard;
+    /// constraint.Apply();
+    ///
+    /// SetExtraDataById(constraint.ID, 0.0f); // You can use ID value.
+    ///
+    /// float YourCallback(float current, uint id, in PropertyInputContainer inputContainer)
+    /// {
+    ///     float input0 = inputContainer.GetFloat(0u);       // Match with AddSource or AddLocalSource order.
+    ///     UIVector3 input1 = inputContainer.GetVector3(1u); // Match with AddSource or AddLocalSource order.
+    ///
+    ///     // Get extra data by id if you need.
+    ///     float extraValue = GetExtraDataById(id);
+    ///
+    ///     // Implement custom logic.
+    ///     float finalValue = current + input0 * 0.1f + input1.X * 0.3f + extraValue;
+    ///
+    ///     return finalValue;
+    /// }
+    /// </code></example>
     internal class Constraint : BaseHandle
     {
-        internal Constraint(IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
+        public delegate bool ConstraintBooleanFunctionCallbackType(bool current, uint id, in PropertyInputContainer inputContainer);
+        public delegate float ConstraintFloatFunctionCallbackType(float current, uint id, in PropertyInputContainer inputContainer);
+        public delegate int ConstraintIntegerFunctionCallbackType(int current, uint id, in PropertyInputContainer inputContainer);
+        public delegate UIVector2 ConstraintVector2FunctionCallbackType(UIVector2 current, uint id, in PropertyInputContainer inputContainer);
+        public delegate UIVector3 ConstraintVector3FunctionCallbackType(UIVector3 current, uint id, in PropertyInputContainer inputContainer);
+        public delegate UIColor ConstraintColorFunctionCallbackType(UIColor current, uint id, in PropertyInputContainer inputContainer);
+        public delegate Vector4 ConstraintVector4FunctionCallbackType(in Vector4 current, uint id, in PropertyInputContainer inputContainer);
+        public delegate Matrix3 ConstraintMatrix3FunctionCallbackType(in Matrix3 current, uint id, in PropertyInputContainer inputContainer);
+        public delegate Matrix ConstraintMatrixFunctionCallbackType(in Matrix current, uint id, in PropertyInputContainer inputContainer);
+        public delegate Rotation ConstraintRotationFunctionCallbackType(in Rotation current, uint id, in PropertyInputContainer inputContainer);
+
+        /// <summary>
+        /// Static custructor.
+        /// </summary>
+        /// <exception cref="ArgumentNullException"> Thrown when the target or callback is null. </exception>
+        /// <exception cref="ArgumentException"> Thrown when the property is not animatable. </exception>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static Constraint GenerateConstraint(Animatable target, int propertyIndex, System.Delegate callback)
         {
+            if (target == null)
+            {
+                throw new ArgumentNullException(nameof(target));
+            }
+            if (callback == null)
+            {
+                throw new ArgumentNullException(nameof(callback));
+            }
+            if (propertyIndex == Property.InvalidIndex)
+            {
+                throw new ArgumentException(nameof(propertyIndex));
+            }
+            if (!target.IsPropertyAnimatable(propertyIndex))
+            {
+                throw new ArgumentException("PropertyIndex is not animatable! index : " + propertyIndex);
+            }
+
+            PropertyType type = target.GetPropertyType(propertyIndex);
+
+            ConstraintFunctionBase function;
+            IntPtr cPtr;
+            switch (type)
+            {
+                case PropertyType.Boolean:
+                {
+                    if (!(callback is ConstraintBooleanFunctionCallbackType))
+                    {
+                        throw new ArgumentException("Callback is not ConstraintBooleanFunctionCallbackType!");
+                    }
+                    function = new ConstraintBooleanFunction(callback as ConstraintBooleanFunctionCallbackType);
+                    cPtr = Interop.Constraint.ConstraintBooleanNew(Animatable.getCPtr(target), propertyIndex, ConstraintFunctionBase.getCPtr(function));
+                    break;
+                }
+                case PropertyType.Float:
+                {
+                    if (!(callback is ConstraintFloatFunctionCallbackType))
+                    {
+                        throw new ArgumentException("Callback is not ConstraintFloatFunctionCallbackType!");
+                    }
+                    function = new ConstraintFloatFunction(callback as ConstraintFloatFunctionCallbackType);
+                    cPtr = Interop.Constraint.ConstraintFloatNew(Animatable.getCPtr(target), propertyIndex, ConstraintFunctionBase.getCPtr(function));
+                    break;
+                }
+                case PropertyType.Integer:
+                {
+                    if (!(callback is ConstraintIntegerFunctionCallbackType))
+                    {
+                        throw new ArgumentException("Callback is not ConstraintIntegerFunctionCallbackType!");
+                    }
+                    function = new ConstraintIntegerFunction(callback as ConstraintIntegerFunctionCallbackType);
+                    cPtr = Interop.Constraint.ConstraintIntegerNew(Animatable.getCPtr(target), propertyIndex, ConstraintFunctionBase.getCPtr(function));
+                    break;
+                }
+                case PropertyType.Vector2:
+                {
+                    if (!(callback is ConstraintVector2FunctionCallbackType))
+                    {
+                        throw new ArgumentException("Callback is not ConstraintVector2FunctionCallbackType!");
+                    }
+                    function = new ConstraintVector2Function(callback as ConstraintVector2FunctionCallbackType);
+                    cPtr = Interop.Constraint.ConstraintVector2New(Animatable.getCPtr(target), propertyIndex, ConstraintFunctionBase.getCPtr(function));
+                    break;
+                }
+                case PropertyType.Vector3:
+                {
+                    if (!(callback is ConstraintVector3FunctionCallbackType))
+                    {
+                        throw new ArgumentException("Callback is not ConstraintVector3FunctionCallbackType!");
+                    }
+                    function = new ConstraintVector3Function(callback as ConstraintVector3FunctionCallbackType);
+                    cPtr = Interop.Constraint.ConstraintVector3New(Animatable.getCPtr(target), propertyIndex, ConstraintFunctionBase.getCPtr(function));
+                    break;
+                }
+                case PropertyType.Vector4:
+                {
+                    if (!(callback is ConstraintVector4FunctionCallbackType || callback is ConstraintColorFunctionCallbackType))
+                    {
+                        throw new ArgumentException("Callback is not ConstraintVector4FunctionCallbackType or ConstraintColorFunctionCallbackType");
+                    }
+                    if (callback is ConstraintVector4FunctionCallbackType)
+                    {
+                        function = new ConstraintVector4Function(callback as ConstraintVector4FunctionCallbackType);
+                    }
+                    else
+                    {
+                        function = new ConstraintColorFunction(callback as ConstraintColorFunctionCallbackType);
+                    }
+                    cPtr = Interop.Constraint.ConstraintVector4New(Animatable.getCPtr(target), propertyIndex, ConstraintFunctionBase.getCPtr(function));
+                    break;
+                }
+                case PropertyType.Matrix3:
+                {
+                    if (!(callback is ConstraintMatrix3FunctionCallbackType))
+                    {
+                        throw new ArgumentException("Callback is not ConstraintMatrix3FunctionCallbackType!");
+                    }
+                    function = new ConstraintMatrix3Function(callback as ConstraintMatrix3FunctionCallbackType);
+                    cPtr = Interop.Constraint.ConstraintMatrix3New(Animatable.getCPtr(target), propertyIndex, ConstraintFunctionBase.getCPtr(function));
+                    break;
+                }
+                case PropertyType.Matrix:
+                {
+                    if (!(callback is ConstraintMatrixFunctionCallbackType))
+                    {
+                        throw new ArgumentException("Callback is not ConstraintMatrixFunctionCallbackType!");
+                    }
+                    function = new ConstraintMatrixFunction(callback as ConstraintMatrixFunctionCallbackType);
+                    cPtr = Interop.Constraint.ConstraintMatrixNew(Animatable.getCPtr(target), propertyIndex, ConstraintFunctionBase.getCPtr(function));
+                    break;
+                }
+                case PropertyType.Rotation:
+                {
+                    if (!(callback is ConstraintRotationFunctionCallbackType))
+                    {
+                        throw new ArgumentException("Callback is not ConstraintRotationFunctionCallbackType!");
+                    }
+                    function = new ConstraintRotationFunction(callback as ConstraintRotationFunctionCallbackType);
+                    cPtr = Interop.Constraint.ConstraintRotationNew(Animatable.getCPtr(target), propertyIndex, ConstraintFunctionBase.getCPtr(function));
+                    break;
+                }
+                default:
+                {
+                    throw new ArgumentException("PropertyIndex is not animatable type! index : " + propertyIndex + " type : " + type);
+                }
+            }
+            NDalicPINVOKE.ThrowExceptionIfExists();
+            Constraint ret = new Constraint(target, propertyIndex, function, cPtr);
+            return ret;
         }
 
         /// <summary>
-        /// Apply current constraint.
-        /// Constraint will work until Remove called.
+        /// Static custructor.
         /// </summary>
-        internal void Apply()
+        /// <exception cref="ArgumentNullException"> Thrown when the target or callback is null. </exception>
+        /// <exception cref="ArgumentException"> Thrown when the property is not animatable. </exception>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static Constraint GenerateConstraint(Animatable target, string propertyName, System.Delegate callback)
         {
-            Interop.Constraint.Apply(SwigCPtr);
+            if (target == null)
+            {
+                throw new ArgumentNullException(nameof(target));
+            }
+            if (callback == null)
+            {
+                throw new ArgumentNullException(nameof(callback));
+            }
+
+            int propertyIndex = target.GetPropertyIndex(propertyName);
+            if (propertyIndex == Property.InvalidIndex)
+            {
+                throw new ArgumentException("Invalid property! input name : " + propertyName);
+            }
+
+            return GenerateConstraint(target, propertyIndex, callback);
+        }
+
+        private ConstraintFunctionBase Function { get; init; }
+        private WeakReference<Animatable> internalTarget { get; init; }
+
+        internal Constraint(Animatable target, int propertyIndex, ConstraintFunctionBase function, IntPtr cPtr) : this(cPtr, true)
+        {
+            internalTarget = new WeakReference<Animatable>(target);
+            PropertyIndex = propertyIndex;
+            Function = function;
+        }
+
+        internal Constraint(IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
+        {
+        }
+
+        internal Constraint(IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
+        {
+        }
+
+        /// <summary>
+        /// Gets the target of constarint
+        /// Read-only
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Animatable Target
+        {
+            get
+            {
+                if (internalTarget.TryGetTarget(out Animatable ret) && (ret != null) && !ret.IsDisposedOrQueued)
+                {
+                    return ret;
+                }
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// Gets the property index of constarint
+        /// Read-only
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int PropertyIndex { get; init; }
+
+        /// <summary>
+        /// Gets the constraint's ID.
+        /// Read-only
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public uint ID
+        {
+            get => (Function?.Id ?? 0u);
+        }
+
+        /// <summary>
+        /// Remove action.
+        /// Determine the target values action after apply current constriant.
+        /// Default is ConstraintApplyActionType.Bake
+        /// </summary>
+        /// <remarks>
+        /// If ApplyAction is ConstraintApplyActionType.Bake, next frame's current value comes as previous returned value.
+        /// For example, if current value was 1.0f and callback return 2.0f, next frame's current value is 2.0f.
+        ///
+        /// If ApplyAction is ConstraintApplyActionType.Discard, next frame's current value comes as base value.
+        /// For example, if current value was 1.0f and callback return 2.0f, next frame's current value is 1.0f.
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public ConstraintApplyActionType ApplyAction
+        {
+            set => Interop.Constraint.SetApplyAction(SwigCPtr, (int)value);
+            get => (ConstraintApplyActionType) Interop.Constraint.GetApplyAction(SwigCPtr);
+        }
+
+        /// <summary>
+        /// Tag number. It will be useful when you want to seperate constraints.
+        /// We can only use [ConstraintTagRanges.TagMin ConstraintTagRanges.TagMax] and ConstraintTagRanges.Default.
+        /// </summary>
+        /// <exception cref="ArgumentException"> Thrown when the tag value out of ranges. </exception>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public uint Tag
+        {
+            set
+            {
+                if (value > ConstraintTagRanges.TagMax)
+                {
+                    throw new ArgumentException($"The given tag '{value}' is bigger than maximum tag {ConstraintTagRanges.TagMax}");
+                }
+                Interop.Constraint.SetTag(SwigCPtr, value);
+                NDalicPINVOKE.ThrowExceptionIfExists();
+            }
+            get => Interop.Constraint.GetTag(SwigCPtr);
+        }
+
+        /// <summary>
+        /// Add source input.
+        /// </summary>
+        /// <exception cref="ArgumentNullException"> Thrown when the source is null. </exception>
+        /// <exception cref="ArgumentException"> Thrown when the property index is invalid. </exception>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void AddSource(Animatable source, int propertyIndex)
+        {
+            if (source == null)
+            {
+                throw new ArgumentNullException(nameof(source));
+            }
+            if (!source.IsPropertyAConstraintInput(propertyIndex))
+            {
+                throw new ArgumentException("PropertyIndex is not a valid constraint input! index : " + propertyIndex);
+            }
+
+            Interop.Constraint.AddSource(SwigCPtr, Animatable.getCPtr(source), propertyIndex);
             NDalicPINVOKE.ThrowExceptionIfExists();
         }
 
         /// <summary>
-        /// Remove current constraint.
+        /// Add source input.
+        /// </summary>
+        /// <exception cref="ArgumentNullException"> Thrown when the source is null. </exception>
+        /// <exception cref="ArgumentException"> Thrown when the property name is invalid. </exception>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void AddSource(Animatable source, string propertyName)
+        {
+            if (source == null)
+            {
+                throw new ArgumentNullException(nameof(source));
+            }
+
+            AddSource(source, source.GetPropertyIndex(propertyName));
+        }
+
+        /// <summary>
+        /// Add local source input.
         /// </summary>
-        internal void Remove()
+        /// <exception cref="ArgumentException"> Thrown when the property index is invalid. </exception>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void AddLocalSource(int propertyIndex)
         {
-            Interop.Constraint.Remove(SwigCPtr);
+            var target = Target;
+            if (target == null)
+            {
+                Tizen.Log.Error("NUI", $"Constraint {ID} lost target! Skip AddLocalSource\n");
+                return;
+            }
+
+            if (!target.IsPropertyAConstraintInput(propertyIndex))
+            {
+                throw new ArgumentException("PropertyIndex is not a valid constraint input! index : " + propertyIndex);
+            }
+            Interop.Constraint.AddLocalSource(SwigCPtr, propertyIndex);
             NDalicPINVOKE.ThrowExceptionIfExists();
         }
 
         /// <summary>
-        /// Remove action. Determine the target values action after remove current constriant.
-        /// Default is RemoveActionType.Bake
+        /// Add local source input.
         /// </summary>
-        internal RemoveActionType RemoveAction
+        /// <exception cref="ArgumentException"> Thrown when the property name is invalid. </exception>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void AddLocalSource(string propertyName)
         {
-            set => Interop.Constraint.SetRemoveAction(SwigCPtr, (int)value);
-            get => (RemoveActionType) Interop.Constraint.GetRemoveAction(SwigCPtr);
+            var target = Target;
+            if (target == null)
+            {
+                Tizen.Log.Error("NUI", $"Constraint {ID} lost target! Skip AddLocalSource\n");
+                return;
+            }
+
+            AddLocalSource(target.GetPropertyIndex(propertyName));
         }
 
         /// <summary>
-        /// Tag number. It will be useful when you want to seperate constraints
+        /// Apply current constraint.
+        /// Constraint will work until Remove called.
         /// </summary>
-        internal uint Tag
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Apply()
         {
-            set => Interop.Constraint.SetTag(SwigCPtr, value);
-            get => Interop.Constraint.GetTag(SwigCPtr);
+            Interop.Constraint.Apply(SwigCPtr);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        /// <summary>
+        /// Apply current constraint after transform update finished.
+        /// Constraint will work until Remove called.
+        /// </summary>
+        /// <remarks>
+        /// Transform relative properties (e.g. Size, Position, Orientation) will not be changed this frame.
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void ApplyPost()
+        {
+            Interop.Constraint.ApplyPost(SwigCPtr);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        /// <summary>
+        /// Remove current constraint.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Remove()
+        {
+            Interop.Constraint.Remove(SwigCPtr);
+            NDalicPINVOKE.ThrowExceptionIfExists();
         }
 
         /// <summary>
         /// Get constrainted target object
         /// </summary>
-        internal BaseHandle GetTargetObject()
+        internal Animatable GetTargetObject()
         {
-            BaseHandle handle = new BaseHandle(Interop.Constraint.GetTargetObject(SwigCPtr), true);
+            IntPtr cPtr = Interop.Constraint.GetTargetObject(SwigCPtr);
+            Animatable ret = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Animatable;
+            if (ret != null)
+            {
+                Interop.BaseHandle.DeleteBaseHandle(new global::System.Runtime.InteropServices.HandleRef(this, cPtr));
+            }
+            else
+            {
+                ret = new Animatable(cPtr, true);
+            }
             NDalicPINVOKE.ThrowExceptionIfExists();
-            return handle;
+            return ret;
         }
+
         /// <summary>
         /// Get constrainted target property index
         /// </summary>
@@ -103,6 +486,31 @@ namespace Tizen.NUI
             return index;
         }
 
+        /// <summary>
+        /// Add parent source input. Only availiable for BaseComponents.View.
+        /// </summary>
+        /// <remarks>
+        /// We cannot throw exception even if propertyIndex is valid or not. Please use this API carefully
+        /// </remarks>
+        /// <exception cref="InvalidOperationException"> Thrown when the target is not a BaseComponents.View. </exception>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        internal void AddParentSource(int propertyIndex)
+        {
+            var target = Target;
+            if (target == null)
+            {
+                Tizen.Log.Error("NUI", $"Constraint {ID} lost target! Skip AddParentSource\n");
+                return;
+            }
+
+            if (!(target is BaseComponents.View))
+            {
+                throw new InvalidOperationException($"Error! Target is not a View! type:{target.GetType()}");
+            }
+            Interop.Constraint.AddParentSource(SwigCPtr, propertyIndex);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
         /// <summary>
         /// Dispose
         /// </summary>
@@ -120,6 +528,7 @@ namespace Tizen.NUI
                 //Release your own managed resources here.
                 //You should release all of your own disposable objects here.
                 Remove();
+                Function?.Dispose();
             }
             base.Dispose(type);
         }
@@ -131,23 +540,5 @@ namespace Tizen.NUI
             Interop.Constraint.DeleteConstraint(swigCPtr);
             NDalicPINVOKE.ThrowExceptionIfExists();
         }
-
-        /// <summary>
-        /// Determinate how objects property will be when constraint removed.
-        /// Default is Bake.
-        /// </summary>
-        internal enum RemoveActionType
-        {
-            /// <summary>
-            /// Target objects property will bake when constraint removed.
-            /// </summary>
-            [EditorBrowsable(EditorBrowsableState.Never)]
-            Bake,
-            /// <summary>
-            /// Target objects property will be original value when constraint removed.
-            /// </summary>
-            [EditorBrowsable(EditorBrowsableState.Never)]
-            Discard,
-        }
     }
 }
diff --git a/src/Tizen.NUI/src/internal/Animation/ConstraintApplyActionType.cs b/src/Tizen.NUI/src/internal/Animation/ConstraintApplyActionType.cs
new file mode 100755 (executable)
index 0000000..7f9e9f4
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright(c) 2025 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using global::System;
+using global::System.ComponentModel;
+using global::System.Runtime.InteropServices;
+namespace Tizen.NUI
+{
+    /// <summary>
+    /// Determinate how objects property will be when constraint apply.
+    /// Default is Bake.
+    /// </summary>
+    internal enum ConstraintApplyActionType
+    {
+        /// <summary>
+        /// Target objects property will bake when constraint applied.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Bake,
+
+        /// <summary>
+        /// Target objects property will be original value when constraint applied.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Discard,
+    }
+}
diff --git a/src/Tizen.NUI/src/internal/Animation/ConstraintFunction.cs b/src/Tizen.NUI/src/internal/Animation/ConstraintFunction.cs
new file mode 100755 (executable)
index 0000000..7228856
--- /dev/null
@@ -0,0 +1,465 @@
+/*
+ * Copyright(c) 2025 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using global::System;
+using global::System.ComponentModel;
+using global::System.Runtime.InteropServices;
+namespace Tizen.NUI
+{
+    /// <summary>
+    /// An abstract base class for ConstraintsFunction.
+    /// Must not be open to public.
+    /// </summary>
+    internal class ConstraintFunctionBase : Disposable
+    {
+        internal ConstraintFunctionBase(IntPtr cPtr, System.Delegate callback) : this(cPtr, true)
+        {
+            Callback = callback;
+        }
+
+        internal ConstraintFunctionBase(IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
+        {
+        }
+
+        internal PropertyType Type { get; init; }
+        internal System.Delegate Callback { get; init; } // Invoke to user
+        internal System.Delegate InternalCallback { get; init; } // Comes from native
+        internal uint Id { get; init; }
+
+        /// <summary>
+        /// Dispose
+        /// </summary>
+        /// <param name="type"></param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override void Dispose(DisposeTypes type)
+        {
+            if(Disposed)
+            {
+                return;
+            }
+
+            if(type == DisposeTypes.Explicit)
+            {
+                //Called by User
+                //Release your own managed resources here.
+                //You should release all of your own disposable objects here.
+
+                RenderThreadObjectHolder.RegisterDelegate(Callback);
+                RenderThreadObjectHolder.RegisterDelegate(InternalCallback);
+            }
+            base.Dispose(type);
+        }
+
+        /// This will not be public opened.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override void ReleaseSwigCPtr(HandleRef swigCPtr)
+        {
+            switch (Type)
+            {
+                case PropertyType.Boolean:
+                {
+                    Interop.ConstraintFunction.DeleteBooleanFunction(swigCPtr);
+                    break;
+                }
+                case PropertyType.Float:
+                {
+                    Interop.ConstraintFunction.DeleteFloatFunction(swigCPtr);
+                    break;
+                }
+                case PropertyType.Integer:
+                {
+                    Interop.ConstraintFunction.DeleteIntegerFunction(swigCPtr);
+                    break;
+                }
+                case PropertyType.Vector2:
+                {
+                    Interop.ConstraintFunction.DeleteVector2Function(swigCPtr);
+                    break;
+                }
+                case PropertyType.Vector3:
+                {
+                    Interop.ConstraintFunction.DeleteVector3Function(swigCPtr);
+                    break;
+                }
+                case PropertyType.Vector4:
+                {
+                    Interop.ConstraintFunction.DeleteVector4Function(swigCPtr);
+                    break;
+                }
+                case PropertyType.Matrix3:
+                {
+                    Interop.ConstraintFunction.DeleteMatrix3Function(swigCPtr);
+                    break;
+                }
+                case PropertyType.Matrix:
+                {
+                    Interop.ConstraintFunction.DeleteMatrixFunction(swigCPtr);
+                    break;
+                }
+                case PropertyType.Rotation:
+                {
+                    Interop.ConstraintFunction.DeleteRotationFunction(swigCPtr);
+                    break;
+                }
+                default:
+                {
+                    throw new ArgumentException("Type : " + Type);
+                }
+            }
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+    }
+
+    /// <summary>
+    /// An class for ConstraintsFunction for boolean.
+    /// </summary>
+    internal class ConstraintBooleanFunction : ConstraintFunctionBase
+    {
+        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+        internal delegate void InternalCallbackType(ref bool current, uint id, IntPtr inputContainerCPtr);
+
+        public ConstraintBooleanFunction(Constraint.ConstraintBooleanFunctionCallbackType callback) : base(Interop.ConstraintFunction.BooleanFunctionNew(), callback)
+        {
+            Type = PropertyType.Boolean;
+
+            InternalCallback = (InternalCallbackType)OnCallback;
+
+            Id = Interop.ConstraintFunction.GetBooleanFunctionId(SwigCPtr);
+
+            var ip = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate<System.Delegate>(InternalCallback);
+
+            Interop.ConstraintFunction.SetBooleanFunction(SwigCPtr, new HandleRef(this, ip));
+        }
+
+        private void OnCallback(ref bool current, uint id, IntPtr inputContainerCPtr)
+        {
+            using PropertyInputContainer container = new PropertyInputContainer(inputContainerCPtr);
+            bool ret = (Callback as Constraint.ConstraintBooleanFunctionCallbackType).Invoke(current, id, in container);
+            current = ret;
+        }
+    }
+
+    /// <summary>
+    /// An class for ConstraintsFunction for float.
+    /// </summary>
+    internal class ConstraintFloatFunction : ConstraintFunctionBase
+    {
+        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+        internal delegate void InternalCallbackType(ref float current, uint id, IntPtr inputContainerCPtr);
+
+        public ConstraintFloatFunction(Constraint.ConstraintFloatFunctionCallbackType callback) : base(Interop.ConstraintFunction.FloatFunctionNew(), callback)
+        {
+            Type = PropertyType.Float;
+
+            InternalCallback = (InternalCallbackType)OnCallback;
+
+            Id = Interop.ConstraintFunction.GetFloatFunctionId(SwigCPtr);
+
+            var ip = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate<System.Delegate>(InternalCallback);
+
+            Interop.ConstraintFunction.SetFloatFunction(SwigCPtr, new HandleRef(this, ip));
+        }
+
+        private void OnCallback(ref float current, uint id, IntPtr inputContainerCPtr)
+        {
+            using PropertyInputContainer container = new PropertyInputContainer(inputContainerCPtr);
+            float ret = (Callback as Constraint.ConstraintFloatFunctionCallbackType).Invoke(current, id, in container);
+            current = ret;
+        }
+    }
+
+    /// <summary>
+    /// An class for ConstraintsFunction for int.
+    /// </summary>
+    internal class ConstraintIntegerFunction : ConstraintFunctionBase
+    {
+        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+        internal delegate void InternalCallbackType(ref int current, uint id, IntPtr inputContainerCPtr);
+
+        public ConstraintIntegerFunction(Constraint.ConstraintIntegerFunctionCallbackType callback) : base(Interop.ConstraintFunction.IntegerFunctionNew(), callback)
+        {
+            Type = PropertyType.Integer;
+
+            InternalCallback = (InternalCallbackType)OnCallback;
+
+            Id = Interop.ConstraintFunction.GetIntegerFunctionId(SwigCPtr);
+
+            var ip = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate<System.Delegate>(InternalCallback);
+
+            Interop.ConstraintFunction.SetIntegerFunction(SwigCPtr, new HandleRef(this, ip));
+        }
+
+        private void OnCallback(ref int current, uint id, IntPtr inputContainerCPtr)
+        {
+            using PropertyInputContainer container = new PropertyInputContainer(inputContainerCPtr);
+            int ret = (Callback as Constraint.ConstraintIntegerFunctionCallbackType).Invoke(current, id, in container);
+            current = ret;
+        }
+    }
+
+    /// <summary>
+    /// An class for ConstraintsFunction for Vector2.
+    /// </summary>
+    internal class ConstraintVector2Function : ConstraintFunctionBase
+    {
+        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+        internal delegate void InternalCallbackType(IntPtr current, uint id, IntPtr inputContainerCPtr);
+
+        public ConstraintVector2Function(Constraint.ConstraintVector2FunctionCallbackType callback) : base(Interop.ConstraintFunction.Vector2FunctionNew(), callback)
+        {
+            Type = PropertyType.Vector2;
+
+            InternalCallback = (InternalCallbackType)OnCallback;
+
+            Id = Interop.ConstraintFunction.GetVector2FunctionId(SwigCPtr);
+
+            var ip = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate<System.Delegate>(InternalCallback);
+
+            Interop.ConstraintFunction.SetVector2Function(SwigCPtr, new HandleRef(this, ip));
+        }
+
+        private void OnCallback(IntPtr current, uint id, IntPtr inputContainerCPtr)
+        {
+            using Vector2 tempVector2 = new Vector2(current, false);
+            using PropertyInputContainer container = new PropertyInputContainer(inputContainerCPtr);
+
+            UIVector2 realCurrent = new UIVector2(tempVector2.X, tempVector2.Y);
+            UIVector2 ret = (Callback as Constraint.ConstraintVector2FunctionCallbackType).Invoke(realCurrent, id, in container);
+
+            Interop.Vector2.XSet(Vector2.getCPtr(tempVector2), ret.X);
+            Interop.Vector2.YSet(Vector2.getCPtr(tempVector2), ret.Y);
+        }
+    }
+
+    /// <summary>
+    /// An class for ConstraintsFunction for Vector3.
+    /// </summary>
+    internal class ConstraintVector3Function : ConstraintFunctionBase
+    {
+        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+        internal delegate void InternalCallbackType(IntPtr current, uint id, IntPtr inputContainerCPtr);
+
+        public ConstraintVector3Function(Constraint.ConstraintVector3FunctionCallbackType callback) : base(Interop.ConstraintFunction.Vector3FunctionNew(), callback)
+        {
+            Type = PropertyType.Vector3;
+
+            InternalCallback = (InternalCallbackType)OnCallback;
+
+            Id = Interop.ConstraintFunction.GetVector3FunctionId(SwigCPtr);
+
+            var ip = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate<System.Delegate>(InternalCallback);
+
+            Interop.ConstraintFunction.SetVector3Function(SwigCPtr, new HandleRef(this, ip));
+        }
+
+        private void OnCallback(IntPtr current, uint id, IntPtr inputContainerCPtr)
+        {
+            using Vector3 tempVector3 = new Vector3(current, false);
+            using PropertyInputContainer container = new PropertyInputContainer(inputContainerCPtr);
+
+            UIVector3 realCurrent = new UIVector3(tempVector3.X, tempVector3.Y, tempVector3.Z);
+            UIVector3 ret = (Callback as Constraint.ConstraintVector3FunctionCallbackType).Invoke(realCurrent, id, in container);
+
+            Interop.Vector3.XSet(Vector3.getCPtr(tempVector3), ret.X);
+            Interop.Vector3.YSet(Vector3.getCPtr(tempVector3), ret.Y);
+            Interop.Vector3.ZSet(Vector3.getCPtr(tempVector3), ret.Z);
+        }
+    }
+
+    /// <summary>
+    /// An class for ConstraintsFunction for Color. (Special case of Vector4, that we can use UIColor)
+    /// </summary>
+    internal class ConstraintColorFunction : ConstraintFunctionBase
+    {
+        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+        internal delegate void InternalCallbackType(IntPtr current, uint id, IntPtr inputContainerCPtr);
+
+        public ConstraintColorFunction(Constraint.ConstraintColorFunctionCallbackType callback) : base(Interop.ConstraintFunction.Vector4FunctionNew(), callback)
+        {
+            Type = PropertyType.Vector4;
+
+            InternalCallback = (InternalCallbackType)OnCallback;
+
+            Id = Interop.ConstraintFunction.GetVector4FunctionId(SwigCPtr);
+
+            var ip = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate<System.Delegate>(InternalCallback);
+
+            Interop.ConstraintFunction.SetVector4Function(SwigCPtr, new HandleRef(this, ip));
+        }
+
+        private void OnCallback(IntPtr current, uint id, IntPtr inputContainerCPtr)
+        {
+            using Vector4 tempVector4 = new Vector4(current, false);
+            using PropertyInputContainer container = new PropertyInputContainer(inputContainerCPtr);
+
+            UIColor realCurrent = new UIColor(tempVector4.X, tempVector4.Y, tempVector4.Z, tempVector4.W);
+            UIColor ret = (Callback as Constraint.ConstraintColorFunctionCallbackType).Invoke(realCurrent, id, in container);
+
+            Interop.Vector4.XSet(Vector3.getCPtr(tempVector4), ret.R);
+            Interop.Vector4.YSet(Vector3.getCPtr(tempVector4), ret.G);
+            Interop.Vector4.ZSet(Vector3.getCPtr(tempVector4), ret.B);
+            Interop.Vector4.WSet(Vector3.getCPtr(tempVector4), ret.A);
+        }
+    }
+
+    /// <summary>
+    /// An class for ConstraintsFunction for Vector4.
+    /// </summary>
+    internal class ConstraintVector4Function : ConstraintFunctionBase
+    {
+        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+        internal delegate void InternalCallbackType(IntPtr current, uint id, IntPtr inputContainerCPtr);
+
+        public ConstraintVector4Function(Constraint.ConstraintVector4FunctionCallbackType callback) : base(Interop.ConstraintFunction.Vector4FunctionNew(), callback)
+        {
+            Type = PropertyType.Vector4;
+
+            InternalCallback = (InternalCallbackType)OnCallback;
+
+            Id = Interop.ConstraintFunction.GetVector4FunctionId(SwigCPtr);
+
+            var ip = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate<System.Delegate>(InternalCallback);
+
+            Interop.ConstraintFunction.SetVector4Function(SwigCPtr, new HandleRef(this, ip));
+        }
+
+        private void OnCallback(IntPtr current, uint id, IntPtr inputContainerCPtr)
+        {
+            using Vector4 tempVector4 = new Vector4(current, false);
+            using PropertyInputContainer container = new PropertyInputContainer(inputContainerCPtr);
+
+            // TODO : Chane below logic if UIVector4 Implemented.
+            using Vector4 ret = (Callback as Constraint.ConstraintVector4FunctionCallbackType).Invoke(in tempVector4, id, in container);
+
+            if (ret != null)
+            {
+                Interop.Vector4.XSet(Vector4.getCPtr(tempVector4), ret.X);
+                Interop.Vector4.YSet(Vector4.getCPtr(tempVector4), ret.Y);
+                Interop.Vector4.ZSet(Vector4.getCPtr(tempVector4), ret.Z);
+                Interop.Vector4.WSet(Vector4.getCPtr(tempVector4), ret.W);
+            }
+        }
+    }
+
+    /// <summary>
+    /// An class for ConstraintsFunction for Matrix3.
+    /// </summary>
+    internal class ConstraintMatrix3Function : ConstraintFunctionBase
+    {
+        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+        internal delegate void InternalCallbackType(IntPtr current, uint id, IntPtr inputContainerCPtr);
+
+        public ConstraintMatrix3Function(Constraint.ConstraintMatrix3FunctionCallbackType callback) : base(Interop.ConstraintFunction.Matrix3FunctionNew(), callback)
+        {
+            Type = PropertyType.Matrix3;
+
+            InternalCallback = (InternalCallbackType)OnCallback;
+
+            Id = Interop.ConstraintFunction.GetMatrix3FunctionId(SwigCPtr);
+
+            var ip = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate<System.Delegate>(InternalCallback);
+
+            Interop.ConstraintFunction.SetMatrix3Function(SwigCPtr, new HandleRef(this, ip));
+        }
+
+        private void OnCallback(IntPtr current, uint id, IntPtr inputContainerCPtr)
+        {
+            using Matrix3 tempMatix3 = new Matrix3(current, false);
+            using PropertyInputContainer container = new PropertyInputContainer(inputContainerCPtr);
+
+            using Matrix3 ret = (Callback as Constraint.ConstraintMatrix3FunctionCallbackType).Invoke(in tempMatix3, id, in container);
+
+            if (ret != null)
+            {
+                // Copy to native result. TODO : Can we optimize here?
+                tempMatix3.Assign(ret);
+            }
+        }
+    }
+
+    /// <summary>
+    /// An class for ConstraintsFunction for Matrix.
+    /// </summary>
+    internal class ConstraintMatrixFunction : ConstraintFunctionBase
+    {
+        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+        internal delegate void InternalCallbackType(IntPtr current, uint id, IntPtr inputContainerCPtr);
+
+        public ConstraintMatrixFunction(Constraint.ConstraintMatrixFunctionCallbackType callback) : base(Interop.ConstraintFunction.MatrixFunctionNew(), callback)
+        {
+            Type = PropertyType.Matrix;
+
+            InternalCallback = (InternalCallbackType)OnCallback;
+
+            Id = Interop.ConstraintFunction.GetMatrixFunctionId(SwigCPtr);
+
+            var ip = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate<System.Delegate>(InternalCallback);
+
+            Interop.ConstraintFunction.SetMatrixFunction(SwigCPtr, new HandleRef(this, ip));
+        }
+
+        private void OnCallback(IntPtr current, uint id, IntPtr inputContainerCPtr)
+        {
+            using Matrix tempMatix = new Matrix(current, false);
+            using PropertyInputContainer container = new PropertyInputContainer(inputContainerCPtr);
+
+            using Matrix ret = (Callback as Constraint.ConstraintMatrixFunctionCallbackType).Invoke(in tempMatix, id, in container);
+
+            if (ret != null)
+            {
+                // Copy to native result. TODO : Can we optimize here?
+                tempMatix.Assign(ret);
+            }
+        }
+    }
+
+    /// <summary>
+    /// An class for ConstraintsFunction for Rotation.
+    /// </summary>
+    internal class ConstraintRotationFunction : ConstraintFunctionBase
+    {
+        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+        internal delegate void InternalCallbackType(IntPtr current, uint id, IntPtr inputContainerCPtr);
+
+        public ConstraintRotationFunction(Constraint.ConstraintRotationFunctionCallbackType callback) : base(Interop.ConstraintFunction.RotationFunctionNew(), callback)
+        {
+            Type = PropertyType.Rotation;
+
+            InternalCallback = (InternalCallbackType)OnCallback;
+
+            Id = Interop.ConstraintFunction.GetRotationFunctionId(SwigCPtr);
+
+            var ip = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate<System.Delegate>(InternalCallback);
+
+            Interop.ConstraintFunction.SetRotationFunction(SwigCPtr, new HandleRef(this, ip));
+        }
+
+        private void OnCallback(IntPtr current, uint id, IntPtr inputContainerCPtr)
+        {
+            using Rotation tempRotation = new Rotation(current, false);
+            using PropertyInputContainer container = new PropertyInputContainer(inputContainerCPtr);
+
+            using Rotation ret = (Callback as Constraint.ConstraintRotationFunctionCallbackType).Invoke(in tempRotation, id, in container);
+
+            if (ret != null)
+            {
+                // Copy to native result. TODO : Can we optimize here?
+                tempRotation.Assign(ret);
+            }
+        }
+    }
+}
diff --git a/src/Tizen.NUI/src/internal/Animation/ConstraintTagRanges.cs b/src/Tizen.NUI/src/internal/Animation/ConstraintTagRanges.cs
new file mode 100755 (executable)
index 0000000..7e7530d
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright(c) 2025 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using global::System;
+using global::System.ComponentModel;
+using global::System.Runtime.InteropServices;
+namespace Tizen.NUI
+{
+    /// <summary>
+    /// Determinate the range of constraint tag
+    /// </summary>
+    internal sealed class ConstraintTagRanges
+    {
+        /// <summary>
+        /// Default tag of constraint.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly uint Default = 0;
+
+        /// <summary>
+        /// Minimum number of tag we can use.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly uint TagMin = 1;
+
+        /// <summary>
+        /// Maximum number of tag we can use.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly uint TagMax = 999999999;
+    }
+}
index e62dd495c36f68508c9f4cc330d4e0e47d5d8ae0..144bc96fde9713a0af077a316428f3a38d704b9a 100755 (executable)
@@ -23,7 +23,7 @@ namespace Tizen.NUI
     /// Specialized Constraint.
     /// Make handle's targetIndex value always equal with handle's parent's parentIndex value
     /// </summary>
-    internal class EqualConstraintWithParentFloat : Constraint
+    internal sealed class EqualConstraintWithParentFloat : Constraint
     {
         internal EqualConstraintWithParentFloat(HandleRef handle, int targetIndex, int parentIndex)
          : base(Interop.Constraint.NewEqualConstraintWithParentFloat(handle, targetIndex, parentIndex), true)
diff --git a/src/Tizen.NUI/src/internal/Animation/PropertyInputContainer.cs b/src/Tizen.NUI/src/internal/Animation/PropertyInputContainer.cs
new file mode 100755 (executable)
index 0000000..8127af7
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright(c) 2025 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using global::System;
+using global::System.ComponentModel;
+using global::System.Runtime.InteropServices;
+namespace Tizen.NUI
+{
+    /// <summary>
+    /// An class for Constraints Function.
+    /// </summary>
+    internal class PropertyInputContainer : IDisposable
+    {
+        private HandleRef swigCPtr;
+        private bool disposed;
+
+        internal PropertyInputContainer(IntPtr cPtr)
+        {
+            swigCPtr = new HandleRef(this, cPtr);
+            Count = Interop.PropertyInputContainer.GetCount(swigCPtr);
+        }
+
+        ~PropertyInputContainer() => Dispose(false);
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public uint Count { get; init; }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public PropertyType GetPropertyType(uint index)
+        {
+            int ret = Interop.PropertyInputContainer.GetPropertyType(swigCPtr, index);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+            return (PropertyType)ret;
+        }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool GetBoolean(uint index)
+        {
+            bool ret = Interop.PropertyInputContainer.GetBoolean(swigCPtr, index);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+            return ret;
+        }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float GetFloat(uint index)
+        {
+            float ret = Interop.PropertyInputContainer.GetFloat(swigCPtr, index);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+            return ret;
+        }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int GetInteger(uint index)
+        {
+            int ret = Interop.PropertyInputContainer.GetInteger(swigCPtr, index);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+            return ret;
+        }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public UIVector2 GetVector2(uint index)
+        {
+            Interop.PropertyInputContainer.GetVector2Componentwise(swigCPtr, index, out float x, out float y);
+            UIVector2 ret = new UIVector2(x, y);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+            return ret;
+        }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public UIVector3 GetVector3(uint index)
+        {
+            Interop.PropertyInputContainer.GetVector3Componentwise(swigCPtr, index, out float x, out float y, out float z);
+            UIVector3 ret = new UIVector3(x, y, z);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+            return ret;
+        }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public UIColor GetColor(uint index)
+        {
+            Interop.PropertyInputContainer.GetVector4Componentwise(swigCPtr, index, out float x, out float y, out float z, out float w);
+            UIColor ret = new UIColor(x, y, z, w);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+            return ret;
+        }
+
+        public Vector4 GetVector4(uint index)
+        {
+            Interop.PropertyInputContainer.GetVector4Componentwise(swigCPtr, index, out float x, out float y, out float z, out float w);
+            Vector4 ret = new Vector4(x, y, z, w);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+            return ret;
+        }
+
+        public Matrix3 GetMatrix3(uint index)
+        {
+            Matrix3 ret = new Matrix3(Interop.PropertyInputContainer.GetMatrix3(swigCPtr, index), true);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+            return ret;
+        }
+
+        public Matrix GetMatrix(uint index)
+        {
+            Matrix ret = new Matrix(Interop.PropertyInputContainer.GetMatrix(swigCPtr, index), true);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+            return ret;
+        }
+
+        public Rotation GetRotation(uint index)
+        {
+            Rotation ret = new Rotation(Interop.PropertyInputContainer.GetRotation(swigCPtr, index), true);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+            return ret;
+        }
+
+        /// <summary>
+        /// Dispose
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposed)
+            {
+                return;
+            }
+
+            if (swigCPtr.Handle != global::System.IntPtr.Zero)
+            {
+                var nativeSwigCPtr = swigCPtr.Handle;
+                swigCPtr = new HandleRef(null, global::System.IntPtr.Zero);
+            }
+
+            disposed = true;
+        }
+
+    }
+}
index bda6b0287709db26b764ddd55928ee0d49e53e95..bed1cd1d8a84301c981a838438bb8f86ffca1d8d 100755 (executable)
@@ -23,7 +23,7 @@ namespace Tizen.NUI
     /// Specialized Constraint.
     /// Make handle's targetIndex value always equal with handle's parent's parentIndex value
     /// </summary>
-    internal class RelativeConstraintWithParentFloat : Constraint
+    internal sealed class RelativeConstraintWithParentFloat : Constraint
     {
         internal RelativeConstraintWithParentFloat(HandleRef handle, int targetIndex, int parentIndex, float rate)
          : base(Interop.Constraint.NewRelativeConstraintWithParentFloat(handle, targetIndex, parentIndex, rate), true)
index 314eda553f0fe9f4c0f5a1aef4ca26b7937c67b8..b56dfdd8a1a61594f31dab416d29f210ed03195c 100755 (executable)
@@ -21,21 +21,63 @@ namespace Tizen.NUI
     {
         internal static partial class Constraint
         {
-            
+            // Property type specific API
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_New_Boolean")]
+            public static extern global::System.IntPtr ConstraintBooleanNew(global::System.Runtime.InteropServices.HandleRef target, int propertyIndex, global::System.Runtime.InteropServices.HandleRef constraintFunction);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_New_Float")]
+            public static extern global::System.IntPtr ConstraintFloatNew(global::System.Runtime.InteropServices.HandleRef target, int propertyIndex, global::System.Runtime.InteropServices.HandleRef constraintFunction);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_New_Integer")]
+            public static extern global::System.IntPtr ConstraintIntegerNew(global::System.Runtime.InteropServices.HandleRef target, int propertyIndex, global::System.Runtime.InteropServices.HandleRef constraintFunction);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_New_Vector2")]
+            public static extern global::System.IntPtr ConstraintVector2New(global::System.Runtime.InteropServices.HandleRef target, int propertyIndex, global::System.Runtime.InteropServices.HandleRef constraintFunction);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_New_Vector3")]
+            public static extern global::System.IntPtr ConstraintVector3New(global::System.Runtime.InteropServices.HandleRef target, int propertyIndex, global::System.Runtime.InteropServices.HandleRef constraintFunction);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_New_Vector4")]
+            public static extern global::System.IntPtr ConstraintVector4New(global::System.Runtime.InteropServices.HandleRef target, int propertyIndex, global::System.Runtime.InteropServices.HandleRef constraintFunction);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_New_Matrix3")]
+            public static extern global::System.IntPtr ConstraintMatrix3New(global::System.Runtime.InteropServices.HandleRef target, int propertyIndex, global::System.Runtime.InteropServices.HandleRef constraintFunction);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_New_Matrix")]
+            public static extern global::System.IntPtr ConstraintMatrixNew(global::System.Runtime.InteropServices.HandleRef target, int propertyIndex, global::System.Runtime.InteropServices.HandleRef constraintFunction);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_New_Quaternion")]
+            public static extern global::System.IntPtr ConstraintRotationNew(global::System.Runtime.InteropServices.HandleRef target, int propertyIndex, global::System.Runtime.InteropServices.HandleRef constraintFunction);
+
+            // Common API
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_Constraint")]
             public static extern global::System.IntPtr DeleteConstraint(global::System.Runtime.InteropServices.HandleRef jarg1);
 
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_AddSource")]
+            public static extern void AddSource(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef sourceHandle, int sourceIndex);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_AddLocalSource")]
+            public static extern void AddLocalSource(global::System.Runtime.InteropServices.HandleRef jarg1, int sourceIndex);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_AddParentSource")]
+            public static extern void AddParentSource(global::System.Runtime.InteropServices.HandleRef jarg1, int sourceIndex);
+
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Apply")]
             public static extern void Apply(global::System.Runtime.InteropServices.HandleRef jarg1);
 
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_ApplyPost")]
+            public static extern void ApplyPost(global::System.Runtime.InteropServices.HandleRef jarg1);
+
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Remove")]
             public static extern void Remove(global::System.Runtime.InteropServices.HandleRef jarg1);
 
+            // Note : Dali use RemoveAction as apply action behavior.
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_SetRemoveAction")]
-            public static extern void SetRemoveAction(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2);
+            public static extern void SetApplyAction(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2);
 
+            // Note : Dali use RemoveAction as apply action behavior.
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_GetRemoveAction")]
-            public static extern int GetRemoveAction(global::System.Runtime.InteropServices.HandleRef jarg1);
+            public static extern int GetApplyAction(global::System.Runtime.InteropServices.HandleRef jarg1);
 
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_SetTag")]
             public static extern void SetTag(global::System.Runtime.InteropServices.HandleRef jarg1, uint jarg2);
diff --git a/src/Tizen.NUI/src/internal/Interop/Interop.ConstraintFunction.cs b/src/Tizen.NUI/src/internal/Interop/Interop.ConstraintFunction.cs
new file mode 100755 (executable)
index 0000000..d666658
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Tizen.NUI
+{
+    internal static partial class Interop
+    {
+        internal static partial class ConstraintFunction
+        {
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Boolean_New")]
+            public static extern global::System.IntPtr BooleanFunctionNew();
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Boolean_SetHandler")]
+            public static extern void SetBooleanFunction(global::System.Runtime.InteropServices.HandleRef function, global::System.Runtime.InteropServices.HandleRef handler);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Boolean_GetId")]
+            public static extern uint GetBooleanFunctionId(global::System.Runtime.InteropServices.HandleRef function);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_Constraint_Function_Boolean")]
+            public static extern void DeleteBooleanFunction(global::System.Runtime.InteropServices.HandleRef function);
+
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Float_New")]
+            public static extern global::System.IntPtr FloatFunctionNew();
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Float_SetHandler")]
+            public static extern void SetFloatFunction(global::System.Runtime.InteropServices.HandleRef function, global::System.Runtime.InteropServices.HandleRef handler);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Float_GetId")]
+            public static extern uint GetFloatFunctionId(global::System.Runtime.InteropServices.HandleRef function);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_Constraint_Function_Float")]
+            public static extern void DeleteFloatFunction(global::System.Runtime.InteropServices.HandleRef function);
+
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Integer_New")]
+            public static extern global::System.IntPtr IntegerFunctionNew();
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Integer_SetHandler")]
+            public static extern void SetIntegerFunction(global::System.Runtime.InteropServices.HandleRef function, global::System.Runtime.InteropServices.HandleRef handler);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Integer_GetId")]
+            public static extern uint GetIntegerFunctionId(global::System.Runtime.InteropServices.HandleRef function);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_Constraint_Function_Integer")]
+            public static extern void DeleteIntegerFunction(global::System.Runtime.InteropServices.HandleRef function);
+
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Vector2_New")]
+            public static extern global::System.IntPtr Vector2FunctionNew();
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Vector2_SetHandler")]
+            public static extern void SetVector2Function(global::System.Runtime.InteropServices.HandleRef function, global::System.Runtime.InteropServices.HandleRef handler);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Vector2_GetId")]
+            public static extern uint GetVector2FunctionId(global::System.Runtime.InteropServices.HandleRef function);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_Constraint_Function_Vector2")]
+            public static extern void DeleteVector2Function(global::System.Runtime.InteropServices.HandleRef function);
+
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Vector3_New")]
+            public static extern global::System.IntPtr Vector3FunctionNew();
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Vector3_SetHandler")]
+            public static extern void SetVector3Function(global::System.Runtime.InteropServices.HandleRef function, global::System.Runtime.InteropServices.HandleRef handler);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Vector3_GetId")]
+            public static extern uint GetVector3FunctionId(global::System.Runtime.InteropServices.HandleRef function);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_Constraint_Function_Vector3")]
+            public static extern void DeleteVector3Function(global::System.Runtime.InteropServices.HandleRef function);
+
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Vector4_New")]
+            public static extern global::System.IntPtr Vector4FunctionNew();
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Vector4_SetHandler")]
+            public static extern void SetVector4Function(global::System.Runtime.InteropServices.HandleRef function, global::System.Runtime.InteropServices.HandleRef handler);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Vector4_GetId")]
+            public static extern uint GetVector4FunctionId(global::System.Runtime.InteropServices.HandleRef function);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_Constraint_Function_Vector4")]
+            public static extern void DeleteVector4Function(global::System.Runtime.InteropServices.HandleRef function);
+
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Matrix3_New")]
+            public static extern global::System.IntPtr Matrix3FunctionNew();
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Matrix3_SetHandler")]
+            public static extern void SetMatrix3Function(global::System.Runtime.InteropServices.HandleRef function, global::System.Runtime.InteropServices.HandleRef handler);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Matrix3_GetId")]
+            public static extern uint GetMatrix3FunctionId(global::System.Runtime.InteropServices.HandleRef function);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_Constraint_Function_Matrix3")]
+            public static extern void DeleteMatrix3Function(global::System.Runtime.InteropServices.HandleRef function);
+
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Matrix_New")]
+            public static extern global::System.IntPtr MatrixFunctionNew();
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Matrix_SetHandler")]
+            public static extern void SetMatrixFunction(global::System.Runtime.InteropServices.HandleRef function, global::System.Runtime.InteropServices.HandleRef handler);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Matrix_GetId")]
+            public static extern uint GetMatrixFunctionId(global::System.Runtime.InteropServices.HandleRef function);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_Constraint_Function_Matrix")]
+            public static extern void DeleteMatrixFunction(global::System.Runtime.InteropServices.HandleRef function);
+
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Quaternion_New")]
+            public static extern global::System.IntPtr RotationFunctionNew();
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Quaternion_SetHandler")]
+            public static extern void SetRotationFunction(global::System.Runtime.InteropServices.HandleRef function, global::System.Runtime.InteropServices.HandleRef handler);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Constraint_Function_Quaternion_GetId")]
+            public static extern uint GetRotationFunctionId(global::System.Runtime.InteropServices.HandleRef function);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_Constraint_Function_Quaternion")]
+            public static extern void DeleteRotationFunction(global::System.Runtime.InteropServices.HandleRef function);
+        }
+    }
+}
index 87f54b5b972718bd880d3c75533a7271a2d388ea..db6dfd1af3c76ca2f87bb77e0c170e0ee449b5bf 100755 (executable)
@@ -42,6 +42,10 @@ namespace Tizen.NUI
             [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)]
             public static extern bool IsPropertyAnimatable(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2);
 
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Handle_IsPropertyAConstraintInput")]
+            [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)]
+            public static extern bool IsPropertyAConstraintInput(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2);
+
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Handle_GetPropertyType")]
             public static extern int GetPropertyType(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2);
 
diff --git a/src/Tizen.NUI/src/internal/Interop/Interop.PropertyInputContainer.cs b/src/Tizen.NUI/src/internal/Interop/Interop.PropertyInputContainer.cs
new file mode 100755 (executable)
index 0000000..ddbd4b1
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Tizen.NUI
+{
+    internal static partial class Interop
+    {
+        internal static partial class PropertyInputContainer
+        {
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PropertyInputContainer_GetCount")]
+            public static extern uint GetCount(global::System.Runtime.InteropServices.HandleRef jarg1);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PropertyInputContainer_GetType")]
+            public static extern int GetPropertyType(global::System.Runtime.InteropServices.HandleRef jarg1, uint index);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PropertyInputContainer_GetBoolean")]
+            [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)]
+            public static extern bool GetBoolean(global::System.Runtime.InteropServices.HandleRef jarg1, uint index);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PropertyInputContainer_GetFloat")]
+            public static extern float GetFloat(global::System.Runtime.InteropServices.HandleRef jarg1, uint index);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PropertyInputContainer_GetInteger")]
+            public static extern int GetInteger(global::System.Runtime.InteropServices.HandleRef jarg1, uint index);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PropertyInputContainer_GetVector2_Componentwise")]
+            public static extern void GetVector2Componentwise(global::System.Runtime.InteropServices.HandleRef jarg1, uint index, out float x, out float y);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PropertyInputContainer_GetVector3_Componentwise")]
+            public static extern void GetVector3Componentwise(global::System.Runtime.InteropServices.HandleRef jarg1, uint index, out float x, out float y, out float z);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PropertyInputContainer_GetVector4_Componentwise")]
+            public static extern void GetVector4Componentwise(global::System.Runtime.InteropServices.HandleRef jarg1, uint index, out float x, out float y, out float z, out float w);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PropertyInputContainer_GetMatrix3")]
+            public static extern global::System.IntPtr GetMatrix3(global::System.Runtime.InteropServices.HandleRef jarg1, uint index);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PropertyInputContainer_GetMatrix")]
+            public static extern global::System.IntPtr GetMatrix(global::System.Runtime.InteropServices.HandleRef jarg1, uint index);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PropertyInputContainer_GetQuaternion")]
+            public static extern global::System.IntPtr GetRotation(global::System.Runtime.InteropServices.HandleRef jarg1, uint index);
+        }
+    }
+}
index fce9a54af5089f7e58dd3fdbb7c7253706d2e95f..22baae2ed84bc752453f8cce2633c4efbc25aae8 100755 (executable)
@@ -156,6 +156,19 @@ namespace Tizen.NUI
             return ret;
         }
 
+        /// <summary>
+        /// whether a writable property can be the source of an constraint.
+        /// </summary>
+        /// <param name="index">The index of the property.</param>
+        /// <returns>True if the property is a constraint input.</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        internal bool IsPropertyAConstraintInput(int index)
+        {
+            bool ret = Interop.Handle.IsPropertyAConstraintInput(SwigCPtr, index);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+            return ret;
+        }
+
         /// <summary>
         /// Queries the type of a property.
         /// </summary>
diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/ConstraintWithCustomShaderTest.cs b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/ConstraintWithCustomShaderTest.cs
new file mode 100644 (file)
index 0000000..15f3de2
--- /dev/null
@@ -0,0 +1,713 @@
+using System;
+using System.Runtime.InteropServices;
+using Tizen.NUI.BaseComponents;
+using System.Collections.Generic;
+
+namespace Tizen.NUI.Samples
+{
+    public class ConstraintWithCustomShaderTest : IExample
+    {
+        static readonly string VERTEX_SHADER =
+        "//@name ConstraintWithCustomShaderTest.vert\n" +
+        "\n" +
+        "//@version 100\n" +
+        "\n" +
+        "precision highp float;\n" +
+        "INPUT highp vec2 aPosition;\n" +
+        "OUTPUT highp vec2 vPosition;\n" +
+        "FLAT OUTPUT highp float vCornerRadius;\n" +
+        "\n" +
+        "UNIFORM_BLOCK VertBlock\n" +
+        "{\n" +
+        "  UNIFORM highp mat4 uMvpMatrix;\n" +
+        "  UNIFORM highp float uCornerRadius;\n" +
+        "};\n" +
+        "UNIFORM_BLOCK SharedBlock\n" +
+        "{\n" +
+        "  UNIFORM highp vec3 uSize;\n" +
+        "}\n" +
+        "void main()\n" +
+        "{\n" +
+        "    vec4 pos = vec4(aPosition, 0.0, 1.0) * vec4(uSize.xy, 0.0, 1.0);\n" +
+        "    vPosition = (aPosition + vec2(0.5)) * uSize.xy;\n" +
+        "    vCornerRadius = max(0.0, min(uCornerRadius, min(uSize.x, uSize.y)));\n" +
+        "\n" +
+        "    gl_Position = uMvpMatrix * pos;\n" +
+        "}\n";
+
+        static readonly string FRAGMENT_SHADER =
+        "//@name ConstraintWithCustomShaderTest.frag\n" +
+        "\n" +
+        "//@version 100\n" +
+        "\n" +
+        "precision highp float;\n" +
+        "INPUT highp vec2 vPosition;\n" +
+        "FLAT INPUT highp float vCornerRadius;\n" +
+        "\n" +
+        "UNIFORM_BLOCK SharedBlock\n" +
+        "{\n" +
+        "  UNIFORM highp vec3 uSize;\n" +
+        "}\n" +
+        "UNIFORM_BLOCK FragBlock\n" +
+        "{\n" +
+        "  UNIFORM lowp vec4 uColor;\n" +
+        "  UNIFORM highp vec2 CursorPosition;\n" +
+        "  UNIFORM highp float uCornerSquareness;\n" +
+        "  UNIFORM highp float uCustomCursorRadius;\n" +
+        "};\n" +
+        "\n" +
+        "// Simplest CornerRadius implements\n" +
+        "float roundedBoxSDF(vec2 pixelPositionFromCenter, vec2 rectangleEdgePositionFromCenter, float radius, float squareness) {\n" +
+        "  highp vec2 diff = pixelPositionFromCenter\n" +
+        "                    - rectangleEdgePositionFromCenter\n" +
+        "                    + radius;\n" +
+        "\n" +
+        "  // If squareness is near 1.0 or 0.0, it make some numeric error. Let we avoid this situation by heuristic value.\n" +
+        "  if(squareness < 0.01)\n" +
+        "  {\n" +
+        "    return length(max(diff, 0.0)) + min(0.0, max(diff.x, diff.y)) - radius;\n" +
+        "  }\n" +
+        "  if(squareness > 0.99)\n" +
+        "  {\n" +
+        "    return max(diff.x, diff.y) - radius;\n" +
+        "  }\n" +
+        "\n" +
+        "  highp vec2 positiveDiff = max(diff, 0.0);\n" +
+        "\n" +
+        "  // make sqr to avoid duplicate codes.\n" +
+        "  positiveDiff *= positiveDiff;\n" +
+        "\n" +
+        "  // TODO : Could we remove this double-sqrt code?\n" +
+        "  return sqrt(((positiveDiff.x + positiveDiff.y)\n" +
+        "               + sqrt(positiveDiff.x * positiveDiff.x\n" +
+        "                      + positiveDiff.y * positiveDiff.y\n" +
+        "                      + (2.0 - 4.0 * squareness * squareness) * positiveDiff.x * positiveDiff.y))\n" +
+        "              * 0.5)\n" +
+        "         + min(0.0, max(diff.x, diff.y)) ///< Consider negative potential, to avoid visual defect when radius is zero\n" +
+        "         - radius;\n" +
+        "}\n" +
+        "\n" +
+        "void main()\n" +
+        "{\n" +
+        "    highp float dist = length(vPosition - CursorPosition);\n" +
+        "    dist /= uCustomCursorRadius;\n" +
+        "    gl_FragColor = uColor * vec4(dist, 0.0, 1.0, 1.0);\n" +
+        " \n" +
+        "    highp vec2 location = abs(vPosition.xy - vec2(0.5) * uSize.xy);\n" +
+        "    highp vec2 halfSize = uSize.xy * 0.5;\n" +
+        "    highp float radius = vCornerRadius;\n" +
+        "    highp float edgeSoftness = min(1.0, radius);" +
+        "\n" +
+        "    highp float signedDistance = roundedBoxSDF(location, halfSize, radius, uCornerSquareness);\n" +
+        "    mediump float smoothedAlpha = 1.0 - smoothstep(-edgeSoftness, edgeSoftness, signedDistance);\n" +
+        "\n" +
+        "    gl_FragColor.a *= smoothedAlpha;\n" +
+        "}\n";
+
+
+        struct SimpleQuadVertex
+        {
+            public UIVector2 position;
+        }
+
+        private PropertyBuffer CreateQuadPropertyBuffer()
+        {
+            /* Create Property buffer */
+            PropertyMap vertexFormat = new PropertyMap();
+            vertexFormat.Add("aPosition", (int)PropertyType.Vector2);
+
+            PropertyBuffer vertexBuffer = new PropertyBuffer(vertexFormat);
+
+            SimpleQuadVertex vertex1 = new SimpleQuadVertex();
+            SimpleQuadVertex vertex2 = new SimpleQuadVertex();
+            SimpleQuadVertex vertex3 = new SimpleQuadVertex();
+            SimpleQuadVertex vertex4 = new SimpleQuadVertex();
+            vertex1.position = new UIVector2(-0.5f, -0.5f);
+            vertex2.position = new UIVector2(-0.5f, 0.5f);
+            vertex3.position = new UIVector2(0.5f, -0.5f);
+            vertex4.position = new UIVector2(0.5f, 0.5f);
+
+            SimpleQuadVertex[] texturedQuadVertexData = new SimpleQuadVertex[4] { vertex1, vertex2, vertex3, vertex4 };
+
+            int size = Marshal.SizeOf(vertex1);
+            IntPtr pA = Marshal.AllocHGlobal(checked(size * texturedQuadVertexData.Length));
+
+            try
+            {
+                for (int i = 0; i < texturedQuadVertexData.Length; i++)
+                {
+                    Marshal.StructureToPtr(texturedQuadVertexData[i], pA + i * size, true);
+                }
+
+                vertexBuffer.SetData(pA, (uint)texturedQuadVertexData.Length);
+            }
+            catch(Exception e)
+            {
+                Tizen.Log.Error("NUI", "Exception in PropertyBuffer : " + e.Message);
+            }
+            finally
+            {
+                // Free AllocHGlobal memory after call PropertyBuffer.SetData()
+                Marshal.FreeHGlobal(pA);
+            }
+
+            vertexFormat.Dispose();
+
+            return vertexBuffer;
+        }
+
+        private enum ConstraintBehaviorType
+        {
+            None = 0,
+            Noise,
+            Max,
+        };
+        private static ConstraintBehaviorType constraintType;
+        private static float gWindowWidth = 0.0f;
+        private static float gWindowHeight = 0.0f;
+        private static Random rand = new Random();
+
+        private static object lockObject = new object();
+
+        private const bool _printLogs = false; // Make it true if you want to see the logs
+
+        private static UIVector2 OnConstraintVector2(UIVector2 current, uint id, in PropertyInputContainer container)
+        {
+            float viewWidth = container.GetFloat(0u);
+            float viewHeight = container.GetFloat(1u);
+            UIVector3 viewPosition = container.GetVector3(2u);
+            UIColor viewColor = container.GetColor(3u);
+            using Rotation viewRotation = container.GetRotation(4u);
+            using Matrix viewModelMatrix = container.GetMatrix(5u);
+
+            float hoveViewX = container.GetFloat(6u);
+            float hoveViewY = container.GetFloat(7u);
+
+            using Vector3 axis = new Vector3();
+            using Radian angle = new Radian();
+            bool converted = viewRotation.GetAxisAngle(axis, angle);
+
+            ConstraintBehaviorType type;
+            lock (lockObject)
+            {
+                type = constraintType;
+            }
+
+            UIVector2 result = new UIVector2(hoveViewX - viewPosition.X + viewWidth * 0.5f, hoveViewY - viewPosition.Y + viewHeight * 0.5f);
+            switch(type)
+            {
+                case ConstraintBehaviorType.Noise:
+                {
+                    result = new UIVector2(result.X + rand.Next(-1000, 1000) * 0.01f, result.Y + rand.Next(-1000, 1000) * 0.01f);
+                    break;
+                }
+                default:
+                {
+                    // Do nothing.
+                    break;
+                }
+            }
+
+            if (_printLogs)
+            {
+                Tizen.Log.Error("NUI", $"ID : {id}, container size : {container.Count}, current : {current.X}, {current.Y}\n");
+                Tizen.Log.Error("NUI", $"w:{viewWidth} h:{viewHeight}, x:{viewPosition.X}, y:{viewPosition.Y}, z:{viewPosition.Z}\n");
+                Tizen.Log.Error("NUI", $"r:{viewColor.R} g:{viewColor.G}, b:{viewColor.B}, a:{viewColor.A}\n");
+                Tizen.Log.Error("NUI", $"{converted} / angle:{angle.Value} axis:{axis.X}, {axis.Y}, {axis.Z}\n");
+                Tizen.Log.Error("NUI", $"hover : {hoveViewX}, {hoveViewY}\n");
+
+                Tizen.Log.Error("NUI", $"  Model Matrix :\n");
+                for (uint i = 0; i < 4; i++)
+                {
+                    Tizen.Log.Error("NUI", $"  {viewModelMatrix.ValueOfIndex(i, 0)}, {viewModelMatrix.ValueOfIndex(i, 1)}, {viewModelMatrix.ValueOfIndex(i, 2)}, {viewModelMatrix.ValueOfIndex(i, 3)}\n");
+                }
+                Tizen.Log.Error("NUI", $"ID : {id}, result : {result.X}, {result.Y}\n");
+            }
+
+            return result;
+        }
+
+        private static float OnConstraintFloat(float current, uint id, in PropertyInputContainer container)
+        {
+            float result = container.GetVector4(0u).X;
+            if(container.Count > 1)
+            {
+                switch((VisualTransformPolicyType)container.GetInteger(1u))
+                {
+                    case VisualTransformPolicyType.Relative:
+                    {
+                        result *= Math.Min(container.GetFloat(2u), container.GetFloat(3u));
+                        break;
+                    }
+                    case VisualTransformPolicyType.Absolute:
+                    {
+                        break;
+                    }
+                }
+            }
+
+            if (_printLogs)
+            {
+                Tizen.Log.Error("NUI", $"ID : {id}, container size : {container.Count}, current : {current}, input : {container.GetVector4(0u).X}, result : {result}\n");
+                if(container.Count > 1)
+                {
+                    Tizen.Log.Error("NUI", $"Type : {container.GetPropertyType(1u)}, value : {container.GetInteger(1u)}\n");
+                    switch((VisualTransformPolicyType)container.GetInteger(1u))
+                    {
+                        case VisualTransformPolicyType.Relative:
+                        {
+                            Tizen.Log.Error("NUI", $"Relative\n");
+                            break;
+                        }
+                        case VisualTransformPolicyType.Absolute:
+                        {
+                            Tizen.Log.Error("NUI", $"Absolute\n");
+                            break;
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+
+        private static Rotation OnConstraintRotation(in Rotation current, uint id, in PropertyInputContainer container)
+        {
+            float windowWidth, windowHeight;
+            lock (lockObject)
+            {
+                windowWidth = gWindowWidth;
+                windowHeight = gWindowHeight;
+            }
+            float cursorX = container.GetFloat(0u) / windowWidth;
+            float cursorY = container.GetFloat(1u) / windowHeight;
+
+            using Radian pitch = new Radian(-cursorY * 0.2f);
+            using Radian yaw = new Radian(cursorX * 0.2f);
+            using Radian roll = new Radian(0.0f);
+            Rotation rotation = new Rotation(pitch, yaw, roll);
+            if (_printLogs)
+            {
+                Tizen.Log.Error("NUI", $"ID : {id}, container size : {container.Count}, cursor pos : {cursorX}, {cursorY}\n");
+
+                using Vector3 axis = new Vector3();
+                using Radian angle = new Radian();
+                bool converted = current.GetAxisAngle(axis, angle);
+                Tizen.Log.Error("NUI", $"Current : {converted} / angle:{angle.Value} axis:{axis.X}, {axis.Y}, {axis.Z}\n");
+
+                converted = rotation.GetAxisAngle(axis, angle);
+                Tizen.Log.Error("NUI", $"Result : {converted} / angle:{angle.Value} axis:{axis.X}, {axis.Y}, {axis.Z}\n");
+            }
+            return rotation;
+        }
+
+        private Window win;
+        private View root;
+        private Layer overlayLayer;
+
+        private View view; // Custom renderable holder
+        private View hoverView;
+
+        private static Geometry geometry;
+        private static Shader shader;
+        private Renderable renderable;
+
+        private Constraint constraint;
+        private bool constraintApplied;
+
+        private Constraint cornerConstraint;
+        private Constraint cornerConstraint2;
+
+        private Constraint orientationConstraint;
+
+        private Animation radiusAnimation;
+
+        private Animation cursorMoveAnimation;
+        private int cursorPositionIndex;
+
+        public void Activate()
+        {
+            win = NUIApplication.GetDefaultWindow();
+
+            lock (lockObject)
+            {
+                gWindowWidth = win.Size.Width;
+                gWindowHeight = win.Size.Height;
+            }
+
+            win.OrientationChanged += OnWindowOrientationChangedEvent;
+            win.Resized += WindowResized;
+            win.KeyEvent += WindowKeyEvent;
+
+            root = new View()
+            {
+                Name = "root",
+                WidthResizePolicy = ResizePolicyType.FillToParent,
+                HeightResizePolicy = ResizePolicyType.FillToParent,
+            };
+            win.Add(root);
+
+            CreateCustomRenderableView();
+            GenerateConstraint();
+
+            var infoLabel = new TextLabel()
+            {
+                Text = "Constraint the mouse cursor position, and use this value as custom shader uniform.\n" +
+                       "If touch down and release, curosr position animate.\n" +
+                       "\n" +
+                       "  Press 0 to give noise at cursor constraint result\n" +
+                       "  Press 1 to test re-generate new constraints\n" +
+                       "  Press 2 to test Apply / Remove cursor constraint\n" +
+                       "  Press 3 to test re-generate source view\n" +
+                       "  Press 4 to test re-generate target renderer\n" +
+                       "  Press 5 to test corner radius / squareness change of view\n",
+                MultiLine = true,
+            };
+            overlayLayer = new Layer();
+            win.AddLayer(overlayLayer);
+            overlayLayer.Add(infoLabel);
+        }
+
+        public void Deactivate()
+        {
+            root?.Unparent();
+            root?.DisposeRecursively();
+
+            if (constraint != null)
+            {
+                Tizen.Log.Error("NUI", $"Constraint with ID : {constraint.ID} will be Disposed(), but callback could be comes after now\n");
+                constraint?.Dispose();
+            }
+
+            if (cornerConstraint != null)
+            {
+                Tizen.Log.Error("NUI", $"Constraint with ID : {cornerConstraint.ID} will be Disposed(), but callback could be comes after now\n");
+                cornerConstraint?.Dispose();
+            }
+
+            if (cornerConstraint2 != null)
+            {
+                Tizen.Log.Error("NUI", $"Constraint with ID : {cornerConstraint2.ID} will be Disposed(), but callback could be comes after now\n");
+                cornerConstraint2?.Dispose();
+            }
+
+            if (orientationConstraint != null)
+            {
+                Tizen.Log.Error("NUI", $"Constraint with ID : {orientationConstraint.ID} will be Disposed(), but callback could be comes after now\n");
+                orientationConstraint?.Dispose();
+            }
+
+            if (overlayLayer != null)
+            {
+                win?.RemoveLayer(overlayLayer);
+            }
+
+            renderable?.Dispose();
+            overlayLayer?.Dispose();
+
+            if (win != null)
+            {
+                win.OrientationChanged -= OnWindowOrientationChangedEvent;
+                win.Resized -= WindowResized;
+                win.KeyEvent -= WindowKeyEvent;
+            }
+        }
+
+        private void OnWindowOrientationChangedEvent(object sender, WindowOrientationChangedEventArgs e)
+        {
+            Window.WindowOrientation orientation = e.WindowOrientation;
+            Tizen.Log.Error("NUI", $"OnWindowOrientationChangedEvent() called!, orientation:{orientation}");
+        }
+
+        private void WindowResized(object sender, Window.ResizedEventArgs e)
+        {
+            lock (lockObject)
+            {
+                gWindowWidth = e.WindowSize.Width;
+                gWindowHeight = e.WindowSize.Height;
+            }
+            Tizen.Log.Error("NUI", $"Window resized : {gWindowWidth}, {gWindowHeight}\n");
+        }
+
+        private void WindowKeyEvent(object sender, Window.KeyEventArgs e)
+        {
+            if (e.Key.State == Key.StateType.Down)
+            {
+                if (e.Key.KeyPressedName == "0")
+                {
+                    lock (lockObject)
+                    {
+                        constraintType = (ConstraintBehaviorType)(((int)constraintType + 1) % ((int)ConstraintBehaviorType.Max));
+
+                        Tizen.Log.Error("NUI", $"Constraint : {constraint.ID} will act by {constraintType}\n");
+                    }
+                }
+                if (e.Key.KeyPressedName == "1")
+                {
+                    GenerateConstraint();
+                }
+                if (e.Key.KeyPressedName == "2")
+                {
+                    ToggleConstraintActivation();
+                }
+                if (e.Key.KeyPressedName == "3")
+                {
+                    RegenerateView();
+                }
+                if (e.Key.KeyPressedName == "4")
+                {
+                    RegenerateRenderable();
+                }
+                if (e.Key.KeyPressedName == "5")
+                {
+                    float v = view.CornerRadius.X;
+                    view.CornerRadius = 0.35f - v;
+                }
+            }
+        }
+
+        private void CreateCustomRenderableView()
+        {
+            view = new View()
+            {
+                SizeWidth = 300,
+                SizeHeight = 500,
+                PositionX = 50,
+                PositionY = 100,
+
+                CornerRadius = 0.35f,
+                CornerRadiusPolicy = VisualTransformPolicyType.Relative,
+                CornerSquareness = 0.6f,
+            };
+
+            hoverView = new View()
+            {
+                BackgroundColor = Color.Black,
+                SizeWidth = 4,
+                SizeHeight = 4,
+                PositionX = 200,
+                PositionY = 350,
+            };
+
+            cursorMoveAnimation = new Animation(500);
+
+            root.HoverEvent += (o, e) =>
+            {
+                //if (cursorMoveAnimation.State == Animation.States.Stopped)
+                {
+                    using var localPosition = e.Hover.GetLocalPosition(0u);
+                    hoverView.PositionX = localPosition.X;
+                    hoverView.PositionY = localPosition.Y;
+                }
+                return true;
+            };
+
+            root.TouchEvent += (o, e) =>
+            {
+                if (e.Touch.GetState(0) == PointStateType.Down)
+                {
+                    cursorMoveAnimation.Stop();
+                    cursorMoveAnimation.Clear();
+                }
+                else if (e.Touch.GetState(0) == PointStateType.Up)
+                {
+                    cursorMoveAnimation.Stop();
+                    cursorMoveAnimation.Clear();
+
+                    // Reverse the animation localPosition -> currentPosition.
+                    // If than, it will works like currentPositoin -> latest position what updated by Hover
+                    using var localPosition = e.Touch.GetLocalPosition(0u);
+                    cursorMoveAnimation.AnimateTo(hoverView, "PositionX", hoverView.PositionX, new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutBack));
+                    cursorMoveAnimation.AnimateTo(hoverView, "PositionY", hoverView.PositionY, new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutBack));
+                    cursorMoveAnimation.SpeedFactor = -1;
+                    cursorMoveAnimation.Play();
+
+                    hoverView.PositionX = localPosition.X;
+                    hoverView.PositionY = localPosition.Y;
+                }
+                return true;
+            };
+
+            renderable = GenerateRenderable();
+            view.AddRenderable(renderable);
+
+            root.Add(view);
+            root.Add(hoverView);
+        }
+
+        private void GenerateConstraint()
+        {
+            if (constraint != null)
+            {
+                Tizen.Log.Error("NUI", $"Constraint with ID : {constraint.ID} will be Disposed(), but callback could be comes after now\n");
+                constraint.Dispose();
+            }
+
+            // Create constraint for renderable
+            // Note that we cannot use "CursorPosition" as input of property name, because
+            // the first charactor of property name become lower case internally.
+            // To avoid this situation, we should use the index of property.
+            constraint = Constraint.GenerateConstraint(renderable, cursorPositionIndex, new Constraint.ConstraintVector2FunctionCallbackType(OnConstraintVector2));
+            constraint.AddSource(view, "SizeWidth");
+            constraint.AddSource(view, "SizeHeight");
+            constraint.AddSource(view, view.GetPropertyIndex("WorldPosition")); // Test for Vector3
+            constraint.AddSource(view, view.GetPropertyIndex("Color")); // Test for Vector4
+            constraint.AddSource(view, view.GetPropertyIndex("Orientation")); // Test for rotation
+            constraint.AddSource(view, view.GetPropertyIndex("WorldMatrix")); // Test for matrix
+            constraint.AddSource(hoverView, "WorldPositionX");
+            constraint.AddSource(hoverView, hoverView.GetPropertyIndex("WorldPositionY"));
+            constraint.Apply();
+
+            cornerConstraint?.Dispose();
+            cornerConstraint2?.Dispose();
+            orientationConstraint?.Dispose();
+            cornerConstraint = null;
+            cornerConstraint2 = null;
+            orientationConstraint = null;
+
+            // Set corner radius as input of constraints
+            cornerConstraint = Constraint.GenerateConstraint(renderable, "uCornerRadius", new Constraint.ConstraintFloatFunctionCallbackType(OnConstraintFloat));
+            cornerConstraint.AddSource(view, "CornerRadius");
+            cornerConstraint.AddSource(view, "CornerRadiusPolicy");
+            cornerConstraint.AddSource(view, "sizeWidth");
+            cornerConstraint.AddSource(view, "sizeHeight");
+            cornerConstraint.Apply();
+
+            // Note that the first charactor of property name become lower case internally.
+            // Here, "UCornerSquareness" -> "uCornerSquareness", "CornerSquareness" -> "cornerSquareness"
+            cornerConstraint2 = Constraint.GenerateConstraint(renderable, "UCornerSquareness", new Constraint.ConstraintFloatFunctionCallbackType(OnConstraintFloat));
+            cornerConstraint2.AddSource(view, "CornerSquareness");
+            cornerConstraint2.Apply();
+
+            // Set orientation as input of constraints
+            orientationConstraint = Constraint.GenerateConstraint(view, "Orientation", new Constraint.ConstraintRotationFunctionCallbackType(OnConstraintRotation));
+            orientationConstraint.AddSource(hoverView, "worldPositionX");
+            orientationConstraint.AddSource(hoverView, "WorldPositionY");
+            orientationConstraint.Apply();
+
+            constraintApplied = true;
+
+            Tizen.Log.Error("NUI", $"Constraint with ID : {constraint.ID} {cornerConstraint.ID} {cornerConstraint2.ID} {orientationConstraint.ID} Created and applied\n");
+        }
+
+        private void ToggleConstraintActivation()
+        {
+            if (constraint != null)
+            {
+                if (constraintApplied)
+                {
+                    constraint.Remove();
+                    Tizen.Log.Error("NUI", $"Constraint with ID : {constraint.ID} removed\n");
+                }
+                else
+                {
+                    constraint.Apply();
+                    Tizen.Log.Error("NUI", $"Constraint with ID : {constraint.ID} applied\n");
+                }
+                constraintApplied ^= true;
+            }
+        }
+
+        private void RegenerateView()
+        {
+            view.Dispose();
+            hoverView.Dispose();
+
+            view = new View()
+            {
+                SizeWidth = 300,
+                SizeHeight = 500,
+                PositionX = 50,
+                PositionY = 100,
+
+                CornerRadius = 0.35f,
+                CornerRadiusPolicy = VisualTransformPolicyType.Relative,
+                CornerSquareness = 0.6f,
+            };
+
+            hoverView = new View()
+            {
+                BackgroundColor = Color.Black,
+                SizeWidth = 4,
+                SizeHeight = 4,
+                PositionX = 200,
+                PositionY = 350,
+            };
+
+            view.AddRenderable(renderable);
+            root.Add(view);
+            root.Add(hoverView);
+
+            if (constraint != null)
+            {
+                Tizen.Log.Error("NUI", $"Constraint with ID : {constraint.ID} {orientationConstraint.ID} {cornerConstraint.ID} {cornerConstraint2.ID} invalidate after RenderThread object destroyed\n");
+            }
+        }
+
+        private void RegenerateRenderable()
+        {
+            view.RemoveRenderable(renderable);
+            renderable.Dispose();
+
+            renderable = GenerateRenderable();
+            view.AddRenderable(renderable);
+
+            if (constraint != null)
+            {
+                Tizen.Log.Error("NUI", $"Constraint with ID : {constraint.ID} {cornerConstraint.ID} {cornerConstraint2.ID} invalidate after RenderThread object destroyed\n");
+            }
+        }
+
+        private Geometry GenerateGeometry()
+        {
+            if (geometry == null)
+            {
+                using PropertyBuffer vertexBuffer = CreateQuadPropertyBuffer();
+                geometry = new Geometry();
+                geometry.AddVertexBuffer(vertexBuffer);
+                geometry.SetType(Geometry.Type.TRIANGLE_STRIP);
+            }
+            return geometry;
+        }
+
+        private Shader GenerateShader()
+        {
+            if (shader == null)
+            {
+                shader = new Shader(VERTEX_SHADER, FRAGMENT_SHADER, "ConstraintWithCustomShaderTest");
+            }
+            return shader;
+        }
+
+        private Renderable GenerateRenderable()
+        {
+            if (renderable == null)
+            {
+                renderable = new Renderable()
+                {
+                    Geometry = GenerateGeometry(),
+                    Shader = GenerateShader(),
+                };
+
+                // Note that if the first charactor of custom registered property name is not lower case,
+                // We cannot access to that property by name.
+                // In this case, we should keep the index of property to access, or animate, or constraint it.
+                cursorPositionIndex = renderable.RegisterProperty("CursorPosition", new PropertyValue(100.0f, 200.0f));
+
+                renderable.RegisterProperty("uCustomCursorRadius", new PropertyValue(300.0f));
+                renderable.RegisterProperty("uCornerRadius", new PropertyValue(0.0f));
+                renderable.RegisterProperty("uCornerSquareness", new PropertyValue(0.0f));
+
+                //renderable.BlendPreMultipliedAlpha = true;
+                renderable.BlendMode = BlendMode.On;
+
+                radiusAnimation = new Animation(10000);
+                radiusAnimation.LoopingMode = Animation.LoopingModes.AutoReverse;
+                radiusAnimation.Looping = true;
+                radiusAnimation.AnimateTo(renderable, "uCustomCursorRadius", 50.0f, new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseInOutSine));
+                radiusAnimation.Play();
+            }
+
+            return renderable;
+        }
+    }
+}