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