[NUI] Add Scrollbar and CircularScrollbar (#1628)
authorJiyun Yang <ji.yang@samsung.com>
Wed, 27 May 2020 07:32:31 +0000 (16:32 +0900)
committerGitHub <noreply@github.com>
Wed, 27 May 2020 07:32:31 +0000 (16:32 +0900)
* Implement Arc Visual to support arc shapes used in CircularScrollbar
* Move previous ScrollBar class code from Scrollbar.cs to ImageScrollBar.cs.
* Implement new Scrollbar class based on a ScrollbarBase class.
* Implement new CircularScrollbar class based on a ScrollbarBase class.

Signed-off-by: Jiyun Yang <ji.yang@samsung.com>
src/Tizen.NUI.Components/Controls/ImageScrollBar.cs [new file with mode: 0755]
src/Tizen.NUI.Components/Controls/Scrollbar.cs [changed mode: 0755->0644]
src/Tizen.NUI.Components/Controls/ScrollbarBase.cs [new file with mode: 0644]
src/Tizen.NUI.Components/Style/ImageScrollBarStyle.cs [new file with mode: 0755]
src/Tizen.NUI.Components/Style/ScrollbarStyle.cs [changed mode: 0755->0644]
src/Tizen.NUI.Wearable/src/public/CircularScrollbar.cs [new file with mode: 0644]
src/Tizen.NUI.Wearable/src/public/WearableStyle/CircularScrollbarStyle.cs [new file with mode: 0644]
src/Tizen.NUI/src/public/VisualConstants.cs
src/Tizen.NUI/src/public/VisualMaps.cs
src/Tizen.NUI/src/public/Visuals/ArcVisual.cs [new file with mode: 0644]
src/Tizen.NUI/src/public/Visuals/ColorVisual.cs

diff --git a/src/Tizen.NUI.Components/Controls/ImageScrollBar.cs b/src/Tizen.NUI.Components/Controls/ImageScrollBar.cs
new file mode 100755 (executable)
index 0000000..16f66db
--- /dev/null
@@ -0,0 +1,657 @@
+/*
+ * Copyright(c) 2019 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 Tizen.NUI.BaseComponents;
+using System.ComponentModel;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Components
+{
+    /// <summary>
+    /// The ScrollBar class of nui component. It allows users to recognize the direction and the range of lists/content.
+    /// </summary>
+    /// <remarks>
+    /// Please note that this class will be replaced with Scrollbar class in the near future.
+    /// </remarks>
+    /// <since_tizen> 6 </since_tizen>
+    public class ScrollBar : Control
+    {
+        /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty DirectionProperty = BindableProperty.Create(nameof(Direction), typeof(DirectionType), typeof(ScrollBar), DirectionType.Horizontal, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            var instance = (ScrollBar)bindable;
+            if (newValue != null)
+            {
+                instance.Style.Direction = (DirectionType?)newValue;
+                instance.UpdateValue();
+            }
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            var instance = (ScrollBar)bindable;
+            return instance.Style.Direction;
+        });
+        /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty MaxValueProperty = BindableProperty.Create(nameof(MaxValue), typeof(int), typeof(ScrollBar), default(int), propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            var instance = (ScrollBar)bindable;
+            if (newValue != null)
+            {
+                if ((int)newValue >= 0)
+                {
+                    instance.maxValue = (int)newValue;
+                    instance.UpdateValue();
+                }
+            }
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            var instance = (ScrollBar)bindable;
+            return instance.maxValue;
+        });
+        /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty MinValueProperty = BindableProperty.Create(nameof(MinValue), typeof(int), typeof(ScrollBar), default(int), propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            var instance = (ScrollBar)bindable;
+            if (newValue != null)
+            {
+                if ((int)newValue >= 0)
+                {
+                    instance.minValue = (int)newValue;
+                    instance.UpdateValue();
+                }
+            }
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            var instance = (ScrollBar)bindable;
+            return instance.minValue;
+        });
+        /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty CurrentValueProperty = BindableProperty.Create(nameof(CurrentValue), typeof(int), typeof(ScrollBar), default(int), propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            var instance = (ScrollBar)bindable;
+            if (newValue != null)
+            {
+                if ((int)newValue >= 0)
+                {
+                    instance.curValue = (int)newValue;
+                    instance.UpdateValue();
+                }
+            }
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            var instance = (ScrollBar)bindable;
+            return instance.curValue;
+        });
+        /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty DurationProperty = BindableProperty.Create(nameof(Duration), typeof(uint), typeof(ScrollBar), default(uint), propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            var instance = (ScrollBar)bindable;
+            if (newValue != null)
+            {
+                instance.Style.Duration = (uint)newValue;
+                if (instance.scrollAniPlayer != null)
+                {
+                    instance.scrollAniPlayer.Duration = (int)(uint)newValue;
+                }
+            }
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            var instance = (ScrollBar)bindable;
+            return instance.Style.Duration;
+        });
+
+        private ImageView trackImage;
+        private ImageView thumbImage;
+        private Animation scrollAniPlayer = null;
+        private float thumbImagePosX;
+        private float thumbImagePosY;
+        private bool enableAni = false;
+        private int minValue;
+        private int maxValue;
+        private int curValue;
+        static ScrollBar() { }
+
+        /// <summary>
+        /// The constructor of ScrollBar.
+        /// </summary>
+        /// <since_tizen> 6 </since_tizen>
+        public ScrollBar() : base()
+        {
+            Initialize();
+        }
+
+        /// <summary>
+        /// The constructor of ScrollBar with specific style.
+        /// </summary>
+        /// <param name="style">style name</param>
+        /// <since_tizen> 8 </since_tizen>
+        public ScrollBar(string style) : base(style)
+        {
+            Initialize();
+        }
+
+        /// <summary>
+        /// The constructor of ScrollBar with specific style.
+        /// </summary>
+        /// <param name="scrollBarStyle">The style object to initialize the ScrollBar.</param>
+        /// <since_tizen> 8 </since_tizen>
+        public ScrollBar(ScrollBarStyle scrollBarStyle) : base(scrollBarStyle)
+        {
+            Initialize();
+        }
+
+        /// <summary>
+        /// The direction type of the Scroll.
+        /// </summary>
+        /// <since_tizen> 6 </since_tizen>
+        public enum DirectionType
+        {
+            /// <summary>
+            /// The Horizontal type.
+            /// </summary>
+            /// <since_tizen> 6 </since_tizen>
+            Horizontal,
+
+            /// <summary>
+            /// The Vertical type.
+            /// </summary>
+            /// <since_tizen> 6 </since_tizen>
+            Vertical
+        }
+
+        #region public property 
+        /// <summary>
+        /// Get style of scrollbar.
+        /// </summary>
+        /// <since_tizen> 8 </since_tizen>
+        public new ScrollBarStyle Style => ViewStyle as ScrollBarStyle;
+
+        /// <summary>
+        /// The property to get/set the direction of the ScrollBar.
+        /// </summary>
+        /// <since_tizen> 6 </since_tizen>
+        public DirectionType Direction
+        {
+            get
+            {
+                return (DirectionType)GetValue(DirectionProperty);
+            }
+            set
+            {
+                SetValue(DirectionProperty, value);
+            }
+        }
+
+        /// <summary>
+        /// The property to get/set the size of the thumb object.
+        /// </summary>
+        /// <exception cref="InvalidOperationException">Throw when ThumbSize is null.</exception>
+        /// <example>
+        /// <code>
+        /// ScrollBar scroll;
+        /// try
+        /// {
+        ///     scroll.ThumbSize = new Size(500, 10, 0);
+        /// }
+        /// catch(InvalidOperationException e)
+        /// {
+        ///     Tizen.Log.Error(LogTag, "Failed to set ThumbSize value : " + e.Message);
+        /// }
+        /// </code>
+        /// </example>
+        /// <since_tizen> 6 </since_tizen>
+        public Size ThumbSize
+        {
+            get
+            {
+                return Style?.Thumb?.Size;
+            }
+            set
+            {
+                if (null != Style?.Thumb)
+                {
+                    Style.Thumb.Size = value;
+                    RelayoutRequest();
+                }
+            }
+        }
+
+        /// <summary>
+        /// The property to get/set the image URL of the track object.
+        /// </summary>
+        /// <since_tizen> 6 </since_tizen>
+        public string TrackImageURL
+        {
+            get
+            {
+                return Style?.Track?.ResourceUrl?.All;
+            }
+            set
+            {
+                if (null != Style?.Track)
+                {
+                    Style.Track.ResourceUrl = value;
+                    RelayoutRequest();
+                }
+            }
+        }
+
+        /// <summary>
+        /// The property to get/set the color of the track object.
+        /// </summary>
+        /// <since_tizen> 6 </since_tizen>
+        public Color TrackColor
+        {
+            get
+            {
+                return Style?.Track?.BackgroundColor?.All;
+            }
+            set
+            {
+                if (null != Style?.Track)
+                {
+                    Style.Track.BackgroundColor = value;
+                    RelayoutRequest();
+                }
+            }
+        }
+
+        /// <summary>
+        /// The property to get/set the color of the thumb object.
+        /// </summary>
+        /// <since_tizen> 6 </since_tizen>
+        public Color ThumbColor
+        {
+            get
+            {
+                return Style?.Thumb?.BackgroundColor?.All;
+            }
+            set
+            {
+                if(null != Style?.Thumb)
+                {
+                    Style.Thumb.BackgroundColor = value;
+                    RelayoutRequest();
+                }
+            }
+        }
+
+        /// <summary>
+        /// The property to get/set the max value of the ScrollBar.
+        /// </summary>
+        /// <since_tizen> 6 </since_tizen>
+        public int MaxValue
+        {
+            get
+            {
+                return (int)GetValue(MaxValueProperty);
+            }
+            set
+            {
+                SetValue(MaxValueProperty, value);
+            }
+        }
+
+        /// <summary>
+        /// The property to get/set the min value of the ScrollBar.
+        /// </summary>
+        /// <since_tizen> 6 </since_tizen>
+        public int MinValue
+        {
+            get
+            {
+                return (int)GetValue(MinValueProperty);
+            }
+            set
+            {
+                SetValue(MinValueProperty, value);
+            }
+        }
+
+        /// <summary>
+        /// The property to get/set the current value of the ScrollBar.
+        /// </summary>
+        /// <exception cref="ArgumentOutOfRangeException">Throw when Current value is less than Min value, or greater than Max value.</exception>
+        /// <example>
+        /// <code>
+        /// ScrollBar scroll;
+        /// scroll.MaxValue = 100;
+        /// scroll.MinValue = 0;
+        /// try
+        /// {
+        ///     scroll.CurrentValue = 50;
+        /// }
+        /// catch(ArgumentOutOfRangeException e)
+        /// {
+        ///     Tizen.Log.Error(LogTag, "Failed to set Current value : " + e.Message);
+        /// }
+        /// </code>
+        /// </example>
+        /// <since_tizen> 6 </since_tizen>
+        public int CurrentValue
+        {
+            get
+            {
+                return (int)GetValue(CurrentValueProperty);
+            }
+            set
+            {
+                SetValue(CurrentValueProperty, value);
+            }
+        }
+
+        /// <summary>
+        /// Property to set/get animation duration.
+        /// </summary>
+        /// <since_tizen> 6 </since_tizen>
+        public uint Duration
+        {
+            get
+            {
+                return (uint)GetValue(DurationProperty);
+            }
+            set
+            {
+                SetValue(DurationProperty, value);
+            }
+        }
+        #endregion
+
+        /// <summary>
+        /// Method to set current value. The thumb object would move to the corresponding position with animation or not.
+        /// </summary>
+        /// <param name="currentValue">The special current value.</param>
+        /// <param name="enableAnimation">Enable move with animation or not, the default value is true.</param>
+        /// <exception cref="ArgumentOutOfRangeException">Throw when current size is less than the min value, or greater than the max value.</exception>
+        /// <example>
+        /// <code>
+        /// ScrollBar scroll;
+        /// scroll.MinValue = 0;
+        /// scroll.MaxValue = 100;
+        /// try
+        /// {
+        ///     scroll.SetCurrentValue(50);
+        /// }
+        /// catch(ArgumentOutOfRangeException e)
+        /// {
+        ///     Tizen.Log.Error(LogTag, "Failed to set current value : " + e.Message);
+        /// }
+        /// </code>
+        /// </example>
+        /// <since_tizen> 6 </since_tizen>
+        public void SetCurrentValue(int currentValue, bool enableAnimation = true)
+        {
+            if (currentValue < minValue || currentValue > maxValue)
+            {
+                //TNLog.E("Current value is less than the Min value, or greater than the Max value. currentValue = " + currentValue + ";");
+#pragma warning disable CA2208 // Instantiate argument exceptions correctly
+                throw new ArgumentOutOfRangeException("Wrong Current value. It shoud be greater than the Min value, and less than the Max value!");
+#pragma warning restore CA2208 // Instantiate argument exceptions correctly
+            }
+
+            enableAni = enableAnimation;
+            CurrentValue = currentValue;
+        }
+
+        /// <summary>
+        /// Dispose ScrollBar.
+        /// </summary>
+        /// <param name="type">The DisposeTypes value.</param>
+        /// <since_tizen> 6 </since_tizen>
+        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.
+
+                Utility.Dispose(trackImage);
+                Utility.Dispose(thumbImage);
+
+                if (scrollAniPlayer != null)
+                {
+                    scrollAniPlayer.Stop();
+                    scrollAniPlayer.Clear();
+                    scrollAniPlayer.Dispose();
+                    scrollAniPlayer = null;
+                }
+            }
+
+            //Release your own unmanaged resources here.
+            //You should not access any managed member here except static instance.
+            //because the execution order of Finalizes is non-deterministic.
+            //Unreference this from if a static instance refer to this. 
+
+            //You must call base.Dispose(type) just before exit.
+            base.Dispose(type);
+        }
+
+        /// <summary>
+        /// Get Scrollbar style.
+        /// </summary>
+        /// <returns>The default scrollbar style.</returns>
+        /// <since_tizen> 8 </since_tizen>
+        protected override ViewStyle GetViewStyle()
+        {
+            return new ScrollBarStyle();
+        }
+
+        /// <summary>
+        /// Theme change callback when theme is changed, this callback will be trigger.
+        /// </summary>
+        /// <param name="sender">The sender</param>
+        /// <param name="e">The event data</param>
+        /// <since_tizen> 8 </since_tizen>
+        protected override void OnThemeChangedEvent(object sender, StyleManager.ThemeChangeEventArgs e)
+        {
+            ScrollBarStyle tempStyle = StyleManager.Instance.GetViewStyle(style) as ScrollBarStyle;
+            if (tempStyle != null)
+            {
+                Style.CopyFrom(tempStyle);
+                UpdateValue();
+            }
+        }
+
+        private void Initialize()
+        {
+            this.Focusable = false;
+
+            trackImage = new ImageView
+            {
+                Focusable = false,
+                WidthResizePolicy = ResizePolicyType.FillToParent,
+                HeightResizePolicy = ResizePolicyType.FillToParent,
+                PositionUsesPivotPoint = true,
+                ParentOrigin = Tizen.NUI.ParentOrigin.CenterLeft,
+                PivotPoint = Tizen.NUI.PivotPoint.CenterLeft
+            };
+            this.Add(trackImage);
+            trackImage.ApplyStyle(Style.Track);
+
+            thumbImage = new ImageView
+            {
+                Focusable = false,
+                WidthResizePolicy = ResizePolicyType.Fixed,
+                HeightResizePolicy = ResizePolicyType.Fixed,
+                PositionUsesPivotPoint = true,
+                ParentOrigin = Tizen.NUI.ParentOrigin.CenterLeft,
+                PivotPoint = Tizen.NUI.PivotPoint.CenterLeft
+            };
+            this.Add(thumbImage);
+            thumbImage.ApplyStyle(Style.Thumb);
+
+            scrollAniPlayer = new Animation(334);
+            scrollAniPlayer.DefaultAlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.Linear);
+
+            thumbImagePosX = 0;
+            thumbImagePosY = 0;
+            LayoutDirectionChanged += OnLayoutDirectionChanged;
+        }
+
+        private void OnLayoutDirectionChanged(object sender, LayoutDirectionChangedEventArgs e)
+        {
+            RelayoutRequest();
+        }
+
+        private void UpdateValue()
+        {
+            if (minValue >= maxValue || curValue < minValue || curValue > maxValue) return;
+
+            float width = (float)Size2D.Width;
+            float height = (float)Size2D.Height;
+            float thumbW = 0.0f;
+            float thumbH = 0.0f;
+            if (Style.Thumb.Size == null)
+            {
+                return;
+            }
+            else
+            {
+                thumbW = Style.Thumb.Size.Width;
+                thumbH = Style.Thumb.Size.Height;
+            }
+            float ratio = (float)(curValue - minValue) / (float)(maxValue - minValue);
+
+            if (Style.Direction == DirectionType.Horizontal)
+            {
+                if (LayoutDirection == ViewLayoutDirectionType.RTL)
+                {
+                    ratio = 1.0f - ratio;
+                }
+
+                float posX = ratio * (width - thumbW);
+                float posY = (height - thumbH) / 2.0f;
+
+                thumbImagePosX = posX;
+                if (null != scrollAniPlayer)
+                {
+                    scrollAniPlayer.Stop();
+                }
+
+                if (!enableAni)
+                {
+                    thumbImage.Position = new Position(posX, posY, 0);
+                }
+                else
+                {
+                    if (null != scrollAniPlayer)
+                    {
+                        scrollAniPlayer.Clear();
+                        scrollAniPlayer.AnimateTo(thumbImage, "PositionX", posX);
+                        scrollAniPlayer.Play();
+                    }
+                }
+            }
+            else
+            {
+                float posX = (width - thumbW) / 2.0f;
+                float posY = ratio * (height - thumbH);
+
+                thumbImagePosY = posY;
+                if (null != scrollAniPlayer)
+                {
+                    scrollAniPlayer.Stop();
+                }
+
+                if (!enableAni)
+                {
+                    thumbImage.Position = new Position(posX, posY, 0);
+                }
+                else
+                {
+                    if (null != scrollAniPlayer)
+                    {
+                        scrollAniPlayer.Clear();
+                        scrollAniPlayer.AnimateTo(thumbImage, "PositionY", posY);
+                        scrollAniPlayer.Play();
+                    }
+                }
+            }
+
+            if (enableAni) enableAni = false;
+        }
+
+        private DirectionType CurrentDirection()
+        {
+            DirectionType dir = DirectionType.Horizontal;
+            if (null != Style.Direction)
+            {
+                dir = Style.Direction.Value;
+            }
+            return dir;
+        }
+
+        private int CalculateCurrentValue(float offset, DirectionType dir)
+        {
+            if (dir == DirectionType.Horizontal)
+            {
+                thumbImagePosX += offset;
+                if (thumbImagePosX < 0)
+                {
+                    thumbImage.PositionX = 0;
+                    curValue = minValue;
+                }
+                else if (thumbImagePosX > Size2D.Width - thumbImage.Size2D.Width)
+                {
+                    thumbImage.PositionX = Size2D.Width - thumbImage.Size2D.Width;
+                    curValue = maxValue;
+                }
+                else
+                {
+                    thumbImage.PositionX = thumbImagePosX;
+                    curValue = (int)((thumbImagePosX / (float)(Size2D.Width - thumbImage.Size2D.Width)) * (float)(maxValue - minValue) + 0.5f);
+                }
+            }
+            else
+            {
+                thumbImagePosY += offset;
+                if (thumbImagePosY < 0)
+                {
+                    thumbImage.PositionY = 0;
+                    curValue = minValue;
+                }
+                else if (thumbImagePosY > Size2D.Height - thumbImage.Size2D.Height)
+                {
+                    thumbImage.PositionY = Size2D.Height - thumbImage.Size2D.Height;
+                    curValue = maxValue;
+                }
+                else
+                {
+                    thumbImage.PositionY = thumbImagePosY;
+                    curValue = (int)((thumbImagePosY / (float)(Size2D.Height - thumbImage.Size2D.Height)) * (float)(maxValue - minValue) + 0.5f);
+                }
+            }
+
+            return curValue;
+        }
+    }
+}
old mode 100755 (executable)
new mode 100644 (file)
index 64a2d49..7ebe33c
@@ -1,5 +1,5 @@
-/*
- * Copyright(c) 2019 Samsung Electronics Co., Ltd.
+/*
+ * Copyright(c) 2020 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.
  *
  */
 using System;
-using Tizen.NUI.BaseComponents;
 using System.ComponentModel;
+using Tizen.NUI.BaseComponents;
 using Tizen.NUI.Binding;
 
 namespace Tizen.NUI.Components
 {
     /// <summary>
-    /// The ScrollBar class of nui component. It allows users to recognize the direction and the range of lists/content. .
+    /// The Scrollbar is a component that contains track and thumb to indicate the current scrolled position of a scrollable object.
     /// </summary>
-    /// <since_tizen> 6 </since_tizen>
-    public class ScrollBar : Control
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class Scrollbar : ScrollbarBase
     {
-        /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+        #region Fields
+
+        /// <summary>Bindable property of TrackThickness</summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public static readonly BindableProperty DirectionProperty = BindableProperty.Create(nameof(Direction), typeof(DirectionType), typeof(ScrollBar), DirectionType.Horizontal, propertyChanged: (bindable, oldValue, newValue) =>
+        public static readonly BindableProperty TrackThicknessProperty = BindableProperty.Create(nameof(TrackThickness), typeof(float), typeof(Scrollbar), default(float), propertyChanged: (bindable, oldValue, newValue) =>
         {
-            var instance = (ScrollBar)bindable;
-            if (newValue != null)
-            {
-                instance.Style.Direction = (DirectionType?)newValue;
-                instance.UpdateValue();
-            }
+            var instance = ((Scrollbar)bindable);
+            var thickness = (float?)newValue;
+
+            ((ScrollbarStyle)instance.viewStyle).TrackThickness = thickness;
+            instance.UpdateTrackThickness(thickness ?? 0);
         },
         defaultValueCreator: (bindable) =>
         {
-            var instance = (ScrollBar)bindable;
-            return instance.Style.Direction;
+            return ((ScrollbarStyle)((Scrollbar)bindable).viewStyle)?.TrackThickness ?? 0;
         });
-        /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+
+        /// <summary>Bindable property of ThumbThickness</summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public static readonly BindableProperty MaxValueProperty = BindableProperty.Create(nameof(MaxValue), typeof(int), typeof(ScrollBar), default(int), propertyChanged: (bindable, oldValue, newValue) =>
+        public static readonly BindableProperty ThumbThicknessProperty = BindableProperty.Create(nameof(ThumbThickness), typeof(float), typeof(Scrollbar), default(float), propertyChanged: (bindable, oldValue, newValue) =>
         {
-            var instance = (ScrollBar)bindable;
-            if (newValue != null)
-            {
-                if ((int)newValue >= 0)
-                {
-                    instance.maxValue = (int)newValue;
-                    instance.UpdateValue();
-                }
-            }
+            var instance = ((Scrollbar)bindable);
+            var thickness = (float?)newValue;
+
+            ((ScrollbarStyle)instance.viewStyle).ThumbThickness = thickness;
+            instance.UpdateThumbThickness(thickness ?? 0);
         },
         defaultValueCreator: (bindable) =>
         {
-            var instance = (ScrollBar)bindable;
-            return instance.maxValue;
+            return ((ScrollbarStyle)((Scrollbar)bindable).viewStyle)?.ThumbThickness ?? 0;
         });
-        /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+
+        /// <summary>Bindable property of TrackColor</summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public static readonly BindableProperty MinValueProperty = BindableProperty.Create(nameof(MinValue), typeof(int), typeof(ScrollBar), default(int), propertyChanged: (bindable, oldValue, newValue) =>
+        public static readonly BindableProperty TrackColorProperty = BindableProperty.Create(nameof(TrackColor), typeof(Color), typeof(Scrollbar), null, propertyChanged: (bindable, oldValue, newValue) =>
         {
-            var instance = (ScrollBar)bindable;
-            if (newValue != null)
-            {
-                if ((int)newValue >= 0)
-                {
-                    instance.minValue = (int)newValue;
-                    instance.UpdateValue();
-                }
-            }
+            var instance = ((Scrollbar)bindable);
+            var color = (Color)newValue;
+
+            ((ScrollbarStyle)instance.viewStyle).TrackColor = color;
+            instance.UpdateTrackColor(color);
         },
         defaultValueCreator: (bindable) =>
         {
-            var instance = (ScrollBar)bindable;
-            return instance.minValue;
+            return ((ScrollbarStyle)((Scrollbar)bindable).viewStyle)?.TrackColor;
         });
-        /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+
+        /// <summary>Bindable property of ThumbColor</summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public static readonly BindableProperty CurrentValueProperty = BindableProperty.Create(nameof(CurrentValue), typeof(int), typeof(ScrollBar), default(int), propertyChanged: (bindable, oldValue, newValue) =>
+        public static readonly BindableProperty ThumbColorProperty = BindableProperty.Create(nameof(ThumbColor), typeof(Color), typeof(Scrollbar), null, propertyChanged: (bindable, oldValue, newValue) =>
         {
-            var instance = (ScrollBar)bindable;
-            if (newValue != null)
-            {
-                if ((int)newValue >= 0)
-                {
-                    instance.curValue = (int)newValue;
-                    instance.UpdateValue();
-                }
-            }
+            var instance = ((Scrollbar)bindable);
+            var color = (Color)newValue;
+
+            ((ScrollbarStyle)instance.viewStyle).ThumbColor = color;
+            instance.UpdateThumbColor(color);
         },
         defaultValueCreator: (bindable) =>
         {
-            var instance = (ScrollBar)bindable;
-            return instance.curValue;
+            return ((ScrollbarStyle)((Scrollbar)bindable).viewStyle)?.ThumbColor;
         });
-        /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+
+        /// <summary>Bindable property of TrackPadding</summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public static readonly BindableProperty DurationProperty = BindableProperty.Create(nameof(Duration), typeof(uint), typeof(ScrollBar), default(uint), propertyChanged: (bindable, oldValue, newValue) =>
+        public static readonly BindableProperty TrackPaddingProperty = BindableProperty.Create(nameof(TrackPadding), typeof(Extents), typeof(Scrollbar), null, propertyChanged: (bindable, oldValue, newValue) =>
         {
-            var instance = (ScrollBar)bindable;
-            if (newValue != null)
-            {
-                instance.Style.Duration = (uint)newValue;
-                if (instance.scrollAniPlayer != null)
-                {
-                    instance.scrollAniPlayer.Duration = (int)(uint)newValue;
-                }
-            }
+            var instance = ((Scrollbar)bindable);
+            var trackPadding = (Extents)newValue;
+
+            ((ScrollbarStyle)instance.viewStyle).TrackPadding = trackPadding;
+            instance.UpdateTrackPadding(trackPadding);
         },
         defaultValueCreator: (bindable) =>
         {
-            var instance = (ScrollBar)bindable;
-            return instance.Style.Duration;
+            return ((ScrollbarStyle)((Scrollbar)bindable).viewStyle)?.TrackPadding;
         });
 
-        private ImageView trackImage;
-        private ImageView thumbImage;
-        private Animation scrollAniPlayer = null;
-        private float thumbImagePosX;
-        private float thumbImagePosY;
-        private bool enableAni = false;
-        private int minValue;
-        private int maxValue;
-        private int curValue;
-        static ScrollBar() { }
+        private static readonly string TrackVisualName = "Track";
+        private static readonly string ThumbVisualName = "Thumb";
+        private ColorVisual trackVisual;
+        private ColorVisual thumbVisual;
+        private Animation thumbPositionAnimation;
+        private Animation thumbSizeAnimation;
+        private Calculator calculator;
+
+        #endregion Fields
+
+
+        #region Constructors
 
         /// <summary>
-        /// The constructor of ScrollBar.
+        /// Create an empty Scrollbar.
         /// </summary>
-        /// <since_tizen> 6 </since_tizen>
-        public ScrollBar() : base()
+        public Scrollbar() : base(new ScrollbarStyle())
         {
-            Initialize();
         }
 
         /// <summary>
-        /// The constructor of ScrollBar with specific style.
+        /// Create a Scrollbar and initialize with properties.
         /// </summary>
-        /// <param name="style">style name</param>
-        /// <since_tizen> 8 </since_tizen>
-        public ScrollBar(string style) : base(style)
+        /// <param name="contentLength">The total length of the content.</param>
+        /// <param name="viewSize">The size of View that contains the content to scroll.</param>
+        /// <param name="currentPosition">The start position of the View in content length. This is the View's top position if the scroller is vertical, otherwise, View's left position.</param>
+        /// <param name="isHorizontal">Whether the direction of scrolling is horizontal or not. It is vertical if the value is false.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Scrollbar(float contentLength, Size viewSize, float currentPosition, bool isHorizontal = false) : base(new ScrollbarStyle())
         {
-            Initialize();
+            Initialize(contentLength, viewSize, currentPosition, isHorizontal);
         }
 
         /// <summary>
-        /// The constructor of ScrollBar with specific style.
+        /// Create an empty Scrollbar with a ScrollbarStyle instance to set style properties.
         /// </summary>
-        /// <param name="scrollBarStyle">The style object to initialize the ScrollBar.</param>
-        /// <since_tizen> 8 </since_tizen>
-        public ScrollBar(ScrollBarStyle scrollBarStyle) : base(scrollBarStyle)
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Scrollbar(ScrollbarStyle style) : base(style)
         {
-            Initialize();
         }
 
         /// <summary>
-        /// The direction type of the Scroll.
+        /// Static constructor to initialize bindable properties when loading.
         /// </summary>
-        /// <since_tizen> 6 </since_tizen>
-        public enum DirectionType
-        {
-            /// <summary>
-            /// The Horizontal type.
-            /// </summary>
-            /// <since_tizen> 6 </since_tizen>
-            Horizontal,
-
-            /// <summary>
-            /// The Vertical type.
-            /// </summary>
-            /// <since_tizen> 6 </since_tizen>
-            Vertical
+        static Scrollbar()
+        {
         }
 
-        #region public property 
+        #endregion Constructors
+
+
+        #region Properties
+
         /// <summary>
-        /// Get style of scrollbar.
+        /// The thickness of the track.
         /// </summary>
-        /// <since_tizen> 8 </since_tizen>
-        public new ScrollBarStyle Style => ViewStyle as ScrollBarStyle;
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float TrackThickness
+        {
+            get => (float)GetValue(TrackThicknessProperty);
+            set => SetValue(TrackThicknessProperty, value);
+        }
 
         /// <summary>
-        /// The property to get/set the direction of the ScrollBar.
+        /// The thickness of the thumb.
         /// </summary>
-        /// <since_tizen> 6 </since_tizen>
-        public DirectionType Direction
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float ThumbThickness
         {
-            get
-            {
-                return (DirectionType)GetValue(DirectionProperty);
-            }
-            set
-            {
-                SetValue(DirectionProperty, value);
-            }
+            get => (float)GetValue(ThumbThicknessProperty);
+            set => SetValue(ThumbThicknessProperty, value);
         }
 
         /// <summary>
-        /// The property to get/set the size of the thumb object.
+        /// The color of the track part.
         /// </summary>
-        /// <exception cref="InvalidOperationException">Throw when ThumbSize is null.</exception>
-        /// <example>
-        /// <code>
-        /// ScrollBar scroll;
-        /// try
-        /// {
-        ///     scroll.ThumbSize = new Size(500, 10, 0);
-        /// }
-        /// catch(InvalidOperationException e)
-        /// {
-        ///     Tizen.Log.Error(LogTag, "Failed to set ThumbSize value : " + e.Message);
-        /// }
-        /// </code>
-        /// </example>
-        /// <since_tizen> 6 </since_tizen>
-        public Size ThumbSize
-        {
-            get
-            {
-                return Style?.Thumb?.Size;
-            }
-            set
-            {
-                if (null != Style?.Thumb)
-                {
-                    Style.Thumb.Size = value;
-                    RelayoutRequest();
-                }
-            }
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Color TrackColor
+        {
+            get => (Color)GetValue(TrackColorProperty);
+            set => SetValue(TrackColorProperty, value);
         }
 
         /// <summary>
-        /// The property to get/set the image URL of the track object.
+        /// The color of the thumb part.
         /// </summary>
-        /// <since_tizen> 6 </since_tizen>
-        public string TrackImageURL
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Color ThumbColor
         {
-            get
-            {
-                return Style?.Track?.ResourceUrl?.All;
-            }
-            set
-            {
-                if (null != Style?.Track)
-                {
-                    Style.Track.ResourceUrl = value;
-                    RelayoutRequest();
-                }
-            }
+            get => (Color)GetValue(ThumbColorProperty);
+            set => SetValue(ThumbColorProperty, value);
         }
 
         /// <summary>
-        /// The property to get/set the color of the track object.
+        /// The padding value of the track.
         /// </summary>
-        /// <since_tizen> 6 </since_tizen>
-        public Color TrackColor
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Extents TrackPadding
+        {
+            get => (Extents)GetValue(TrackPaddingProperty);
+            set => SetValue(TrackPaddingProperty, value);
+        }
+
+        #endregion Properties
+
+
+        #region Methods
+
+        /// <inheritdoc/>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public override void Initialize(float contentLength, Size viewSize, float currentPosition, bool isHorizontal = false)
         {
-            get
+            if (isHorizontal)
             {
-                return Style?.Track?.BackgroundColor?.All;
+                calculator = new HorizontalCalculator(contentLength > 0.0f ? contentLength : 0.0f, viewSize.Width);
             }
-            set
+            else
             {
-                if (null != Style?.Track)
-                {
-                    Style.Track.BackgroundColor = value;
-                    RelayoutRequest();
-                }
+                calculator = new VerticalCalculator(contentLength > 0.0f ? contentLength : 0.0f, viewSize.Height);
             }
+
+            Size = viewSize;
+
+            thumbPositionAnimation?.Stop();
+            thumbPositionAnimation = null;
+
+            thumbSizeAnimation?.Stop();
+            thumbSizeAnimation = null;
+
+            CreateTrackVisual();
+            CreateThumbVisual(currentPosition);
+
+            AddVisual(TrackVisualName, trackVisual);
+            AddVisual(ThumbVisualName, thumbVisual);
         }
 
-        /// <summary>
-        /// The property to get/set the color of the thumb object.
-        /// </summary>
-        /// <since_tizen> 6 </since_tizen>
-        public Color ThumbColor
+        /// <inheritdoc/>
+        /// <remarks>Please note that, for now, only alpha functions created with BuiltinFunctions are valid when animating. Otherwise, it will be treated as a linear alpha function. </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public override void Update(float contentLength, float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
         {
-            get
+            if (calculator == null)
             {
-                return Style?.Thumb?.BackgroundColor?.All;
+                return;
             }
-            set
+
+            calculator.Update(contentLength > 0.0f ? contentLength : 0.0f);
+
+            thumbVisual.Size = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
+            thumbVisual.Position = calculator.CalculateThumbScrollPosition(position, trackVisual.Size, thumbVisual.Position, TrackPadding);
+            thumbVisual.Opacity = calculator.CalculateThumbVisibility() ? 1.0f : 0.0f;
+
+            if (durationMs == 0)
             {
-                if(null != Style?.Thumb)
-                {
-                    Style.Thumb.BackgroundColor = value;
-                    RelayoutRequest();
-                }
+                thumbVisual.UpdateVisual(true);
+
+                return;
             }
+
+            // TODO Support non built-in alpha function for visual trainsition in DALi.
+            AlphaFunction.BuiltinFunctions builtinAlphaFunction = alphaFunction?.GetBuiltinFunction() ?? AlphaFunction.BuiltinFunctions.Default;
+
+            thumbPositionAnimation?.Stop();
+            thumbPositionAnimation = AnimateVisual(thumbVisual, "position", thumbVisual.Position, 0, (int)durationMs, builtinAlphaFunction);
+            thumbPositionAnimation.Play();
+
+            thumbSizeAnimation?.Stop();
+            thumbSizeAnimation = AnimateVisual(thumbVisual, "size", thumbVisual.Size, 0, (int)durationMs, builtinAlphaFunction);
+            thumbSizeAnimation.Play();
         }
 
-        /// <summary>
-        /// The property to get/set the max value of the ScrollBar.
-        /// </summary>
-        /// <since_tizen> 6 </since_tizen>
-        public int MaxValue
+        /// <inheritdoc/>
+        /// <remarks>Please note that, for now, only alpha functions created with BuiltinFunctions are valid when animating. Otherwise, it will be treated as a linear alpha function. </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public override void ScrollTo(float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
         {
-            get
+            if (thumbVisual == null)
             {
-                return (int)GetValue(MaxValueProperty);
+                return;
             }
-            set
+
+            thumbVisual.Position = calculator.CalculateThumbScrollPosition(position, trackVisual.Size, thumbVisual.Position, TrackPadding);
+
+            if (durationMs == 0)
             {
-                SetValue(MaxValueProperty, value);
+                thumbVisual.UpdateVisual(true);
+
+                return;
             }
+
+            // TODO Support non built-in alpha function for visual trainsition in DALi.
+            AlphaFunction.BuiltinFunctions builtinAlphaFunction = alphaFunction?.GetBuiltinFunction() ?? AlphaFunction.BuiltinFunctions.Default;
+
+            thumbPositionAnimation?.Stop();
+            thumbPositionAnimation = AnimateVisual(thumbVisual, "position", thumbVisual.Position, 0, (int)durationMs, builtinAlphaFunction);
+            thumbPositionAnimation.Play();
+        }
+
+        /// <inheritdoc/>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override ViewStyle GetViewStyle()
+        {
+            return new ScrollbarStyle();
         }
 
         /// <summary>
-        /// The property to get/set the min value of the ScrollBar.
+        /// Create a track visual.
         /// </summary>
-        /// <since_tizen> 6 </since_tizen>
-        public int MinValue
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected virtual void CreateTrackVisual()
         {
-            get
+            trackVisual = new ColorVisual
             {
-                return (int)GetValue(MinValueProperty);
-            }
-            set
-            {
-                SetValue(MinValueProperty, value);
-            }
+                SuppressUpdateVisual = true,
+                Color = Color.Black,
+                SizePolicy = VisualTransformPolicyType.Absolute,
+                Origin = calculator.CalculatorTrackAlign(),
+                AnchorPoint = calculator.CalculatorTrackAlign(),
+                Size = calculator.CalculateTrackSize(TrackThickness, TrackPadding),
+                Position = calculator.CalculateTrackPosition(TrackPadding),
+            };
         }
 
         /// <summary>
-        /// The property to get/set the current value of the ScrollBar.
+        /// Create a thumb visual.
         /// </summary>
-        /// <exception cref="ArgumentOutOfRangeException">Throw when Current value is less than Min value, or greater than Max value.</exception>
-        /// <example>
-        /// <code>
-        /// ScrollBar scroll;
-        /// scroll.MaxValue = 100;
-        /// scroll.MinValue = 0;
-        /// try
-        /// {
-        ///     scroll.CurrentValue = 50;
-        /// }
-        /// catch(ArgumentOutOfRangeException e)
-        /// {
-        ///     Tizen.Log.Error(LogTag, "Failed to set Current value : " + e.Message);
-        /// }
-        /// </code>
-        /// </example>
-        /// <since_tizen> 6 </since_tizen>
-        public int CurrentValue
-        {
-            get
-            {
-                return (int)GetValue(CurrentValueProperty);
-            }
-            set
-            {
-                SetValue(CurrentValueProperty, value);
-            }
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected virtual void CreateThumbVisual(float currentPosition)
+        {
+            Size thumbSize = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
+
+            thumbVisual = new ColorVisual
+            {
+                SuppressUpdateVisual = true,
+                MixColor = ThumbColor,
+                SizePolicy = VisualTransformPolicyType.Absolute,
+                Origin = calculator.CalculatorThumbAlign(),
+                AnchorPoint = calculator.CalculatorThumbAlign(),
+                Size = thumbSize,
+                Position = calculator.CalculateThumbPosition(currentPosition, trackVisual.Size, thumbSize, TrackPadding),
+                Opacity = (calculator.CalculateThumbVisibility() ? 1.0f : 0.0f),
+            };
         }
 
         /// <summary>
-        /// Property to set/get animation duration.
+        /// Update TrackThickness property of the scrollbar.
         /// </summary>
-        /// <since_tizen> 6 </since_tizen>
-        public uint Duration
+        /// <param name="thickness">The width of the track.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected virtual void UpdateTrackThickness(float thickness)
         {
-            get
-            {
-                return (uint)GetValue(DurationProperty);
-            }
-            set
+            if (trackVisual == null)
             {
-                SetValue(DurationProperty, value);
+                return;
             }
-        }
-        #endregion
 
-        /// <summary>
-        /// Method to set current value. The thumb object would move to the corresponding position with animation or not.
-        /// </summary>
-        /// <param name="currentValue">The special current value.</param>
-        /// <param name="enableAnimation">Enable move with animation or not, the default value is true.</param>
-        /// <exception cref="ArgumentOutOfRangeException">Throw when current size is less than the min value, or greater than the max value.</exception>
-        /// <example>
-        /// <code>
-        /// ScrollBar scroll;
-        /// scroll.MinValue = 0;
-        /// scroll.MaxValue = 100;
-        /// try
-        /// {
-        ///     scroll.SetCurrentValue(50);
-        /// }
-        /// catch(ArgumentOutOfRangeException e)
-        /// {
-        ///     Tizen.Log.Error(LogTag, "Failed to set current value : " + e.Message);
-        /// }
-        /// </code>
-        /// </example>
-        /// <since_tizen> 6 </since_tizen>
-        public void SetCurrentValue(int currentValue, bool enableAnimation = true)
-        {
-            if (currentValue < minValue || currentValue > maxValue)
-            {
-                //TNLog.E("Current value is less than the Min value, or greater than the Max value. currentValue = " + currentValue + ";");
-#pragma warning disable CA2208 // Instantiate argument exceptions correctly
-                throw new ArgumentOutOfRangeException("Wrong Current value. It shoud be greater than the Min value, and less than the Max value!");
-#pragma warning restore CA2208 // Instantiate argument exceptions correctly
-            }
-
-            enableAni = enableAnimation;
-            CurrentValue = currentValue;
+            trackVisual.Size = calculator.CalculateTrackSize(thickness, TrackPadding);
+            trackVisual.UpdateVisual(true);
         }
 
         /// <summary>
-        /// Dispose ScrollBar.
+        /// Update ThumbThickness property of the scrollbar.
         /// </summary>
-        /// <param name="type">The DisposeTypes value.</param>
-        /// <since_tizen> 6 </since_tizen>
-        protected override void Dispose(DisposeTypes type)
+        /// <param name="thickness">The width of the track.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected virtual void UpdateThumbThickness(float thickness)
         {
-            if (disposed)
+            if (thumbVisual == null)
             {
                 return;
             }
 
-            if (type == DisposeTypes.Explicit)
-            {
-                //Called by User
-                //Release your own managed resources here.
-                //You should release all of your own disposable objects here.
-
-                Utility.Dispose(trackImage);
-                Utility.Dispose(thumbImage);
+            thumbVisual.Size = calculator.CalculateThumbSize(thickness, trackVisual.Size);
+            thumbVisual.UpdateVisual(true);
+        }
 
-                if (scrollAniPlayer != null)
-                {
-                    scrollAniPlayer.Stop();
-                    scrollAniPlayer.Clear();
-                    scrollAniPlayer.Dispose();
-                    scrollAniPlayer = null;
-                }
+        /// <summary>
+        /// Update TrackColor property of the scrollbar.
+        /// </summary>
+        /// <param name="color">The color of the track.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected virtual void UpdateTrackColor(Color color)
+        {
+            if (trackVisual == null)
+            {
+                return;
             }
 
-            //Release your own unmanaged resources here.
-            //You should not access any managed member here except static instance.
-            //because the execution order of Finalizes is non-deterministic.
-            //Unreference this from if a static instance refer to this. 
-
-            //You must call base.Dispose(type) just before exit.
-            base.Dispose(type);
+            trackVisual.MixColor = color;
+            trackVisual.UpdateVisual(true);
         }
 
         /// <summary>
-        /// Get Scrollbar style.
+        /// Update ThumbColor property of the scrollbar.
         /// </summary>
-        /// <returns>The default scrollbar style.</returns>
-        /// <since_tizen> 8 </since_tizen>
-        protected override ViewStyle GetViewStyle()
+        /// <param name="color">The color of the thumb.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected virtual void UpdateThumbColor(Color color)
         {
-            return new ScrollBarStyle();
+            if (thumbVisual == null)
+            {
+                return;
+            }
+
+            thumbVisual.MixColor = color;
+            thumbVisual.UpdateVisual(true);
         }
 
         /// <summary>
-        /// Theme change callback when theme is changed, this callback will be trigger.
+        /// Update TrackPadding property of the scrollbar.
         /// </summary>
-        /// <param name="sender">The sender</param>
-        /// <param name="e">The event data</param>
-        /// <since_tizen> 8 </since_tizen>
-        protected override void OnThemeChangedEvent(object sender, StyleManager.ThemeChangeEventArgs e)
+        /// <param name="trackPadding">The padding of the track.</param>
+        protected virtual void UpdateTrackPadding(Extents trackPadding)
         {
-            ScrollBarStyle tempStyle = StyleManager.Instance.GetViewStyle(style) as ScrollBarStyle;
-            if (tempStyle != null)
+            if (trackVisual == null || thumbVisual == null)
             {
-                Style.CopyFrom(tempStyle);
-                UpdateValue();
+                return;
             }
+
+            trackVisual.Size = calculator.CalculateTrackSize(TrackThickness, trackPadding); 
+            trackVisual.Position = calculator.CalculateTrackPosition(trackPadding);
+            thumbVisual.Size = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
+            thumbVisual.Position = calculator.CalculateThumbPaddingPosition(trackVisual.Size, thumbVisual.Size, thumbVisual.Position, trackPadding);
+
+            trackVisual.UpdateVisual(true);
+            thumbVisual.UpdateVisual(true);
         }
 
-        private void Initialize()
+        #endregion Methods
+
+
+        #region Classes
+
+        private abstract class Calculator
         {
-            this.Focusable = false;
+            protected float contentLength;
+            protected float visibleLength;
 
-            trackImage = new ImageView
+            public Calculator(float contentLength, float visibleLength)
             {
-                Focusable = false,
-                WidthResizePolicy = ResizePolicyType.FillToParent,
-                HeightResizePolicy = ResizePolicyType.FillToParent,
-                PositionUsesPivotPoint = true,
-                ParentOrigin = Tizen.NUI.ParentOrigin.CenterLeft,
-                PivotPoint = Tizen.NUI.PivotPoint.CenterLeft
-            };
-            this.Add(trackImage);
-            trackImage.ApplyStyle(Style.Track);
+                this.contentLength = contentLength;
+                this.visibleLength = visibleLength;
+            }
 
-            thumbImage = new ImageView
+            public void Update(float contentLength)
             {
-                Focusable = false,
-                WidthResizePolicy = ResizePolicyType.Fixed,
-                HeightResizePolicy = ResizePolicyType.Fixed,
-                PositionUsesPivotPoint = true,
-                ParentOrigin = Tizen.NUI.ParentOrigin.CenterLeft,
-                PivotPoint = Tizen.NUI.PivotPoint.CenterLeft
-            };
-            this.Add(thumbImage);
-            thumbImage.ApplyStyle(Style.Thumb);
+                this.contentLength = contentLength;
+            }
 
-            scrollAniPlayer = new Animation(334);
-            scrollAniPlayer.DefaultAlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.Linear);
+            public bool CalculateThumbVisibility()
+            {
+                return contentLength > visibleLength;
+            }
 
-            thumbImagePosX = 0;
-            thumbImagePosY = 0;
-            LayoutDirectionChanged += OnLayoutDirectionChanged;
+            public abstract Visual.AlignType CalculatorTrackAlign();
+            public abstract Visual.AlignType CalculatorThumbAlign();
+            public abstract Size CalculateTrackSize(float thickness, Extents trackPadding);
+            public abstract Vector2 CalculateTrackPosition(Extents trackPadding);
+            public abstract Size CalculateThumbSize(float thickness, Size trackSize);
+            public abstract Vector2 CalculateThumbPosition(float position, Size trackSize, Size thumbSize, Extents trackPadding);
+            public abstract Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, Extents trackPadding);
+            public abstract Vector2 CalculateThumbScrollPosition(float position, Size trackSize, Vector2 thumbCurrentPosition, Extents trackPadding);
         }
 
-        private void OnLayoutDirectionChanged(object sender, LayoutDirectionChangedEventArgs e)
+        private class HorizontalCalculator : Calculator
         {
-            RelayoutRequest();
-        }
+            public HorizontalCalculator(float contentLength, float visibleLength) : base(contentLength, visibleLength)
+            {
+            }
 
-        private void UpdateValue()
-        {
-            if (minValue >= maxValue || curValue < minValue || curValue > maxValue) return;
+            public override Visual.AlignType CalculatorTrackAlign()
+            {
+                return Visual.AlignType.BottomCenter;
+            }
 
-            float width = (float)Size2D.Width;
-            float height = (float)Size2D.Height;
-            float thumbW = 0.0f;
-            float thumbH = 0.0f;
-            if (Style.Thumb.Size == null)
+            public override Visual.AlignType CalculatorThumbAlign()
             {
-                return;
+                return Visual.AlignType.BottomBegin;
             }
-            else
+
+            public override Size CalculateTrackSize(float thickness, Extents trackPadding)
             {
-                thumbW = Style.Thumb.Size.Width;
-                thumbH = Style.Thumb.Size.Height;
-            }
-            float ratio = (float)(curValue - minValue) / (float)(maxValue - minValue);
-
-            if (Style.Direction == DirectionType.Horizontal)
-            {
-                if (LayoutDirection == ViewLayoutDirectionType.RTL)
-                {
-                    ratio = 1.0f - ratio;
-                }
-
-                float posX = ratio * (width - thumbW);
-                float posY = (height - thumbH) / 2.0f;
-
-                thumbImagePosX = posX;
-                if (null != scrollAniPlayer)
-                {
-                    scrollAniPlayer.Stop();
-                }
-
-                if (!enableAni)
-                {
-                    thumbImage.Position = new Position(posX, posY, 0);
-                }
-                else
-                {
-                    if (null != scrollAniPlayer)
-                    {
-                        scrollAniPlayer.Clear();
-                        scrollAniPlayer.AnimateTo(thumbImage, "PositionX", posX);
-                        scrollAniPlayer.Play();
-                    }
-                }
+                return new Size(visibleLength - trackPadding.Start - trackPadding.End, thickness);
             }
-            else
+
+            public override Vector2 CalculateTrackPosition(Extents trackPadding)
+            {
+                return new Vector2(0, -trackPadding.Bottom);
+            }
+
+            public override Size CalculateThumbSize(float thickness, Size trackSize)
             {
-                float posX = (width - thumbW) / 2.0f;
-                float posY = ratio * (height - thumbH);
-
-                thumbImagePosY = posY;
-                if (null != scrollAniPlayer)
-                {
-                    scrollAniPlayer.Stop();
-                }
-
-                if (!enableAni)
-                {
-                    thumbImage.Position = new Position(posX, posY, 0);
-                }
-                else
-                {
-                    if (null != scrollAniPlayer)
-                    {
-                        scrollAniPlayer.Clear();
-                        scrollAniPlayer.AnimateTo(thumbImage, "PositionY", posY);
-                        scrollAniPlayer.Play();
-                    }
-                }
-            }
-
-            if (enableAni) enableAni = false;
+                return new Size(trackSize.Width * visibleLength / contentLength, thickness);
+            }
+
+            public override Vector2 CalculateThumbPosition(float position, Size trackSize, Size thumbSize, Extents trackPadding)
+            {
+                float padding = ((trackSize.Height - thumbSize.Height) / 2.0f) + trackPadding.Bottom;
+                float pos = Math.Min(Math.Max(position, 0.0f), contentLength - visibleLength);
+                return new Vector2(trackPadding.Start + trackSize.Width * pos / contentLength, -padding);
+            }
+
+            public override Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, Extents trackPadding)
+            {
+                float padding = ((trackSize.Height - thumbSize.Height) / 2.0f) + trackPadding.Bottom;
+                return new Vector2(thumbCurrentPosition.X, -padding);
+            }
+
+            public override Vector2 CalculateThumbScrollPosition(float position, Size trackSize, Vector2 thumbCurrentPosition, Extents trackPadding)
+            {
+                float pos = Math.Min(Math.Max(position, 0.0f), contentLength - visibleLength);
+                return new Vector2(trackPadding.Start + trackSize.Width * pos / contentLength, thumbCurrentPosition.Y);
+            }
         }
 
