[NUI] Fix text padding issue
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / BaseComponents / TextField.cs
index f9dd39d..c7b1d8b 100755 (executable)
@@ -31,13 +31,29 @@ namespace Tizen.NUI.BaseComponents
     /// <since_tizen> 3 </since_tizen>
     public partial class TextField : View
     {
+        static private string defaultStyleName = "Tizen.NUI.BaseComponents.TextField";
+        static private string defaultFontFamily = "TizenSans";
+        private static SystemFontTypeChanged systemFontTypeChanged = new SystemFontTypeChanged();
+        private static SystemLocaleLanguageChanged systemLocaleLanguageChanged = new SystemLocaleLanguageChanged();
         private string textFieldTextSid = null;
         private string textFieldPlaceHolderTextSid = null;
         private string textFieldPlaceHolderTextFocusedSid = null;
-        private bool systemlangTextFlag = false;
         private InputMethodContext inputMethodCotext = null;
+        private string fontFamily = defaultFontFamily;
         private float fontSizeScale = 1.0f;
-        private bool hasFontSizeChangedCallback = false;
+        private bool hasSystemLanguageChanged = false;
+        private bool hasSystemFontSizeChanged = false;
+        private bool hasSystemFontTypeChanged = false;
+        private bool isSettingTextInCSharp = false;
+
+        private Vector4 internalPlaceholderTextColor = null;
+        private Vector4 internalPrimaryCursorColor = null;
+        private Vector4 internalSecondaryCursorColor = null;
+        private Vector4 internalSelectionHighlightColor = null;
+        private Vector4 internalInputColor = null;
+        private Color internalTextColor = null;
+        private Color internalGrabHandleColor = null;
+
 
         static TextField() { }
 
@@ -45,7 +61,7 @@ namespace Tizen.NUI.BaseComponents
         /// Creates the TextField control.
         /// </summary>
         /// <since_tizen> 3 </since_tizen>
-        public TextField() : this(Interop.TextField.New(), true)
+        public TextField() : this(Interop.TextField.New(ThemeManager.GetStyle(defaultStyleName) == null ? false : true), true)
         {
             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
         }
@@ -56,7 +72,7 @@ namespace Tizen.NUI.BaseComponents
         /// <param name="shown">false : Not displayed (hidden), true : displayed (shown)</param>
         /// This will be public opened in next release of tizen after ACR done. Before ACR, it is used as HiddenAPI (InhouseAPI).
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public TextField(bool shown) : this(Interop.TextField.New(), true)
+        public TextField(bool shown) : this(Interop.TextField.New(ThemeManager.GetStyle(defaultStyleName) == null ? false : true), true)
         {
             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
             SetVisible(shown);
@@ -77,6 +93,8 @@ namespace Tizen.NUI.BaseComponents
             {
                 SetVisible(false);
             }
+            Focusable = true;
+            TextChanged += TextFieldTextChanged;
         }
 
         internal TextField(global::System.IntPtr cPtr, bool cMemoryOwn, bool shown = true) : base(cPtr, cMemoryOwn, null)
@@ -85,16 +103,13 @@ namespace Tizen.NUI.BaseComponents
             {
                 SetVisible(false);
             }
+            Focusable = true;
+            TextChanged += TextFieldTextChanged;
         }
 
         internal TextField(TextField handle, bool shown = true) : this(Interop.TextField.NewTextField(TextField.getCPtr(handle)), true)
         {
             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-
-            if (!shown)
-            {
-                SetVisible(false);
-            }
         }
 
         internal enum ExceedPolicyType
@@ -103,6 +118,11 @@ namespace Tizen.NUI.BaseComponents
             ExceedPolicyClip
         }
 
+        private bool HasStyle()
+        {
+            return ThemeManager.GetStyle(this.GetType()) == null ? false : true;
+        }
+
         /// <summary>
         /// The TranslatableText property.<br />
         /// The text can set the SID value.<br />
@@ -228,7 +248,7 @@ namespace Tizen.NUI.BaseComponents
             }
             set
             {
-                SetValueAndForceSendChangeSignal(TextProperty, value);
+                SetValue(TextProperty, value);
                 NotifyPropertyChanged();
             }
         }
