[NUI] Enable selectors work in View : EnableControlState (#1851)
authorJiyun Yang <ji.yang@samsung.com>
Fri, 24 Jul 2020 01:47:19 +0000 (10:47 +0900)
committerGitHub <noreply@github.com>
Fri, 24 Jul 2020 01:47:19 +0000 (10:47 +0900)
* Previously, the View did not support ControlState so that selector values are not applied to the View.
* Introduce a new property EnableControlState.
  If this property is set to true, the View can have a touch related ControlState (such as Pressed) when touch.
  By default, it is false in View, true in Control.
  Note that if the value is true, the View will be a touch receptor.

Signed-off-by: Jiyun Yang <ji.yang@samsung.com>
src/Tizen.NUI.Components/Controls/Button.Internal.cs
src/Tizen.NUI.Components/Controls/Button.cs
src/Tizen.NUI.Components/Controls/Control.cs
src/Tizen.NUI.Components/Controls/SelectButton.cs
src/Tizen.NUI/src/public/BaseComponents/ControlState.cs
src/Tizen.NUI/src/public/BaseComponents/Style/ViewStyle.cs
src/Tizen.NUI/src/public/BaseComponents/Style/ViewStyleBindableProperty.cs
src/Tizen.NUI/src/public/BaseComponents/View.cs
src/Tizen.NUI/src/public/BaseComponents/ViewBindableProperty.cs
src/Tizen.NUI/src/public/BaseComponents/ViewEvent.cs
src/Tizen.NUI/src/public/BaseComponents/ViewInternal.cs

index dd0c0fb..2bea1dd 100755 (executable)
@@ -81,6 +81,59 @@ namespace Tizen.NUI.Components
             Extension?.OnRelayout(this);
         }
 
+        /// <inheritdoc/>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override bool HandleControlStateOnTouch(Touch touch)
+        {
+            if (!IsEnabled || null == touch)
+            {
+                return false;
+            }
+
+            PointStateType state = touch.GetState(0);
+
+            switch (state)
+            {
+                case PointStateType.Down:
+                    isPressed = true;
+                    Extension?.SetTouchInfo(touch);
+                    UpdateState();
+                    return true;
+                case PointStateType.Interrupted:
+                    isPressed = false;
+                    UpdateState();
+                    return true;
+                case PointStateType.Up:
+                    {
+                        bool clicked = isPressed && IsEnabled;
+
+                        isPressed = false;
+
+                        if (IsSelectable)
+                        {
+                            Extension?.SetTouchInfo(touch);
+                            IsSelected = !IsSelected;
+                        }
+                        else
+                        {
+                            Extension?.SetTouchInfo(touch);
+                            UpdateState();
+                        }
+
+                        if (clicked)
+                        {
+                            ClickedEventArgs eventArgs = new ClickedEventArgs();
+                            OnClickedInternal(eventArgs);
+                        }
+
+                        return true;
+                    }
+                default:
+                    break;
+            }
+            return base.HandleControlStateOnTouch(touch);
+        }
+
         /// <summary>
         /// Update Button State.
         /// </summary>
index 9225147..7ddf2d4 100755 (executable)
@@ -720,52 +720,6 @@ namespace Tizen.NUI.Components
         /// <since_tizen> 8 </since_tizen>
         public override bool OnTouch(Touch touch)
         {
-            if (!IsEnabled || null == touch)
-            {
-                return false;
-            }
-
-            PointStateType state = touch.GetState(0);
-
-            switch (state)
-            {
-                case PointStateType.Down:
-                    isPressed = true;
-                    Extension?.SetTouchInfo(touch);
-                    UpdateState();
-                    return true;
-                case PointStateType.Interrupted:
-                    isPressed = false;
-                    UpdateState();
-                    return true;
-                case PointStateType.Up:
-                    {
-                        bool clicked = isPressed && IsEnabled;
-
-                        isPressed = false;
-
-                        if (IsSelectable)
-                        {
-                            Extension?.SetTouchInfo(touch);
-                            IsSelected = !IsSelected;
-                        }
-                        else
-                        {
-                            Extension?.SetTouchInfo(touch);
-                            UpdateState();
-                        }
-
-                        if (clicked)
-                        {
-                            ClickedEventArgs eventArgs = new ClickedEventArgs();
-                            OnClickedInternal(eventArgs);
-                        }
-
-                        return true;
-                    }
-                default:
-                    break;
-            }
             return base.OnTouch(touch);
         }
 
index fc3abce..0d608bc 100755 (executable)
@@ -241,37 +241,6 @@ namespace Tizen.NUI.Components
         protected virtual void OnTapGestureDetected(object source, TapGestureDetector.DetectedEventArgs e) { }
 
         /// <summary>