-        private DirectionType CurrentDirection()
+        private class VerticalCalculator : Calculator
         {
-            DirectionType dir = DirectionType.Horizontal;
-            if (null != Style.Direction)
+            public VerticalCalculator(float contentLength, float visibleLength) : base(contentLength, visibleLength)
             {
-                dir = Style.Direction.Value;
             }
-            return dir;
-        }
 
-        private int CalculateCurrentValue(float offset, DirectionType dir)
-        {
-            if (dir == DirectionType.Horizontal)
-            {
-                thumbImagePosX += offset;
-                if (thumbImagePosX < 0)
-                {
-                    thumbImage.PositionX = 0;
-                    curValue = minValue;
-                }
-                else if (thumbImagePosX > Size2D.Width - thumbImage.Size2D.Width)
-                {
-                    thumbImage.PositionX = Size2D.Width - thumbImage.Size2D.Width;
-                    curValue = maxValue;
-                }
-                else
-                {
-                    thumbImage.PositionX = thumbImagePosX;
-                    curValue = (int)((thumbImagePosX / (float)(Size2D.Width - thumbImage.Size2D.Width)) * (float)(maxValue - minValue) + 0.5f);
-                }
+            public override Visual.AlignType CalculatorTrackAlign()
+            {
+                return Visual.AlignType.CenterEnd;
             }
-            else
+
+            public override Visual.AlignType CalculatorThumbAlign()
+            {
+                return Visual.AlignType.TopEnd;
+            }
+
+            public override Size CalculateTrackSize(float thickness, Extents trackPadding)
+            {
+                return new Size(thickness, visibleLength - trackPadding.Top - trackPadding.Bottom);
+            }
+
+            public override Vector2 CalculateTrackPosition(Extents trackPadding)
+            {
+                return new Vector2(-trackPadding.End, 0);
+            }
+
+            public override Size CalculateThumbSize(float thickness, Size trackSize)
             {
-                thumbImagePosY += offset;
-                if (thumbImagePosY < 0)
-                {
-                    thumbImage.PositionY = 0;
-                    curValue = minValue;
-                }
-                else if (thumbImagePosY > Size2D.Height - thumbImage.Size2D.Height)
-                {
-                    thumbImage.PositionY = Size2D.Height - thumbImage.Size2D.Height;
-                    curValue = maxValue;
-                }
-                else
-                {
-                    thumbImage.PositionY = thumbImagePosY;
-                    curValue = (int)((thumbImagePosY / (float)(Size2D.Height - thumbImage.Size2D.Height)) * (float)(maxValue - minValue) + 0.5f);
-                }
-            }
-
-            return curValue;
+                return new Size(thickness, trackSize.Height * visibleLength / contentLength);
+            }
+
+            public override Vector2 CalculateThumbPosition(float position, Size trackSize, Size thumbSize, Extents trackPadding)
+            {
+                float padding = ((trackSize.Width - thumbSize.Width) / 2.0f) + trackPadding.End;
+                float pos = Math.Min(Math.Max(position, 0.0f), contentLength - visibleLength);
+                return new Vector2(-padding, trackPadding.Top + trackSize.Height * pos / contentLength);
+            }
+
+            public override Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, Extents trackPadding)
+            {
+                float padding = ((trackSize.Width - thumbSize.Width) / 2.0f) + trackPadding.End;
+                return new Vector2(-padding, thumbCurrentPosition.Y);
+            }
+
+            public override Vector2 CalculateThumbScrollPosition(float position, Size trackSize, Vector2 thumbPosition, Extents trackPadding)
+            {
+                float pos = Math.Min(Math.Max(position, 0.0f), contentLength - visibleLength);
+                return new Vector2(thumbPosition.X, trackPadding.Top + trackSize.Height * pos / contentLength);
+            }
         }
