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 + + +