[NUI] Implement VisualObject feature for View using Visual feature
authorEunki, Hong <eunkiki.hong@samsung.com>
Wed, 17 Apr 2024 07:55:32 +0000 (16:55 +0900)
committerEunki Hong <h.pichulia@gmail.com>
Tue, 11 Jun 2024 10:37:05 +0000 (19:37 +0900)
It was hard to use Visual feature for `BaseComponents.View`

We only allow to use `VisualBase` only for `VisualView`, with name.
But there was some user side hardness when they want to use it

1. Subclass of View cannot use Visual feature
2. Some ImageVisual feature doesn't allow to used another visuals.

To resolve this issue,
let we make new class, named `Visuals.VisualBase` and let View use it.

Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
24 files changed:
src/Tizen.NUI/src/internal/Common/VisualObjectsContainer.cs [new file with mode: 0644]
src/Tizen.NUI/src/internal/Interop/Interop.VisualObject.cs [new file with mode: 0755]
src/Tizen.NUI/src/internal/Interop/Interop.VisualObjectsContainer.cs [new file with mode: 0755]
src/Tizen.NUI/src/public/BaseComponents/ViewInternal.cs
src/Tizen.NUI/src/public/BaseComponents/ViewVisuals.cs [new file with mode: 0755]
src/Tizen.NUI/src/public/Common/PropertyMap.cs
src/Tizen.NUI/src/public/Visuals/VisualConstants.cs
src/Tizen.NUI/src/public/Visuals/VisualObject/AdvancedTextVisual.cs [new file with mode: 0644]
src/Tizen.NUI/src/public/Visuals/VisualObject/AnimatedImageVisual.cs [new file with mode: 0644]
src/Tizen.NUI/src/public/Visuals/VisualObject/BorderVisual.cs [new file with mode: 0644]
src/Tizen.NUI/src/public/Visuals/VisualObject/ColorVisual.cs [new file with mode: 0644]
src/Tizen.NUI/src/public/Visuals/VisualObject/ImageVisual.cs [new file with mode: 0644]
src/Tizen.NUI/src/public/Visuals/VisualObject/NPatchVisual.cs [new file with mode: 0644]
src/Tizen.NUI/src/public/Visuals/VisualObject/TextVisual.cs [new file with mode: 0644]
src/Tizen.NUI/src/public/Visuals/VisualObject/VisualBase.cs [new file with mode: 0644]
test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/VisualTest.cs [new file with mode: 0755]
test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/images/i_focus_stroke_tile_2unit.9.webp [new file with mode: 0644]
test/Tizen.NUI.VisualTest/Tizen.NUI.VisualTest.code-workspace [new file with mode: 0644]
test/Tizen.NUI.VisualTest/Tizen.NUI.VisualTest.csproj [new file with mode: 0644]
test/Tizen.NUI.VisualTest/Tizen.NUI.VisualTest.sln [new file with mode: 0755]
test/Tizen.NUI.VisualTest/VisualTest.cs [new file with mode: 0644]
test/Tizen.NUI.VisualTest/res/image/gallery-small-1.jpg [new file with mode: 0644]
test/Tizen.NUI.VisualTest/shared/res/Tizen.NUI.VisualTest.png [new file with mode: 0644]
test/Tizen.NUI.VisualTest/tizen-manifest.xml [new file with mode: 0755]