+
+        #endregion Classes
     }
 }
diff --git a/src/Tizen.NUI.Components/Controls/ScrollbarBase.cs b/src/Tizen.NUI.Components/Controls/ScrollbarBase.cs
new file mode 100644 (file)
index 0000000..65b278a
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright(c) 2020 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.ComponentModel;
+
+namespace Tizen.NUI.Components
+{
+    /// <summary>
+    /// The ScrollbarBase is an abstract class that can be linked to the scrollable objects
+    /// indicating the current scrolled position of the scrollable object.
+    /// This only contains non-graphical functionalities of basic scrollbar.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public abstract class ScrollbarBase : Control
+    {
+        #region Constructors
+
+        /// <summary>
+        /// Create an empty ScrollbarBase.
+        /// </summary>
+        public ScrollbarBase() : base()
+        {
+        }
+
+        /// <summary>
+        /// Create an empty Scrollbar with a ControlStyle instance to set style properties.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public ScrollbarBase(ControlStyle style) : base(style)
+        {
+        }
+
+        /// <summary>
+        /// Static constructor to initialize bindable properties when loading.
+        /// </summary>
+        static ScrollbarBase()
+        {
+        }
+
+        #endregion Constructors
+
+
+        #region Methods
+
+        /// <summary>
+        /// Update content length and position at once.
+        /// </summary>
+        /// <param name="contentLength">The total length of the content.</param>
+        /// <param name="position">The destination position of the View in content length. This is the View's top position if the scroller is vertical, otherwise, View's left position.</param>
+        /// <param name="durationMs">The time it takes to scroll in milliseconds.</param>
+        /// <param name="alphaFunction">The timing function used in animation. It describes the rate of change of the animation parameter over time. (e.g. EaseOut)</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public abstract void Update(float contentLength, float position, uint durationMs = 0, AlphaFunction alphaFunction = null);
+
+        /// <summary>
+        /// Scroll content to a specific position.
+        /// </summary>
+        /// <param name="position">The destination to scroll.</param>
+        /// <param name="durationMs">The time it takes to scroll in milliseconds.</param>
+        /// <param name="alphaFunction">The timing function used in animation. It describes the rate of change of the animation parameter over time. (e.g. EaseOut)</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public abstract void ScrollTo(float position, uint durationMs = 0, AlphaFunction alphaFunction = null);
+
+        /// <summary>
+        /// Initialize the scroll bar.
+        /// </summary>
+        /// <param name="contentLength">The total length of the content.</param>
+        /// <param name="viewSize">The size of the View that contains the content to scroll. The ScrollbarBase will have the same size as the given viewSize.</param>
+        /// <param name="currentPosition">The start position of the View in content length. This is the View's top position if the scroller is vertical, otherwise, View's left position.</param>
+        /// <param name="isHorizontal">Whether the direction of scrolling is horizontal or not. It is vertical if the value is false.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public abstract void Initialize(float contentLength, Size viewSize, float currentPosition, bool isHorizontal = false);
+
+        #endregion Methods
+    }
+}
diff --git a/src/Tizen.NUI.Components/Style/ImageScrollBarStyle.cs b/src/Tizen.NUI.Components/Style/ImageScrollBarStyle.cs
new file mode 100755 (executable)
index 0000000..234ce25
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright(c) 2019 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.ComponentModel;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Components
+{
+    /// <summary>
+    /// ScrollBarStyle is a class which saves Scrollbar's ux data.
+    /// </summary>
+    /// <remarks>
+    /// Please note that this class will be replaced with ScrollbarStyle class in the near future.
+    /// </remarks>
+    /// <since_tizen> 8 </since_tizen>
+    public class ScrollBarStyle : ControlStyle
+    {
+        static ScrollBarStyle() { }
+
+        /// <summary>
+        /// Creates a new instance of a ScrollBarStyle.
+        /// </summary>
+        /// <since_tizen> 8 </since_tizen>
+        public ScrollBarStyle() : base()
+        {
+            InitSubStyle();
+            Direction = ScrollBar.DirectionType.Horizontal;
+        }
+
+        /// <summary>
+        /// Creates a new instance of a ScrollBarStyle with style.
+        /// </summary>
+        /// <param name="style">Create ScrollBarStyle by style customized by user.</param>
+        /// <since_tizen> 8 </since_tizen>
+        public ScrollBarStyle(ScrollBarStyle style) : base(style)
+        {
+            if (null == style) return;
+
+            InitSubStyle();
+
+            this.CopyFrom(style);
+        }
+
+        /// <summary>
+        /// Get or set track image style.
+        /// </summary>
+        /// <since_tizen> 8 </since_tizen>
+        public ImageViewStyle Track { get; set; }
+
+        /// <summary>
+        /// Get or set thumb image style.
+        /// </summary>
+        /// <since_tizen> 8 </since_tizen>
+        public ImageViewStyle Thumb { get; set; }
+
+        /// <summary>
+        /// Get or set direction type.
+        /// </summary>
+        /// <since_tizen> 8 </since_tizen>
+        public ScrollBar.DirectionType? Direction { get; set; }
+
+        /// <summary>
+        /// Get or set duration.
+        /// </summary>
+        /// <since_tizen> 8 </since_tizen>
+        public uint Duration { get; set; }
+
+        /// <summary>
+        /// Style's clone function.
+        /// </summary>
+        /// <param name="bindableObject">The style that need to copy.</param>
+        /// <since_tizen> 8 </since_tizen>
+        public override void CopyFrom(BindableObject bindableObject)
+        {
+            base.CopyFrom(bindableObject);
+
+            ScrollBarStyle scrollBarStyle = bindableObject as ScrollBarStyle;
+
+            if (null != scrollBarStyle)
+            {
+                if (null != scrollBarStyle.Track)
+                {
+                    Track?.CopyFrom(scrollBarStyle.Track);
+                }
+
+                if (null != scrollBarStyle.Thumb)
+                {
+                    Thumb?.CopyFrom(scrollBarStyle.Thumb);
+                }
+
+                Direction = scrollBarStyle.Direction;
+                Duration = scrollBarStyle.Duration;
+            }
+        }
+
+        private void InitSubStyle()
+        {
+            Track = new ImageViewStyle()
+            {
+                PositionUsesPivotPoint = true,
+                ParentOrigin = Tizen.NUI.ParentOrigin.CenterLeft,
+                PivotPoint = Tizen.NUI.PivotPoint.CenterLeft,
+                WidthResizePolicy = ResizePolicyType.FillToParent,
+                HeightResizePolicy = ResizePolicyType.FillToParent
+            };
+
+            Thumb = new ImageViewStyle()
+            {
+                PositionUsesPivotPoint = true,
+                ParentOrigin = Tizen.NUI.ParentOrigin.CenterLeft,
+                PivotPoint = Tizen.NUI.PivotPoint.CenterLeft,
+                WidthResizePolicy = ResizePolicyType.Fixed,
+                HeightResizePolicy = ResizePolicyType.Fixed
+            };
+        }
+    }
+}
old mode 100755 (executable)
new mode 100644 (file)
index 461f00c..c707f9b
@@ -1,4 +1,4 @@
-/*
+/*
  * Copyright(c) 2019 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  *
  */
 using System.ComponentModel;
