diff --git a/src/Tizen.NUI/src/internal/Common/VisualObjectsContainer.cs b/src/Tizen.NUI/src/internal/Common/VisualObjectsContainer.cs
new file mode 100644
index 00000000000..767b2eb882b
--- /dev/null
+++ b/src/Tizen.NUI/src/internal/Common/VisualObjectsContainer.cs
@@ -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
+{
+ ///
+ /// VisualObjectsContainer is a container for visual objects.
+ /// For each VisualObjectContainer, there is a corresponding view.
+ /// Each view can have only one VisualObjectsContainer per rangeType.
+ ///
+ ///
+ /// 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.
+ ///
+ internal class VisualObjectsContainer : BaseHandle
+ {
+ private List visuals = new List(); // Keep visual object reference.
+
+ ///
+ /// Creates an empty visual object handle.
+ ///
+ public VisualObjectsContainer() : this(Interop.VisualObjectsContainer.NewVisualObjectsContainer(), true, false)
+ {
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ ///
+ /// Creates an visual object with VisualObjectsContainer.
+ ///
+ 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;
+ }
+
+ ///
+ /// Dispose for VisualObjectsContainer
+ ///
+ [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
index 00000000000..95922aa690f
--- /dev/null
+++ b/src/Tizen.NUI/src/internal/Interop/Interop.VisualObject.cs
@@ -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
index 00000000000..865b4e67ebd
--- /dev/null
+++ b/src/Tizen.NUI/src/internal/Interop/Interop.VisualObjectsContainer.cs
@@ -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);
+ }
+ }
+}
diff --git a/src/Tizen.NUI/src/public/BaseComponents/ViewInternal.cs b/src/Tizen.NUI/src/public/BaseComponents/ViewInternal.cs
index 206cc9acdfa..ea3b60554fe 100755
--- a/src/Tizen.NUI/src/public/BaseComponents/ViewInternal.cs
+++ b/src/Tizen.NUI/src/public/BaseComponents/ViewInternal.cs
@@ -1425,6 +1425,15 @@ protected override void Dispose(DisposeTypes type)
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
index 00000000000..99ee999362b
--- /dev/null
+++ b/src/Tizen.NUI/src/public/BaseComponents/ViewVisuals.cs
@@ -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
+{
+ ///
+ /// View is the base class for all views.
+ ///
+ /// 3
+ public partial class View
+ {
+ #region Internal and Private
+ private List visualContainers = null;
+
+ ///
+ /// Range of visual for the container.
+ ///
+ internal struct ContainerRangeType
+ {
+ ///
+ /// Visual will be rendered under the shadow.
+ ///
+ internal static readonly int Shadow = Interop.VisualObjectsContainer.ContainerRangeTypeBackgroundEffectGet();
+
+ ///
+ /// Visual will be rendered under the background.
+ ///
+ internal static readonly int Background = Interop.VisualObjectsContainer.ContainerRangeTypeBackgroundGet();
+
+ ///
+ /// Visual will be rendered under the content.
+ /// It is default value.
+ ///
+ internal static readonly int Content = Interop.VisualObjectsContainer.ContainerRangeTypeContentGet();
+
+ ///
+ /// Visual will be rendered under the decoration.
+ ///
+ internal static readonly int Decoration = Interop.VisualObjectsContainer.ContainerRangeTypeDecorationGet();
+
+ ///
+ /// Visual will be rendered above the foreground effect.
+ ///
+ internal static readonly int ForegroundEffect = Interop.VisualObjectsContainer.ContainerRangeTypeForegroundEffectGet();
+ };
+ #endregion
+
+ #region Public Methods
+ ///
+ /// Add a Tizen.NUI.Visuals.VisualBase to the view.
+ ///
+ ///
+ /// 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.
+ ///
+ /// The visual to add.
+ /// True if the visual was added successfully, false otherwise.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool AddVisual(Tizen.NUI.Visuals.VisualBase visualBase)
+ {
+ return AddVisualInternal(visualBase, ContainerRangeType.Content);
+ }
+
+ ///
+ /// Remove a Tizen.NUI.Visuals.VisualBase from the view.
+ ///
+ ///
+ /// The value of all other Visuals.VisualBases will be changed automatically.
+ ///
+ /// The visual to remove.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void RemoveVisual(Tizen.NUI.Visuals.VisualBase visualBase)
+ {
+ if (visualContainers != null)
+ {
+ foreach (var visualContainer in visualContainers)
+ {
+ visualContainer?.RemoveVisualObject(visualBase);
+ }
+ }
+ }
+
+ ///
+ /// Get a Tizen.NUI.Visuals.VisualBase by sibling index
+ ///
+ /// Get visual base by sibling index
+ /// Thrown when index is out of bounds.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Tizen.NUI.Visuals.VisualBase GetVisualAt(uint index)
+ {
+ return GetVisualAtInternal(index, ContainerRangeType.Content);
+ }
+
+ ///
+ /// Get total number of Tizen.NUI.Visuals.VisualBase which we added using .
+ ///
+ /// Get the number of visual base.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public uint GetVisualsCount()
+ {
+ return GetVisualsCountInternal(ContainerRangeType.Content);
+ }
+
+ ///
+ /// Find Tizen.NUI.Visuals.VisualBase by name. Given name should not be empty.
+ ///
+ /// Get the visual base.
+ [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();
+ }
+
+ 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
+ }
+}
diff --git a/src/Tizen.NUI/src/public/Common/PropertyMap.cs b/src/Tizen.NUI/src/public/Common/PropertyMap.cs
index 5dc953a292b..b37e30b483d 100755
--- a/src/Tizen.NUI/src/public/Common/PropertyMap.cs
+++ b/src/Tizen.NUI/src/public/Common/PropertyMap.cs
@@ -99,10 +99,7 @@ public PropertyValue this[string key]
}
set
{
- using (PropertyKey pKey = new PropertyKey(key))
- {
- SetValue(pKey, value);
- }
+ SetValue(key, value);
}
}
@@ -121,10 +118,7 @@ public PropertyValue this[int key]
}
set
{
- using (PropertyKey pKey = new PropertyKey(key))
- {
- SetValue(pKey, value);
- }
+ SetValue(key, value);
}
}
@@ -277,6 +271,17 @@ public bool Remove(PropertyKey key)
return isRemoved;
}
+ ///
+ /// Removes the element by the specified integer key.
+ ///
+ /// The index key to find.
+ /// True if the element is removed, false otherwise.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool Remove(int key)
+ {
+ return Interop.PropertyMap.Remove(SwigCPtr, key);
+ }
+
///
/// Determines whether the PropertyMap contains the specified key.
///
@@ -416,7 +421,19 @@ internal void SetValue(PropertyKey key, PropertyValue value)
{
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.
diff --git a/src/Tizen.NUI/src/public/Visuals/VisualConstants.cs b/src/Tizen.NUI/src/public/Visuals/VisualConstants.cs
index c73700f4744..e80aa64f4d6 100755
--- a/src/Tizen.NUI/src/public/Visuals/VisualConstants.cs
+++ b/src/Tizen.NUI/src/public/Visuals/VisualConstants.cs
@@ -329,6 +329,11 @@ public enum VisualFittingModeType
///
[EditorBrowsable(EditorBrowsableState.Never)]
FitWidth,
+ ///
+ /// The visual should not use fitting mode.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ DontCare,
}
///
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
index 00000000000..c6b53e9f57e
--- /dev/null
+++ b/src/Tizen.NUI/src/public/Visuals/VisualObject/AdvancedTextVisual.cs
@@ -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
+{
+ ///
+ /// The text visual with advanced options.
+ ///
+ ///
+ /// It will be used when we want to control TextVisual with more options.
+ /// This visual allow to translated text with SID.
+ ///
+ [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
+ ///
+ /// The TranslatableText property.
+ /// The text can set the SID value.
+ ///
+ ///
+ /// ResourceManager about multilingual is null.
+ ///
+ 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;
+ }
+ }
+
+ ///
+ [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
index 00000000000..3875bc53273
--- /dev/null
+++ b/src/Tizen.NUI/src/public/Visuals/VisualObject/AnimatedImageVisual.cs
@@ -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
+{
+ ///
+ /// The visual which can display and control an animated image resource.
+ /// We can also set image sequences by using ResourceUrlList and FrameDelay property.
+ ///
+ [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 resourceUrls = null;
+ #endregion
+
+ #region Constructor
+ ///
+ /// Creates an visual object.
+ ///
+ [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
+ ///
+ /// Gets and Sets the url list in the AnimatedImageVisual.
+ ///
+ ///
+ /// If we set ResourceUrlList as non-null, ImageVisual.ResourceUrl will be ignored.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public List ResourceUrlList
+ {
+ get
+ {
+ return resourceUrls;
+ }
+ set
+ {
+ resourceUrls = value;
+
+ // Always request to create new visual
+ visualCreationRequiredFlag = true;
+ ReqeustProcessorOnceEvent();
+ }
+ }
+
+ ///
+ /// The number of milliseconds between each frame in the Image-Array animation.
+ ///
+ ///
+ /// This is only used when ResourceUrlList(multiple string) are provided.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Sets or gets the stop behavior.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Get the number of total frames.
+ /// Or -1 if image is invalid, or not loaded yet.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Set or get the current frame. When setting a specific frame, it is displayed as a still image.
+ ///
+ ///
+ /// 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.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Gets and Sets the batch size for pre-loading images in the AnimatedImageVisual. (Advanced)
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Gets and Sets the cache size for loading images in the AnimatedImageVisual. (Advanced)
+ ///
+ [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
+ ///
+ /// Play the animated image.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Play()
+ {
+ // Sync as current properties
+ UpdateVisualPropertyMap();
+
+ Interop.VisualObject.DoActionWithEmptyAttributes(SwigCPtr, ActionPlay);
+ }
+
+ ///
+ /// Pause the animated image.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Pause()
+ {
+ // Sync as current properties
+ UpdateVisualPropertyMap();
+
+ Interop.VisualObject.DoActionWithEmptyAttributes(SwigCPtr, ActionPause);
+ }
+
+ ///
+ /// Stop the animated image.
+ ///
+ [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
index 00000000000..45186458d53
--- /dev/null
+++ b/src/Tizen.NUI/src/public/Visuals/VisualObject/BorderVisual.cs
@@ -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
+{
+ ///
+ /// Simple visual to render a solid border.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class BorderVisual : VisualBase
+ {
+ #region Constructor
+ ///
+ /// Creates an visual object.
+ ///
+ [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
+ ///
+ /// Gets or sets the color of the border.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Gets or sets the width of the border (in pixels).
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Gets or sets whether the anti-aliasing of the border is required. default is false.
+ ///
+ [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
index 00000000000..9d6d8d7c12a
--- /dev/null
+++ b/src/Tizen.NUI/src/public/Visuals/VisualObject/ColorVisual.cs
@@ -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
+{
+ ///
+ /// Simple visual to render a solid color.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class ColorVisual : VisualBase
+ {
+ #region Constructor
+ ///
+ /// Creates an visual object.
+ ///
+ [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
+ ///
+ /// Blur radius for this visual
+ ///
+ ///
+ /// This property will ignore BorderlineWidth property when we set BlurRadius property at least one time.
+ ///
+ [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
+ ///
+ /// 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.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// The width for the borderline of the visual.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// The color for the borderline of the visual.
+ /// It is Color.Black by default.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ [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
index 00000000000..e31665ae813
--- /dev/null
+++ b/src/Tizen.NUI/src/public/Visuals/VisualObject/ImageVisual.cs
@@ -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
+{
+ ///
+ /// The visual which can display an image resource.
+ ///
+ [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
+
+ ///
+ /// Creates an visual object.
+ ///
+ [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
+ ///
+ /// Gets or sets the URL of the image.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Gets or sets the image area to be displayed.
+ /// It is a rectangular area.
+ /// 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.
+ /// If not specified, the default value is Vector4 (0.0, 0.0, 1.0, 1.0), i.e., the entire area of the image.
+ /// For normal quad images only.
+ /// Optional.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// ImageView PreMultipliedAlpha, type Boolean.
+ /// Image must be initialized.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Synchronously load the image for the visual.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Gets or sets whether to automatically correct the orientation of an image.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Gets or sets the URL of the alpha mask.
+ /// Optional.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Gets or sets scale factor to apply to the content image before masking.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Whether to crop image to mask or scale mask to fit image.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Gets or sets whether to apply mask on GPU or not.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Gets or sets whether to apply fast track uploading or not.
+ ///
+ ///
+ /// If we use fast track uploading feature, It can upload texture without event-thead dependency. But also,
+ /// - Texture size is invalid until ResourceReady signal comes.
+ /// - Texture cannot be cached (We always try to load new image).
+ /// - Seamless visual change didn't supported.
+ /// - Alpha masking didn't supported. If you try, It will load as normal case.
+ /// - Synchronous loading didn't supported. If you try, It will load as normal case.
+ /// - Reload action didn't supported. If you try, It will load as normal case.
+ /// - Atlas loading didn't supported. If you try, It will load as normal case.
+ /// - Custom shader didn't supported. If you try, It will load as normal case.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Gets or sets the Image Visual release policy.
+ /// It decides if a texture should be released from the cache or kept to reduce the loading time.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Gets or sets the desired image width.
+ /// If not specified, the actual image width is used.
+ /// For normal quad images only.
+ /// Optional.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Gets or sets the desired image height.
+ /// If not specified, the actual image height is used.
+ /// For normal quad images only.
+ /// Optional.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Gets or sets the Image Visual image loading policy.
+ /// It decides if a texture should be loaded immediately after source set or only after the visual is added to the window.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Gets or sets the wrap mode for the u coordinate.
+ /// It decides how the texture should be sampled when the u coordinate exceeds the range of 0.0 to 1.0.
+ /// If not specified, the default is WrapModeType.Default(CLAMP).
+ /// For normal quad images only.
+ /// Optional.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Gets or sets the wrap mode for the v coordinate.
+ /// It decides how the texture should be sampled when the v coordinate exceeds the range of 0.0 to 1.0.
+ /// 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.
+ /// If not specified, the default is WrapModeType.Default(CLAMP).
+ /// For normal quad images only.
+ /// Optional.
+ ///
+ [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
+ ///
+ /// 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.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// The width for the borderline of the visual.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// The color for the borderline of the visual.
+ /// It is Color.Black by default.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ [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
+ ///
+ /// Reload image.
+ ///
+ [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
index 00000000000..8ab1fb72d8d
--- /dev/null
+++ b/src/Tizen.NUI/src/public/Visuals/VisualObject/NPatchVisual.cs
@@ -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
+{
+ ///
+ /// 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.
+ ///
+ ///
+ /// Following ImageVisual properties are not supported in NPatchVisual.
+ /// - CornerRadius
+ /// - BorderlineWidth
+ /// - AlphaMaskUrl
+ ///
+ ///
+ /// We assume that the image is a n-patch image always. So it does not support other image formats, like svg, lottie.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class NPatchVisual : ImageVisual
+ {
+ #region Constructor
+ ///
+ /// Creates an visual object.
+ ///
+ [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
+ ///
+ /// Gets or sets whether to draw the borders only (If true).
+ /// If not specified, the default is false.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// The border of the regular image is in the order: left, right, bottom, top.
+ ///
+ ///
+ /// Note that it is not mean the value from 9 patch image.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// An alpha value for mixing between the masked main NPatch image and the auxiliary image.
+ ///
+ [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
index 00000000000..5bcd517a2d8
--- /dev/null
+++ b/src/Tizen.NUI/src/public/Visuals/VisualObject/TextVisual.cs
@@ -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
+{
+ ///
+ /// The visual which can display simple text.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class TextVisual : VisualBase
+ {
+ #region Constructor
+ ///
+ /// Creates an visual object.
+ ///
+ [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
+ ///
+ /// The Text property.
+ /// The text to display in the UTF-8 format.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// The requested font family to use.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// The size of font in points.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// The single-line or multi-line layout option.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// The line horizontal alignment.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// The line vertical alignment.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// The color of the text.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Whether the mark-up processing is enabled.
+ ///
+ [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
index 00000000000..b82bcc0e274
--- /dev/null
+++ b/src/Tizen.NUI/src/public/Visuals/VisualObject/VisualBase.cs
@@ -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
+{
+ ///
+ /// The base class of all visual in namespace Tizen.NUI.Visuals.
+ /// This class is abstract class. We cannot use it without type of Properties.
+ ///
+ ///
+ /// 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.
+ ///
+ ///
+ /// animation.AnimateTo(view, "BorderlineOffset", -1.0f);
+ ///
+ [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
+ ///
+ /// Creates an visual object.
+ ///
+ [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
+ ///
+ /// The update mode of this VisualBase property.
+ /// Default is Auto.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public enum PropertyUpdateModeType
+ {
+ ///
+ /// Update property automatically, by NUI event loop.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ Auto,
+ ///
+ /// Update property manually.
+ /// Need to call function manually to update property.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ Manual,
+ }
+ #endregion
+
+ #region Properties
+ ///
+ /// Sibling order of this VisualBase.
+ ///
+ ///
+ /// 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.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Type of this VisualObject. It will be set at construction time.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Name of the visual.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string Name { get; set; }
+
+ ///
+ /// The way of visual property update.
+ /// Default is PropertyUpdateModeType.Auto.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public PropertyUpdateModeType PropertyUpdateMode
+ {
+ set
+ {
+ visualCreationManually = (value == PropertyUpdateModeType.Manual);
+ }
+ get
+ {
+ return visualCreationManually ? PropertyUpdateModeType.Manual : PropertyUpdateModeType.Auto;
+ }
+ }
+ #endregion
+
+ #region Visual Properties
+ ///
+ /// Color for the visual. Default color is White
+ ///
+ ///
+ /// This is exclusive with the Opacity property.
+ /// Opacity property be applied as Color.A.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Opacity for the visual.
+ ///
+ ///
+ /// This is exclusive with the Color property.
+ ///
+ [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
+ ///
+ /// FittingMode for the visual.
+ ///
+ ///
+ /// 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.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Width of the visual.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float Width
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.width != value)
+ {
+ transformInfo.width = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.width;
+ }
+ }
+
+ ///
+ /// Height of the visual.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float Height
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.height != value)
+ {
+ transformInfo.height = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.height;
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public VisualTransformPolicyType WidthPolicy
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.widthPolicy != value)
+ {
+ transformInfo.widthPolicy = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.widthPolicy;
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public VisualTransformPolicyType HeightPolicy
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.heightPolicy != value)
+ {
+ transformInfo.heightPolicy = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.heightPolicy;
+ }
+ }
+
+ ///
+ /// OffsetX of the visual.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float OffsetX
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.offsetX != value)
+ {
+ transformInfo.offsetX = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.offsetX;
+ }
+ }
+
+ ///
+ /// OffsetY of the visual.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float OffsetY
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.offsetY != value)
+ {
+ transformInfo.offsetY = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.offsetY;
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public VisualTransformPolicyType OffsetXPolicy
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.offsetXPolicy != value)
+ {
+ transformInfo.offsetXPolicy = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.offsetXPolicy;
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public VisualTransformPolicyType OffsetYPolicy
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.offsetYPolicy != value)
+ {
+ transformInfo.offsetYPolicy = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.offsetYPolicy;
+ }
+ }
+
+ ///
+ /// Origin of the visual from view.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Pivot point of the visual from view.
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// Extra width of the visual as absolute policy.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float ExtraWidth
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.extraWidth != value)
+ {
+ transformInfo.extraWidth = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.extraWidth;
+ }
+ }
+
+ ///
+ /// Extra height of the visual as absolute policy.
+ ///
+ [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
+ ///
+ /// Get attached View.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Tizen.NUI.BaseComponents.View GetOwner()
+ {
+ var container = GetVisualContainer();
+ if (container != null)
+ {
+ return container.GetView();
+ }
+ return null;
+ }
+
+ ///
+ /// Detach from View.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Detach()
+ {
+ if (Disposed)
+ {
+ return;
+ }
+
+ var container = GetVisualContainer();
+ if (container != null)
+ {
+ container.RemoveVisualObject(this);
+ }
+
+ Interop.VisualObject.Detach(SwigCPtr);
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ ///
+ /// Raise above the next sibling visual object
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Raise()
+ {
+ Interop.VisualObject.Raise(SwigCPtr);
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ ///
+ /// Lower below the previous sibling visual object
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Lower()
+ {
+ Interop.VisualObject.Lower(SwigCPtr);
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ ///
+ /// Raise above all other sibling visual objects
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void RaiseToTop()
+ {
+ Interop.VisualObject.RaiseToTop(SwigCPtr);
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ ///
+ /// Raise below all other sibling visual objects
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void LowerToBottom()
+ {
+ Interop.VisualObject.LowerToBottom(SwigCPtr);
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ ///
+ /// Raise above target visual objects. No effects if visual object is already above target.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void RaiseAbove(Visuals.VisualBase target)
+ {
+ Interop.VisualObject.RaiseAbove(SwigCPtr, Visuals.VisualBase.getCPtr(target));
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ ///
+ /// Lower below target visual objects. No effects if visual object is already below target.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void LowerBelow(Visuals.VisualBase target)
+ {
+ Interop.VisualObject.LowerBelow(SwigCPtr, Visuals.VisualBase.getCPtr(target));
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ ///
+ /// Update visual properties manually.
+ ///
+ [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;
+ }
+
+ ///
+ /// Unregister visual from control. It will not remove cached data.
+ ///
+ internal void UnregisterVisual()
+ {
+ using var tempPropertyMap = new PropertyMap();
+ Interop.VisualObject.CreateVisual(SwigCPtr, PropertyMap.getCPtr(tempPropertyMap));
+ }
+
+ ///
+ /// Set or Get visual property.
+ ///
+ ///
+ /// This property might change the type of visual. We should not set it from subclass of VisualBase.
+ ///
+ 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()
+ {
+ }
+
+ ///
+ /// 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)
+ ///
+ [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();
+ }
+
+ ///
+ /// Get visual property by key.
+ /// If we found value in local cached result, return that.
+ /// Else, get synced native map and return that.
+ ///
+ /// Matched value. If there is no matched value, return null.
+ 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;
+ }
+
+ ///
+ /// Get visual property by key from native engine.
+ ///
+ /// Matched value. If there is no matched value, return null.
+ internal PropertyValue GetCurrentVisualProperty(int key)
+ {
+ return Properties?.Find(key);
+ }
+
+ ///
+ /// Get visual property from NUI cached map by key.
+ ///
+ /// Matched value. If there is no matched value, return null.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal virtual PropertyValue GetCachedVisualProperty(int key)
+ {
+ return cachedVisualPropertyMap?.Find(key);
+ }
+
+ ///
+ /// Change visual transform information.
+ ///
+ [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();
+ }
+ }
+
+ ///
+ /// Dispose for VisualObject
+ ///
+ [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
index 00000000000..2f243127961
--- /dev/null
+++ b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/VisualTest.cs
@@ -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
index 00000000000..f1224f56044
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
index 00000000000..f12d91018c8
--- /dev/null
+++ b/test/Tizen.NUI.VisualTest/Tizen.NUI.VisualTest.code-workspace
@@ -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
index 00000000000..37a222e9466
--- /dev/null
+++ b/test/Tizen.NUI.VisualTest/Tizen.NUI.VisualTest.csproj
@@ -0,0 +1,24 @@
+
+
+ Exe
+ net6.0
+ VisualTest
+
+
+
+ portable
+
+
+ None
+
+
+
+
+
+
+
+
+
+ True
+
+
diff --git a/test/Tizen.NUI.VisualTest/Tizen.NUI.VisualTest.sln b/test/Tizen.NUI.VisualTest/Tizen.NUI.VisualTest.sln
new file mode 100755
index 00000000000..18e709629b5
--- /dev/null
+++ b/test/Tizen.NUI.VisualTest/Tizen.NUI.VisualTest.sln
@@ -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
index 00000000000..61d7dadd358
--- /dev/null
+++ b/test/Tizen.NUI.VisualTest/VisualTest.cs
@@ -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();
+ }
+
+ ///
+ /// The main entry point for the application.
+ ///
+ [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
index 00000000000..cac624f9496
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
index 00000000000..ef30093cdca
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
index 00000000000..7a85ab77cc5
--- /dev/null
+++ b/test/Tizen.NUI.VisualTest/tizen-manifest.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+ Tizen.NUI.VisualTest.png
+
+
+