@@ -287,6 +307,50 @@ namespace Tizen.NUI.BaseComponents
             }
         }
 
+        private string InternalFontFamily
+        {
+            get
+            {
+                if (HasStyle())
+                    return fontFamily;
+                else
+                    return Object.InternalGetPropertyString(this.SwigCPtr, TextField.Property.FontFamily);
+            }
+            set
+            {
+                string newFontFamily;
+
+                if (string.Equals(fontFamily, value)) return;
+
+                fontFamily = value;
+                if (fontFamily == Tizen.NUI.FontFamily.UseSystemSetting)
+                {
+                    try
+                    {
+                        newFontFamily = SystemSettings.FontType;
+                    }
+                    catch (Exception e)
+                    {
+                        Console.WriteLine("{0} Exception caught.", e);
+                        newFontFamily = defaultFontFamily;
+                    }
+                    AddSystemSettingsFontTypeChanged();
+                }
+                else
+                {
+                    newFontFamily = fontFamily;
+                    RemoveSystemSettingsFontTypeChanged();
+                }
+
+                SetInternalFontFamily(newFontFamily);
+            }
+        }
+
+        private void SetInternalFontFamily(string fontFamily)
+        {
+            Object.InternalSetPropertyString(this.SwigCPtr, TextField.Property.FontFamily, (string)fontFamily);
+        }
+
         /// <summary>
         /// The FontStyle property.<br />
         /// The requested font style to use.<br />
@@ -361,6 +425,7 @@ namespace Tizen.NUI.BaseComponents
         /// The size of font in points.<br />
         /// </summary>
         /// <since_tizen> 3 </since_tizen>