-using Tizen.NUI.BaseComponents;
 using Tizen.NUI.Binding;
 
 namespace Tizen.NUI.Components
 {
     /// <summary>
-    /// ScrollBarStyle is a class which saves Scrollbar's ux data.
+    /// ScrollbarStyle is a class which saves Scrollbar's style data.
     /// </summary>
-    /// <since_tizen> 8 </since_tizen>
-    public class ScrollBarStyle : ControlStyle
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class ScrollbarStyle : ControlStyle
     {
-        static ScrollBarStyle() { }
+        #region Fields
+
+        /// <summary>Bindable property of TrackThickness</summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty TrackThicknessProperty = BindableProperty.Create(nameof(TrackThickness), typeof(float?), typeof(ScrollbarStyle), null, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            ((ScrollbarStyle)bindable).trackThickness = (float?)newValue;
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            return ((ScrollbarStyle)bindable).trackThickness;
+        });
+
+        /// <summary>Bindable property of ThumbThickness</summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty ThumbThicknessProperty = BindableProperty.Create(nameof(ThumbThickness), typeof(float?), typeof(ScrollbarStyle), null, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            ((ScrollbarStyle)bindable).thumbThickness = (float?)newValue;
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            return ((ScrollbarStyle)bindable).thumbThickness;
+        });
+
+        /// <summary>Bindable property of TrackColor</summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty TrackColorProperty = BindableProperty.Create(nameof(TrackColor), typeof(Color), typeof(ScrollbarStyle), null, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            ((ScrollbarStyle)bindable).trackColor = (Color)newValue;
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            return ((ScrollbarStyle)bindable).trackColor;
+        });
+
+        /// <summary>Bindable property of ThumbColor</summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty ThumbColorProperty = BindableProperty.Create(nameof(ThumbColor), typeof(Color), typeof(ScrollbarStyle), null, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            ((ScrollbarStyle)bindable).thumbColor = (Color)newValue;
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            return ((ScrollbarStyle)bindable).thumbColor;
+        });
+
+        /// <summary>Bindable property of TrackPadding</summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty TrackPaddingProperty = BindableProperty.Create(nameof(TrackPadding), typeof(Extents), typeof(ScrollbarStyle), null, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            ((ScrollbarStyle)bindable).trackPadding = (Extents)newValue;
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            return ((ScrollbarStyle)bindable).trackPadding;
+        });
+
+        private float? trackThickness;
+        private float? thumbThickness;
+        private Color trackColor;
+        private Color thumbColor;
+        private Extents trackPadding;
+
+        #endregion Fields
+
+
+        #region Constructors
 
         /// <summary>