-        /// Called after a touch event is received by the owning view.<br />
-        /// CustomViewBehaviour.REQUIRES_TOUCH_EVENTS must be enabled during construction. See CustomView(ViewWrapperImpl.CustomViewBehaviour behaviour).<br />
-        /// </summary>
-        /// <param name="touch">The touch event.</param>
-        /// <returns>True if the event should be consumed.</returns>
-        /// <since_tizen> 6 </since_tizen>
-        /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public override bool OnTouch(Touch touch)
-        {
-            // Handle Normal and Pressed states
-            PointStateType state = touch.GetState(0);
-            switch(state)
-            {
-                case PointStateType.Down:
-                    ControlState = ControlState.Pressed;
-                    break;
-                case PointStateType.Interrupted:
-                case PointStateType.Up:
-                    if (ControlState == ControlState.Pressed)
-                    {
-                        ControlState = ControlState.Normal;
-                    }
-                    break;
-                default:
-                    break;
-            }
-            return false;
-        }
-
-        /// <summary>
         /// Update by style.
         /// </summary>
         /// <since_tizen> 6 </since_tizen>
@@ -307,6 +276,8 @@ namespace Tizen.NUI.Components
             tapGestureDetector.Attach(this);
             tapGestureDetector.Detected += OnTapGestureDetected;
 
+            EnableControlState = true;
+
             StyleManager.Instance.ThemeChangedEvent += OnThemeChangedEvent;
         }
     }
index 65ed893..baa39e8 100755 (executable)
@@ -174,13 +174,20 @@ namespace Tizen.NUI.Components
         [EditorBrowsable(EditorBrowsableState.Never)]
         public override bool OnTouch(Touch touch)
         {
+            return base.OnTouch(touch);
+        }
+
+        /// <inheritdoc/>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override bool HandleControlStateOnTouch(Touch touch)
+        {
             if (false == IsEnabled)
             {
                 return false;
             }
 
             PointStateType state = touch.GetState(0);
-            bool ret = base.OnTouch(touch);
+            bool ret = base.HandleControlStateOnTouch(touch);
             switch (state)
             {
                 case PointStateType.Up:
index c844f06..5d60fc1 100644 (file)
@@ -245,6 +245,37 @@ namespace Tizen.NUI.BaseComponents
         /// <returns>The <see cref="ControlState"/> containing the result of the addition.</returns>
         [EditorBrowsable(EditorBrowsableState.Never)]
         public static ControlState operator +(ControlState lhs, ControlState rhs) => Create(lhs, rhs);
+
+        /// <summary>
+        /// The substraction operator.
+        /// </summary>
+        /// <param name="lhs">A <see cref="ControlState"/> on the left hand side.</param>
+        /// <param name="rhs">A <see cref="ControlState"/> on the right hand side.</param>
+        /// <returns>The <see cref="ControlState"/> containing the result of the substraction.</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static ControlState operator -(ControlState lhs, ControlState rhs)
+        {
+            if (!lhs.IsCombined)
+            {
+                return ReferenceEquals(lhs, rhs) ? Normal : lhs;
+            }
+            
+            var rest = lhs.stateList.Except(rhs.stateList);
+
+            if (rest.Count() == 0)
+            {
+                return Normal;
+            }
+
+            if (rest.Count() == 1)
+            {
+                return rest.First();
+            }
+
+            ControlState newState = new ControlState();
+            newState.stateList.AddRange(rest);
+            return newState;
+        }
     }
 
     /// <summary>
index 0d0cf0a..84a0b95 100755 (executable)
@@ -73,6 +73,7 @@ namespace Tizen.NUI.BaseComponents
         private ViewLayoutDirectionType? layoutDirection;
         private Extents margin;
         private float? weight;
+        private bool? enableControlState;
 
         private Selector<ImageShadow> imageShadow;
         private Selector<Shadow> boxShadow;
@@ -661,6 +662,16 @@ namespace Tizen.NUI.BaseComponents
         }
 
         /// <summary>
+        /// The EnableControlState value of the View.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool? EnableControlState
+        {
+            get => (bool?)GetValue(EnableControlStateProperty);
+            set => SetValue(EnableControlStateProperty, value);
+        }
+
+        /// <summary>
         /// Set style's bindable properties from the view.
         /// </summary>
         /// <param name="view">The view that includes property data.</param>
index fcdd29b..5146ba9 100755 (executable)
@@ -850,5 +850,18 @@ namespace Tizen.NUI.BaseComponents
             var viewStyle = (ViewStyle)bindable;
             return viewStyle.cornerRadius;
         });
+
+        /// <summary>
+        /// EnableControlState property
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty EnableControlStateProperty = BindableProperty.Create("EnableControlState", typeof(bool?), typeof(ViewStyle), null, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            ((ViewStyle)bindable).enableControlState = (bool?)newValue;
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            return ((ViewStyle)bindable).enableControlState;
+        });
     }
 }
