/* * 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 { /// /// The ScrollBar class of nui component. It allows users to recognize the direction and the range of lists/content. /// /// /// Please note that this class will be replaced with Scrollbar class in the near future. /// /// 6 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() { } /// /// The constructor of ScrollBar. /// /// 6 public ScrollBar() : base() { Initialize(); } /// /// The constructor of ScrollBar with specific style. /// /// style name /// 8 public ScrollBar(string style) : base(style) { Initialize(); } /// /// The constructor of ScrollBar with specific style. /// /// The style object to initialize the ScrollBar. /// 8 public ScrollBar(ScrollBarStyle scrollBarStyle) : base(scrollBarStyle) { Initialize(); } /// /// The direction type of the Scroll. /// /// 6 public enum DirectionType { /// /// The Horizontal type. /// /// 6 Horizontal, /// /// The Vertical type. /// /// 6 Vertical } #region public property /// /// Get style of scrollbar. /// /// 8 public new ScrollBarStyle Style => ViewStyle as ScrollBarStyle; /// /// The property to get/set the direction of the ScrollBar. /// /// 6 public DirectionType Direction { get { return (DirectionType)GetValue(DirectionProperty); } set { SetValue(DirectionProperty, value); } } /// /// The property to get/set the size of the thumb object. /// /// Throw when ThumbSize is null. /// /// /// ScrollBar scroll; /// try /// { /// scroll.ThumbSize = new Size(500, 10, 0); /// } /// catch(InvalidOperationException e) /// { /// Tizen.Log.Error(LogTag, "Failed to set ThumbSize value : " + e.Message); /// } /// /// /// 6 public Size ThumbSize { get { return Style?.Thumb?.Size; } set { if (null != Style?.Thumb) { Style.Thumb.Size = value; RelayoutRequest(); } } } /// /// The property to get/set the image URL of the track object. /// /// 6 public string TrackImageURL { get { return Style?.Track?.ResourceUrl?.All; } set { if (null != Style?.Track) { Style.Track.ResourceUrl = value; RelayoutRequest(); } } } /// /// The property to get/set the color of the track object. /// /// 6 public Color TrackColor { get { return Style?.Track?.BackgroundColor?.All; } set { if (null != Style?.Track) { Style.Track.BackgroundColor = value; RelayoutRequest(); } } } /// /// The property to get/set the color of the thumb object. /// /// 6 public Color ThumbColor { get { return Style?.Thumb?.BackgroundColor?.All; } set { if(null != Style?.Thumb) { Style.Thumb.BackgroundColor = value; RelayoutRequest(); } } } /// /// The property to get/set the max value of the ScrollBar. /// /// 6 public int MaxValue { get { return (int)GetValue(MaxValueProperty); } set { SetValue(MaxValueProperty, value); } } /// /// The property to get/set the min value of the ScrollBar. /// /// 6 public int MinValue { get { return (int)GetValue(MinValueProperty); } set { SetValue(MinValueProperty, value); } } /// /// The property to get/set the current value of the ScrollBar. /// /// Throw when Current value is less than Min value, or greater than Max value. /// /// /// 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); /// } /// /// /// 6 public int CurrentValue { get { return (int)GetValue(CurrentValueProperty); } set { SetValue(CurrentValueProperty, value); } } /// /// Property to set/get animation duration. /// /// 6 public uint Duration { get { return (uint)GetValue(DurationProperty); } set { SetValue(DurationProperty, value); } } #endregion /// /// Method to set current value. The thumb object would move to the corresponding position with animation or not. /// /// The special current value. /// Enable move with animation or not, the default value is true. /// Throw when current size is less than the min value, or greater than the max value. /// /// /// 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); /// } /// /// /// 6 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; } /// /// Dispose ScrollBar. /// /// The DisposeTypes value. /// 6 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); } /// /// Get Scrollbar style. /// /// The default scrollbar style. /// 8 protected override ViewStyle CreateViewStyle() { return new ScrollBarStyle(); } /// /// Theme change callback when theme is changed, this callback will be trigger. /// /// The sender /// The event data /// 8 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; } } }