-        /// Creates a new instance of a ScrollBarStyle.
+        /// Creates a new instance of a ScrollbarStyle.
         /// </summary>
-        /// <since_tizen> 8 </since_tizen>
-        public ScrollBarStyle() : base()
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public ScrollbarStyle() : base()
         {
-            InitSubStyle();
-            Direction = ScrollBar.DirectionType.Horizontal;
+            Initialize();
         }
 
         /// <summary>
-        /// Creates a new instance of a ScrollBarStyle with style.
+        /// Copy constructor.
         /// </summary>
-        /// <param name="style">Create ScrollBarStyle by style customized by user.</param>
-        /// <since_tizen> 8 </since_tizen>
-        public ScrollBarStyle(ScrollBarStyle style) : base(style)
+        /// <param name="style">Create ScrollbarStyle by style customized by user.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public ScrollbarStyle(ScrollbarStyle style) : base(style)
         {
-            if (null == style) return;
-
-            InitSubStyle();
-
             this.CopyFrom(style);
         }
 
         /// <summary>
-        /// Get or set track image style.
+        /// Static constructor to initialize bindable properties when loading.
+        /// </summary>
+        static ScrollbarStyle()
+        {
+        }
+
+        #endregion Constructors
+
+
+        #region Properties
+
+        /// <summary>
+        /// The thickness of the track.
         /// </summary>
