Merge remote-tracking branch 'origin/master' into tizen
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / ImageScrollBar.cs
1 /*
2  * Copyright(c) 2019 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 using System;
18 using Tizen.NUI.BaseComponents;
19 using System.ComponentModel;
20 using Tizen.NUI.Binding;
21
22 namespace Tizen.NUI.Components
23 {
24     /// <summary>
25     /// The ScrollBar class of nui component. It allows users to recognize the direction and the range of lists/content.
26     /// </summary>
27     /// <remarks>
28     /// Please note that this class will be replaced with Scrollbar class in the near future.
29     /// </remarks>
30     /// <since_tizen> 6 </since_tizen>
31     /// This will be deprecated
32     [Obsolete("Deprecated in API8; Will be removed in API10")]
33     public class ScrollBar : Control
34     {
35         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
36         [EditorBrowsable(EditorBrowsableState.Never)]
37         public static readonly BindableProperty DirectionProperty = BindableProperty.Create(nameof(Direction), typeof(DirectionType), typeof(ScrollBar), DirectionType.Horizontal, propertyChanged: (bindable, oldValue, newValue) =>
38         {
39             var instance = (ScrollBar)bindable;
40             if (newValue != null)
41             {
42                 instance.Style.Direction = (DirectionType?)newValue;
43                 instance.UpdateValue();
44             }
45         },
46         defaultValueCreator: (bindable) =>
47         {
48             var instance = (ScrollBar)bindable;
49             return instance.Style.Direction;
50         });
51         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
52         [EditorBrowsable(EditorBrowsableState.Never)]
53         public static readonly BindableProperty MaxValueProperty = BindableProperty.Create(nameof(MaxValue), typeof(int), typeof(ScrollBar), default(int), propertyChanged: (bindable, oldValue, newValue) =>
54         {
55             var instance = (ScrollBar)bindable;
56             if (newValue != null)
57             {
58                 if ((int)newValue >= 0)
59                 {
60                     instance.maxValue = (int)newValue;
61                     instance.UpdateValue();
62                 }
63             }
64         },
65         defaultValueCreator: (bindable) =>
66         {
67             var instance = (ScrollBar)bindable;
68             return instance.maxValue;
69         });
70         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
71         [EditorBrowsable(EditorBrowsableState.Never)]
72         public static readonly BindableProperty MinValueProperty = BindableProperty.Create(nameof(MinValue), typeof(int), typeof(ScrollBar), default(int), propertyChanged: (bindable, oldValue, newValue) =>
73         {
74             var instance = (ScrollBar)bindable;
75             if (newValue != null)
76             {
77                 if ((int)newValue >= 0)
78                 {
79                     instance.minValue = (int)newValue;
80                     instance.UpdateValue();
81                 }
82             }
83         },
84         defaultValueCreator: (bindable) =>
85         {
86             var instance = (ScrollBar)bindable;
87             return instance.minValue;
88         });
89         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
90         [EditorBrowsable(EditorBrowsableState.Never)]
91         public static readonly BindableProperty CurrentValueProperty = BindableProperty.Create(nameof(CurrentValue), typeof(int), typeof(ScrollBar), default(int), propertyChanged: (bindable, oldValue, newValue) =>
92         {
93             var instance = (ScrollBar)bindable;
94             if (newValue != null)
95             {
96                 if ((int)newValue >= 0)
97                 {
98                     instance.curValue = (int)newValue;
99                     instance.UpdateValue();
100                 }
101             }
102         },
103         defaultValueCreator: (bindable) =>
104         {
105             var instance = (ScrollBar)bindable;
106             return instance.curValue;
107         });
108         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
109         [EditorBrowsable(EditorBrowsableState.Never)]
110         public static readonly BindableProperty DurationProperty = BindableProperty.Create(nameof(Duration), typeof(uint), typeof(ScrollBar), default(uint), propertyChanged: (bindable, oldValue, newValue) =>
111         {
112             var instance = (ScrollBar)bindable;
113             if (newValue != null)
114             {
115                 instance.Style.Duration = (uint)newValue;
116                 if (instance.scrollAniPlayer != null)
117                 {
118                     instance.scrollAniPlayer.Duration = (int)(uint)newValue;
119                 }
120             }
121         },
122         defaultValueCreator: (bindable) =>
123         {
124             var instance = (ScrollBar)bindable;
125             return instance.Style.Duration;
126         });
127
128         private ImageView trackImage;
129         private ImageView thumbImage;
130         private Animation scrollAniPlayer = null;
131         private float thumbImagePosX;
132         private float thumbImagePosY;
133         private bool enableAni = false;
134         private int minValue;
135         private int maxValue;
136         private int curValue;
137         static ScrollBar() { }
138
139         /// <summary>
140         /// The constructor of ScrollBar.
141         /// </summary>
142         /// <since_tizen> 6 </since_tizen>
143         /// This will be deprecated
144         [Obsolete("Deprecated in API8; Will be removed in API10")]
145         public ScrollBar() : base()
146         {
147             Initialize();
148         }
149
150         /// <summary>
151         /// The constructor of ScrollBar with specific style.
152         /// </summary>
153         /// <param name="style">style name</param>
154         [EditorBrowsable(EditorBrowsableState.Never)]
155         public ScrollBar(string style) : base(style)
156         {
157             Initialize();
158         }
159
160         /// <summary>
161         /// The constructor of ScrollBar with specific style.
162         /// </summary>
163         /// <param name="scrollBarStyle">The style object to initialize the ScrollBar.</param>
164         [EditorBrowsable(EditorBrowsableState.Never)]
165         public ScrollBar(ScrollBarStyle scrollBarStyle) : base(scrollBarStyle)
166         {
167             Initialize();
168         }
169
170         /// <summary>
171         /// The direction type of the Scroll.
172         /// </summary>
173         /// <since_tizen> 6 </since_tizen>
174         /// This will be deprecated
175         [Obsolete("Deprecated in API8; Will be removed in API10")]
176         public enum DirectionType
177         {
178             /// <summary>
179             /// The Horizontal type.
180             /// </summary>
181             /// <since_tizen> 6 </since_tizen>
182             /// This will be deprecated
183             [Obsolete("Deprecated in API8; Will be removed in API10")]
184             Horizontal,
185
186             /// <summary>
187             /// The Vertical type.
188             /// </summary>
189             /// <since_tizen> 6 </since_tizen>
190             /// This will be deprecated
191             [Obsolete("Deprecated in API8; Will be removed in API10")]
192             Vertical
193         }
194
195         #region public property 
196         /// <summary>
197         /// Get style of scrollbar.
198         /// </summary>
199         [EditorBrowsable(EditorBrowsableState.Never)]
200         public new ScrollBarStyle Style => ViewStyle as ScrollBarStyle;
201
202         /// <summary>
203         /// The property to get/set the direction of the ScrollBar.
204         /// </summary>
205         /// <since_tizen> 6 </since_tizen>
206         /// This will be deprecated
207         [Obsolete("Deprecated in API8; Will be removed in API10")]
208         public DirectionType Direction
209         {
210             get
211             {
212                 return (DirectionType)GetValue(DirectionProperty);
213             }
214             set
215             {
216                 SetValue(DirectionProperty, value);
217             }
218         }
219
220         /// <summary>
221         /// The property to get/set the size of the thumb object.
222         /// </summary>
223         /// <exception cref="InvalidOperationException">Throw when ThumbSize is null.</exception>
224         /// <example>
225         /// <code>
226         /// ScrollBar scroll;
227         /// try
228         /// {
229         ///     scroll.ThumbSize = new Size(500, 10, 0);
230         /// }
231         /// catch(InvalidOperationException e)
232         /// {
233         ///     Tizen.Log.Error(LogTag, "Failed to set ThumbSize value : " + e.Message);
234         /// }
235         /// </code>
236         /// </example>
237         /// <since_tizen> 6 </since_tizen>
238         /// This will be deprecated
239         [Obsolete("Deprecated in API8; Will be removed in API10")]
240         public Size ThumbSize
241         {
242             get
243             {
244                 return Style?.Thumb?.Size;
245             }
246             set
247             {
248                 if (null != Style?.Thumb)
249                 {
250                     Style.Thumb.Size = value;
251                     RelayoutRequest();
252                 }
253             }
254         }
255
256         /// <summary>
257         /// The property to get/set the image URL of the track object.
258         /// </summary>
259         /// <since_tizen> 6 </since_tizen>
260         /// This will be deprecated
261         [Obsolete("Deprecated in API8; Will be removed in API10")]
262         public string TrackImageURL
263         {
264             get
265             {
266                 return Style?.Track?.ResourceUrl?.All;
267             }
268             set
269             {
270                 if (null != Style?.Track)
271                 {
272                     Style.Track.ResourceUrl = value;
273                     RelayoutRequest();
274                 }
275             }
276         }
277
278         /// <summary>
279         /// The property to get/set the color of the track object.
280         /// </summary>
281         /// <since_tizen> 6 </since_tizen>
282         /// This will be deprecated
283         [Obsolete("Deprecated in API8; Will be removed in API10")]
284         public Color TrackColor
285         {
286             get
287             {
288                 return Style?.Track?.BackgroundColor?.All;
289             }
290             set
291             {
292                 if (null != Style?.Track)
293                 {
294                     Style.Track.BackgroundColor = value;
295                     RelayoutRequest();
296                 }
297             }
298         }
299
300         /// <summary>
301         /// The property to get/set the color of the thumb object.
302         /// </summary>
303         /// <since_tizen> 6 </since_tizen>
304         /// This will be deprecated
305         [Obsolete("Deprecated in API8; Will be removed in API10")]
306         public Color ThumbColor
307         {
308             get
309             {
310                 return Style?.Thumb?.BackgroundColor?.All;
311             }
312             set
313             {
314                 if(null != Style?.Thumb)
315                 {
316                     Style.Thumb.BackgroundColor = value;
317                     RelayoutRequest();
318                 }
319             }
320         }
321
322         /// <summary>
323         /// The property to get/set the max value of the ScrollBar.
324         /// </summary>
325         /// <since_tizen> 6 </since_tizen>
326         /// This will be deprecated
327         [Obsolete("Deprecated in API8; Will be removed in API10")]
328         public int MaxValue
329         {
330             get
331             {
332                 return (int)GetValue(MaxValueProperty);
333             }
334             set
335             {
336                 SetValue(MaxValueProperty, value);
337             }
338         }
339
340         /// <summary>
341         /// The property to get/set the min value of the ScrollBar.
342         /// </summary>
343         /// <since_tizen> 6 </since_tizen>
344         /// This will be deprecated
345         [Obsolete("Deprecated in API8; Will be removed in API10")]
346         public int MinValue
347         {
348             get
349             {
350                 return (int)GetValue(MinValueProperty);
351             }
352             set
353             {
354                 SetValue(MinValueProperty, value);
355             }
356         }
357
358         /// <summary>
359         /// The property to get/set the current value of the ScrollBar.
360         /// </summary>
361         /// <exception cref="ArgumentOutOfRangeException">Throw when Current value is less than Min value, or greater than Max value.</exception>
362         /// <example>
363         /// <code>
364         /// ScrollBar scroll;
365         /// scroll.MaxValue = 100;
366         /// scroll.MinValue = 0;
367         /// try
368         /// {
369         ///     scroll.CurrentValue = 50;
370         /// }
371         /// catch(ArgumentOutOfRangeException e)
372         /// {
373         ///     Tizen.Log.Error(LogTag, "Failed to set Current value : " + e.Message);
374         /// }
375         /// </code>
376         /// </example>
377         /// <since_tizen> 6 </since_tizen>
378         /// This will be deprecated
379         [Obsolete("Deprecated in API8; Will be removed in API10")]
380         public int CurrentValue
381         {
382             get
383             {
384                 return (int)GetValue(CurrentValueProperty);
385             }
386             set
387             {
388                 SetValue(CurrentValueProperty, value);
389             }
390         }
391
392         /// <summary>
393         /// Property to set/get animation duration.
394         /// </summary>
395         /// <since_tizen> 6 </since_tizen>
396         /// This will be deprecated
397         [Obsolete("Deprecated in API8; Will be removed in API10")]
398         public uint Duration
399         {
400             get
401             {
402                 return (uint)GetValue(DurationProperty);
403             }
404             set
405             {
406                 SetValue(DurationProperty, value);
407             }
408         }
409         #endregion
410
411         /// <summary>
412         /// Method to set current value. The thumb object would move to the corresponding position with animation or not.
413         /// </summary>
414         /// <param name="currentValue">The special current value.</param>
415         /// <param name="enableAnimation">Enable move with animation or not, the default value is true.</param>
416         /// <exception cref="ArgumentOutOfRangeException">Throw when current size is less than the min value, or greater than the max value.</exception>
417         /// <example>
418         /// <code>
419         /// ScrollBar scroll;
420         /// scroll.MinValue = 0;
421         /// scroll.MaxValue = 100;
422         /// try
423         /// {
424         ///     scroll.SetCurrentValue(50);
425         /// }
426         /// catch(ArgumentOutOfRangeException e)
427         /// {
428         ///     Tizen.Log.Error(LogTag, "Failed to set current value : " + e.Message);
429         /// }
430         /// </code>
431         /// </example>
432         /// <since_tizen> 6 </since_tizen>
433         /// This will be deprecated
434         [Obsolete("Deprecated in API8; Will be removed in API10")]
435         public void SetCurrentValue(int currentValue, bool enableAnimation = true)
436         {
437             if (currentValue < minValue || currentValue > maxValue)
438             {
439                 //TNLog.E("Current value is less than the Min value, or greater than the Max value. currentValue = " + currentValue + ";");
440 #pragma warning disable CA2208 // Instantiate argument exceptions correctly
441                 throw new ArgumentOutOfRangeException("Wrong Current value. It shoud be greater than the Min value, and less than the Max value!");
442 #pragma warning restore CA2208 // Instantiate argument exceptions correctly
443             }
444
445             enableAni = enableAnimation;
446             CurrentValue = currentValue;
447         }
448
449         /// <summary>
450         /// Dispose ScrollBar.
451         /// </summary>
452         /// <param name="type">The DisposeTypes value.</param>
453         /// <since_tizen> 6 </since_tizen>
454         /// This will be deprecated
455         [Obsolete("Deprecated in API8; Will be removed in API10")]
456         protected override void Dispose(DisposeTypes type)
457         {
458             if (disposed)
459             {
460                 return;
461             }
462
463             if (type == DisposeTypes.Explicit)
464             {
465                 //Called by User
466                 //Release your own managed resources here.
467                 //You should release all of your own disposable objects here.
468
469                 Utility.Dispose(trackImage);
470                 Utility.Dispose(thumbImage);
471
472                 if (scrollAniPlayer != null)
473                 {
474                     scrollAniPlayer.Stop();
475                     scrollAniPlayer.Clear();
476                     scrollAniPlayer.Dispose();
477                     scrollAniPlayer = null;
478                 }
479             }
480
481             //Release your own unmanaged resources here.
482             //You should not access any managed member here except static instance.
483             //because the execution order of Finalizes is non-deterministic.
484             //Unreference this from if a static instance refer to this. 
485
486             //You must call base.Dispose(type) just before exit.
487             base.Dispose(type);
488         }
489
490         /// <summary>
491         /// Get Scrollbar style.
492         /// </summary>
493         /// <returns>The default scrollbar style.</returns>
494         [EditorBrowsable(EditorBrowsableState.Never)]
495         protected override ViewStyle CreateViewStyle()
496         {
497             return new ScrollBarStyle();
498         }
499
500         /// <summary>
501         /// Theme change callback when theme is changed, this callback will be trigger.
502         /// </summary>
503         /// <param name="sender">The sender</param>
504         /// <param name="e">The event data</param>
505         [EditorBrowsable(EditorBrowsableState.Never)]
506         protected override void OnThemeChangedEvent(object sender, StyleManager.ThemeChangeEventArgs e)
507         {
508             ScrollBarStyle tempStyle = StyleManager.Instance.GetViewStyle(StyleName) as ScrollBarStyle;
509             if (tempStyle != null)
510             {
511                 Style.CopyFrom(tempStyle);
512                 UpdateValue();
513             }
514         }
515
516         private void Initialize()
517         {
518             this.Focusable = false;
519
520             trackImage = new ImageView
521             {
522                 Focusable = false,
523                 WidthResizePolicy = ResizePolicyType.FillToParent,
524                 HeightResizePolicy = ResizePolicyType.FillToParent,
525                 PositionUsesPivotPoint = true,
526                 ParentOrigin = Tizen.NUI.ParentOrigin.CenterLeft,
527                 PivotPoint = Tizen.NUI.PivotPoint.CenterLeft
528             };
529             this.Add(trackImage);
530             trackImage.ApplyStyle(Style.Track);
531
532             thumbImage = new ImageView
533             {
534                 Focusable = false,
535                 WidthResizePolicy = ResizePolicyType.Fixed,
536                 HeightResizePolicy = ResizePolicyType.Fixed,
537                 PositionUsesPivotPoint = true,
538                 ParentOrigin = Tizen.NUI.ParentOrigin.CenterLeft,
539                 PivotPoint = Tizen.NUI.PivotPoint.CenterLeft
540             };
541             this.Add(thumbImage);
542             thumbImage.ApplyStyle(Style.Thumb);
543
544             scrollAniPlayer = new Animation(334);
545             scrollAniPlayer.DefaultAlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.Linear);
546
547             thumbImagePosX = 0;
548             thumbImagePosY = 0;
549             LayoutDirectionChanged += OnLayoutDirectionChanged;
550         }
551
552         private void OnLayoutDirectionChanged(object sender, LayoutDirectionChangedEventArgs e)
553         {
554             RelayoutRequest();
555         }
556
557         private void UpdateValue()
558         {
559             if (minValue >= maxValue || curValue < minValue || curValue > maxValue) return;
560
561             float width = (float)Size2D.Width;
562             float height = (float)Size2D.Height;
563             float thumbW = 0.0f;
564             float thumbH = 0.0f;
565             if (Style.Thumb.Size == null)
566             {
567                 return;
568             }
569             else
570             {
571                 thumbW = Style.Thumb.Size.Width;
572                 thumbH = Style.Thumb.Size.Height;
573             }
574             float ratio = (float)(curValue - minValue) / (float)(maxValue - minValue);
575
576             if (Style.Direction == DirectionType.Horizontal)
577             {
578                 if (LayoutDirection == ViewLayoutDirectionType.RTL)
579                 {
580                     ratio = 1.0f - ratio;
581                 }
582
583                 float posX = ratio * (width - thumbW);
584                 float posY = (height - thumbH) / 2.0f;
585
586                 thumbImagePosX = posX;
587                 if (null != scrollAniPlayer)
588                 {
589                     scrollAniPlayer.Stop();
590                 }
591
592                 if (!enableAni)
593                 {
594                     thumbImage.Position = new Position(posX, posY, 0);
595                 }
596                 else
597                 {
598                     if (null != scrollAniPlayer)
599                     {
600                         scrollAniPlayer.Clear();
601                         scrollAniPlayer.AnimateTo(thumbImage, "PositionX", posX);
602                         scrollAniPlayer.Play();
603                     }
604                 }
605             }
606             else
607             {
608                 float posX = (width - thumbW) / 2.0f;
609                 float posY = ratio * (height - thumbH);
610
611                 thumbImagePosY = posY;
612                 if (null != scrollAniPlayer)
613                 {
614                     scrollAniPlayer.Stop();
615                 }
616
617                 if (!enableAni)
618                 {
619                     thumbImage.Position = new Position(posX, posY, 0);
620                 }
621                 else
622                 {
623                     if (null != scrollAniPlayer)
624                     {
625                         scrollAniPlayer.Clear();
626                         scrollAniPlayer.AnimateTo(thumbImage, "PositionY", posY);
627                         scrollAniPlayer.Play();
628                     }
629                 }
630             }
631
632             if (enableAni) enableAni = false;
633         }
634
635         private DirectionType CurrentDirection()
636         {
637             DirectionType dir = DirectionType.Horizontal;
638             if (null != Style.Direction)
639             {
640                 dir = Style.Direction.Value;
641             }
642             return dir;
643         }
644
645         private int CalculateCurrentValue(float offset, DirectionType dir)
646         {
647             if (dir == DirectionType.Horizontal)
648             {
649                 thumbImagePosX += offset;
650                 if (thumbImagePosX < 0)
651                 {
652                     thumbImage.PositionX = 0;
653                     curValue = minValue;
654                 }
655                 else if (thumbImagePosX > Size2D.Width - thumbImage.Size2D.Width)
656                 {
657                     thumbImage.PositionX = Size2D.Width - thumbImage.Size2D.Width;
658                     curValue = maxValue;
659                 }
660                 else
661                 {
662                     thumbImage.PositionX = thumbImagePosX;
663                     curValue = (int)((thumbImagePosX / (float)(Size2D.Width - thumbImage.Size2D.Width)) * (float)(maxValue - minValue) + 0.5f);
664                 }
665             }
666             else
667             {
668                 thumbImagePosY += offset;
669                 if (thumbImagePosY < 0)
670                 {
671                     thumbImage.PositionY = 0;
672                     curValue = minValue;
673                 }
674                 else if (thumbImagePosY > Size2D.Height - thumbImage.Size2D.Height)
675                 {
676                     thumbImage.PositionY = Size2D.Height - thumbImage.Size2D.Height;
677                     curValue = maxValue;
678                 }
679                 else
680                 {
681                     thumbImage.PositionY = thumbImagePosY;
682                     curValue = (int)((thumbImagePosY / (float)(Size2D.Height - thumbImage.Size2D.Height)) * (float)(maxValue - minValue) + 0.5f);
683                 }
684             }
685
686             return curValue;
687         }
688     }
689 }