diff --git a/src/Tizen.NUI/src/internal/Common/VisualObjectsContainer.cs b/src/Tizen.NUI/src/internal/Common/VisualObjectsContainer.cs
new file mode 100644 (file)
index 0000000..767b2eb
--- /dev/null
@@ -0,0 +1,191 @@
+// Copyright (c) 2024 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 System;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Linq;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Visuals
+{
+    /// <summary>
+    /// VisualObjectsContainer is a container for visual objects.
+    /// For each VisualObjectContainer, there is a corresponding view.
+    /// Each view can have only one VisualObjectsContainer per rangeType.
+    /// </summary>
+    /// <remarks>
+    /// To avoid the collision between Dali toolkit logic and NUI specific policy,
+    /// this container has an internal limitation of the number of visual objects.
+    /// If user try to add visual object over the limitation, it will be ignored.
+    /// </remarks>
+    internal class VisualObjectsContainer : BaseHandle
+    {
+        private List<Tizen.NUI.Visuals.VisualBase> visuals = new List<Tizen.NUI.Visuals.VisualBase>(); // Keep visual object reference.
+
+        /// <summary>
+        /// Creates an empty visual object handle.
+        /// </summary>
+        public VisualObjectsContainer() : this(Interop.VisualObjectsContainer.NewVisualObjectsContainer(), true, false)
+        {
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        /// <summary>
+        /// Creates an visual object with VisualObjectsContainer.
+        /// </summary>
+        public VisualObjectsContainer(Tizen.NUI.BaseComponents.View view, int rangeType) : this(Interop.VisualObjectsContainer.VisualObjectsContainerNew(Tizen.NUI.BaseComponents.View.getCPtr(view), rangeType), true)
+        {
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        internal VisualObjectsContainer(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
+        {
+        }
+
+        internal VisualObjectsContainer(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
+        {
+        }
+
+        public Tizen.NUI.BaseComponents.View GetView()
+        {
+            global::System.IntPtr cPtr = Interop.VisualObjectsContainer.GetOwner(SwigCPtr);
+            
+            Tizen.NUI.BaseComponents.View ret = null;
+            if (Interop.RefObject.GetRefObjectPtr(cPtr) == global::System.IntPtr.Zero)
+            {
+                // Visual container don't have owner. Return null.
+                Interop.BaseHandle.DeleteBaseHandle(new global::System.Runtime.InteropServices.HandleRef(this, cPtr));
+            }
+            else
+            {
+                ret = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Tizen.NUI.BaseComponents.View;
+                if (ret != null)
+                {
+                    Interop.BaseHandle.DeleteBaseHandle(new global::System.Runtime.InteropServices.HandleRef(this, cPtr));
+                }
+                else
+                {
+                    ret = new Tizen.NUI.BaseComponents.View(cPtr, true);
+                }
+            }
+            NDalicPINVOKE.ThrowExceptionIfExists();
+            return ret;
+        }
+
+        public int GetContainerRangeType()
+        {
+            return Interop.VisualObjectsContainer.GetContainerRangeType(SwigCPtr);
+        }
+
+        public Tizen.NUI.Visuals.VisualBase this[uint index]
+        {
+            get
+            {
+                return GetVisualObjectAt(index);
+            }
+        }
+
+        public uint GetVisualObjectsCount()
+        {
+            uint ret = Interop.VisualObjectsContainer.GetVisualObjectsCount(SwigCPtr);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+            return ret;
+        }
+
+        public bool AddVisualObject(Tizen.NUI.Visuals.VisualBase visualObject)
+        {
+            // Detach from previous container first.
+            var previousContainer = visualObject.GetVisualContainer();
+            if (previousContainer != null)
+            {
+                if (previousContainer == this)
+                {
+                    // Already added to this container.
+                    return false;
+                }
+                visualObject.Detach();
+            }
+
+            visuals.Add(visualObject);
+
+            bool ret = Interop.VisualObjectsContainer.AddVisualObject(SwigCPtr, Tizen.NUI.Visuals.VisualBase.getCPtr(visualObject));
+            NDalicPINVOKE.ThrowExceptionIfExists();
+            return ret;
+        }
+
+        public void RemoveVisualObject(Tizen.NUI.Visuals.VisualBase visualObject)
+        {
+            visuals.Remove(visualObject);
+
+            Interop.VisualObjectsContainer.RemoveVisualObject(SwigCPtr, Tizen.NUI.Visuals.VisualBase.getCPtr(visualObject));
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        public Tizen.NUI.Visuals.VisualBase FindVisualObjectByName(string name)
+        {
+            Tizen.NUI.Visuals.VisualBase ret = null;
+            if(!string.IsNullOrEmpty(name))
+            {
+                foreach (var visual in visuals)
+                {
+                    if (visual?.Name == name)
+                    {
+                        return visual;
+                    }
+                }
+            }
+            return ret;
+        }
+
+        private Tizen.NUI.Visuals.VisualBase GetVisualObjectAt(uint index)
+        {
+            global::System.IntPtr cPtr = Interop.VisualObjectsContainer.GetVisualObjectAt(SwigCPtr, index);
+            Visuals.VisualBase ret = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Visuals.VisualBase;
+            if (ret != null)
+            {
+                Interop.BaseHandle.DeleteBaseHandle(new global::System.Runtime.InteropServices.HandleRef(this, cPtr));
+            }
+            else
+            {
+                ret = new Visuals.VisualBase(cPtr, true);
+            }
+            NDalicPINVOKE.ThrowExceptionIfExists();
+            return ret;
+        }
+
+        /// <summary>
+        /// Dispose for VisualObjectsContainer
+        /// </summary>
+        [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.
+            }
+
+            base.Dispose(type);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.NUI/src/internal/Interop/Interop.VisualObject.cs b/src/Tizen.NUI/src/internal/Interop/Interop.VisualObject.cs
new file mode 100755 (executable)
index 0000000..95922aa
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright(c) 2024 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 VisualObject
+        {
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_New")]
+            public static extern global::System.IntPtr VisualObjectNew();
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_GetContainer")]
+            public static extern global::System.IntPtr GetContainer(global::System.Runtime.InteropServices.HandleRef visualObject);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_CreateVisual")]
+            public static extern void CreateVisual(global::System.Runtime.InteropServices.HandleRef visualObject, global::System.Runtime.InteropServices.HandleRef propertyMap);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_RetrieveVisualPropertyMap")]
+            public static extern void RetrieveVisualPropertyMap(global::System.Runtime.InteropServices.HandleRef visualObject, global::System.Runtime.InteropServices.HandleRef propertyMap);
+
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_DoAction_UpdatePropertyMap")]
+            public static extern void UpdateVisualPropertyMap(global::System.Runtime.InteropServices.HandleRef visualObject, global::System.Runtime.InteropServices.HandleRef propertyMap);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_DoActionWithEmptyAttributes")]
+            public static extern void DoActionWithEmptyAttributes(global::System.Runtime.InteropServices.HandleRef visualObject, int actionId);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_DoActionWithSingleIntAttributes")]
+            public static extern void DoActionWithSingleIntAttributes(global::System.Runtime.InteropServices.HandleRef visualObject, int actionId, int actionValue);
+
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_SetSiblingOrder")]
+            public static extern void SetSiblingOrder(global::System.Runtime.InteropServices.HandleRef visualObject, uint siblingOrder);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_GetSiblingOrder")]
+            public static extern uint GetSiblingOrder(global::System.Runtime.InteropServices.HandleRef visualObject);
+
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_DetachFromContainer")]
+            public static extern void Detach(global::System.Runtime.InteropServices.HandleRef visualObject);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_Raise")]
+            public static extern uint Raise(global::System.Runtime.InteropServices.HandleRef visualObject);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_Lower")]
+            public static extern uint Lower(global::System.Runtime.InteropServices.HandleRef visualObject);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_RaiseToTop")]
+            public static extern uint RaiseToTop(global::System.Runtime.InteropServices.HandleRef visualObject);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_LowerToBottom")]
+            public static extern uint LowerToBottom(global::System.Runtime.InteropServices.HandleRef visualObject);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_RaiseAbove")]
+            public static extern uint RaiseAbove(global::System.Runtime.InteropServices.HandleRef visualObject, global::System.Runtime.InteropServices.HandleRef target);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_LowerBelow")]
+            public static extern uint LowerBelow(global::System.Runtime.InteropServices.HandleRef visualObject, global::System.Runtime.InteropServices.HandleRef target);
+        }
+    }
+}
diff --git a/src/Tizen.NUI/src/internal/Interop/Interop.VisualObjectsContainer.cs b/src/Tizen.NUI/src/internal/Interop/Interop.VisualObjectsContainer.cs
new file mode 100755 (executable)
index 0000000..865b4e6
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright(c) 2024 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 VisualObjectsContainer
+        {
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_ContainerRangeTypeBackgroundEffectGet")]
+            public static extern int ContainerRangeTypeBackgroundEffectGet();
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_ContainerRangeTypeBackgroundGet")]
+            public static extern int ContainerRangeTypeBackgroundGet();
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_ContainerRangeTypeContentGet")]
+            public static extern int ContainerRangeTypeContentGet();
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_ContainerRangeTypeDecorationGet")]
+            public static extern int ContainerRangeTypeDecorationGet();
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_ContainerRangeTypeForegroundEffectGet")]
+            public static extern int ContainerRangeTypeForegroundEffectGet();
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_new_VisualObjectsContainer__SWIG_0")]
+            public static extern global::System.IntPtr NewVisualObjectsContainer();
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_VisualObjectsContainer")]
+            public static extern void DeleteVisualObjectsContainer(global::System.Runtime.InteropServices.HandleRef container);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_New")]
+            public static extern global::System.IntPtr VisualObjectsContainerNew(global::System.Runtime.InteropServices.HandleRef view, int rangeType);
+
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_GetOwner")]
+            public static extern global::System.IntPtr GetOwner(global::System.Runtime.InteropServices.HandleRef container);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_GetContainerRangeType")]
+            public static extern int GetContainerRangeType(global::System.Runtime.InteropServices.HandleRef container);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_GetVisualObjectsCount")]
+            public static extern uint GetVisualObjectsCount(global::System.Runtime.InteropServices.HandleRef container);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_GetVisualObjectAt")]
+            public static extern global::System.IntPtr GetVisualObjectAt(global::System.Runtime.InteropServices.HandleRef container, uint index);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_AddVisualObject")]
+            [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)]
+            public static extern bool AddVisualObject(global::System.Runtime.InteropServices.HandleRef container, global::System.Runtime.InteropServices.HandleRef viewObject);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_RemoveVisualObject")]
+            public static extern void RemoveVisualObject(global::System.Runtime.InteropServices.HandleRef container, global::System.Runtime.InteropServices.HandleRef viewObject);
+        }
+    }
+}
index 206cc9acdfa02e55e4fd8bd329ca80b909ea8ecb..ea3b60554fe941b9d7855fc55dd283821378e466 100755 (executable)
@@ -1425,6 +1425,15 @@ namespace Tizen.NUI.BaseComponents
             internalCurrentScreenPosition?.Dispose();
             internalCurrentScreenPosition = null;
 
+            if (visualContainers != null)
+            {
+                foreach (var visualContainer in visualContainers)
+                {
+                    visualContainer?.Dispose();
+                }
+                visualContainers = null;
+            }
+
             if (type == DisposeTypes.Explicit)
             {
                 //Called by User
diff --git a/src/Tizen.NUI/src/public/BaseComponents/ViewVisuals.cs b/src/Tizen.NUI/src/public/BaseComponents/ViewVisuals.cs
new file mode 100755 (executable)
index 0000000..99ee999
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Copyright(c) 2024 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 System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.BaseComponents
+{
+    /// <summary>
+    /// View is the base class for all views.
+    /// </summary>
+    /// <since_tizen> 3 </since_tizen>
+    public partial class View
+    {
+        #region Internal and Private
+        private List<Tizen.NUI.Visuals.VisualObjectsContainer> visualContainers = null;
+
+        /// <summary>
+        /// Range of visual for the container.
+        /// </summary>
+        internal struct ContainerRangeType
+        {
+            /// <summary>
+            /// Visual will be rendered under the shadow.
+            /// </summary>
+            internal static readonly int Shadow = Interop.VisualObjectsContainer.ContainerRangeTypeBackgroundEffectGet();
+
+            /// <summary>
+            /// Visual will be rendered under the background.
+            /// </summary>
+            internal static readonly int Background = Interop.VisualObjectsContainer.ContainerRangeTypeBackgroundGet();
+
+            /// <summary>
+            /// Visual will be rendered under the content.
+            /// It is default value.
+            /// </summary>
+            internal static readonly int Content = Interop.VisualObjectsContainer.ContainerRangeTypeContentGet();
+
+            /// <summary>
+            /// Visual will be rendered under the decoration.
+            /// </summary>
+            internal static readonly int Decoration = Interop.VisualObjectsContainer.ContainerRangeTypeDecorationGet();
+
+            /// <summary>
+            /// Visual will be rendered above the foreground effect.
+            /// </summary>
+            internal static readonly int ForegroundEffect = Interop.VisualObjectsContainer.ContainerRangeTypeForegroundEffectGet();
+        };
+        #endregion
+
+        #region Public Methods
+        /// <summary>
+        /// Add a Tizen.NUI.Visuals.VisualBase to the view.
+        /// </summary>
+        /// <remarks>
+        /// The visual is added to the top of the visuals.
+        /// If the container cannot add more than maxium count of visuals
+        /// or the visual is already added, It will be ignored.
+        ///
+        /// If input visual already added to another view,
+        /// visual will be detached from old view and added to this view.
+        /// </remarks>
+        /// <param name="visualBase">The visual to add.</param>
+        /// <returns>True if the visual was added successfully, false otherwise.</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool AddVisual(Tizen.NUI.Visuals.VisualBase visualBase)
+        {
+            return AddVisualInternal(visualBase, ContainerRangeType.Content);
+        }
+
+        /// <summary>
+        /// Remove a Tizen.NUI.Visuals.VisualBase from the view.
+        /// </summary>
+        /// <remarks>
+        /// The <see cref="Tizen.NUI.Visuals.VisualBase.SiblingOrder"/> value of all other Visuals.VisualBases will be changed automatically.
+        /// </remarks>
+        /// <param name="visualBase">The visual to remove.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void RemoveVisual(Tizen.NUI.Visuals.VisualBase visualBase)
+        {
+            if (visualContainers != null)
+            {
+                foreach (var visualContainer in visualContainers)
+                {
+                    visualContainer?.RemoveVisualObject(visualBase);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Get a Tizen.NUI.Visuals.VisualBase by sibling index
+        /// </summary>
+        /// <returns>Get visual base by sibling index</returns>
+        /// <exception cref="InvalidOperationException"> Thrown when index is out of bounds. </exception>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Tizen.NUI.Visuals.VisualBase GetVisualAt(uint index)
+        {
+            return GetVisualAtInternal(index, ContainerRangeType.Content);
+        }
+
+        /// <summary>
+        /// Get total number of Tizen.NUI.Visuals.VisualBase which we added using <see cref="AddVisual"/>.
+        /// </summary>
+        /// <returns>Get the number of visual base.</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public uint GetVisualsCount()
+        {
+            return GetVisualsCountInternal(ContainerRangeType.Content);
+        }
+
+        /// <summary>
+        /// Find Tizen.NUI.Visuals.VisualBase by name. Given name should not be empty.
+        /// </summary>
+        /// <returns>Get the visual base.</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Visuals.VisualBase FindVisualByName(string name)
+        {
+            Visuals.VisualBase ret = null;
+            if (visualContainers != null)
+            {
+                foreach (var visualContainer in visualContainers)
+                {
+                    if (visualContainer != null)
+                    {
+                        ret = visualContainer.FindVisualObjectByName(name);
+                        if (ret != null)
+                        {
+                            break;
+                        }
+                    }
+                }
+            }
+            return ret;
+        }
+        #endregion
+
+        #region Internal Method
+        internal bool AddVisualInternal(Tizen.NUI.Visuals.VisualBase visualBase, int rangeType)
+        {
+            var visualContainer = EnsureVisualContainer(rangeType);
+            return visualContainer.AddVisualObject(visualBase);
+        }
+
+        internal Tizen.NUI.Visuals.VisualBase GetVisualAtInternal(uint index, int rangeType)
+        {
+            if (index >= GetVisualsCountInternal(rangeType))
+            {
+                throw new InvalidOperationException($"Index {index} is out of bounds. Bound is {GetVisualsCountInternal(rangeType)}");
+            }
+            var visualContainer = EnsureVisualContainer(rangeType);
+            return visualContainer[index];
+        }
+
+        internal uint GetVisualsCountInternal(int rangeType)
+        {
+            uint ret = 0;
+            if (visualContainers != null)
+            {
+                foreach (var visualContainer in visualContainers)
+                {
+                    if (visualContainer != null && visualContainer.GetContainerRangeType() == rangeType)
+                    {
+                        ret = visualContainer.GetVisualObjectsCount();
+                        break;
+                    }
+                }
+            }
+            return ret;
+        }
+
+        private Tizen.NUI.Visuals.VisualObjectsContainer EnsureVisualContainer(int rangeType)
+        {
+            if (visualContainers == null)
+            {
+                visualContainers = new List<Tizen.NUI.Visuals.VisualObjectsContainer>();
+            }
+
+            foreach (var visualContainer in visualContainers)
+            {
+                if (visualContainer != null && visualContainer.GetContainerRangeType() == rangeType)
+                {
+                    return visualContainer;
+                }
+            }
+
+            var newContainer = new Tizen.NUI.Visuals.VisualObjectsContainer(this, rangeType);
+            visualContainers.Add(newContainer);
+            return newContainer;
+        }
+        #endregion
+    }
+}
index 5dc953a292bdb8b669feec5c11128666bf08c6e9..b37e30b483dacadf9274d4eb9890c349b367b33e 100755 (executable)
@@ -99,10 +99,7 @@ namespace Tizen.NUI
             }
             set
             {
-                using (PropertyKey pKey = new PropertyKey(key))
-                {
-                    SetValue(pKey, value);
-                }
+                SetValue(key, value);
             }
         }
 
@@ -121,10 +118,7 @@ namespace Tizen.NUI
             }
             set
             {
-                using (PropertyKey pKey = new PropertyKey(key))
-                {
-                    SetValue(pKey, value);
-                }
+                SetValue(key, value);
             }
         }
 
@@ -277,6 +271,17 @@ namespace Tizen.NUI
             return isRemoved;
         }
 
+        /// <summary>
+        /// Removes the element by the specified integer key.
+        /// </summary>
+        /// <param name="key">The index key to find.</param>
+        /// <returns>True if the element is removed, false otherwise.</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool Remove(int key)
+        {
+            return Interop.PropertyMap.Remove(SwigCPtr, key);
+        }
+
         /// <summary>
         /// Determines whether the PropertyMap contains the specified key.
         /// </summary>
@@ -416,7 +421,19 @@ namespace Tizen.NUI
             {
                 Interop.PropertyMap.SetValueStringKey(SwigCPtr, key.StringKey, PropertyValue.getCPtr(value));
             }
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        internal void SetValue(int key, PropertyValue value)
+        {
+            Interop.PropertyMap.SetValueIntKey(SwigCPtr, key, PropertyValue.getCPtr(value));
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        internal void SetValue(string key, PropertyValue value)
+        {
+            Interop.PropertyMap.SetValueStringKey(SwigCPtr, key, PropertyValue.getCPtr(value));
+            NDalicPINVOKE.ThrowExceptionIfExists();
         }
 
         /// This will not be public opened.
index c73700f474490e93ba09b0bf9d0cc1996140e1b1..e80aa64f4d6ed5756aa497e337cfa1436f6ec01b 100755 (executable)
@@ -329,6 +329,11 @@ namespace Tizen.NUI
         /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
         FitWidth,
+        /// <summary>
+        /// The visual should not use fitting mode.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        DontCare,
     }
 
     /// <summary>
diff --git a/src/Tizen.NUI/src/public/Visuals/VisualObject/AdvancedTextVisual.cs b/src/Tizen.NUI/src/public/Visuals/VisualObject/AdvancedTextVisual.cs
new file mode 100644 (file)
index 0000000..c6b53e9
--- /dev/null
@@ -0,0 +1,124 @@
+// Copyright (c) 2024 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.
+//
+
+extern alias TizenSystemSettings;
+using TizenSystemSettings.Tizen.System;
+
+using System.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Linq;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Visuals
+{
+    /// <summary>
+    /// The text visual with advanced options.
+    /// </summary>
+    /// <remarks>
+    /// It will be used when we want to control TextVisual with more options.
+    /// This visual allow to translated text with SID.
+    /// </remarks>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class AdvancedTextVisual : Visuals.TextVisual
+    {
+        #region Internal
+        private string textLabelSid = null;
+
+        private static Tizen.NUI.SystemLocaleLanguageChanged systemLocaleLanguageChanged = new Tizen.NUI.SystemLocaleLanguageChanged();
+        private bool hasSystemLanguageChanged = false;
+        #endregion
+
+        #region Constructor
+        public AdvancedTextVisual() : base()
+        {
+        }
+        #endregion
+
+        #region Visual Properties
+        /// <summary>
+        /// The TranslatableText property.<br />
+        /// The text can set the SID value.<br />
+        /// </summary>
+        /// <exception cref='global::System.ArgumentNullException'>
+        /// ResourceManager about multilingual is null.
+        /// </exception>
+        public string TranslatableText
+        {
+            get
+            {
+                return textLabelSid;
+            }
+            set
+            {
+                if (NUIApplication.MultilingualResourceManager == null)
+                {
+                    throw new global::System.ArgumentNullException(null, "ResourceManager about multilingual is null");
+                }
+                string translatableText = null;
+                textLabelSid = value;
+                translatableText = NUIApplication.MultilingualResourceManager?.GetString(textLabelSid, new global::System.Globalization.CultureInfo(SystemSettings.LocaleLanguage.Replace("_", "-")));
+
+                if (translatableText != null)
+                {
+                    Text = translatableText;
+                    if (hasSystemLanguageChanged == false)
+                    {
+                        systemLocaleLanguageChanged.Add(SystemSettingsLocaleLanguageChanged);
+                        hasSystemLanguageChanged = true;
+                    }
+                }
+                else
+                {
+                    Text = value;
+                }
+            }
+        }
+        #endregion
+
+        #region Internal Method
+        private void SystemSettingsLocaleLanguageChanged(object sender, LocaleLanguageChangedEventArgs e)
+        {
+            string translatableText = null;
+            translatableText = NUIApplication.MultilingualResourceManager?.GetString(textLabelSid, new global::System.Globalization.CultureInfo(e.Value.Replace("_", "-")));
+            if (translatableText != null)
+            {
+                Text = translatableText;
+            }
+            else
+            {
+                Tizen.Log.Error("NUI", $"Fail to get translated text : {textLabelSid};");
+                Text = textLabelSid;
+            }
+        }
+
+        /// <inheritdoc/>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override void Dispose(DisposeTypes type)
+        {
+            if (Disposed)
+            {
+                return;
+            }
+
+            if (hasSystemLanguageChanged)
+            {
+                systemLocaleLanguageChanged.Remove(SystemSettingsLocaleLanguageChanged);
+            }
+
+            base.Dispose(type);
+        }
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.NUI/src/public/Visuals/VisualObject/AnimatedImageVisual.cs b/src/Tizen.NUI/src/public/Visuals/VisualObject/AnimatedImageVisual.cs
new file mode 100644 (file)
index 0000000..3875bc5
--- /dev/null
@@ -0,0 +1,296 @@
+// Copyright (c) 2024 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 System.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Linq;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Visuals
+{
+    /// <summary>
+    /// The visual which can display and control an animated image resource.
+    /// We can also set image sequences by using ResourceUrlList and FrameDelay property.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class AnimatedImageVisual : ImageVisual
+    {
+        #region Internal And Private
+        internal static readonly int ActionPlay = Tizen.NUI.BaseComponents.ImageView.ActionPlay;
+        internal static readonly int ActionPause = Tizen.NUI.BaseComponents.ImageView.ActionPause;
+        internal static readonly int ActionStop = Tizen.NUI.BaseComponents.ImageView.ActionStop;
+
+        internal static readonly int ActionJumpTo = Tizen.NUI.BaseComponents.AnimatedImageView.ActionJumpTo;
+
+        private List<string> resourceUrls = null;
+        #endregion
+
+        #region Constructor
+        /// <summary>
+        /// Creates an visual object.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AnimatedImageVisual() : this(Interop.VisualObject.VisualObjectNew(), true)
+        {
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        internal AnimatedImageVisual(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
+        {
+        }
+
+        internal AnimatedImageVisual(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
+        {
+            Type = (int)Tizen.NUI.Visual.Type.AnimatedImage;
+        }
+        #endregion
+
+        #region Visual Properties
+        /// <summary>
+        /// Gets and Sets the url list in the AnimatedImageVisual.
+        /// </summary>
+        /// <remarks>
+        /// If we set ResourceUrlList as non-null, ImageVisual.ResourceUrl will be ignored.
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public List<string> ResourceUrlList
+        {
+            get
+            {
+                return resourceUrls;
+            }
+            set
+            {
+                resourceUrls = value;
+
+                // Always request to create new visual
+                visualCreationRequiredFlag = true;
+                ReqeustProcessorOnceEvent();
+            }
+        }
+
+        /// <summary>
+        /// The number of milliseconds between each frame in the Image-Array animation.
+        /// </summary>
+        /// <remarks>
+        /// This is only used when ResourceUrlList(multiple string) are provided.
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int FrameDelay
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.FrameDelay, new PropertyValue(value));
+            }
+            get
+            {
+                int ret = 100;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.FrameDelay);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Gets and sets the number of times the AnimatedImageVisual will be looped.
+        /// The default is -1. If the number is less than 0 then it loops unlimited,otherwise loop loopCount times.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int LoopCount
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.LoopCount, new PropertyValue(value));
+            }
+            get
+            {
+                int ret = -1;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.LoopCount);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Sets or gets the stop behavior.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Tizen.NUI.BaseComponents.AnimatedImageView.StopBehaviorType StopBehavior
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.StopBehavior, new PropertyValue((int)value));
+            }
+            get
+            {
+                int ret = (int)Tizen.NUI.BaseComponents.AnimatedImageView.StopBehaviorType.CurrentFrame;
+                var propertyValue = GetVisualProperty((int)Tizen.NUI.ImageVisualProperty.StopBehavior);
+                propertyValue?.Get(out ret);
+                return (Tizen.NUI.BaseComponents.AnimatedImageView.StopBehaviorType)ret;
+            }
+        }
+
+        /// <summary>
+        /// Get the number of total frames.
+        /// Or -1 if image is invalid, or not loaded yet.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int TotalFrame
+        {
+            get
+            {
+                // Sync as current properties
+                UpdateVisualPropertyMap();
+
+                int ret = -1;
+                var propertyValue = GetCurrentVisualProperty((int)Tizen.NUI.ImageVisualProperty.TotalFrameNumber);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Set or get the current frame. When setting a specific frame, it is displayed as a still image.
+        /// </summary>
+        /// <remarks>
+        /// Gets the value set by a user. If the setting value is out-ranged, it is reset as a minimum frame or a maximum frame.
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int CurrentFrame
+        {
+            set
+            {
+                // Sync as current properties
+                UpdateVisualPropertyMap();
+
+                Interop.VisualObject.DoActionWithSingleIntAttributes(SwigCPtr, ActionJumpTo, value);
+            }
+            get
+            {
+                // Sync as current properties
+                UpdateVisualPropertyMap();
+
+                int ret = -1;
+                var propertyValue = GetCurrentVisualProperty((int)Tizen.NUI.ImageVisualProperty.CurrentFrameNumber);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Gets and Sets the batch size for pre-loading images in the AnimatedImageVisual. (Advanced)
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int BatchSize
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.BatchSize, new PropertyValue(value));
+            }
+            get
+            {
+                int ret = 1;
+                var propertyValue = GetVisualProperty((int)Tizen.NUI.ImageVisualProperty.BatchSize);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Gets and Sets the cache size for loading images in the AnimatedImageVisual. (Advanced)
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int CacheSize
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.CacheSize, new PropertyValue(value));
+            }
+            get
+            {
+                int ret = 1;
+                var propertyValue = GetVisualProperty((int)Tizen.NUI.ImageVisualProperty.CacheSize);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+        #endregion
+
+        #region Public Methods
+        /// <summary>
+        /// Play the animated image.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Play()
+        {
+            // Sync as current properties
+            UpdateVisualPropertyMap();
+
+            Interop.VisualObject.DoActionWithEmptyAttributes(SwigCPtr, ActionPlay);
+        }
+
+        /// <summary>
+        /// Pause the animated image.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Pause()
+        {
+            // Sync as current properties
+            UpdateVisualPropertyMap();
+
+            Interop.VisualObject.DoActionWithEmptyAttributes(SwigCPtr, ActionPause);
+        }
+
+        /// <summary>
+        /// Stop the animated image.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Stop()
+        {
+            // Sync as current properties
+            UpdateVisualPropertyMap();
+
+            Interop.VisualObject.DoActionWithEmptyAttributes(SwigCPtr, ActionStop);
+        }
+        #endregion
+
+        #region Internal Methods
+        internal override void OnUpdateVisualPropertyMap()
+        {
+            if (resourceUrls != null && resourceUrls.Count > 0)
+            {
+                using var urlArray = new PropertyArray();
+                foreach (var url in resourceUrls)
+                {
+                    urlArray.Add(new PropertyValue(url));
+                }
+                using var urlArrayValue = new PropertyValue(urlArray);
+
+                if (cachedVisualPropertyMap != null)
+                {
+                    // Remove ResourceUrl from cachedVisualPropertyMap
+                    cachedVisualPropertyMap.Remove((int)Tizen.NUI.ImageVisualProperty.URL);
+                    cachedVisualPropertyMap.Add((int)Tizen.NUI.ImageVisualProperty.URL, urlArrayValue);
+                }
+            }
+            else
+            {
+                // If we don't use image sequence, follow the ImageVisual logic.
+                base.OnUpdateVisualPropertyMap();
+            }
+        }
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.NUI/src/public/Visuals/VisualObject/BorderVisual.cs b/src/Tizen.NUI/src/public/Visuals/VisualObject/BorderVisual.cs
new file mode 100644 (file)
index 0000000..4518645
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright (c) 2024 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 System.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Linq;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Visuals
+{
+    /// <summary>
+    /// Simple visual to render a solid border.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class BorderVisual : VisualBase
+    {
+        #region Constructor
+        /// <summary>
+        /// Creates an visual object.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public BorderVisual() : this(Interop.VisualObject.VisualObjectNew(), true)
+        {
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        internal BorderVisual(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
+        {
+        }
+
+        internal BorderVisual(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
+        {
+            Type = (int)Tizen.NUI.Visual.Type.Border;
+        }
+        #endregion
+
+        #region Visual Properties
+        /// <summary>
+        /// Gets or sets the color of the border.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Tizen.NUI.Color BorderColor
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.BorderVisualProperty.Color, new PropertyValue(value));
+            }
+            get
+            {
+                Tizen.NUI.Color ret = new Tizen.NUI.Color();
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.BorderVisualProperty.Color);
+                propertyValue?.Get(ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the width of the border (in pixels).
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float BorderWidth
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.BorderVisualProperty.Size, new PropertyValue(value));
+            }
+            get
+            {
+                float ret = 0.0f;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.BorderVisualProperty.Size);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets whether the anti-aliasing of the border is required. default is false.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool AntiAliasing
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.BorderVisualProperty.AntiAliasing, new PropertyValue(value));
+            }
+            get
+            {
+                bool ret = false;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.BorderVisualProperty.AntiAliasing);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.NUI/src/public/Visuals/VisualObject/ColorVisual.cs b/src/Tizen.NUI/src/public/Visuals/VisualObject/ColorVisual.cs
new file mode 100644 (file)
index 0000000..9d6d8d7
--- /dev/null
@@ -0,0 +1,180 @@
+// Copyright (c) 2024 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 System.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Linq;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Visuals
+{
+    /// <summary>
+    /// Simple visual to render a solid color.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class ColorVisual : VisualBase
+    {
+        #region Constructor
+        /// <summary>
+        /// Creates an visual object.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public ColorVisual() : this(Interop.VisualObject.VisualObjectNew(), true)
+        {
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        internal ColorVisual(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
+        {
+        }
+
+        internal ColorVisual(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
+        {
+            Type = (int)Tizen.NUI.Visual.Type.Color;
+        }
+        #endregion
+
+        #region Visual Properties
+        /// <summary>
+        /// Blur radius for this visual
+        /// </summary>
+        /// <remarks>
+        /// This property will ignore BorderlineWidth property when we set BlurRadius property at least one time.
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float BlurRadius
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ColorVisualProperty.BlurRadius, new PropertyValue(value), false);
+            }
+            get
+            {
+                float ret = 0.0f;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ColorVisualProperty.BlurRadius);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+        #endregion
+
+        #region Decorated Visual Properties
+        /// <summary>
+        /// The radius for the rounded corners of the visual.
+        /// The values in Vector4 are used in clockwise order from top-left to bottom-left : Vector4(top-left-corner, top-right-corner, bottom-right-corner, bottom-left-corner).
+        /// Each radius will clamp internally to the half of smaller of the visual's width or height.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Vector4 CornerRadius
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.Visual.Property.CornerRadius, new PropertyValue(value), false);
+            }
+            get
+            {
+                Vector4 ret = new Vector4();
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.CornerRadius);
+                propertyValue?.Get(ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Whether the CornerRadius property value is relative (percentage [0.0f to 0.5f] of the visual size) or absolute (in world units).
+        /// It is absolute by default.
+        /// When the policy is relative, the corner radius is relative to the smaller of the visual's width and height.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public VisualTransformPolicyType CornerRadiusPolicy
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.Visual.Property.CornerRadiusPolicy, new PropertyValue((int)value), false);
+            }
+            get
+            {
+                int ret = (int)VisualTransformPolicyType.Absolute;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.CornerRadiusPolicy);
+                propertyValue?.Get(out ret);
+                return (VisualTransformPolicyType)ret;
+            }
+        }
+
+        /// <summary>
+        /// The width for the borderline of the visual.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float BorderlineWidth
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineWidth, new PropertyValue(value), false);
+            }
+            get
+            {
+                float ret = 0.0f;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineWidth);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// The color for the borderline of the visual.
+        /// It is Color.Black by default.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Color BorderlineColor
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineColor, new PropertyValue(value), false);
+            }
+            get
+            {
+                Color ret = new Color(0.0f, 0.0f, 0.0f, 1.0f);
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineColor);
+                propertyValue?.Get(ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// The Relative offset for the borderline of the visual.
+        /// Recommended range : [-1.0f to 1.0f].
+        /// If -1.0f, draw borderline inside of the visual.
+        /// If 1.0f, draw borderline outside of the visual.
+        /// If 0.0f, draw borderline half inside and half outside.
+        /// It is 0.0f by default.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float BorderlineOffset
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineOffset, new PropertyValue(value), false);
+            }
+            get
+            {
+                float ret = 0.0f;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineOffset);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.NUI/src/public/Visuals/VisualObject/ImageVisual.cs b/src/Tizen.NUI/src/public/Visuals/VisualObject/ImageVisual.cs
new file mode 100644 (file)
index 0000000..e31665a
--- /dev/null
@@ -0,0 +1,562 @@
+// Copyright (c) 2024 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 System.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Linq;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Visuals
+{
+    /// <summary>
+    /// The visual which can display an image resource.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class ImageVisual : VisualBase
+    {
+        #region Internal And Private
+        internal static readonly int ActionReload = Tizen.NUI.BaseComponents.ImageView.ActionReload;
+        internal bool isResourceUrlValid = false;
+
+        private PropertyMap temperalStoredPropertyMap = null; // To store property map when resource url is not valid.
+        #endregion
+
+        /// <summary>
+        /// Creates an visual object.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public ImageVisual() : this(Interop.VisualObject.VisualObjectNew(), true)
+        {
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        internal ImageVisual(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
+        {
+        }
+
+        internal ImageVisual(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
+        {
+            Type = (int)Tizen.NUI.Visual.Type.Image;
+        }
+
+        #region Visual Properties
+        /// <summary>
+        /// Gets or sets the URL of the image.<br />
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public string ResourceUrl
+        {
+            set
+            {
+                if(string.IsNullOrEmpty(value))
+                {
+                    isResourceUrlValid = false;
+
+                    UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.URL, null);
+
+                    // Special behavior. If ResourceUrl is empty, unregister visual, and do not show anything.
+                    UnregisterVisual();
+                }
+                else
+                {
+                    isResourceUrlValid = true;
+
+                    UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.URL, new PropertyValue(value));
+
+                    // Special case. If set GeneratedUrl, or FastTrackUploading, Create ImageVisual synchronously.
+                    if (value.StartsWith("dali://") || value.StartsWith("enbuf://") || FastTrackUploading)
+                    {
+                        UpdateVisualPropertyMap();
+                    }
+                }
+            }
+            get
+            {
+                string ret = "";
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.URL);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the image area to be displayed.<br />
+        /// It is a rectangular area.<br />
+        /// The first two elements indicate the top-left position of the area, and the last two elements are the areas of the width and the height respectively.<br />
+        /// If not specified, the default value is Vector4 (0.0, 0.0, 1.0, 1.0), i.e., the entire area of the image.<br />
+        /// For normal quad images only.<br />
+        /// Optional.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Vector4 PixelArea
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.PixelArea, new PropertyValue(value), false);
+            }
+            get
+            {
+                Vector4 ret = new Vector4(0.0f, 0.0f, 1.0f, 1.0f);
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.PixelArea);
+                propertyValue?.Get(ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// ImageView PreMultipliedAlpha, type Boolean.<br />
+        /// Image must be initialized.<br />
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool PreMultipliedAlpha
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.Visual.Property.PremultipliedAlpha, new PropertyValue(value), true);
+            }
+            get
+            {
+                bool ret = true;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.PremultipliedAlpha);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Synchronously load the image for the visual.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool SynchronousLoading
+        {
+            set
+            {
+                // Note : We need to create new visual if previous visual was async, and now we set value as sync.
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.SynchronousLoading, new PropertyValue(value), value);
+            }
+            get
+            {
+                bool ret = false;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.SynchronousLoading);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets whether to automatically correct the orientation of an image.<br />
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool OrientationCorrection
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.OrientationCorrection, new PropertyValue(value), true);
+            }
+            get
+            {
+                bool ret = true;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.OrientationCorrection);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the URL of the alpha mask.<br />
+        /// Optional.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public string AlphaMaskURL
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.AlphaMaskURL, string.IsNullOrEmpty(value) ? null : new PropertyValue(value));
+            }
+            get
+            {
+                string ret = "";
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.AlphaMaskURL);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets scale factor to apply to the content image before masking.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float MaskContentScale
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.MaskContentScale, new PropertyValue(value));
+            }
+            get
+            {
+                float ret = 1.0f;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.MaskContentScale);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        ///  Whether to crop image to mask or scale mask to fit image.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool CropToMask
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.CropToMask, new PropertyValue(value));
+            }
+            get
+            {
+                bool ret = false;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.CropToMask);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets whether to apply mask on GPU or not.<br />
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Tizen.NUI.BaseComponents.ImageView.MaskingModeType MaskingMode
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.MaskingMode, new PropertyValue((int)value));
+            }
+            get
+            {
+                int ret = (int)Tizen.NUI.BaseComponents.ImageView.MaskingModeType.MaskingOnLoading;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.MaskingMode);
+                propertyValue?.Get(out ret);
+                return (Tizen.NUI.BaseComponents.ImageView.MaskingModeType)ret;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets whether to apply fast track uploading or not.<br />
+        /// </summary>
+        /// <remarks>
+        /// If we use fast track uploading feature, It can upload texture without event-thead dependency. But also,<br />
+        ///  - Texture size is invalid until ResourceReady signal comes.<br />
+        ///  - Texture cannot be cached (We always try to load new image).<br />
+        ///  - Seamless visual change didn't supported.<br />
+        ///  - Alpha masking didn't supported. If you try, It will load as normal case.<br />
+        ///  - Synchronous loading didn't supported. If you try, It will load as normal case.<br />
+        ///  - Reload action didn't supported. If you try, It will load as normal case.<br />
+        ///  - Atlas loading didn't supported. If you try, It will load as normal case.<br />
+        ///  - Custom shader didn't supported. If you try, It will load as normal case.
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool FastTrackUploading
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.FastTrackUploading, new PropertyValue(value));
+
+                if (value && !string.IsNullOrEmpty(ResourceUrl))
+                {
+                    // Special case. If user set FastTrackUploading mean, user want to upload image As-Soon-As-Possible.
+                    // Create ImageVisual synchronously.
+                    UpdateVisualPropertyMap();
+                }
+            }
+            get
+            {
+                bool ret = false;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.FastTrackUploading);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the Image Visual release policy.<br/>
+        /// It decides if a texture should be released from the cache or kept to reduce the loading time.<br/>
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public ReleasePolicyType ReleasePolicy
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.ReleasePolicy, new PropertyValue((int)value));
+            }
+            get
+            {
+                int ret = (int)ReleasePolicyType.Detached;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.ReleasePolicy);
+                propertyValue?.Get(out ret);
+                return (ReleasePolicyType)ret;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the desired image width.<br />
+        /// If not specified, the actual image width is used.<br />
+        /// For normal quad images only.<br />
+        /// Optional.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int DesiredWidth
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.DesiredWidth, new PropertyValue(value));
+            }
+            get
+            {
+                int ret = -1;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.DesiredWidth);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the desired image height.<br />
+        /// If not specified, the actual image height is used.<br />
+        /// For normal quad images only.<br />
+        /// Optional.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int DesiredHeight
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.DesiredHeight, new PropertyValue(value));
+            }
+            get
+            {
+                int ret = -1;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.DesiredHeight);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the Image Visual image loading policy.<br />
+        /// It decides if a texture should be loaded immediately after source set or only after the visual is added to the window.<br />
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public LoadPolicyType LoadPolicy
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.LoadPolicy, new PropertyValue((int)value));
+            }
+            get
+            {
+                int ret = (int)LoadPolicyType.Attached;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.LoadPolicy);
+                propertyValue?.Get(out ret);
+                return (LoadPolicyType)ret;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the wrap mode for the u coordinate.<br />
+        /// It decides how the texture should be sampled when the u coordinate exceeds the range of 0.0 to 1.0.<br />
+        /// If not specified, the default is WrapModeType.Default(CLAMP).<br />
+        /// For normal quad images only.<br />
+        /// Optional.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public WrapModeType WrapModeU
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.WrapModeU, new PropertyValue((int)value));
+            }
+            get
+            {
+                int ret = (int)WrapModeType.Default;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.WrapModeU);
+                propertyValue?.Get(out ret);
+                return (WrapModeType)ret;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the wrap mode for the v coordinate.<br />
+        /// It decides how the texture should be sampled when the v coordinate exceeds the range of 0.0 to 1.0.<br />
+        /// The first two elements indicate the top-left position of the area, and the last two elements are the areas of the width and the height respectively.<br />
+        /// If not specified, the default is WrapModeType.Default(CLAMP).<br />
+        /// For normal quad images only.
+        /// Optional.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public WrapModeType WrapModeV
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.WrapModeV, new PropertyValue((int)value));
+            }
+            get
+            {
+                int ret = (int)WrapModeType.Default;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.WrapModeV);
+                propertyValue?.Get(out ret);
+                return (WrapModeType)ret;
+            }
+        }
+        #endregion
+
+        #region Decorated Visual Properties
+        /// <summary>
+        /// The radius for the rounded corners of the visual.
+        /// The values in Vector4 are used in clockwise order from top-left to bottom-left : Vector4(top-left-corner, top-right-corner, bottom-right-corner, bottom-left-corner).
+        /// Each radius will clamp internally to the half of smaller of the visual's width or height.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Vector4 CornerRadius
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.Visual.Property.CornerRadius, new PropertyValue(value), false);
+            }
+            get
+            {
+                Vector4 ret = new Vector4();
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.CornerRadius);
+                propertyValue?.Get(ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Whether the CornerRadius property value is relative (percentage [0.0f to 0.5f] of the visual size) or absolute (in world units).
+        /// It is absolute by default.
+        /// When the policy is relative, the corner radius is relative to the smaller of the visual's width and height.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public VisualTransformPolicyType CornerRadiusPolicy
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.Visual.Property.CornerRadiusPolicy, new PropertyValue((int)value), false);
+            }
+            get
+            {
+                int ret = (int)VisualTransformPolicyType.Absolute;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.CornerRadiusPolicy);
+                propertyValue?.Get(out ret);
+                return (VisualTransformPolicyType)ret;
+            }
+        }
+
+        /// <summary>
+        /// The width for the borderline of the visual.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float BorderlineWidth
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineWidth, new PropertyValue(value), false);
+            }
+            get
+            {
+                float ret = 0.0f;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineWidth);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// The color for the borderline of the visual.
+        /// It is Color.Black by default.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Color BorderlineColor
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineColor, new PropertyValue(value), false);
+            }
+            get
+            {
+                Color ret = new Color(0.0f, 0.0f, 0.0f, 1.0f);
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineColor);
+                propertyValue?.Get(ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// The Relative offset for the borderline of the visual.
+        /// Recommended range : [-1.0f to 1.0f].
+        /// If -1.0f, draw borderline inside of the visual.
+        /// If 1.0f, draw borderline outside of the visual.
+        /// If 0.0f, draw borderline half inside and half outside.
+        /// It is 0.0f by default.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float BorderlineOffset
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineOffset, new PropertyValue(value), false);
+            }
+            get
+            {
+                float ret = 0.0f;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineOffset);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+        #endregion
+
+        #region Public Methods
+        /// <summary>
+        /// Reload image.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Reload()
+        {
+            Interop.VisualObject.DoActionWithEmptyAttributes(SwigCPtr, ActionReload);
+        }
+        #endregion
+
+        #region Internal Methods
+        internal override void OnUpdateVisualPropertyMap()
+        {
+            // We should not create visual if url is invalid.
+            if (!isResourceUrlValid)
+            {
+                temperalStoredPropertyMap = cachedVisualPropertyMap;
+                cachedVisualPropertyMap = null;
+            }
+        }
+
+        internal override void OnVisualCreated()
+        {
+            if (temperalStoredPropertyMap != null)
+            {
+                cachedVisualPropertyMap = temperalStoredPropertyMap;
+                temperalStoredPropertyMap = null;
+            }
+        }
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.NUI/src/public/Visuals/VisualObject/NPatchVisual.cs b/src/Tizen.NUI/src/public/Visuals/VisualObject/NPatchVisual.cs
new file mode 100644 (file)
index 0000000..8ab1fb7
--- /dev/null
@@ -0,0 +1,142 @@
+// Copyright (c) 2024 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 System.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Linq;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Visuals
+{
+    /// <summary>
+    /// The visual which can display an n-patch image resource.
+    /// It will be used when we want to display n-patch image, border only n-patch, or make regular image stretched.
+    /// </summary>
+    /// <remarks>
+    /// Following ImageVisual properties are not supported in NPatchVisual.
+    /// - CornerRadius
+    /// - BorderlineWidth
+    /// - AlphaMaskUrl
+    /// </remarks>
+    /// <remarks>
+    /// We assume that the image is a n-patch image always. So it does not support other image formats, like svg, lottie.
+    /// </remarks>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class NPatchVisual : ImageVisual
+    {
+        #region Constructor
+        /// <summary>
+        /// Creates an visual object.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public NPatchVisual() : this(Interop.VisualObject.VisualObjectNew(), true)
+        {
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        internal NPatchVisual(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
+        {
+        }
+
+        internal NPatchVisual(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
+        {
+            Type = (int)Tizen.NUI.Visual.Type.NPatch;
+        }
+        #endregion
+
+        #region Visual Properties
+        /// <summary>
+        /// Gets or sets whether to draw the borders only (If true).<br />
+        /// If not specified, the default is false.<br />
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool BorderOnly
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.NpatchImageVisualProperty.BorderOnly, new PropertyValue(value));
+            }
+            get
+            {
+                bool ret = false;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.NpatchImageVisualProperty.BorderOnly);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// The border of the regular image is in the order: left, right, bottom, top.<br />
+        /// </summary>
+        /// <remarks>
+        /// Note that it is not mean the value from 9 patch image.<br />
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Rectangle Border
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.NpatchImageVisualProperty.Border, (value == null) ? null : new PropertyValue(value));
+            }
+            get
+            {
+                Rectangle ret = new Rectangle();
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.NpatchImageVisualProperty.Border);
+                propertyValue?.Get(ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Overlays the auxiliary image on top of an NPatch image.
+        /// The resulting visual image will be at least as large as the smallest possible n-patch or the auxiliary image, whichever is larger.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public string AuxiliaryImageUrl
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.AuxiliaryImageURL, string.IsNullOrEmpty(value) ? null : new PropertyValue(value));
+            }
+            get
+            {
+                string ret = "";
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.AuxiliaryImageURL);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// An alpha value for mixing between the masked main NPatch image and the auxiliary image.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float AuxiliaryImageAlpha
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.AuxiliaryImageAlpha, new PropertyValue(value));
+            }
+            get
+            {
+                float ret = 1.0f;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.AuxiliaryImageAlpha);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.NUI/src/public/Visuals/VisualObject/TextVisual.cs b/src/Tizen.NUI/src/public/Visuals/VisualObject/TextVisual.cs
new file mode 100644 (file)
index 0000000..5bcd517
--- /dev/null
@@ -0,0 +1,204 @@
+// Copyright (c) 2024 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 System.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Linq;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Visuals
+{
+    /// <summary>
+    /// The visual which can display simple text.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class TextVisual : VisualBase
+    {
+        #region Constructor
+        /// <summary>
+        /// Creates an visual object.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public TextVisual() : this(Interop.VisualObject.VisualObjectNew(), true)
+        {
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        internal TextVisual(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
+        {
+        }
+
+        internal TextVisual(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
+        {
+            Type = (int)Tizen.NUI.Visual.Type.Text;
+        }
+        #endregion
+
+        #region Visual Properties
+        /// <summary>
+        /// The Text property.<br />
+        /// The text to display in the UTF-8 format.<br />
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public string Text
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.TextVisualProperty.Text, new PropertyValue(string.IsNullOrEmpty(value) ? "" : value));
+            }
+            get
+            {
+                string ret = "";
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.TextVisualProperty.Text);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// The requested font family to use.<br />
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public string FontFamily
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.TextVisualProperty.FontFamily, new PropertyValue(string.IsNullOrEmpty(value) ? "" : value));
+            }
+            get
+            {
+                string ret = "";
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.TextVisualProperty.FontFamily);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// The size of font in points.<br />
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float PointSize
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.TextVisualProperty.PointSize, new PropertyValue(value));
+            }
+            get
+            {
+                float ret = 0.0f;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.TextVisualProperty.PointSize);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// The single-line or multi-line layout option.<br />
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool MultiLine
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.TextVisualProperty.MultiLine, new PropertyValue(value));
+            }
+            get
+            {
+                bool ret = false;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.TextVisualProperty.MultiLine);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// The line horizontal alignment.<br />
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Tizen.NUI.HorizontalAlignment HorizontalAlignment
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.TextVisualProperty.HorizontalAlignment, new PropertyValue((int)value));
+            }
+            get
+            {
+                int ret = (int)Tizen.NUI.HorizontalAlignment.Begin;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.TextVisualProperty.HorizontalAlignment);
+                propertyValue?.Get(out ret);
+                return (Tizen.NUI.HorizontalAlignment)ret;
+            }
+        }
+
+        /// <summary>
+        /// The line vertical alignment.<br />
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Tizen.NUI.VerticalAlignment VerticalAlignment
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.TextVisualProperty.VerticalAlignment, new PropertyValue((int)value));
+            }
+            get
+            {
+                int ret = (int)Tizen.NUI.VerticalAlignment.Top;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.TextVisualProperty.VerticalAlignment);
+                propertyValue?.Get(out ret);
+                return (Tizen.NUI.VerticalAlignment)ret;
+            }
+        }
+
+        /// <summary>
+        /// The color of the text.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Tizen.NUI.Color TextColor
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.TextVisualProperty.TextColor, new PropertyValue(value));
+            }
+            get
+            {
+                Tizen.NUI.Color ret = new Color(0.0f, 0.0f, 0.0f, 1.0f);
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.TextVisualProperty.TextColor);
+                propertyValue?.Get(ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Whether the mark-up processing is enabled.<br />
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool EnableMarkup
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.TextVisualProperty.EnableMarkup, new PropertyValue(value));
+            }
+            get
+            {
+                bool ret = false;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.TextVisualProperty.EnableMarkup);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.NUI/src/public/Visuals/VisualObject/VisualBase.cs b/src/Tizen.NUI/src/public/Visuals/VisualObject/VisualBase.cs
new file mode 100644 (file)
index 0000000..b82bcc0
--- /dev/null
@@ -0,0 +1,1108 @@
+// Copyright (c) 2024 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 System.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Linq;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Visuals
+{
+    /// <summary>
+    /// The base class of all visual in namespace Tizen.NUI.Visuals.
+    /// This class is abstract class. We cannot use it without type of Properties.
+    /// </summary>
+    /// <remarks>
+    /// Visual is the smallest rendering unit that application can control without custom renderer.
+    /// It will be used when we want to add a new visual to the View.
+    /// We can change the size or offset of visuals, and sibling order.
+    ///
+    /// When we change the property of visual, the visual will be recreated at end of event loop.
+    /// </remarks>
+    /// <code>
+    /// animation.AnimateTo(view, "BorderlineOffset", -1.0f);
+    /// </code>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class VisualBase : BaseHandle
+    {
+        #region Internal And Private
+        internal PropertyMap cachedVisualPropertyMap = null;
+        internal PropertyMap changedPropertyMap = null;
+
+        internal bool visualCreationRequiredFlag = true; // The first time should create visual.
+        internal bool visualUpdateRequiredFlag = false;
+
+        internal bool visualCreationManually = false;
+
+        private int internalType = (int)Tizen.NUI.Visual.Type.Invalid;
+
+        private bool visualPropertyUpdateProcessAttachedFlag = false;
+
+        private bool visualFittingModeApplied = false; // Whether we use fitting mode, or DontCare.
+
+        internal struct VisualTransformInfo
+        {
+            public float width;
+            public float height;
+            public float offsetX;
+            public float offsetY;
+
+            public VisualTransformPolicyType widthPolicy;
+            public VisualTransformPolicyType heightPolicy;
+            public VisualTransformPolicyType offsetXPolicy;
+            public VisualTransformPolicyType offsetYPolicy;
+
+            public Visual.AlignType origin;
+            public Visual.AlignType pivotPoint;
+
+            public float extraWidth;
+            public float extraHeight;
+
+            public PropertyMap cachedVisualTransformPropertyMap;
+
+            internal bool changed;
+            
+            public void Clear()
+            {
+                width = 1.0f;
+                height = 1.0f;
+                offsetX = 0.0f;
+                offsetY = 0.0f;
+
+                widthPolicy = VisualTransformPolicyType.Relative;
+                heightPolicy = VisualTransformPolicyType.Relative;
+                offsetXPolicy = VisualTransformPolicyType.Relative;
+                offsetYPolicy = VisualTransformPolicyType.Relative;
+
+                origin = Visual.AlignType.TopBegin;
+                pivotPoint = Visual.AlignType.TopBegin;
+
+                extraWidth = 0.0f;
+                extraHeight = 0.0f;
+
+                cachedVisualTransformPropertyMap = null;
+
+                changed = true;
+            }
+
+            internal void ConvertToPropertyMap()
+            {
+                if (cachedVisualTransformPropertyMap == null)
+                {
+                    cachedVisualTransformPropertyMap = new PropertyMap();
+                }
+
+                cachedVisualTransformPropertyMap.Clear();
+                cachedVisualTransformPropertyMap.Add((int)VisualTransformPropertyType.Size, new PropertyValue(new Vector2(width, height)))
+                                                .Add((int)VisualTransformPropertyType.Offset, new PropertyValue(new Vector2(offsetX, offsetY)))
+                                                .Add((int)VisualTransformPropertyType.SizePolicy, new PropertyValue(new Vector2((float)widthPolicy, (float)heightPolicy)))
+                                                .Add((int)VisualTransformPropertyType.OffsetPolicy, new PropertyValue(new Vector2((float)offsetXPolicy, (float)offsetYPolicy)))
+                                                .Add((int)VisualTransformPropertyType.Origin, new PropertyValue((int)origin))
+                                                .Add((int)VisualTransformPropertyType.AnchorPoint, new PropertyValue((int)pivotPoint))
+                                                .Add((int)VisualTransformPropertyType.ExtraSize, new PropertyValue(new Vector2(extraWidth, extraHeight)));
+            }
+
+            internal void ConvertFromPropertyMap(PropertyMap inputMap)
+            {
+                PropertyValue value = null;
+
+                if ((value = inputMap?.Find((int)VisualTransformPropertyType.Size)) != null)
+                {
+                    using var size = new Size();
+                    if (value.Get(size))
+                    {
+                        width = size.Width;
+                        height = size.Height;
+                    }
+                }
+                if ((value = inputMap?.Find((int)VisualTransformPropertyType.Offset)) != null)
+                {
+                    using var offset = new Position();
+                    if (value.Get(offset))
+                    {
+                        offsetX = offset.X;
+                        offsetY = offset.Y;
+                    }
+                }
+                if ((value = inputMap?.Find((int)VisualTransformPropertyType.SizePolicy)) != null)
+                {
+                    using var policyValue = new Vector2();
+                    if (value.Get(policyValue))
+                    {
+                        widthPolicy = (VisualTransformPolicyType)policyValue.X;
+                        heightPolicy = (VisualTransformPolicyType)policyValue.Y;
+                    }
+                }
+                if ((value = inputMap?.Find((int)VisualTransformPropertyType.OffsetPolicy)) != null)
+                {
+                    using var policyValue = new Vector2();
+                    if (value.Get(policyValue))
+                    {
+                        offsetXPolicy = (VisualTransformPolicyType)policyValue.X;
+                        offsetYPolicy = (VisualTransformPolicyType)policyValue.Y;
+                    }
+                }
+                if ((value = inputMap?.Find((int)VisualTransformPropertyType.Origin)) != null)
+                {
+                    int ret = 0;
+                    if (value.Get(out ret))
+                    {
+                        origin = (Visual.AlignType)ret;
+                    }
+                }
+                if ((value = inputMap?.Find((int)VisualTransformPropertyType.AnchorPoint)) != null)
+                {
+                    int ret = 0;
+                    if (value.Get(out ret))
+                    {
+                        pivotPoint = (Visual.AlignType)ret;
+                    }
+                }
+                if ((value = inputMap?.Find((int)VisualTransformPropertyType.ExtraSize)) != null)
+                {
+                    using var extraValue = new Vector2();
+                    if (value.Get(extraValue))
+                    {
+                        extraWidth = extraValue.Width;
+                        extraHeight = extraValue.Height;
+                    }
+                }
+                value?.Dispose();
+            }
+        };
+        internal VisualTransformInfo transformInfo;
+        #endregion
+
+        #region Constructor
+        /// <summary>
+        /// Creates an visual object.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public VisualBase() : this(Interop.VisualObject.VisualObjectNew(), true)
+        {
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        internal VisualBase(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
+        {
+        }
+
+        internal VisualBase(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
+        {
+            transformInfo.Clear();
+        }
+        #endregion
+
+        #region Enum
+        /// <summary>
+        /// The update mode of this VisualBase property.
+        /// Default is Auto.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public enum PropertyUpdateModeType
+        {
+            /// <summary>
+            /// Update property automatically, by NUI event loop.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            Auto,
+            /// <summary>
+            /// Update property manually.
+            /// Need to call <see cref="UpdateProperty"/> function manually to update property.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            Manual,
+        }
+        #endregion
+
+        #region Properties
+        /// <summary>
+        /// Sibling order of this VisualBase.
+        /// </summary>
+        /// <remarks>
+        /// The sibling order is used to determine the draw order of the visuals.
+        /// The visuals with smaller sibling order are drawn bottom,
+        /// and the visuals with larger sibling order are drawn top.
+        ///
+        /// It will be changed automatically when the visuals are added to the view.
+        /// The default value is 0.
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public uint SiblingOrder
+        {
+            set
+            {
+                Interop.VisualObject.SetSiblingOrder(SwigCPtr, value);
+                NDalicPINVOKE.ThrowExceptionIfExists();
+            }
+            get
+            {
+                uint ret = Interop.VisualObject.GetSiblingOrder(SwigCPtr);
+                NDalicPINVOKE.ThrowExceptionIfExists();
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Type of this VisualObject. It will be set at construction time.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int Type
+        {
+            internal set
+            {
+                if(internalType != value)
+                {
+                    internalType = value;
+                    UpdateVisualProperty((int)Tizen.NUI.Visual.Property.Type, new PropertyValue(value), true);
+                }
+            }
+            get
+            {
+                return internalType;
+            }
+        }
+
+        /// <summary>
+        /// Name of the visual.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public string Name { get; set; }
+
+        /// <summary>
+        /// The way of visual property update.
+        /// Default is PropertyUpdateModeType.Auto.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public PropertyUpdateModeType PropertyUpdateMode
+        {
+            set
+            {
+                visualCreationManually = (value == PropertyUpdateModeType.Manual);
+            }
+            get
+            {
+                return visualCreationManually ? PropertyUpdateModeType.Manual : PropertyUpdateModeType.Auto;
+            }
+        }
+        #endregion
+
+        #region Visual Properties
+        /// <summary>
+        /// Color for the visual. Default color is White
+        /// </summary>
+        /// <remarks>
+        /// This is exclusive with the Opacity property.
+        /// Opacity property be applied as Color.A.
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Tizen.NUI.Color Color
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.Visual.Property.MixColor, new PropertyValue(value), false);
+
+                // warning : We should set cached Opacity after set MixColor.
+                UpdateVisualProperty((int)Tizen.NUI.Visual.Property.Opacity, new PropertyValue(value.A), false);
+            }
+            get
+            {
+                Tizen.NUI.Color ret = new Tizen.NUI.Color(1.0f, 1.0f, 1.0f, 1.0f);
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.MixColor);
+                propertyValue?.Get(ret);
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Opacity for the visual.
+        /// </summary>
+        /// <remarks>
+        /// This is exclusive with the Color property.
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float Opacity
+        {
+            set
+            {
+                UpdateVisualProperty((int)Tizen.NUI.Visual.Property.Opacity, new PropertyValue(value), false);
+            }
+            get
+            {
+                float ret = 1.0f;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.Opacity);
+                propertyValue?.Get(out ret);
+                return ret;
+            }
+        }
+        #endregion
+
+        #region Visual Transform Properties
+        /// <summary>
+        /// FittingMode for the visual.
+        /// </summary>
+        /// <remarks>
+        /// The fitting mode is used to decide how the visual should be fitted to the control area.
+        /// The default value is VisualFittingModeType.DontCare.
+        /// If user set one of Transform property, it will be set as VisualFittingModeType.DontCare automatically.
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public VisualFittingModeType FittingMode
+        {
+            set
+            {
+                if (value != VisualFittingModeType.DontCare)
+                {
+                    visualFittingModeApplied = true;
+                }
+                else
+                {
+                    visualFittingModeApplied = false;
+                }
+                UpdateVisualProperty((int)Tizen.NUI.Visual.Property.VisualFittingMode, new PropertyValue((int)value));
+            }
+            get
+            {
+                int ret = (int)VisualFittingModeType.DontCare;
+                var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.VisualFittingMode);
+                propertyValue?.Get(out ret);
+                return (VisualFittingModeType)ret;
+            }
+        }
+
+        /// <summary>
+        /// Width of the visual.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float Width
+        {
+            set
+            {
+                if (visualFittingModeApplied)
+                {
+                    FittingMode = VisualFittingModeType.DontCare;
+                }
+                if (transformInfo.width != value)
+                {
+                    transformInfo.width = value;
+                    TransformPropertyChanged();
+                }
+            }
+            get
+            {
+                return transformInfo.width;
+            }
+        }
+
+        /// <summary>
+        /// Height of the visual.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float Height
+        {
+            set
+            {
+                if (visualFittingModeApplied)
+                {
+                    FittingMode = VisualFittingModeType.DontCare;
+                }
+                if (transformInfo.height != value)
+                {
+                    transformInfo.height = value;
+                    TransformPropertyChanged();
+                }
+            }
+            get
+            {
+                return transformInfo.height;
+            }
+        }
+
+        /// <summary>
+        /// Policy of width.
+        /// If it is Relative, The width will be relative by the View's width.
+        /// If it is Absolute, The width will be used as the absolute Width value.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public VisualTransformPolicyType WidthPolicy
+        {
+            set
+            {
+                if (visualFittingModeApplied)
+                {
+                    FittingMode = VisualFittingModeType.DontCare;
+                }
+                if (transformInfo.widthPolicy != value)
+                {
+                    transformInfo.widthPolicy = value;
+                    TransformPropertyChanged();
+                }
+            }
+            get
+            {
+                return transformInfo.widthPolicy;
+            }
+        }
+
+        /// <summary>
+        /// Policy of height.
+        /// If it is Relative, The height will be relative by the View's height.
+        /// If it is Absolute, The height will be used as the absolute Height value.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public VisualTransformPolicyType HeightPolicy
+        {
+            set
+            {
+                if (visualFittingModeApplied)
+                {
+                    FittingMode = VisualFittingModeType.DontCare;
+                }
+                if (transformInfo.heightPolicy != value)
+                {
+                    transformInfo.heightPolicy = value;
+                    TransformPropertyChanged();
+                }
+            }
+            get
+            {
+                return transformInfo.heightPolicy;
+            }
+        }
+
+        /// <summary>
+        /// OffsetX of the visual.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float OffsetX
+        {
+            set
+            {
+                if (visualFittingModeApplied)
+                {
+                    FittingMode = VisualFittingModeType.DontCare;
+                }
+                if (transformInfo.offsetX != value)
+                {
+                    transformInfo.offsetX = value;
+                    TransformPropertyChanged();
+                }
+            }
+            get
+            {
+                return transformInfo.offsetX;
+            }
+        }
+
+        /// <summary>
+        /// OffsetY of the visual.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float OffsetY
+        {
+            set
+            {
+                if (visualFittingModeApplied)
+                {
+                    FittingMode = VisualFittingModeType.DontCare;
+                }
+                if (transformInfo.offsetY != value)
+                {
+                    transformInfo.offsetY = value;
+                    TransformPropertyChanged();
+                }
+            }
+            get
+            {
+                return transformInfo.offsetY;
+            }
+        }
+
+        /// <summary>
+        /// Policy of offsetX.
+        /// If it is Relative, The offsetX will be relative by the View's width.
+        /// If it is Absolute, The offsetX will be used as the absolute OffsetX value.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public VisualTransformPolicyType OffsetXPolicy
+        {
+            set
+            {
+                if (visualFittingModeApplied)
+                {
+                    FittingMode = VisualFittingModeType.DontCare;
+                }
+                if (transformInfo.offsetXPolicy != value)
+                {
+                    transformInfo.offsetXPolicy = value;
+                    TransformPropertyChanged();
+                }
+            }
+            get
+            {
+                return transformInfo.offsetXPolicy;
+            }
+        }
+
+        /// <summary>
+        /// Policy of offsetY.
+        /// If it is Relative, The offsetY will be relative by the View's height.
+        /// If it is Absolute, The offsetY will be used as the absolute OffsetY value.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public VisualTransformPolicyType OffsetYPolicy
+        {
+            set
+            {
+                if (visualFittingModeApplied)
+                {
+                    FittingMode = VisualFittingModeType.DontCare;
+                }
+                if (transformInfo.offsetYPolicy != value)
+                {
+                    transformInfo.offsetYPolicy = value;
+                    TransformPropertyChanged();
+                }
+            }
+            get
+            {
+                return transformInfo.offsetYPolicy;
+            }
+        }
+
+        /// <summary>
+        /// Origin of the visual from view.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Visual.AlignType Origin
+        {
+            set
+            {
+                if (visualFittingModeApplied)
+                {
+                    FittingMode = VisualFittingModeType.DontCare;
+                }
+                if (transformInfo.origin != value)
+                {
+                    transformInfo.origin = value;
+                    TransformPropertyChanged();
+                }
+            }
+            get
+            {
+                return transformInfo.origin;
+            }
+        }
+
+        /// <summary>
+        /// Pivot point of the visual from view.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Visual.AlignType PivotPoint
+        {
+            set
+            {
+                if (visualFittingModeApplied)
+                {
+                    FittingMode = VisualFittingModeType.DontCare;
+                }
+                if (transformInfo.pivotPoint != value)
+                {
+                    transformInfo.pivotPoint = value;
+                    TransformPropertyChanged();
+                }
+            }
+            get
+            {
+                return transformInfo.pivotPoint;
+            }
+        }
+
+        /// <summary>
+        /// Extra width of the visual as absolute policy.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float ExtraWidth
+        {
+            set
+            {
+                if (visualFittingModeApplied)
+                {
+                    FittingMode = VisualFittingModeType.DontCare;
+                }
+                if (transformInfo.extraWidth != value)
+                {
+                    transformInfo.extraWidth = value;
+                    TransformPropertyChanged();
+                }
+            }
+            get
+            {
+                return transformInfo.extraWidth;
+            }
+        }
+
+        /// <summary>
+        /// Extra height of the visual as absolute policy.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float ExtraHeight
+        {
+            set
+            {
+                if (visualFittingModeApplied)
+                {
+                    FittingMode = VisualFittingModeType.DontCare;
+                }
+                if (transformInfo.extraHeight != value)
+                {
+                    transformInfo.extraHeight = value;
+                    TransformPropertyChanged();
+                }
+            }
+            get
+            {
+                return transformInfo.extraHeight;
+            }
+        }
+        #endregion
+
+        #region Public Methods
+        /// <summary>
+        /// Get attached View.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Tizen.NUI.BaseComponents.View GetOwner()
+        {
+            var container = GetVisualContainer();
+            if (container != null)
+            {
+                return container.GetView();
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Detach from View.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Detach()
+        {
+            if (Disposed)
+            {
+                return;
+            }
+
+            var container = GetVisualContainer();
+            if (container != null)
+            {
+                container.RemoveVisualObject(this);
+            }
+
+            Interop.VisualObject.Detach(SwigCPtr);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        /// <summary>
+        /// Raise above the next sibling visual object
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Raise()
+        {
+            Interop.VisualObject.Raise(SwigCPtr);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        /// <summary>
+        /// Lower below the previous sibling visual object
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Lower()
+        {
+            Interop.VisualObject.Lower(SwigCPtr);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        /// <summary>
+        /// Raise above all other sibling visual objects
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void RaiseToTop()
+        {
+            Interop.VisualObject.RaiseToTop(SwigCPtr);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        /// <summary>
+        /// Raise below all other sibling visual objects
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void LowerToBottom()
+        {
+            Interop.VisualObject.LowerToBottom(SwigCPtr);
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        /// <summary>
+        /// Raise above target visual objects. No effects if visual object is already above target.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void RaiseAbove(Visuals.VisualBase target)
+        {
+            Interop.VisualObject.RaiseAbove(SwigCPtr, Visuals.VisualBase.getCPtr(target));
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        /// <summary>
+        /// Lower below target visual objects. No effects if visual object is already below target.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void LowerBelow(Visuals.VisualBase target)
+        {
+            Interop.VisualObject.LowerBelow(SwigCPtr, Visuals.VisualBase.getCPtr(target));
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        /// <summary>
+        /// Update visual properties manually.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void UpdateProperty()
+        {
+            UpdateVisualPropertyMap();
+        }
+        #endregion
+
+        #region Internal Methods
+        internal Visuals.VisualObjectsContainer GetVisualContainer()
+        {
+            global::System.IntPtr cPtr = Interop.VisualObject.GetContainer(SwigCPtr);
+            Visuals.VisualObjectsContainer ret = null;
+            if (Interop.RefObject.GetRefObjectPtr(cPtr) == global::System.IntPtr.Zero)
+            {
+                // Visual contianer is not created yet. Return null.
+                Interop.BaseHandle.DeleteBaseHandle(new global::System.Runtime.InteropServices.HandleRef(this, cPtr));
+            }
+            else
+            {
+                ret = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Visuals.VisualObjectsContainer;
+                if (ret != null)
+                {
+                    Interop.BaseHandle.DeleteBaseHandle(new global::System.Runtime.InteropServices.HandleRef(this, cPtr));
+                }
+                else
+                {
+                    ret = new Visuals.VisualObjectsContainer(cPtr, true);
+                }
+            }
+            NDalicPINVOKE.ThrowExceptionIfExists();
+            return ret;
+        }
+
+        /// <summary>
+        /// Unregister visual from control. It will not remove cached data.
+        /// </summary>
+        internal void UnregisterVisual()
+        {
+            using var tempPropertyMap = new PropertyMap();
+            Interop.VisualObject.CreateVisual(SwigCPtr, PropertyMap.getCPtr(tempPropertyMap));
+        }
+
+        /// <summary>
+        /// Set or Get visual property.
+        /// </summary>
+        /// <remarks>
+        /// This property might change the type of visual. We should not set it from subclass of VisualBase.
+        /// </remarks>
+        internal PropertyMap Properties
+        {
+            private set
+            {
+                visualCreationRequiredFlag = true;
+                cachedVisualPropertyMap = value;
+
+                visualUpdateRequiredFlag = false;
+                changedPropertyMap?.Dispose();
+                changedPropertyMap = null;
+
+                transformInfo.Clear();
+
+                // Get transform informations from input property map.
+                using var transformValue = cachedVisualPropertyMap?.Find((int)Tizen.NUI.Visual.Property.Transform);
+                if (transformValue != null)
+                {
+                    PropertyMap transformMap = new PropertyMap();
+                    if (transformValue.Get(ref transformMap) && transformMap != null)
+                    {
+                        transformInfo.ConvertFromPropertyMap(transformMap);
+                    }
+                }
+                transformInfo.changed = false;
+
+                // Get type from the property map.
+                internalType = (int)Tizen.NUI.Visual.Type.Invalid;
+                if (cachedVisualPropertyMap?.Find((int)Tizen.NUI.Visual.Property.Type)?.Get(out internalType) ?? false)
+                {
+                    UpdateVisualPropertyMap();
+                }
+                else
+                {
+                    // If type is not set, then remove the visual.
+                    UnregisterVisual();
+                }
+            }
+            get
+            {
+                // Sync as current properties
+                UpdateVisualPropertyMap();
+
+                PropertyMap ret = new PropertyMap();
+                Interop.VisualObject.RetrieveVisualPropertyMap(SwigCPtr, PropertyMap.getCPtr(ret));
+                return ret;
+            }
+        }
+
+        virtual internal void OnUpdateVisualPropertyMap()
+        {
+        }
+
+        virtual internal void OnVisualCreated()
+        {
+        }
+
+        /// <summary>
+        /// Lazy call to UpdateVisualPropertyMap.
+        /// Collect Properties need to be update, and set properties that starts the Processing.
+        ///
+        /// If you want to update cachedVisualPropertyMap, but don't want to request new visual creation, make requiredVisualCreation value as false.
+        /// (Example : if we change SynchronousLoading property from 'true' to 'false', or if we call this function during OnUpdateVisualPropertyMap)
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        virtual internal void UpdateVisualProperty(int key, PropertyValue value, bool requiredVisualCreation = true)
+        {
+            // Update visual property map value as inputed value.
+            if (key != 0)
+            {
+                if (!HasBody())
+                {
+                    // Throw exception if VisualBase is disposed.
+                    throw new global::System.InvalidOperationException($"[NUI][VisualBase] Someone try to change disposed VisualBase property.\n");
+                }
+
+                if (cachedVisualPropertyMap == null)
+                {
+                    cachedVisualPropertyMap = new PropertyMap();
+                }
+
+                visualCreationRequiredFlag |= requiredVisualCreation;
+                if (value != null)
+                {
+                    cachedVisualPropertyMap[key] = value;
+
+                    // Store the changed values in the changedPropertyMap, only if visualCreationRequiredFlag is false.
+                    // It will be used when we create the visual, only by UpdateVisualPropertyMap
+                    if (!visualCreationRequiredFlag)
+                    {
+                        visualUpdateRequiredFlag = true;
+                        if (changedPropertyMap == null)
+                        {
+                            changedPropertyMap = new PropertyMap();
+                        }
+                        changedPropertyMap[key] = value;
+                    }
+                }
+                else
+                {
+                    // Remove value from cachedVisualPropertyMap if input property map is null.
+                    cachedVisualPropertyMap.Remove(key);
+                }
+
+                ReqeustProcessorOnceEvent();
+            }
+        }
+
+        internal void UpdateVisualPropertyMap(object o, global::System.EventArgs e)
+        {
+            // Note : To allow event attachment during UpdateVisualPropertyMap, let we make flag as false before call UpdateVisualPropertyMap().
+            visualPropertyUpdateProcessAttachedFlag = false;
+            if (!visualCreationManually)
+            {
+                UpdateVisualPropertyMap();
+            }
+        }
+
+        internal void UpdateVisualPropertyMap()
+        {
+            if (Disposed)
+            {
+                return;
+            }
+
+            if (internalType == (int)Tizen.NUI.Visual.Type.Invalid)
+            {
+                Tizen.Log.Error("NUI", "Invalid visual type.\n");
+                return;
+            }
+
+            if (!visualCreationRequiredFlag)
+            {
+                if (visualUpdateRequiredFlag && changedPropertyMap != null)
+                {
+                    // We can change property map of visuals without creating them.
+                    Interop.VisualObject.UpdateVisualPropertyMap(SwigCPtr, PropertyMap.getCPtr(changedPropertyMap));
+
+                    changedPropertyMap?.Dispose();
+                    changedPropertyMap = null;
+                }
+                return;
+            }
+
+            visualCreationRequiredFlag = false;
+            visualUpdateRequiredFlag = false;
+
+            changedPropertyMap?.Dispose();
+            changedPropertyMap = null;
+
+            if (cachedVisualPropertyMap == null)
+            {
+                cachedVisualPropertyMap = new PropertyMap();
+            }
+
+            if (transformInfo.changed)
+            {
+                transformInfo.changed = false;
+                cachedVisualPropertyMap.Remove((int)Tizen.NUI.Visual.Property.Transform);
+
+                transformInfo.ConvertToPropertyMap();
+
+                if (transformInfo.cachedVisualTransformPropertyMap != null)
+                {
+                    using var transformValue = new PropertyValue(transformInfo.cachedVisualTransformPropertyMap);
+                    cachedVisualPropertyMap.Add((int)Tizen.NUI.Visual.Property.Transform, transformValue);
+                }
+            }
+
+            // Update the sub classes property map.
+            OnUpdateVisualPropertyMap();
+
+            Interop.VisualObject.CreateVisual(SwigCPtr, PropertyMap.getCPtr(cachedVisualPropertyMap));
+
+            // Post process for sub classes.
+            OnVisualCreated();
+
+            NDalicPINVOKE.ThrowExceptionIfExists();
+        }
+
+        /// <summary>
+        /// Get visual property by key.
+        /// If we found value in local cached result, return that.
+        /// Else, get synced native map and return that.
+        /// </summary>
+        /// <returns>Matched value. If there is no matched value, return null.</returns>
+        internal PropertyValue GetVisualProperty(int key)
+        {
+            PropertyValue ret = GetCachedVisualProperty(key);
+            if (ret == null)
+            {
+                // If we cannot find result from cached map, Get value from native engine.
+                GetCurrentVisualProperty(key);
+            }
+            return ret;
+        }
+
+        /// <summary>
+        /// Get visual property by key from native engine.
+        /// </summary>
+        /// <returns>Matched value. If there is no matched value, return null.</returns>
+        internal PropertyValue GetCurrentVisualProperty(int key)
+        {
+            return Properties?.Find(key);
+        }
+
+        /// <summary>
+        /// Get visual property from NUI cached map by key.
+        /// </summary>
+        /// <returns>Matched value. If there is no matched value, return null.</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        internal virtual PropertyValue GetCachedVisualProperty(int key)
+        {
+            return cachedVisualPropertyMap?.Find(key);
+        }
+
+        /// <summary>
+        /// Change visual transform information.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        internal void TransformPropertyChanged()
+        {
+            if (transformInfo.cachedVisualTransformPropertyMap == null)
+            {
+                transformInfo.cachedVisualTransformPropertyMap = new PropertyMap();
+            }
+
+            // Mark as transform property map.
+            visualCreationRequiredFlag = true;
+            transformInfo.changed = true;
+
+            ReqeustProcessorOnceEvent();
+        }
+
+        internal void ReqeustProcessorOnceEvent()
+        {
+            if (!visualCreationManually && !visualPropertyUpdateProcessAttachedFlag)
+            {
+                visualPropertyUpdateProcessAttachedFlag = true;
+                ProcessorController.Instance.ProcessorOnceEvent += UpdateVisualPropertyMap;
+                // Call process hardly.
+                ProcessorController.Instance.Awake();
+            }
+        }
+
+        /// <summary>
+        /// Dispose for VisualObject
+        /// </summary>
+        [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.
+
+                // Note : Do not call this function in Implicit dispose case.
+                // Since if visual is already under some VisualObjectsContainer,
+                // it will never be GC.
+                Detach();
+            }
+
+            visualCreationRequiredFlag = false;
+            visualUpdateRequiredFlag = false;
+
+            changedPropertyMap?.Dispose();
+            changedPropertyMap = null;
+            cachedVisualPropertyMap?.Dispose();
+            cachedVisualPropertyMap = null;
+
+            base.Dispose(type);
+        }
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/VisualTest.cs b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/VisualTest.cs
new file mode 100755 (executable)
index 0000000..2f24312
--- /dev/null
@@ -0,0 +1,395 @@
+using System.Net.Mime;
+using Tizen.NUI.BaseComponents;
+using System.Collections.Generic;
+
+namespace Tizen.NUI.Samples
+{
+    public class VisualTest : IExample
+    {
+        Window window = null;
+
+        static private string DEMO_IMAGE_DIR = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "images/";
+
+        static private readonly string focusIndicatorImageUrl = DEMO_IMAGE_DIR + "i_focus_stroke_tile_2unit.9.webp";
+        static private readonly string[] ImageUrlList = {
+            DEMO_IMAGE_DIR + "Dali/DaliDemo/application-icon-1.png",
+            DEMO_IMAGE_DIR + "Dali/DaliDemo/application-icon-6.png",
+            DEMO_IMAGE_DIR + "Dali/DaliDemo/Kid1.svg",
+            DEMO_IMAGE_DIR + "Dali/ContactCard/gallery-small-2.jpg",
+        };
+
+        const float viewSizeWidth = 320.0f;
+        const float viewSizeHeight = 280.0f;
+        const float thumbnailAreaHeight = 96.0f;
+        const float thumbnailSize = 72.0f;
+        const float viewGap = 24.0f;
+
+        View rootView;
+
+        View[] visualViewList = new View[4];
+
+        Visuals.NPatchVisual focusIndicatorVisual;
+        Visuals.ColorVisual shadowVisual1;
+        Visuals.ColorVisual shadowVisual2;
+
+        public void Activate()
+        {
+            FocusManager.Instance.EnableDefaultAlgorithm(true);
+
+            // To use custom indicator, in this sample, removed default indicator
+            FocusManager.Instance.FocusIndicator = null;
+
+            window = NUIApplication.GetDefaultWindow();
+
+            CreateFocusedVisuals();
+
+            CreateLayoutViews();
+
+            window.KeyEvent += WinKeyEvent;
+        }
+
+        private void WinKeyEvent(object sender, Window.KeyEventArgs e)
+        {
+            if (e.Key.State == Key.StateType.Down)
+            {
+                if (e.Key.KeyPressedName == "1")
+                {
+                    Tizen.Log.Error("NUI", $"Reset scene\n");
+
+                    rootView?.Unparent();
+                    rootView?.Dispose();
+
+                    focusIndicatorVisual?.Dispose();
+                    shadowVisual1?.Dispose();
+                    shadowVisual2?.Dispose();
+
+                    CreateFocusedVisuals();
+
+                    CreateLayoutViews();
+                }
+                else if(e.Key.KeyPressedName == "2")
+                {
+                    Tizen.Log.Error("NUI", $"GC test\n");
+                    FullGC();
+                }
+                else if(e.Key.KeyPressedName == "3")
+                {
+                    View focusedView = FocusManager.Instance.GetCurrentFocusView();
+                    if(focusedView != null)
+                    {
+                        float tmp = focusedView.SizeWidth;
+                        focusedView.SizeWidth = focusedView.SizeHeight * 2.0f;
+                        focusedView.SizeHeight = tmp / 2.0f;
+                    }
+                }
+                else if(e.Key.KeyPressedName == "4")
+                {
+                    focusIndicatorVisual.ResourceUrl = null;
+                }
+                else if(e.Key.KeyPressedName == "5")
+                {
+                    focusIndicatorVisual.ResourceUrl = focusIndicatorImageUrl;
+                }
+            }
+        }
+
+        public void Deactivate()
+        {
+            window.KeyEvent -= WinKeyEvent;
+
+            FocusManager.Instance.EnableDefaultAlgorithm(false);
+            rootView?.Unparent();
+            rootView?.Dispose();
+
+            focusIndicatorVisual?.Dispose();
+            shadowVisual1?.Dispose();
+            shadowVisual2?.Dispose();
+        }
+
+        private void FullGC()
+        {
+            global::System.GC.Collect();
+            global::System.GC.WaitForPendingFinalizers();
+            global::System.GC.Collect();
+        }
+
+        private void CreateFocusedVisuals()
+        {
+            focusIndicatorVisual = new Visuals.NPatchVisual()
+            {
+                Name = "indicator",
+
+                ResourceUrl = focusIndicatorImageUrl,
+
+                Origin = Visual.AlignType.Center,
+                PivotPoint = Visual.AlignType.Center,
+
+                Width = 1.01f,
+                Height = 1.01f,
+
+                BorderOnly = true,
+            };
+            shadowVisual1 = new Visuals.ColorVisual()
+            {
+                Name = "shadow1",
+
+                Color = new Color(0.0f, 0.0f, 0.0f, 0.2f),
+
+                CornerRadius = new Vector4(16.0f, 16.0f, 16.0f, 16.0f),
+
+                OffsetX = 2.0f,
+                OffsetY = 5.0f,
+                Width = 1.03f,
+                Height = 1.01f,
+
+                OffsetXPolicy = VisualTransformPolicyType.Absolute,
+                OffsetYPolicy = VisualTransformPolicyType.Absolute,
+            };
+            shadowVisual2 = new Visuals.ColorVisual()
+            {
+                Name = "shadow2",
+
+                Color = new Color(0.0f, 0.0f, 0.0f, 0.3f),
+
+                CornerRadius = new Vector4(16.0f, 16.0f, 16.0f, 16.0f),
+
+                OffsetX = 2.0f,
+                OffsetY = 5.0f,
+                Width = 1.01f,
+                Height = 1.0f,
+
+                OffsetXPolicy = VisualTransformPolicyType.Absolute,
+                OffsetYPolicy = VisualTransformPolicyType.Absolute,
+            };
+        }
+
+        private void CreateLayoutViews()
+        {
+            rootView = new View()
+            {
+                Name = "rootView",
+                BackgroundColor = new Color("#7c9df0"),
+
+                WidthResizePolicy = ResizePolicyType.FillToParent,
+                HeightResizePolicy = ResizePolicyType.FillToParent,
+            };
+
+            for(int i=0; i<4; i++)
+            {
+                visualViewList[i] = CreateViewWithVisual(i);
+                rootView.Add(visualViewList[i]);
+            }
+
+            window.Add(rootView);
+        }
+
+        private View CreateViewWithVisual(int id)
+        {
+            View view = new View()
+            {
+                Name = $"ID{id}",
+
+                SizeWidth = viewSizeWidth,
+                SizeHeight = viewSizeHeight,
+                PositionX = viewGap + (id % 2) * (viewSizeWidth + viewGap),
+                PositionY = viewGap + (id / 2) * (viewSizeHeight + viewGap),
+
+                Focusable = true,
+                FocusableInTouch = true,
+                KeyInputFocus = true,
+
+                Padding = new Extents(10, 10, 10, (ushort)thumbnailAreaHeight),
+            };
+
+            Visuals.ColorVisual backgroundVisual = new Visuals.ColorVisual()
+            {
+                Name = "background",
+
+                Color = Color.Gray,
+
+                CornerRadius = new Vector4(16.0f, 16.0f, 16.0f, 16.0f),
+            };
+
+            Visuals.ImageVisual imageVisual = new Visuals.ImageVisual()
+            {
+                Name = "mainImage",
+
+                ResourceUrl = ImageUrlList[id % 4],
+
+                CornerRadius = new Vector4(16.0f, 16.0f, 0.0f, 0.0f),
+
+                FittingMode = VisualFittingModeType.FitKeepAspectRatio,
+            };
+
+            Visuals.ColorVisual foregroundVisual = new Visuals.ColorVisual()
+            {
+                Name = "foreground",
+
+                Color = Color.LightSlateGray,
+                Opacity = 0.5f,
+
+                CornerRadius = new Vector4(0.0f, 0.0f, 16.0f, 16.0f),
+
+                Origin = Visual.AlignType.BottomBegin,
+                PivotPoint = Visual.AlignType.BottomBegin,
+
+                Height = thumbnailAreaHeight,
+
+                HeightPolicy = VisualTransformPolicyType.Absolute,
+            };
+
+            Visuals.TextVisual textVisual = new Visuals.TextVisual()
+            {
+                Name = "text",
+
+                Text = $"View {id} long text long long long long looooong",
+                TextColor = Color.White,
+                PointSize = 20.0f,
+
+                Origin = Visual.AlignType.BottomBegin,
+                PivotPoint = Visual.AlignType.BottomBegin,
+                
+                HorizontalAlignment = HorizontalAlignment.Begin,
+                VerticalAlignment = VerticalAlignment.Center,
+
+                OffsetX = thumbnailAreaHeight,
+                OffsetY = -thumbnailAreaHeight * 0.4f,
+                Width = viewSizeWidth - thumbnailAreaHeight,
+                Height = thumbnailAreaHeight * 0.6f,
+
+                OffsetXPolicy = VisualTransformPolicyType.Absolute,
+                OffsetYPolicy = VisualTransformPolicyType.Absolute,
+                WidthPolicy = VisualTransformPolicyType.Absolute,
+                HeightPolicy = VisualTransformPolicyType.Absolute,
+            };
+
+            Visuals.AdvancedTextVisual subTextVisual = new Visuals.AdvancedTextVisual()
+            {
+                Name = "subtext",
+
+                Text = "subtext",
+                TextColor = Color.White,
+                PointSize = 12.0f,
+
+                Origin = Visual.AlignType.BottomBegin,
+                PivotPoint = Visual.AlignType.BottomBegin,
+                
+                HorizontalAlignment = HorizontalAlignment.Begin,
+                VerticalAlignment = VerticalAlignment.Center,
+
+                OffsetX = thumbnailAreaHeight,
+                Width = viewSizeWidth - thumbnailAreaHeight,
+                Height = thumbnailAreaHeight * 0.4f,
+
+                OffsetXPolicy = VisualTransformPolicyType.Absolute,
+                WidthPolicy = VisualTransformPolicyType.Absolute,
+                HeightPolicy = VisualTransformPolicyType.Absolute,
+            };
+
+            try
+            {
+                subTextVisual.TranslatableText = "SID_OK";
+            }
+            catch(global::System.Exception e)
+            {
+                subTextVisual.Text = e.Message;
+            }
+
+            Visuals.ImageVisual thumbnailVisual = new Visuals.ImageVisual()
+            {
+                Name = "thumbnailImage",
+
+                ResourceUrl = ImageUrlList[id % 4],
+
+                CornerRadius = new Vector4(8.0f, 8.0f, 8.0f, 8.0f),
+
+                Origin = Visual.AlignType.BottomBegin,
+                PivotPoint = Visual.AlignType.Center,
+
+                OffsetX = thumbnailAreaHeight / 2.0f,
+                OffsetY = -thumbnailAreaHeight / 2.0f,
+
+                Width = thumbnailSize,
+                Height = thumbnailSize,
+
+                DesiredWidth = (int)thumbnailSize,
+                DesiredHeight = (int)thumbnailSize,
+
+                OffsetXPolicy = VisualTransformPolicyType.Absolute,
+                OffsetYPolicy = VisualTransformPolicyType.Absolute,
+                WidthPolicy = VisualTransformPolicyType.Absolute,
+                HeightPolicy = VisualTransformPolicyType.Absolute,
+            };
+
+            view.AddVisual(backgroundVisual);
+            view.AddVisual(imageVisual);
+            view.AddVisual(foregroundVisual);
+            view.AddVisual(textVisual);
+            view.AddVisual(subTextVisual);
+            view.AddVisual(thumbnailVisual);
+
+            view.FocusGained += (s, e) =>
+            {
+                View me = s as View;
+                if(me != null)
+                {
+                    Tizen.Log.Error("NUI", $"View {me.ID} focus gained.\n");
+
+                    me.AddVisual(focusIndicatorVisual);
+                    me.AddVisual(shadowVisual1);
+                    me.AddVisual(shadowVisual2);
+
+                    focusIndicatorVisual.RaiseToTop();
+                    shadowVisual1.LowerToBottom();
+                    shadowVisual2.LowerBelow(shadowVisual1);
+
+                    var visual = me.FindVisualByName("foreground");
+                    visual.Color = Color.LightGray;
+                    visual.Opacity = 0.5f;
+
+                    //visual = me.FindVisualByName("background");
+                    visual = me.GetVisualAt(2u); // Should be background
+                    visual.Color = Color.White;
+
+                    var textVisual = me.FindVisualByName("text") as Visuals.TextVisual;
+                    textVisual.TextColor = Color.Black;
+                    textVisual = me.FindVisualByName("subtext") as Visuals.TextVisual;
+                    textVisual.TextColor = Color.Black;
+                }
+            };
+
+            view.FocusLost += (s, e) =>
+            {
+                View me = s as View;
+                if(me != null)
+                {
+                    Tizen.Log.Error("NUI", $"View {me.ID} focus losted.\n");
+
+                    me.RemoveVisual(focusIndicatorVisual);
+                    me.RemoveVisual(shadowVisual1);
+                    me.RemoveVisual(shadowVisual2);
+
+                    var visual = me.FindVisualByName("foreground");
+                    visual.Color = Color.LightSlateGray;
+                    visual.Opacity = 0.5f;
+
+                    //visual = me.FindVisualByName("background");
+                    visual = me.GetVisualAt(0u); // Should be background
+                    visual.Color = Color.Gray;
+
+                    var textVisual = me.FindVisualByName("text") as Visuals.TextVisual;
+                    textVisual.TextColor = Color.White;
+                    textVisual = me.FindVisualByName("subtext") as Visuals.TextVisual;
+                    textVisual.TextColor = Color.White;
+                }
+            };
+
+            view.TouchEvent += (o, e) =>
+            {
+                return true;
+            };
+
+            return view;
+        }
+    }
+}
diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/images/i_focus_stroke_tile_2unit.9.webp b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/images/i_focus_stroke_tile_2unit.9.webp
new file mode 100644 (file)
index 0000000..f1224f5
Binary files /dev/null and b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/images/i_focus_stroke_tile_2unit.9.webp differ
diff --git a/test/Tizen.NUI.VisualTest/Tizen.NUI.VisualTest.code-workspace b/test/Tizen.NUI.VisualTest/Tizen.NUI.VisualTest.code-workspace
new file mode 100644 (file)
index 0000000..f12d910
--- /dev/null
@@ -0,0 +1,14 @@
+{
+       "folders": [
+               {
+                       "path": "."
+               },
+               {
+                       "path": "../../src/Tizen.NUI"
+               },
+               {
+                       "path": "../../src/Tizen.NUI.Components"
+               }
+       ],
+       "settings": {}
+}
diff --git a/test/Tizen.NUI.VisualTest/Tizen.NUI.VisualTest.csproj b/test/Tizen.NUI.VisualTest/Tizen.NUI.VisualTest.csproj
new file mode 100644 (file)
index 0000000..37a222e
--- /dev/null
@@ -0,0 +1,24 @@
+<Project Sdk="Microsoft.NET.Sdk">
+    <PropertyGroup>
+        <OutputType>Exe</OutputType>
+        <TargetFramework>net6.0</TargetFramework>
+        <AssemblyName>VisualTest</AssemblyName>
+    </PropertyGroup>
+
+    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+        <DebugType>portable</DebugType>
+    </PropertyGroup>
+    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+        <DebugType>None</DebugType>
+    </PropertyGroup>
+
+    <ItemGroup>
+        <PackageReference Include="Tizen.NET.Sdk" Version="1.0.9" />
+        <ProjectReference Include="../../src/Tizen/Tizen.csproj" />
+        <ProjectReference Include="../../src/Tizen.NUI/Tizen.NUI.csproj" />
+    </ItemGroup>
+
+    <PropertyGroup>
+        <NeedInjection>True</NeedInjection>
+    </PropertyGroup>
+</Project>
diff --git a/test/Tizen.NUI.VisualTest/Tizen.NUI.VisualTest.sln b/test/Tizen.NUI.VisualTest/Tizen.NUI.VisualTest.sln
new file mode 100755 (executable)
index 0000000..18e7096
--- /dev/null
@@ -0,0 +1,91 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.33214.272
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.NUI.VisualTest", "Tizen.NUI.VisualTest.csproj", "{3C6CE4CE-9D35-42C9-B23D-BBFFA96B3955}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen", "..\..\src\Tizen\Tizen.csproj", "{F4ADAF15-01AA-477E-A85A-BEB297E6B07E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Applications.Common", "..\..\src\Tizen.Applications.Common\Tizen.Applications.Common.csproj", "{0B96B17C-DACA-4745-88B1-6CFC1825A510}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Applications.ComponentBased", "..\..\src\Tizen.Applications.ComponentBased\Tizen.Applications.ComponentBased.csproj", "{E117D074-C23D-41FD-A77D-2E9E6FF85676}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Applications.ThemeManager", "..\..\src\Tizen.Applications.ThemeManager\Tizen.Applications.ThemeManager.csproj", "{FB8B42D6-76CC-4836-8A80-58A816C6A17F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.System.SystemSettings", "..\..\src\Tizen.System.SystemSettings\Tizen.System.SystemSettings.csproj", "{EC28F259-C790-4FA3-A834-00795E2A7E2F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.System.Information", "..\..\src\Tizen.System.Information\Tizen.System.Information.csproj", "{02BEE3AD-99A6-44A5-89FC-D9F4132D9ECE}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.System.Feedback", "..\..\src\Tizen.System.Feedback\Tizen.System.Feedback.csproj", "{D422D03E-7E32-4230-8306-B16DFE27E95A}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Tracer", "..\..\src\Tizen.Tracer\Tizen.Tracer.csproj", "{A0AA9346-2025-4803-A168-3B39A367BB92}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Log", "..\..\src\Tizen.Log\Tizen.Log.csproj", "{1E8250DB-92C3-44A5-8D57-3CFDE0C0021D}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.NUI", "..\..\src\Tizen.NUI\Tizen.NUI.csproj", "{29B426DA-FFDE-49D2-BD73-FE155F9502E8}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.NUI.Components", "..\..\src\Tizen.NUI.Components\Tizen.NUI.Components.csproj", "{2A669CBF-DFA8-4EA3-852D-3137493DE884}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Any CPU = Debug|Any CPU
+               Release|Any CPU = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {3C6CE4CE-9D35-42C9-B23D-BBFFA96B3955}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {3C6CE4CE-9D35-42C9-B23D-BBFFA96B3955}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {3C6CE4CE-9D35-42C9-B23D-BBFFA96B3955}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {3C6CE4CE-9D35-42C9-B23D-BBFFA96B3955}.Release|Any CPU.Build.0 = Release|Any CPU
+               {F4ADAF15-01AA-477E-A85A-BEB297E6B07E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {F4ADAF15-01AA-477E-A85A-BEB297E6B07E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {F4ADAF15-01AA-477E-A85A-BEB297E6B07E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {F4ADAF15-01AA-477E-A85A-BEB297E6B07E}.Release|Any CPU.Build.0 = Release|Any CPU
+               {0B96B17C-DACA-4745-88B1-6CFC1825A510}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {0B96B17C-DACA-4745-88B1-6CFC1825A510}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {0B96B17C-DACA-4745-88B1-6CFC1825A510}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {0B96B17C-DACA-4745-88B1-6CFC1825A510}.Release|Any CPU.Build.0 = Release|Any CPU
+               {E117D074-C23D-41FD-A77D-2E9E6FF85676}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {E117D074-C23D-41FD-A77D-2E9E6FF85676}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {E117D074-C23D-41FD-A77D-2E9E6FF85676}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {E117D074-C23D-41FD-A77D-2E9E6FF85676}.Release|Any CPU.Build.0 = Release|Any CPU
+               {FB8B42D6-76CC-4836-8A80-58A816C6A17F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {FB8B42D6-76CC-4836-8A80-58A816C6A17F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {FB8B42D6-76CC-4836-8A80-58A816C6A17F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {FB8B42D6-76CC-4836-8A80-58A816C6A17F}.Release|Any CPU.Build.0 = Release|Any CPU
+               {EC28F259-C790-4FA3-A834-00795E2A7E2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {EC28F259-C790-4FA3-A834-00795E2A7E2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {EC28F259-C790-4FA3-A834-00795E2A7E2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {EC28F259-C790-4FA3-A834-00795E2A7E2F}.Release|Any CPU.Build.0 = Release|Any CPU
+               {02BEE3AD-99A6-44A5-89FC-D9F4132D9ECE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {02BEE3AD-99A6-44A5-89FC-D9F4132D9ECE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {02BEE3AD-99A6-44A5-89FC-D9F4132D9ECE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {02BEE3AD-99A6-44A5-89FC-D9F4132D9ECE}.Release|Any CPU.Build.0 = Release|Any CPU
+               {D422D03E-7E32-4230-8306-B16DFE27E95A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {D422D03E-7E32-4230-8306-B16DFE27E95A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {D422D03E-7E32-4230-8306-B16DFE27E95A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {D422D03E-7E32-4230-8306-B16DFE27E95A}.Release|Any CPU.Build.0 = Release|Any CPU
+               {A0AA9346-2025-4803-A168-3B39A367BB92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {A0AA9346-2025-4803-A168-3B39A367BB92}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {A0AA9346-2025-4803-A168-3B39A367BB92}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {A0AA9346-2025-4803-A168-3B39A367BB92}.Release|Any CPU.Build.0 = Release|Any CPU
+               {1E8250DB-92C3-44A5-8D57-3CFDE0C0021D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {1E8250DB-92C3-44A5-8D57-3CFDE0C0021D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {1E8250DB-92C3-44A5-8D57-3CFDE0C0021D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {1E8250DB-92C3-44A5-8D57-3CFDE0C0021D}.Release|Any CPU.Build.0 = Release|Any CPU
+               {29B426DA-FFDE-49D2-BD73-FE155F9502E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {29B426DA-FFDE-49D2-BD73-FE155F9502E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {29B426DA-FFDE-49D2-BD73-FE155F9502E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {29B426DA-FFDE-49D2-BD73-FE155F9502E8}.Release|Any CPU.Build.0 = Release|Any CPU
+               {2A669CBF-DFA8-4EA3-852D-3137493DE884}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {2A669CBF-DFA8-4EA3-852D-3137493DE884}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {2A669CBF-DFA8-4EA3-852D-3137493DE884}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {2A669CBF-DFA8-4EA3-852D-3137493DE884}.Release|Any CPU.Build.0 = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+       GlobalSection(ExtensibilityGlobals) = postSolution
+               SolutionGuid = {355D568D-D02A-490A-A6AC-FD6C7D97457A}
+       EndGlobalSection
+EndGlobal
diff --git a/test/Tizen.NUI.VisualTest/VisualTest.cs b/test/Tizen.NUI.VisualTest/VisualTest.cs
new file mode 100644 (file)
index 0000000..61d7dad
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2024 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 Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Constants;
+
+class VisualTestExample : NUIApplication
+{
+    const uint VIEW_COUNT = 1000;
+
+    static string IMAGE_DIR = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "image/";
+    readonly static string[] IMAGE_PATH = 
+    {
+        IMAGE_DIR + "gallery-small-1.jpg",
+    };
+
+    Window mWindow;
+    Vector2 mWindowSize;
+    float mViewSize;
+
+    TextLabel infoLabel;
+
+    View rootView;
+
+    ImageView dummyView;
+    Animation dummyAnimation;
+
+    int state = 0;
+
+    private global::System.Random mRandom = new global::System.Random();
+
+    protected void CreateScene()
+    {
+        mWindow = Window.Instance;
+        mWindow.BackgroundColor = Color.White;
+        mWindowSize = mWindow.WindowSize;
+
+        mViewSize = global::System.Math.Min(mWindowSize.X, mWindowSize.Y) / 10.0f;
+
+        infoLabel = new TextLabel(
+            $"VisualObject Test with {VIEW_COUNT} and 2 children. (ImageView + TextLabel)\n" +
+            $"Press 1 key to start test with View. (ImageView + TextLabel)\n" +
+            $"Press 2 key to start test with Visual. (ImageVisual + TextLabel)\n" +
+            $"Press 3 key to start test with various Visuals. (ColorVisual + ImageVisual + TextVisual + BorderVisual)\n" +
+            $"Press 4 key to animate the size of View.\n" +
+            $"(View size : {mViewSize})\n")
+        {
+            MultiLine = true,
+            PointSize = 20.0f,
+        };
+
+        // For image cache.
+        dummyView = new ImageView()
+        {
+            ResourceUrl = IMAGE_PATH[0],
+            SizeWidth = 1.0f,
+            SizeHeight = 1.0f,
+        };
+
+        // For keep rendering forever
+        dummyAnimation = new Animation(1000);
+        dummyAnimation.AnimateTo(dummyView, "PositionX", 1.0f);
+        dummyAnimation.Looping = true;
+        dummyAnimation.Play();
+
+        rootView = new View()
+        {
+            SizeWidth = mWindowSize.X,
+            SizeHeight = mWindowSize.Y,
+            BackgroundColor = Color.White,
+        };
+        mWindow.Add(dummyView);
+        mWindow.Add(rootView);
+
+        mWindow.GetOverlayLayer().Add(infoLabel);
+
+        mWindow.KeyEvent += OnKeyEvent;
+    }
+
+    void NormalViewTest()
+    {
+        global::System.DateTime startTime;
+        global::System.DateTime endTime;
+
+        startTime = global::System.DateTime.Now;
+
+        for(int i = 0; i < VIEW_COUNT; i++)
+        {
+            View view = new View()
+            {
+                SizeWidth = mViewSize,
+                SizeHeight = mViewSize,
+                PositionX = (mRandom.Next()%1000 / 999.0f) * (mWindowSize.X - mViewSize),
+                PositionY = (mRandom.Next()%1000 / 999.0f) * (mWindowSize.Y - mViewSize),
+            };
+            CreateNormalView(ref view);
+            rootView.Add(view);
+        }
+
+        endTime = global::System.DateTime.Now;
+
+        Tizen.Log.Error("NUI.Visuals", $"NormalViewTest : {(endTime - startTime).TotalMilliseconds} ms\n");
+    }
+
+    void VisualViewTest()
+    {
+        global::System.DateTime startTime;
+        global::System.DateTime endTime;
+
+        startTime = global::System.DateTime.Now;
+
+        for(int i = 0; i < VIEW_COUNT; i++)
+        {
+            View view = new View()
+            {
+                SizeWidth = mViewSize,
+                SizeHeight = mViewSize,
+                PositionX = (mRandom.Next()%1000 / 999.0f) * (mWindowSize.X - mViewSize),
+                PositionY = (mRandom.Next()%1000 / 999.0f) * (mWindowSize.Y - mViewSize),
+            };
+            CreateVisualView(ref view);
+            rootView.Add(view);
+        }
+
+        endTime = global::System.DateTime.Now;
+
+        Tizen.Log.Error("NUI.Visuals", $"VisualViewTest : {(endTime - startTime).TotalMilliseconds} ms\n");
+    }
+
+    void GeneralVisualTest()
+    {
+        global::System.DateTime startTime;
+        global::System.DateTime endTime;
+
+        startTime = global::System.DateTime.Now;
+
+        for(int i = 0; i < VIEW_COUNT; i++)
+        {
+            View view = new View()
+            {
+                SizeWidth = mViewSize,
+                SizeHeight = mViewSize,
+                PositionX = (mRandom.Next()%1000 / 999.0f) * (mWindowSize.X - mViewSize),
+                PositionY = (mRandom.Next()%1000 / 999.0f) * (mWindowSize.Y - mViewSize),
+            };
+            CreateGeneralVisualView(ref view);
+            rootView.Add(view);
+        }
+
+        endTime = global::System.DateTime.Now;
+
+        Tizen.Log.Error("NUI.Visuals", $"GeneralVisualTest : {(endTime - startTime).TotalMilliseconds} ms\n");
+    }
+
+
+    void OnKeyEvent(object source, Window.KeyEventArgs e)
+    {
+        if (e.Key.State == Key.StateType.Down)
+        {
+            switch(e.Key.KeyPressedName)
+            {
+                case "Escape":
+                case "Back":
+                case "XF86Back":
+                {
+                    if(state == 0)
+                    {
+                        Deactivate();
+                        Exit();
+                    }
+                    else
+                    {
+                        state = 0;
+                        viewWidthChangeAnimation?.Stop();
+                        viewWidthChangeAnimation?.Clear();
+                        viewWidthChangeAnimation?.Dispose();
+                        viewWidthChangeAnimation = null;
+
+                        rootView?.Unparent();
+                        rootView?.DisposeRecursively();
+                        rootView = new View()
+                        {
+                            SizeWidth = mWindowSize.X,
+                            SizeHeight = mWindowSize.Y,
+                            BackgroundColor = Color.White,
+                        };
+                        mWindow.Add(rootView);
+                        FullGC();
+                        FullGC();
+                    }
+                    break;
+                }
+                case "1":
+                {
+                    if(state == 0)
+                    {
+                        state = 1;
+                        NormalViewTest();
+                    }
+                    break;
+                }
+                case "2":
+                {
+                    if(state == 0)
+                    {
+                        state = 2;
+                        VisualViewTest();
+                    }
+                    break;
+                }
+                case "3":
+                {
+                    if(state == 0)
+                    {
+                        state = 3;
+                        GeneralVisualTest();
+                    }
+                    break;
+                }
+                case "4":
+                {
+                    if(state != 0)
+                    {
+                        ViewSizeChangeTest();
+                    }
+                    break;
+                }
+                default:
+                {
+                    FullGC();
+                    FullGC();
+                    break;
+                }
+            }
+        }
+    }
+
+    public void Activate()
+    {
+        CreateScene();
+    }
+    public void FullGC()
+    {
+        global::System.GC.Collect();
+        global::System.GC.WaitForPendingFinalizers();
+        global::System.GC.Collect();
+    }
+
+    public void Deactivate()
+    {
+        DestroyScene();
+    }
+
+    private void DestroyScene()
+    {
+        rootView?.Unparent();
+        rootView?.Dispose();
+    }
+
+    private Animation viewWidthChangeAnimation = null;
+    private void ViewSizeChangeTest()
+    {
+        viewWidthChangeAnimation?.Stop();
+        viewWidthChangeAnimation?.Clear();
+        viewWidthChangeAnimation?.Dispose();
+        viewWidthChangeAnimation = new Animation(3000);
+        for(int i = 0; i < VIEW_COUNT; i++)
+        {
+            View view = rootView.GetChildAt((uint)i);
+
+            if(view == null)break;
+
+            viewWidthChangeAnimation.AnimateTo(view, "SizeWidth", mViewSize * 2.0f, 0, 1000);
+            viewWidthChangeAnimation.AnimateTo(view, "SizeWidth", mViewSize * 0.0f, 1000, 2000);
+            viewWidthChangeAnimation.AnimateTo(view, "SizeWidth", mViewSize * 1.0f, 2000, 3000);
+        }
+
+        viewWidthChangeAnimation.Play();
+    }
+
+    private void CreateNormalView(ref View view)
+    {
+        // ImageView with corner radius top.
+        ImageView imageView = new ImageView()
+        {
+            ResourceUrl = IMAGE_PATH[0],
+            CornerRadius = new Vector4(0.15f, 0.15f, 0.15f, 0.15f),
+            CornerRadiusPolicy = VisualTransformPolicyType.Relative,
+
+            SizeWidth = mViewSize,
+            SizeHeight = mViewSize,
+        };
+
+        TextLabel textLabel = new TextLabel()
+        {
+            Text = "1",
+            PointSize = 20.0f,
+
+            SizeWidth = mViewSize,
+            SizeHeight = mViewSize,
+
+            PositionY = mViewSize * 0.25f,
+            PositionX = mViewSize * 0.5f,
+
+            ParentOrigin = Position.ParentOriginCenter,
+            PivotPoint = Position.PivotPointCenter,
+            PositionUsesPivotPoint = true,
+        };
+
+        view.Add(imageView);
+        view.Add(textLabel);
+    }
+
+    private void CreateVisualView(ref View view)
+    {
+        // ImageView with corner radius top.
+        Tizen.NUI.Visuals.ImageVisual imageVisual = new Tizen.NUI.Visuals.ImageVisual()
+        {
+            ResourceUrl = IMAGE_PATH[0],
+            CornerRadius = new Vector4(0.15f, 0.15f, 0.15f, 0.15f),
+            CornerRadiusPolicy = VisualTransformPolicyType.Relative,
+
+            Width = mViewSize,
+            Height = mViewSize,
+
+            WidthPolicy = VisualTransformPolicyType.Absolute,
+            HeightPolicy = VisualTransformPolicyType.Absolute,
+        };
+
+        /*
+        Tizen.NUI.Visuals.TextVisual textVisual = new Tizen.NUI.Visuals.TextVisual()
+        {
+            Text = "1",
+            PointSize = 20.0f,
+
+            Width = mViewSize,
+            Height = mViewSize,
+
+            OffsetY = mViewSize * 0.25f,
+
+            Origin = Visual.AlignType.Center,
+            PivotPoint = Visual.AlignType.Center,
+
+            WidthPolicy = VisualTransformPolicyType.Absolute,
+            HeightPolicy = VisualTransformPolicyType.Absolute,
+            OffsetYPolicy = VisualTransformPolicyType.Absolute,
+        };
+        */
+
+        view.AddVisual(imageVisual);
+        //view.AddVisual(textVisual);
+
+        TextLabel textLabel = new TextLabel()
+        {
+            Text = "1",
+            PointSize = 20.0f,
+
+            SizeWidth = mViewSize,
+            SizeHeight = mViewSize,
+
+            PositionY = mViewSize * 0.25f,
+            PositionX = mViewSize * 0.5f,
+
+            ParentOrigin = Position.ParentOriginCenter,
+            PivotPoint = Position.PivotPointCenter,
+            PositionUsesPivotPoint = true,
+        };
+        view.Add(textLabel);
+    }
+
+    private void CreateGeneralVisualView(ref View view)
+    {
+        #region ColorVisual
+        Tizen.NUI.Visuals.ColorVisual colorVisual = new Tizen.NUI.Visuals.ColorVisual()
+        {
+            Color = new Color(1.0f, 0.0f, 0.0f, 0.9f),
+            CornerRadius = new Vector4(0.15f, 0.15f, 0.15f, 0.15f),
+            CornerRadiusPolicy = VisualTransformPolicyType.Relative,
+
+            Width = 1.1f,
+            Height = 1.1f,
+
+            BlurRadius = mViewSize * 0.05f,
+            OffsetX = 0.1f,
+            OffsetY = 0.05f,
+
+            ExtraWidth = mViewSize * 0.15f,
+            ExtraHeight = -mViewSize * 0.05f,
+        };
+        view.AddVisual(colorVisual);
+        #endregion
+
+        #region ImageVisual
+        Tizen.NUI.Visuals.ImageVisual imageVisual = new Tizen.NUI.Visuals.ImageVisual()
+        {
+            ResourceUrl = IMAGE_PATH[0],
+            CornerRadius = new Vector4(0.15f, 0.15f, 0.15f, 0.15f),
+            CornerRadiusPolicy = VisualTransformPolicyType.Relative,
+            BorderlineWidth = mViewSize * 0.05f,
+            BorderlineColor = Color.Green,
+            BorderlineOffset = 1.0f,
+
+            Width = mViewSize,
+            Height = mViewSize,
+
+            WidthPolicy = VisualTransformPolicyType.Absolute,
+            HeightPolicy = VisualTransformPolicyType.Absolute,
+        };
+        view.AddVisual(imageVisual);
+        #endregion
+
+        #region TextVisual
+        Tizen.NUI.Visuals.TextVisual textVisual = new Tizen.NUI.Visuals.TextVisual()
+        {
+            Text = "1",
+            PointSize = 20.0f,
+
+            Width = mViewSize,
+            Height = mViewSize,
+
+            OffsetY = mViewSize * 0.25f,
+
+            Origin = Visual.AlignType.Center,
+            PivotPoint = Visual.AlignType.Center,
+
+            WidthPolicy = VisualTransformPolicyType.Absolute,
+            HeightPolicy = VisualTransformPolicyType.Absolute,
+            OffsetYPolicy = VisualTransformPolicyType.Absolute,
+        };
+        view.AddVisual(textVisual);
+        #endregion
+
+        #region BorderVisual
+        Tizen.NUI.Visuals.BorderVisual borderVisual = new Tizen.NUI.Visuals.BorderVisual()
+        {
+            BorderColor = Color.Blue,
+            BorderWidth = mViewSize * 0.05f,
+            AntiAliasing = false, // For speed up
+        };
+        view.AddVisual(borderVisual);
+        #endregion
+    }
+
+    protected override void OnCreate()
+    {
+        // Up call to the Base class first
+        base.OnCreate();
+        Activate();
+    }
+
+    /// <summary>
+    /// The main entry point for the application.
+    /// </summary>
+    [global::System.STAThread] // Forces app to use one thread to access NUI
+    static void Main(string[] args)
+    {
+        VisualTestExample example = new VisualTestExample();
+        example.Run(args);
+    }
+}
diff --git a/test/Tizen.NUI.VisualTest/res/image/gallery-small-1.jpg b/test/Tizen.NUI.VisualTest/res/image/gallery-small-1.jpg
new file mode 100644 (file)
index 0000000..cac624f
Binary files /dev/null and b/test/Tizen.NUI.VisualTest/res/image/gallery-small-1.jpg differ
diff --git a/test/Tizen.NUI.VisualTest/shared/res/Tizen.NUI.VisualTest.png b/test/Tizen.NUI.VisualTest/shared/res/Tizen.NUI.VisualTest.png
new file mode 100644 (file)
index 0000000..ef30093
Binary files /dev/null and b/test/Tizen.NUI.VisualTest/shared/res/Tizen.NUI.VisualTest.png differ
diff --git a/test/Tizen.NUI.VisualTest/tizen-manifest.xml b/test/Tizen.NUI.VisualTest/tizen-manifest.xml
new file mode 100755 (executable)
index 0000000..7a85ab7
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns="http://tizen.org/ns/packages" api-version="6" package="org.tizen.example.Tizen.NUI.VisualTest" version="1.0.0">
+  <profile name="common" />
+  <ui-application appid="org.tizen.example.Tizen.NUI.VisualTest"
+                                       exec="VisualTest.dll"
+                                       type="dotnet-nui"
+                                       multiple="false"
+                                       taskmanage="true"
+                                       nodisplay="false"
+                                       launch_mode="single"
+                                       >
+    <label>Tizen.NUI.VisualTest</label>
+    <icon>Tizen.NUI.VisualTest.png</icon>
+    <metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
+  </ui-application>
+</manifest>