-        /// <since_tizen> 8 </since_tizen>
-        public ImageViewStyle Track { get; set; }
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float? TrackThickness
+        {
+            get => (float?)GetValue(TrackThicknessProperty);
+            set => SetValue(TrackThicknessProperty, value);
+        }
 
         /// <summary>
-        /// Get or set thumb image style.
+        /// The thickness of the thumb.
         /// </summary>
-        /// <since_tizen> 8 </since_tizen>
-        public ImageViewStyle Thumb { get; set; }
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float? ThumbThickness
+        {
+            get => (float?)GetValue(ThumbThicknessProperty);
+            set => SetValue(ThumbThicknessProperty, value);
+        }
 
         /// <summary>
-        /// Get or set direction type.
+        /// The color of the track part.
         /// </summary>
-        /// <since_tizen> 8 </since_tizen>
-        public ScrollBar.DirectionType? Direction { get; set; }
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Color TrackColor
+        {
+            get => (Color)GetValue(TrackColorProperty);
+            set => SetValue(TrackColorProperty, value);
+        }
 
         /// <summary>
-        /// Get or set duration.
+        /// The color of the thumb part.
         /// </summary>
-        /// <since_tizen> 8 </since_tizen>
-        public uint Duration { get; set; }
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Color ThumbColor
+        {
+            get => (Color)GetValue(ThumbColorProperty);
+            set => SetValue(ThumbColorProperty, value);
+        }
 
         /// <summary>
-        /// Style's clone function.
+        /// The padding value of the track.
         /// </summary>
-        /// <param name="bindableObject">The style that need to copy.</param>
-        /// <since_tizen> 8 </since_tizen>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Extents TrackPadding
+        {
+            get => (Extents)GetValue(TrackPaddingProperty);
+            set => SetValue(TrackPaddingProperty, value);
+        }
+
+        #endregion Properties
+
+
+        #region Methods
+
+        /// <inheritdoc/>
+        [EditorBrowsable(EditorBrowsableState.Never)]
         public override void CopyFrom(BindableObject bindableObject)
         {
             base.CopyFrom(bindableObject);
 
-            ScrollBarStyle scrollBarStyle = bindableObject as ScrollBarStyle;
+            var style = bindableObject as ScrollbarStyle;
 
-            if (null != scrollBarStyle)
+            if (null != style)
             {
-                if (null != scrollBarStyle.Track)
-                {
-                    Track?.CopyFrom(scrollBarStyle.Track);
-                }
-
-                if (null != scrollBarStyle.Thumb)
-                {
-                    Thumb?.CopyFrom(scrollBarStyle.Thumb);
-                }
-
-                Direction = scrollBarStyle.Direction;
-                Duration = scrollBarStyle.Duration;
+                TrackThickness = style.TrackThickness;
+                ThumbThickness = style.ThumbThickness;
+                TrackColor = style.TrackColor;
+                ThumbColor = style.ThumbColor;
+                TrackPadding = style.TrackPadding;
             }
         }
 
-        private void InitSubStyle()
+        private void Initialize()
         {
-            Track = new ImageViewStyle()
-            {
-                PositionUsesPivotPoint = true,
-                ParentOrigin = Tizen.NUI.ParentOrigin.CenterLeft,
-                PivotPoint = Tizen.NUI.PivotPoint.CenterLeft,
-                WidthResizePolicy = ResizePolicyType.FillToParent,
-                HeightResizePolicy = ResizePolicyType.FillToParent
-            };
-
-            Thumb = new ImageViewStyle()
-            {
-                PositionUsesPivotPoint = true,
-                ParentOrigin = Tizen.NUI.ParentOrigin.CenterLeft,
-                PivotPoint = Tizen.NUI.PivotPoint.CenterLeft,
-                WidthResizePolicy = ResizePolicyType.Fixed,
-                HeightResizePolicy = ResizePolicyType.Fixed
-            };
+            TrackThickness = 6.0f;
+            ThumbThickness = 6.0f;
+            TrackColor = new Color(1.0f, 1.0f, 1.0f, 0.15f);
+            ThumbColor = new Color(0.6f, 0.6f, 0.6f, 1.0f);
+            TrackPadding = 4;
         }
+
+        #endregion Methods
     }
 }