+        [Binding.TypeConverter(typeof(PointSizeTypeConverter))]
         public float PointSize
         {
             get
@@ -498,7 +563,7 @@ namespace Tizen.NUI.BaseComponents
         /// Deprecated.(API Level 6) Use Shadow instead.
         /// The property cascade chaining set is possible. For example, this (textField.ShadowOffset.X = 0.1f;) is possible.
         /// </remarks>
-        [Obsolete("Please do not use this ShadowOffset(Deprecated). Please use Shadow instead.")]
+        [Obsolete("Do not use this ShadowOffset(Deprecated). Use Shadow instead.")]
         public Vector2 ShadowOffset
         {
             get
@@ -549,7 +614,7 @@ namespace Tizen.NUI.BaseComponents
         /// Deprecated.(API Level 6) Use Shadow instead.
         /// The property cascade chaining set is possible. For example, this (textField.ShadowColor.X = 0.1f;) is possible.
         /// </remarks>
-        [Obsolete("Please do not use this ShadowColor(Deprecated). Please use Shadow instead.")]
+        [Obsolete("Do not use this ShadowColor(Deprecated). Use Shadow instead.")]
         public Vector4 ShadowColor
         {
             get
@@ -782,6 +847,24 @@ namespace Tizen.NUI.BaseComponents
         }
 
         /// <summary>
+        /// The SelectionPopupStyle property.<br />
+        /// The style of the text selection popup can be set through SelectionPopupStyle property.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public PropertyMap SelectionPopupStyle
+        {
+            get
+            {
+                return (PropertyMap)GetValue(SelectionPopupStyleProperty);
+            }
+            set
+            {
+                SetValue(SelectionPopupStyleProperty, value);
+                NotifyPropertyChanged();
+            }
+        }
+
+        /// <summary>
         /// The SelectionHandleImageLeft property.<br />
         /// The image to display for the left selection handle.<br />
         /// The selectionHandleImageLeft map contains the following key :<br />
@@ -1127,7 +1210,7 @@ namespace Tizen.NUI.BaseComponents
         /// The settings to relating to the System's Input Method, Key and Value.<br />
         /// </summary>
         /// <remarks>
-        /// <see cref="InputMethod"/> is a class encapsulating the input method map. Please use the <see cref="InputMethod"/> class for this property.
+        /// <see cref="InputMethod"/> is a class encapsulating the input method map. Use the <see cref="InputMethod"/> class for this property.
         /// </remarks>
         /// <example>
         /// The following example demonstrates how to set the InputMethodSettings property.
@@ -1286,6 +1369,7 @@ namespace Tizen.NUI.BaseComponents
         /// The font's size of the new input text in points.<br />
         /// </summary>
         /// <since_tizen> 3 </since_tizen>
+        [Binding.TypeConverter(typeof(PointSizeTypeConverter))]
         public float InputPointSize
         {
             get
@@ -1681,6 +1765,7 @@ namespace Tizen.NUI.BaseComponents
         /// The size of font in pixels.<br />
         /// </summary>
         /// <since_tizen> 3 </since_tizen>
+        [Binding.TypeConverter(typeof(FloatGraphicsTypeConverter))]
         public float PixelSize
         {
             get
@@ -1851,9 +1936,13 @@ namespace Tizen.NUI.BaseComponents
         }
 
         /// <summary>
-        /// Specify primary cursor (caret) position in text control.
+        /// PrimaryCursorPosition property.<br />
+        /// Specify the position of the primary cursor (caret) in text control.
         /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
+        /// <remarks>
+        /// If the value set is out of range (negative or greater than or equal the number of characters in Text) then the PrimaryCursorPosition is moved to the end of Text (the number of characters in Text).
+        /// </remarks>
+        /// <since_tizen> 10 </since_tizen>
         public int PrimaryCursorPosition
         {
             get
@@ -1927,6 +2016,27 @@ namespace Tizen.NUI.BaseComponents
         }
 
         /// <summary>
+        /// The spaces between characters in Pixels.
+        /// <remarks>
+        /// A positive value will make the characters far apart (expanded) and a negative value will bring them closer (condensed).<br />
+        /// The default value is 0.f which does nothing.
+        ///</remarks>
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float CharacterSpacing
+        {
+            get
+            {
+                return (float)GetValue(CharacterSpacingProperty);
+            }
+            set
+            {
+                SetValue(CharacterSpacingProperty, value);
+                NotifyPropertyChanged();
+            }
+        }
+
+        /// <summary>
         /// Set InputFilter to TextField.
         /// </summary>
         /// <param name="inputFilter">The InputFilter</param>
@@ -2232,6 +2342,19 @@ namespace Tizen.NUI.BaseComponents
         {
             get
             {
+                return (float)GetValue(FontSizeScaleProperty);
+            }
+            set
+            {
+                SetValue(FontSizeScaleProperty, value);
+                NotifyPropertyChanged();
+            }
+        }
+
+        private float InternalFontSizeScale
+        {
+            get
+            {
                 return fontSizeScale;
             }
             set
@@ -2255,19 +2378,23 @@ namespace Tizen.NUI.BaseComponents
                         systemSettingsFontSize = SystemSettingsFontSize.Normal;
                     }
                     newFontSizeScale = TextUtils.GetFontSizeScale(systemSettingsFontSize);
-                    addFontSizeChangedCallback();
+                    AddSystemSettingsFontSizeChanged();
                 }
                 else
                 {
                     newFontSizeScale = fontSizeScale;
-                    removeFontSizeChangedCallback();
+                    RemoveSystemSettingsFontSizeChanged();
                 }
 
-                SetValue(FontSizeScaleProperty, newFontSizeScale);
-                NotifyPropertyChanged();
+                SetInternalFontSizeScale(newFontSizeScale);
             }
         }
 
+        private void SetInternalFontSizeScale(float fontSizeScale)
+        {
+            Object.InternalSetPropertyFloat(this.SwigCPtr, TextField.Property.FontSizeScale, (float)fontSizeScale);
+        }
+
         /// <summary>
         /// The EnableFontSizeScale property.<br />
         /// Whether the font size scale is enabled. (The default value is true)
@@ -2286,28 +2413,6 @@ namespace Tizen.NUI.BaseComponents
             }
         }
 