index e0641ae..3f80c68 100755 (executable)
@@ -2274,6 +2274,24 @@ namespace Tizen.NUI.BaseComponents
         }
 
         /// <summary>
+        /// If this property is set to true, the View can have a touch related ControlState (such as Pressed) when touch.
+        /// By default, it is false in View, true in Control.
+        /// Note that if the value is true, the View will be a touch receptor.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool EnableControlState
+        {
+            get
+            {
+                return (bool)GetValue(EnableControlStateProperty);
+            }
+            set
+            {
+                SetValue(EnableControlStateProperty, value);
+            }
+        }
+
+        /// <summary>
         /// Get Style, it is abstract function and must be override.
         /// </summary>
         /// <since_tizen> 6 </since_tizen>
index ac46ce4..a0493bb 100755 (executable)
@@ -1558,6 +1558,32 @@ namespace Tizen.NUI.BaseComponents
         [EditorBrowsable(EditorBrowsableState.Never)]
         public static readonly BindableProperty XamlStyleProperty = BindableProperty.Create("XamlStyle", typeof(Style), typeof(View), default(Style), propertyChanged: (bindable, oldvalue, newvalue) => ((View)bindable)._mergedStyle.Style = (Style)newvalue);
 
+        /// <summary>
+        /// EnableControlState property
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty EnableControlStateProperty = BindableProperty.Create(nameof(EnableControlState), typeof(bool), typeof(View), false, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            var view = (View)bindable;
+            bool prev = view.enableControlState;
+            view.enableControlState = (bool)newValue;
+
+            if (prev != view.enableControlState)
+            {
+                if (prev)
+                {
+                    view.TouchEvent -= view.EmptyOnTouch;
+                }
+                else
+                {
+                    view.TouchEvent += view.EmptyOnTouch;
+                }
+            }
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            return ((View)bindable).enableControlState;
+        });
 
         #region Selectors
         internal static readonly BindableProperty BackgroundImageSelectorProperty = BindableProperty.Create("BackgroundImageSelector", typeof(Selector<string>), typeof(View), null, propertyChanged: (bindable, oldValue, newValue) =>
index ec8f48c..2a2d74f 100755 (executable)
@@ -244,7 +244,6 @@ namespace Tizen.NUI.BaseComponents
                 {
                     this.TouchSignal().Disconnect(_touchDataCallback);
                 }
-
             }
         }
 
@@ -728,11 +727,19 @@ namespace Tizen.NUI.BaseComponents
 
             e.Touch = Tizen.NUI.Touch.GetTouchFromPtr(touchData);
 
+            bool consumed = false;
+
             if (_touchDataEventHandler != null)
             {
-                return _touchDataEventHandler(this, e);
+                consumed = _touchDataEventHandler(this, e);
             }
-            return false;
+
+            if (enableControlState && !consumed)
+            {
+                consumed = HandleControlStateOnTouch(e.Touch);
+            }
+
+            return consumed;
         }
 
         // Callback for View Hover signal
index 34d55cf..73a469d 100755 (executable)
@@ -253,6 +253,11 @@ namespace Tizen.NUI.BaseComponents
             }
         }
 
+        /// <summary>
+        /// Indicates that this View should listen Touch event to handle its ControlState.
+        /// </summary>
+        private bool enableControlState = false;
+
         private int LeftFocusableViewId
         {
             get
@@ -1101,6 +1106,32 @@ namespace Tizen.NUI.BaseComponents
             Interop.View.delete_View(swigCPtr);
         }
 
+        /// <summary>
+        /// The touch event handler for ControlState.
+        /// Please change ControlState value by touch state if needed.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected virtual bool HandleControlStateOnTouch(Touch touch)
+        {
+            switch(touch.GetState(0))
+            {
+                case PointStateType.Down:
+                    ControlState += ControlState.Pressed;
+                    break;
+                case PointStateType.Interrupted:
+                case PointStateType.Up:
+                    if (ControlState.Contains(ControlState.Pressed))
+                    {
+                        ControlState -= ControlState.Pressed;
+                    }
+                    break;
+                default:
+                    break;
+            }
+
+            return false;
+        }
+
         private void DisConnectFromSignals()
         {
             // Save current CPtr.
@@ -1315,5 +1346,10 @@ namespace Tizen.NUI.BaseComponents
                 Tizen.NUI.Object.SetProperty(swigCPtr, View.Property.SHADOW, new PropertyValue(map));
             }
         }
+
+        private bool EmptyOnTouch(object target, TouchEventArgs args)
+        {
+            return false;
+        }
     }
 }