diff --git a/src/Tizen.NUI.Wearable/src/public/CircularScrollbar.cs b/src/Tizen.NUI.Wearable/src/public/CircularScrollbar.cs
new file mode 100644 (file)
index 0000000..17ed39f
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ * Copyright(c) 2020 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.ComponentModel;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Components;
+
+namespace Tizen.NUI.Wearable
+{
+    /// <summary>
+    /// The CircualrScrollbar is a wearable NUI component that can be linked to the scrollable objects
+    /// indicating the current scroll position of the scrollable object.<br />
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class CircularScrollbar : ScrollbarBase
+    {
+        #region Fields
+
+        /// <summary>Bindable property of Thickness</summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty ThicknessProperty = BindableProperty.Create(nameof(Thickness), typeof(float), typeof(CircularScrollbar), default(float), propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            var instance = ((CircularScrollbar)bindable);
+            var thickness = (float?)newValue;
+
+            ((CircularScrollbarStyle)instance.viewStyle).Thickness = thickness;
+            instance.UpdateVisualThickness(thickness ?? 0);
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            return ((CircularScrollbarStyle)((CircularScrollbar)bindable).viewStyle)?.Thickness ?? 0;
+        });
+
+        /// <summary>Bindable property of TrackSweepAngle</summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty TrackSweepAngleProperty = BindableProperty.Create(nameof(TrackSweepAngle), typeof(float), typeof(CircularScrollbar), default(float), propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            var instance = ((CircularScrollbar)bindable);
+            var angle = (float?)newValue;
+
+            ((CircularScrollbarStyle)instance.viewStyle).TrackSweepAngle = angle;
+            instance.UpdateTrackVisualSweepAngle(angle ?? 0);
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            return ((CircularScrollbarStyle)((CircularScrollbar)bindable).viewStyle)?.TrackSweepAngle ?? 0;
+        });
+
+        /// <summary>Bindable property of TrackColor</summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty TrackColorProperty = BindableProperty.Create(nameof(TrackColor), typeof(Color), typeof(CircularScrollbar), null, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            var instance = ((CircularScrollbar)bindable);
+            var color = (Color)newValue;
+
+            ((CircularScrollbarStyle)instance.viewStyle).TrackColor = color;
+            instance.UpdateTrackVisualColor(color);
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            return ((CircularScrollbarStyle)((CircularScrollbar)bindable).viewStyle)?.TrackColor;
+        });
+
+        /// <summary>Bindable property of ThumbColor</summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty ThumbColorProperty = BindableProperty.Create(nameof(ThumbColor), typeof(Color), typeof(CircularScrollbar), null, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            var instance = ((CircularScrollbar)bindable);
+            var color = (Color)newValue;
+
+            ((CircularScrollbarStyle)instance.viewStyle).ThumbColor = color;
+            instance.UpdateThumbVisualColor(color);
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            return ((CircularScrollbarStyle)((CircularScrollbar)bindable).viewStyle)?.ThumbColor;
+        });
+
+        private ArcVisual trackVisual;
+        private ArcVisual thumbVisual;
+        private float contentLength;
+        private float visibleLength;
+        private float currentPosition;
+        private float directionAlpha;
+        private Animation thumbStartAngleAnimation;
+        private Animation thumbSweepAngleAnimation;
+
+        #endregion Fields
+
+
+        #region Constructors
+
+        /// <summary>
+        /// Create an empty CircularScrollbar.
+        /// </summary>
+        public CircularScrollbar() : base(new CircularScrollbarStyle())
+        {
+        }
+
+        /// <summary>
+        /// Create a CircularScrollbar and initialize with properties.
+        /// </summary>
+        /// <param name="contentLength">The total length of the content.</param>
+        /// <param name="viewSize">The size of View that contains the content to scroll.</param>
+        /// <param name="currentPosition">Scrolled position.</param>
+        /// <param name="isHorizontal">Whether the direction of scrolling is horizontal or not. It is vertical if the value is false.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public CircularScrollbar(float contentLength, Size viewSize, float currentPosition, bool isHorizontal = false) : base(new CircularScrollbarStyle())
+        {
+            Initialize(contentLength, viewSize, currentPosition, isHorizontal);
+        }
+
+        /// <summary>
+        /// Create an empty CircularScrollbar with a CircularScrollbarStyle instance to set style properties.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public CircularScrollbar(CircularScrollbarStyle style) : base(style)
+        {
+        }
+
+        /// <summary>
+        /// Static constructor to initialize bindable properties when loading.
+        /// </summary>
+        static CircularScrollbar()
+        {
+        }
+
+        #endregion Constructors
+
+
+        #region Properties
+
+        /// <summary>
+        /// The thickness of the scrollbar and track.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float Thickness
+        {
+            get => (float)GetValue(ThicknessProperty);
+            set => SetValue(ThicknessProperty, value);
+        }
+
+        /// <summary>
+        /// The sweep angle of track area in degrees.
+        /// </summary>
+        /// <remarks>
+        /// Values below 6 degrees are treated as 6 degrees.
+        /// Values exceeding 180 degrees are treated as 180 degrees.
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float TrackSweepAngle
+        {
+            get => (float)GetValue(TrackSweepAngleProperty);
+            set => SetValue(TrackSweepAngleProperty, value);
+        }
+
+        /// <summary>
+        /// The color of the track part.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Color TrackColor
+        {
+            get => (Color)GetValue(TrackColorProperty);
+            set => SetValue(TrackColorProperty, value);
+        }
+
+        /// <summary>
+        /// The color of the thumb part.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Color ThumbColor
+        {
+            get => (Color)GetValue(ThumbColorProperty);
+            set => SetValue(ThumbColorProperty, value);
+        }
+
+        #endregion Properties
+
+
+        #region Methods
+
+        /// <inheritdoc/>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public override void Initialize(float contentLength, Size viewSize, float currentPosition, bool isHorizontal = false)
+        {
+            this.contentLength = contentLength > 0.0f ? contentLength : 0.0f;
+            this.visibleLength = isHorizontal ? viewSize.Width : viewSize.Height;
+            this.currentPosition = currentPosition;
+            this.directionAlpha = isHorizontal ? 270.0f : 0.0f;
+
+            Size = viewSize;
+
+            thumbStartAngleAnimation?.Stop();
+            thumbStartAngleAnimation = null;
+
+            thumbSweepAngleAnimation?.Stop();
+            thumbSweepAngleAnimation = null;
+
+            CreateTrackVisual();
+            CreateThumbVisual(currentPosition);
+
+            AddVisual("Track", trackVisual);
+            AddVisual("Thumb", thumbVisual);
+        }
+
+        /// <inheritdoc/>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public override void Update(float contentLength, float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
+        {
+            this.currentPosition = position;
+            this.contentLength = contentLength > 0.0f ? contentLength : 0.0f;
+
+            if (thumbVisual == null)
+            {
+                return;
+            }
+
+            thumbVisual.SweepAngle = CalculateThumbSweepAngle(TrackSweepAngle);
+            thumbVisual.StartAngle = CalculateThumbStartAngle(position, trackVisual.StartAngle, trackVisual.SweepAngle, thumbVisual.SweepAngle);
+            thumbVisual.Opacity = CalculateThumbVisibility() ? 1.0f : 0.0f;
+
+            if (durationMs == 0)
+            {
+                thumbVisual.UpdateVisual(true);
+
+                return;
+            }
+
+            // TODO Support non built-in alpha function for visual trainsition in DALi.
+            AlphaFunction.BuiltinFunctions builtinAlphaFunction = alphaFunction?.GetBuiltinFunction() ?? AlphaFunction.BuiltinFunctions.Default;
+
+            thumbStartAngleAnimation?.Stop();
+            thumbStartAngleAnimation = AnimateVisual(thumbVisual, "startAngle", thumbVisual.StartAngle, 0, (int)durationMs, builtinAlphaFunction);
+            thumbStartAngleAnimation.Play();
+
+            thumbSweepAngleAnimation?.Stop();
+            thumbSweepAngleAnimation = AnimateVisual(thumbVisual, "sweepAngle", thumbVisual.SweepAngle, 0, (int)durationMs, builtinAlphaFunction);
+            thumbSweepAngleAnimation.Play();
+        }
+
+        /// <inheritdoc/>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public override void ScrollTo(float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
+        {
+            currentPosition = position;
+
+            if (thumbVisual == null)
+            {
+                return;
+            }
+
+            var oldThumbStartAngle = thumbVisual.StartAngle;
+
+            thumbVisual.StartAngle = CalculateThumbStartAngle(position, trackVisual.StartAngle, trackVisual.SweepAngle, thumbVisual.SweepAngle);
+
+            if (durationMs == 0)
+            {
+                thumbVisual.UpdateVisual(true);
+
+                return;
+            }
+
+            // TODO Support non built-in alpha function for visual trainsition in DALi.
+            AlphaFunction.BuiltinFunctions builtinAlphaFunction = alphaFunction?.GetBuiltinFunction() ?? AlphaFunction.BuiltinFunctions.Default;
+
+            thumbStartAngleAnimation?.Stop();
+            thumbStartAngleAnimation = AnimateVisual(thumbVisual, "startAngle", thumbVisual.StartAngle, 0, (int)durationMs, builtinAlphaFunction);
+            thumbStartAngleAnimation.Play();
+        }
+
+        /// <inheritdoc/>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override ViewStyle GetViewStyle()
+        {
+            return new CircularScrollbarStyle();
+        }
+
+        private void CreateTrackVisual()
+        {
+            float sweepAngle = CalculateTrackSweepAngle(TrackSweepAngle);
+
+            trackVisual = new ArcVisual
+            {
+                SuppressUpdateVisual = true,
+                Thickness = this.Thickness,
+                Cap = ArcVisual.CapType.Round,
+                MixColor = TrackColor,
+                Size = new Size(visibleLength - 2, visibleLength - 2),
+                SizePolicy = VisualTransformPolicyType.Absolute,
+                SweepAngle = sweepAngle,
+                StartAngle = CalculateTrackStartAngle(sweepAngle),
+            };
+        }
+
+        private void CreateThumbVisual(float position)
+        {
+            float sweepAngle = CalculateThumbSweepAngle(TrackSweepAngle);
+            
+            thumbVisual = new ArcVisual
+            {
+                SuppressUpdateVisual = true,
+                Thickness = trackVisual.Thickness,
+                Cap = ArcVisual.CapType.Round,
+                MixColor = ThumbColor,
+                Size = new Size(visibleLength - 2, visibleLength - 2),
+                SizePolicy = VisualTransformPolicyType.Absolute,
+                SweepAngle = sweepAngle,
+                StartAngle = CalculateThumbStartAngle(position, trackVisual.StartAngle, trackVisual.SweepAngle, sweepAngle),
+                Opacity = CalculateThumbVisibility() ? 1.0f : 0.0f,
+            };
+        }
+
+        private float CalculateTrackStartAngle(float currentTrackSweepAngle)
+        {
+            return ((180.0f - currentTrackSweepAngle) / 2.0f) + directionAlpha;
+        }
+
+        private float CalculateTrackSweepAngle(float inputTrackSweepAngle)
+        {
+            return Math.Min(Math.Max(inputTrackSweepAngle, 3), 180);
+        }
+
+        private float CalculateThumbStartAngle(float position, float trackStartAngle, float trackSweepAngle, float thumbSweepAngle)
+        {
+            float minAngle = trackStartAngle;
+            float maxAngle = trackStartAngle + trackSweepAngle - thumbSweepAngle;
+            float resultAngle = trackStartAngle + (trackSweepAngle * (position < 0.0f ? 0.0f : position) / contentLength);
+
+            return Math.Min(Math.Max(resultAngle, minAngle), maxAngle);
+        }
+
+        private float CalculateThumbSweepAngle(float trackSweepAngle)
+        {
+            return trackSweepAngle * visibleLength / contentLength;
+        }
+
+        private bool CalculateThumbVisibility()
+        {
+            return contentLength > visibleLength;
+        }
+
+        private void UpdateVisualThickness(float thickness)
+        {
+            if (trackVisual == null)
+            {
+                return;
+            }
+
+            trackVisual.Thickness = thickness;
+            thumbVisual.Thickness = thickness;
+
+            trackVisual.UpdateVisual(true);
+            thumbVisual.UpdateVisual(true);
+        }
+
+        private void UpdateTrackVisualSweepAngle(float trackSweepAngle)
+        {
+            if (trackVisual == null || thumbVisual == null)
+            {
+                return;
+            }
+
+            trackVisual.SweepAngle = CalculateTrackSweepAngle(trackSweepAngle);
+            trackVisual.StartAngle = CalculateTrackStartAngle(trackVisual.SweepAngle);
+
+            thumbVisual.SweepAngle = CalculateThumbSweepAngle(TrackSweepAngle);
+            thumbVisual.StartAngle = CalculateThumbStartAngle(currentPosition, trackVisual.StartAngle, trackVisual.SweepAngle, thumbVisual.SweepAngle);
+
+            trackVisual.UpdateVisual(true);
+            thumbVisual.UpdateVisual(true);
+        }
+
+        private void UpdateTrackVisualColor(Color trackColor)
+        {
+            if (trackVisual == null)
+            {
+                return;
+            }
+
+            trackVisual.MixColor = trackColor;
+            trackVisual.UpdateVisual(true);
+        }
+
+        private void UpdateThumbVisualColor(Color thumbColor)
+        {
+            if (thumbVisual == null)
+            {
+                return;
+            }
+
+            thumbVisual.MixColor = thumbColor;
+            thumbVisual.UpdateVisual(true);
+        }
+
+        #endregion Methods
+    }
+}
diff --git a/src/Tizen.NUI.Wearable/src/public/WearableStyle/CircularScrollbarStyle.cs b/src/Tizen.NUI.Wearable/src/public/WearableStyle/CircularScrollbarStyle.cs
new file mode 100644 (file)
index 0000000..dae9f94
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright(c) 2019 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.ComponentModel;
+using Tizen.NUI.Components;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Wearable
+{
+    /// <summary>
+    /// CircularScrollbarStyle is a class which saves CircularScrollbar's ux data.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class CircularScrollbarStyle : ControlStyle
+    {
+        #region Fields
+
+        /// <summary>Bindable property of Thickness</summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty ThicknessProperty = BindableProperty.Create(nameof(Thickness), typeof(float?), typeof(CircularScrollbarStyle), null, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            ((CircularScrollbarStyle)bindable).thickness = (float?)newValue;
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            return ((CircularScrollbarStyle)bindable).thickness;
+        });
+
+        /// <summary>Bindable property of TrackSweepAngle</summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty TrackSweepAngleProperty = BindableProperty.Create(nameof(TrackSweepAngle), typeof(float?), typeof(CircularScrollbarStyle), null, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            ((CircularScrollbarStyle)bindable).trackSweepAngle = (float?)newValue;
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            return ((CircularScrollbarStyle)bindable).trackSweepAngle;
+        });
+
+        /// <summary>Bindable property of TrackColor</summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty TrackColorProperty = BindableProperty.Create(nameof(TrackColor), typeof(Color), typeof(CircularScrollbarStyle), null, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            ((CircularScrollbarStyle)bindable).trackColor = (Color)newValue;
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            return ((CircularScrollbarStyle)bindable).trackColor;
+        });
+
+        /// <summary>Bindable property of ThumbColor</summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty ThumbColorProperty = BindableProperty.Create(nameof(ThumbColor), typeof(Color), typeof(CircularScrollbarStyle), null, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            ((CircularScrollbarStyle)bindable).thumbColor = (Color)newValue;
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            return ((CircularScrollbarStyle)bindable).thumbColor;
+        });
+
+        private float? thickness;
+        private float? trackSweepAngle;
+        private Color trackColor;
+        private Color thumbColor;
+
+        #endregion Fields
+
+
+        #region Constructors
+
+        /// <summary>
+        /// Creates a new instance of a CircularScrollbarStyle.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public CircularScrollbarStyle() : base()
+        {
+            Initialize();
+        }
+
+        /// <summary>
+        /// Copy constructor.
+        /// </summary>
+        /// <param name="style">Create ScrollbarStyle by style customized by user.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public CircularScrollbarStyle(CircularScrollbarStyle style) : base(style)
+        {
+            this.CopyFrom(style);
+        }
+
+        /// <summary>
+        /// Static constructor to initialize bindable properties when loading.
+        /// </summary>
+        static CircularScrollbarStyle()
+        {
+        }
+
+        #endregion Constructors
+
+
+        #region Properties
+
+        /// <summary>
+        /// The thickness of the scrollbar and track.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float? Thickness
+        {
+            get => (float?)GetValue(ThicknessProperty);
+            set => SetValue(ThicknessProperty, value);
+        }
+
+        /// <summary>
+        /// The sweep angle of track area in degrees.
+        /// </summary>
+        /// <remarks>
+        /// Values below 6 degrees are treated as 6 degrees.
+        /// Values exceeding 180 degrees are treated as 180 degrees.
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float? TrackSweepAngle
+        {
+            get => (float?)GetValue(TrackSweepAngleProperty);
+            set => SetValue(TrackSweepAngleProperty, value);
+        }
+
+        /// <summary>
+        /// The color of the track part.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Color TrackColor
+        {
+            get => (Color)GetValue(TrackColorProperty);
+            set => SetValue(TrackColorProperty, value);
+        }
+
+        /// <summary>
+        /// The color of the thumb part.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Color ThumbColor
+        {
+            get => (Color)GetValue(ThumbColorProperty);
+            set => SetValue(ThumbColorProperty, value);
+        }
+
+        #endregion Properties
+
+
+        #region Methods
+
+        /// <inheritdoc/>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public override void CopyFrom(BindableObject bindableObject)
+        {
+            base.CopyFrom(bindableObject);
+
+            var style = bindableObject as CircularScrollbarStyle;
+
+            if (null != style)
+            {
+                Thickness = style.Thickness;
+                TrackSweepAngle = style.TrackSweepAngle;
+                TrackColor = style.TrackColor;
+                ThumbColor = style.ThumbColor;
+            }
+        }
+
+        private void Initialize()
+        {
+            Thickness = 10.0f;
+            TrackSweepAngle = 60.0f;
+            TrackColor = new Color(1.0f, 1.0f, 1.0f, 0.15f);
+            ThumbColor = new Color(0.6f, 0.6f, 0.6f, 1.0f);
+        }
+
+        #endregion Methods
+    }
+}
index 16c4561..d4a14ec 100755 (executable)
@@ -409,7 +409,12 @@ namespace Tizen.NUI
             /// <summary>
             /// Renders a animated image (animated GIF).
             /// </summary>