-        /// Only used by the IL of xaml, will never changed to not hidden.
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public override bool IsCreateByXaml
-        {
-            get
-            {
-                return base.IsCreateByXaml;
-            }
-            set
-            {
-                base.IsCreateByXaml = value;
-
-                if (value == true)
-                {
-                    this.TextChanged += (obj, e) =>
-                    {
-                        this.Text = e.TextField.Text;
-                    };
-                }
-            }
-        }
-
         /// <summary>
         /// Get the InputMethodContext instance.
         /// </summary>
@@ -2385,12 +2490,22 @@ namespace Tizen.NUI.BaseComponents
                 return;
             }
 
-            if (systemlangTextFlag)
+
+            internalPlaceholderTextColor?.Dispose();
+            internalPrimaryCursorColor?.Dispose();
+            internalSecondaryCursorColor?.Dispose();
+            internalSelectionHighlightColor?.Dispose();
+            internalInputColor?.Dispose();
+            internalTextColor?.Dispose();
+            internalGrabHandleColor?.Dispose();
+
+            if (hasSystemLanguageChanged)
             {
-                SystemSettings.LocaleLanguageChanged -= SystemSettings_LocaleLanguageChanged;
+                systemLocaleLanguageChanged.Remove(SystemSettingsLocaleLanguageChanged);
             }
 
-            removeFontSizeChangedCallback();
+            RemoveSystemSettingsFontTypeChanged();
+            RemoveSystemSettingsFontSizeChanged();
 
             if (type == DisposeTypes.Explicit)
             {
@@ -2414,6 +2529,11 @@ namespace Tizen.NUI.BaseComponents
                     this.MaxLengthReachedSignal().Disconnect(textFieldMaxLengthReachedCallbackDelegate);
                 }
 
+                if (textFieldSelectionStartedCallbackDelegate != null)
+                {
+                    this.SelectionStartedSignal().Disconnect(textFieldSelectionStartedCallbackDelegate);
+                }
+
                 if (textFieldSelectionClearedCallbackDelegate != null)
                 {
                     this.SelectionClearedSignal().Disconnect(textFieldSelectionClearedCallbackDelegate);
@@ -2430,6 +2550,9 @@ namespace Tizen.NUI.BaseComponents
                 }
             }
 
+            TextChanged -= TextFieldTextChanged;
+            GetInputMethodContext()?.DestroyContext();
+
             base.Dispose(type);
         }
 
@@ -2437,21 +2560,31 @@ namespace Tizen.NUI.BaseComponents
         [EditorBrowsable(EditorBrowsableState.Never)]
         protected override void ReleaseSwigCPtr(System.Runtime.InteropServices.HandleRef swigCPtr)
         {
-            // In order to speed up IME hide, temporarily add
-            GetInputMethodContext()?.DestroyContext();
             Interop.TextField.DeleteTextField(swigCPtr);
         }
 
+        internal override LayoutItem CreateDefaultLayout()
+        {
+            return new TextFieldLayout();
+        }
+
+        internal void SetTextWithoutTextChanged(string text)
+        {
+            invokeTextChanged = false;
+            Tizen.NUI.Object.SetProperty((System.Runtime.InteropServices.HandleRef)SwigCPtr, TextField.Property.TEXT, new Tizen.NUI.PropertyValue(text));
+            invokeTextChanged = true;
+        }
+
         private string SetTranslatable(string textFieldSid)
         {
             string translatableText = null;
             translatableText = NUIApplication.MultilingualResourceManager?.GetString(textFieldSid, new CultureInfo(SystemSettings.LocaleLanguage.Replace("_", "-")));
             if (translatableText != null)
             {
-                if (systemlangTextFlag == false)
+                if (hasSystemLanguageChanged == false)
                 {
-                    SystemSettings.LocaleLanguageChanged += SystemSettings_LocaleLanguageChanged;
-                    systemlangTextFlag = true;
+                    systemLocaleLanguageChanged.Add(SystemSettingsLocaleLanguageChanged);
+                    hasSystemLanguageChanged = true;
                 }
                 return translatableText;
             }
@@ -2462,7 +2595,7 @@ namespace Tizen.NUI.BaseComponents
             }
         }
 