-            AnimatedImage
+            AnimatedImage,
+            /// <summary>
+            /// Renders an arc.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            Arc = AnimatedImage + 3,
         }
 
         /// <summary>
@@ -454,7 +459,7 @@ namespace Tizen.NUI
             /// <since_tizen> 5 </since_tizen>
             public static readonly int VisualFittingMode = NDalic.VISUAL_PROPERTY_MIX_COLOR + 2;
             /// <summary>
-            /// The fitting mode of the visual.
+            /// The corner radius of the visual.
             /// </summary>
             [EditorBrowsable(EditorBrowsableState.Never)]
             public static readonly int CornerRadius = NDalic.VISUAL_PROPERTY_MIX_COLOR + 3;
@@ -1121,4 +1126,42 @@ namespace Tizen.NUI
         /// <since_tizen> 3 </since_tizen>
         public static readonly int Border = NDalic.IMAGE_VISUAL_WRAP_MODE_V + 1;
     }
+
+    /// <summary>
+    /// This specifies properties of the ArcVisual.
+    /// </summary>
+    internal struct ArcVisualProperty
+    {
+        /// <summary>
+        /// The thickness of the arc.
+        /// </summary>
+        /// <remarks>The value is float type.</remarks>
+        /// <remarks>This is mandatory property.</remarks>
+        internal static readonly int Thickness = NDalic.IMAGE_VISUAL_URL;
+
+        /// <summary>
+        /// The start angle where the arc begins in degrees.
+        /// </summary>
+        /// <remarks>The value is float type.</remarks>
+        /// <remarks>The property of optional. The default value is 0.</remarks>
+        internal static readonly int StartAngle = Thickness + 1;
+
+        /// <summary>
+        /// The sweep angle of the arc in degrees.
+        /// </summary>
+        /// <remarks>The value is float type.</remarks>
+        /// <remarks>The property of optional. The default value is 360.</remarks>
+        internal static readonly int SweepAngle = Thickness + 2;
+
+        /// <summary>
+        /// The cap style of the arc.
+        /// </summary>
+        /// <remarks>
+        /// The value is integer type.
+        /// The value 0 means butt, the arc does not extend beyond its two endpoints.
+        /// The value 1 means round, the arc will be extended by a half circle with the center at the end.
+        /// </remarks>
+        /// <remarks>The property of optional. The default value is 0 (butt).</remarks>
+        internal static readonly int Cap = Thickness + 3;
+    }
 }
index d3b3924..c5d63a3 100755 (executable)
@@ -14,6 +14,7 @@
  * limitations under the License.
  *
  */
+using System.ComponentModel;
 using Tizen.NUI.BaseComponents;
 
 namespace Tizen.NUI
@@ -62,6 +63,12 @@ namespace Tizen.NUI
         protected VisualFittingModeType? _visualFittingMode = null;
 
         /// <summary>
+        /// The corner radius value of the visual.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected float? _cornerRadius = null;
+
+        /// <summary>
         /// The map for visual.
         /// </summary>
         /// <since_tizen> 3 </since_tizen>
@@ -594,6 +601,23 @@ namespace Tizen.NUI
             }
         }
 
+        /// <summary>
+        /// The corner radius of the visual.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float CornerRadius
+        {
+            get
+            {
+                return _cornerRadius ?? (0.0f);
+            }
+            set
+            {
+                _cornerRadius = value;
+                UpdateVisual();
+            }
+        }
+
         internal string Name
         {
             set;
@@ -612,9 +636,15 @@ namespace Tizen.NUI
             get;
         }
 
-        internal void UpdateVisual()
+        /// <summary>
+        /// Suppress UpdateVisual() to update properties to Parent.
+        /// If it is set to true, UpdateVisual() is ignored unless it is called with force.
+        /// </summary>
+        internal bool SuppressUpdateVisual { get; set; } = false;
+
+        internal void UpdateVisual(bool force = false)
         {
-            if (VisualIndex > 0)
+            if (VisualIndex > 0 && (!SuppressUpdateVisual || force))
             {
                 NUILog.Debug("UpdateVisual()! VisualIndex=" + VisualIndex);
                 Parent.UpdateVisual(VisualIndex, Name, this);
@@ -641,6 +671,7 @@ namespace Tizen.NUI
             if (_mixColor != null) { _outputVisualMap.Add(Visual.Property.MixColor, new PropertyValue(_mixColor)); }
             if (_opacity != null) { _outputVisualMap.Add(Visual.Property.Opacity, new PropertyValue((float)_opacity)); }
             if (_visualFittingMode != null) { _outputVisualMap.Add(Visual.Property.VisualFittingMode, new PropertyValue((int)_visualFittingMode)); }
+            if (_cornerRadius != null) { _outputVisualMap.Add(Visual.Property.CornerRadius, new PropertyValue((int)_cornerRadius)); }
         }
 
         private void ComposingTransformMap()
diff --git a/src/Tizen.NUI/src/public/Visuals/ArcVisual.cs b/src/Tizen.NUI/src/public/Visuals/ArcVisual.cs
new file mode 100644 (file)
index 0000000..7506ae2
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright(c) 2020 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.ComponentModel;
+
+namespace Tizen.NUI
+{
+    /// <summary>
+    /// A class encapsulating the property map of the arc visual.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class ArcVisual : VisualMap
+    {
+        #region Fields
+
+        private float thickness;
+        private float startAngle;
+        private float sweepAngle;
+        private CapType cap;
+
+        #endregion Fields
+
+
+        #region Constructors
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public ArcVisual() : base()
+        {
+        }
+
+        #endregion Constructors
+
+
+        #region Enums
+
+        /// <summary>
+        /// Enumeration for the cap style of the arc line.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public enum CapType
+        {
+            /// <summary>
+            /// The arc does not extend beyond its two endpoints.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            Butt,
+
+            /// <summary>
+            /// The arc will be extended by a half circle with the center at the end.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            Round,
+        }
+
+        #endregion Enums
+
+
+        #region Properties
+
+        /// <summary>
+        /// The thickness of the arc.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float Thickness
+        {
+            get => thickness;
+            set
+            {
+                thickness = value;
+                UpdateVisual();
+            }
+        }
+
+        /// <summary>
+        /// The start angle where the arc begins in degrees.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float StartAngle
+        {
+            get => startAngle;
+            set
+            {
+                startAngle = value;
+                UpdateVisual();
+            }
+        }
+
+        /// <summary>
+        /// The sweep angle of the arc in degrees.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float SweepAngle
+        {
+            get => sweepAngle;
+            set
+            {
+                sweepAngle = value;
+                UpdateVisual();
+            }
+        }
+
+        /// <summary>
+        /// The cap style of the arc.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public CapType Cap
+        {
+            get => cap;
+            set
+            {
+                cap = value;
+                UpdateVisual();
+            }
+        }
+
+        #endregion Properties
+
+
+        #region Methods
+
+        /// <inheritdoc/>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override void ComposingPropertyMap()
+        {
+            _outputVisualMap = null;
+
+            base.ComposingPropertyMap();
+
+            _outputVisualMap.Add(Visual.Property.Type, new PropertyValue((int)Visual.Type.Arc));
+            _outputVisualMap.Add(ArcVisualProperty.Thickness, new PropertyValue(Thickness < 0.0f ? 0.0f : Thickness));
+            _outputVisualMap.Add(ArcVisualProperty.StartAngle, new PropertyValue(StartAngle));
+            _outputVisualMap.Add(ArcVisualProperty.SweepAngle, new PropertyValue(SweepAngle));
+            _outputVisualMap.Add(ArcVisualProperty.Cap, new PropertyValue((int)Cap));
+        }
+
+        #endregion Methods
+    }
+}
index 5906fcd..bacde98 100755 (executable)
@@ -76,16 +76,20 @@ namespace Tizen.NUI
         /// <since_tizen> 3 </since_tizen>
         protected override void ComposingPropertyMap()
         {
-            if (_mixColorForColorVisual != null)
+            Color color = _mixColorForColorVisual ?? _mixColor;
+
+            if (color != null)
             {
-                _outputVisualMap = new PropertyMap();
+                _outputVisualMap = null;
+
+                base.ComposingPropertyMap();
+
                 _outputVisualMap.Add(Visual.Property.Type, new PropertyValue((int)Visual.Type.Color));
-                _outputVisualMap.Add(ColorVisualProperty.MixColor, new PropertyValue(_mixColorForColorVisual));
-                if (_shader != null) { _outputVisualMap.Add(Visual.Property.Shader, new PropertyValue(_shader)); }
-                if (_premultipliedAlpha != null) { _outputVisualMap.Add(Visual.Property.PremultipliedAlpha, new PropertyValue((bool)_premultipliedAlpha)); }
-                if (_opacity != null) { _outputVisualMap.Add(Visual.Property.Opacity, new PropertyValue((float)_opacity)); }
-                if (_renderIfTransparent != null) { _outputVisualMap.Add(ColorVisualProperty.RenderIfTransparent, new PropertyValue((bool)_renderIfTransparent)); }
-                if (_visualFittingMode != null) { _outputVisualMap.Add(Visual.Property.VisualFittingMode, new PropertyValue((int)_visualFittingMode)); }
+                _outputVisualMap.Add(ColorVisualProperty.MixColor, new PropertyValue(color));
+            }
+            else
+            {
+                _outputVisualMap = new PropertyMap();
             }
         }
     }