-        private void SystemSettings_LocaleLanguageChanged(object sender, LocaleLanguageChangedEventArgs e)
+        private void SystemSettingsLocaleLanguageChanged(object sender, LocaleLanguageChangedEventArgs e)
         {
             if (textFieldTextSid != null)
             {
@@ -2481,44 +2614,90 @@ namespace Tizen.NUI.BaseComponents
         private void SystemSettingsFontSizeChanged(object sender, FontSizeChangedEventArgs e)
         {
             float newFontSizeScale = TextUtils.GetFontSizeScale(e.Value);
-            SetValue(FontSizeScaleProperty, newFontSizeScale);
-            NotifyPropertyChanged();
+            SetInternalFontSizeScale(newFontSizeScale);
         }
 
-        private void addFontSizeChangedCallback()
+        private void AddSystemSettingsFontSizeChanged()
         {
-            if (hasFontSizeChangedCallback != true)
+            if (hasSystemFontSizeChanged != true)
             {
                 try
                 {
-                    SystemSettings.FontSizeChanged += SystemSettingsFontSizeChanged;
-                    hasFontSizeChangedCallback = true;
+                    SystemFontSizeChangedManager.Add(SystemSettingsFontSizeChanged);
+                    hasSystemFontSizeChanged = true;
                 }
                 catch (Exception e)
                 {
                     Console.WriteLine("{0} Exception caught.", e);
-                    hasFontSizeChangedCallback = false;
+                    hasSystemFontSizeChanged = false;
                 }
             }
         }
 
-        private void removeFontSizeChangedCallback()
+        private void RemoveSystemSettingsFontSizeChanged()
         {
-            if (hasFontSizeChangedCallback == true)
+            if (hasSystemFontSizeChanged == true)
             {
                 try
                 {
-                    SystemSettings.FontSizeChanged -= SystemSettingsFontSizeChanged;
-                    hasFontSizeChangedCallback = false;
+                    SystemFontSizeChangedManager.Remove(SystemSettingsFontSizeChanged);
+                    hasSystemFontSizeChanged = false;
                 }
                 catch (Exception e)
                 {
                     Console.WriteLine("{0} Exception caught.", e);
-                    hasFontSizeChangedCallback = true;
+                    hasSystemFontSizeChanged = true;
                 }
             }
         }
 
+        private void SystemSettingsFontTypeChanged(object sender, FontTypeChangedEventArgs e)
+        {
+            SetInternalFontFamily(e.Value);
+        }
+
+        private void AddSystemSettingsFontTypeChanged()
+        {
+            if (HasStyle() && !hasSystemFontTypeChanged)
+            {
+                try
+                {
+                    systemFontTypeChanged.Add(SystemSettingsFontTypeChanged);
+                    hasSystemFontTypeChanged = true;
+                }
+                catch (Exception e)
+                {
+                    Console.WriteLine("{0} Exception caught.", e);
+                    hasSystemFontTypeChanged = false;
+                }
+            }
+        }
+        
+        private void RemoveSystemSettingsFontTypeChanged()
+        {
+            if (hasSystemFontTypeChanged)
+            {
+                try
+                {
+                    systemFontTypeChanged.Remove(SystemSettingsFontTypeChanged);
+                    hasSystemFontTypeChanged = false;
+                }
+                catch (Exception e)
+                {
+                    Console.WriteLine("{0} Exception caught.", e);
+                    hasSystemFontTypeChanged = true;
+                }
+            }
+        }
+
+        private void TextFieldTextChanged(object sender, TextChangedEventArgs e)
+        {
+            if (!isSettingTextInCSharp)
+            {
+                EnforceNotifyBindedInstance(TextProperty);
+            }
+        }
+
         internal new class Property
         {
             internal static readonly int TEXT = Interop.TextField.TextGet();
@@ -2543,6 +2722,7 @@ namespace Tizen.NUI.BaseComponents
             internal static readonly int GrabHandlePressedImage = Interop.TextField.GrabHandlePressedImageGet();
             internal static readonly int ScrollThreshold = Interop.TextField.ScrollThresholdGet();
             internal static readonly int ScrollSpeed = Interop.TextField.ScrollSpeedGet();
+            internal static readonly int SelectionPopupStyle = Interop.TextField.SelectionPopupStyleGet();
             internal static readonly int SelectionHandleImageLeft = Interop.TextField.SelectionHandleImageLeftGet();
             internal static readonly int SelectionHandleImageRight = Interop.TextField.SelectionHandleImageRightGet();
             internal static readonly int SelectionHandlePressedImageLeft = Interop.TextField.SelectionHandlePressedImageLeftGet();
@@ -2585,7 +2765,7 @@ namespace Tizen.NUI.BaseComponents
             internal static readonly int EllipsisPosition = Interop.TextField.EllipsisPositionGet();
             internal static readonly int InputFilter = Interop.TextField.InputFilterGet();
             internal static readonly int Strikethrough = Interop.TextField.StrikethroughGet();
-
+            internal static readonly int CharacterSpacing = Interop.TextField.CharacterSpacingGet();
         }
 
         internal class InputStyle
@@ -2644,5 +2824,65 @@ namespace Tizen.NUI.BaseComponents
         {
             GrabHandleColor = new Color(r, g, b, a);
         }
+
+        internal class TextFieldLayout : LayoutItem
+        {
+            protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
+            {
+                // Padding will be automatically applied by DALi TextField.
+                var totalWidth = widthMeasureSpec.Size.AsDecimal();
+                var totalHeight = heightMeasureSpec.Size.AsDecimal();
+                var minSize = Owner.MinimumSize;
+                var maxSize = Owner.MaximumSize;
+                var naturalSize = Owner.GetNaturalSize();
+
+                if (((TextField)Owner).Text.Length == 0)
+                {
+                    // Calculate height of TextField by setting Text with " ".
+                    // By calling SetTextWithoutTextChanged, TextChanged callback is not called for this.
+                    ((TextField)Owner).SetTextWithoutTextChanged(" ");
+
+                    // Store original WidthSpecification to restore it after setting ResizePolicy.
+                    var widthSpecification = Owner.WidthSpecification;
+
+                    // In DALi's Size logic, if Width or Height is set to be 0, then
+                    // ResizePolicy is not changed to Fixed.
+                    // This causes Size changes after NUI Layout's OnMeasure is finished.
+                    // e.g. TextField's Width fills to its parent although Text is null and
+                    //      WidthSpecification is WrapContent.
+                    // To prevent the Size changes, WidthResizePolicy is set to be Fixed
+                    // in advance if Text is null.
+                    Owner.WidthResizePolicy = ResizePolicyType.Fixed;
+
+                    // Restore WidthSpecification because ResizePolicy changes WidthSpecification.
+                    Owner.WidthSpecification = widthSpecification;
+
+                    naturalSize = Owner.GetNaturalSize();
+
+                    // Restore TextField's Text after calculating height of TextField.
+                    // By calling SetTextWithoutTextChanged, TextChanged callback is not called for this.
+                    ((TextField)Owner).SetTextWithoutTextChanged("");
+                }
+
+                if (widthMeasureSpec.Mode != MeasureSpecification.ModeType.Exactly)
+                {
+                    totalWidth = Math.Min(Math.Max(naturalSize.Width, minSize.Width), maxSize.Width);
+                }
+
+                if (heightMeasureSpec.Mode != MeasureSpecification.ModeType.Exactly)
+                {
+                    totalHeight = Math.Min(Math.Max(naturalSize.Height, minSize.Height), maxSize.Height);
+                }
+
+                widthMeasureSpec = new MeasureSpecification(new LayoutLength(totalWidth), MeasureSpecification.ModeType.Exactly);
+                heightMeasureSpec = new MeasureSpecification(new LayoutLength(totalHeight), MeasureSpecification.ModeType.Exactly);
+
+                MeasuredSize.StateType childWidthState = MeasuredSize.StateType.MeasuredSizeOK;
+                MeasuredSize.StateType childHeightState = MeasuredSize.StateType.MeasuredSizeOK;
+
+                SetMeasuredDimensions(ResolveSizeAndState(new LayoutLength(totalWidth), widthMeasureSpec, childWidthState),
+                                      ResolveSizeAndState(new LayoutLength(totalHeight), heightMeasureSpec, childHeightState));
+            }
+        }
     }
 }